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
package/dist/node-projection.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Canonical StateNode projection (F9 de-triplication) — the SINGLE source of
|
|
3
|
-
// truth for which StateNode fields make up the derived, fingerprinted body.
|
|
4
|
-
//
|
|
5
|
-
// Previously this 13-field set was hand-copied in three places: node-snapshot.ts's
|
|
6
|
-
// snapshotBody, reclamation.ts's snapshotProjectionDigest, and reclamation.ts's
|
|
7
|
-
// rawNodeBody/nodeBodyDigest (whose comment literally said "Mirror
|
|
8
|
-
// node-snapshot.ts"). Any field added in one place but not the others would drift
|
|
9
|
-
// the projection — and because reclamation hashes are tombstone-chained, a drift
|
|
10
|
-
// would silently break the chain. This module collapses the list to ONE export so
|
|
11
|
-
// the field set can only change in one place.
|
|
12
|
-
//
|
|
13
|
-
// BYTE-IDENTITY [load-bearing]: the projection / digest OUTPUT here is identical to
|
|
14
|
-
// the prior in-line implementations. `normalizeValue` sorts object keys, so the
|
|
15
|
-
// literal field ORDER never affected the bytes — only the field SET ever mattered.
|
|
16
|
-
// `replayStableStringify(value) === JSON.stringify(normalizeValue(value))` and
|
|
17
|
-
// `normalizeValue` is idempotent, so the projected-body digest and the raw-body
|
|
18
|
-
// digest funnel through the same canonical bytes (node-snapshot-diff-replay +
|
|
19
|
-
// reclamation smokes verify this).
|
|
20
|
-
//
|
|
21
|
-
// Pure: no I/O, no wall-clock, no random — safe in core/state/replay logic.
|
|
22
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.rawNodeProjection = rawNodeProjection;
|
|
24
|
-
exports.projectNodeBody = projectNodeBody;
|
|
25
|
-
exports.nodeProjectionDigestInput = nodeProjectionDigestInput;
|
|
26
|
-
const multi_agent_eval_1 = require("./multi-agent-eval");
|
|
27
|
-
/** The raw (un-normalized) projection input: the canonical field set, copied off
|
|
28
|
-
* the StateNode with no scrubbing. `normalizeValue`/`replayStableStringify` apply
|
|
29
|
-
* the timestamp/path scrubbing downstream. This is the ONE place the field list
|
|
30
|
-
* lives — add or drop a projected field here and every consumer follows. */
|
|
31
|
-
function rawNodeProjection(node) {
|
|
32
|
-
return {
|
|
33
|
-
id: node.id,
|
|
34
|
-
kind: node.kind,
|
|
35
|
-
status: node.status,
|
|
36
|
-
loopStage: node.loopStage,
|
|
37
|
-
inputs: node.inputs,
|
|
38
|
-
outputs: node.outputs,
|
|
39
|
-
artifacts: node.artifacts,
|
|
40
|
-
evidence: node.evidence,
|
|
41
|
-
errors: node.errors,
|
|
42
|
-
parents: node.parents,
|
|
43
|
-
children: node.children,
|
|
44
|
-
contractId: node.contractId,
|
|
45
|
-
metadata: node.metadata
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
/** The normalized, derived projected body of one StateNode — timestamps/paths
|
|
49
|
-
* stripped via the eval normalizer, so it is byte-stable across captures of the
|
|
50
|
-
* same logical state. This is exactly node-snapshot.ts's historical snapshotBody. */
|
|
51
|
-
function projectNodeBody(node) {
|
|
52
|
-
return (0, multi_agent_eval_1.normalizeValue)(rawNodeProjection(node));
|
|
53
|
-
}
|
|
54
|
-
/** Stable digest input for the projected body: the canonical bytes that the
|
|
55
|
-
* snapshot/reconstruction digests bind. `replayStableStringify` re-normalizes, so
|
|
56
|
-
* feeding the raw projection or the already-normalized body yields identical bytes. */
|
|
57
|
-
function nodeProjectionDigestInput(node) {
|
|
58
|
-
return (0, multi_agent_eval_1.replayStableStringify)(rawNodeProjection(node));
|
|
59
|
-
}
|
package/dist/node-snapshot.js
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Node Snapshot / Diff / Replay (v0.1.35) — per-node granularity over the eval
|
|
3
|
-
// harness. Snapshot one StateNode into a DERIVED, sha256-fingerprinted projection,
|
|
4
|
-
// diff two snapshots structurally, and deterministically replay one node in
|
|
5
|
-
// isolation.
|
|
6
|
-
//
|
|
7
|
-
// BSD discipline:
|
|
8
|
-
// - MECHANISM, not policy: the caller names the node id; nothing decides which
|
|
9
|
-
// node "matters".
|
|
10
|
-
// - FAIL CLOSED ON SOURCE DRIFT [load-bearing]: a snapshot carries a
|
|
11
|
-
// sourceFingerprint over the RAW node (id:status:updatedAt + artifact/evidence
|
|
12
|
-
// ids+paths). loadNodeSnapshot recomputes it from the current source; on
|
|
13
|
-
// divergence (`stale`) or a missing node/artifact (`absent`) diff/replay REFUSE
|
|
14
|
-
// with a structured error — never a silent stale replay.
|
|
15
|
-
// - REUSE, don't fork: operates on the real StateNode (getRunNode) and reuses the
|
|
16
|
-
// eval harness's normalizeValue/replayStableStringify and state-explosion's
|
|
17
|
-
// fingerprintStrings. No parallel node type, normalizer, or replay engine.
|
|
18
|
-
// - DETERMINISTIC: `now` is injected; the deterministic payload (normalized body
|
|
19
|
-
// + outputFingerprint) carries zero wall-clock, so two replays are byte-identical.
|
|
20
|
-
//
|
|
21
|
-
// Additive: StateNode and STATE_NODE_SCHEMA_VERSION are unchanged. See
|
|
22
|
-
// docs/node-snapshot-diff-replay.7.md.
|
|
23
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
25
|
-
};
|
|
26
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
exports.NodeSnapshotError = exports.NODE_SNAPSHOT_SCHEMA_VERSION = void 0;
|
|
28
|
-
exports.readNodeSnapshot = readNodeSnapshot;
|
|
29
|
-
exports.readNodeReplay = readNodeReplay;
|
|
30
|
-
exports.snapshotNode = snapshotNode;
|
|
31
|
-
exports.loadNodeSnapshot = loadNodeSnapshot;
|
|
32
|
-
exports.diffNodeSnapshots = diffNodeSnapshots;
|
|
33
|
-
exports.replayNodeSnapshot = replayNodeSnapshot;
|
|
34
|
-
exports.verifyNodeReplay = verifyNodeReplay;
|
|
35
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
36
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
37
|
-
const pipeline_runner_1 = require("./pipeline-runner");
|
|
38
|
-
const state_1 = require("./state");
|
|
39
|
-
const multi_agent_eval_1 = require("./multi-agent-eval");
|
|
40
|
-
const node_projection_1 = require("./node-projection");
|
|
41
|
-
const fingerprint_1 = require("./util/fingerprint");
|
|
42
|
-
const validation_1 = require("./validation");
|
|
43
|
-
exports.NODE_SNAPSHOT_SCHEMA_VERSION = 1;
|
|
44
|
-
/** Structured fail-closed error (mirrors the PipelineContractError shape). */
|
|
45
|
-
class NodeSnapshotError extends Error {
|
|
46
|
-
code;
|
|
47
|
-
freshness;
|
|
48
|
-
details;
|
|
49
|
-
constructor(code, message, options = {}) {
|
|
50
|
-
super(message);
|
|
51
|
-
this.name = "NodeSnapshotError";
|
|
52
|
-
this.code = code;
|
|
53
|
-
this.freshness = options.freshness;
|
|
54
|
-
this.details = options.details;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
exports.NodeSnapshotError = NodeSnapshotError;
|
|
58
|
-
const SNAPSHOT_SECTIONS = [
|
|
59
|
-
"status",
|
|
60
|
-
"inputs",
|
|
61
|
-
"outputs",
|
|
62
|
-
"artifacts",
|
|
63
|
-
"evidence",
|
|
64
|
-
"errors",
|
|
65
|
-
"links",
|
|
66
|
-
"metadata"
|
|
67
|
-
];
|
|
68
|
-
/** The normalized projection of a node — timestamps/paths stripped by the eval
|
|
69
|
-
* normalizer, so it is byte-stable across captures of the same logical state. The
|
|
70
|
-
* canonical field set lives in node-projection.ts (shared with reclamation.ts so
|
|
71
|
-
* the projection can never drift across the two). */
|
|
72
|
-
function snapshotBody(node) {
|
|
73
|
-
return (0, node_projection_1.projectNodeBody)(node);
|
|
74
|
-
}
|
|
75
|
-
/** RAW fingerprint (NOT normalized): any transition (updatedAt/status) or
|
|
76
|
-
* artifact/evidence change flips it, which is how drift is detected. */
|
|
77
|
-
function sourceFingerprint(node) {
|
|
78
|
-
return (0, fingerprint_1.fingerprintStrings)([
|
|
79
|
-
`node:${node.id}:${node.status}:${node.updatedAt}`,
|
|
80
|
-
...node.artifacts.map((artifact) => `artifact:${artifact.id}:${artifact.path}`),
|
|
81
|
-
...node.evidence.map((evidence) => `evidence:${evidence.id}:${evidence.path || ""}`)
|
|
82
|
-
]);
|
|
83
|
-
}
|
|
84
|
-
function tryGetNode(run, nodeId) {
|
|
85
|
-
try {
|
|
86
|
-
return (0, pipeline_runner_1.getRunNode)(run, nodeId);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function snapshotsRoot(run) {
|
|
93
|
-
const base = run.paths.stateNodesDir || node_path_1.default.join(run.paths.runDir, "nodes");
|
|
94
|
-
return node_path_1.default.join(base, "snapshots");
|
|
95
|
-
}
|
|
96
|
-
function snapshotDir(run, nodeId) {
|
|
97
|
-
return node_path_1.default.join(snapshotsRoot(run), (0, state_1.safeFileName)(nodeId));
|
|
98
|
-
}
|
|
99
|
-
/** Load a persisted snapshot by id (scans the per-node snapshot dirs). */
|
|
100
|
-
function readNodeSnapshot(run, snapshotId) {
|
|
101
|
-
const root = snapshotsRoot(run);
|
|
102
|
-
if (node_fs_1.default.existsSync(root)) {
|
|
103
|
-
for (const nodeDir of node_fs_1.default.readdirSync(root)) {
|
|
104
|
-
const file = node_path_1.default.join(root, nodeDir, `${snapshotId}.json`);
|
|
105
|
-
if (node_fs_1.default.existsSync(file))
|
|
106
|
-
return (0, validation_1.validateNodeSnapshot)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
throw new NodeSnapshotError("snapshot-not-found", `Node snapshot ${snapshotId} not found in run ${run.id}`, { freshness: "absent" });
|
|
110
|
-
}
|
|
111
|
-
/** Load a persisted replay run by id. */
|
|
112
|
-
function readNodeReplay(run, replayId) {
|
|
113
|
-
const root = snapshotsRoot(run);
|
|
114
|
-
if (node_fs_1.default.existsSync(root)) {
|
|
115
|
-
for (const nodeDir of node_fs_1.default.readdirSync(root)) {
|
|
116
|
-
const file = node_path_1.default.join(root, nodeDir, "replays", `${replayId}.json`);
|
|
117
|
-
if (node_fs_1.default.existsSync(file))
|
|
118
|
-
return (0, validation_1.validateNodeReplayRun)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
throw new NodeSnapshotError("replay-not-found", `Node replay ${replayId} not found in run ${run.id}`, { freshness: "absent" });
|
|
122
|
-
}
|
|
123
|
-
/** Snapshot one StateNode by id. Throws (fail closed) if the node is absent. */
|
|
124
|
-
function snapshotNode(run, nodeId, options = {}) {
|
|
125
|
-
const node = tryGetNode(run, nodeId);
|
|
126
|
-
if (!node) {
|
|
127
|
-
throw new NodeSnapshotError("node-absent", `Cannot snapshot: node ${nodeId} not found in run ${run.id}`, { freshness: "absent" });
|
|
128
|
-
}
|
|
129
|
-
const fingerprint = sourceFingerprint(node);
|
|
130
|
-
const snapshot = {
|
|
131
|
-
schemaVersion: 1,
|
|
132
|
-
snapshotId: `snap-${(0, state_1.safeFileName)(nodeId)}-${fingerprint.replace("sha256:", "").slice(0, 12)}`,
|
|
133
|
-
runId: run.id,
|
|
134
|
-
nodeId,
|
|
135
|
-
capturedAt: options.now || new Date().toISOString(),
|
|
136
|
-
sourceFingerprint: fingerprint,
|
|
137
|
-
body: snapshotBody(node)
|
|
138
|
-
};
|
|
139
|
-
if (options.persist !== false) {
|
|
140
|
-
(0, state_1.writeJson)(node_path_1.default.join(snapshotDir(run, nodeId), `${snapshot.snapshotId}.json`), snapshot);
|
|
141
|
-
}
|
|
142
|
-
return snapshot;
|
|
143
|
-
}
|
|
144
|
-
/** Recompute freshness from current source. valid | stale | absent. */
|
|
145
|
-
function loadNodeSnapshot(run, snapshot) {
|
|
146
|
-
const node = tryGetNode(run, snapshot.nodeId);
|
|
147
|
-
if (!node) {
|
|
148
|
-
return { snapshot, freshness: "absent", reason: `source node ${snapshot.nodeId} is gone from run ${run.id}` };
|
|
149
|
-
}
|
|
150
|
-
const missingArtifact = node.artifacts.find((artifact) => artifact.path && !node_fs_1.default.existsSync(artifact.path));
|
|
151
|
-
if (missingArtifact) {
|
|
152
|
-
return { snapshot, freshness: "absent", reason: `referenced artifact path is unreadable: ${missingArtifact.id}` };
|
|
153
|
-
}
|
|
154
|
-
if (sourceFingerprint(node) !== snapshot.sourceFingerprint) {
|
|
155
|
-
return { snapshot, freshness: "stale", reason: `source node ${snapshot.nodeId} changed since capture` };
|
|
156
|
-
}
|
|
157
|
-
return { snapshot, freshness: "valid" };
|
|
158
|
-
}
|
|
159
|
-
function sectionValue(body, section) {
|
|
160
|
-
if (section === "links")
|
|
161
|
-
return { parents: body.parents, children: body.children };
|
|
162
|
-
return body[section];
|
|
163
|
-
}
|
|
164
|
-
/** Stable, structural diff of two snapshots (same node id or two explicit ids). */
|
|
165
|
-
function diffNodeSnapshots(baseline, candidate) {
|
|
166
|
-
const sections = SNAPSHOT_SECTIONS.map((section) => {
|
|
167
|
-
const baselineValue = sectionValue(baseline.body, section);
|
|
168
|
-
const candidateValue = sectionValue(candidate.body, section);
|
|
169
|
-
const sameBytes = (0, multi_agent_eval_1.replayStableStringify)(baselineValue) === (0, multi_agent_eval_1.replayStableStringify)(candidateValue);
|
|
170
|
-
let change;
|
|
171
|
-
if (sameBytes)
|
|
172
|
-
change = "same";
|
|
173
|
-
else if (baselineValue === undefined)
|
|
174
|
-
change = "added";
|
|
175
|
-
else if (candidateValue === undefined)
|
|
176
|
-
change = "removed";
|
|
177
|
-
else
|
|
178
|
-
change = "changed";
|
|
179
|
-
const entry = { section, change };
|
|
180
|
-
if (change !== "same") {
|
|
181
|
-
entry.baseline = baselineValue;
|
|
182
|
-
entry.candidate = candidateValue;
|
|
183
|
-
}
|
|
184
|
-
return entry;
|
|
185
|
-
});
|
|
186
|
-
return {
|
|
187
|
-
schemaVersion: 1,
|
|
188
|
-
runId: baseline.runId,
|
|
189
|
-
baselineSnapshotId: baseline.snapshotId,
|
|
190
|
-
candidateSnapshotId: candidate.snapshotId,
|
|
191
|
-
baselineNodeId: baseline.nodeId,
|
|
192
|
-
candidateNodeId: candidate.nodeId,
|
|
193
|
-
changed: sections.some((entry) => entry.change !== "same"),
|
|
194
|
-
sections
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
/** Deterministically replay one node from its snapshot, fail-closed on drift.
|
|
198
|
-
* `now` is injected; the deterministic payload (body + outputFingerprint) has
|
|
199
|
-
* zero wall-clock, so two replays are byte-identical. */
|
|
200
|
-
function replayNodeSnapshot(run, snapshot, options = {}) {
|
|
201
|
-
const { freshness, reason } = loadNodeSnapshot(run, snapshot);
|
|
202
|
-
if (freshness !== "valid") {
|
|
203
|
-
throw new NodeSnapshotError(freshness === "stale" ? "snapshot-stale" : "snapshot-absent", reason || `cannot replay a ${freshness} snapshot of node ${snapshot.nodeId}`, { freshness, details: { runId: run.id, nodeId: snapshot.nodeId } });
|
|
204
|
-
}
|
|
205
|
-
const body = (0, multi_agent_eval_1.normalizeValue)(snapshot.body);
|
|
206
|
-
const outputFingerprint = (0, fingerprint_1.fingerprintStrings)([(0, multi_agent_eval_1.replayStableStringify)(body)]);
|
|
207
|
-
const replay = {
|
|
208
|
-
schemaVersion: 1,
|
|
209
|
-
replayId: `replay-${snapshot.snapshotId}-${outputFingerprint.replace("sha256:", "").slice(0, 8)}`,
|
|
210
|
-
runId: run.id,
|
|
211
|
-
nodeId: snapshot.nodeId,
|
|
212
|
-
snapshotId: snapshot.snapshotId,
|
|
213
|
-
replayedAt: options.now || new Date().toISOString(),
|
|
214
|
-
freshness: "valid",
|
|
215
|
-
contractValidated: Boolean(snapshot.body.contractId),
|
|
216
|
-
outputFingerprint,
|
|
217
|
-
body
|
|
218
|
-
};
|
|
219
|
-
if (options.persist !== false) {
|
|
220
|
-
(0, state_1.writeJson)(node_path_1.default.join(snapshotDir(run, snapshot.nodeId), "replays", `${replay.replayId}.json`), replay);
|
|
221
|
-
}
|
|
222
|
-
return replay;
|
|
223
|
-
}
|
|
224
|
-
/** Compare a replay to a fresh snapshot of the source node; pass = byte-identical
|
|
225
|
-
* normalized body. Findings reuse the eval harness severity/category shape. */
|
|
226
|
-
function verifyNodeReplay(run, replay, options = {}) {
|
|
227
|
-
const fresh = tryGetNode(run, replay.nodeId);
|
|
228
|
-
if (!fresh) {
|
|
229
|
-
return {
|
|
230
|
-
schemaVersion: 1,
|
|
231
|
-
runId: run.id,
|
|
232
|
-
nodeId: replay.nodeId,
|
|
233
|
-
replayId: replay.replayId,
|
|
234
|
-
pass: false,
|
|
235
|
-
freshness: "absent",
|
|
236
|
-
findings: [{ id: "source-absent", severity: "error", category: "source", reason: `source node ${replay.nodeId} is gone` }]
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
const freshSnapshot = snapshotNode(run, replay.nodeId, { now: options.now, persist: false });
|
|
240
|
-
const diff = diffNodeSnapshots(freshSnapshot, { ...freshSnapshot, body: replay.body, snapshotId: replay.snapshotId });
|
|
241
|
-
const findings = diff.sections
|
|
242
|
-
.filter((section) => section.change !== "same")
|
|
243
|
-
.map((section) => ({
|
|
244
|
-
id: `drift:${section.section}`,
|
|
245
|
-
severity: "error",
|
|
246
|
-
category: section.section,
|
|
247
|
-
reason: `replay diverged from source in ${section.section}`,
|
|
248
|
-
baselineRef: replay.snapshotId,
|
|
249
|
-
replayRef: replay.replayId
|
|
250
|
-
}));
|
|
251
|
-
return {
|
|
252
|
-
schemaVersion: 1,
|
|
253
|
-
runId: run.id,
|
|
254
|
-
nodeId: replay.nodeId,
|
|
255
|
-
replayId: replay.replayId,
|
|
256
|
-
pass: findings.length === 0,
|
|
257
|
-
freshness: "valid",
|
|
258
|
-
findings
|
|
259
|
-
};
|
|
260
|
-
}
|