@astrosheep/keiyaku 2.9.12 → 2.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -18
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +1 -0
- package/build/agents/providers/claude-agent-sdk/adapter.js +2 -2
- package/build/cli/commands/akuma/akuma/handler.js +2 -1
- package/build/cli/commands/akuma/akuma/meta.js +4 -3
- package/build/cli/commands/akuma/catalog.js +2 -0
- package/build/cli/commands/akuma/list/handler.js +1 -1
- package/build/cli/commands/akuma/list/meta-list.js +12 -0
- package/build/cli/commands/akuma/list/meta-ls.js +2 -2
- package/build/cli/commands/akuma.js +5 -0
- package/build/cli/commands/contract/amend/meta.js +4 -3
- package/build/cli/commands/contract/arc/meta.js +2 -0
- package/build/cli/commands/contract/audit/handler.js +28 -2
- package/build/cli/commands/contract/audit/meta.js +4 -3
- package/build/cli/commands/contract/petition/handler.js +2 -1
- package/build/cli/commands/contract/petition/meta.js +2 -2
- package/build/cli/commands/contract/renew/handler.js +44 -3
- package/build/cli/commands/contract/renew/meta.js +5 -4
- package/build/cli/commands/metadata.js +12 -9
- package/build/cli/commands/projection/call/handler.js +1 -1
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -2
- package/build/cli/commands/projection/{revive → fork}/handler.js +10 -5
- package/build/cli/commands/projection/fork/meta.js +12 -0
- package/build/cli/commands/projection/history/handler.js +46 -2
- package/build/cli/commands/projection/history/meta.js +3 -3
- package/build/cli/commands/projection/kill/meta.js +2 -2
- package/build/cli/commands/projection/status/handler.js +29 -13
- package/build/cli/commands/projection/status/meta.js +14 -3
- package/build/cli/commands/projection/tell/handler.js +8 -4
- package/build/cli/commands/projection/tell/meta.js +1 -1
- package/build/cli/commands/projection/wait/handler.js +45 -20
- package/build/cli/commands/projection/wait/meta.js +1 -1
- package/build/cli/commands/shared.js +1 -1
- package/build/cli/commands/system/catalog.js +2 -0
- package/build/cli/commands/task/add/handler.js +28 -12
- package/build/cli/commands/task/add/meta.js +18 -6
- package/build/cli/commands/task/catalog.js +2 -0
- package/build/cli/commands/task/compose/handler.js +2 -2
- package/build/cli/commands/task/compose/meta.js +2 -2
- package/build/cli/commands/task/doctor/handler.js +2 -3
- package/build/cli/commands/task/doctor/meta.js +2 -2
- package/build/cli/commands/task/done/meta.js +2 -2
- package/build/cli/commands/task/drop/handler.js +7 -2
- package/build/cli/commands/task/drop/meta.js +6 -3
- package/build/cli/commands/task/hold/meta.js +2 -2
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/ls/meta.js +2 -2
- package/build/cli/commands/task/note/handler.js +6 -0
- package/build/cli/commands/task/note/meta.js +11 -0
- package/build/cli/commands/task/resume/meta.js +2 -2
- package/build/cli/commands/task/shared.js +29 -15
- package/build/cli/commands/task/show/meta.js +2 -2
- package/build/cli/commands/task/start/meta.js +2 -2
- package/build/cli/commands/task/stop/meta.js +2 -2
- package/build/cli/commands/task/update/meta.js +3 -2
- package/build/cli/commands/verification/handler.js +43 -0
- package/build/cli/commands/verification/meta.js +13 -0
- package/build/cli/completion.js +16 -13
- package/build/cli/flags.js +43 -11
- package/build/cli/help.js +29 -30
- package/build/cli/index.js +6 -5
- package/build/cli/parse-flags.js +39 -0
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +18 -0
- package/build/cli/parse.js +21 -8
- package/build/cli/render/arc.js +12 -3
- package/build/cli/render/audit.js +2 -2
- package/build/cli/render/call.js +4 -4
- package/build/cli/render/kanshi.js +122 -85
- package/build/cli/render/misc.js +2 -2
- package/build/cli/render/petition.js +16 -1
- package/build/cli/render/projection-history.js +17 -4
- package/build/cli/render/shared.js +5 -5
- package/build/cli/render/status-indicator.js +47 -0
- package/build/cli/render/status.js +106 -76
- package/build/cli/render/success-response.js +20 -5
- package/build/cli/render/task.js +6 -5
- package/build/cli/render/tell.js +10 -4
- package/build/cli/render/tool-command-normalization.js +137 -0
- package/build/cli/render/tool-presentation.js +2 -1
- package/build/cli/render/verification.js +23 -0
- package/build/cli/render/wait.js +101 -33
- package/build/cli/types.js +2 -1
- package/build/config/akuma-loader.js +21 -1
- package/build/config/settings/knobs.js +7 -1
- package/build/config/settings/schema.js +10 -5
- package/build/core/amend.js +102 -17
- package/build/core/arc.js +4 -4
- package/build/core/audit/candidate.js +10 -18
- package/build/core/audit/coordinates.js +12 -17
- package/build/core/audit/evidence.js +6 -4
- package/build/core/audit/facade.js +3 -3
- package/build/core/audit/report.js +1 -1
- package/build/core/bind-reconciliation.js +42 -23
- package/build/core/bind.js +182 -81
- package/build/core/call/call.js +6 -7
- package/build/core/call/context.js +43 -30
- package/build/core/call/execution.js +21 -6
- package/build/core/call/prompt.js +11 -42
- package/build/core/contract-carrier-runtime.js +209 -105
- package/build/core/contract-carrier.js +156 -73
- package/build/core/contract-view.js +42 -5
- package/build/core/contract.js +2 -1
- package/build/core/derived-replay.js +168 -35
- package/build/core/draft.js +9 -5
- package/build/core/forfeit.js +1 -1
- package/build/core/lifecycle-history.js +13 -0
- package/build/core/lifecycle-recovery.js +32 -27
- package/build/core/lifecycle-runner.js +14 -14
- package/build/core/log.js +1 -1
- package/build/core/outcome-base.js +2 -2
- package/build/core/projection/akuma-name.js +43 -0
- package/build/core/projection/generation/database.js +141 -79
- package/build/core/projection/generation/ledger.js +91 -0
- package/build/core/projection/generation/model.js +18 -13
- package/build/core/projection/generation/projection-generation-continuation.js +1 -1
- package/build/core/projection/generation/projection-generation-doorbell.js +88 -0
- package/build/core/projection/generation/projection-generation-execution.js +24 -0
- package/build/core/projection/generation/projection-generation-identity.js +4 -0
- package/build/core/projection/generation/projection-generation-launcher.js +72 -138
- package/build/core/projection/generation/projection-generation-process.js +16 -15
- package/build/core/projection/generation/projection-generation-runner.js +125 -79
- package/build/core/projection/generation/projection-generation-runtime.js +10 -61
- package/build/core/projection/generation/protocol.js +68 -0
- package/build/core/projection/generation/store.js +17 -7
- package/build/core/projection/generation/transitions.js +14 -14
- package/build/core/projection/index.js +5 -5
- package/build/core/projection/projection-core.js +6 -2
- package/build/core/projection/projection-execution-observer.js +1 -1
- package/build/core/projection/projection-history.js +7 -7
- package/build/core/projection/projection-kill.js +15 -6
- package/build/core/projection/projection-life-observer.js +8 -8
- package/build/core/projection/projection-mint.js +6 -8
- package/build/core/projection/projection-status-observation.js +77 -8
- package/build/core/projection/projection-status.js +151 -4
- package/build/core/projection/projection-wait.js +46 -27
- package/build/core/projection/projection-wake.js +27 -89
- package/build/core/projection/tell/launch-store.js +1 -1
- package/build/core/projection/tell/store.js +1 -1
- package/build/core/renew-build.js +204 -74
- package/build/core/renew-plan.js +34 -9
- package/build/core/renew-rewrite.js +56 -15
- package/build/core/renew.js +39 -35
- package/build/core/repository-ledger/accepted-fold-read.js +6 -3
- package/build/core/repository-ledger/codec.js +11 -5
- package/build/core/repository-ledger/current-state-store.js +13 -16
- package/build/core/repository-ledger/fold-repository.js +5 -6
- package/build/core/repository-ledger/identity.js +60 -0
- package/build/core/repository-ledger/inventory.js +3 -3
- package/build/core/repository-ledger/read-model.js +54 -6
- package/build/core/repository-ledger/write-transaction.js +9 -4
- package/build/core/run-control/connection-bound-close.js +41 -0
- package/build/core/run-control/detached-lease-bootstrap.js +208 -0
- package/build/core/run-control/detached-process.js +14 -0
- package/build/core/run-control/index.js +6 -0
- package/build/core/{process-group.js → run-control/process-tree.js} +1 -1
- package/build/core/run-control/runner-lease.js +172 -0
- package/build/core/{sqlite-process-lifetime-lock.js → run-control/sqlite-process-lifetime-lock.js} +4 -24
- package/build/core/seal.js +44 -32
- package/build/core/settlement/claim-delivery.js +22 -9
- package/build/core/settlement/claim.js +8 -6
- package/build/core/settlement/petition-claim-gates.js +9 -8
- package/build/core/settlement/petition-head-guard.js +5 -6
- package/build/core/settlement/petition-preview.js +21 -5
- package/build/core/settlement/petition.js +51 -17
- package/build/core/settlement/settlement.js +20 -15
- package/build/core/settlement/verdict.js +2 -2
- package/build/core/settlement/verification.js +492 -364
- package/build/core/status/board.js +184 -75
- package/build/core/status/drift.js +8 -10
- package/build/core/task/board.js +1 -0
- package/build/core/task/commands.js +25 -0
- package/build/core/task/compose.js +3 -2
- package/build/core/task/document.js +102 -39
- package/build/core/task/index.js +3 -3
- package/build/core/task/settlement-git.js +1 -4
- package/build/core/task/settlement-policy.js +27 -14
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-bind-preparation.js +59 -9
- package/build/core/task/task-contract.js +2 -2
- package/build/core/task/task-store-repository.js +1 -0
- package/build/core/task/task.js +2 -2
- package/build/core/transcripts.js +4 -4
- package/build/core/verification-declaration.js +95 -0
- package/build/core/worktree-bootstrap.js +1 -1
- package/build/core/worktree-path.js +7 -11
- package/build/flow-error.js +9 -1
- package/build/generated/version.js +2 -2
- package/build/git/branches.js +41 -70
- package/build/git/commits.js +92 -21
- package/build/git/core.js +9 -161
- package/build/git/diff/preview.js +4 -4
- package/build/git/diff/read.js +4 -4
- package/build/git/diff/structured.js +5 -5
- package/build/git/process.js +229 -0
- package/build/git/refs.js +30 -5
- package/build/git/staging.js +39 -115
- package/build/git/streaming-batch.js +9 -16
- package/build/git/worktree.js +104 -91
- package/build/index.js +7 -0
- package/package.json +1 -1
- package/skills/keiyaku-akuma/SKILL.md +21 -20
- package/skills/keiyaku-task/SKILL.md +38 -4
- package/skills/keiyaku-workflow/SKILL.md +51 -11
- package/build/cli/commands/projection/revive/meta.js +0 -12
- package/build/core/projection/projection-life-protocol.js +0 -115
- package/build/core/projection/projection-runner-lock.js +0 -211
- package/build/core/projection/tell/database.js +0 -127
- package/build/core/settlement/verification-coordination.js +0 -305
- package/build/core/settlement/verification-supervisor.js +0 -275
|
@@ -2,18 +2,11 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { FlowError, asMessage } from "../../flow-error.js";
|
|
5
|
-
import {
|
|
5
|
+
import { requireCommitCoordinate } from "../../git/commits.js";
|
|
6
|
+
import { createGit } from "../../git/core.js";
|
|
6
7
|
import { readStructuredDiff } from "../../git/diff/structured.js";
|
|
7
8
|
import { abortDetachedRenewChain, buildDetachedRenewChain, renewScratchName } from "../renew-rewrite.js";
|
|
8
9
|
import { isBootstrapSuccess, runWorktreeBootstrap } from "../worktree-bootstrap.js";
|
|
9
|
-
async function resolveObject(cwd, revision, kind) {
|
|
10
|
-
try {
|
|
11
|
-
return (await createGit(cwd).raw(["rev-parse", "--verify", `${revision}^{${kind}}`])).trim();
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
throw wrapGitError(`rev-parse ${revision}^{${kind}}`, error, cwd);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
10
|
export async function createAuditCandidate(input) {
|
|
18
11
|
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "keiyaku-audit-"));
|
|
19
12
|
const git = createGit(input.root);
|
|
@@ -30,7 +23,8 @@ export async function createAuditCandidate(input) {
|
|
|
30
23
|
const rewrite = await buildDetachedRenewChain({
|
|
31
24
|
cwd,
|
|
32
25
|
scratchName,
|
|
33
|
-
observedLedgerHead: input.frozen.
|
|
26
|
+
observedLedgerHead: input.frozen.repository.observedLedgerHead,
|
|
27
|
+
lifecycleHead: input.frozen.lifecycle.contractHead,
|
|
34
28
|
deliveryRef: input.frozen.coordinates.delivery.ref,
|
|
35
29
|
targetRef: input.frozen.coordinates.target.ref,
|
|
36
30
|
effectiveScope: input.frozen.scope,
|
|
@@ -44,8 +38,8 @@ export async function createAuditCandidate(input) {
|
|
|
44
38
|
return { cwd, rehearsal: { status: "conflict", paths: [...rewrite.conflictPaths], pathCapture: "captured" }, candidate: null };
|
|
45
39
|
}
|
|
46
40
|
await candidateGit.raw(["reset", "--hard", rewrite.newHead]);
|
|
47
|
-
const
|
|
48
|
-
return { cwd, rehearsal: { status: "clean", oldBase: input.frozen.base, newBase: input.frozen.coordinates.target.head, oldHead: input.frozen.coordinates.delivery.head }, candidate: { base: input.frozen.coordinates.target.head, head, tree, rewritten: true } };
|
|
41
|
+
const coordinate = await requireCommitCoordinate(cwd, "HEAD");
|
|
42
|
+
return { cwd, rehearsal: { status: "clean", oldBase: input.frozen.base, newBase: input.frozen.coordinates.target.head, oldHead: input.frozen.coordinates.delivery.head }, candidate: { base: input.frozen.coordinates.target.head, head: coordinate.commit, tree: coordinate.tree, rewritten: true } };
|
|
49
43
|
}
|
|
50
44
|
catch (error) {
|
|
51
45
|
return { cwd, rehearsal: { status: "unknown", cause: { code: error instanceof FlowError ? error.code : "INTERNAL_STATE", message: asMessage(error) } }, candidate: null };
|
|
@@ -59,13 +53,11 @@ export async function readAuditCandidateDiff(candidateResult) {
|
|
|
59
53
|
return readStructuredDiff(candidateResult.cwd, candidate.base, candidate.head);
|
|
60
54
|
}
|
|
61
55
|
async function readCandidateIntegrity(cwd) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
resolveObject(cwd, "HEAD", "tree"),
|
|
66
|
-
git.raw(["status", "--porcelain=v1", "-z", "--untracked-files=no"]),
|
|
56
|
+
const [coordinate, status] = await Promise.all([
|
|
57
|
+
requireCommitCoordinate(cwd, "HEAD"),
|
|
58
|
+
createGit(cwd).raw(["status", "--porcelain=v1", "-z", "--untracked-files=no"]),
|
|
67
59
|
]);
|
|
68
|
-
return { head, tree, trackedChanges: status.split("\0").filter(Boolean) };
|
|
60
|
+
return { head: coordinate.commit, tree: coordinate.tree, trackedChanges: status.split("\0").filter(Boolean) };
|
|
69
61
|
}
|
|
70
62
|
function preparationPlan(plan) {
|
|
71
63
|
return { command: [...plan.command], timeoutMs: plan.timeoutMs };
|
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { FlowError, asMessage } from "../../flow-error.js";
|
|
5
|
+
import { requireCommitCoordinate } from "../../git/commits.js";
|
|
5
6
|
import { createGit, wrapGitError } from "../../git/core.js";
|
|
6
7
|
import { effectiveCriteria } from "../amendment-criteria.js";
|
|
7
8
|
import { hasStrandableProjectionGeneration } from "../projection/index.js";
|
|
@@ -9,15 +10,7 @@ import { admitRepositoryLifecycleContract, } from "../repository-ledger/admissio
|
|
|
9
10
|
import { lookupCurrentContract, readRepositoryLifecycle, } from "../repository-ledger/read-model.js";
|
|
10
11
|
import { deriveQueueReadModel, queueMembership } from "../settlement/queue.js";
|
|
11
12
|
import { findRegisteredContractWorktreePathFromModel } from "../worktree-path.js";
|
|
12
|
-
|
|
13
|
-
const git = createGit(cwd);
|
|
14
|
-
try {
|
|
15
|
-
return (await git.raw(["rev-parse", "--verify", `${revision}^{${kind}}`])).trim();
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
throw wrapGitError(`rev-parse ${revision}^{${kind}}`, error, cwd);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
13
|
+
import { readRemainingTaskNeedsForSettlement } from "../task/settlement-policy.js";
|
|
21
14
|
export function appendedScopeTerms(model) {
|
|
22
15
|
return model.history.flatMap(({ entry }) => entry.kind === "amend" && entry.data.scopeDelta ? entry.data.scopeDelta.add : []);
|
|
23
16
|
}
|
|
@@ -63,17 +56,17 @@ async function pinLedgerCoordinates(input) {
|
|
|
63
56
|
const bind = model.history.find(({ entry }) => entry.kind === "bind")?.entry;
|
|
64
57
|
if (!bind || bind.kind !== "bind")
|
|
65
58
|
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} is missing folded bind terms`);
|
|
66
|
-
const [
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
const [delivery, target] = await Promise.all([
|
|
60
|
+
requireCommitCoordinate(input.root, model.resources.deliveryRef),
|
|
61
|
+
requireCommitCoordinate(input.root, model.pins.target.ref),
|
|
69
62
|
]);
|
|
70
|
-
if (model.pins.target.approvedHead !== null && model.petition.state === "approved" && model.pins.target.approvedHead !==
|
|
63
|
+
if (model.pins.target.approvedHead !== null && model.petition.state === "approved" && model.pins.target.approvedHead !== target.commit) {
|
|
71
64
|
throw new FlowError("INTERNAL_STATE", `target ref ${model.pins.target.ref} moved from approved petition pin`);
|
|
72
65
|
}
|
|
73
66
|
return {
|
|
74
67
|
criteria: auditCriteria(model), scope: [...model.effectiveScope], appendScope: appendedScopeTerms(model), base: model.pins.base,
|
|
75
68
|
lifecycle: model, repository,
|
|
76
|
-
coordinates: { ledger: { head: repository.observedLedgerHead }, delivery: { ref: model.resources.deliveryRef, head:
|
|
69
|
+
coordinates: { ledger: { head: repository.observedLedgerHead }, delivery: { ref: model.resources.deliveryRef, head: delivery.commit, tree: delivery.tree }, target: { ref: model.pins.target.ref, head: target.commit, tree: target.tree } },
|
|
77
70
|
};
|
|
78
71
|
}
|
|
79
72
|
async function deliveryResidue(cwd) {
|
|
@@ -123,8 +116,8 @@ async function residueFingerprint(cwd, residue) {
|
|
|
123
116
|
return digest.digest("hex");
|
|
124
117
|
}
|
|
125
118
|
async function deliveryCoordinate(cwd) {
|
|
126
|
-
const [
|
|
127
|
-
return { head, tree, residue, residueFingerprint: await residueFingerprint(cwd, residue) };
|
|
119
|
+
const [coordinate, residue] = await Promise.all([requireCommitCoordinate(cwd, "HEAD"), deliveryResidue(cwd)]);
|
|
120
|
+
return { head: coordinate.commit, tree: coordinate.tree, residue, residueFingerprint: await residueFingerprint(cwd, residue) };
|
|
128
121
|
}
|
|
129
122
|
async function checkedOutRef(cwd) {
|
|
130
123
|
try {
|
|
@@ -146,7 +139,7 @@ async function receiptsAfterPinnedFence(input) {
|
|
|
146
139
|
}
|
|
147
140
|
async function readReadiness(input) {
|
|
148
141
|
const model = input.frozen.lifecycle;
|
|
149
|
-
const [residue, looseCommits, queue, liveProjection,
|
|
142
|
+
const [residue, looseCommits, queue, liveProjection, afterDependencies, taskNeeds] = await Promise.all([
|
|
150
143
|
deliveryResidue(input.deliveryCwd), receiptsAfterPinnedFence({ root: input.root, model, deliveryHead: input.frozen.coordinates.delivery.head }), Promise.resolve(deriveQueueReadModel(input.frozen.repository)),
|
|
151
144
|
hasStrandableProjectionGeneration({ cwd: input.root, commissionId: input.contractId, deliveryWorktree: input.deliveryCwd, nowMs: Date.now() }),
|
|
152
145
|
Promise.resolve(model.causal.after.map((id) => {
|
|
@@ -154,7 +147,9 @@ async function readReadiness(input) {
|
|
|
154
147
|
const state = outcome.status === "healthy" ? outcome.model.phase : outcome.status;
|
|
155
148
|
return { id, satisfied: outcome.status === "healthy" && (state === "claimed" || state === "forfeited"), state };
|
|
156
149
|
})),
|
|
150
|
+
readRemainingTaskNeedsForSettlement(input.root, model.causal.needs),
|
|
157
151
|
]);
|
|
152
|
+
const dependencies = [...afterDependencies, ...taskNeeds];
|
|
158
153
|
const membership = queueMembership(queue, input.contractId);
|
|
159
154
|
return { deliveryResidue: residue, arc: { open: model.phase === "active" ? model.intent.arc : null, max: model.intent.arc, fence: model.pins.delivery, looseCommits }, rewriteGuard: { liveProjection }, dependencies, petition: { state: model.phase, queue: membership ? { position: membership.position, length: membership.queueLength, head: membership.queueHead, diagnostics: membership.diagnostics.map((item) => item.kind) } : null } };
|
|
160
155
|
}
|
|
@@ -133,14 +133,16 @@ export async function evaluateVerification(input) {
|
|
|
133
133
|
const plan = input.plan;
|
|
134
134
|
if (plan.length === 0)
|
|
135
135
|
return { status: "not_configured", results: [] };
|
|
136
|
-
const
|
|
137
|
-
|
|
136
|
+
const invocation = await runVerificationPlan({ cwd: input.cwd, candidate: { head: input.candidate.head, tree: input.candidate.tree }, plan, signal: input.signal, root: input.root });
|
|
137
|
+
// runId is addressable immediately; owner await cancels on abort and observes terminal cleanup.
|
|
138
|
+
const completion = await invocation.awaitTerminal();
|
|
139
|
+
const results = completion.results.map((result) => {
|
|
138
140
|
const common = { source: result.source, declaration: result.declaration, label: result.label, executor: result.executor, command: result.command, argv: [result.command, ...result.args], candidate: result.candidate };
|
|
139
141
|
if (result.execution.status === "runner_failed")
|
|
140
142
|
return { ...common, ...result.execution };
|
|
141
143
|
return { status: "executed", ...common, body: result.shell ? result.command : result.args.at(-1) ?? "", exitCode: result.execution.code, durationMs: result.execution.durationMs, stdout: result.execution.stdout, stderr: result.execution.stderr };
|
|
142
144
|
});
|
|
143
|
-
return { status: "evaluated", results };
|
|
145
|
+
return { status: "evaluated", runId: completion.runId, results };
|
|
144
146
|
}
|
|
145
147
|
export async function collectEvidence(input) {
|
|
146
148
|
const candidate = input.candidateResult.candidate;
|
|
@@ -150,5 +152,5 @@ export async function collectEvidence(input) {
|
|
|
150
152
|
return null;
|
|
151
153
|
const diff = input.diff;
|
|
152
154
|
const scope = await evaluateScope({ cwd: input.candidateResult.cwd, frozen: input.frozen, diff });
|
|
153
|
-
return { diff, scope, presentation: presentDiff({ diff, scope, budget: input.diffBudgetBytes, retrievalCoordinates: { from: input.frozen.base, to: input.frozen.coordinates.delivery.head } }), files: fileFacts(diff, scope), verification: input.verificationOverride ?? await evaluateVerification({ cwd: input.candidateResult.cwd,
|
|
155
|
+
return { diff, scope, presentation: presentDiff({ diff, scope, budget: input.diffBudgetBytes, retrievalCoordinates: { from: input.frozen.base, to: input.frozen.coordinates.delivery.head } }), files: fileFacts(diff, scope), verification: input.verificationOverride ?? await evaluateVerification({ cwd: input.candidateResult.cwd, root: input.root, candidate, plan: input.verificationPlan, signal: input.signal }), candidate };
|
|
154
156
|
}
|
|
@@ -3,11 +3,11 @@ import { completeAuditCoordinates, initialCoordinateRace, pinAuditSnapshot, rere
|
|
|
3
3
|
import { collectEvidence, resolveAuditVerificationPlan } from "./evidence.js";
|
|
4
4
|
import { collectFindings, emptyRaceReport } from "./report.js";
|
|
5
5
|
import { readinessFromFacts } from "./readiness.js";
|
|
6
|
+
import { effectiveVerification } from "../lifecycle-history.js";
|
|
6
7
|
export async function auditContract(input) {
|
|
7
8
|
const contractId = input.address.binding.commissionId;
|
|
8
9
|
const frozenSnapshot = await pinAuditSnapshot({ address: input.address });
|
|
9
|
-
const
|
|
10
|
-
const contractVerification = bind?.kind === "bind" ? bind.data.verification : [];
|
|
10
|
+
const contractVerification = effectiveVerification(frozenSnapshot.lifecycle.history.map(({ entry }) => entry));
|
|
11
11
|
const admission = {
|
|
12
12
|
frozen: frozenSnapshot,
|
|
13
13
|
contractVerification,
|
|
@@ -43,7 +43,7 @@ export async function auditContract(input) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
const diff = await readAuditCandidateDiff(candidateResult);
|
|
46
|
-
evidence = await collectEvidence({ candidateResult, frozen, diff, diffBudgetBytes: input.diffBudgetBytes ?? 32_000, verificationPlan, signal: input.signal,
|
|
46
|
+
evidence = await collectEvidence({ candidateResult, frozen, diff, diffBudgetBytes: input.diffBudgetBytes ?? 32_000, verificationPlan, signal: input.signal, root: input.address.repo.stableRoot, ...(verificationOverride ? { verificationOverride } : {}) });
|
|
47
47
|
verification = evidence?.verification ?? verificationOverride ?? { status: "not_evaluated", reason: candidateResult.rehearsal.status === "conflict" ? "renew_conflict" : "renew_unknown", results: [] };
|
|
48
48
|
await input.afterEvidence?.();
|
|
49
49
|
}
|
|
@@ -8,7 +8,7 @@ export function collectFindings(input) {
|
|
|
8
8
|
if (input.rehearsal.status === "unknown")
|
|
9
9
|
findings.push({ code: "RENEW_UNKNOWN", detail: `${input.rehearsal.cause.code}: ${input.rehearsal.cause.message}`, nextCommand: `${selector} audit` });
|
|
10
10
|
for (const row of input.scope?.filter((item) => item.class === "violated") ?? [])
|
|
11
|
-
findings.push({ code: "SCOPE_RESIDUE", detail: `${row.path}: ${row.residue.length} unexplained changes`, nextCommand: `${selector} amend --scope-add ${JSON.stringify(row.path)}` });
|
|
11
|
+
findings.push({ code: "SCOPE_RESIDUE", severity: "warning", detail: `${row.path}: ${row.residue.length} unexplained changes`, nextCommand: `${selector} amend --scope-add ${JSON.stringify(row.path)}` });
|
|
12
12
|
if (input.candidatePreparation.status === "failed")
|
|
13
13
|
findings.push({ code: "CANDIDATE_PREPARATION_FAILED", detail: `${input.candidatePreparation.cause.code}: ${input.candidatePreparation.cause.message}`, nextCommand: `${selector} audit` });
|
|
14
14
|
if (input.verification.status === "evaluated") {
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import { FlowError } from "../flow-error.js";
|
|
2
2
|
import { access } from "node:fs/promises";
|
|
3
|
-
import { lookupCurrentContract, readRepositoryLifecycle } from "./repository-ledger/read-model.js";
|
|
4
|
-
import { withContractCarrierSession } from "./contract-carrier.js";
|
|
5
|
-
import {
|
|
3
|
+
import { lookupCurrentContract, readRepositoryLifecycle, } from "./repository-ledger/read-model.js";
|
|
4
|
+
import { withContractCarrierSession, withObservedContractCarrierSession } from "./contract-carrier.js";
|
|
5
|
+
import { contractWorktreePathFromStableRoot, findRegisteredContractWorktreePathFromModel } from "./worktree-path.js";
|
|
6
6
|
import { defaultCreateWorktree } from "./bind-workspace.js";
|
|
7
7
|
import { isCommissionId } from "./ids.js";
|
|
8
8
|
import { REPOSITORY_LEDGER_REF, repositoryDeliveryRef } from "./repository-ledger/codec.js";
|
|
9
9
|
import { resolveLocalBranchHead } from "../git/refs.js";
|
|
10
10
|
import { runWorktreeBootstrap, bootstrapEntryDataFromObservation, isBootstrapSuccess } from "./worktree-bootstrap.js";
|
|
11
11
|
import { committedLifecycleFacts, containedCommittedLifecycleFacts, EffectJournal } from "./outcome-base.js";
|
|
12
|
+
/**
|
|
13
|
+
* Repository admission can only recover a bind whose authority remains active.
|
|
14
|
+
* A terminal contract may retain its historical bootstrap disposition, but its
|
|
15
|
+
* projection is addressed recovery work and must not be adopted by another bind.
|
|
16
|
+
*/
|
|
17
|
+
export function requiresBindRecovery(lifecycle) {
|
|
18
|
+
if (lifecycle.phase !== "active")
|
|
19
|
+
return false;
|
|
20
|
+
return lifecycle.bootstrapReplay.state === "pending" || lifecycle.bootstrapReplay.state === "failed-interrupted";
|
|
21
|
+
}
|
|
12
22
|
export async function publishBindBootstrap(session, entry, expectedLedgerHead) {
|
|
13
|
-
return await session.publishAuthoritative({ verb: "bootstrap", admittedLedgerHead: expectedLedgerHead, acceptedLifecycleTail: session.lifecycle.
|
|
23
|
+
return await session.publishAuthoritative({ verb: "bootstrap", admittedLedgerHead: expectedLedgerHead, acceptedLifecycleTail: session.lifecycle.contractHead, entries: [entry] });
|
|
14
24
|
}
|
|
15
25
|
export async function publishBindFailedForfeit(session, entry, delivery, expectedLedgerHead) {
|
|
16
26
|
return await session.publishAuthoritative({
|
|
17
27
|
verb: "forfeit",
|
|
18
28
|
admittedLedgerHead: expectedLedgerHead,
|
|
19
|
-
acceptedLifecycleTail: session.lifecycle.
|
|
29
|
+
acceptedLifecycleTail: session.lifecycle.contractHead,
|
|
20
30
|
entries: [entry],
|
|
21
31
|
delivery: {
|
|
22
32
|
ref: repositoryDeliveryRef(entry.contract),
|
|
@@ -40,7 +50,7 @@ function copyAcceptedBindEntry(entry) {
|
|
|
40
50
|
...(entry.data.taskIds ? { taskIds: [...entry.data.taskIds] } : {}),
|
|
41
51
|
};
|
|
42
52
|
return {
|
|
43
|
-
v:
|
|
53
|
+
v: 3,
|
|
44
54
|
kind: "bind",
|
|
45
55
|
contract: entry.contract,
|
|
46
56
|
at: entry.at,
|
|
@@ -76,18 +86,6 @@ function bootstrapProgressLine(command) {
|
|
|
76
86
|
function workspaceBindView(entry) {
|
|
77
87
|
return entry;
|
|
78
88
|
}
|
|
79
|
-
export async function revalidateBindAuthority(input) {
|
|
80
|
-
const [target, delivery] = await Promise.all([
|
|
81
|
-
resolveLocalBranchHead(input.cwd, input.target),
|
|
82
|
-
resolveLocalBranchHead(input.cwd, input.deliveryRef),
|
|
83
|
-
]);
|
|
84
|
-
if (target?.head !== input.targetHead) {
|
|
85
|
-
throw new FlowError("CONCURRENT_MODIFICATION", `bind target changed from ${input.targetHead}`);
|
|
86
|
-
}
|
|
87
|
-
if (delivery !== null) {
|
|
88
|
-
throw new FlowError("CONCURRENT_MODIFICATION", `bind delivery ref already exists: ${input.deliveryRef}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
89
|
export function committedOrThrow(result, operation) {
|
|
92
90
|
if (result.family === "committed")
|
|
93
91
|
return result;
|
|
@@ -163,6 +161,18 @@ function bindSurfaceReceipts(journal) {
|
|
|
163
161
|
}
|
|
164
162
|
return receipts;
|
|
165
163
|
}
|
|
164
|
+
export async function reconcileCommittedBindFromSnapshot(input, admittedScopeOverlaps, snapshot) {
|
|
165
|
+
const result = await withObservedContractCarrierSession({
|
|
166
|
+
stableRoot: snapshot.stableRoot,
|
|
167
|
+
contractId: input.contractId,
|
|
168
|
+
observation: snapshot.observation,
|
|
169
|
+
signal: input.signal,
|
|
170
|
+
...(input.terminalWorkspaceCleanup ? { terminalWorkspaceCleanup: input.terminalWorkspaceCleanup } : {}),
|
|
171
|
+
}, async (session) => reconcileBindContractLocked({ ...input, cwd: snapshot.stableRoot }, session, admittedScopeOverlaps));
|
|
172
|
+
if (!("continueAfterFailedBootstrap" in result))
|
|
173
|
+
return result;
|
|
174
|
+
return reconcileCommittedBind(input, admittedScopeOverlaps);
|
|
175
|
+
}
|
|
166
176
|
/**
|
|
167
177
|
* Sole replay-only entry for a committed bind. It never allocates identity or
|
|
168
178
|
* reads draft input; every coordinate is reconstructed from the accepted bind.
|
|
@@ -186,11 +196,11 @@ export async function reconcileCommittedBind(input, admittedScopeOverlaps) {
|
|
|
186
196
|
throw new FlowError("INTERNAL_STATE", `bind-failed finalization for ${input.contractId} did not settle after bootstrap re-admission`);
|
|
187
197
|
}
|
|
188
198
|
async function reconcileBindContractLocked(input, replaySession, admittedScopeOverlaps) {
|
|
189
|
-
const stableRoot =
|
|
199
|
+
const stableRoot = replaySession.stableRoot;
|
|
190
200
|
if (!isCommissionId(input.contractId)) {
|
|
191
201
|
throw new FlowError("INVALID_TARGET", `bind replay requires a full canonical contract id; got ${input.contractId}`);
|
|
192
202
|
}
|
|
193
|
-
const initialRead =
|
|
203
|
+
const initialRead = replaySession.repository;
|
|
194
204
|
const outcome = lookupCurrentContract(initialRead, input.contractId);
|
|
195
205
|
if (outcome.status === "absent")
|
|
196
206
|
throw new FlowError("CONTRACT_NOT_FOUND", `contract ${input.contractId} not found`);
|
|
@@ -213,7 +223,7 @@ async function reconcileBindContractLocked(input, replaySession, admittedScopeOv
|
|
|
213
223
|
const entry = copyAcceptedBindEntry(bindRow.entry);
|
|
214
224
|
const workspace = entry.data.workspace;
|
|
215
225
|
const branch = `keiyaku/${entry.contract}`;
|
|
216
|
-
const worktreePath =
|
|
226
|
+
const worktreePath = contractWorktreePathFromStableRoot(stableRoot, entry.contract, workspaceBindView(entry));
|
|
217
227
|
const targetRoot = workspace === "here" ? stableRoot : worktreePath;
|
|
218
228
|
const deps = input.dependencies ?? {};
|
|
219
229
|
const heads = {
|
|
@@ -231,12 +241,21 @@ async function reconcileBindContractLocked(input, replaySession, admittedScopeOv
|
|
|
231
241
|
let containedCause;
|
|
232
242
|
const rememberFailure = (row) => { containedCause ??= effectCause(row); };
|
|
233
243
|
const scopeOverlaps = [...admittedScopeOverlaps];
|
|
244
|
+
if (input.preparedTask && input.preparedTaskProjectionSucceeded) {
|
|
245
|
+
replaySession.journal.beginDerivedReplay();
|
|
246
|
+
replaySession.journal.record({
|
|
247
|
+
effect: "task-board-projection",
|
|
248
|
+
idempotencyKey: `${entry.contract}:${outcome.model.contractHead}:task-board`,
|
|
249
|
+
status: "succeeded",
|
|
250
|
+
receipt: { surface: "task-board", status: "created", authoritativeHead: outcome.model.contractHead, facts: { taskCount: input.preparedTask.taskIds.length } },
|
|
251
|
+
});
|
|
252
|
+
}
|
|
234
253
|
const bootstrapPlan = entry.data.workspace === "worktree" ? entry.data.bootstrap : undefined;
|
|
235
254
|
if (!replayingBindFailedTerminal && bootstrapPlan) {
|
|
236
255
|
const worktreeReplay = await journal.run({
|
|
237
256
|
effect: "bootstrap-worktree-prerequisite",
|
|
238
257
|
run: async () => {
|
|
239
|
-
const registered = await
|
|
258
|
+
const registered = await findRegisteredContractWorktreePathFromModel(stableRoot, outcome.model);
|
|
240
259
|
if (registered === worktreePath)
|
|
241
260
|
return { status: "already-present", path: worktreePath };
|
|
242
261
|
try {
|
|
@@ -261,7 +280,7 @@ async function reconcileBindContractLocked(input, replaySession, admittedScopeOv
|
|
|
261
280
|
: undefined;
|
|
262
281
|
let publishedFailedBootstrapThroughSession = false;
|
|
263
282
|
if (bootstrapPlan) {
|
|
264
|
-
const locked = lookupCurrentContract(
|
|
283
|
+
const locked = lookupCurrentContract(replaySession.repository, entry.contract);
|
|
265
284
|
if (locked.status !== "healthy")
|
|
266
285
|
throw new FlowError("INTERNAL_STATE", `contract ${entry.contract} became unavailable during bootstrap replay`);
|
|
267
286
|
const existingBootstrap = locked.model.history.find((row) => row.entry.kind === "bootstrap")?.entry;
|