cool-workflow 0.1.98 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +11 -2
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/cli/dispatch.js +236 -0
- package/dist/cli/entry.js +120 -0
- package/dist/cli/io.js +21 -4
- package/dist/cli/parseargv.js +157 -0
- package/dist/cli.js +6 -33
- package/dist/core/capability-table.js +3534 -0
- package/dist/core/format/help.js +314 -0
- package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
- package/dist/core/hash.js +137 -0
- package/dist/core/multi-agent/candidate-scoring.js +219 -0
- package/dist/core/multi-agent/collaboration.js +481 -0
- package/dist/core/multi-agent/coordinator.js +515 -0
- package/dist/core/multi-agent/eval-replay.js +306 -0
- package/dist/core/multi-agent/runtime.js +929 -0
- package/dist/core/multi-agent/topology.js +298 -0
- package/dist/core/multi-agent/trust-policy.js +197 -0
- package/dist/core/pipeline/commit-gate.js +320 -0
- package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
- package/dist/core/pipeline/dispatch.js +103 -0
- package/dist/core/pipeline/drive-decide.js +227 -0
- package/dist/core/pipeline/error-feedback.js +161 -0
- package/dist/core/pipeline/loop-expansion.js +124 -0
- package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
- package/dist/core/pipeline/runner.js +230 -0
- package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
- package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
- package/dist/core/state/node-projection.js +95 -0
- package/dist/core/state/node-snapshot.js +230 -0
- package/dist/core/state/run-paths.js +93 -0
- package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
- package/dist/core/state/schema.js +50 -0
- package/dist/core/state/state-explosion/digest.js +243 -0
- package/dist/core/state/state-explosion/graph.js +527 -0
- package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
- package/dist/core/state/state-explosion/report.js +187 -0
- package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
- package/dist/{state-node.js → core/state/state-node.js} +90 -113
- package/dist/core/state/types.js +19 -0
- package/dist/{validation.js → core/state/validation.js} +64 -131
- package/dist/core/trust/evidence-grounding.js +134 -0
- package/dist/core/trust/ledger.js +199 -0
- package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
- package/dist/core/trust/telemetry-ledger.js +127 -0
- package/dist/core/types.js +20 -0
- package/dist/core/version.js +16 -0
- package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
- package/dist/mcp/dispatch.js +104 -0
- package/dist/mcp/server.js +144 -0
- package/dist/mcp-server.js +6 -84
- package/dist/{agent-config.js → shell/agent-config.js} +118 -71
- package/dist/shell/app-run-cli.js +88 -0
- package/dist/shell/audit-cli.js +259 -0
- package/dist/shell/audit-provenance.js +83 -0
- package/dist/shell/candidate-scoring-io.js +459 -0
- package/dist/shell/collaboration-io.js +264 -0
- package/dist/shell/commit-summary.js +104 -0
- package/dist/shell/commit.js +290 -0
- package/dist/shell/coordinator-io.js +476 -0
- package/dist/shell/demo-cli.js +19 -0
- package/dist/shell/dispatch.js +162 -0
- package/dist/{doctor.js → shell/doctor.js} +123 -56
- package/dist/shell/drive.js +873 -0
- package/dist/shell/error-feedback-io.js +305 -0
- package/dist/shell/eval-io.js +473 -0
- package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
- package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
- package/dist/shell/exec-backend-cli.js +88 -0
- package/dist/shell/execution-backend/agent.js +475 -0
- package/dist/shell/execution-backend/ci.js +15 -0
- package/dist/shell/execution-backend/container.js +69 -0
- package/dist/shell/execution-backend/envelopes.js +55 -0
- package/dist/shell/execution-backend/local.js +113 -0
- package/dist/shell/execution-backend/probes.js +175 -0
- package/dist/shell/execution-backend/registry.js +402 -0
- package/dist/shell/execution-backend/remote.js +128 -0
- package/dist/shell/execution-backend/types.js +11 -0
- package/dist/shell/feedback-cli.js +81 -0
- package/dist/shell/feedback-operations.js +48 -0
- package/dist/shell/fs-atomic.js +276 -0
- package/dist/shell/harness.js +98 -0
- package/dist/shell/ledger-cli.js +212 -0
- package/dist/shell/ledger-io.js +169 -0
- package/dist/shell/man-cli.js +89 -0
- package/dist/shell/metrics-cli.js +98 -0
- package/dist/shell/multi-agent-cli.js +1002 -0
- package/dist/shell/multi-agent-host.js +563 -0
- package/dist/shell/multi-agent-io.js +387 -0
- package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
- package/dist/shell/node-store.js +124 -0
- package/dist/{observability/format.js → shell/observability-format.js} +7 -1
- package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
- package/dist/{observability.js → shell/observability.js} +159 -332
- package/dist/{onramp.js → shell/onramp.js} +11 -0
- package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
- package/dist/shell/operator-ux.js +431 -0
- package/dist/shell/orchestrator.js +231 -0
- package/dist/shell/pipeline-cli.js +667 -0
- package/dist/shell/pipeline.js +217 -0
- package/dist/shell/reclamation-io.js +1366 -0
- package/dist/shell/registry-cli.js +329 -0
- package/dist/{remote-source.js → shell/remote-source.js} +2 -2
- package/dist/shell/report-cli.js +101 -0
- package/dist/shell/report-view-cli.js +117 -0
- package/dist/{orchestrator → shell}/report.js +289 -282
- package/dist/shell/reporter.js +62 -0
- package/dist/shell/run-export-cli.js +106 -0
- package/dist/shell/run-export.js +680 -0
- package/dist/shell/run-registry-io.js +1014 -0
- package/dist/shell/run-store.js +164 -0
- package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
- package/dist/{scheduler.js → shell/scheduler-io.js} +248 -48
- package/dist/shell/scheduling-io.js +311 -0
- package/dist/shell/state-cli.js +181 -0
- package/dist/shell/state-explosion-cli.js +197 -0
- package/dist/shell/telemetry-cli.js +85 -0
- package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
- package/dist/shell/telemetry-ledger-io.js +132 -0
- package/dist/{term.js → shell/term.js} +36 -46
- package/dist/shell/topology-io.js +361 -0
- package/dist/shell/trust-audit.js +471 -0
- package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
- package/dist/shell/verifier.js +48 -0
- package/dist/shell/workbench-host.js +250 -0
- package/dist/shell/workbench-text.js +18 -0
- package/dist/shell/workbench.js +175 -0
- package/dist/shell/worker-cli.js +124 -0
- package/dist/shell/worker-isolation.js +852 -0
- package/dist/shell/workflow-app-loader.js +650 -0
- package/docs/agent-delegation-drive.7.md +2 -0
- package/docs/cli-mcp-parity.7.md +280 -219
- package/docs/contract-migration-tooling.7.md +2 -0
- package/docs/control-plane-scheduling.7.md +2 -0
- package/docs/durable-state-and-locking.7.md +2 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
- package/docs/execution-backends.7.md +2 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +2 -0
- package/docs/multi-agent-eval-replay-harness.7.md +2 -0
- package/docs/multi-agent-operator-ux.7.md +2 -0
- package/docs/node-snapshot-diff-replay.7.md +2 -0
- package/docs/observability-cost-accounting.7.md +2 -0
- package/docs/project-index.md +132 -71
- package/docs/real-execution-backends.7.md +2 -0
- package/docs/release-and-migration.7.md +2 -0
- package/docs/release-tooling.7.md +2 -0
- package/docs/run-registry-control-plane.7.md +2 -0
- package/docs/run-retention-reclamation.7.md +23 -0
- package/docs/state-explosion-management.7.md +2 -0
- package/docs/team-collaboration.7.md +2 -0
- package/docs/web-desktop-workbench.7.md +2 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +9 -13
- package/package.json +1 -1
- package/scripts/agents/cw-attest-wrap.js +2 -2
- package/scripts/bump-version.js +4 -3
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-architecture-review.js +2 -3
- package/scripts/dogfood-release.js +3 -3
- package/scripts/gen-parity-doc.js +15 -2
- package/scripts/golden-path.js +4 -4
- package/scripts/onramp-check.js +1 -1
- package/scripts/parity-check.js +38 -21
- package/scripts/release-flow.js +2 -2
- package/scripts/sync-project-index.js +51 -27
- package/scripts/validate-run-state-schema.js +2 -2
- package/scripts/version-sync-check.js +30 -30
- package/dist/candidate-scoring.js +0 -729
- package/dist/capability-core.js +0 -1189
- package/dist/capability-registry.js +0 -885
- package/dist/cli/command-surface.js +0 -494
- package/dist/cli/format.js +0 -56
- package/dist/cli/handlers/audit.js +0 -82
- package/dist/cli/handlers/blackboard.js +0 -81
- package/dist/cli/handlers/candidate.js +0 -40
- package/dist/cli/handlers/clones.js +0 -34
- package/dist/cli/handlers/collaboration.js +0 -61
- package/dist/cli/handlers/eval.js +0 -40
- package/dist/cli/handlers/ledger.js +0 -169
- package/dist/cli/handlers/maintenance.js +0 -107
- package/dist/cli/handlers/multi-agent.js +0 -165
- package/dist/cli/handlers/node.js +0 -41
- package/dist/cli/handlers/operational.js +0 -155
- package/dist/cli/handlers/operator.js +0 -146
- package/dist/cli/handlers/registry.js +0 -68
- package/dist/cli/handlers/run.js +0 -153
- package/dist/cli/handlers/scheduling.js +0 -132
- package/dist/cli/handlers/workbench.js +0 -41
- package/dist/cli/handlers/worker.js +0 -45
- package/dist/cli/run-summary.js +0 -45
- package/dist/clones.js +0 -162
- package/dist/collaboration.js +0 -726
- package/dist/commit.js +0 -592
- package/dist/compare.js +0 -18
- package/dist/coordinator/classify.js +0 -45
- package/dist/coordinator/paths.js +0 -42
- package/dist/coordinator/util.js +0 -126
- package/dist/coordinator.js +0 -990
- package/dist/daemon.js +0 -44
- package/dist/dispatch.js +0 -250
- package/dist/drive.js +0 -864
- package/dist/error-feedback.js +0 -419
- package/dist/evidence-grounding.js +0 -184
- package/dist/execution-backend/agent.js +0 -354
- package/dist/execution-backend/probes.js +0 -112
- package/dist/execution-backend/util.js +0 -47
- package/dist/execution-backend.js +0 -961
- package/dist/gates.js +0 -48
- package/dist/harness.js +0 -61
- package/dist/ledger.js +0 -313
- package/dist/loop-expansion.js +0 -60
- package/dist/mcp/tool-call.js +0 -470
- package/dist/mcp/tool-definitions.js +0 -1066
- package/dist/mcp-surface.js +0 -30
- package/dist/multi-agent/graph.js +0 -84
- package/dist/multi-agent/helpers.js +0 -141
- package/dist/multi-agent/ids.js +0 -20
- package/dist/multi-agent/paths.js +0 -22
- package/dist/multi-agent-eval/normalize.js +0 -51
- package/dist/multi-agent-eval.js +0 -678
- package/dist/multi-agent-host.js +0 -777
- package/dist/multi-agent.js +0 -984
- package/dist/node-projection.js +0 -59
- package/dist/node-snapshot.js +0 -260
- package/dist/operator-ux.js +0 -631
- package/dist/orchestrator/app-operations.js +0 -211
- package/dist/orchestrator/audit-operations.js +0 -182
- package/dist/orchestrator/candidate-operations.js +0 -117
- package/dist/orchestrator/cli-options.js +0 -294
- package/dist/orchestrator/collaboration-operations.js +0 -86
- package/dist/orchestrator/feedback-operations.js +0 -81
- package/dist/orchestrator/host-operations.js +0 -78
- package/dist/orchestrator/lifecycle-operations.js +0 -650
- package/dist/orchestrator/migration-operations.js +0 -44
- package/dist/orchestrator/multi-agent-operations.js +0 -362
- package/dist/orchestrator/topology-operations.js +0 -84
- package/dist/orchestrator.js +0 -925
- package/dist/pipeline-runner.js +0 -285
- package/dist/reclamation/hash.js +0 -72
- package/dist/reclamation.js +0 -812
- package/dist/reporter.js +0 -67
- package/dist/run-export.js +0 -815
- package/dist/run-registry/derive.js +0 -175
- package/dist/run-registry/format.js +0 -124
- package/dist/run-registry/gc.js +0 -251
- package/dist/run-registry/policy.js +0 -16
- package/dist/run-registry/queue.js +0 -115
- package/dist/run-registry.js +0 -850
- package/dist/run-state-schema.js +0 -68
- package/dist/scheduling.js +0 -184
- package/dist/state-explosion.js +0 -1014
- package/dist/state.js +0 -367
- package/dist/telemetry-ledger.js +0 -196
- package/dist/topology.js +0 -565
- package/dist/triggers.js +0 -184
- package/dist/trust-audit.js +0 -644
- package/dist/types/blackboard.js +0 -2
- package/dist/types/candidate.js +0 -2
- package/dist/types/collaboration.js +0 -2
- package/dist/types/core.js +0 -2
- package/dist/types/drive.js +0 -10
- package/dist/types/error-feedback.js +0 -2
- package/dist/types/evidence-reasoning.js +0 -2
- package/dist/types/execution-backend.js +0 -2
- package/dist/types/multi-agent.js +0 -2
- package/dist/types/observability.js +0 -2
- package/dist/types/pipeline.js +0 -2
- package/dist/types/reclamation.js +0 -8
- package/dist/types/report-bundle.js +0 -6
- package/dist/types/result.js +0 -2
- package/dist/types/run-registry.js +0 -2
- package/dist/types/run.js +0 -2
- package/dist/types/sandbox.js +0 -2
- package/dist/types/schedule.js +0 -2
- package/dist/types/state-node.js +0 -2
- package/dist/types/topology.js +0 -2
- package/dist/types/trust.js +0 -2
- package/dist/types/workbench.js +0 -2
- package/dist/types/worker.js +0 -2
- package/dist/types/workflow-app.js +0 -2
- package/dist/types.js +0 -44
- package/dist/util/fingerprint.js +0 -19
- package/dist/util/fingerprint.test.js +0 -27
- package/dist/verifier.js +0 -78
- package/dist/version.js +0 -8
- package/dist/workbench-host.js +0 -192
- package/dist/workbench.js +0 -192
- package/dist/worker-accept/acceptance.js +0 -114
- package/dist/worker-accept/blackboard-fanout.js +0 -80
- package/dist/worker-accept/blackboard-linkage.js +0 -19
- package/dist/worker-accept/context.js +0 -2
- package/dist/worker-accept/telemetry-ledger.js +0 -126
- package/dist/worker-accept/validation.js +0 -77
- package/dist/worker-accept/verifier-completion.js +0 -73
- package/dist/worker-isolation/helpers.js +0 -51
- package/dist/worker-isolation/paths.js +0 -46
- package/dist/worker-isolation.js +0 -656
- package/dist/workflow-api.js +0 -131
- /package/dist/{types → core/types}/boundary.js +0 -0
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// shell/evidence-reasoning.ts — the Evidence Adoption Reasoning Chain
|
|
3
|
+
// (v0.1.26). Faithful port of the old flat build's src/evidence-reasoning.ts
|
|
4
|
+
// (+ its src/types/evidence-reasoning.ts types), adapted to v2's core/shell
|
|
5
|
+
// split. DERIVES the "why" behind each evidence adoption decision from
|
|
6
|
+
// existing run state; never mutates source records, never fabricates a
|
|
7
|
+
// rationale (an untraceable adoption renders `unexplained`).
|
|
8
|
+
//
|
|
9
|
+
// Evidence: SPEC/multi-agent.md "Evidence adoption reasoning";
|
|
10
|
+
// plugins/cool-workflow/src/evidence-reasoning.ts (byte-behavior source).
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
@@ -15,30 +24,31 @@ exports.formatEvidenceReasoningReport = formatEvidenceReasoningReport;
|
|
|
15
24
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
16
25
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
17
26
|
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
-
const
|
|
27
|
+
const validation_1 = require("../core/state/validation");
|
|
28
|
+
const fs_atomic_1 = require("./fs-atomic");
|
|
19
29
|
const multi_agent_operator_ux_1 = require("./multi-agent-operator-ux");
|
|
20
30
|
const trust_audit_1 = require("./trust-audit");
|
|
21
|
-
const
|
|
22
|
-
const validation_1 = require("./validation");
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Evidence Adoption Reasoning Chain (v0.1.26)
|
|
25
|
-
//
|
|
26
|
-
// This module DERIVES the "why" behind each evidence adoption decision from
|
|
27
|
-
// existing run state. It is the mechanism half of the FreeBSD mechanism/policy
|
|
28
|
-
// split: it captures, fingerprints and renders the recorded rationale; it never
|
|
29
|
-
// decides whether a rationale is *sufficient* (that stays with the verifier /
|
|
30
|
-
// role policy). It never mutates source-of-truth records and never fabricates a
|
|
31
|
-
// rationale — an adoption whose reason cannot be traced renders `unexplained`.
|
|
32
|
-
//
|
|
33
|
-
// The persisted view mirrors the v0.1.25 state-explosion summaries: a derived,
|
|
34
|
-
// versioned, provenance-backed index under .cw/runs/<id>/reasoning/ with a
|
|
35
|
-
// sourceFingerprint and valid|stale|absent freshness, refreshable, never
|
|
36
|
-
// authoritative over raw state.
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
31
|
+
const trust_policy_1 = require("../core/multi-agent/trust-policy");
|
|
38
32
|
exports.EVIDENCE_REASONING_SCHEMA_VERSION = 1;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
function candidatesOf(run) {
|
|
34
|
+
return (run.candidates || []);
|
|
35
|
+
}
|
|
36
|
+
function selectionsOf(run) {
|
|
37
|
+
return (run.candidateSelections || []);
|
|
38
|
+
}
|
|
39
|
+
function commitsOf(run) {
|
|
40
|
+
return (run.commits || []);
|
|
41
|
+
}
|
|
42
|
+
function decisionsOf(run) {
|
|
43
|
+
return (run.blackboard?.decisions || []);
|
|
44
|
+
}
|
|
45
|
+
function faninsOf(run) {
|
|
46
|
+
return (run.multiAgent?.fanins || []);
|
|
47
|
+
}
|
|
48
|
+
function rolesOf(run) {
|
|
49
|
+
return (run.multiAgent?.roles || []);
|
|
50
|
+
}
|
|
51
|
+
// ---- Derivation ------------------------------------------------------------
|
|
42
52
|
function buildEvidenceReasoningReport(run, options = {}) {
|
|
43
53
|
const operator = (0, multi_agent_operator_ux_1.summarizeMultiAgentOperator)(run);
|
|
44
54
|
const scores = readAllScores(run);
|
|
@@ -62,27 +72,18 @@ function buildEvidenceReasoningReport(run, options = {}) {
|
|
|
62
72
|
schemaVersion: exports.EVIDENCE_REASONING_SCHEMA_VERSION,
|
|
63
73
|
runId: run.id,
|
|
64
74
|
generatedAt: new Date().toISOString(),
|
|
65
|
-
freshness: {
|
|
66
|
-
status,
|
|
67
|
-
persistedFingerprint: persisted?.sourceFingerprint,
|
|
68
|
-
currentFingerprint
|
|
69
|
-
},
|
|
75
|
+
freshness: { status, persistedFingerprint: persisted?.sourceFingerprint, currentFingerprint },
|
|
70
76
|
sourceFingerprint: currentFingerprint,
|
|
71
77
|
totals,
|
|
72
78
|
chains,
|
|
73
|
-
nextAction
|
|
79
|
+
nextAction,
|
|
74
80
|
};
|
|
75
81
|
}
|
|
76
82
|
function buildChain(run, evidence, context) {
|
|
77
83
|
const steps = [];
|
|
78
84
|
const sourceRecordIds = new Set();
|
|
79
|
-
const note = (id) => {
|
|
80
|
-
|
|
81
|
-
sourceRecordIds.add(id);
|
|
82
|
-
};
|
|
83
|
-
// Walk the adopters/rejecters recorded on the evidence row and classify each
|
|
84
|
-
// by the gate it represents. We never invent gates: a step exists only when a
|
|
85
|
-
// real adopter/decision record references this evidence.
|
|
85
|
+
const note = (id) => { if (id)
|
|
86
|
+
sourceRecordIds.add(id); };
|
|
86
87
|
const adopters = [...evidence.adoptedBy, ...evidence.rejectedBy];
|
|
87
88
|
for (const scoreId of evidence.scoreIds) {
|
|
88
89
|
const score = context.scores.get(scoreId);
|
|
@@ -90,22 +91,20 @@ function buildChain(run, evidence, context) {
|
|
|
90
91
|
steps.push(buildScoreStep(run, evidence, score, scoreId, context));
|
|
91
92
|
}
|
|
92
93
|
for (const selectionId of evidence.selectionIds) {
|
|
93
|
-
const selection = (run
|
|
94
|
+
const selection = selectionsOf(run).find((entry) => entry.id === selectionId);
|
|
94
95
|
note(selectionId);
|
|
95
96
|
steps.push(buildSelectionStep(run, evidence, selection, selectionId, context));
|
|
96
97
|
}
|
|
97
98
|
for (const commitId of evidence.commitIds) {
|
|
98
|
-
const commit = (run
|
|
99
|
+
const commit = commitsOf(run).find((entry) => entry.id === commitId);
|
|
99
100
|
note(commitId);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const verifierStep = buildVerifierStep(run, evidence, commit, commitId);
|
|
101
|
+
steps.push(buildCommitStep(run, evidence, commit, commitId));
|
|
102
|
+
const verifierStep = buildVerifierStep(evidence, commit, commitId);
|
|
103
103
|
if (verifierStep)
|
|
104
104
|
steps.push(verifierStep);
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
const decisions = run.blackboard?.decisions || [];
|
|
106
|
+
const faninIds = new Set(faninsOf(run).map((entry) => entry.id));
|
|
107
|
+
const decisions = decisionsOf(run);
|
|
109
108
|
for (const adopter of unique(adopters)) {
|
|
110
109
|
if (faninIds.has(adopter)) {
|
|
111
110
|
note(adopter);
|
|
@@ -115,13 +114,10 @@ function buildChain(run, evidence, context) {
|
|
|
115
114
|
const decision = decisions.find((entry) => entry.id === adopter);
|
|
116
115
|
if (decision) {
|
|
117
116
|
note(decision.id);
|
|
118
|
-
steps.push(buildDecisionStep(
|
|
117
|
+
steps.push(buildDecisionStep(evidence, decision));
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
|
-
// An adopted/rejected item that produced no decision-gate step has a known
|
|
123
|
-
// WHAT but no recorded WHY: fail closed with an explicit unexplained step so
|
|
124
|
-
// the gap is visible rather than silently treated as adopted.
|
|
125
121
|
if (!steps.length && isDecisionStatus(evidence.status)) {
|
|
126
122
|
steps.push(buildUnexplainedStep(evidence));
|
|
127
123
|
}
|
|
@@ -142,17 +138,12 @@ function buildChain(run, evidence, context) {
|
|
|
142
138
|
sourceId: evidence.sourceId,
|
|
143
139
|
steps,
|
|
144
140
|
sourceRecordIds: [...sourceRecordIds].filter(Boolean).sort(),
|
|
145
|
-
unexplainedReasons
|
|
141
|
+
unexplainedReasons,
|
|
146
142
|
};
|
|
147
143
|
}
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
// Per-gate steps
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
144
|
function buildScoreStep(run, evidence, score, scoreId, context) {
|
|
152
145
|
const decision = score?.verdict === "fail" ? "rejected" : "adopted";
|
|
153
|
-
const judge = context.auditEvents.find((event) => event.kind === "judge.rationale" &&
|
|
154
|
-
event.decision === "accepted" &&
|
|
155
|
-
(event.scoreId === scoreId || (!event.scoreId && event.candidateId && evidence.candidateIds.includes(event.candidateId))));
|
|
146
|
+
const judge = context.auditEvents.find((event) => event.kind === "judge.rationale" && event.decision === "accepted" && (event.scoreId === scoreId || (!event.scoreId && event.candidateId && evidence.candidateIds.includes(event.candidateId))));
|
|
156
147
|
const rationaleText = score?.notes || judgeRationaleText(judge);
|
|
157
148
|
const rationale = rationaleText
|
|
158
149
|
? {
|
|
@@ -161,13 +152,9 @@ function buildScoreStep(run, evidence, score, scoreId, context) {
|
|
|
161
152
|
sourceKind: score?.notes ? "score-notes" : "judge-rationale",
|
|
162
153
|
sourceId: score?.notes ? scoreId : judge?.id,
|
|
163
154
|
scoreCriteria: score?.criteria,
|
|
164
|
-
scoreDelta: context.counterfactuals.bestRejectedNormalized !== undefined && score
|
|
165
|
-
? round(score.normalized - context.counterfactuals.bestRejectedNormalized)
|
|
166
|
-
: undefined
|
|
155
|
+
scoreDelta: context.counterfactuals.bestRejectedNormalized !== undefined && score ? round(score.normalized - context.counterfactuals.bestRejectedNormalized) : undefined,
|
|
167
156
|
}
|
|
168
157
|
: unexplainedRationale();
|
|
169
|
-
// AUTHORITY: the judge role that authored the rationale, when recorded; the
|
|
170
|
-
// host that mechanically wrote the score is the fallback actor.
|
|
171
158
|
const auditIds = unique([...collectAuditIds(score), ...(judge ? [judge.id] : [])]);
|
|
172
159
|
return {
|
|
173
160
|
gate: "candidate-score",
|
|
@@ -175,77 +162,44 @@ function buildScoreStep(run, evidence, score, scoreId, context) {
|
|
|
175
162
|
basis: basisFor(evidence, { auditEventIds: auditIds, evidenceRefs: scoreEvidenceRefs(score) }),
|
|
176
163
|
authority: roleAuthority(run, judge?.agentRoleId || score?.scorer, judge ? judge.decision === "accepted" : undefined),
|
|
177
164
|
rationale,
|
|
178
|
-
counterfactuals: decision === "adopted" ? context.counterfactuals.forScoreGate : []
|
|
165
|
+
counterfactuals: decision === "adopted" ? context.counterfactuals.forScoreGate : [],
|
|
179
166
|
};
|
|
180
167
|
}
|
|
181
168
|
function buildSelectionStep(run, evidence, selection, selectionId, context) {
|
|
182
169
|
const rationaleText = selection?.reason;
|
|
183
170
|
const acceptance = selection?.acceptanceRationale;
|
|
184
171
|
const rationale = rationaleText
|
|
185
|
-
? {
|
|
186
|
-
status: "explained",
|
|
187
|
-
text: truncate(rationaleText),
|
|
188
|
-
sourceKind: "selection-reason",
|
|
189
|
-
sourceId: selectionId,
|
|
190
|
-
scoreCriteria: acceptance?.scoreCriteria,
|
|
191
|
-
judgeRationaleIds: acceptance?.judgeRationaleIds,
|
|
192
|
-
panelDecisionId: acceptance?.panelDecisionId
|
|
193
|
-
}
|
|
172
|
+
? { status: "explained", text: truncate(rationaleText), sourceKind: "selection-reason", sourceId: selectionId, scoreCriteria: acceptance?.scoreCriteria, judgeRationaleIds: acceptance?.judgeRationaleIds, panelDecisionId: acceptance?.panelDecisionId }
|
|
194
173
|
: acceptance
|
|
195
|
-
? {
|
|
196
|
-
status: "explained",
|
|
197
|
-
text: `commit gate ${acceptance.commitGateResult || "recorded"} with ${acceptance.evidenceCount} evidence ref(s)`,
|
|
198
|
-
sourceKind: "acceptance-rationale",
|
|
199
|
-
sourceId: selectionId,
|
|
200
|
-
scoreCriteria: acceptance.scoreCriteria,
|
|
201
|
-
judgeRationaleIds: acceptance.judgeRationaleIds,
|
|
202
|
-
panelDecisionId: acceptance.panelDecisionId
|
|
203
|
-
}
|
|
174
|
+
? { status: "explained", text: `commit gate ${acceptance.commitGateResult || "recorded"} with ${acceptance.evidenceCount} evidence ref(s)`, sourceKind: "acceptance-rationale", sourceId: selectionId, scoreCriteria: acceptance.scoreCriteria, judgeRationaleIds: acceptance.judgeRationaleIds, panelDecisionId: acceptance.panelDecisionId }
|
|
204
175
|
: unexplainedRationale();
|
|
205
|
-
|
|
206
|
-
// coordinator decision for this selection; the host is the fallback actor.
|
|
207
|
-
const synthesis = (run.blackboard?.decisions || []).find((entry) => entry.kind === "candidate-synthesis" && entry.subjectIds.includes(selectionId) && entry.author?.kind === "role");
|
|
176
|
+
const synthesis = decisionsOf(run).find((entry) => entry.kind === "candidate-synthesis" && (entry.subjectIds || []).includes(selectionId) && entry.author?.kind === "role");
|
|
208
177
|
return {
|
|
209
178
|
gate: "selection",
|
|
210
179
|
decision: "adopted",
|
|
211
|
-
basis: basisFor(evidence, {
|
|
212
|
-
auditEventIds: acceptance?.auditEventIds || [],
|
|
213
|
-
evidenceRefs: (selection?.evidence || []).map(evidenceRef).filter(Boolean)
|
|
214
|
-
}),
|
|
180
|
+
basis: basisFor(evidence, { auditEventIds: acceptance?.auditEventIds || [], evidenceRefs: (selection?.evidence || []).map(evidenceRef).filter(Boolean) }),
|
|
215
181
|
authority: roleAuthority(run, synthesis?.author?.id || selection?.selectedBy, true),
|
|
216
182
|
rationale,
|
|
217
|
-
counterfactuals: context.counterfactuals.forSelectionGate
|
|
183
|
+
counterfactuals: context.counterfactuals.forSelectionGate,
|
|
218
184
|
};
|
|
219
185
|
}
|
|
220
|
-
function buildCommitStep(
|
|
186
|
+
function buildCommitStep(_run, evidence, commit, commitId) {
|
|
221
187
|
const decision = commit?.verifierGated ? "adopted" : "pending";
|
|
222
188
|
const rationale = commit?.reason
|
|
223
|
-
? {
|
|
224
|
-
status: "explained",
|
|
225
|
-
text: truncate(commit.reason),
|
|
226
|
-
sourceKind: "commit-reason",
|
|
227
|
-
sourceId: commitId
|
|
228
|
-
}
|
|
189
|
+
? { status: "explained", text: truncate(commit.reason), sourceKind: "commit-reason", sourceId: commitId }
|
|
229
190
|
: decision === "adopted"
|
|
230
191
|
? unexplainedRationale()
|
|
231
192
|
: { status: "not-applicable" };
|
|
232
193
|
return {
|
|
233
194
|
gate: "commit",
|
|
234
195
|
decision,
|
|
235
|
-
basis: basisFor(evidence, {
|
|
236
|
-
|
|
237
|
-
evidenceRefs: (commit?.evidence || []).map(evidenceRef).filter(Boolean)
|
|
238
|
-
}),
|
|
239
|
-
authority: {
|
|
240
|
-
actor: commitId,
|
|
241
|
-
actorKind: "runtime",
|
|
242
|
-
allowed: commit?.verifierGated
|
|
243
|
-
},
|
|
196
|
+
basis: basisFor(evidence, { auditEventIds: commit?.acceptanceRationale?.auditEventIds || [], evidenceRefs: (commit?.evidence || []).map(evidenceRef).filter(Boolean) }),
|
|
197
|
+
authority: { actor: commitId, actorKind: "runtime", allowed: commit?.verifierGated },
|
|
244
198
|
rationale,
|
|
245
|
-
counterfactuals: []
|
|
199
|
+
counterfactuals: [],
|
|
246
200
|
};
|
|
247
201
|
}
|
|
248
|
-
function buildVerifierStep(
|
|
202
|
+
function buildVerifierStep(evidence, commit, commitId) {
|
|
249
203
|
const verifierNodeId = commit?.verifierNodeId;
|
|
250
204
|
if (!verifierNodeId)
|
|
251
205
|
return undefined;
|
|
@@ -260,27 +214,22 @@ function buildVerifierStep(run, evidence, commit, commitId) {
|
|
|
260
214
|
: commit?.verifierGated
|
|
261
215
|
? { status: "explained", text: "verifier-gated commit recorded", sourceKind: "commit-reason", sourceId: commitId }
|
|
262
216
|
: { status: "not-applicable" },
|
|
263
|
-
counterfactuals: []
|
|
217
|
+
counterfactuals: [],
|
|
264
218
|
};
|
|
265
219
|
}
|
|
266
220
|
function buildFaninStep(run, evidence, faninId, decisions) {
|
|
267
|
-
const fanin = (run
|
|
268
|
-
const readiness = decisions.find((entry) => entry.kind === "fanin-readiness" && entry.subjectIds.includes(faninId));
|
|
221
|
+
const fanin = faninsOf(run).find((entry) => entry.id === faninId);
|
|
222
|
+
const readiness = decisions.find((entry) => entry.kind === "fanin-readiness" && (entry.subjectIds || []).includes(faninId));
|
|
269
223
|
const adopted = evidence.adoptedBy.includes(faninId);
|
|
270
224
|
const decision = adopted ? "adopted" : "pending";
|
|
271
225
|
let rationale;
|
|
272
226
|
if (readiness?.reason) {
|
|
273
227
|
rationale = { status: "explained", text: truncate(readiness.reason), sourceKind: "coordinator-decision", sourceId: readiness.id };
|
|
274
228
|
}
|
|
275
|
-
else if (fanin && fanin.verifierReady && coverageComplete(fanin
|
|
276
|
-
rationale = {
|
|
277
|
-
status: "explained",
|
|
278
|
-
text: `fanin ${faninId} ready: required evidence covered under "${fanin.strategy}" strategy`,
|
|
279
|
-
sourceKind: "coordinator-decision",
|
|
280
|
-
sourceId: faninId
|
|
281
|
-
};
|
|
229
|
+
else if (fanin && fanin.verifierReady && coverageComplete(fanin)) {
|
|
230
|
+
rationale = { status: "explained", text: `fanin ${faninId} ready: required evidence covered under "${fanin.strategy}" strategy`, sourceKind: "coordinator-decision", sourceId: faninId };
|
|
282
231
|
}
|
|
283
|
-
else if (fanin && fanin.blockedReasons.length) {
|
|
232
|
+
else if (fanin && (fanin.blockedReasons || []).length) {
|
|
284
233
|
rationale = { status: "explained", text: truncate(fanin.blockedReasons[0]), sourceKind: "coordinator-decision", sourceId: faninId };
|
|
285
234
|
}
|
|
286
235
|
else {
|
|
@@ -292,109 +241,66 @@ function buildFaninStep(run, evidence, faninId, decisions) {
|
|
|
292
241
|
basis: basisFor(evidence, { auditEventIds: [], evidenceRefs: [] }),
|
|
293
242
|
authority: { actor: faninId, actorKind: "coordinator", allowed: adopted },
|
|
294
243
|
rationale,
|
|
295
|
-
counterfactuals: []
|
|
244
|
+
counterfactuals: [],
|
|
296
245
|
};
|
|
297
246
|
}
|
|
298
|
-
function buildDecisionStep(
|
|
299
|
-
const status = mapDecisionOutcome(decision.outcome);
|
|
247
|
+
function buildDecisionStep(evidence, decision) {
|
|
248
|
+
const status = mapDecisionOutcome(decision.outcome || "");
|
|
300
249
|
return {
|
|
301
250
|
gate: "fanin",
|
|
302
251
|
decision: status,
|
|
303
252
|
basis: basisFor(evidence, { auditEventIds: [], evidenceRefs: decision.evidenceRefs || [] }),
|
|
304
|
-
authority: {
|
|
305
|
-
actor: decision.author?.id || decision.id,
|
|
306
|
-
actorKind: authorKind(decision.author?.kind),
|
|
307
|
-
allowed: decision.outcome === "accepted" || decision.outcome === "ready"
|
|
308
|
-
},
|
|
253
|
+
authority: { actor: decision.author?.id || decision.id, actorKind: authorKind(decision.author?.kind), allowed: decision.outcome === "accepted" || decision.outcome === "ready" },
|
|
309
254
|
rationale: decision.reason
|
|
310
255
|
? { status: "explained", text: truncate(decision.reason), sourceKind: "coordinator-decision", sourceId: decision.id }
|
|
311
256
|
: isDecisionStatus(status)
|
|
312
257
|
? unexplainedRationale()
|
|
313
258
|
: { status: "not-applicable" },
|
|
314
|
-
counterfactuals: []
|
|
259
|
+
counterfactuals: [],
|
|
315
260
|
};
|
|
316
261
|
}
|
|
317
262
|
function buildUnexplainedStep(evidence) {
|
|
318
|
-
// The item is marked adopted/rejected but no decision record carries a reason.
|
|
319
|
-
// Render the gap explicitly (fail closed) rather than inferring a rationale.
|
|
320
263
|
return {
|
|
321
264
|
gate: "fanin",
|
|
322
265
|
decision: mapStatus(evidence.status),
|
|
323
266
|
basis: basisFor(evidence, { auditEventIds: [], evidenceRefs: [] }),
|
|
324
|
-
authority: {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
allowed: evidence.status === "adopted"
|
|
328
|
-
},
|
|
329
|
-
rationale: evidence.reason
|
|
330
|
-
? { status: "explained", text: truncate(evidence.reason), sourceKind: "coordinator-decision", sourceId: evidence.sourceId }
|
|
331
|
-
: unexplainedRationale(),
|
|
332
|
-
counterfactuals: []
|
|
267
|
+
authority: { actor: evidence.adoptedBy[0] || evidence.rejectedBy[0] || evidence.sourceId, actorKind: actorKindForSource(evidence.sourceKind), allowed: evidence.status === "adopted" },
|
|
268
|
+
rationale: evidence.reason ? { status: "explained", text: truncate(evidence.reason), sourceKind: "coordinator-decision", sourceId: evidence.sourceId } : unexplainedRationale(),
|
|
269
|
+
counterfactuals: [],
|
|
333
270
|
};
|
|
334
271
|
}
|
|
335
|
-
// ---------------------------------------------------------------------------
|
|
336
|
-
// Counterfactuals
|
|
337
|
-
// ---------------------------------------------------------------------------
|
|
338
272
|
function deriveCounterfactuals(run, scores) {
|
|
339
273
|
const forScoreGate = [];
|
|
340
274
|
const forSelectionGate = [];
|
|
341
275
|
let bestRejectedNormalized;
|
|
342
|
-
for (const candidate of run
|
|
276
|
+
for (const candidate of candidatesOf(run)) {
|
|
343
277
|
if (candidate.status === "rejected" || candidate.status === "failed") {
|
|
344
|
-
forSelectionGate.push({
|
|
345
|
-
ref: candidate.id,
|
|
346
|
-
kind: "candidate",
|
|
347
|
-
status: "rejected",
|
|
348
|
-
reason: candidate.feedbackIds[0] ? `see feedback ${candidate.feedbackIds[0]}` : `candidate ${candidate.id} ${candidate.status}`
|
|
349
|
-
});
|
|
278
|
+
forSelectionGate.push({ ref: candidate.id, kind: "candidate", status: "rejected", reason: (candidate.feedbackIds || [])[0] ? `see feedback ${candidate.feedbackIds[0]}` : `candidate ${candidate.id} ${candidate.status}` });
|
|
350
279
|
for (const scoreId of candidate.scores || []) {
|
|
351
280
|
const score = scores.get(scoreId);
|
|
352
|
-
if (score && (bestRejectedNormalized === undefined || score.normalized > bestRejectedNormalized))
|
|
281
|
+
if (score && (bestRejectedNormalized === undefined || score.normalized > bestRejectedNormalized))
|
|
353
282
|
bestRejectedNormalized = score.normalized;
|
|
354
|
-
}
|
|
355
283
|
}
|
|
356
284
|
}
|
|
357
285
|
}
|
|
358
286
|
for (const [scoreId, score] of scores) {
|
|
359
287
|
if (score.verdict === "fail") {
|
|
360
|
-
forScoreGate.push({
|
|
361
|
-
ref: scoreId,
|
|
362
|
-
kind: "score",
|
|
363
|
-
status: "rejected",
|
|
364
|
-
reason: score.notes ? truncate(score.notes) : `score ${scoreId} verdict=fail (normalized ${round(score.normalized)})`
|
|
365
|
-
});
|
|
288
|
+
forScoreGate.push({ ref: scoreId, kind: "score", status: "rejected", reason: score.notes ? truncate(score.notes) : `score ${scoreId} verdict=fail (normalized ${round(score.normalized)})` });
|
|
366
289
|
}
|
|
367
290
|
}
|
|
368
|
-
for (const decision of run
|
|
291
|
+
for (const decision of decisionsOf(run)) {
|
|
369
292
|
if (decision.outcome === "rejected" || decision.outcome === "superseded" || decision.outcome === "conflicting") {
|
|
370
|
-
forSelectionGate.push({
|
|
371
|
-
ref: decision.id,
|
|
372
|
-
kind: "decision",
|
|
373
|
-
status: mapDecisionOutcome(decision.outcome),
|
|
374
|
-
reason: decision.reason ? truncate(decision.reason) : `decision ${decision.id} ${decision.outcome}`
|
|
375
|
-
});
|
|
293
|
+
forSelectionGate.push({ ref: decision.id, kind: "decision", status: mapDecisionOutcome(decision.outcome), reason: decision.reason ? truncate(decision.reason) : `decision ${decision.id} ${decision.outcome}` });
|
|
376
294
|
}
|
|
377
295
|
}
|
|
378
|
-
return {
|
|
379
|
-
forScoreGate: forScoreGate.sort(byRef),
|
|
380
|
-
forSelectionGate: forSelectionGate.sort(byRef),
|
|
381
|
-
bestRejectedNormalized
|
|
382
|
-
};
|
|
296
|
+
return { forScoreGate: forScoreGate.sort(byRef), forSelectionGate: forSelectionGate.sort(byRef), bestRejectedNormalized };
|
|
383
297
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
//
|
|
387
|
-
// FreeBSD tenet — ORTHOGONALITY & COMPOSABILITY: the reasoning chain composes
|
|
388
|
-
// with the existing graph views and must survive compaction. A reasoning step is
|
|
389
|
-
// on the critical path and must NEVER be collapsed into a synthetic summary
|
|
390
|
-
// node. This returns the operator-graph node ids backing every decision-bearing
|
|
391
|
-
// reasoning step of an adopted chain, so state-explosion can protect them.
|
|
392
|
-
// ---------------------------------------------------------------------------
|
|
393
|
-
function reasoningCriticalNodeIds(run, operator = (0, multi_agent_operator_ux_1.summarizeMultiAgentOperator)(run)) {
|
|
298
|
+
/** Critical-path node ids that state-explosion compaction must never collapse. */
|
|
299
|
+
function reasoningCriticalNodeIds(run) {
|
|
394
300
|
const ids = new Set();
|
|
395
|
-
const faninIds = new Set((run
|
|
396
|
-
const commitById = new Map((run
|
|
397
|
-
for (const evidence of
|
|
301
|
+
const faninIds = new Set(faninsOf(run).map((entry) => entry.id));
|
|
302
|
+
const commitById = new Map(commitsOf(run).map((commit) => [commit.id, commit]));
|
|
303
|
+
for (const evidence of (0, multi_agent_operator_ux_1.summarizeMultiAgentOperator)(run).evidence) {
|
|
398
304
|
if (evidence.status !== "adopted")
|
|
399
305
|
continue;
|
|
400
306
|
for (const id of evidence.candidateIds)
|
|
@@ -403,20 +309,15 @@ function reasoningCriticalNodeIds(run, operator = (0, multi_agent_operator_ux_1.
|
|
|
403
309
|
ids.add(`${run.id}:score:${id}`);
|
|
404
310
|
for (const id of evidence.selectionIds)
|
|
405
311
|
ids.add(`${run.id}:selection:${id}`);
|
|
406
|
-
for (const id of evidence.commitIds)
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
for (const adopter of evidence.adoptedBy) {
|
|
312
|
+
for (const id of evidence.commitIds)
|
|
313
|
+
ids.add(commitById.get(id)?.stateNodeId || `${run.id}:commit:${id}`);
|
|
314
|
+
for (const adopter of evidence.adoptedBy)
|
|
411
315
|
if (faninIds.has(adopter))
|
|
412
316
|
ids.add(`${run.id}:multi-agent:fanin:${adopter}`);
|
|
413
|
-
}
|
|
414
317
|
}
|
|
415
318
|
return [...ids].sort();
|
|
416
319
|
}
|
|
417
|
-
//
|
|
418
|
-
// Persistence + refresh (mirrors state-explosion summaries discipline)
|
|
419
|
-
// ---------------------------------------------------------------------------
|
|
320
|
+
// ---- Persistence + refresh -------------------------------------------------
|
|
420
321
|
function reasoningDir(run) {
|
|
421
322
|
return node_path_1.default.join(run.paths.runDir, "reasoning");
|
|
422
323
|
}
|
|
@@ -426,15 +327,9 @@ function refreshEvidenceReasoning(run) {
|
|
|
426
327
|
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
427
328
|
const entries = [];
|
|
428
329
|
for (const chain of report.chains) {
|
|
429
|
-
const file = node_path_1.default.join(dir, `chain-${(0,
|
|
430
|
-
(0,
|
|
431
|
-
entries.push({
|
|
432
|
-
id: chain.id,
|
|
433
|
-
path: file,
|
|
434
|
-
evidenceStatus: chain.evidenceStatus,
|
|
435
|
-
rationaleStatus: chain.rationaleStatus,
|
|
436
|
-
sourceFingerprint: fingerprintChains([chain])
|
|
437
|
-
});
|
|
330
|
+
const file = node_path_1.default.join(dir, `chain-${(0, fs_atomic_1.safeFileName)(chain.id)}.json`);
|
|
331
|
+
(0, fs_atomic_1.writeJson)(file, chain);
|
|
332
|
+
entries.push({ id: chain.id, path: file, evidenceStatus: chain.evidenceStatus, rationaleStatus: chain.rationaleStatus, sourceFingerprint: fingerprintChains([chain]) });
|
|
438
333
|
}
|
|
439
334
|
const indexPath = node_path_1.default.join(dir, "index.json");
|
|
440
335
|
const reportPath = node_path_1.default.join(dir, "report.json");
|
|
@@ -447,10 +342,10 @@ function refreshEvidenceReasoning(run) {
|
|
|
447
342
|
totals: report.totals,
|
|
448
343
|
entries: entries.sort((a, b) => a.id.localeCompare(b.id)),
|
|
449
344
|
paths: { reasoningDir: dir, indexPath, reportPath },
|
|
450
|
-
nextAction: `node scripts/cw.js multi-agent reasoning ${run.id}
|
|
345
|
+
nextAction: `node scripts/cw.js multi-agent reasoning ${run.id}`,
|
|
451
346
|
};
|
|
452
|
-
(0,
|
|
453
|
-
(0,
|
|
347
|
+
(0, fs_atomic_1.writeJson)(indexPath, index);
|
|
348
|
+
(0, fs_atomic_1.writeJson)(reportPath, { ...report, freshness: { ...report.freshness, status: "valid", persistedFingerprint: report.sourceFingerprint } });
|
|
454
349
|
return index;
|
|
455
350
|
}
|
|
456
351
|
function loadEvidenceReasoningIndex(run) {
|
|
@@ -475,10 +370,9 @@ function showEvidenceReasoning(run, options = {}) {
|
|
|
475
370
|
const chains = report.chains.filter((chain) => chain.id === options.evidenceId || chain.ref === options.evidenceId);
|
|
476
371
|
return { ...report, chains, totals: summarizeTotals(chains) };
|
|
477
372
|
}
|
|
373
|
+
/** Derive the reasoning eval sections WITHOUT the persisted index (a replay
|
|
374
|
+
* run has no reasoning/index.json). Port of normalizeEvidenceReasoningForEval. */
|
|
478
375
|
function normalizeEvidenceReasoningForEval(run) {
|
|
479
|
-
// Derive without the persisted index: a replay run has no reasoning/index.json,
|
|
480
|
-
// so persistence-derived freshness status would drift. Parity is asserted over
|
|
481
|
-
// the derived content (the CLI smoke test covers valid|stale|absent behavior).
|
|
482
376
|
const report = buildEvidenceReasoningReport(run);
|
|
483
377
|
return {
|
|
484
378
|
reasoningFreshness: [
|
|
@@ -489,8 +383,8 @@ function normalizeEvidenceReasoningForEval(run) {
|
|
|
489
383
|
unexplained: report.totals.unexplained,
|
|
490
384
|
notApplicable: report.totals.notApplicable,
|
|
491
385
|
adopted: report.totals.adopted,
|
|
492
|
-
rejected: report.totals.rejected
|
|
493
|
-
})
|
|
386
|
+
rejected: report.totals.rejected,
|
|
387
|
+
}),
|
|
494
388
|
],
|
|
495
389
|
reasoningChains: report.chains
|
|
496
390
|
.map((chain) => JSON.stringify({
|
|
@@ -498,21 +392,16 @@ function normalizeEvidenceReasoningForEval(run) {
|
|
|
498
392
|
evidenceStatus: chain.evidenceStatus,
|
|
499
393
|
rationaleStatus: chain.rationaleStatus,
|
|
500
394
|
gates: chain.steps.map((step) => `${step.gate}:${step.decision}:${step.rationale.status}`),
|
|
501
|
-
counterfactuals: chain.steps.reduce((total, step) => total + step.counterfactuals.length, 0)
|
|
395
|
+
counterfactuals: chain.steps.reduce((total, step) => total + step.counterfactuals.length, 0),
|
|
502
396
|
}))
|
|
503
397
|
.sort(),
|
|
504
|
-
reasoningUnexplained: report.chains
|
|
505
|
-
.filter((chain) => chain.rationaleStatus === "unexplained")
|
|
506
|
-
.map((chain) => stripRunId(run, chain.id))
|
|
507
|
-
.sort()
|
|
398
|
+
reasoningUnexplained: report.chains.filter((chain) => chain.rationaleStatus === "unexplained").map((chain) => stripRunId(run, chain.id)).sort(),
|
|
508
399
|
};
|
|
509
400
|
}
|
|
510
401
|
function stripRunId(run, id) {
|
|
511
402
|
return id.startsWith(`${run.id}:`) ? id.slice(run.id.length + 1) : id;
|
|
512
403
|
}
|
|
513
|
-
//
|
|
514
|
-
// Human formatting (stable, six-panel-compatible idiom)
|
|
515
|
-
// ---------------------------------------------------------------------------
|
|
404
|
+
// ---- Human formatting ------------------------------------------------------
|
|
516
405
|
function formatEvidenceReasoningReport(report) {
|
|
517
406
|
const lines = [];
|
|
518
407
|
lines.push(`Evidence Adoption Reasoning: ${report.runId}`);
|
|
@@ -521,9 +410,8 @@ function formatEvidenceReasoningReport(report) {
|
|
|
521
410
|
lines.push("Adoption Rationale");
|
|
522
411
|
lines.push(` chains=${report.totals.chains}; explained=${report.totals.explained}; unexplained=${report.totals.unexplained}; n/a=${report.totals.notApplicable}; adopted=${report.totals.adopted}; rejected=${report.totals.rejected}`);
|
|
523
412
|
lines.push("");
|
|
524
|
-
if (!report.chains.length)
|
|
413
|
+
if (!report.chains.length)
|
|
525
414
|
lines.push(" none");
|
|
526
|
-
}
|
|
527
415
|
for (const chain of report.chains.slice(0, 60)) {
|
|
528
416
|
lines.push(` [${chain.evidenceStatus}/${chain.rationaleStatus}] ${chain.id} (${chain.ref || chain.sourceKind})`);
|
|
529
417
|
for (const step of chain.steps) {
|
|
@@ -531,9 +419,8 @@ function formatEvidenceReasoningReport(report) {
|
|
|
531
419
|
const why = step.rationale.status === "explained" ? step.rationale.text : `(${step.rationale.status})`;
|
|
532
420
|
const policy = step.authority.policyRef ? ` policy=${step.authority.policyRef}` : "";
|
|
533
421
|
lines.push(` - ${step.gate} [${step.decision}] by ${actor}${policy}: ${why}`);
|
|
534
|
-
for (const cf of step.counterfactuals.slice(0, 4))
|
|
422
|
+
for (const cf of step.counterfactuals.slice(0, 4))
|
|
535
423
|
lines.push(` x ${cf.kind} ${cf.ref} [${cf.status}]: ${cf.reason}`);
|
|
536
|
-
}
|
|
537
424
|
}
|
|
538
425
|
for (const reason of chain.unexplainedReasons)
|
|
539
426
|
lines.push(` ! ${reason}`);
|
|
@@ -545,41 +432,30 @@ function formatEvidenceReasoningReport(report) {
|
|
|
545
432
|
lines.push(` ${report.nextAction}`);
|
|
546
433
|
return lines.join("\n");
|
|
547
434
|
}
|
|
548
|
-
//
|
|
549
|
-
// Helpers
|
|
550
|
-
// ---------------------------------------------------------------------------
|
|
435
|
+
// ---- Helpers ---------------------------------------------------------------
|
|
551
436
|
function basisFor(evidence, extra) {
|
|
552
437
|
return {
|
|
553
438
|
evidenceRefs: unique([evidence.locator || evidence.path || evidence.ref || evidence.id, ...extra.evidenceRefs].filter(Boolean)),
|
|
554
439
|
provenanceSource: provenanceSourceFor(evidence),
|
|
555
440
|
parentEvidenceIds: [],
|
|
556
|
-
auditEventIds: unique(extra.auditEventIds.filter(Boolean))
|
|
441
|
+
auditEventIds: unique(extra.auditEventIds.filter(Boolean)),
|
|
557
442
|
};
|
|
558
443
|
}
|
|
559
444
|
function provenanceSourceFor(evidence) {
|
|
560
445
|
const value = evidence.provenanceSource;
|
|
561
|
-
if (value === "cw-validated" || value === "host-attested" || value === "operator-recorded" || value === "runtime-derived")
|
|
446
|
+
if (value === "cw-validated" || value === "host-attested" || value === "operator-recorded" || value === "runtime-derived")
|
|
562
447
|
return value;
|
|
563
|
-
}
|
|
564
448
|
return undefined;
|
|
565
449
|
}
|
|
566
|
-
// AUTHORITY resolver: links the actor to its role policy when the actor is a
|
|
567
|
-
// role; never fabricates a policy. allowed comes from the recorded decision.
|
|
568
450
|
function roleAuthority(run, actor, allowed) {
|
|
569
|
-
const role = (run
|
|
570
|
-
const policyRef = role ? (role.policy || (0,
|
|
571
|
-
return {
|
|
572
|
-
actor,
|
|
573
|
-
actorKind: role ? "role" : actor === "multi-agent-host" ? "operator" : actorKindForActor(actor),
|
|
574
|
-
policyRef,
|
|
575
|
-
allowed
|
|
576
|
-
};
|
|
451
|
+
const role = rolesOf(run).find((entry) => entry.id === actor);
|
|
452
|
+
const policyRef = role ? (role.policy || (0, trust_policy_1.policyForRole)(role)).policyRef : undefined;
|
|
453
|
+
return { actor, actorKind: role ? "role" : actor === "multi-agent-host" ? "operator" : actorKindForActor(actor), policyRef, allowed };
|
|
577
454
|
}
|
|
578
455
|
function rollupRationale(steps, evidenceStatus) {
|
|
579
456
|
const decisionSteps = steps.filter((step) => isDecisionStatus(step.decision));
|
|
580
457
|
if (!decisionSteps.length)
|
|
581
458
|
return "not-applicable";
|
|
582
|
-
// Explained only when EVERY decision-bearing step is explained — fail closed.
|
|
583
459
|
if (decisionSteps.some((step) => step.rationale.status === "unexplained"))
|
|
584
460
|
return "unexplained";
|
|
585
461
|
if (decisionSteps.every((step) => step.rationale.status === "explained"))
|
|
@@ -588,11 +464,7 @@ function rollupRationale(steps, evidenceStatus) {
|
|
|
588
464
|
}
|
|
589
465
|
function summarizeTotals(chains) {
|
|
590
466
|
const byStatus = {};
|
|
591
|
-
let explained = 0;
|
|
592
|
-
let unexplained = 0;
|
|
593
|
-
let notApplicable = 0;
|
|
594
|
-
let adopted = 0;
|
|
595
|
-
let rejected = 0;
|
|
467
|
+
let explained = 0, unexplained = 0, notApplicable = 0, adopted = 0, rejected = 0;
|
|
596
468
|
for (const chain of chains) {
|
|
597
469
|
byStatus[chain.evidenceStatus] = (byStatus[chain.evidenceStatus] || 0) + 1;
|
|
598
470
|
if (chain.rationaleStatus === "explained")
|
|
@@ -611,31 +483,28 @@ function summarizeTotals(chains) {
|
|
|
611
483
|
function readAllScores(run) {
|
|
612
484
|
const scores = new Map();
|
|
613
485
|
const candidatesDir = run.paths.candidatesDir || node_path_1.default.join(run.paths.runDir, "candidates");
|
|
614
|
-
for (const candidate of run
|
|
615
|
-
const dir = node_path_1.default.join(candidatesDir, (0,
|
|
486
|
+
for (const candidate of candidatesOf(run)) {
|
|
487
|
+
const dir = node_path_1.default.join(candidatesDir, (0, fs_atomic_1.safeFileName)(candidate.id), "scores");
|
|
616
488
|
if (!node_fs_1.default.existsSync(dir))
|
|
617
489
|
continue;
|
|
618
490
|
for (const file of node_fs_1.default.readdirSync(dir).filter((entry) => entry.endsWith(".json")).sort()) {
|
|
619
491
|
try {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
492
|
+
// Fail closed on a malformed/forged score shape via the shared core
|
|
493
|
+
// guard (full field-shape check, not just id/normalized).
|
|
494
|
+
const parsed = (0, validation_1.tryValidateCandidateScore)(JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, file), "utf8")));
|
|
495
|
+
if (!parsed)
|
|
496
|
+
continue;
|
|
497
|
+
scores.set(parsed.id, parsed);
|
|
624
498
|
}
|
|
625
499
|
catch {
|
|
626
|
-
// Unreadable score record: skip; the score gate
|
|
500
|
+
// Unreadable score record: skip; the score gate fails closed.
|
|
627
501
|
}
|
|
628
502
|
}
|
|
629
503
|
}
|
|
630
504
|
return scores;
|
|
631
505
|
}
|
|
632
506
|
function fingerprintChains(chains) {
|
|
633
|
-
const lines = chains.map((chain) => JSON.stringify([
|
|
634
|
-
chain.id,
|
|
635
|
-
chain.evidenceStatus,
|
|
636
|
-
chain.rationaleStatus,
|
|
637
|
-
chain.steps.map((step) => [step.gate, step.decision, step.rationale.status, step.rationale.sourceId || ""])
|
|
638
|
-
]));
|
|
507
|
+
const lines = chains.map((chain) => JSON.stringify([chain.id, chain.evidenceStatus, chain.rationaleStatus, chain.steps.map((step) => [step.gate, step.decision, step.rationale.status, step.rationale.sourceId || ""])]));
|
|
639
508
|
const hash = node_crypto_1.default.createHash("sha256");
|
|
640
509
|
hash.update(JSON.stringify([...lines].sort()));
|
|
641
510
|
return `sha256:${hash.digest("hex").slice(0, 32)}`;
|
|
@@ -649,10 +518,9 @@ function judgeRationaleText(event) {
|
|
|
649
518
|
}
|
|
650
519
|
function collectAuditIds(score) {
|
|
651
520
|
const ids = [];
|
|
652
|
-
for (const item of score?.evidence || [])
|
|
521
|
+
for (const item of score?.evidence || [])
|
|
653
522
|
for (const id of item.provenance?.auditEventIds || [])
|
|
654
523
|
ids.push(id);
|
|
655
|
-
}
|
|
656
524
|
return ids;
|
|
657
525
|
}
|
|
658
526
|
function scoreEvidenceRefs(score) {
|
|
@@ -661,8 +529,9 @@ function scoreEvidenceRefs(score) {
|
|
|
661
529
|
function evidenceRef(item) {
|
|
662
530
|
return item.locator || item.path || item.summary || item.id || "";
|
|
663
531
|
}
|
|
664
|
-
function coverageComplete(fanin
|
|
665
|
-
|
|
532
|
+
function coverageComplete(fanin) {
|
|
533
|
+
const coverage = fanin.evidenceCoverage || [];
|
|
534
|
+
return coverage.length > 0 && coverage.every((entry) => entry.complete);
|
|
666
535
|
}
|
|
667
536
|
function mapStatus(status) {
|
|
668
537
|
return status;
|
|
@@ -719,7 +588,7 @@ function actorKindForSource(sourceKind) {
|
|
|
719
588
|
return "runtime";
|
|
720
589
|
}
|
|
721
590
|
function statusRank(status) {
|
|
722
|
-
return { adopted: 0, pending: 1, missing: 2, conflicting: 3, rejected: 4, superseded: 5, unexplained: 6 }[status];
|
|
591
|
+
return { adopted: 0, pending: 1, missing: 2, conflicting: 3, rejected: 4, superseded: 5, unexplained: 6 }[status] ?? 9;
|
|
723
592
|
}
|
|
724
593
|
function truncate(value) {
|
|
725
594
|
const single = value.replace(/\s+/g, " ").trim();
|