@astrosheep/keiyaku 2.8.4 → 2.9.0
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 +35 -15
- package/build/.tsbuildinfo +1 -1
- package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
- package/build/agents/harness/control-types.js +1 -0
- package/build/agents/harness/execution-handle.js +23 -3
- package/build/agents/harness/index.js +6 -607
- package/build/agents/harness/outcome.js +141 -0
- package/build/agents/harness/projection.js +310 -0
- package/build/agents/harness/router.js +201 -0
- package/build/agents/harness/runtime.js +2 -1
- package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
- package/build/agents/launch-snapshot/resolve.js +72 -0
- package/build/agents/opencode-sdk.js +24 -3
- package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
- package/build/agents/providers/claude-agent-sdk/events.js +218 -0
- package/build/agents/providers/claude-agent-sdk/session.js +158 -0
- package/build/agents/providers/codex-app-server/adapter.js +347 -0
- package/build/agents/providers/codex-app-server/events.js +352 -0
- package/build/agents/providers/codex-app-server/session.js +266 -0
- package/build/agents/providers/codex-sdk.js +23 -5
- package/build/agents/providers/opencode-sdk/adapter.js +344 -0
- package/build/agents/providers/opencode-sdk/events.js +354 -0
- package/build/agents/providers/opencode-sdk/session.js +180 -0
- package/build/agents/providers/pi/adapter.js +269 -0
- package/build/agents/providers/pi/checkpoint.js +41 -0
- package/build/agents/providers/pi/events.js +282 -0
- package/build/agents/{selector_v2.js → selector.js} +8 -6
- package/build/cli/commands/akuma/akuma/handler.js +4 -0
- package/build/cli/commands/akuma/akuma/meta.js +16 -0
- package/build/cli/commands/akuma/catalog.js +8 -0
- package/build/cli/commands/akuma/list/handler.js +15 -0
- package/build/cli/commands/akuma/list/meta-ls.js +9 -0
- package/build/cli/commands/akuma/view/handler.js +34 -0
- package/build/cli/commands/akuma/view/meta.js +8 -0
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +10 -0
- package/build/cli/commands/contract/amend/meta.js +12 -0
- package/build/cli/commands/contract/arc/handler.js +9 -0
- package/build/cli/commands/contract/arc/meta.js +26 -0
- package/build/cli/commands/contract/bind/handler.js +23 -0
- package/build/cli/commands/contract/bind/meta.js +30 -0
- package/build/cli/commands/contract/catalog.js +16 -0
- package/build/cli/commands/contract/forfeit/handler.js +13 -0
- package/build/cli/commands/contract/forfeit/meta.js +12 -0
- package/build/cli/commands/contract/log/handler.js +12 -0
- package/build/cli/commands/contract/log/meta.js +12 -0
- package/build/cli/commands/contract/petition/handler.js +26 -0
- package/build/cli/commands/contract/petition/meta.js +23 -0
- package/build/cli/commands/contract/renew/handler.js +10 -0
- package/build/cli/commands/contract/renew/meta.js +17 -0
- package/build/cli/commands/projection/call/handler.js +39 -0
- package/build/cli/commands/projection/call/meta.js +9 -0
- package/build/cli/commands/projection/catalog.js +14 -0
- package/build/cli/commands/projection/kill/handler.js +35 -0
- package/build/cli/commands/projection/kill/meta.js +11 -0
- package/build/cli/commands/projection/revive/handler.js +53 -0
- package/build/cli/commands/projection/revive/meta.js +9 -0
- package/build/cli/commands/projection/status/handler.js +23 -0
- package/build/cli/commands/projection/status/meta.js +9 -0
- package/build/cli/commands/projection/tell/handler.js +34 -0
- package/build/cli/commands/projection/tell/meta.js +9 -0
- package/build/cli/commands/projection/wait/handler.js +21 -0
- package/build/cli/commands/projection/wait/meta.js +11 -0
- package/build/cli/commands/registry.js +100 -0
- package/build/cli/commands/shared.js +71 -0
- package/build/cli/commands/skills/catalog.js +6 -0
- package/build/cli/commands/skills/install/handler.js +10 -0
- package/build/cli/commands/skills/install/meta.js +9 -0
- package/build/cli/commands/skills/skills/handler.js +4 -0
- package/build/cli/commands/skills/skills/meta.js +10 -0
- package/build/cli/commands/system/catalog.js +8 -0
- package/build/cli/commands/system/completion/handler.js +10 -0
- package/build/cli/commands/system/completion/meta.js +9 -0
- package/build/cli/commands/system/dump-env/handler.js +3 -0
- package/build/cli/commands/system/dump-env/meta.js +10 -0
- package/build/cli/commands/system/guide/handler.js +4 -0
- package/build/cli/commands/system/guide/meta.js +9 -0
- package/build/cli/commands/task/add/handler.js +21 -0
- package/build/cli/commands/task/add/meta.js +8 -0
- package/build/cli/commands/task/catalog.js +22 -0
- package/build/cli/commands/task/doctor/handler.js +4 -0
- package/build/cli/commands/task/doctor/meta.js +8 -0
- package/build/cli/commands/task/done/handler.js +17 -0
- package/build/cli/commands/task/done/meta.js +8 -0
- package/build/cli/commands/task/drop/handler.js +6 -0
- package/build/cli/commands/task/drop/meta.js +8 -0
- package/build/cli/commands/task/ls/handler.js +13 -0
- package/build/cli/commands/task/ls/meta.js +8 -0
- package/build/cli/commands/task/shared.js +131 -0
- package/build/cli/commands/task/start/handler.js +6 -0
- package/build/cli/commands/task/start/meta.js +8 -0
- package/build/cli/commands/task/stop/handler.js +17 -0
- package/build/cli/commands/task/stop/meta.js +8 -0
- package/build/cli/commands/task/task/handler.js +5 -0
- package/build/cli/commands/task/task/meta.js +11 -0
- package/build/cli/commands/task/update/handler.js +18 -0
- package/build/cli/commands/task/update/meta.js +8 -0
- package/build/cli/commands/task/view/handler.js +14 -0
- package/build/cli/commands/task/view/meta.js +8 -0
- package/build/cli/completion.js +26 -27
- package/build/cli/flags.js +79 -2
- package/build/cli/help.js +27 -49
- package/build/cli/index.js +121 -374
- package/build/cli/output-stream-error-policy.js +17 -0
- package/build/cli/parse.js +159 -72
- package/build/cli/projection-address.js +5 -0
- package/build/cli/render/arc.js +1 -1
- package/build/cli/render/errors.js +4 -3
- package/build/cli/render/format.js +14 -0
- package/build/cli/render/kanshi.js +106 -0
- package/build/cli/render/petition.js +24 -1
- package/build/cli/render/projection-activity.js +5 -1
- package/build/cli/render/shared.js +2 -2
- package/build/cli/render/status.js +79 -13
- package/build/cli/render/task.js +113 -0
- package/build/cli/render/wait.js +23 -3
- package/build/cli/types.js +1 -1
- package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
- package/build/config/env.js +9 -4
- package/build/config/settings/disease.js +26 -0
- package/build/config/settings/knobs.js +8 -0
- package/build/config/settings/loader.js +244 -0
- package/build/config/settings/schema.js +276 -0
- package/build/core/addressing.js +1 -1
- package/build/core/amend.js +3 -3
- package/build/core/arc.js +5 -4
- package/build/core/bind-workspace.js +123 -0
- package/build/core/bind.js +75 -155
- package/build/core/call/call.js +224 -0
- package/build/core/call/context.js +238 -0
- package/build/core/call/execution.js +217 -0
- package/build/core/call/prompt.js +42 -0
- package/build/core/call/reference.js +24 -0
- package/build/core/call-persist.js +1 -1
- package/build/core/claim-delivery.js +247 -0
- package/build/core/claim.js +39 -277
- package/build/core/context.js +2 -1
- package/build/core/{render.js → contract-view.js} +12 -140
- package/build/core/draft.js +107 -9
- package/build/core/entry.js +9 -1
- package/build/core/execution-coordinate.js +4 -20
- package/build/core/execution-pact.js +16 -31
- package/build/core/forfeit.js +35 -22
- package/build/core/hints.js +2 -2
- package/build/core/log.js +2 -2
- package/build/core/petition-claim-gates.js +8 -6
- package/build/core/petition-preview.js +97 -0
- package/build/core/petition-run.js +3 -2
- package/build/core/petition.js +39 -26
- package/build/core/projection/generation/database.js +306 -0
- package/build/core/projection/generation/identity.js +84 -0
- package/build/core/projection/generation/model.js +201 -0
- package/build/core/projection/generation/store.js +73 -0
- package/build/core/projection/generation/transitions.js +258 -0
- package/build/core/projection/heart.js +0 -307
- package/build/core/projection/tell/database.js +109 -0
- package/build/core/projection/tell/model.js +97 -0
- package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
- package/build/core/projection-activity.js +23 -2
- package/build/core/projection-core.js +2 -1
- package/build/core/projection-execution-observer.js +259 -0
- package/build/core/projection-generation-continuation.js +1 -1
- package/build/core/projection-generation-execution.js +90 -20
- package/build/core/projection-generation-launcher.js +1 -1
- package/build/core/projection-generation-runner.js +198 -4
- package/build/core/projection-identity.js +1 -1
- package/build/core/projection-kill.js +50 -17
- package/build/core/projection-life-observer.js +1 -1
- package/build/core/projection-life-protocol.js +10 -0
- package/build/core/projection-mint.js +1 -1
- package/build/core/projection-status.js +45 -32
- package/build/core/projection-wait.js +12 -2
- package/build/core/projection-wake.js +5 -2
- package/build/core/{queue_v2.js → queue.js} +2 -1
- package/build/core/registry.js +1 -1
- package/build/core/renew.js +7 -7
- package/build/core/response-artifact-catalog-sqlite.js +112 -0
- package/build/core/response-artifact-catalog.js +7 -0
- package/build/core/seal.js +44 -16
- package/build/core/status/board.js +286 -0
- package/build/core/status/drift.js +99 -0
- package/build/core/status/lifecycle.js +84 -0
- package/build/core/status/reconciliation.js +131 -0
- package/build/core/stored-agent-event.js +28 -4
- package/build/core/target-ref.js +10 -0
- package/build/core/task/board.js +175 -0
- package/build/core/task/commands.js +211 -0
- package/build/core/task/document.js +189 -0
- package/build/core/task/model.js +1 -0
- package/build/core/task/settlement-git.js +207 -0
- package/build/core/task/settlement-policy.js +82 -0
- package/build/core/task/source-board.js +84 -0
- package/build/core/task/source-model.js +1 -0
- package/build/core/task/validation.js +44 -0
- package/build/core/task-contract.js +224 -0
- package/build/core/task-doctor.js +14 -0
- package/build/core/task-git-actor.js +38 -0
- package/build/core/task-git-runtime.js +34 -0
- package/build/core/task-git-store.js +375 -0
- package/build/core/task-repository.js +1 -0
- package/build/core/task-store-repository.js +86 -0
- package/build/core/task-store.js +1 -0
- package/build/core/task-worktree.js +51 -0
- package/build/core/task.js +4 -0
- package/build/core/transcripts.js +138 -56
- package/build/core/validation.js +17 -0
- package/build/core/verdict.js +2 -2
- package/build/core/worktree-path.js +24 -6
- package/build/flow-error.js +3 -2
- package/build/generated/version.js +1 -1
- package/build/git/commits.js +3 -0
- package/build/git/diff/parsers.js +0 -94
- package/build/index.js +2 -0
- package/build/keiyaku-constants.js +2 -0
- package/build/keiyaku.js +4 -3
- package/package.json +3 -2
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +11 -6
- package/build/agents/harness/pump.js +0 -158
- package/build/agents/providers/codex-app-server.js +0 -864
- package/build/agents/providers/opencode-sdk.js +0 -363
- package/build/agents/providers/pi.js +0 -557
- package/build/config/settings.js +0 -533
- package/build/core/call.js +0 -686
- package/build/core/projection/generation.js +0 -412
- package/build/core/projection/identity.js +0 -81
- package/build/core/projection/mint.js +0 -174
- package/build/core/projection-generation-store.js +0 -707
- package/build/core/status.js +0 -539
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { openProjectionGenerationStore, } from "./projection
|
|
1
|
+
import { openProjectionGenerationStore, } from "./projection/generation/store.js";
|
|
2
2
|
import { acquireProjectionRunnerLock, observeProjectionRunnerLock, } from "./projection-runner-lock.js";
|
|
3
3
|
import { createProjectionExecutionId } from "./projection-generation-identity.js";
|
|
4
4
|
import { applyContinuationEffort, } from "./projection-generation-continuation.js";
|
|
5
|
+
import { openProjectionTellObserver } from "./projection/tell/database.js";
|
|
6
|
+
/** Private runner-side kill grace. Not a setting, env, parameter, or export. */
|
|
7
|
+
const KILL_GRACE_MS = 5000;
|
|
5
8
|
function successorLaunchFacts(launch, completionFacts, effort, now) {
|
|
6
9
|
const { tellFence: _tellFence, ...inherited } = launch.facts;
|
|
7
10
|
const rawInputs = launch.facts.inputs;
|
|
@@ -10,13 +13,15 @@ function successorLaunchFacts(launch, completionFacts, effort, now) {
|
|
|
10
13
|
&& !Array.isArray(rawInputs)
|
|
11
14
|
? rawInputs
|
|
12
15
|
: {};
|
|
16
|
+
// Revive source identity is launch-local; never inherit it onto a tell handoff successor.
|
|
17
|
+
const { sourceArtifactId: _sourceArtifactId, ...inheritedInputs } = inputs;
|
|
13
18
|
return {
|
|
14
19
|
...inherited,
|
|
15
20
|
createdAt: new Date(now()).toISOString(),
|
|
16
21
|
launchedBy: "sweep-wake",
|
|
17
22
|
parentExecutionId: launch.executionId,
|
|
18
23
|
inputs: applyContinuationEffort({
|
|
19
|
-
...
|
|
24
|
+
...inheritedInputs,
|
|
20
25
|
...(completionFacts.session ? { session: completionFacts.session } : {}),
|
|
21
26
|
...(typeof completionFacts.responsePath === "string"
|
|
22
27
|
? { resumePath: completionFacts.responsePath }
|
|
@@ -30,6 +35,19 @@ function normalizeTellFence(tellIds) {
|
|
|
30
35
|
function errorDetail(error) {
|
|
31
36
|
return error instanceof Error ? error.message : String(error);
|
|
32
37
|
}
|
|
38
|
+
function nonReservedRunnerKillFacts(facts) {
|
|
39
|
+
const { state: _state, killIntentSeq: _killIntentSeq, killedAt: _killedAt, ...rest } = facts;
|
|
40
|
+
return rest;
|
|
41
|
+
}
|
|
42
|
+
function readOutcomeState(state) {
|
|
43
|
+
if (state.status === "fulfilled") {
|
|
44
|
+
return { status: "fulfilled", execution: state.execution };
|
|
45
|
+
}
|
|
46
|
+
if (state.status === "rejected") {
|
|
47
|
+
return { status: "rejected", error: state.error };
|
|
48
|
+
}
|
|
49
|
+
return { status: "pending" };
|
|
50
|
+
}
|
|
33
51
|
function acquireRunnerLockOrObserveDuplicate(projectionDirectory) {
|
|
34
52
|
try {
|
|
35
53
|
return acquireProjectionRunnerLock(projectionDirectory);
|
|
@@ -41,6 +59,9 @@ function acquireRunnerLockOrObserveDuplicate(projectionDirectory) {
|
|
|
41
59
|
throw error;
|
|
42
60
|
}
|
|
43
61
|
}
|
|
62
|
+
function observeAbandoned(promise) {
|
|
63
|
+
void promise.then(() => { }, () => { });
|
|
64
|
+
}
|
|
44
65
|
/**
|
|
45
66
|
* Own one exact generation from kernel-lock acquisition through its terminal
|
|
46
67
|
* transaction. Provider execution is injected so this actor never depends on
|
|
@@ -52,6 +73,14 @@ export async function runProjectionGeneration(input) {
|
|
|
52
73
|
let runnerLock;
|
|
53
74
|
let adopted = false;
|
|
54
75
|
let settled = false;
|
|
76
|
+
let tellObserver;
|
|
77
|
+
let graceTimer;
|
|
78
|
+
const clearGraceTimer = () => {
|
|
79
|
+
if (graceTimer === undefined)
|
|
80
|
+
return;
|
|
81
|
+
clearTimeout(graceTimer);
|
|
82
|
+
graceTimer = undefined;
|
|
83
|
+
};
|
|
55
84
|
try {
|
|
56
85
|
const initial = store.readCurrentGeneration();
|
|
57
86
|
if (initial?.launch.executionId !== input.executionId
|
|
@@ -73,7 +102,151 @@ export async function runProjectionGeneration(input) {
|
|
|
73
102
|
if (current?.launch.executionId !== input.executionId) {
|
|
74
103
|
throw new Error("adopted generation stopped being current");
|
|
75
104
|
}
|
|
76
|
-
|
|
105
|
+
// Pre-admission kill: skip provider work and commit killed directly.
|
|
106
|
+
if (current.killIntent) {
|
|
107
|
+
const killed = store.runnerKilledIfRequested({ executionId: input.executionId });
|
|
108
|
+
if (killed.status !== "committed")
|
|
109
|
+
return { status: "rejected" };
|
|
110
|
+
settled = true;
|
|
111
|
+
return { status: "completed" };
|
|
112
|
+
}
|
|
113
|
+
const handle = input.execute(current.launch);
|
|
114
|
+
tellObserver = openProjectionTellObserver(input.projectionDirectory);
|
|
115
|
+
let gracefulAbortInvoked = false;
|
|
116
|
+
let forceAbortInvoked = false;
|
|
117
|
+
let sawKillIntent = false;
|
|
118
|
+
const observeKillBoundary = () => {
|
|
119
|
+
try {
|
|
120
|
+
if (!tellObserver.hasDataVersionChanged())
|
|
121
|
+
return;
|
|
122
|
+
const live = store.readCurrentGeneration();
|
|
123
|
+
if (live?.launch.executionId !== input.executionId)
|
|
124
|
+
return;
|
|
125
|
+
if (live.verdict)
|
|
126
|
+
return;
|
|
127
|
+
if (!live.killIntent)
|
|
128
|
+
return;
|
|
129
|
+
sawKillIntent = true;
|
|
130
|
+
if (gracefulAbortInvoked)
|
|
131
|
+
return;
|
|
132
|
+
gracefulAbortInvoked = true;
|
|
133
|
+
void handle.abort("graceful").catch(() => {
|
|
134
|
+
// Abort observation failures fail closed for this boundary.
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Observation failures fail closed and must not change provider outcome.
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
// Mutable box so async settlement is readable without control-flow narrowing traps.
|
|
142
|
+
const outcomeBox = { status: "pending" };
|
|
143
|
+
let resolveActivity;
|
|
144
|
+
const activityChanged = () => new Promise((resolve) => {
|
|
145
|
+
resolveActivity = resolve;
|
|
146
|
+
});
|
|
147
|
+
const bumpActivity = () => {
|
|
148
|
+
const resolve = resolveActivity;
|
|
149
|
+
resolveActivity = undefined;
|
|
150
|
+
resolve?.();
|
|
151
|
+
};
|
|
152
|
+
const outcomeWatch = handle.outcome.then((execution) => {
|
|
153
|
+
outcomeBox.status = "fulfilled";
|
|
154
|
+
outcomeBox.execution = execution;
|
|
155
|
+
observeKillBoundary();
|
|
156
|
+
bumpActivity();
|
|
157
|
+
}, (error) => {
|
|
158
|
+
outcomeBox.status = "rejected";
|
|
159
|
+
outcomeBox.error = error;
|
|
160
|
+
observeKillBoundary();
|
|
161
|
+
bumpActivity();
|
|
162
|
+
});
|
|
163
|
+
// Always rejection-observe so abandon paths never surface unhandled rejections.
|
|
164
|
+
observeAbandoned(outcomeWatch);
|
|
165
|
+
const eventDrain = (async () => {
|
|
166
|
+
try {
|
|
167
|
+
for await (const _event of handle.events) {
|
|
168
|
+
if (forceAbortInvoked)
|
|
169
|
+
return;
|
|
170
|
+
observeKillBoundary();
|
|
171
|
+
bumpActivity();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Event-stream failures fail closed for observation; abandon quietly.
|
|
176
|
+
}
|
|
177
|
+
bumpActivity();
|
|
178
|
+
})();
|
|
179
|
+
observeAbandoned(eventDrain);
|
|
180
|
+
while (outcomeBox.status === "pending" && !sawKillIntent) {
|
|
181
|
+
await activityChanged();
|
|
182
|
+
}
|
|
183
|
+
if (sawKillIntent) {
|
|
184
|
+
// Grace race: outcome settlement inside the window is stop proof.
|
|
185
|
+
if (outcomeBox.status === "pending") {
|
|
186
|
+
const graceExpired = new Promise((resolve) => {
|
|
187
|
+
graceTimer = setTimeout(() => {
|
|
188
|
+
graceTimer = undefined;
|
|
189
|
+
resolve("timeout");
|
|
190
|
+
}, KILL_GRACE_MS);
|
|
191
|
+
});
|
|
192
|
+
await Promise.race([
|
|
193
|
+
outcomeWatch.then(() => "outcome"),
|
|
194
|
+
graceExpired,
|
|
195
|
+
]);
|
|
196
|
+
clearGraceTimer();
|
|
197
|
+
}
|
|
198
|
+
const killOutcome = readOutcomeState(outcomeBox);
|
|
199
|
+
if (killOutcome.status !== "pending") {
|
|
200
|
+
const facts = killOutcome.status === "fulfilled"
|
|
201
|
+
? nonReservedRunnerKillFacts(killOutcome.execution.facts)
|
|
202
|
+
: undefined;
|
|
203
|
+
const killed = store.runnerKilledIfRequested({
|
|
204
|
+
executionId: input.executionId,
|
|
205
|
+
...(facts && Object.keys(facts).length > 0 ? { facts } : {}),
|
|
206
|
+
});
|
|
207
|
+
if (killed.status !== "committed")
|
|
208
|
+
return { status: "rejected" };
|
|
209
|
+
settled = true;
|
|
210
|
+
return { status: "completed" };
|
|
211
|
+
}
|
|
212
|
+
// Force escalation: resolution is stop proof; rejection is kill failure.
|
|
213
|
+
forceAbortInvoked = true;
|
|
214
|
+
try {
|
|
215
|
+
await handle.abort("force");
|
|
216
|
+
const killed = store.runnerKilledIfRequested({ executionId: input.executionId });
|
|
217
|
+
if (killed.status !== "committed")
|
|
218
|
+
return { status: "rejected" };
|
|
219
|
+
settled = true;
|
|
220
|
+
return { status: "completed" };
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
const failed = store.verdictIfOpen({
|
|
224
|
+
executionId: input.executionId,
|
|
225
|
+
verdict: "failed",
|
|
226
|
+
facts: {
|
|
227
|
+
operatorAction: "kill",
|
|
228
|
+
diagnostic: "escalation-failed",
|
|
229
|
+
detail: errorDetail(error),
|
|
230
|
+
failedAt: new Date(now()).toISOString(),
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
// Durably completed after the failed verdict; outer catch must not overwrite.
|
|
234
|
+
settled = true;
|
|
235
|
+
if (failed.status !== "committed")
|
|
236
|
+
return { status: "rejected" };
|
|
237
|
+
return { status: "completed" };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// No kill intent: ordinary outcome, then pending-tell handoff or verdict.
|
|
241
|
+
await outcomeWatch;
|
|
242
|
+
const ordinaryOutcome = readOutcomeState(outcomeBox);
|
|
243
|
+
if (ordinaryOutcome.status === "rejected") {
|
|
244
|
+
throw ordinaryOutcome.error;
|
|
245
|
+
}
|
|
246
|
+
if (ordinaryOutcome.status !== "fulfilled") {
|
|
247
|
+
throw new Error("projection generation outcome did not settle");
|
|
248
|
+
}
|
|
249
|
+
const execution = ordinaryOutcome.execution;
|
|
77
250
|
const pending = execution.verdict === "completed"
|
|
78
251
|
? input.snapshotPendingTells()
|
|
79
252
|
: { tellIds: [] };
|
|
@@ -115,8 +288,22 @@ export async function runProjectionGeneration(input) {
|
|
|
115
288
|
verdict: execution.verdict,
|
|
116
289
|
facts: execution.facts,
|
|
117
290
|
});
|
|
118
|
-
if (verdict.status !== "committed")
|
|
291
|
+
if (verdict.status !== "committed") {
|
|
292
|
+
// Kill intent may commit after the last outcome-boundary observation and
|
|
293
|
+
// before this transaction. The settled outcome is already stop proof.
|
|
294
|
+
if (verdict.reason === "kill-requested") {
|
|
295
|
+
const facts = nonReservedRunnerKillFacts(execution.facts);
|
|
296
|
+
const killed = store.runnerKilledIfRequested({
|
|
297
|
+
executionId: input.executionId,
|
|
298
|
+
...(Object.keys(facts).length > 0 ? { facts } : {}),
|
|
299
|
+
});
|
|
300
|
+
if (killed.status !== "committed")
|
|
301
|
+
return { status: "rejected" };
|
|
302
|
+
settled = true;
|
|
303
|
+
return { status: "completed" };
|
|
304
|
+
}
|
|
119
305
|
return { status: "rejected" };
|
|
306
|
+
}
|
|
120
307
|
settled = true;
|
|
121
308
|
return { status: "completed" };
|
|
122
309
|
}
|
|
@@ -134,6 +321,13 @@ export async function runProjectionGeneration(input) {
|
|
|
134
321
|
throw error;
|
|
135
322
|
}
|
|
136
323
|
finally {
|
|
324
|
+
clearGraceTimer();
|
|
325
|
+
try {
|
|
326
|
+
tellObserver?.close();
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// Observer cleanup cannot reopen life or product authority.
|
|
330
|
+
}
|
|
137
331
|
try {
|
|
138
332
|
runnerLock?.close();
|
|
139
333
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { openProjectionGenerationStoreReadOnly, } from "./projection
|
|
1
|
+
import { openProjectionGenerationStoreReadOnly, } from "./projection/generation/store.js";
|
|
2
2
|
/** Read the immutable projection identity from the heart database. */
|
|
3
3
|
export function readProjectionIdentity(projectionDirectory) {
|
|
4
4
|
const heart = openProjectionGenerationStoreReadOnly(projectionDirectory);
|
|
@@ -1,24 +1,57 @@
|
|
|
1
|
-
import { openProjectionGenerationStore } from "./projection
|
|
1
|
+
import { openProjectionGenerationStore } from "./projection/generation/store.js";
|
|
2
|
+
import { observeProjectionRunnerLock } from "./projection-runner-lock.js";
|
|
3
|
+
function settleReleasedLeash(store, projectionDirectory, executionId) {
|
|
4
|
+
const observation = observeProjectionRunnerLock(projectionDirectory);
|
|
5
|
+
if (observation.state === "held" || observation.state === "unknown") {
|
|
6
|
+
return { status: "accepted", executionId };
|
|
7
|
+
}
|
|
8
|
+
// Positive released-leash evidence only; settlement race still reports accepted.
|
|
9
|
+
store.settleKillIfRunnerDead({
|
|
10
|
+
executionId,
|
|
11
|
+
releasedLockEvidence: {
|
|
12
|
+
state: "released",
|
|
13
|
+
executionId,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
return { status: "accepted", executionId };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Durably request stop for the current open generation. Intent durability is
|
|
20
|
+
* never published as killed; terminal settlement is runner-owned or dead-leash
|
|
21
|
+
* settle-kill-if-runner-dead only.
|
|
22
|
+
*/
|
|
2
23
|
export function killProjectionGeneration(projectionDirectory, nowMs = Date.now()) {
|
|
3
24
|
const store = openProjectionGenerationStore(projectionDirectory);
|
|
4
25
|
try {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
26
|
+
const killedAt = new Date(nowMs).toISOString();
|
|
27
|
+
// Retry only on not-current races so an open successor is never labeled closed.
|
|
28
|
+
for (;;) {
|
|
29
|
+
const current = store.readCurrentGeneration();
|
|
30
|
+
if (!current)
|
|
31
|
+
return { status: "already-closed" };
|
|
32
|
+
if (current.verdict) {
|
|
33
|
+
return { status: "already-closed", executionId: current.launch.executionId };
|
|
34
|
+
}
|
|
35
|
+
const executionId = current.launch.executionId;
|
|
36
|
+
const request = store.requestKillIfOpen({ executionId, killedAt });
|
|
37
|
+
if (request.status === "committed") {
|
|
38
|
+
return settleReleasedLeash(store, projectionDirectory, executionId);
|
|
39
|
+
}
|
|
40
|
+
if (request.reason === "kill-requested") {
|
|
41
|
+
// Idempotent first intent: still accepted, then one leash observation.
|
|
42
|
+
return settleReleasedLeash(store, projectionDirectory, executionId);
|
|
43
|
+
}
|
|
44
|
+
if (request.reason === "already-terminal") {
|
|
45
|
+
return { status: "already-closed", executionId };
|
|
46
|
+
}
|
|
47
|
+
if (request.reason === "no-current-launch") {
|
|
48
|
+
return { status: "already-closed" };
|
|
49
|
+
}
|
|
50
|
+
if (request.reason === "not-current") {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
return { status: "already-closed", executionId };
|
|
10
54
|
}
|
|
11
|
-
const transition = store.verdictIfOpen({
|
|
12
|
-
executionId: current.launch.executionId,
|
|
13
|
-
verdict: "completed",
|
|
14
|
-
facts: {
|
|
15
|
-
operatorAction: "kill",
|
|
16
|
-
killedAt: new Date(nowMs).toISOString(),
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
return transition.status === "committed"
|
|
20
|
-
? { status: "killed", executionId: current.launch.executionId }
|
|
21
|
-
: { status: "already-resting", executionId: current.launch.executionId };
|
|
22
55
|
}
|
|
23
56
|
finally {
|
|
24
57
|
store.close();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { openProjectionGenerationStoreReadOnly, } from "./projection
|
|
1
|
+
import { openProjectionGenerationStoreReadOnly, } from "./projection/generation/store.js";
|
|
2
2
|
import { deriveProjectionLife, selectCurrentGeneration, } from "./projection-life-protocol.js";
|
|
3
3
|
import { observeProjectionRunnerLock } from "./projection-runner-lock.js";
|
|
4
4
|
function errorDetail(error) {
|
|
@@ -4,6 +4,7 @@ export const GENERATION_VERDICT_STATES = [
|
|
|
4
4
|
"launch-failed",
|
|
5
5
|
"lost-runner",
|
|
6
6
|
"dismissed",
|
|
7
|
+
"killed",
|
|
7
8
|
];
|
|
8
9
|
function asLaunch(record) {
|
|
9
10
|
return record.kind === "launch"
|
|
@@ -15,6 +16,11 @@ function asAdoption(record) {
|
|
|
15
16
|
? record
|
|
16
17
|
: undefined;
|
|
17
18
|
}
|
|
19
|
+
function asKillIntent(record) {
|
|
20
|
+
return record.kind === "kill-intent"
|
|
21
|
+
? record
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
18
24
|
function asVerdict(record) {
|
|
19
25
|
return record.kind === "verdict"
|
|
20
26
|
? record
|
|
@@ -34,16 +40,19 @@ export function selectCurrentGeneration(records) {
|
|
|
34
40
|
if (!launch)
|
|
35
41
|
return null;
|
|
36
42
|
let adoption;
|
|
43
|
+
let killIntent;
|
|
37
44
|
let verdict;
|
|
38
45
|
for (const record of records) {
|
|
39
46
|
if (record.seq <= launch.seq || record.executionId !== launch.executionId)
|
|
40
47
|
continue;
|
|
41
48
|
adoption ??= asAdoption(record);
|
|
49
|
+
killIntent ??= asKillIntent(record);
|
|
42
50
|
verdict ??= asVerdict(record);
|
|
43
51
|
}
|
|
44
52
|
return {
|
|
45
53
|
launch,
|
|
46
54
|
...(adoption ? { adoption } : {}),
|
|
55
|
+
...(killIntent ? { killIntent } : {}),
|
|
47
56
|
...(verdict ? { verdict } : {}),
|
|
48
57
|
};
|
|
49
58
|
}
|
|
@@ -58,6 +67,7 @@ function phaseForVerdict(state) {
|
|
|
58
67
|
switch (state) {
|
|
59
68
|
case "completed": return "done";
|
|
60
69
|
case "dismissed": return "dismissed";
|
|
70
|
+
case "killed": return "killed";
|
|
61
71
|
case "lost-runner": return "lost";
|
|
62
72
|
case "failed":
|
|
63
73
|
case "launch-failed":
|
|
@@ -4,7 +4,7 @@ import { isErrnoException } from "../errno.js";
|
|
|
4
4
|
import { ProjectionStateError, randomHex8 } from "./atomic-publish.js";
|
|
5
5
|
import { isoFromNowMs, PROJECTION_ROOT_SEGMENTS, projectionDir, projectionRoot, } from "./projection-core.js";
|
|
6
6
|
import { parseExecutionAuthoritySelection, parseExecutionPact, parseExecutionPactFields, } from "./execution-pact.js";
|
|
7
|
-
import { openProjectionGenerationStore } from "./projection
|
|
7
|
+
import { openProjectionGenerationStore } from "./projection/generation/store.js";
|
|
8
8
|
import { initializeProjectionRunnerLockDatabase } from "./projection-runner-lock.js";
|
|
9
9
|
export class ProjectionMintCollisionError extends Error {
|
|
10
10
|
code = "PROJECTION_MINT_COLLISION";
|
|
@@ -6,8 +6,8 @@ import { readProjectionAlias } from "./projection-alias.js";
|
|
|
6
6
|
import { ProjectionStateError } from "./atomic-publish.js";
|
|
7
7
|
import { foldAgentActivity, } from "./projection-activity.js";
|
|
8
8
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
9
|
-
import { readProjectionTellCounts
|
|
10
|
-
import { ProjectionGenerationStoreError } from "./projection
|
|
9
|
+
import { readProjectionTellCounts } from "./projection/tell/store.js";
|
|
10
|
+
import { isProjectionGenerationSchemaV1Residue, ProjectionGenerationStoreError, } from "./projection/generation/store.js";
|
|
11
11
|
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
|
|
12
12
|
import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
|
|
13
13
|
import { selectCurrentGeneration } from "./projection-life-protocol.js";
|
|
@@ -23,10 +23,15 @@ const STATUS_GROUP = {
|
|
|
23
23
|
failed: 2,
|
|
24
24
|
dead: 2,
|
|
25
25
|
done: 3,
|
|
26
|
+
killed: 4,
|
|
26
27
|
dismissed: 4,
|
|
27
28
|
};
|
|
28
29
|
function isOmissibleProjectionStatusState(state) {
|
|
29
|
-
return state === "failed"
|
|
30
|
+
return state === "failed"
|
|
31
|
+
|| state === "dead"
|
|
32
|
+
|| state === "done"
|
|
33
|
+
|| state === "killed"
|
|
34
|
+
|| state === "dismissed";
|
|
30
35
|
}
|
|
31
36
|
function rowSortTime(row) {
|
|
32
37
|
if (row.activityAtMs !== undefined && Number.isFinite(row.activityAtMs)) {
|
|
@@ -65,6 +70,7 @@ export function prioritizeProjectionStatusRows(rows, showAll) {
|
|
|
65
70
|
failed: 0,
|
|
66
71
|
dead: 0,
|
|
67
72
|
done: 0,
|
|
73
|
+
killed: 0,
|
|
68
74
|
dismissed: 0,
|
|
69
75
|
};
|
|
70
76
|
for (const row of ordered) {
|
|
@@ -84,27 +90,29 @@ class ProjectionStatusFileError extends Error {
|
|
|
84
90
|
diagnostic;
|
|
85
91
|
constructor(kind, filePath) {
|
|
86
92
|
const label = path.basename(filePath);
|
|
87
|
-
const detail =
|
|
88
|
-
? `${label} is not a regular file`
|
|
89
|
-
: `${label} exceeds status read limit`;
|
|
93
|
+
const detail = `${label} is not a regular file`;
|
|
90
94
|
super(detail);
|
|
91
95
|
this.name = "ProjectionStatusFileError";
|
|
92
96
|
this.diagnostic = { kind, detail };
|
|
93
97
|
}
|
|
94
98
|
}
|
|
99
|
+
function oversizedProjectionFileDiagnostic(filePath) {
|
|
100
|
+
const label = path.basename(filePath);
|
|
101
|
+
return {
|
|
102
|
+
kind: "oversized-projection-file",
|
|
103
|
+
detail: `${label} exceeds status read limit · newest complete events retained`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
95
106
|
function recordProjectionStatusFileError(error, diagnostics) {
|
|
96
107
|
if (!(error instanceof ProjectionStatusFileError))
|
|
97
108
|
return false;
|
|
98
109
|
diagnostics.push(error.diagnostic);
|
|
99
110
|
return true;
|
|
100
111
|
}
|
|
101
|
-
function
|
|
112
|
+
function readBoundedRegularFileTail(filePath) {
|
|
102
113
|
const before = fs.lstatSync(filePath);
|
|
103
114
|
if (!before.isFile())
|
|
104
115
|
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
105
|
-
if (before.size > MAX_STATUS_FILE_BYTES) {
|
|
106
|
-
throw new ProjectionStatusFileError("oversized-projection-file", filePath);
|
|
107
|
-
}
|
|
108
116
|
let fd;
|
|
109
117
|
try {
|
|
110
118
|
fd = fs.openSync(filePath, fs.constants.O_RDONLY | fs.constants.O_NONBLOCK | fs.constants.O_NOFOLLOW);
|
|
@@ -119,23 +127,27 @@ function readBoundedRegularFile(filePath) {
|
|
|
119
127
|
const opened = fs.fstatSync(fd);
|
|
120
128
|
if (!opened.isFile())
|
|
121
129
|
throw new ProjectionStatusFileError("non-regular-projection-file", filePath);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
130
|
+
const snapshotSize = opened.size;
|
|
131
|
+
const truncated = snapshotSize > MAX_STATUS_FILE_BYTES;
|
|
132
|
+
const readLength = Math.min(snapshotSize, MAX_STATUS_FILE_BYTES);
|
|
133
|
+
const readOffset = Math.max(0, snapshotSize - MAX_STATUS_FILE_BYTES);
|
|
134
|
+
const buffer = Buffer.allocUnsafe(readLength);
|
|
126
135
|
let total = 0;
|
|
127
|
-
while (total
|
|
128
|
-
const
|
|
129
|
-
const bytesRead = fs.readSync(fd, chunk, 0, chunk.length, null);
|
|
136
|
+
while (total < readLength) {
|
|
137
|
+
const bytesRead = fs.readSync(fd, buffer, total, readLength - total, readOffset + total);
|
|
130
138
|
if (bytesRead === 0)
|
|
131
139
|
break;
|
|
132
|
-
chunks.push(chunk.subarray(0, bytesRead));
|
|
133
140
|
total += bytesRead;
|
|
134
141
|
}
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
let tail = buffer.subarray(0, total);
|
|
143
|
+
if (truncated) {
|
|
144
|
+
const firstLf = tail.indexOf(0x0a);
|
|
145
|
+
if (firstLf < 0) {
|
|
146
|
+
return { content: "", truncated: true };
|
|
147
|
+
}
|
|
148
|
+
tail = tail.subarray(firstLf + 1);
|
|
137
149
|
}
|
|
138
|
-
return
|
|
150
|
+
return { content: tail.toString("utf8"), truncated };
|
|
139
151
|
}
|
|
140
152
|
finally {
|
|
141
153
|
fs.closeSync(fd);
|
|
@@ -196,8 +208,12 @@ function readHeartTellCounts(projectionDir, diagnostics) {
|
|
|
196
208
|
}
|
|
197
209
|
function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
198
210
|
let content;
|
|
211
|
+
let truncated = false;
|
|
212
|
+
const eventsPath = executionEventsPath(projectionDir, executionId);
|
|
199
213
|
try {
|
|
200
|
-
|
|
214
|
+
const read = readBoundedRegularFileTail(eventsPath);
|
|
215
|
+
content = read.content;
|
|
216
|
+
truncated = read.truncated;
|
|
201
217
|
}
|
|
202
218
|
catch (error) {
|
|
203
219
|
if (isErrnoException(error) && error.code === "ENOENT")
|
|
@@ -207,8 +223,12 @@ function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
|
207
223
|
diagnostics.push({ kind: "unreadable-activity", detail: `activity ledger unreadable: ${String(error)}` });
|
|
208
224
|
return [];
|
|
209
225
|
}
|
|
226
|
+
if (truncated) {
|
|
227
|
+
diagnostics.push(oversizedProjectionFileDiagnostic(eventsPath));
|
|
228
|
+
}
|
|
229
|
+
// Parse only LF-terminated records. An unterminated final line is ignored even
|
|
230
|
+
// when it happens to parse: it may be a concurrent append fragment.
|
|
210
231
|
const lines = content.split("\n");
|
|
211
|
-
const terminated = content.endsWith("\n");
|
|
212
232
|
const values = [];
|
|
213
233
|
let malformed = 0;
|
|
214
234
|
for (const line of lines.slice(0, -1)) {
|
|
@@ -219,15 +239,6 @@ function readStoredEvents(projectionDir, executionId, diagnostics) {
|
|
|
219
239
|
malformed += 1;
|
|
220
240
|
}
|
|
221
241
|
}
|
|
222
|
-
const finalLine = lines.at(-1);
|
|
223
|
-
if (!terminated && finalLine) {
|
|
224
|
-
try {
|
|
225
|
-
values.push(JSON.parse(finalLine));
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
// A concurrent append can leave only this final record incomplete.
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
242
|
if (malformed > 0) {
|
|
232
243
|
diagnostics.push({
|
|
233
244
|
kind: "invalid-activity-event",
|
|
@@ -371,6 +382,8 @@ export function readProjectionStatusBoard(cwd, nowMs, options = {}) {
|
|
|
371
382
|
catch {
|
|
372
383
|
continue;
|
|
373
384
|
}
|
|
385
|
+
if (isProjectionGenerationSchemaV1Residue(dir))
|
|
386
|
+
continue;
|
|
374
387
|
rows.push(readProjectionRow(dir, id, aliases.get(id), nowMs));
|
|
375
388
|
}
|
|
376
389
|
}
|
|
@@ -4,7 +4,7 @@ import { readProjectionIdentity } from "./projection-identity.js";
|
|
|
4
4
|
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
|
|
5
5
|
import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
|
|
6
6
|
import { selectCurrentGeneration } from "./projection-life-protocol.js";
|
|
7
|
-
import { readProjectionTellCounts } from "./projection
|
|
7
|
+
import { readProjectionTellCounts } from "./projection/tell/store.js";
|
|
8
8
|
import { invalidActivityEventDiagnostic, selectValidStoredAgentEvents, } from "./stored-agent-event.js";
|
|
9
9
|
const WAIT_POLL_MS = 100;
|
|
10
10
|
function sleep(ms) {
|
|
@@ -39,7 +39,7 @@ function relativeEventLedgerFile(executionId) {
|
|
|
39
39
|
}
|
|
40
40
|
function timestampFact(current, nowMs) {
|
|
41
41
|
const facts = current.verdict?.facts;
|
|
42
|
-
for (const key of ["completedAt", "failedAt", "dismissedAt"]) {
|
|
42
|
+
for (const key of ["completedAt", "failedAt", "dismissedAt", "killedAt"]) {
|
|
43
43
|
const value = facts?.[key];
|
|
44
44
|
if (typeof value === "string" && Number.isFinite(Date.parse(value)))
|
|
45
45
|
return value;
|
|
@@ -76,6 +76,14 @@ function buildSnapshot(input) {
|
|
|
76
76
|
const invalidActivity = invalidActivityEventDiagnostic(malformedEvents);
|
|
77
77
|
const responsePath = current?.verdict?.facts.responsePath;
|
|
78
78
|
const artifactId = current?.verdict?.facts.artifactId;
|
|
79
|
+
const sourceArtifactId = current?.verdict?.facts.sourceArtifactId;
|
|
80
|
+
const errorFact = current?.verdict?.facts.error;
|
|
81
|
+
const failureCode = errorFact
|
|
82
|
+
&& typeof errorFact === "object"
|
|
83
|
+
&& !Array.isArray(errorFact)
|
|
84
|
+
&& typeof errorFact.code === "string"
|
|
85
|
+
? errorFact.code
|
|
86
|
+
: undefined;
|
|
79
87
|
return {
|
|
80
88
|
phase,
|
|
81
89
|
observedAtMs: Number.isFinite(anchorMs) ? anchorMs : nowMs,
|
|
@@ -93,6 +101,8 @@ function buildSnapshot(input) {
|
|
|
93
101
|
} : {}),
|
|
94
102
|
...(typeof responsePath === "string" && responsePath.trim() ? { responsePath } : {}),
|
|
95
103
|
...(typeof artifactId === "string" && artifactId.trim() ? { artifactId } : {}),
|
|
104
|
+
...(typeof sourceArtifactId === "string" && sourceArtifactId.trim() ? { sourceArtifactId } : {}),
|
|
105
|
+
...(failureCode ? { failureCode } : {}),
|
|
96
106
|
};
|
|
97
107
|
}
|
|
98
108
|
export async function waitForProjection(input) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { FlowError } from "../flow-error.js";
|
|
2
|
-
import { parseResolvedAkumaLaunchSnapshot } from "../agents/launch-
|
|
2
|
+
import { parseResolvedAkumaLaunchSnapshot } from "../agents/launch-snapshot/model.js";
|
|
3
3
|
import { ProjectionStateError } from "./atomic-publish.js";
|
|
4
4
|
import { applyContinuationEffort, snapshotPendingTells, } from "./projection-generation-continuation.js";
|
|
5
5
|
import { createProjectionExecutionId } from "./projection-generation-identity.js";
|
|
6
6
|
import { startProjectionGeneration } from "./projection-generation-launcher.js";
|
|
7
|
-
import { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, } from "./projection
|
|
7
|
+
import { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, } from "./projection/generation/store.js";
|
|
8
8
|
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
|
|
9
9
|
import { observeProjectionLife } from "./projection-life-observer.js";
|
|
10
10
|
import { observeProjectionRunnerLock } from "./projection-runner-lock.js";
|
|
@@ -59,6 +59,9 @@ export function assertTellEffortSupported(projectionDirectory, effort) {
|
|
|
59
59
|
catch (error) {
|
|
60
60
|
throw new ProjectionStateError("generation launch has an invalid immutable launchSnapshot", { cause: error });
|
|
61
61
|
}
|
|
62
|
+
if (launchSnapshot.akuma.model === undefined) {
|
|
63
|
+
throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' requires an explicit model.`);
|
|
64
|
+
}
|
|
62
65
|
const effortOptions = launchSnapshot.akuma.effortOptions;
|
|
63
66
|
if (effortOptions === undefined)
|
|
64
67
|
return;
|
|
@@ -2,7 +2,8 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { FlowError } from "../flow-error.js";
|
|
3
3
|
import { createGit, errorContainsAnyPattern, MISSING_HEAD_PATTERNS, wrapGitError } from "../git/core.js";
|
|
4
4
|
import { listContractIds, readLedger } from "./ledger.js";
|
|
5
|
-
import {
|
|
5
|
+
import { deriveContractState } from "./status/lifecycle.js";
|
|
6
|
+
import { commissionTarget } from "./status/drift.js";
|
|
6
7
|
const EMPTY_TREE_HASH = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
7
8
|
const MISSING_REF_SENTINEL = "0".repeat(40);
|
|
8
9
|
const ISO_UTC_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
|
package/build/core/registry.js
CHANGED
|
@@ -2,7 +2,7 @@ import { FlowError } from "../flow-error.js";
|
|
|
2
2
|
import { readLedger } from "./ledger.js";
|
|
3
3
|
import { appendRefLogWithRetry } from "./ref-log.js";
|
|
4
4
|
import { isNegativeScopePattern, patternsOverlap } from "./scope.js";
|
|
5
|
-
import { deriveContractState, isTerminalState } from "./status.js";
|
|
5
|
+
import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
|
|
6
6
|
export const REGISTRY_REF = "refs/keiyaku/registry";
|
|
7
7
|
function parseRegistryEntry(message) {
|
|
8
8
|
const body = message.slice(message.indexOf("\n\n") + 2).trim();
|