@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
|
@@ -10,7 +10,7 @@ export function launchIfSettled(database, readOnly, input) {
|
|
|
10
10
|
const executionId = assertExecutionId(input.executionId);
|
|
11
11
|
const facts = validateLaunchFacts(input.facts, "launch facts");
|
|
12
12
|
return writeTransition(database, readOnly, () => {
|
|
13
|
-
const history = readValidatedHistory(database);
|
|
13
|
+
const history = readValidatedHistory(database, readOnly);
|
|
14
14
|
if (history.records.some((record) => record.kind === "launch" && record.executionId === executionId)) {
|
|
15
15
|
return rejected("execution-id-already-used", history.current);
|
|
16
16
|
}
|
|
@@ -27,7 +27,7 @@ export function failInterruptWakeIfSettled(database, readOnly, input) {
|
|
|
27
27
|
const successorFacts = validateLaunchFacts(input.successorFacts, "interrupt wake successor launch facts");
|
|
28
28
|
const terminalAt = assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
29
29
|
return writeTransition(database, readOnly, () => {
|
|
30
|
-
const history = readValidatedHistory(database);
|
|
30
|
+
const history = readValidatedHistory(database, readOnly);
|
|
31
31
|
const current = history.current;
|
|
32
32
|
if (!current)
|
|
33
33
|
return rejected("no-current-launch", null);
|
|
@@ -56,7 +56,7 @@ export function adoptionIfCurrent(database, readOnly, input) {
|
|
|
56
56
|
const executionId = assertExecutionId(input.executionId);
|
|
57
57
|
const facts = validateAdoptionFacts(input.facts, "adoption facts");
|
|
58
58
|
return writeTransition(database, readOnly, () => {
|
|
59
|
-
const history = readValidatedHistory(database);
|
|
59
|
+
const history = readValidatedHistory(database, readOnly);
|
|
60
60
|
const current = history.current;
|
|
61
61
|
if (!current)
|
|
62
62
|
return rejected("no-current-launch", null);
|
|
@@ -73,7 +73,7 @@ export function requestKillIfOpen(database, readOnly, input) {
|
|
|
73
73
|
const executionId = assertExecutionId(input.executionId);
|
|
74
74
|
const killedAt = assertIsoTimestamp(input.killedAt, "killedAt");
|
|
75
75
|
return writeTransition(database, readOnly, () => {
|
|
76
|
-
const history = readValidatedHistory(database);
|
|
76
|
+
const history = readValidatedHistory(database, readOnly);
|
|
77
77
|
const current = history.current;
|
|
78
78
|
if (!current)
|
|
79
79
|
return rejected("no-current-launch", null);
|
|
@@ -93,7 +93,7 @@ export function requestInterruptIfOpen(database, readOnly, input) {
|
|
|
93
93
|
const executionId = assertExecutionId(input.executionId);
|
|
94
94
|
const interruptedAt = assertIsoTimestamp(input.interruptedAt, "interruptedAt");
|
|
95
95
|
return writeTransition(database, readOnly, () => {
|
|
96
|
-
const history = readValidatedHistory(database);
|
|
96
|
+
const history = readValidatedHistory(database, readOnly);
|
|
97
97
|
const current = history.current;
|
|
98
98
|
if (!current)
|
|
99
99
|
return rejected("no-current-launch", null);
|
|
@@ -126,7 +126,7 @@ export function runnerKilledIfRequested(database, readOnly, input) {
|
|
|
126
126
|
throw new ProjectionGenerationStoreError("killed verdict facts.terminalAt is reserved");
|
|
127
127
|
}
|
|
128
128
|
return writeTransition(database, readOnly, () => {
|
|
129
|
-
const history = readValidatedHistory(database);
|
|
129
|
+
const history = readValidatedHistory(database, readOnly);
|
|
130
130
|
const current = history.current;
|
|
131
131
|
if (!current)
|
|
132
132
|
return rejected("no-current-launch", null);
|
|
@@ -158,7 +158,7 @@ export function runnerInterruptedIfRequested(database, readOnly, input) {
|
|
|
158
158
|
? undefined
|
|
159
159
|
: assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
160
160
|
return writeTransition(database, readOnly, () => {
|
|
161
|
-
const history = readValidatedHistory(database);
|
|
161
|
+
const history = readValidatedHistory(database, readOnly);
|
|
162
162
|
const current = history.current;
|
|
163
163
|
if (!current)
|
|
164
164
|
return rejected("no-current-launch", null);
|
|
@@ -189,7 +189,7 @@ export function runnerVerdictIfOpen(database, readOnly, input) {
|
|
|
189
189
|
const callerFacts = cloneFacts(input.facts ?? {}, "runner verdict facts");
|
|
190
190
|
const terminalAt = assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
191
191
|
return writeTransition(database, readOnly, () => {
|
|
192
|
-
const history = readValidatedHistory(database);
|
|
192
|
+
const history = readValidatedHistory(database, readOnly);
|
|
193
193
|
const current = history.current;
|
|
194
194
|
if (!current)
|
|
195
195
|
return rejected("no-current-launch", null);
|
|
@@ -245,7 +245,7 @@ export function settleKillIfRunnerDead(database, readOnly, input) {
|
|
|
245
245
|
throw new ProjectionGenerationStoreError("killed verdict facts.terminalAt is reserved");
|
|
246
246
|
}
|
|
247
247
|
return writeTransition(database, readOnly, () => {
|
|
248
|
-
const history = readValidatedHistory(database);
|
|
248
|
+
const history = readValidatedHistory(database, readOnly);
|
|
249
249
|
const current = history.current;
|
|
250
250
|
if (!current)
|
|
251
251
|
return rejected("no-current-launch", null);
|
|
@@ -274,7 +274,7 @@ export function verdictIfOpen(database, readOnly, input) {
|
|
|
274
274
|
throw new ProjectionGenerationStoreError(`verdict '${input.verdict}' is reserved to its runner-owned transition`);
|
|
275
275
|
}
|
|
276
276
|
return writeTransition(database, readOnly, () => {
|
|
277
|
-
const history = readValidatedHistory(database);
|
|
277
|
+
const history = readValidatedHistory(database, readOnly);
|
|
278
278
|
const current = history.current;
|
|
279
279
|
if (!current)
|
|
280
280
|
return rejected("no-current-launch", null);
|
|
@@ -308,7 +308,7 @@ export function supersedeStartupTimeout(database, readOnly, input) {
|
|
|
308
308
|
? undefined
|
|
309
309
|
: assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
310
310
|
return writeTransition(database, readOnly, () => {
|
|
311
|
-
const history = readValidatedHistory(database);
|
|
311
|
+
const history = readValidatedHistory(database, readOnly);
|
|
312
312
|
const current = history.current;
|
|
313
313
|
if (!current)
|
|
314
314
|
return rejected("no-current-launch", null);
|
|
@@ -356,7 +356,7 @@ export function settleStartupFailure(database, readOnly, input) {
|
|
|
356
356
|
? undefined
|
|
357
357
|
: assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
358
358
|
return writeTransition(database, readOnly, () => {
|
|
359
|
-
const history = readValidatedHistory(database);
|
|
359
|
+
const history = readValidatedHistory(database, readOnly);
|
|
360
360
|
const current = history.current;
|
|
361
361
|
if (!current)
|
|
362
362
|
return rejected("no-current-launch", null);
|
|
@@ -395,7 +395,7 @@ export function replaceDeadRunner(database, readOnly, input) {
|
|
|
395
395
|
? undefined
|
|
396
396
|
: assertIsoTimestamp(input.terminalAt, "terminalAt");
|
|
397
397
|
return writeTransition(database, readOnly, () => {
|
|
398
|
-
const history = readValidatedHistory(database);
|
|
398
|
+
const history = readValidatedHistory(database, readOnly);
|
|
399
399
|
const current = history.current;
|
|
400
400
|
if (!current)
|
|
401
401
|
return rejected("no-current-launch", null);
|
|
@@ -436,7 +436,7 @@ export function handoff(database, readOnly, input) {
|
|
|
436
436
|
const tellFence = validateTellFence([...input.tellFence], "handoff tellFence");
|
|
437
437
|
const successorFacts = validateLaunchFacts({ ...successorFactsBase, tellFence }, "handoff successor launch facts");
|
|
438
438
|
return writeTransition(database, readOnly, () => {
|
|
439
|
-
const history = readValidatedHistory(database);
|
|
439
|
+
const history = readValidatedHistory(database, readOnly);
|
|
440
440
|
const current = history.current;
|
|
441
441
|
if (!current)
|
|
442
442
|
return rejected("no-current-launch", null);
|
|
@@ -10,18 +10,18 @@ export { resolveProjectionCoordinate } from "./projection-coordinate.js";
|
|
|
10
10
|
export { appendGenerationEvent, executionEventsPath, isProjectionId, isPublishedProjection, isoFromNowMs, projectionDir, projectionDirAtCoordinate, projectionRoot, readProjectionEvents, readGenerationEventsWithRetention, } from "./projection-core.js";
|
|
11
11
|
export { readProjectionIdentity } from "./projection-identity.js";
|
|
12
12
|
export { interruptProjectionGeneration, killProjectionGeneration } from "./projection-kill.js";
|
|
13
|
+
export { openProjectionGenerationDoorbell, projectionGenerationDoorbellAddress, ringProjectionGenerationDoorbell, } from "./generation/projection-generation-doorbell.js";
|
|
13
14
|
export { observeProjectionLife, observeProjectionLifeSnapshot, } from "./projection-life-observer.js";
|
|
14
15
|
export { mintProjection, mintRepositoryProjection, ProjectionMintCollisionError, } from "./projection-mint.js";
|
|
15
|
-
export {
|
|
16
|
-
export { hasStrandableProjectionGeneration, prioritizeProjectionStatusRows, readAkumaNonterminalProjectionStatus, readExactProjectionStatus, readOperationalProjectionStatusBoard, } from "./projection-status.js";
|
|
16
|
+
export { hasStrandableProjectionGeneration, prioritizeProjectionStatusRows, paginateProjectionStatusRoster, triageProjectionStatusRows, readAkumaNonterminalProjectionStatus, readExactProjectionStatus, readOperationalProjectionStatusBoard, readProjectionRosterStatusBoard, selectProjectionStatus, } from "./projection-status.js";
|
|
17
17
|
export { PROJECTION_HISTORY_FILTER_COMPLETION, PROJECTION_HISTORY_FILTER_FIELDS, PROJECTION_HISTORY_FILTER_GRAMMAR, parseProjectionHistoryFilter, parseProjectionHistorySort, readProjectionHistoryAddress, readExactProjectionHistory, readProjectionHistory, resolveProjectionHistoryAddress, selectProjectionHistory, } from "./projection-history.js";
|
|
18
18
|
export { projectTerminalFailure, } from "./projection-terminal-failure.js";
|
|
19
19
|
export { snapshotCommissionProjectionIds, snapshotCommissionProjectionIdsAtCoordinate, waitForProjection, waitForProjectionSet, } from "./projection-wait.js";
|
|
20
20
|
export { assertTellEffortSupported, assertProjectionTellable, tellProjection, } from "./projection-wake.js";
|
|
21
21
|
export { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, ProjectionGenerationStore, } from "./generation/store.js";
|
|
22
|
-
export { createProjectionExecutionId } from "./generation/projection-generation-identity.js";
|
|
23
|
-
export {
|
|
24
|
-
export { projectionGenerationRunnerArgv,
|
|
22
|
+
export { createProjectionExecutionId, projectionRunnerLeasePath, } from "./generation/projection-generation-identity.js";
|
|
23
|
+
export { startProjectionGeneration } from "./generation/projection-generation-launcher.js";
|
|
24
|
+
export { projectionGenerationRunnerArgv, prepareProjectionGenerationRunner, } from "./generation/projection-generation-process.js";
|
|
25
25
|
export { runProjectionGeneration, } from "./generation/projection-generation-runner.js";
|
|
26
26
|
export { executeProjectionGeneration, prepareProjectionGenerationExecution, } from "./generation/projection-generation-execution.js";
|
|
27
27
|
export { runProjectionGenerationRuntime } from "./generation/projection-generation-runtime.js";
|
|
@@ -3,14 +3,18 @@ import * as path from "node:path";
|
|
|
3
3
|
import { isErrnoException } from "../../errno.js";
|
|
4
4
|
import { resolveProjectionCoordinate } from "./projection-coordinate.js";
|
|
5
5
|
import { ProjectionStateError, } from "../atomic-publish.js";
|
|
6
|
+
import { isAkumaName } from "./akuma-name.js";
|
|
6
7
|
export { atomicPublishFile, ProjectionStateError, randomHex8 } from "../atomic-publish.js";
|
|
7
8
|
export { isTellCausallyConsumed, } from "./tell/model.js";
|
|
8
9
|
export { bindTellLaunchReservation, claimAllInbox, claimAndReserveFencedTells, claimFencedTells, listTellLaunchBatch, listTellLaunchAdmissions, isTellLaunchAdmissionMember, claimTellToInflight, listTellIds, markTellSubmitted, recordTellReceiptCapabilities, recordTellReceipt, readTellReceiptCapabilities, readTellOriginal, readTellSubmitted, snapshotPendingTells, writeInboxTell, } from "./tell/store.js";
|
|
9
10
|
/** Relative segments for `.keiyaku/projection`. */
|
|
10
11
|
export const PROJECTION_ROOT_SEGMENTS = [".keiyaku", "projection"];
|
|
11
|
-
|
|
12
|
+
const PROJECTION_HEX_PATTERN = /^[0-9a-f]{8}$/;
|
|
12
13
|
export function isProjectionId(value) {
|
|
13
|
-
|
|
14
|
+
const slash = value.indexOf("/");
|
|
15
|
+
if (slash <= 0 || slash !== value.lastIndexOf("/"))
|
|
16
|
+
return false;
|
|
17
|
+
return isAkumaName(value.slice(0, slash)) && PROJECTION_HEX_PATTERN.test(value.slice(slash + 1));
|
|
14
18
|
}
|
|
15
19
|
/** Derive one projection storage root from already-resolved repository authority. */
|
|
16
20
|
export function projectionRootAtCoordinate(coordinate) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { claimAllInbox, isTellLaunchAdmissionMember, listTellLaunchAdmissions, listTellIds, markTellSubmitted, bindTellLaunchReservation, recordTellReceiptCapabilities, recordTellReceipt, readTellSubmitted, readTellOriginal, isTellCausallyConsumed, appendGenerationEvent, } from "./projection-core.js";
|
|
2
|
-
import { openProjectionTellObserver
|
|
2
|
+
import { openProjectionTellObserver } from "./generation/database.js";
|
|
3
3
|
const LIVE_TELL_DELIVERY_THROTTLE_MS = 200;
|
|
4
4
|
export function renderProjectionTellFrame(tellId, text) {
|
|
5
5
|
void tellId;
|
|
@@ -13,13 +13,12 @@ import { isProjectionId, projectionDir, projectionRoot, readGenerationEventsWith
|
|
|
13
13
|
import { projectionCoordinateRoot } from "./projection-coordinate.js";
|
|
14
14
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
15
15
|
import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
|
|
16
|
-
import { selectCurrentGeneration } from "./
|
|
17
|
-
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./generation/projection-generation-launcher.js";
|
|
16
|
+
import { selectCurrentGeneration } from "./generation/protocol.js";
|
|
18
17
|
export const PROJECTION_HISTORY_FILTER_FIELDS = ["contract", "akuma", "role", "outcome", "created", "updated"];
|
|
19
18
|
export const PROJECTION_HISTORY_FILTER_GRAMMAR = STRUCTURED_QUERY_GRAMMAR;
|
|
20
19
|
export const PROJECTION_HISTORY_FILTER_COMPLETION = STRUCTURED_QUERY_COMPLETION;
|
|
21
20
|
const HISTORY_FIELDS = new Set(PROJECTION_HISTORY_FILTER_FIELDS);
|
|
22
|
-
const HISTORY_ROLES = new Set(["call", "
|
|
21
|
+
const HISTORY_ROLES = new Set(["call", "fork", "unknown"]);
|
|
23
22
|
const HISTORY_OUTCOMES = new Set(["minting", "startup-timeout", "unknown", "out", "lost", "done", "killed", "dismissed", "failed", "dead", "incompatible"]);
|
|
24
23
|
const RELATIVE_TIME = /^now-([1-9][0-9]*)([smhdw])$/;
|
|
25
24
|
const UNIT_MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000 };
|
|
@@ -119,7 +118,7 @@ function outcomeFromLife(phase) {
|
|
|
119
118
|
function roleFromRecords(records) {
|
|
120
119
|
const inputs = records?.find((record) => record.kind === "launch")?.facts.inputs;
|
|
121
120
|
return inputs && typeof inputs === "object" && !Array.isArray(inputs) && typeof inputs.sourceArtifactId === "string"
|
|
122
|
-
? "
|
|
121
|
+
? "fork"
|
|
123
122
|
: records?.some((record) => record.kind === "launch") ? "call" : "unknown";
|
|
124
123
|
}
|
|
125
124
|
async function artifactFromVerdict(cwd, artifactId, executionId, index) {
|
|
@@ -235,10 +234,9 @@ async function readRun(artifactRoot, directory, id, alias, artifactIndex, addres
|
|
|
235
234
|
const diagnostics = [];
|
|
236
235
|
const snapshot = observeProjectionLifeSnapshot(directory, {
|
|
237
236
|
nowMs: Date.now(),
|
|
238
|
-
startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
|
|
239
237
|
});
|
|
240
238
|
if (snapshot.compatibility === "incompatible") {
|
|
241
|
-
return { id, ...(alias ? { alias } : {}), akuma: null, provider: null, pid: null, role: "unknown", contractId: null, outcome: "incompatible", mintedAt: null, terminalAt: null, generation: null, activityAt: null, artifact: null, artifacts: [], activityRetention: "incompatible", activityCount: 0, activityRange: null, telemetry: null, consequences: null, diagnostics: [snapshot.diagnostic], activity: null };
|
|
239
|
+
return { id, ...(alias ? { alias } : {}), akuma: null, provider: null, pid: null, role: "unknown", contractId: null, outcome: "incompatible", mintedAt: null, terminalAt: null, generation: null, activityAt: null, artifact: null, artifacts: [], activityRetention: "incompatible", activityCount: 0, activityRange: null, telemetry: null, consequences: null, diagnostics: [snapshot.diagnostic], terminalAnswer: null, activity: null };
|
|
242
240
|
}
|
|
243
241
|
let identity;
|
|
244
242
|
try {
|
|
@@ -296,6 +294,9 @@ async function readRun(artifactRoot, directory, id, alias, artifactIndex, addres
|
|
|
296
294
|
telemetry: telemetryFromActivity(activity),
|
|
297
295
|
consequences: null,
|
|
298
296
|
diagnostics,
|
|
297
|
+
terminalAnswer: typeof current?.verdict?.facts.finalMessage === "string"
|
|
298
|
+
? { kind: "text", text: current.verdict.facts.finalMessage }
|
|
299
|
+
: null,
|
|
299
300
|
activity,
|
|
300
301
|
};
|
|
301
302
|
}
|
|
@@ -384,7 +385,6 @@ async function retainedArtifactRelationships(root, artifactId, preferredAkuma) {
|
|
|
384
385
|
return [];
|
|
385
386
|
const snapshot = observeProjectionLifeSnapshot(directory, {
|
|
386
387
|
nowMs: Date.now(),
|
|
387
|
-
startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
|
|
388
388
|
});
|
|
389
389
|
if (snapshot.compatibility === "incompatible" || !snapshot.records)
|
|
390
390
|
return [];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { openProjectionGenerationStore } from "./generation/store.js";
|
|
2
|
-
import {
|
|
2
|
+
import { acquireRunnerLostProof, observeRunnerLease, RunnerLeaseUnavailableError, } from "../run-control/runner-lease.js";
|
|
3
|
+
import { projectionRunnerLeasePath } from "./generation/projection-generation-identity.js";
|
|
4
|
+
import { ringProjectionGenerationDoorbell } from "./generation/projection-generation-doorbell.js";
|
|
3
5
|
/** The runner observes this durable intent and owns native termination. */
|
|
4
6
|
export function interruptProjectionGeneration(projectionDirectory, nowMs = Date.now()) {
|
|
5
7
|
const store = openProjectionGenerationStore(projectionDirectory);
|
|
@@ -11,19 +13,23 @@ export function interruptProjectionGeneration(projectionDirectory, nowMs = Date.
|
|
|
11
13
|
if (current.verdict)
|
|
12
14
|
return { status: "already-closed", executionId: current.launch.executionId };
|
|
13
15
|
const executionId = current.launch.executionId;
|
|
14
|
-
if (!current.adoption ||
|
|
16
|
+
if (!current.adoption || observeRunnerLease(projectionRunnerLeasePath(projectionDirectory)).state !== "held") {
|
|
15
17
|
return { status: "already-closed", executionId };
|
|
16
18
|
}
|
|
17
19
|
const request = store.requestInterruptIfOpen({
|
|
18
20
|
executionId,
|
|
19
21
|
interruptedAt: new Date(nowMs).toISOString(),
|
|
20
22
|
});
|
|
21
|
-
if (request.status === "committed")
|
|
23
|
+
if (request.status === "committed") {
|
|
24
|
+
ringProjectionGenerationDoorbell(store.readIdentity(), executionId);
|
|
22
25
|
return { status: "accepted", executionId };
|
|
26
|
+
}
|
|
23
27
|
if (request.reason === "not-current")
|
|
24
28
|
continue;
|
|
25
|
-
if (request.reason === "interrupt-requested")
|
|
29
|
+
if (request.reason === "interrupt-requested") {
|
|
30
|
+
ringProjectionGenerationDoorbell(store.readIdentity(), executionId);
|
|
26
31
|
return { status: "accepted", executionId };
|
|
32
|
+
}
|
|
27
33
|
return { status: "already-closed", executionId };
|
|
28
34
|
}
|
|
29
35
|
}
|
|
@@ -39,10 +45,10 @@ function settleReleasedLeash(store, projectionDirectory, executionId, terminalAt
|
|
|
39
45
|
}
|
|
40
46
|
let deathEvidence;
|
|
41
47
|
try {
|
|
42
|
-
deathEvidence =
|
|
48
|
+
deathEvidence = acquireRunnerLostProof(projectionRunnerLeasePath(projectionDirectory));
|
|
43
49
|
}
|
|
44
50
|
catch (error) {
|
|
45
|
-
if (error instanceof
|
|
51
|
+
if (error instanceof RunnerLeaseUnavailableError) {
|
|
46
52
|
return { status: "accepted", executionId };
|
|
47
53
|
}
|
|
48
54
|
return { status: "accepted", executionId };
|
|
@@ -79,10 +85,13 @@ export function killProjectionGeneration(projectionDirectory, nowMs = Date.now()
|
|
|
79
85
|
const executionId = current.launch.executionId;
|
|
80
86
|
const request = store.requestKillIfOpen({ executionId, killedAt });
|
|
81
87
|
if (request.status === "committed") {
|
|
88
|
+
// A missing, stale, or rejected endpoint has no lifecycle meaning.
|
|
89
|
+
ringProjectionGenerationDoorbell(store.readIdentity(), executionId);
|
|
82
90
|
return settleReleasedLeash(store, projectionDirectory, executionId, new Date(nowMs).toISOString());
|
|
83
91
|
}
|
|
84
92
|
if (request.reason === "kill-requested") {
|
|
85
93
|
// Idempotent first intent: still accepted, then one leash observation.
|
|
94
|
+
ringProjectionGenerationDoorbell(store.readIdentity(), executionId);
|
|
86
95
|
return settleReleasedLeash(store, projectionDirectory, executionId, new Date(nowMs).toISOString());
|
|
87
96
|
}
|
|
88
97
|
if (request.reason === "already-terminal") {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { isIncompatibleProjectionGenerationStoreError, openProjectionGenerationStoreReadOnly, } from "./generation/store.js";
|
|
2
|
-
import { deriveProjectionLife, selectCurrentGeneration, } from "./
|
|
3
|
-
import {
|
|
2
|
+
import { deriveProjectionLife, selectCurrentGeneration, } from "./generation/protocol.js";
|
|
3
|
+
import { observeRunnerLease } from "../run-control/runner-lease.js";
|
|
4
|
+
import { projectionRunnerLeasePath } from "./generation/projection-generation-identity.js";
|
|
4
5
|
function errorDetail(error) {
|
|
5
6
|
return error instanceof Error ? error.message : String(error);
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* Observe the current generation without creating, repairing, or mutating
|
|
9
10
|
* projection storage. Generation history is the ordering authority; the
|
|
10
|
-
* runner lock is consulted
|
|
11
|
+
* runner lock is consulted for every non-terminal generation. Launch age is
|
|
12
|
+
* not lifecycle authority.
|
|
11
13
|
*/
|
|
12
14
|
export function observeProjectionLifeSnapshot(projectionDirectory, options) {
|
|
13
15
|
const readRecords = () => {
|
|
@@ -37,18 +39,17 @@ export function observeProjectionLifeSnapshot(projectionDirectory, options) {
|
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
const current = selectCurrentGeneration(records);
|
|
40
|
-
if (!current || current.verdict
|
|
42
|
+
if (!current || current.verdict) {
|
|
41
43
|
return {
|
|
42
44
|
compatibility: "current",
|
|
43
45
|
life: deriveProjectionLife({
|
|
44
46
|
records,
|
|
45
47
|
nowMs: options.nowMs,
|
|
46
|
-
startupTimeoutMs: options.startupTimeoutMs,
|
|
47
48
|
}),
|
|
48
49
|
records,
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
|
-
const lock =
|
|
52
|
+
const lock = observeRunnerLease(projectionRunnerLeasePath(projectionDirectory));
|
|
52
53
|
let after;
|
|
53
54
|
try {
|
|
54
55
|
after = readRecords();
|
|
@@ -74,13 +75,12 @@ export function observeProjectionLifeSnapshot(projectionDirectory, options) {
|
|
|
74
75
|
compatibility: "current",
|
|
75
76
|
life: deriveProjectionLife({
|
|
76
77
|
records,
|
|
77
|
-
|
|
78
|
+
runnerLease: lock.state === "held"
|
|
78
79
|
? "held"
|
|
79
80
|
: lock.state === "released"
|
|
80
81
|
? "released"
|
|
81
82
|
: "unknown",
|
|
82
83
|
nowMs: options.nowMs,
|
|
83
|
-
startupTimeoutMs: options.startupTimeoutMs,
|
|
84
84
|
}),
|
|
85
85
|
records,
|
|
86
86
|
};
|
|
@@ -5,7 +5,9 @@ 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
7
|
import { openProjectionGenerationStore } from "./generation/store.js";
|
|
8
|
-
import {
|
|
8
|
+
import { initializeRunnerLeaseDatabase } from "../run-control/runner-lease.js";
|
|
9
|
+
import { projectionRunnerLeasePath } from "./generation/projection-generation-identity.js";
|
|
10
|
+
import { isAkumaName } from "./akuma-name.js";
|
|
9
11
|
export class ProjectionMintCollisionError extends Error {
|
|
10
12
|
code = "PROJECTION_MINT_COLLISION";
|
|
11
13
|
constructor(message, options) {
|
|
@@ -15,14 +17,10 @@ export class ProjectionMintCollisionError extends Error {
|
|
|
15
17
|
}
|
|
16
18
|
const DEFAULT_MINT_ATTEMPTS = 16;
|
|
17
19
|
function assertMintSlug(slug) {
|
|
18
|
-
|
|
19
|
-
if (!normalized) {
|
|
20
|
-
throw new ProjectionStateError("projection slug cannot be empty");
|
|
21
|
-
}
|
|
22
|
-
if (!/^[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*$/.test(normalized)) {
|
|
20
|
+
if (!isAkumaName(slug)) {
|
|
23
21
|
throw new ProjectionStateError(`invalid projection slug: ${slug}`);
|
|
24
22
|
}
|
|
25
|
-
return
|
|
23
|
+
return slug;
|
|
26
24
|
}
|
|
27
25
|
function removeEmptyAkumaRoot(dir) {
|
|
28
26
|
try {
|
|
@@ -115,7 +113,7 @@ function publishReservedProjection(pact, reserved) {
|
|
|
115
113
|
finally {
|
|
116
114
|
heart.close();
|
|
117
115
|
}
|
|
118
|
-
|
|
116
|
+
initializeRunnerLeaseDatabase(projectionRunnerLeasePath(reserved.stagingDir));
|
|
119
117
|
fs.renameSync(reserved.stagingDir, reserved.dir);
|
|
120
118
|
published = true;
|
|
121
119
|
return { id: reserved.id, dir: reserved.dir, pact };
|
|
@@ -7,12 +7,51 @@ import { foldPublicProjectionActivity } from "./projection-activity.js";
|
|
|
7
7
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
8
8
|
import { readPendingTellWindow, readProjectionTellCounts } from "./tell/store.js";
|
|
9
9
|
import { ProjectionGenerationStoreError } from "./generation/store.js";
|
|
10
|
-
import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./generation/projection-generation-launcher.js";
|
|
11
10
|
import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
|
|
12
|
-
import { selectCurrentGeneration } from "./
|
|
11
|
+
import { selectCurrentGeneration } from "./generation/protocol.js";
|
|
13
12
|
import { invalidActivityEventDiagnostic, selectValidStoredAgentEvents } from "../stored-agent-event.js";
|
|
14
13
|
import { projectTerminalFailure } from "./projection-terminal-failure.js";
|
|
15
14
|
import { extractTerminalTimestamp } from "./generation/model.js";
|
|
15
|
+
function latestActivityRow(activity, kind, predicate) {
|
|
16
|
+
const rows = activity?.retainedTimeline.filter((row) => row.kind === kind) ?? [];
|
|
17
|
+
return [...rows].reverse().find((row) => predicate?.(row) ?? true);
|
|
18
|
+
}
|
|
19
|
+
export function deriveProjectionStatusReadFacts(input) {
|
|
20
|
+
const warning = latestActivityRow(input.activity, "warning");
|
|
21
|
+
const runningTool = latestActivityRow(input.activity, "ran", (row) => row.state === "running");
|
|
22
|
+
const said = latestActivityRow(input.activity, "said");
|
|
23
|
+
const answer = typeof input.verdictFacts?.finalMessage === "string"
|
|
24
|
+
? { kind: "text", text: input.verdictFacts.finalMessage }
|
|
25
|
+
: undefined;
|
|
26
|
+
const responsePath = typeof input.verdictFacts?.responsePath === "string" ? input.verdictFacts.responsePath : undefined;
|
|
27
|
+
const artifactId = typeof input.verdictFacts?.artifactId === "string" ? input.verdictFacts.artifactId : undefined;
|
|
28
|
+
const launchInputs = input.launchFacts?.inputs;
|
|
29
|
+
const incognito = launchInputs !== null && typeof launchInputs === "object" && !Array.isArray(launchInputs)
|
|
30
|
+
&& launchInputs.persistProjectionResponse === false;
|
|
31
|
+
const persistenceFailed = input.verdictFacts?.responsePersistError !== undefined;
|
|
32
|
+
const snapshot = warning
|
|
33
|
+
? { kind: "warning", row: warning }
|
|
34
|
+
: runningTool
|
|
35
|
+
? { kind: "running-tool", row: runningTool }
|
|
36
|
+
: said
|
|
37
|
+
? { kind: "said", row: said }
|
|
38
|
+
: input.activity?.plan
|
|
39
|
+
? { kind: "plan", plan: input.activity.plan }
|
|
40
|
+
: undefined;
|
|
41
|
+
const responseArtifact = input.verdictFacts === undefined
|
|
42
|
+
? undefined
|
|
43
|
+
: responsePath
|
|
44
|
+
? { state: "retained", path: responsePath, ...(artifactId ? { artifactId } : {}) }
|
|
45
|
+
: incognito
|
|
46
|
+
? { state: "none", reason: "incognito" }
|
|
47
|
+
: { state: "unavailable", reason: persistenceFailed ? "persistence-failed" : "not-observed" };
|
|
48
|
+
return {
|
|
49
|
+
...(answer ? { terminalAnswer: answer } : {}),
|
|
50
|
+
...(responseArtifact ? { responseArtifact } : {}),
|
|
51
|
+
attention: { ...(warning ? { latestWarning: warning } : {}) },
|
|
52
|
+
...(snapshot ? { snapshot } : {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
16
55
|
const MAX_STATUS_FILE_BYTES = 256 * 1024;
|
|
17
56
|
class ProjectionStatusFileError extends Error {
|
|
18
57
|
diagnostic;
|
|
@@ -233,11 +272,19 @@ function readActivityFacts(projectionDir, executionId, nowMs, diagnostics, fallb
|
|
|
233
272
|
function terminalTimestamp(current) {
|
|
234
273
|
return extractTerminalTimestamp(current?.verdict?.facts);
|
|
235
274
|
}
|
|
275
|
+
function terminalAgeAt(terminalAt, observedAtMs) {
|
|
276
|
+
const terminalAtMs = Date.parse(terminalAt ?? "");
|
|
277
|
+
return Number.isFinite(terminalAtMs) ? Math.max(0, observedAtMs - terminalAtMs) : undefined;
|
|
278
|
+
}
|
|
279
|
+
function projectionStatusState(life) {
|
|
280
|
+
if (life.verdict === "lost-runner")
|
|
281
|
+
return "dead";
|
|
282
|
+
return life.phase === "active" || life.phase === "quiescent" ? "out" : life.phase;
|
|
283
|
+
}
|
|
236
284
|
export function readProjectionSummary(projectionDir, id, alias, nowMs, options) {
|
|
237
285
|
const diagnostics = [];
|
|
238
286
|
const snapshot = observeProjectionLifeSnapshot(projectionDir, {
|
|
239
287
|
nowMs,
|
|
240
|
-
startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
|
|
241
288
|
});
|
|
242
289
|
if (snapshot.compatibility === "incompatible") {
|
|
243
290
|
return {
|
|
@@ -251,8 +298,7 @@ export function readProjectionSummary(projectionDir, id, alias, nowMs, options)
|
|
|
251
298
|
};
|
|
252
299
|
}
|
|
253
300
|
const life = snapshot.life;
|
|
254
|
-
const
|
|
255
|
-
const state = phase === "active" || phase === "quiescent" ? "out" : phase;
|
|
301
|
+
const state = projectionStatusState(life);
|
|
256
302
|
const identityFacts = options?.requiresIdentity?.(state) === false
|
|
257
303
|
? null
|
|
258
304
|
: readIdentityFacts(projectionDir, diagnostics);
|
|
@@ -268,27 +314,38 @@ export function readProjectionSummary(projectionDir, id, alias, nowMs, options)
|
|
|
268
314
|
}
|
|
269
315
|
export function readProjectionRow(summary, nowMs, readDetails) {
|
|
270
316
|
const { id, alias, projectionDir, snapshot } = summary;
|
|
317
|
+
const identity = { canonicalId: id };
|
|
271
318
|
const diagnostics = [...summary.diagnostics];
|
|
272
319
|
if (snapshot.compatibility === "incompatible") {
|
|
273
320
|
return {
|
|
274
321
|
id,
|
|
322
|
+
identity,
|
|
275
323
|
observedAtMs: nowMs,
|
|
276
324
|
...(alias ? { alias } : {}),
|
|
277
325
|
state: "incompatible",
|
|
278
326
|
observation: snapshot,
|
|
279
327
|
tellCounts: emptyTellCounts(),
|
|
328
|
+
attention: {},
|
|
280
329
|
diagnostics,
|
|
281
330
|
};
|
|
282
331
|
}
|
|
283
332
|
const identityFacts = summary.identityFacts;
|
|
284
333
|
if (identityFacts === null && !readDetails) {
|
|
334
|
+
const current = snapshot.records ? selectCurrentGeneration(snapshot.records) : null;
|
|
335
|
+
const terminalAt = terminalTimestamp(current);
|
|
336
|
+
const terminalAgeMs = current?.verdict ? terminalAgeAt(terminalAt, nowMs) : undefined;
|
|
337
|
+
const readFacts = deriveProjectionStatusReadFacts({ state: summary.state });
|
|
285
338
|
return {
|
|
286
339
|
id,
|
|
340
|
+
identity,
|
|
287
341
|
observedAtMs: nowMs,
|
|
288
342
|
...(alias ? { alias } : {}),
|
|
289
343
|
state: summary.state,
|
|
290
344
|
observation: { compatibility: "current", lifecycle: snapshot.life },
|
|
345
|
+
...(terminalAt ? { terminalAt } : {}),
|
|
346
|
+
...(terminalAgeMs !== undefined ? { terminalAgeMs } : {}),
|
|
291
347
|
tellCounts: emptyTellCounts(),
|
|
348
|
+
...readFacts,
|
|
292
349
|
diagnostics,
|
|
293
350
|
};
|
|
294
351
|
}
|
|
@@ -297,6 +354,7 @@ export function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
297
354
|
?? "projection identity could not be observed";
|
|
298
355
|
return {
|
|
299
356
|
id,
|
|
357
|
+
identity,
|
|
300
358
|
observedAtMs: nowMs,
|
|
301
359
|
...(alias ? { alias } : {}),
|
|
302
360
|
state: "unknown",
|
|
@@ -305,6 +363,7 @@ export function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
305
363
|
lifecycle: { phase: "unknown", diagnostic },
|
|
306
364
|
},
|
|
307
365
|
tellCounts: emptyTellCounts(),
|
|
366
|
+
attention: {},
|
|
308
367
|
diagnostics,
|
|
309
368
|
};
|
|
310
369
|
}
|
|
@@ -325,8 +384,10 @@ export function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
325
384
|
: {};
|
|
326
385
|
const mintedAtMs = Date.parse(identityFacts.mintedAt ?? "");
|
|
327
386
|
const terminalAt = terminalTimestamp(current);
|
|
387
|
+
const terminalAtMs = Date.parse(terminalAt ?? "");
|
|
388
|
+
const terminalAgeMs = current?.verdict ? terminalAgeAt(terminalAt, nowMs) : undefined;
|
|
328
389
|
const durationAnchorMs = current?.verdict
|
|
329
|
-
?
|
|
390
|
+
? terminalAtMs
|
|
330
391
|
: nowMs;
|
|
331
392
|
const durationMs = Number.isFinite(mintedAtMs) && Number.isFinite(durationAnchorMs)
|
|
332
393
|
? Math.max(0, durationAnchorMs - mintedAtMs)
|
|
@@ -336,13 +397,19 @@ export function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
336
397
|
if (life.phase === "unknown" && life.diagnostic) {
|
|
337
398
|
diagnostics.push({ kind: "unknown-lifecycle", detail: life.diagnostic });
|
|
338
399
|
}
|
|
339
|
-
const
|
|
340
|
-
const state = phase === "active" || phase === "quiescent" ? "out" : phase;
|
|
400
|
+
const state = projectionStatusState(life);
|
|
341
401
|
const terminalFailure = current?.verdict
|
|
342
402
|
? projectTerminalFailure(current.verdict.facts.state, current.verdict.facts)
|
|
343
403
|
: undefined;
|
|
404
|
+
const readFacts = deriveProjectionStatusReadFacts({
|
|
405
|
+
state,
|
|
406
|
+
activity: activityFacts.activity,
|
|
407
|
+
verdictFacts: current?.verdict?.facts,
|
|
408
|
+
launchFacts: current?.launch.facts,
|
|
409
|
+
});
|
|
344
410
|
return {
|
|
345
411
|
id,
|
|
412
|
+
identity,
|
|
346
413
|
observedAtMs: nowMs,
|
|
347
414
|
...(alias ? { alias } : {}),
|
|
348
415
|
state,
|
|
@@ -353,11 +420,13 @@ export function readProjectionRow(summary, nowMs, readDetails) {
|
|
|
353
420
|
pid: identityFacts.pid,
|
|
354
421
|
mintedAt: identityFacts.mintedAt,
|
|
355
422
|
...(terminalAt ? { terminalAt } : {}),
|
|
423
|
+
...(terminalAgeMs !== undefined ? { terminalAgeMs } : {}),
|
|
356
424
|
...(durationMs !== undefined ? { durationMs } : {}),
|
|
357
425
|
...(identityFacts.workspaceRoot ? { workspaceRoot: identityFacts.workspaceRoot } : {}),
|
|
358
426
|
...activityFacts,
|
|
359
427
|
...(displayAgeMs !== undefined ? { activityAgeMs: displayAgeMs } : {}),
|
|
360
428
|
...(terminalFailure ? { terminalFailure } : {}),
|
|
429
|
+
...readFacts,
|
|
361
430
|
tellCounts,
|
|
362
431
|
...(pendingTells.length > 0 ? { pendingTells } : {}),
|
|
363
432
|
diagnostics,
|