@astrosheep/keiyaku 2.9.8 → 2.9.10
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 +50 -182
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +10 -7
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +242 -79
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +65 -29
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +13 -35
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +45 -69
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +24 -1
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +13 -6
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +29 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +35 -337
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +125 -127
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- package/build/core/status/reconciliation.js +0 -137
package/build/core/seal.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { FlowError } from "../flow-error.js";
|
|
2
2
|
import { createGit, parseRevListOutput, wrapGitError } from "../git/core.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
3
|
+
import { effectiveScope } from "./lifecycle-history.js";
|
|
4
|
+
import { scopePathEvidence, } from "./scope.js";
|
|
5
|
+
import { isTerminalState } from "./status/lifecycle.js";
|
|
6
|
+
import { currentLifecycleState, lookupCurrentContract, readRepositoryLifecycle, } from "./repository-ledger/read-model.js";
|
|
7
|
+
import { runLifecycle } from "./lifecycle-runner.js";
|
|
8
|
+
import { taskNamespaceFromScope } from "./task/coordinate.js";
|
|
9
|
+
export { effectiveScope } from "./lifecycle-history.js";
|
|
10
10
|
function findBind(entries) {
|
|
11
11
|
const bind = entries.find((entry) => entry.kind === "bind");
|
|
12
12
|
if (!bind)
|
|
@@ -41,17 +41,6 @@ export function getFence(entries) {
|
|
|
41
41
|
export async function receiptsAfterFence(cwd, entries, head = "HEAD") {
|
|
42
42
|
return revList(cwd, getFence(entries), await resolveCommit(cwd, head));
|
|
43
43
|
}
|
|
44
|
-
export function effectiveScope(entries) {
|
|
45
|
-
const scope = [...findBind(entries).data.scope];
|
|
46
|
-
for (const entry of entries) {
|
|
47
|
-
if (entry.kind !== "amend" || !entry.data.scopeDelta)
|
|
48
|
-
continue;
|
|
49
|
-
for (const pattern of entry.data.scopeDelta.add) {
|
|
50
|
-
scope.push(pattern);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return scope;
|
|
54
|
-
}
|
|
55
44
|
async function resolveCommit(cwd, revision) {
|
|
56
45
|
const git = createGit(cwd);
|
|
57
46
|
try {
|
|
@@ -100,12 +89,37 @@ async function diffstat(cwd, from, to) {
|
|
|
100
89
|
}
|
|
101
90
|
}
|
|
102
91
|
async function scopeViolations(cwd, paths, scope) {
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
return (await scopePathEvidence(cwd, scope, paths)).filter((evidence) => !evidence.matched);
|
|
93
|
+
}
|
|
94
|
+
function taskNamespaceViolations(paths, scope) {
|
|
95
|
+
const taskPaths = paths.filter((path) => path.startsWith(".keiyaku/tasks/"));
|
|
96
|
+
if (taskPaths.length === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const namespaces = scope.flatMap((term) => taskNamespaceFromScope(term) ?? []);
|
|
99
|
+
if (namespaces.length !== 1) {
|
|
100
|
+
throw new FlowError("INTERNAL_STATE", "accepted bind must carry exactly one contract task namespace");
|
|
101
|
+
}
|
|
102
|
+
const prefix = `.keiyaku/tasks/${namespaces[0]}/`;
|
|
103
|
+
return taskPaths
|
|
104
|
+
.filter((path) => !path.startsWith(prefix))
|
|
105
|
+
.map((path) => ({ path, patterns: [], matched: false, outcome: "no-positive-match" }));
|
|
106
|
+
}
|
|
107
|
+
async function acceptedBindScope(cwd, contract) {
|
|
108
|
+
const outcome = lookupCurrentContract(await readRepositoryLifecycle(cwd), contract);
|
|
109
|
+
if (outcome.status !== "healthy") {
|
|
110
|
+
throw new FlowError("INTERNAL_STATE", `cannot resolve accepted bind namespace for contract ${contract}`);
|
|
111
|
+
}
|
|
112
|
+
const bind = outcome.model.history.find(({ entry }) => entry.kind === "bind")?.entry;
|
|
113
|
+
if (!bind || bind.kind !== "bind")
|
|
114
|
+
throw new FlowError("INTERNAL_STATE", `contract ${contract} has no accepted bind entry`);
|
|
115
|
+
return bind.data.scope;
|
|
105
116
|
}
|
|
106
117
|
async function auditScope(cwd, entries, paths) {
|
|
107
118
|
const scope = effectiveScope(entries);
|
|
108
|
-
const scopeViolationEvidence =
|
|
119
|
+
const scopeViolationEvidence = [
|
|
120
|
+
...await scopeViolations(cwd, paths, scope),
|
|
121
|
+
...taskNamespaceViolations(paths, findBind(entries).data.scope),
|
|
122
|
+
].filter((row, index, all) => all.findIndex((candidate) => candidate.path === row.path) === index);
|
|
109
123
|
if (scopeViolationEvidence.length > 0) {
|
|
110
124
|
throw new ScopeAuditError(findBind(entries).contract, scope, scopeViolationEvidence);
|
|
111
125
|
}
|
|
@@ -115,29 +129,6 @@ async function auditScope(cwd, entries, paths) {
|
|
|
115
129
|
scopeViolationEvidence,
|
|
116
130
|
};
|
|
117
131
|
}
|
|
118
|
-
const APPEND_SCOPE_AMENDMENT = "Scope extended by lifecycle command.";
|
|
119
|
-
export async function appendScopeTerms(input) {
|
|
120
|
-
if (!input.patterns || input.patterns.length === 0)
|
|
121
|
-
return null;
|
|
122
|
-
const patterns = input.patterns.map(normalizeScopePattern);
|
|
123
|
-
const at = new Date(input.nowMs).toISOString();
|
|
124
|
-
const result = await appendWithRetry(input.cwd, activeLedgerRef(input.contractId), (_head, entries) => {
|
|
125
|
-
assertOperable(input.contractId, entries);
|
|
126
|
-
return {
|
|
127
|
-
v: 1,
|
|
128
|
-
kind: "amend",
|
|
129
|
-
contract: input.contractId,
|
|
130
|
-
at,
|
|
131
|
-
actor: input.actor,
|
|
132
|
-
data: { amendment: APPEND_SCOPE_AMENDMENT, scopeDelta: { add: patterns } },
|
|
133
|
-
};
|
|
134
|
-
});
|
|
135
|
-
if (!result.ok) {
|
|
136
|
-
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} active ledger disappeared while appending scope`);
|
|
137
|
-
}
|
|
138
|
-
await refreshContractView({ ledgerCwd: input.cwd, renderCwd: input.renderCwd, contractId: input.contractId });
|
|
139
|
-
return result.head;
|
|
140
|
-
}
|
|
141
132
|
export class ScopeAuditError extends FlowError {
|
|
142
133
|
scopeViolationEvidence;
|
|
143
134
|
constructor(_contractId, scope, evidence) {
|
|
@@ -154,15 +145,38 @@ export class ScopeAuditError extends FlowError {
|
|
|
154
145
|
this.scopeViolationEvidence = evidence;
|
|
155
146
|
}
|
|
156
147
|
}
|
|
157
|
-
function assertOperable(contractId,
|
|
158
|
-
const state =
|
|
159
|
-
if (state.state === "corrupt") {
|
|
160
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} is corrupt at entry ${state.at}: ${state.reason}`);
|
|
161
|
-
}
|
|
148
|
+
function assertOperable(contractId, model) {
|
|
149
|
+
const state = currentLifecycleState(model);
|
|
162
150
|
if (isTerminalState(state) || state.state === "petitioned") {
|
|
163
151
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot seal from state ${state.state}`);
|
|
164
152
|
}
|
|
165
153
|
}
|
|
154
|
+
function currentFoldedSealArc(model) {
|
|
155
|
+
return model.seal === null ? model.intent.arc : null;
|
|
156
|
+
}
|
|
157
|
+
/** Current-read admission capture: scope and fence come only from the folded model. */
|
|
158
|
+
export async function captureFoldedSeal(cwd, model, head = "HEAD", scopeAppend = []) {
|
|
159
|
+
const arc = currentFoldedSealArc(model);
|
|
160
|
+
if (arc === null)
|
|
161
|
+
return null;
|
|
162
|
+
const oldFence = model.pins.delivery;
|
|
163
|
+
const newFence = await resolveCommit(cwd, head);
|
|
164
|
+
const [receipts, paths, stat] = await Promise.all([
|
|
165
|
+
revList(cwd, oldFence, newFence),
|
|
166
|
+
changedPaths(cwd, oldFence, newFence),
|
|
167
|
+
diffstat(cwd, oldFence, newFence),
|
|
168
|
+
]);
|
|
169
|
+
const effectiveScope = [...model.effectiveScope, ...scopeAppend];
|
|
170
|
+
const bind = model.history.find((row) => row.entry.kind === "bind")?.entry;
|
|
171
|
+
const scopeViolationEvidence = [
|
|
172
|
+
...await scopeViolations(cwd, paths, effectiveScope),
|
|
173
|
+
...taskNamespaceViolations(paths, bind?.kind === "bind" ? bind.data.scope : []),
|
|
174
|
+
].filter((row, index, all) => all.findIndex((candidate) => candidate.path === row.path) === index);
|
|
175
|
+
if (scopeViolationEvidence.length > 0) {
|
|
176
|
+
throw new ScopeAuditError(model.contract, effectiveScope, scopeViolationEvidence);
|
|
177
|
+
}
|
|
178
|
+
return { arc, oldFence, newFence, receipts, diffstat: stat, scopeAudit: { violations: [] }, scopeViolationEvidence };
|
|
179
|
+
}
|
|
166
180
|
/** Current seal intent: open explicit arc, else derived a0 while no explicit arc has ever existed. */
|
|
167
181
|
export function currentSealArc(entries) {
|
|
168
182
|
const open = findOpenArc(entries);
|
|
@@ -207,12 +221,12 @@ export async function previewSeal(cwd, entries, head = "HEAD") {
|
|
|
207
221
|
export async function captureSeal(cwd, entries, head = "HEAD") {
|
|
208
222
|
return (await previewSeal(cwd, entries, head)).capture;
|
|
209
223
|
}
|
|
210
|
-
/**
|
|
211
|
-
export async function
|
|
212
|
-
|
|
213
|
-
if (arc === null)
|
|
224
|
+
/** Folded renew capture: preserve receipt hashes while auditing rebased delivery content. */
|
|
225
|
+
export async function captureFoldedRenewSeal(input) {
|
|
226
|
+
if (!input.receiptSegmentOpen)
|
|
214
227
|
return null;
|
|
215
|
-
const
|
|
228
|
+
const arc = input.intent.arc;
|
|
229
|
+
const oldFence = input.deliveryFence;
|
|
216
230
|
const [receiptHead, contentBase, contentHead] = await Promise.all([
|
|
217
231
|
resolveCommit(input.cwd, input.receiptHead),
|
|
218
232
|
resolveCommit(input.cwd, input.contentBase),
|
|
@@ -223,123 +237,116 @@ export async function captureRenewSeal(input) {
|
|
|
223
237
|
changedPaths(input.cwd, contentBase, contentHead),
|
|
224
238
|
diffstat(input.cwd, contentBase, contentHead),
|
|
225
239
|
]);
|
|
240
|
+
const scope = [...input.effectiveScope, ...input.pendingScopeOverlay];
|
|
241
|
+
const bindScope = await acceptedBindScope(input.cwd, input.contract);
|
|
242
|
+
const scopeViolationEvidence = [
|
|
243
|
+
...await scopeViolations(input.cwd, paths, scope),
|
|
244
|
+
...taskNamespaceViolations(paths, bindScope),
|
|
245
|
+
].filter((row, index, all) => all.findIndex((candidate) => candidate.path === row.path) === index);
|
|
246
|
+
if (scopeViolationEvidence.length > 0) {
|
|
247
|
+
throw new ScopeAuditError(input.contract, scope, scopeViolationEvidence);
|
|
248
|
+
}
|
|
226
249
|
return {
|
|
227
250
|
arc,
|
|
228
251
|
oldFence,
|
|
229
252
|
newFence: receiptHead,
|
|
230
253
|
receipts,
|
|
231
254
|
diffstat: stat,
|
|
232
|
-
|
|
255
|
+
scopeAudit: { violations: [] },
|
|
256
|
+
scopeViolationEvidence,
|
|
233
257
|
};
|
|
234
258
|
}
|
|
235
259
|
export async function sealCurrentArc(input) {
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} not found or not active`);
|
|
239
|
-
}
|
|
240
|
-
assertOperable(input.contractId, ledger.entries);
|
|
241
|
-
const capture = input.capture ?? await captureSeal(input.cwd, ledger.entries, "HEAD");
|
|
242
|
-
if (!capture)
|
|
243
|
-
return null;
|
|
244
|
-
const at = new Date(input.nowMs).toISOString();
|
|
245
|
-
const result = await appendWithRetry(input.cwd, activeLedgerRef(input.contractId), (_head, entries) => {
|
|
246
|
-
assertOperable(input.contractId, entries);
|
|
247
|
-
const currentArc = currentSealArc(entries);
|
|
248
|
-
if (currentArc === null)
|
|
249
|
-
return null;
|
|
250
|
-
// a0 is legal only while no explicit arc has ever existed; otherwise treat as concurrent change.
|
|
251
|
-
if (capture.arc === 0 && getMaxArc(entries) > 0) {
|
|
252
|
-
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} changed while sealing arc a${capture.arc}`);
|
|
253
|
-
}
|
|
254
|
-
if (currentArc !== capture.arc || getFence(entries) !== capture.oldFence) {
|
|
255
|
-
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} changed while sealing arc a${capture.arc}`);
|
|
256
|
-
}
|
|
257
|
-
const { scopeViolationEvidence: _scopeViolationEvidence, ...durableCapture } = capture;
|
|
258
|
-
return {
|
|
259
|
-
v: 2,
|
|
260
|
-
kind: "seal",
|
|
261
|
-
contract: input.contractId,
|
|
262
|
-
at,
|
|
263
|
-
actor: "engine",
|
|
264
|
-
data: { ...durableCapture, sealedBy: input.sealedBy },
|
|
265
|
-
};
|
|
266
|
-
});
|
|
267
|
-
if (!result.ok) {
|
|
268
|
-
throw new FlowError("INTERNAL_STATE", `failed to seal arc for ${input.contractId}: ${result.reason}`);
|
|
269
|
-
}
|
|
270
|
-
await refreshContractView({
|
|
271
|
-
ledgerCwd: input.cwd,
|
|
272
|
-
renderCwd: input.renderCwd,
|
|
260
|
+
const execution = await runLifecycle({
|
|
261
|
+
cwd: input.cwd,
|
|
273
262
|
contractId: input.contractId,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
...
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
263
|
+
mutation: {
|
|
264
|
+
verb: "seal",
|
|
265
|
+
matchesAccepted: (transaction) => {
|
|
266
|
+
const accepted = transaction.entries.at(-1);
|
|
267
|
+
if (transaction.entries.length !== 1 || accepted?.kind !== "seal" || accepted.data.sealedBy !== input.sealedBy)
|
|
268
|
+
return false;
|
|
269
|
+
if (input.capture === undefined)
|
|
270
|
+
return true;
|
|
271
|
+
if (input.capture === null)
|
|
272
|
+
return false;
|
|
273
|
+
const { scopeViolationEvidence: _evidence, ...durableCapture } = input.capture;
|
|
274
|
+
return JSON.stringify(accepted.data) === JSON.stringify({ ...durableCapture, sealedBy: input.sealedBy });
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
signal: input.signal,
|
|
278
|
+
admit: (session, replay) => {
|
|
279
|
+
assertOperable(input.contractId, session.lifecycle);
|
|
280
|
+
if (session.target.status !== "available")
|
|
281
|
+
throw new FlowError("INTERNAL_STATE", session.target.reason);
|
|
282
|
+
const transaction = replay.state === "verb-committed" ? replay.transaction : undefined;
|
|
283
|
+
const accepted = transaction?.entries.at(-1);
|
|
284
|
+
let existing;
|
|
285
|
+
if (accepted?.kind === "seal") {
|
|
286
|
+
existing = {
|
|
287
|
+
transactionObjectId: transaction.transactionObjectId,
|
|
288
|
+
capture: {
|
|
289
|
+
arc: accepted.data.arc,
|
|
290
|
+
oldFence: accepted.data.oldFence,
|
|
291
|
+
newFence: accepted.data.newFence,
|
|
292
|
+
receipts: [...accepted.data.receipts],
|
|
293
|
+
diffstat: { ...accepted.data.diffstat },
|
|
294
|
+
scopeAudit: { violations: [...accepted.data.scopeAudit.violations] },
|
|
295
|
+
scopeViolationEvidence: [],
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return { lifecycle: session.lifecycle, targetRoot: session.target.root, ...(existing ? { existing } : {}) };
|
|
300
|
+
},
|
|
301
|
+
prepare: async (admission) => {
|
|
302
|
+
if (admission.business.existing)
|
|
303
|
+
return { capture: admission.business.existing.capture, existing: { transactionObjectId: admission.business.existing.transactionObjectId } };
|
|
304
|
+
return { capture: input.capture ?? await captureFoldedSeal(admission.business.targetRoot, admission.business.lifecycle, "HEAD") };
|
|
305
|
+
},
|
|
306
|
+
revalidate: ({ session, prepared }) => {
|
|
307
|
+
assertOperable(input.contractId, session.lifecycle);
|
|
308
|
+
if (prepared.existing) {
|
|
309
|
+
return session.repository.topology.nodes.some((node) => node.objectId === prepared.existing.transactionObjectId)
|
|
310
|
+
? undefined
|
|
311
|
+
: { code: "SEAL_STATE_CHANGED", message: "accepted seal changed during replay preparation" };
|
|
312
|
+
}
|
|
313
|
+
if (!prepared.capture)
|
|
314
|
+
return;
|
|
315
|
+
const currentArc = currentFoldedSealArc(session.lifecycle);
|
|
316
|
+
if (currentArc !== prepared.capture.arc || session.lifecycle.pins.delivery !== prepared.capture.oldFence)
|
|
317
|
+
return { code: "SEAL_COORDINATES_CHANGED", message: `contract ${input.contractId} changed while sealing arc a${prepared.capture.arc}` };
|
|
318
|
+
},
|
|
319
|
+
effect: async ({ context, prepared }) => {
|
|
320
|
+
const capture = prepared.capture;
|
|
321
|
+
if (!capture)
|
|
322
|
+
return { kind: "refused-before-effects", authoritativeHead: context.session.lifecycle.observedLedgerHead, refusal: { code: "NO_OPEN_ARC", message: "no current arc requires sealing" } };
|
|
323
|
+
const at = new Date(input.nowMs).toISOString();
|
|
324
|
+
{
|
|
325
|
+
const { scopeViolationEvidence: _scopeViolationEvidence, ...durableCapture } = capture;
|
|
326
|
+
const entry = {
|
|
327
|
+
v: 2,
|
|
328
|
+
kind: "seal",
|
|
329
|
+
contract: input.contractId,
|
|
330
|
+
at,
|
|
331
|
+
actor: "engine",
|
|
332
|
+
data: { ...durableCapture, sealedBy: input.sealedBy },
|
|
333
|
+
};
|
|
334
|
+
const result = prepared.existing
|
|
335
|
+
? await context.replayCommitted({ transactionObjectId: prepared.existing.transactionObjectId })
|
|
336
|
+
: await context.publishAuthoritative({ verb: "seal", admittedLedgerHead: context.session.lifecycle.observedLedgerHead, acceptedLifecycleTail: context.session.lifecycle.history.at(-1).objectId, entries: [entry] });
|
|
337
|
+
if (result.status === "indeterminate")
|
|
338
|
+
return { kind: "precommit-effects-only", authoritativeHead: result.currentHead ?? context.session.lifecycle.observedLedgerHead };
|
|
339
|
+
if (result.status !== "committed")
|
|
340
|
+
return { kind: "refused-before-effects", authoritativeHead: result.currentHead ?? context.session.lifecycle.observedLedgerHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed while sealing` } };
|
|
341
|
+
return { kind: "committed", commit: result, entryKind: "seal", value: {
|
|
342
|
+
...capture,
|
|
343
|
+
sealedBy: input.sealedBy,
|
|
344
|
+
ledgerHead: result.transaction.entryObjectIds[result.transaction.entries.findIndex((candidate) => candidate.kind === "seal")],
|
|
345
|
+
} };
|
|
346
|
+
}
|
|
327
347
|
},
|
|
328
|
-
};
|
|
329
|
-
const message = splitLedgerMessage(renewEntry);
|
|
330
|
-
const renewHead = await createRefLogCommit(input.cwd, {
|
|
331
|
-
...message,
|
|
332
|
-
parentHead,
|
|
333
|
-
errorLabel: `ledger renew ${input.contractId}`,
|
|
334
348
|
});
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const sealed = input.capture ? {
|
|
339
|
-
...input.capture,
|
|
340
|
-
newFence: input.newHead,
|
|
341
|
-
sealedBy: "renew",
|
|
342
|
-
ledgerHead: sealHead,
|
|
343
|
-
} : null;
|
|
344
|
-
return { ledgerHead: renewHead, sealed };
|
|
349
|
+
if (execution.kind === "noncommitted" || execution.kind === "contained")
|
|
350
|
+
return execution.outcome;
|
|
351
|
+
return execution.payload;
|
|
345
352
|
}
|