blun-king-cli 9.1.567 → 9.1.569
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/agent-spine-plugin/.claude-plugin/marketplace.json +1 -1
- package/agent-spine-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-spine-plugin/.codex-plugin/plugin.json +2 -1
- package/agent-spine-plugin/CHANGELOG.md +1581 -0
- package/agent-spine-plugin/README.md +30 -4
- package/agent-spine-plugin/blun.plugin.json +3 -3
- package/agent-spine-plugin/docs/acceptance.md +61 -0
- package/agent-spine-plugin/docs/assignment-continuation.md +48 -0
- package/agent-spine-plugin/docs/host-integration.md +178 -0
- package/agent-spine-plugin/docs/preflight-recall.md +69 -0
- package/agent-spine-plugin/docs/preservation-contract.md +53 -0
- package/agent-spine-plugin/docs/quality-gates.md +50 -0
- package/agent-spine-plugin/docs/releasing.md +85 -0
- package/agent-spine-plugin/docs/session-timeline.md +251 -0
- package/agent-spine-plugin/docs/source-roots.md +113 -0
- package/agent-spine-plugin/docs/structured-completion.md +67 -0
- package/agent-spine-plugin/docs/world-model.md +94 -0
- package/agent-spine-plugin/hooks/codex.json +2 -2
- package/agent-spine-plugin/hooks/hooks.json +1 -1
- package/agent-spine-plugin/hooks/version.json +1 -1
- package/agent-spine-plugin/package.json +13 -3
- package/agent-spine-plugin/scripts/check-codex-install.js +226 -0
- package/agent-spine-plugin/scripts/check-hosts.js +14 -5
- package/agent-spine-plugin/scripts/check-install-hook.js +226 -0
- package/agent-spine-plugin/scripts/check-install-selfstarter.js +154 -0
- package/agent-spine-plugin/scripts/check-install.js +478 -0
- package/agent-spine-plugin/scripts/check-line-budget.js +58 -0
- package/agent-spine-plugin/scripts/check-syntax.js +29 -0
- package/agent-spine-plugin/scripts/github-actions.js +11 -0
- package/agent-spine-plugin/scripts/hermetic-process.js +183 -0
- package/agent-spine-plugin/scripts/release-check.js +145 -0
- package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
- package/agent-spine-plugin/scripts/run-checks.js +47 -0
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +89 -0
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +16 -2
- package/agent-spine-plugin/spine-example/1-identity.md +12 -0
- package/agent-spine-plugin/spine-example/2-voice.md +6 -0
- package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
- package/agent-spine-plugin/spine-example/4-history.md +4 -0
- package/agent-spine-plugin/src/cli-agent.js +296 -0
- package/agent-spine-plugin/src/cli-attention.js +95 -0
- package/agent-spine-plugin/src/cli-autonomy.js +36 -0
- package/agent-spine-plugin/src/cli-common.js +71 -0
- package/agent-spine-plugin/src/cli-continuity.js +116 -0
- package/agent-spine-plugin/src/cli-core.js +128 -0
- package/agent-spine-plugin/src/cli-diagnostics.js +291 -0
- package/agent-spine-plugin/src/cli-host.js +21 -0
- package/agent-spine-plugin/src/cli-learning.js +305 -0
- package/agent-spine-plugin/src/cli-premortem.js +16 -0
- package/agent-spine-plugin/src/cli-sharing.js +230 -0
- package/agent-spine-plugin/src/cli.js +40 -1350
- package/agent-spine-plugin/src/codex-reader-launcher.js +182 -0
- package/agent-spine-plugin/src/hook.js +185 -567
- package/agent-spine-plugin/src/index.js +16 -2
- package/agent-spine-plugin/src/lib/acceptance.js +113 -11
- package/agent-spine-plugin/src/lib/action-lesson-recall.js +53 -0
- package/agent-spine-plugin/src/lib/attention-context.js +167 -0
- package/agent-spine-plugin/src/lib/attention-events.js +113 -0
- package/agent-spine-plugin/src/lib/attention-privacy.js +72 -0
- package/agent-spine-plugin/src/lib/attention-schema.js +164 -0
- package/agent-spine-plugin/src/lib/attention-storage.js +93 -0
- package/agent-spine-plugin/src/lib/attention.js +9 -600
- package/agent-spine-plugin/src/lib/audit-premortem.js +223 -0
- package/agent-spine-plugin/src/lib/audit.js +56 -6
- package/agent-spine-plugin/src/lib/autonomy-policy.js +110 -0
- package/agent-spine-plugin/src/lib/autonomy-store.js +202 -0
- package/agent-spine-plugin/src/lib/autonomy.js +8 -0
- package/agent-spine-plugin/src/lib/briefing.js +67 -4
- package/agent-spine-plugin/src/lib/catalog-document-read.js +51 -0
- package/agent-spine-plugin/src/lib/catalog.js +1 -1
- package/agent-spine-plugin/src/lib/codex-installation.js +231 -0
- package/agent-spine-plugin/src/lib/codex-skill-installation.js +211 -0
- package/agent-spine-plugin/src/lib/context.js +3 -1
- package/agent-spine-plugin/src/lib/delivery-agent-usage.js +224 -0
- package/agent-spine-plugin/src/lib/delivery-assignment.js +220 -0
- package/agent-spine-plugin/src/lib/delivery-command-actions.js +453 -0
- package/agent-spine-plugin/src/lib/delivery-knowledge.js +78 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-binding.js +107 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-closure.js +171 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-codec.js +45 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-correction.js +101 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-file.js +21 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-index.js +493 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-inspection.js +37 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-recovery.js +120 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-rejection.js +65 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-results.js +28 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-session-guard.js +46 -0
- package/agent-spine-plugin/src/lib/delivery-premortem-write-ledger.js +285 -0
- package/agent-spine-plugin/src/lib/delivery-premortem.js +499 -0
- package/agent-spine-plugin/src/lib/delivery-shell-heredoc.js +115 -0
- package/agent-spine-plugin/src/lib/delivery-shell-substitutions.js +111 -0
- package/agent-spine-plugin/src/lib/delivery-shell-wrapper.js +64 -0
- package/agent-spine-plugin/src/lib/delivery-target.js +73 -0
- package/agent-spine-plugin/src/lib/delivery-verification.js +445 -0
- package/agent-spine-plugin/src/lib/documents.js +27 -5
- package/agent-spine-plugin/src/lib/filesystem-retry.js +2 -0
- package/agent-spine-plugin/src/lib/gateway-common.js +68 -0
- package/agent-spine-plugin/src/lib/gateway-control.js +302 -0
- package/agent-spine-plugin/src/lib/gateway-delivery.js +103 -0
- package/agent-spine-plugin/src/lib/gateway-execution.js +350 -0
- package/agent-spine-plugin/src/lib/gateway-host-lifecycle.js +185 -0
- package/agent-spine-plugin/src/lib/gateway-inspection.js +85 -0
- package/agent-spine-plugin/src/lib/gateway-knowledge.js +129 -0
- package/agent-spine-plugin/src/lib/gateway-policy-provenance.js +197 -0
- package/agent-spine-plugin/src/lib/gateway-premortem-disposition.js +82 -0
- package/agent-spine-plugin/src/lib/gateway-premortem.js +363 -0
- package/agent-spine-plugin/src/lib/gateway-runs.js +300 -0
- package/agent-spine-plugin/src/lib/gateway-runtime-identity.js +31 -0
- package/agent-spine-plugin/src/lib/gateway-runtime-records.js +21 -0
- package/agent-spine-plugin/src/lib/gateway-runtime.js +18 -1623
- package/agent-spine-plugin/src/lib/gateway-state-transaction.js +356 -0
- package/agent-spine-plugin/src/lib/gateway-state.js +342 -0
- package/agent-spine-plugin/src/lib/hook-artifact-guards.js +356 -0
- package/agent-spine-plugin/src/lib/hook-audit.js +16 -2
- package/agent-spine-plugin/src/lib/hook-briefing-use.js +68 -0
- package/agent-spine-plugin/src/lib/hook-context.js +424 -0
- package/agent-spine-plugin/src/lib/hook-final-message.js +26 -0
- package/agent-spine-plugin/src/lib/hook-input.js +27 -0
- package/agent-spine-plugin/src/lib/hook-output.js +140 -0
- package/agent-spine-plugin/src/lib/hook-premortem.js +257 -0
- package/agent-spine-plugin/src/lib/hook-process-advisory.js +37 -0
- package/agent-spine-plugin/src/lib/hook-protection.js +95 -0
- package/agent-spine-plugin/src/lib/hook-stop-verification.js +84 -0
- package/agent-spine-plugin/src/lib/hook-timeline.js +91 -0
- package/agent-spine-plugin/src/lib/identifier-analysis.js +446 -0
- package/agent-spine-plugin/src/lib/indexed-memory.js +23 -6
- package/agent-spine-plugin/src/lib/knowledge-evidence.js +431 -0
- package/agent-spine-plugin/src/lib/learning-applications.js +441 -0
- package/agent-spine-plugin/src/lib/learning-candidates.js +274 -0
- package/agent-spine-plugin/src/lib/learning-context.js +130 -0
- package/agent-spine-plugin/src/lib/learning-delivery-contracts.js +310 -0
- package/agent-spine-plugin/src/lib/learning-evaluation-contracts.js +350 -0
- package/agent-spine-plugin/src/lib/learning-evaluation-registration.js +372 -0
- package/agent-spine-plugin/src/lib/learning-evaluation-revocation.js +292 -0
- package/agent-spine-plugin/src/lib/learning-evidence-contracts.js +321 -0
- package/agent-spine-plugin/src/lib/learning-findings.js +458 -0
- package/agent-spine-plugin/src/lib/learning-measurement-contracts.js +285 -0
- package/agent-spine-plugin/src/lib/learning-measurements.js +265 -0
- package/agent-spine-plugin/src/lib/learning-outcome-contracts.js +165 -0
- package/agent-spine-plugin/src/lib/learning-outcomes.js +343 -0
- package/agent-spine-plugin/src/lib/learning-reconciliation.js +290 -0
- package/agent-spine-plugin/src/lib/learning-retry-contracts.js +188 -0
- package/agent-spine-plugin/src/lib/learning-schema.js +229 -0
- package/agent-spine-plugin/src/lib/learning-scope-targets.js +424 -0
- package/agent-spine-plugin/src/lib/learning-state-upgrade.js +477 -0
- package/agent-spine-plugin/src/lib/learning-status-configuration.js +476 -0
- package/agent-spine-plugin/src/lib/learning-storage.js +203 -0
- package/agent-spine-plugin/src/lib/learning-trial-recovery.js +218 -0
- package/agent-spine-plugin/src/lib/learning-validation-contracts.js +375 -0
- package/agent-spine-plugin/src/lib/learning-validation-renewal.js +298 -0
- package/agent-spine-plugin/src/lib/learning-validation-runtime.js +234 -0
- package/agent-spine-plugin/src/lib/learning.js +36 -6923
- package/agent-spine-plugin/src/lib/lesson-recall-session.js +172 -0
- package/agent-spine-plugin/src/lib/mcp-autonomy-tools.js +37 -0
- package/agent-spine-plugin/src/lib/mcp-delivery-completion.js +124 -0
- package/agent-spine-plugin/src/lib/mcp-delivery-tools.js +45 -0
- package/agent-spine-plugin/src/lib/mcp-premortem.js +68 -0
- package/agent-spine-plugin/src/lib/mcp-runtime.js +269 -0
- package/agent-spine-plugin/src/lib/mcp-source-context.js +51 -0
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +164 -0
- package/agent-spine-plugin/src/lib/mcp-world-tools.js +52 -0
- package/agent-spine-plugin/src/lib/owned-file-lock.js +30 -10
- package/agent-spine-plugin/src/lib/project-portfolio.js +176 -0
- package/agent-spine-plugin/src/lib/selfstarter-core.js +382 -0
- package/agent-spine-plugin/src/lib/selfstarter-jobs.js +149 -0
- package/agent-spine-plugin/src/lib/selfstarter-lease.js +204 -0
- package/agent-spine-plugin/src/lib/selfstarter-policy.js +90 -0
- package/agent-spine-plugin/src/lib/selfstarter-workspace.js +111 -0
- package/agent-spine-plugin/src/lib/selfstarter.js +11 -911
- package/agent-spine-plugin/src/lib/session-timeline-auth.js +316 -0
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +58 -0
- package/agent-spine-plugin/src/lib/session-timeline-contract.js +48 -0
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +41 -0
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +132 -0
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +17 -0
- package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +500 -0
- package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +157 -0
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +74 -0
- package/agent-spine-plugin/src/lib/session-timeline-host-receipt.js +117 -0
- package/agent-spine-plugin/src/lib/session-timeline-invocation.js +201 -0
- package/agent-spine-plugin/src/lib/session-timeline-king.js +79 -0
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +59 -0
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +34 -0
- package/agent-spine-plugin/src/lib/session-timeline-query.js +55 -0
- package/agent-spine-plugin/src/lib/session-timeline-results.js +31 -0
- package/agent-spine-plugin/src/lib/session-timeline-root.js +11 -0
- package/agent-spine-plugin/src/lib/session-timeline-search.js +82 -0
- package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +217 -0
- package/agent-spine-plugin/src/lib/session-timeline-source.js +83 -0
- package/agent-spine-plugin/src/lib/session-timeline-state.js +45 -0
- package/agent-spine-plugin/src/lib/session-timeline-transport.js +50 -0
- package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +148 -0
- package/agent-spine-plugin/src/lib/session-timeline.js +453 -0
- package/agent-spine-plugin/src/lib/source-roots.js +69 -136
- package/agent-spine-plugin/src/lib/source-tree-scan.js +178 -0
- package/agent-spine-plugin/src/lib/task-knowledge-context.js +78 -0
- package/agent-spine-plugin/src/lib/timeline-tool-guard.js +202 -0
- package/agent-spine-plugin/src/lib/world-knowledge.js +249 -0
- package/agent-spine-plugin/src/lib/world-model.js +278 -0
- package/agent-spine-plugin/src/mcp.js +20 -161
- package/agent-spine-plugin/src/version.js +1 -1
- package/agent-spine-plugin/src/worker.js +22 -5
- package/bin/agent-resume-snapshot.cjs +2 -2
- package/bin/agentspine-king-goal-inbox.mjs +111 -0
- package/bin/agentspine-king-goal-intake.mjs +106 -0
- package/bin/baseline-skill-performance-policy.cjs +1 -16
- package/bin/core-bootstrap.js +2 -0
- package/bin/curiosity-scout-policy.cjs +5 -1
- package/bin/input-draft-persistence.cjs +2 -2
- package/bin/king-tui-function-contract.json +33 -0
- package/bin/launcher-restart-policy.cjs +150 -0
- package/bin/launcher-runtime.js +56 -44
- package/bin/managed-context-startup-policy.cjs +27 -0
- package/bin/managed-plugin-selection.cjs +116 -0
- package/bin/mistake-relevance-policy.cjs +1 -1
- package/bin/observer-hooks.cjs +14 -0
- package/bin/oversized-context-offload-policy.cjs +86 -0
- package/bin/plugin-bootstrap.js +7 -40
- package/bin/proactive-compaction-policy.cjs +1 -1
- package/bin/provider-model-refresh-deadline.cjs +53 -0
- package/bin/provider-model-refresh-policy.cjs +107 -0
- package/bin/release-artifact-freeze-policy.cjs +30 -0
- package/bin/repeated-user-message-projection.cjs +3 -126
- package/bin/research-page-result.cjs +74 -0
- package/bin/runtime-exit-ledger.cjs +1 -0
- package/bin/session-compaction-policy.cjs +84 -0
- package/bin/skill-listing-performance-policy.cjs +2 -2
- package/bin/standard-tools-bootstrap.js +0 -37
- package/bin/subagent-skill-policy.cjs +3 -1
- package/bin/telegram-approval-relay.cjs +12 -7
- package/bin/telegram-private-conversation-policy.cjs +3 -2
- package/bin/telegram-queue-handoff-policy.cjs +24 -0
- package/bin/thinking-activity-status-policy.cjs +1 -1
- package/bin/thinking-only-guard.cjs +16 -12
- package/bin/tool-call-loop-policy.cjs +0 -2
- package/bin/tool-result-offload-policy.cjs +11 -2
- package/bin/tui-functional-contract.cjs +55 -0
- package/bin/update-notice.js +18 -14
- package/bin/user-message-offload-policy.cjs +1 -1
- package/bin/user-prompt-hook-origin-policy.cjs +34 -0
- package/bin/windows-node-crash-dump.cjs +110 -0
- package/blun.mjs +2517 -1048
- package/codebase-index/codebase_index.py +4 -3
- package/package.json +3 -17
- package/standard-skills/research-evidence/SKILL.md +39 -0
- package/standard-skills/research-evidence/references/evidence-format.md +82 -0
- package/standard-skills/research-evidence/scripts/evidence-collection.cjs +254 -0
- package/standard-skills/research-evidence/scripts/score-report.cjs +112 -0
- package/standard-skills/web-lesen/SKILL.md +37 -22
- package/standard-skills/web-lesen/scripts/crawl_public.py +376 -0
- package/telegram-plugin/DELIVERY.md +36 -0
- package/telegram-plugin/bin/telegram-approval-relay.cjs +13 -7
- package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +122 -0
- package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +3 -2
- package/telegram-plugin/bin/telegram-reply-parts.cjs +149 -0
- package/telegram-plugin/dist/bridge.mjs +7 -56
- package/telegram-plugin/dist/mcp-server.mjs +33 -4
- package/agent-spine-plugin/skill/SKILL.md +0 -76
- package/bin/mnemo-connect-heartbeat.cjs +0 -204
- package/bin/mnemo-tool-agent-policy.cjs +0 -22
- package/telegram-plugin/bin/telegram-mnemo-capture.cjs +0 -297
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { inspectDeliveryPremortems } from "./delivery-premortem.js";
|
|
4
|
+
import { createPremortemAttachment } from "./delivery-premortem-closure.js";
|
|
5
|
+
import { premortemGoalBindingSummary } from "./delivery-premortem-binding.js";
|
|
6
|
+
import { inspectPremortemLaneIndexes, premortemScopeDigest } from "./delivery-premortem-index.js";
|
|
7
|
+
import {
|
|
8
|
+
inspectPremortemWriteIndexes,
|
|
9
|
+
inspectPremortemWriteProof
|
|
10
|
+
} from "./delivery-premortem-write-ledger.js";
|
|
11
|
+
|
|
12
|
+
const WRITE_INDEX_MISMATCH = "AGENTSPINE_PREMORTEM_MISMATCH";
|
|
13
|
+
|
|
14
|
+
export function premortemIndexCrossReferenceFindings(premortems, indexes, gatewayPolicy) {
|
|
15
|
+
const findings = [];
|
|
16
|
+
const statesByLane = new Map(premortems.states.map((state) => [state.laneDigest, state]));
|
|
17
|
+
const pointersByLane = new Map();
|
|
18
|
+
for (const pointer of indexes.pointers) {
|
|
19
|
+
const values = pointersByLane.get(pointer.laneDigest) || [];
|
|
20
|
+
values.push(pointer);
|
|
21
|
+
pointersByLane.set(pointer.laneDigest, values);
|
|
22
|
+
}
|
|
23
|
+
const stateScanComplete = !premortems.errors.length && !premortems.truncations.length;
|
|
24
|
+
const indexScanComplete = !indexes.errors.length && !indexes.truncations.length;
|
|
25
|
+
if (stateScanComplete) for (const pointer of indexes.pointers) {
|
|
26
|
+
const state = statesByLane.get(pointer.laneDigest);
|
|
27
|
+
if (!state) {
|
|
28
|
+
findings.push({ laneDigest: pointer.laneDigest, reason: "premortem index pointer has no state" });
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const binding = state.binding;
|
|
32
|
+
const sessionDigest = createHash("sha256").update(binding.sessionId).digest("hex");
|
|
33
|
+
if (pointer.sessionDigest !== sessionDigest || pointer.goalId !== binding.goalId
|
|
34
|
+
|| pointer.goalStepId !== binding.goalStepId || pointer.queueId !== binding.queueId
|
|
35
|
+
|| pointer.gatewayAttempt !== binding.gatewayAttempt
|
|
36
|
+
|| pointer.planDefinitionsDigest !== binding.planDefinitionsDigest) {
|
|
37
|
+
findings.push({ laneDigest: pointer.laneDigest,
|
|
38
|
+
reason: "premortem index pointer does not match state binding" });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (indexScanComplete) for (const state of premortems.states.filter((item) => item.binding.goalId)) {
|
|
42
|
+
const pointers = pointersByLane.get(state.laneDigest) || [];
|
|
43
|
+
if (!pointers.length) findings.push({ laneDigest: state.laneDigest,
|
|
44
|
+
reason: "goal premortem state has no index pointer" });
|
|
45
|
+
else if (pointers.length > 1) findings.push({ laneDigest: state.laneDigest,
|
|
46
|
+
reason: "goal premortem state has multiple index pointers" });
|
|
47
|
+
const consumed = state.events.some((event) => event.type === "premortem-consumed");
|
|
48
|
+
const finalized = indexes.finalizations.some((item) => item.laneDigest === state.laneDigest);
|
|
49
|
+
if (consumed && !finalized) findings.push({ laneDigest: state.laneDigest,
|
|
50
|
+
reason: "consumed goal premortem state has no scope finalization" });
|
|
51
|
+
}
|
|
52
|
+
if (stateScanComplete && indexScanComplete) for (const finalization of indexes.finalizations) {
|
|
53
|
+
const scopedPointers = indexes.pointers.filter((item) => item.scopeDigest === finalization.scopeDigest);
|
|
54
|
+
const scopedStates = premortems.states.filter((state) => state.binding.goalId
|
|
55
|
+
&& premortemScopeDigest(state.binding.goalId, state.binding.goalStepId,
|
|
56
|
+
state.binding.queueId, state.binding.gatewayAttempt) === finalization.scopeDigest);
|
|
57
|
+
if (finalization.status === "read-only") {
|
|
58
|
+
if (scopedPointers.length || scopedStates.length) findings.push({ laneDigest: null,
|
|
59
|
+
reason: "read-only premortem finalization retains state or index evidence" });
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const pointer = scopedPointers.length === 1 ? scopedPointers[0] : null;
|
|
63
|
+
const state = scopedStates.length === 1 ? scopedStates[0] : null;
|
|
64
|
+
if (!pointer || !state || pointer.laneDigest !== finalization.laneDigest) {
|
|
65
|
+
findings.push({ laneDigest: finalization.laneDigest,
|
|
66
|
+
reason: "closed premortem finalization is orphaned" });
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (pointer.digest !== finalization.pointerDigest) findings.push({ laneDigest: state.laneDigest,
|
|
70
|
+
reason: "closed premortem finalization has the wrong pointer digest" });
|
|
71
|
+
const consumed = state.events.some((event) => event.type === "premortem-consumed");
|
|
72
|
+
if (!consumed || !state.closure || !state.lastWrite) findings.push({ laneDigest: state.laneDigest,
|
|
73
|
+
reason: "closed premortem finalization has no consumed closed state" });
|
|
74
|
+
else if (createPremortemAttachment(state).attachmentDigest !== finalization.attachmentDigest) {
|
|
75
|
+
findings.push({ laneDigest: state.laneDigest,
|
|
76
|
+
reason: "closed premortem finalization has the wrong attachment digest" });
|
|
77
|
+
}
|
|
78
|
+
const binding = state.binding;
|
|
79
|
+
const exact = finalization.goalId === binding.goalId && finalization.goalStepId === binding.goalStepId
|
|
80
|
+
&& finalization.queueId === binding.queueId && finalization.gatewayAttempt === binding.gatewayAttempt
|
|
81
|
+
&& finalization.planDefinitionsDigest === binding.planDefinitionsDigest
|
|
82
|
+
&& finalization.host === binding.host && finalization.projectId === binding.projectId
|
|
83
|
+
&& finalization.entityId === binding.entityId && finalization.groupId === binding.groupId
|
|
84
|
+
&& finalization.taskId === binding.taskId;
|
|
85
|
+
const summaryDigest = createHash("sha256")
|
|
86
|
+
.update(JSON.stringify([premortemGoalBindingSummary(state).digest])).digest("hex");
|
|
87
|
+
if (!exact || finalization.bindingSummaryDigest !== summaryDigest) findings.push({ laneDigest: state.laneDigest,
|
|
88
|
+
reason: "closed premortem finalization has the wrong binding evidence" });
|
|
89
|
+
}
|
|
90
|
+
if (indexScanComplete) for (const goal of gatewayPolicy.goals || []) {
|
|
91
|
+
for (const step of goal.plan?.steps || []) {
|
|
92
|
+
const checkpoint = step.deliveryCheckpoint;
|
|
93
|
+
const outcome = step.outcomeReceipt;
|
|
94
|
+
if (step.status !== "completed" || !new Set(["closed", "read-only"]).has(checkpoint?.status)) continue;
|
|
95
|
+
const finalization = indexes.finalizations.find((item) => item.digest === checkpoint.scopeFinalizationDigest);
|
|
96
|
+
if (!finalization) {
|
|
97
|
+
findings.push({ laneDigest: checkpoint.bindingDigest ?? null,
|
|
98
|
+
reason: "completed goal premortem has no bound scope finalization" });
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const exact = finalization.status === checkpoint.status && finalization.goalId === goal.goalId
|
|
102
|
+
&& finalization.goalStepId === step.stepId && finalization.queueId === checkpoint.queueId
|
|
103
|
+
&& finalization.gatewayAttempt === checkpoint.gatewayAttempt
|
|
104
|
+
&& finalization.planDefinitionsDigest === checkpoint.planDefinitionsDigest
|
|
105
|
+
&& finalization.host === checkpoint.host && finalization.projectId === checkpoint.projectId
|
|
106
|
+
&& finalization.entityId === checkpoint.entityId && finalization.groupId === checkpoint.groupId
|
|
107
|
+
&& finalization.taskId === (checkpoint.taskId ?? null);
|
|
108
|
+
if (!exact) findings.push({ laneDigest: checkpoint.bindingDigest ?? null,
|
|
109
|
+
reason: "completed goal premortem scope finalization has the wrong binding" });
|
|
110
|
+
if (checkpoint.status === "closed" && (checkpoint.sourceAttachmentDigest
|
|
111
|
+
!== finalization.attachmentDigest || outcome?.sourceAttachmentDigest
|
|
112
|
+
!== finalization.attachmentDigest)) {
|
|
113
|
+
findings.push({ laneDigest: checkpoint.bindingDigest ?? null,
|
|
114
|
+
reason: "completed goal premortem source attachment does not match scope finalization" });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return findings;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function boundedWrites(state) {
|
|
122
|
+
const writes = [state.firstWrite, state.lastWrite, ...(state.writeLedger || [])].filter(Boolean);
|
|
123
|
+
return [...new Map(writes.map((write) => [write.idDigest, {
|
|
124
|
+
idDigest: write.idDigest, inputDigest: write.inputDigest,
|
|
125
|
+
inputKnown: write.inputKnown, writeDigest: write.writeDigest || write.digest
|
|
126
|
+
}])).values()];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function sameWrite(entry, expected) {
|
|
130
|
+
return entry?.idDigest === expected.idDigest && entry.inputDigest === expected.inputDigest
|
|
131
|
+
&& entry.inputKnown === expected.inputKnown && entry.writeDigest === expected.writeDigest;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function addIssue(target, seen, laneDigest, item, fallbackPath) {
|
|
135
|
+
const issue = { laneDigest, path: item.path || fallbackPath,
|
|
136
|
+
reason: String(item.reason || "premortem write-index inspection failed").slice(0, 400),
|
|
137
|
+
code: typeof item.code === "string" ? item.code : null };
|
|
138
|
+
const key = `${laneDigest}:${issue.code}:${issue.reason}`;
|
|
139
|
+
if (!seen.has(key)) {
|
|
140
|
+
seen.add(key);
|
|
141
|
+
target.push(issue);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function inspectPremortemWriteIndexAudit(premortems, {
|
|
146
|
+
inspectIndexes = inspectPremortemWriteIndexes,
|
|
147
|
+
inspectProof = inspectPremortemWriteProof
|
|
148
|
+
} = {}) {
|
|
149
|
+
const combined = { directories: [], paths: [], nodes: [], errors: [], uncertainties: [],
|
|
150
|
+
truncations: [], states: 0, attemptedProofs: 0, verifiedProofs: 0,
|
|
151
|
+
authority: "context-only" };
|
|
152
|
+
const paths = new Set();
|
|
153
|
+
const errorKeys = new Set();
|
|
154
|
+
const uncertaintyKeys = new Set();
|
|
155
|
+
for (const state of premortems.states.filter((item) => item.writeIndexRoot)) {
|
|
156
|
+
const statePath = premortems.paths.find((path) => basename(path) === `${state.laneDigest}.json`);
|
|
157
|
+
if (!statePath) {
|
|
158
|
+
addIssue(combined.uncertainties, uncertaintyKeys, state.laneDigest, {
|
|
159
|
+
path: premortems.directory,
|
|
160
|
+
reason: `premortem state ${state.laneDigest} has no inspected path`
|
|
161
|
+
}, premortems.directory);
|
|
162
|
+
if (premortems.directory) paths.add(premortems.directory);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
combined.states += 1;
|
|
166
|
+
let inspected;
|
|
167
|
+
try {
|
|
168
|
+
inspected = await inspectIndexes({ statePath, state });
|
|
169
|
+
} catch (error) {
|
|
170
|
+
const target = error.code === WRITE_INDEX_MISMATCH
|
|
171
|
+
? [combined.errors, errorKeys] : [combined.uncertainties, uncertaintyKeys];
|
|
172
|
+
addIssue(target[0], target[1], state.laneDigest, {
|
|
173
|
+
path: error.path || statePath, reason: error.message, code: error.code
|
|
174
|
+
}, statePath);
|
|
175
|
+
paths.add(error.path || statePath);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
combined.directories.push(inspected.directory);
|
|
179
|
+
for (const path of inspected.paths) paths.add(path);
|
|
180
|
+
combined.nodes.push(...inspected.nodes);
|
|
181
|
+
combined.truncations.push(...inspected.truncations);
|
|
182
|
+
for (const item of inspected.errors) {
|
|
183
|
+
if (item.path) paths.add(item.path);
|
|
184
|
+
const target = item.code === WRITE_INDEX_MISMATCH
|
|
185
|
+
? [combined.errors, errorKeys] : [combined.uncertainties, uncertaintyKeys];
|
|
186
|
+
addIssue(target[0], target[1], state.laneDigest, item, statePath);
|
|
187
|
+
}
|
|
188
|
+
for (const item of inspected.truncations) if (item.path) paths.add(item.path);
|
|
189
|
+
for (const expected of boundedWrites(state)) {
|
|
190
|
+
combined.attemptedProofs += 1;
|
|
191
|
+
try {
|
|
192
|
+
const proof = await inspectProof({ statePath, laneDigest: state.laneDigest,
|
|
193
|
+
rootDigest: state.writeIndexRoot, idDigest: expected.idDigest });
|
|
194
|
+
for (const path of proof.paths) paths.add(path);
|
|
195
|
+
if (!sameWrite(proof.entry, expected)) {
|
|
196
|
+
addIssue(combined.errors, errorKeys, state.laneDigest, {
|
|
197
|
+
path: proof.paths.at(-1) || statePath, code: WRITE_INDEX_MISMATCH,
|
|
198
|
+
reason: "premortem write index does not prove a bounded write"
|
|
199
|
+
}, statePath);
|
|
200
|
+
} else combined.verifiedProofs += 1;
|
|
201
|
+
} catch (error) {
|
|
202
|
+
const item = { path: error.path || inspected.paths[0] || statePath,
|
|
203
|
+
reason: error.message, code: error.code };
|
|
204
|
+
const target = error.code === WRITE_INDEX_MISMATCH
|
|
205
|
+
? [combined.errors, errorKeys] : [combined.uncertainties, uncertaintyKeys];
|
|
206
|
+
addIssue(target[0], target[1], state.laneDigest, item, statePath);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
combined.paths = [...paths].sort();
|
|
211
|
+
return combined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export async function inspectPremortemAudit(root, gatewayPolicy) {
|
|
215
|
+
const premortems = await inspectDeliveryPremortems(root);
|
|
216
|
+
const indexes = premortems.directory
|
|
217
|
+
? await inspectPremortemLaneIndexes(premortems.directory)
|
|
218
|
+
: { directory: null, directories: [], paths: [], pointers: [], errors: [],
|
|
219
|
+
finalizations: [], tamperedPointers: [], tamperedFinalizations: [], truncations: [] };
|
|
220
|
+
const writeIndexes = await inspectPremortemWriteIndexAudit(premortems);
|
|
221
|
+
const crossReferenceIssues = premortemIndexCrossReferenceFindings(premortems, indexes, gatewayPolicy);
|
|
222
|
+
return { premortems, indexes, writeIndexes, crossReferenceIssues };
|
|
223
|
+
}
|
|
@@ -22,11 +22,12 @@ import { fileURLToPath } from "node:url";
|
|
|
22
22
|
import { checkHosts } from "../../scripts/check-hosts.js";
|
|
23
23
|
import { resolveHostSourceCatalog } from "./source-roots.js";
|
|
24
24
|
import { preflightStatus } from "./preflight.js";
|
|
25
|
+
import { inspectPremortemAudit } from "./audit-premortem.js";
|
|
26
|
+
import { worldModelStatePath } from "./world-model.js";
|
|
25
27
|
|
|
26
28
|
function gate(id, name, ok, detail, severity = "error") {
|
|
27
29
|
return { id, name, ok, severity, detail };
|
|
28
30
|
}
|
|
29
|
-
|
|
30
31
|
function authorityViolations(graph, attention, learning, continuity, coordination, sharing, trust, registry, feedState) {
|
|
31
32
|
const records = [
|
|
32
33
|
...graph.edges,
|
|
@@ -125,6 +126,7 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
125
126
|
: await buildCatalog(root));
|
|
126
127
|
const catalog = before;
|
|
127
128
|
const catalogPath = await saveCatalog(catalog);
|
|
129
|
+
const worldModelPath = await worldModelStatePath(before.root);
|
|
128
130
|
const { graph, graphPath } = await loadGraph(before.root, catalog);
|
|
129
131
|
const { attention, attentionPath, error: attentionLoadError } = await inspectAttention(before.root, catalog);
|
|
130
132
|
const { learning, learningPath, error: learningLoadError } = await inspectLearning(before.root, catalog);
|
|
@@ -152,6 +154,9 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
152
154
|
const { trust, trustPath, error: trustLoadError } = await inspectTrust(before.root, catalog);
|
|
153
155
|
const { registry, registryPath, signerDirectory, errors: signerErrors } = await inspectSignerRegistry(before.root, catalog);
|
|
154
156
|
const { state: feedState, statePath: feedStatePath, error: feedStateError } = await inspectHttpsFeedState(before.root);
|
|
157
|
+
const { premortems, indexes: premortemIndexes, writeIndexes: premortemWriteIndexes,
|
|
158
|
+
crossReferenceIssues: premortemCrossReferenceIssues } = await inspectPremortemAudit(
|
|
159
|
+
before.root, gatewayPolicy);
|
|
155
160
|
const context = await resolveContext({ root: before.root, cwd: before.root, host: "generic", maxBytes: 16384, includeContent: true, catalog });
|
|
156
161
|
let briefing = null;
|
|
157
162
|
let briefingError = null;
|
|
@@ -175,6 +180,13 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
175
180
|
const brokenLinks = catalog.conflicts.filter((conflict) => conflict.type === "broken-link");
|
|
176
181
|
const reviewConflicts = catalog.conflicts.filter((conflict) => conflict.type !== "broken-link");
|
|
177
182
|
const authority = authorityViolations(graph, attention, learning, continuity, coordination, sharing, trust, registry, feedState);
|
|
183
|
+
const premortemRecords = premortems.states.flatMap((state) => [state, state.requirement,
|
|
184
|
+
state.artifact, state.firstWrite, state.lastWrite, state.closure, ...state.events].filter(Boolean))
|
|
185
|
+
.concat(premortemIndexes.pointers, premortemIndexes.finalizations, premortemWriteIndexes.nodes);
|
|
186
|
+
const premortemAuthorityIssues = premortemRecords.filter((record) => record.authority !== "context-only");
|
|
187
|
+
const premortemIssues = [...premortems.errors, ...premortemIndexes.errors, ...premortemWriteIndexes.errors]
|
|
188
|
+
.map((item) => `unreadable-state:${item.reason}`)
|
|
189
|
+
.concat(premortemCrossReferenceIssues.map((item) => `index-state-mismatch:${item.reason}`));
|
|
178
190
|
const forbidden = forbiddenEntityKeys(graph);
|
|
179
191
|
const privacyValues = new Set(["private", "shared", "group"]);
|
|
180
192
|
const privateRecords = [
|
|
@@ -292,10 +304,16 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
292
304
|
? `${catalog.documents.length} project documents; host-native source resolution failed closed: ${sourceResolutionError}`
|
|
293
305
|
: sourceResolution ? `${sourceResolution.scopes.user} user, ${sourceResolution.scopes.project} project, and ${sourceResolution.scopes["project-memory"]} memory sources; broad home scan disabled`
|
|
294
306
|
: `${catalog.documents.length} Markdown documents indexed`),
|
|
295
|
-
gate(3, "State isolation", [catalogPath, graphPath, attentionPath, learningPath, continuityPath,
|
|
307
|
+
gate(3, "State isolation", [catalogPath, graphPath, worldModelPath, attentionPath, learningPath, continuityPath,
|
|
296
308
|
policyPath, coordinationPath, executionPolicyPath, selfstarterPath, channelPolicyPath,
|
|
297
309
|
channelRuntimePath, personaPolicyPath, personaRuntimePath, gatewayPolicyPath, gatewayRuntimePath,
|
|
298
|
-
sharingPath, trustPath, registryPath, signerDirectory, feedStatePath
|
|
310
|
+
sharingPath, trustPath, registryPath, signerDirectory, feedStatePath, premortems.directory,
|
|
311
|
+
...premortems.paths, ...premortems.errors.map((item) => item.path), premortemIndexes.directory,
|
|
312
|
+
...premortemIndexes.directories, ...premortemIndexes.paths,
|
|
313
|
+
...premortemIndexes.errors.map((item) => item.path), ...premortemWriteIndexes.directories,
|
|
314
|
+
...premortemWriteIndexes.paths, ...premortemWriteIndexes.errors.map((item) => item.path),
|
|
315
|
+
...premortemWriteIndexes.uncertainties.map((item) => item.path),
|
|
316
|
+
...premortemWriteIndexes.truncations.map((item) => item.path)].filter(Boolean)
|
|
299
317
|
.every((path) => statePathIsScanExcluded(catalog, path)),
|
|
300
318
|
catalog.scanPolicy?.stateRoot === "excluded"
|
|
301
319
|
? `Authenticated state is excluded from the home-root source scan for ${catalog.root}`
|
|
@@ -303,10 +321,10 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
303
321
|
gate(4, "Native hierarchy", nativeMapped.every((document) => document.hosts.length > 0), `${nativeMapped.length} host-native documents mapped`),
|
|
304
322
|
gate(5, "Link integrity", brokenLinks.length === 0, brokenLinks.length ? `${brokenLinks.length} broken Markdown links` : "All indexed Markdown links resolve"),
|
|
305
323
|
gate(6, "Conflict visibility", Array.isArray(catalog.conflicts), `${reviewConflicts.length} precedence or classification findings exposed`, "warning"),
|
|
306
|
-
gate(7, "Authority boundary", authority.length === 0 && forbidden.length === 0 && policyIssues.length === 0 && coordinationAuthorityIssues.length === 0 && executionPolicyIssues.length === 0 && selfstarterAuthorityIssues.length === 0 && channelPolicyIssues.length === 0 && personaPolicyIssues.length === 0 && gatewayPolicyIssues.length === 0 && sharingAuthorityIssues.length === 0 && !preflightError, preflightError
|
|
324
|
+
gate(7, "Authority boundary", authority.length === 0 && premortemAuthorityIssues.length === 0 && forbidden.length === 0 && policyIssues.length === 0 && coordinationAuthorityIssues.length === 0 && executionPolicyIssues.length === 0 && selfstarterAuthorityIssues.length === 0 && channelPolicyIssues.length === 0 && personaPolicyIssues.length === 0 && gatewayPolicyIssues.length === 0 && sharingAuthorityIssues.length === 0 && !preflightError, preflightError
|
|
307
325
|
? `preflight policy or receipt state failed closed: ${preflightError}`
|
|
308
|
-
: `${authority.length} context authority violations; ${forbidden.length} forbidden entity records; ${policyIssues.length} delegation policy findings; ${coordinationAuthorityIssues.length} assignment findings; ${executionPolicyIssues.length} execution policy findings; ${selfstarterAuthorityIssues.length} self-starter authority findings; ${channelPolicyIssues.length} channel policy findings; ${personaPolicyIssues.length} persona policy findings; ${gatewayPolicyIssues.length} gateway policy findings; ${sharingAuthorityIssues.length} shared authority findings; preflight ${preflight.status}`),
|
|
309
|
-
gate(8, "Context privacy", privacyInvalid.length === 0 && attentionGroupInvalid.length === 0 && attentionConfigValid && attentionIssues.length === 0 && learningIssues.length === 0 && continuityIssues.length === 0 && coordinationContextIssues.length === 0 && selfstarterStateIssues.length === 0 && channelRuntimeIssues.length === 0 && personaStateIssues.length === 0 && gatewayStateIssues.length === 0 && sharingContextIssues.length === 0 && authenticationIssues.length === 0, `${graph.entities.length} entities, ${graph.entityEdges.length} relationships, ${attention.signals.length} attention cues, ${attention.events.length} lifecycle events, ${learning.candidates.length} learning records, ${(learning.candidateEvidenceLineage || []).length} candidate-evidence lineage receipts, ${(learning.evaluations || []).length} immutable evaluation contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v9", "agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} exact-target contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v8", "agentspine.learning-evaluation/v9", "agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} precommitted initial-trial contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} deadline-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} staleness-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} promotion-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} candidate-admission contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} candidate-evidence-cohort contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} blocking-defect-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} evidence-source-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} evidence-source-attested contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} bounded retry contracts, ${(learning.trialRetryExhaustions || []).length} terminal retry-exhaustion receipts, ${(learning.applications || []).filter((item) => ["agentspine.learning-application/v5", "agentspine.learning-application/v6", "agentspine.learning-application/v7"].includes(item.schema)).length} immutable initial-trial admissions, ${(learning.applications || []).filter((item) => ["agentspine.learning-application/v6", "agentspine.learning-application/v7"].includes(item.schema)).length} exact-target admissions, ${(learning.applications || []).filter((item) => item.schema === "agentspine.learning-application/v7").length} deadline-bound admissions, ${(learning.trialFailures || []).length} blocking trial-failure receipts, ${(learning.evaluatorRegistry || []).length} locally confirmed evaluator roots, ${(learning.evaluationBindings || []).length} evaluator-registry bindings, ${(learning.validationLeases || []).length} immutable validation leases, ${(learning.measurements || []).length} immutable measurement runs, ${(learning.applications || []).length} turn-bound projections, ${(learning.deliveries || []).length} completed model-turn deliveries, ${(learning.evaluationRevocations || []).length} evaluation revocations, ${(learning.evidenceRevocations || []).length} evidence revocations, ${(learning.measurementRevocations || []).length} measurement revocations, ${(learning.applicationRevocations || []).length} application revocations, ${(learning.deliveryRevocations || []).length} delivery revocations, ${(learning.outcomeRevocations || []).length} outcome revocations, ${(learning.outcomes || []).length} outcome receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v5", "agentspine.learning-outcome/v6", "agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} case-coverage receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v6", "agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} provenance-bound receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} lineage-bound receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} paired-evaluator receipts and ${(learning.outcomes || []).filter((item) => item.schema === "agentspine.learning-outcome/v9").length} evaluator-root-bound receipts, ${continuity.signals.length} continuity signals, ${coordination.tasks.length} coordination items, ${selfstarter.jobs.length} self-starter jobs, ${channelRuntime.events.length} channel events, ${personaRuntime.personas.length} authenticated personas, ${gatewayRuntime.queue.length} gateway queue items, ${gatewayRuntime.outbox.length} delivery records, ${sharing.records.length} shared records, ${trust.records.length} trusted keys, ${registry.signers.length} local signers, and ${feedState.feeds.length} feed receipts checked`),
|
|
326
|
+
: `${authority.length} context authority violations; ${premortemAuthorityIssues.length} premortem authority violations; ${forbidden.length} forbidden entity records; ${policyIssues.length} delegation policy findings; ${coordinationAuthorityIssues.length} assignment findings; ${executionPolicyIssues.length} execution policy findings; ${selfstarterAuthorityIssues.length} self-starter authority findings; ${channelPolicyIssues.length} channel policy findings; ${personaPolicyIssues.length} persona policy findings; ${gatewayPolicyIssues.length} gateway policy findings; ${sharingAuthorityIssues.length} shared authority findings; preflight ${preflight.status}`),
|
|
327
|
+
gate(8, "Context privacy", privacyInvalid.length === 0 && attentionGroupInvalid.length === 0 && attentionConfigValid && attentionIssues.length === 0 && learningIssues.length === 0 && continuityIssues.length === 0 && coordinationContextIssues.length === 0 && selfstarterStateIssues.length === 0 && channelRuntimeIssues.length === 0 && personaStateIssues.length === 0 && gatewayStateIssues.length === 0 && sharingContextIssues.length === 0 && authenticationIssues.length === 0 && premortemIssues.length === 0, `${graph.entities.length} entities, ${graph.entityEdges.length} relationships, ${attention.signals.length} attention cues, ${attention.events.length} lifecycle events, ${learning.candidates.length} learning records, ${(learning.candidateEvidenceLineage || []).length} candidate-evidence lineage receipts, ${(learning.evaluations || []).length} immutable evaluation contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v9", "agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} exact-target contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v8", "agentspine.learning-evaluation/v9", "agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} precommitted initial-trial contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v10", "agentspine.learning-evaluation/v11", "agentspine.learning-evaluation/v12", "agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} deadline-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v14", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} staleness-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v16", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} promotion-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v18", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} candidate-admission contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v20", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} candidate-evidence-cohort contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v22", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} blocking-defect-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v24", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} evidence-source-bound contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v26", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v28", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} evidence-source-attested contracts, ${(learning.evaluations || []).filter((item) => ["agentspine.learning-evaluation/v13", "agentspine.learning-evaluation/v15", "agentspine.learning-evaluation/v17", "agentspine.learning-evaluation/v19", "agentspine.learning-evaluation/v21", "agentspine.learning-evaluation/v23", "agentspine.learning-evaluation/v25", "agentspine.learning-evaluation/v27", "agentspine.learning-evaluation/v29"].includes(item.schema)).length} bounded retry contracts, ${(learning.trialRetryExhaustions || []).length} terminal retry-exhaustion receipts, ${(learning.applications || []).filter((item) => ["agentspine.learning-application/v5", "agentspine.learning-application/v6", "agentspine.learning-application/v7"].includes(item.schema)).length} immutable initial-trial admissions, ${(learning.applications || []).filter((item) => ["agentspine.learning-application/v6", "agentspine.learning-application/v7"].includes(item.schema)).length} exact-target admissions, ${(learning.applications || []).filter((item) => item.schema === "agentspine.learning-application/v7").length} deadline-bound admissions, ${(learning.trialFailures || []).length} blocking trial-failure receipts, ${(learning.evaluatorRegistry || []).length} locally confirmed evaluator roots, ${(learning.evaluationBindings || []).length} evaluator-registry bindings, ${(learning.validationLeases || []).length} immutable validation leases, ${(learning.measurements || []).length} immutable measurement runs, ${(learning.applications || []).length} turn-bound projections, ${(learning.deliveries || []).length} completed model-turn deliveries, ${(learning.evaluationRevocations || []).length} evaluation revocations, ${(learning.evidenceRevocations || []).length} evidence revocations, ${(learning.measurementRevocations || []).length} measurement revocations, ${(learning.applicationRevocations || []).length} application revocations, ${(learning.deliveryRevocations || []).length} delivery revocations, ${(learning.outcomeRevocations || []).length} outcome revocations, ${(learning.outcomes || []).length} outcome receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v5", "agentspine.learning-outcome/v6", "agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} case-coverage receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v6", "agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} provenance-bound receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v7", "agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} lineage-bound receipts, ${(learning.outcomes || []).filter((item) => ["agentspine.learning-outcome/v8", "agentspine.learning-outcome/v9"].includes(item.schema)).length} paired-evaluator receipts and ${(learning.outcomes || []).filter((item) => item.schema === "agentspine.learning-outcome/v9").length} evaluator-root-bound receipts, ${continuity.signals.length} continuity signals, ${coordination.tasks.length} coordination items, ${selfstarter.jobs.length} self-starter jobs, ${channelRuntime.events.length} channel events, ${personaRuntime.personas.length} authenticated personas, ${gatewayRuntime.queue.length} gateway queue items, ${gatewayRuntime.outbox.length} delivery records, ${sharing.records.length} shared records, ${trust.records.length} trusted keys, ${registry.signers.length} local signers, ${feedState.feeds.length} feed receipts, ${premortems.states.length} premortem states, and ${premortemIndexes.pointers.length} premortem index pointers checked`),
|
|
310
328
|
gate(9, "Context budget", loadedBytes <= context.budget.maxBytes && briefingBudgetValid, briefingError
|
|
311
329
|
? `${loadedBytes}/${context.budget.maxBytes} source bytes; briefing failed closed: ${briefingError}`
|
|
312
330
|
: `${loadedBytes}/${context.budget.maxBytes} source bytes; ${briefingBytes}/${briefing.budget.maxBytes} briefing bytes`),
|
|
@@ -321,6 +339,7 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
321
339
|
gates,
|
|
322
340
|
catalogPath,
|
|
323
341
|
graphPath,
|
|
342
|
+
worldModelPath,
|
|
324
343
|
attentionPath,
|
|
325
344
|
learningPath,
|
|
326
345
|
continuityPath,
|
|
@@ -338,6 +357,37 @@ export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
|
338
357
|
trustPath,
|
|
339
358
|
registryPath,
|
|
340
359
|
feedStatePath,
|
|
360
|
+
premortemDiagnostics: {
|
|
361
|
+
directory: premortems.directory,
|
|
362
|
+
paths: [...premortems.paths, ...premortemWriteIndexes.paths],
|
|
363
|
+
states: premortems.states.length,
|
|
364
|
+
artifacts: premortems.states.filter((state) => state.artifact).length,
|
|
365
|
+
closures: premortems.states.filter((state) => state.closure).length,
|
|
366
|
+
errors: structuredClone([...premortems.errors, ...premortemWriteIndexes.errors]),
|
|
367
|
+
truncations: structuredClone([...premortems.truncations, ...premortemWriteIndexes.truncations]),
|
|
368
|
+
writeIndex: { directories: [...premortemWriteIndexes.directories],
|
|
369
|
+
paths: [...premortemWriteIndexes.paths], nodes: premortemWriteIndexes.nodes.length,
|
|
370
|
+
states: premortemWriteIndexes.states,
|
|
371
|
+
attemptedProofs: premortemWriteIndexes.attemptedProofs,
|
|
372
|
+
verifiedProofs: premortemWriteIndexes.verifiedProofs,
|
|
373
|
+
errors: structuredClone(premortemWriteIndexes.errors),
|
|
374
|
+
uncertainties: structuredClone(premortemWriteIndexes.uncertainties),
|
|
375
|
+
truncations: structuredClone(premortemWriteIndexes.truncations), authority: "context-only" },
|
|
376
|
+
index: {
|
|
377
|
+
directory: premortemIndexes.directory,
|
|
378
|
+
directories: [...premortemIndexes.directories],
|
|
379
|
+
paths: [...premortemIndexes.paths],
|
|
380
|
+
pointers: premortemIndexes.pointers.length,
|
|
381
|
+
finalizations: premortemIndexes.finalizations.length,
|
|
382
|
+
tamperedPointers: [...premortemIndexes.tamperedPointers],
|
|
383
|
+
tamperedFinalizations: [...premortemIndexes.tamperedFinalizations],
|
|
384
|
+
errors: structuredClone(premortemIndexes.errors),
|
|
385
|
+
truncations: structuredClone(premortemIndexes.truncations),
|
|
386
|
+
crossReferenceErrors: structuredClone(premortemCrossReferenceIssues),
|
|
387
|
+
authority: "context-only"
|
|
388
|
+
},
|
|
389
|
+
authority: "context-only"
|
|
390
|
+
},
|
|
341
391
|
learningDiagnostics: {
|
|
342
392
|
candidateEvidenceLineageReceipts:
|
|
343
393
|
(learning.candidateEvidenceLineage || []).length,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
AUTONOMY_CONFIRMATION, AUTONOMY_MODES, CAPABILITY_RE, PUBLISH_CONFIRMATION,
|
|
4
|
+
appendHistory, canonicalLocalRoot, exactCapabilities, loadAutonomy, modeAllows,
|
|
5
|
+
mutateAutonomy, publicRepository, safeText, signedRecord, stableId, timestamp
|
|
6
|
+
} from "./autonomy-store.js";
|
|
7
|
+
import { loadExecutionPolicy } from "./selfstarter.js";
|
|
8
|
+
|
|
9
|
+
function confirmation(value) {
|
|
10
|
+
if (value !== AUTONOMY_CONFIRMATION) throw new Error("autonomy changes require explicit local-owner confirmation");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function configureAutonomyProject({
|
|
14
|
+
root = process.cwd(), id = `autonomy-project:${randomUUID()}`, projectId, tenantId, groupId = null,
|
|
15
|
+
localRoot = null, publicUrl = null, mode = "observe", capabilities = [], goal = "Maintain a bounded project overview.",
|
|
16
|
+
confirmation: ownerConfirmation, publishConfirmation = null, now = new Date()
|
|
17
|
+
}) {
|
|
18
|
+
confirmation(ownerConfirmation);
|
|
19
|
+
if (!AUTONOMY_MODES.includes(mode)) throw new Error(`mode must be one of: ${AUTONOMY_MODES.join(", ")}`);
|
|
20
|
+
if (Boolean(localRoot) === Boolean(publicUrl)) throw new Error("configure exactly one local root or public repository URL");
|
|
21
|
+
const source = localRoot
|
|
22
|
+
? { kind: "local-root", value: await canonicalLocalRoot(localRoot) }
|
|
23
|
+
: { kind: "public-repository", value: publicRepository(publicUrl) };
|
|
24
|
+
const requestedCapabilities = exactCapabilities(capabilities);
|
|
25
|
+
if (modeAllows(mode, "execute") && !requestedCapabilities.length) throw new Error("execute and publish modes require exact capabilities");
|
|
26
|
+
if (mode === "publish" && publishConfirmation !== PUBLISH_CONFIRMATION) {
|
|
27
|
+
throw new Error("publish mode requires a separate explicit local publish confirmation");
|
|
28
|
+
}
|
|
29
|
+
const at = timestamp(now, "now");
|
|
30
|
+
const registrationId = stableId(id, "registrationId");
|
|
31
|
+
return mutateAutonomy(root, (state, paths) => {
|
|
32
|
+
const previous = state.projects.find((item) => item.id === registrationId);
|
|
33
|
+
if (previous && (previous.projectId !== projectId || previous.tenantId !== tenantId || previous.groupId !== groupId
|
|
34
|
+
|| previous.source.kind !== source.kind || previous.source.value !== source.value)) {
|
|
35
|
+
throw new Error("project registration identity and scope are immutable; create a new registration");
|
|
36
|
+
}
|
|
37
|
+
state.revision += 1;
|
|
38
|
+
const body = {
|
|
39
|
+
id: registrationId, projectId: stableId(projectId, "projectId"), tenantId: stableId(tenantId, "tenantId"),
|
|
40
|
+
groupId: stableId(groupId, "groupId", true), source, mode, capabilities: requestedCapabilities,
|
|
41
|
+
goal: safeText(goal, "goal", 500), active: true, revision: state.revision,
|
|
42
|
+
createdAt: previous?.createdAt || at, updatedAt: at,
|
|
43
|
+
publishConfirmedAt: mode === "publish" ? at : null,
|
|
44
|
+
sourceAuthority: "explicit-local-owner-policy", authority: "explicit-local-autonomy-policy"
|
|
45
|
+
};
|
|
46
|
+
const project = signedRecord(body);
|
|
47
|
+
if (previous) state.projects = state.projects.map((item) => item.id === registrationId ? project : item);
|
|
48
|
+
else state.projects.push(project);
|
|
49
|
+
state.projects.sort((a, b) => a.id.localeCompare(b.id));
|
|
50
|
+
appendHistory(state, { kind: previous ? "project-updated" : "project-registered", projectRegistrationId: project.id, at });
|
|
51
|
+
return { project, policyRevision: state.revision, autonomyPath: paths.autonomyPath };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function revokeAutonomyProject({ root = process.cwd(), id, reason, confirmation: ownerConfirmation, now = new Date() }) {
|
|
56
|
+
confirmation(ownerConfirmation);
|
|
57
|
+
const registrationId = stableId(id, "registrationId");
|
|
58
|
+
const at = timestamp(now, "now");
|
|
59
|
+
const revokeReason = safeText(reason, "reason", 500);
|
|
60
|
+
return mutateAutonomy(root, (state, paths) => {
|
|
61
|
+
const previous = state.projects.find((item) => item.id === registrationId);
|
|
62
|
+
if (!previous?.active) throw new Error("project registration is unknown or already inactive");
|
|
63
|
+
state.revision += 1;
|
|
64
|
+
const { recordDigest: ignored, ...body } = previous;
|
|
65
|
+
const project = signedRecord({ ...body, active: false, updatedAt: at, revision: state.revision, revokedAt: at, revokeReason });
|
|
66
|
+
state.projects = state.projects.map((item) => item.id === registrationId ? project : item);
|
|
67
|
+
appendHistory(state, { kind: "project-revoked", projectRegistrationId: project.id, at });
|
|
68
|
+
return { project, policyRevision: state.revision, autonomyPath: paths.autonomyPath };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function exactGrant(policy, input, capability, now) {
|
|
73
|
+
return policy.grants.find((grant) => grant.active && grant.actorId === input.actorId
|
|
74
|
+
&& grant.jobId === input.jobId && grant.taskId === input.taskId && grant.targetId === input.targetId
|
|
75
|
+
&& grant.projectId === input.projectId && grant.groupId === input.groupId && grant.host === input.host
|
|
76
|
+
&& grant.capabilities.includes(capability) && (!grant.expiresAt || new Date(grant.expiresAt) > now));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function evaluateAutonomyAction({
|
|
80
|
+
root = process.cwd(), registrationId, tenantId, groupId = null, action, capability = null,
|
|
81
|
+
actorId = null, jobId = null, taskId = null, targetId = null, projectId = null, host = null, now = new Date()
|
|
82
|
+
}) {
|
|
83
|
+
if (!AUTONOMY_MODES.includes(action)) throw new Error(`action must be one of: ${AUTONOMY_MODES.join(", ")}`);
|
|
84
|
+
const { state } = await loadAutonomy(root);
|
|
85
|
+
const project = state.projects.find((item) => item.id === stableId(registrationId, "registrationId") && item.active);
|
|
86
|
+
const base = { schema: "agentspine.autonomy-decision/v1", registrationId, action, allowed: false,
|
|
87
|
+
reason: "project-registration-unavailable", grantsAuthority: false, authority: "additional-autonomy-gate" };
|
|
88
|
+
if (!project || project.tenantId !== stableId(tenantId, "tenantId") || project.groupId !== stableId(groupId, "groupId", true)) return base;
|
|
89
|
+
if (!modeAllows(project.mode, action)) return { ...base, reason: "autonomy-mode-insufficient", configuredMode: project.mode };
|
|
90
|
+
if (!modeAllows(action, "execute")) return { ...base, allowed: true, reason: "configured-context-action", configuredMode: project.mode };
|
|
91
|
+
if (project.projectId !== projectId) return { ...base, reason: "action-project-mismatch", configuredMode: project.mode };
|
|
92
|
+
if (typeof capability !== "string" || !CAPABILITY_RE.test(capability) || !project.capabilities.includes(capability)) {
|
|
93
|
+
return { ...base, reason: "capability-not-configured", configuredMode: project.mode };
|
|
94
|
+
}
|
|
95
|
+
if (action === "publish" && !project.publishConfirmedAt) return { ...base, reason: "publish-not-confirmed", configuredMode: project.mode };
|
|
96
|
+
const scope = { actorId, jobId, taskId, targetId, projectId, groupId, host };
|
|
97
|
+
if (Object.entries(scope).some(([key, value]) => key !== "groupId" && (typeof value !== "string" || !value))) {
|
|
98
|
+
return { ...base, reason: "execution-scope-incomplete", configuredMode: project.mode };
|
|
99
|
+
}
|
|
100
|
+
const { policy } = await loadExecutionPolicy(root);
|
|
101
|
+
const grant = exactGrant(policy, scope, capability, new Date(now));
|
|
102
|
+
if (!grant) return { ...base, reason: "execution-grant-unavailable", configuredMode: project.mode };
|
|
103
|
+
return { ...base, allowed: true, reason: "configured-and-explicitly-granted", configuredMode: project.mode, grantId: grant.id };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function autonomyStatus({ root = process.cwd(), tenantId = null, groupId = null } = {}) {
|
|
107
|
+
const { state, autonomyPath } = await loadAutonomy(root);
|
|
108
|
+
const projects = state.projects.filter((item) => (!tenantId || item.tenantId === tenantId) && item.groupId === groupId);
|
|
109
|
+
return { schema: AUTONOMY_SCHEMA, projects, revision: state.revision, autonomyPath, authority: "context-only" };
|
|
110
|
+
}
|