harness-everything 0.40.0 → 0.41.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/.agents/harness-everything/project-docs.json +9 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +43 -0
- package/benchmarks/results/f1-doc-path-baseline/1-source-clean.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/1-source-clean.stdout.json +20 -0
- package/benchmarks/results/f1-doc-path-baseline/2-injected-architecture.md +229 -0
- package/benchmarks/results/f1-doc-path-baseline/2-source-injected.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/2-source-injected.stdout.json +33 -0
- package/benchmarks/results/f1-doc-path-baseline/3-source-reverted.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/3-source-reverted.stdout.json +20 -0
- package/benchmarks/results/f1-doc-path-baseline/4a-packaged-clean.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/4a-packaged-clean.stdout.json +20 -0
- package/benchmarks/results/f1-doc-path-baseline/4b-packaged-injected.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/4b-packaged-injected.stdout.json +33 -0
- package/benchmarks/results/f1-doc-path-baseline/5-source-missing-config.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/5-source-missing-config.stdout.json +15 -0
- package/benchmarks/results/f1-doc-path-baseline/5b-packaged-missing-config.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/5b-packaged-missing-config.stdout.json +15 -0
- package/benchmarks/results/f1-doc-path-baseline/README.md +54 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/1-source-clean.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/1-source-clean.stdout.json +115 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/2-injected-document.md +328 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/2-source-injected.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/2-source-injected.stdout.json +127 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/3-source-reverted.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/3-source-reverted.stdout.json +115 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/4a-packaged-clean.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/4a-packaged-clean.stdout.json +115 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/4b-packaged-injected.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/4b-packaged-injected.stdout.json +127 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/5-source-missing-config.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/5-source-missing-config.stdout.json +15 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/5b-packaged-missing-config.stderr.txt +0 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/5b-packaged-missing-config.stdout.json +15 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/6-supplementary-fixture-ok.input.md +8 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/6-supplementary-fixture-ok.stdout.json +16 -0
- package/benchmarks/results/f1-doc-path-baseline/before-fix/README.md +34 -0
- package/benchmarks/results/f1-doc-path-baseline/probe-31-docs/after.json +248 -0
- package/benchmarks/results/f1-doc-path-baseline/probe-31-docs/before.json +254 -0
- package/benchmarks/results/f1-doc-path-baseline/probe-31-docs/probe.js +26 -0
- package/benchmarks/results/f2-doc-craft-baseline/README.md +32 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f1-report.md +84 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f1-task.md +21 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f1.diff +19 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f2-report.md +110 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f2-task.md +21 -0
- package/benchmarks/results/f2-doc-craft-baseline/arm-f2.diff +19 -0
- package/benchmarks/results/f3-derived-views-baseline/README.md +34 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f2-report.md +43 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f2-task.md +21 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f2.diff +21 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f3-report.md +57 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f3-task.md +21 -0
- package/benchmarks/results/f3-derived-views-baseline/arm-f3.diff +21 -0
- package/benchmarks/results/live-host/claude-325-3b-s2b/README.md +99 -0
- package/benchmarks/results/live-host/claude-325-3b-s2b/capture.sanitized.jsonl +26 -0
- package/ci/archive/325-prep/README.md +71 -0
- package/ci/{prep → archive/325-prep}/doc-reconciliation-red.js +9 -7
- package/ci/archive/325-prep/f4-expected-red.json +34 -0
- package/ci/archive/325-prep/historical-qualification.test.js +143 -0
- package/ci/fixtures/doc-obligations/reconciliation-prep/cases.json +17 -4
- package/ci/fixtures/doc-obligations/reconciliation-prep/pending-red.json +8 -56
- package/ci/fixtures/doc-obligations/reconciliation-prep/trust-contract.json +2 -2
- package/ci/fixtures/doc-obligations/reconciliation-s1/cases.json +17 -5
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/harness.js +415 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/off-handoff-golden.json +16 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-post-tool-use-failure.json +11 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-post-tool-use-success-minimal.json +9 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-post-tool-use-success.json +13 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-subagent-start.json +7 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-subagent-stop-freetext-reject.json +11 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-subagent-stop-reject.json +11 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-subagent-stop.json +11 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/capture/payload-task-result.json +19 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/off-capture-only.json +99 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/off-legacy.json +67 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-concurrent-writers.json +62 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-lookalikes-runtime-mutations.json +67 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-malformed.json +85 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-normal-session.json +74 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-runtime-drift-later-npm-test.json +58 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/corpus/on-valid-direct-quoted-review.json +85 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/f4/cases.json +2267 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/wiring/cases.json +1110 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2b/wiring/legacy-off-golden.json +674 -0
- package/ci/lib/doc-reconciliation-file-spy.js +23 -0
- package/ci/lib/doc-reconciliation-prep-fixtures.js +136 -10
- package/ci/lib/doc-reconciliation-qualification-preload.js +37 -0
- package/ci/lib/doc-reconciliation-replay.js +104 -0
- package/ci/lib/doc-reconciliation-staged-tree.js +102 -0
- package/ci/mechanism-2p-opencode-v2-entrypoint.test.js +179 -0
- package/ci/mechanism-325-3b-preparation.test.js +27 -101
- package/ci/mechanism-325-3b-s2b-capture.test.js +561 -0
- package/ci/mechanism-325-3b-s2b-wiring.test.js +668 -0
- package/ci/mechanism-325-f1-doc-check.test.js +674 -0
- package/ci/mechanism-325-f2-doc-craft.test.js +597 -0
- package/ci/mechanism-325-f3-derived-views.test.js +798 -0
- package/ci/mechanism-325-f4-invariants.test.js +606 -0
- package/ci/mechanism-325-f4-projections.test.js +382 -0
- package/ci/mechanism-325-f4-qualification.test.js +228 -0
- package/ci/mechanism-325-f4-trust-boundary.test.js +880 -0
- package/ci/mutation-check.js +26 -3
- package/docs/architecture.md +5 -0
- package/docs/doc-workflow-reconciliation.md +331 -4
- package/docs/document-lifecycle.md +11 -0
- package/docs/governed-index.md +20 -0
- package/docs/platform-capabilities.md +22 -2
- package/grill-with-docs/SKILL.md +1 -1
- package/grill-with-docs/references/session-playbook.md +4 -0
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/references/doc-check.md +186 -0
- package/harness-everything/references/documentation/_shared/maintenance.md +41 -0
- package/harness-everything/references/documentation/_shared/writing-craft.md +59 -0
- package/harness-everything/references/triage-and-tiers.md +4 -0
- package/harness-everything/scripts/doc-check.js +442 -0
- package/harness-everything/scripts/doc-lifecycle.js +3 -0
- package/hooks/hooks.json +46 -0
- package/hooks/scripts/lib/doc-reconciliation-capture.sanitized.jsonl +26 -0
- package/hooks/scripts/lib/doc-reconciliation-pilot.js +171 -2
- package/hooks/scripts/lib/doc-reconciliation-provider.js +1059 -0
- package/hooks/scripts/lib/doc-reconciliation-qualification.json +34 -0
- package/hooks/scripts/lib/workflow-obligations.js +7 -0
- package/hooks/scripts/state-persist.js +78 -2
- package/hooks/scripts/workflow-stop-gate.js +7 -2
- package/opencode-plugin/README.md +15 -0
- package/opencode-plugin/index.mjs +77 -0
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-capture.sanitized.jsonl +26 -0
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-pilot.js +171 -2
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-provider.js +1059 -0
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-qualification.json +34 -0
- package/plugins/harness-everything/hooks/scripts/lib/workflow-obligations.js +7 -0
- package/plugins/harness-everything/hooks/scripts/state-persist.js +78 -2
- package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +7 -2
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/grill-with-docs/SKILL.md +1 -1
- package/plugins/harness-everything/skills/grill-with-docs/references/session-playbook.md +4 -0
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/references/doc-check.md +186 -0
- package/plugins/harness-everything/skills/harness-everything/references/documentation/_shared/maintenance.md +41 -0
- package/plugins/harness-everything/skills/harness-everything/references/documentation/_shared/writing-craft.md +59 -0
- package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +4 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/doc-check.js +442 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/doc-lifecycle.js +3 -0
- package/plugins/harness-everything/skills/repo-docs/SKILL.md +1 -1
- package/plugins/harness-everything/skills/repo-docs/references/process-guide.md +4 -0
- package/plugins/harness-everything/skills/to-spec/SKILL.md +1 -1
- package/plugins/harness-everything/skills/to-spec/references/process.md +4 -0
- package/plugins/harness-everything/skills/to-tickets/SKILL.md +1 -1
- package/plugins/harness-everything/skills/to-tickets/references/publishing-and-templates.md +4 -0
- package/repo-docs/SKILL.md +1 -1
- package/repo-docs/references/process-guide.md +4 -0
- package/sbom.cdx.json +7 -7
- package/to-spec/SKILL.md +1 -1
- package/to-spec/references/process.md +4 -0
- package/to-tickets/SKILL.md +1 -1
- package/to-tickets/references/publishing-and-templates.md +4 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// #325 Phase 3b I2 (R2c-2): S2b wiring RED suite - real CLI/Stop surfaces, source AND packaged legs.
|
|
5
|
+
//
|
|
6
|
+
// Contract under test (docs/doc-workflow-reconciliation.md, S2b subsections "Workflow credit, review
|
|
7
|
+
// progression and freshness", "Exact S2b RED handoff and registry retirement", "Carry-over
|
|
8
|
+
// dispositions and non-vacuity" + A2 report section 4 strict rows + carryover.md N1-N4):
|
|
9
|
+
//
|
|
10
|
+
// 1. Positive credit path (gated). With declared test-origin capture records and the simulated
|
|
11
|
+
// qualifying live-capture artifact (the doc's test injection is the explicitly fake qualification
|
|
12
|
+
// object via dependency injection, never an environment switch or a caller trusted flag), a
|
|
13
|
+
// doc-governed typed plan earns verification credit and Stop `satisfied` only when the current
|
|
14
|
+
// chain produceDocSnapshot -> acceptDocEvents -> checkAcceptedDocEvidence credits every expected
|
|
15
|
+
// applicable MUST. Without the live-capture/qualification artifact the S1 withholding stays.
|
|
16
|
+
// 2. Review progression. A self-authored review PASS is refused (exit 2) and Stop reports
|
|
17
|
+
// step:req-review:pending; an independent host review is accepted before any verifier record; the
|
|
18
|
+
// first verification attempt stays refused and a later verification retry with valid evidence
|
|
19
|
+
// completes (P02e/P03/P05 progression consolidated in the wiring corpus).
|
|
20
|
+
// 3. A2 section 4 strict rows: task-scope substitution, omitted authored step/results, an old typed
|
|
21
|
+
// PASS gaining governed scope, F3 commit+rename freshness, F5 git-failure diagnostics, F6
|
|
22
|
+
// genuinely active Fable branch.
|
|
23
|
+
// 4. Carry-over N1-N4 dispositions: only acceptDocEvents output feeds the core (a caller-fabricated
|
|
24
|
+
// accepted object never persists credit), producer final-context failures stay snapshot-changed,
|
|
25
|
+
// candidate-side failures stay fail-closed no-credit, and mixed-invalid batches are rejected
|
|
26
|
+
// conservatively and recover on a fresh retry.
|
|
27
|
+
// 5. Controls: OFF early-return plus legacy byte-equivalence (frozen golden), the committed P06/P07u/
|
|
28
|
+
// P02d/P07-fable-staged control rows replay unchanged, both Stop surfaces exit 0, and pilot-only
|
|
29
|
+
// behavior stays gated on an actual ON + supported host decision.
|
|
30
|
+
// 6. Registry retirement mapping. Every strict assertion name says which of the ten pending-red.json
|
|
31
|
+
// registry entries it supersedes; the report table maps RED assertions to them.
|
|
32
|
+
//
|
|
33
|
+
// Declared test-origin seam (binding for GREEN): the wiring boundary threads the R2c-1 provider into
|
|
34
|
+
// the decision seam by a declared options field (options.originProvider) plus the explicitly fake
|
|
35
|
+
// qualification object `{ source: 'fake-test-fixture', faked: true, ... }`; a caller-fabricated
|
|
36
|
+
// accepted object must never be an alternative input surface (N1). Host events reach the runtime only as
|
|
37
|
+
// hookDeliver/hostRun actions in the corpus, which drive the real hook entries (F4-T1b replaced the
|
|
38
|
+
// declarative input.hostEvents). Production never reads prep-host-events and has no fixture trust switch.
|
|
39
|
+
// RETIRED assertions (F4-T1b) name the F4 case and entry that carry their live RED (see Part D).
|
|
40
|
+
//
|
|
41
|
+
// Statuses follow the mechanism-suite convention: CONTROL assertions must pass today and stay true at
|
|
42
|
+
// GREEN; RED assertions fail today for the stated missing-implementation reason and must pass at
|
|
43
|
+
// GREEN; INFRA (exit 2) means a harness crash - never qualified as RED. The suite exits 0 only when
|
|
44
|
+
// the plan matches exactly: every CONTROL passed and every RED failed for its registered reason.
|
|
45
|
+
|
|
46
|
+
const fs = require('fs');
|
|
47
|
+
const os = require('os');
|
|
48
|
+
const path = require('path');
|
|
49
|
+
const { execFileSync } = require('child_process');
|
|
50
|
+
|
|
51
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
52
|
+
const fx = require(path.join(__dirname, 'lib', 'doc-reconciliation-prep-fixtures'));
|
|
53
|
+
const WIRING_DIR = path.join(__dirname, 'fixtures', 'doc-obligations', 'reconciliation-s2b', 'wiring');
|
|
54
|
+
const PREP_CORPUS_FILE = path.join(__dirname, 'fixtures', 'doc-obligations', 'reconciliation-prep', 'cases.json');
|
|
55
|
+
const LEGS = [
|
|
56
|
+
{ id: 'source', lib: path.join(ROOT, 'hooks', 'scripts', 'lib') },
|
|
57
|
+
{ id: 'packaged', lib: path.join(ROOT, 'plugins', 'harness-everything', 'hooks', 'scripts', 'lib') },
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
const SWITCH = 'HARNESS_DOC_RECONCILIATION_PILOT';
|
|
61
|
+
|
|
62
|
+
// Cells of the committed S1/S2 control corpus replayed unchanged (read-only) as preserved controls.
|
|
63
|
+
const COMMITTED_CONTROL_IDS = ['P06', 'P07u', 'P02d', 'P07-fable-staged'];
|
|
64
|
+
|
|
65
|
+
// Modes per wiring corpus case. `off` replays without the switch, `on` replays with it exactly 1.
|
|
66
|
+
const WIRING_MODES = {
|
|
67
|
+
'W-off-legacy': ['off'],
|
|
68
|
+
'W-credit-freshness': ['on'],
|
|
69
|
+
'W-review-progression': ['on'],
|
|
70
|
+
'W-review-no-surface': ['on'],
|
|
71
|
+
'W-ctrl-nondoc-on': ['on'],
|
|
72
|
+
'W-strict-oldpass-governed': ['on'],
|
|
73
|
+
'W-strict-f3-pin': ['on'],
|
|
74
|
+
'W-strict-f5-gitdiag': ['off', 'on'],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// The plan: every replay-based assertion with its required status and, for RED, the stated
|
|
78
|
+
// missing-implementation reason and the registry entries it supersedes (packet item 6).
|
|
79
|
+
const RED_MISSING_WIRING = 'missing-implementation: the S2b wiring (host-origin provider chain through the workflow credit boundary) is not implemented; the S1 fail-closed refusal persists';
|
|
80
|
+
const PLAN = {
|
|
81
|
+
'P06': { kind: 'committed' },
|
|
82
|
+
'P07u': { kind: 'committed' },
|
|
83
|
+
'P02d': { kind: 'committed' },
|
|
84
|
+
'P07-fable-staged': { kind: 'committed' },
|
|
85
|
+
'W-off-legacy': { kind: 'wiring', byMode: {
|
|
86
|
+
off: [
|
|
87
|
+
{ id: 'w-off.route-exit', path: ['actions', 'route', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
88
|
+
{ id: 'w-off.plan-exit', path: ['actions', 'plan', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
89
|
+
{ id: 'w-off.start-exit', path: ['actions', 'start', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
90
|
+
{ id: 'w-off.doc-pass-exit', path: ['actions', 'doc-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
91
|
+
{ id: 'w-off.review-pass-exit', path: ['actions', 'review-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
92
|
+
{ id: 'w-off.verify-bind-exit', path: ['actions', 'verify-bind', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
93
|
+
{ id: 'w-off.verify-pass-exit', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
94
|
+
{ id: 'w-off.stop-exit', path: ['actions', 'stop', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
95
|
+
{ id: 'w-off.stop-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL', note: 'legacy byte-equivalence behavior pin' },
|
|
96
|
+
{ id: 'w-off.stop-unresolved', path: ['actions', 'stop', 'state', 'workflow', 'unresolved'], operator: 'equals', expected: [], status: 'CONTROL' },
|
|
97
|
+
{ id: 'w-off.stop-generic-exit', path: ['actions', 'stop-generic', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
98
|
+
{ id: 'w-off.stop-generic-satisfied', path: ['actions', 'stop-generic', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL' },
|
|
99
|
+
{ id: 'w-off.pilot-null', path: ['pilot'], operator: 'equals', expected: null, status: 'CONTROL' },
|
|
100
|
+
{ id: 'w-off.pilot-report-origin', path: ['pilotReportOrigin'], operator: 'equals', expected: 'harness', status: 'CONTROL' },
|
|
101
|
+
{ id: 'w-off.no-baseline-captured', path: ['actions', 'stop', 'state', 'workflow', 'docReconciliationBaseline'], operator: 'absent', status: 'CONTROL', note: 'OFF early-return captures nothing' },
|
|
102
|
+
],
|
|
103
|
+
} },
|
|
104
|
+
'W-credit-freshness': { kind: 'wiring', byMode: {
|
|
105
|
+
on: [
|
|
106
|
+
{ id: 'w-credit.doc-pass-exit', path: ['actions', 'doc-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL', note: 'authored doc-change advance keeps its existing allowance' },
|
|
107
|
+
{ id: 'w-credit.review-pass-exit', path: ['actions', 'review-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL', note: 'a declared independent review recipe is review-accepted' },
|
|
108
|
+
// RETIRED (F4-T1b triage): the PRD-scope verification needs conflict-check, which F4 never credits, so it cannot go
|
|
109
|
+
// GREEN in this scope. The body-only edit carries the same credit RED through real entries.
|
|
110
|
+
{ id: 'w-credit.verify-first-exit', path: ['actions', 'verify-first', 'exitCode'], operator: 'equals', expected: 0, status: 'RETIRED', supersededBy: { case: 'F4-POS-body-edit', entry: 'pos.verify-pass' }, supersedes: ['P05.on.stop-on-2-withheld'] },
|
|
111
|
+
{ id: 'w-credit.stop-on1-state', path: ['actions', 'stop-on-1', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'RETIRED', supersededBy: { case: 'F4-POS-body-edit', entry: 'pos.stop-satisfied' }, supersedes: ['P05.on.stop-on-3-withheld'] },
|
|
112
|
+
{ id: 'w-credit.stop-on1-exit', path: ['actions', 'stop-on-1', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL', note: 'both Stop surfaces exit 0 while withheld, too' },
|
|
113
|
+
{ id: 'w-credit.stop-on2-no-stale', path: ['actions', 'stop-on-2', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL', note: 'candidate mutation withholds stale credit' },
|
|
114
|
+
{ id: 'w-credit.stop-on2-exit', path: ['actions', 'stop-on-2', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
115
|
+
{ id: 'w-credit.stop-off-after-on', path: ['actions', 'stop-off', 'state', 'workflow', 'state'], operator: 'equals', expected: 'running', status: 'CONTROL', note: 'OFF stop reveals no pilot and stays withheld' },
|
|
116
|
+
{ id: 'w-credit.stop-on3-no-stale', path: ['actions', 'stop-on-3', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL', note: 'ON-OFF-ON sequence never re-credits stale content' },
|
|
117
|
+
{ id: 'w-credit.stop-on3-exit', path: ['actions', 'stop-on-3', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
118
|
+
],
|
|
119
|
+
} },
|
|
120
|
+
'W-review-no-surface': { kind: 'wiring', byMode: {
|
|
121
|
+
on: [
|
|
122
|
+
{ id: 'w-nosurface.review-retry-refused', path: ['actions', 'review-retry', 'exitCode'], operator: 'equals', expected: 2, status: 'CONTROL', note: 'F5: a reviewer SubagentStop with no Agent/Task result surface is not an approval' },
|
|
123
|
+
{ id: 'w-nosurface.stop-review-pending', path: ['actions', 'stop', 'state', 'workflow', 'unresolved'], operator: 'includes', expected: 'step:req-review:pending', status: 'CONTROL' },
|
|
124
|
+
{ id: 'w-nosurface.stop-exit', path: ['actions', 'stop', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
125
|
+
{ id: 'w-nosurface.stop-not-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL' },
|
|
126
|
+
],
|
|
127
|
+
} },
|
|
128
|
+
'W-review-progression': { kind: 'wiring', byMode: {
|
|
129
|
+
on: [
|
|
130
|
+
{ id: 'w-review.doc-pass-exit', path: ['actions', 'doc-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
131
|
+
{ id: 'w-review.review-self-exit', path: ['actions', 'review-self', 'exitCode'], operator: 'equals', expected: 2, status: 'CONTROL', retired: 'F4-T3', reason: 'missing-implementation: review-mode refusals do not exist; a self-authored review PASS is still accepted (S1 recorded gap: self-review-pass-accepted)', supersedes: ['P02e.on.review-pass-exit'] },
|
|
132
|
+
{ id: 'w-review.stop-mid-state', path: ['actions', 'stop-mid', 'state', 'workflow', 'state'], operator: 'equals', expected: 'running', status: 'CONTROL' },
|
|
133
|
+
{ id: 'w-review.stop-mid-reviews-pending', path: ['actions', 'stop-mid', 'state', 'workflow', 'unresolved'], operator: 'includes', expected: 'step:req-review:pending', status: 'CONTROL', retired: 'F4-T3', reason: 'missing-implementation: the refused review step is not left pending; Stop reports the verifier tokens instead', supersedes: ['P02e.on.stop-reports'] },
|
|
134
|
+
{ id: 'w-review.review-retry-exit', path: ['actions', 'review-retry', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL', retired: 'F4-T3', reason: 'missing-implementation: the self-authored review PASS is accepted and advances the workflow, so the independent retry is refused as not the active step; once review-self is refused (its own RED) the step stays active and the delivered independent review is accepted', note: 'a refused review keeps its step active, so the declared independent review retry is accepted before any verifier record' },
|
|
135
|
+
{ id: 'w-review.verify-bind-exit', path: ['actions', 'verify-bind', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
136
|
+
{ id: 'w-review.verify-pass-exit', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 2, status: 'CONTROL', note: 'the first verification attempt stays refused (review-only evidence lacks execution records)' },
|
|
137
|
+
// RETIRED (F4-T1b triage): verification and completion on the PRD scope need conflict-check, never credited under F4.
|
|
138
|
+
{ id: 'w-review.verify-retry-exit', path: ['actions', 'verify-retry', 'exitCode'], operator: 'equals', expected: 0, status: 'RETIRED', supersededBy: { case: 'F4-POS-body-edit', entry: 'pos.verify-pass' }, supersedes: ['P03.on.verify-retry-exit'] },
|
|
139
|
+
{ id: 'w-review.stop-state', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'RETIRED', supersededBy: { case: 'F4-POS-body-edit', entry: 'pos.stop-satisfied' }, note: 'completion follows the valid retry (same gap family as P05) without a superseded registry entry' },
|
|
140
|
+
{ id: 'w-review.stop-exit', path: ['actions', 'stop', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
141
|
+
{ id: 'w-review.stop-generic-exit', path: ['actions', 'stop-generic', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
142
|
+
],
|
|
143
|
+
} },
|
|
144
|
+
'W-ctrl-nondoc-on': { kind: 'wiring', byMode: {
|
|
145
|
+
on: [
|
|
146
|
+
{ id: 'w-nondoc.route-exit', path: ['actions', 'route', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
147
|
+
{ id: 'w-nondoc.plan-exit', path: ['actions', 'plan', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
148
|
+
{ id: 'w-nondoc.start-exit', path: ['actions', 'start', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
149
|
+
{ id: 'w-nondoc.direct-execute-exit', path: ['actions', 'direct-execute', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
150
|
+
{ id: 'w-nondoc.code-pass-exit', path: ['actions', 'code-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
151
|
+
{ id: 'w-nondoc.verify-pass-exit', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
152
|
+
{ id: 'w-nondoc.stop-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL', note: 'a complete non-document decision keeps its legacy satisfied state under ON' },
|
|
153
|
+
{ id: 'w-nondoc.stop-unresolved', path: ['actions', 'stop', 'state', 'workflow', 'unresolved'], operator: 'equals', expected: [], status: 'CONTROL' },
|
|
154
|
+
{ id: 'w-nondoc.stop-generic-satisfied', path: ['actions', 'stop-generic', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL' },
|
|
155
|
+
{ id: 'w-nondoc.stop-generic-exit', path: ['actions', 'stop-generic', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
156
|
+
{ id: 'w-nondoc.pilot-credit-false', path: ['pilot', 'pilotCredit'], operator: 'equals', expected: false, status: 'CONTROL', note: 'no fabricated verified document credit' },
|
|
157
|
+
{ id: 'w-nondoc.pilot-non-document-scope', path: ['pilot', 'diagnostics'], operator: 'includes', expected: { code: 'trusted-non-document-scope', obligationId: null }, status: 'CONTROL' },
|
|
158
|
+
],
|
|
159
|
+
} },
|
|
160
|
+
'W-strict-oldpass-governed': { kind: 'wiring', byMode: {
|
|
161
|
+
on: [
|
|
162
|
+
{ id: 'w-oldpass.stop-satisfied-state', path: ['actions', 'stop-satisfied', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL', note: 'the genuinely non-document decision reaches satisfied first' },
|
|
163
|
+
{ id: 'w-oldpass.add-governed-exit', path: ['actions', 'add-governed-adr', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
164
|
+
{ id: 'w-oldpass.stop-recheck-exit', path: ['actions', 'stop-recheck', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
165
|
+
{ id: 'w-oldpass.stop-recheck-revoked', path: ['actions', 'stop-recheck', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL', note: 'governed scope appearing mid-workflow revokes completion credit' },
|
|
166
|
+
{ id: 'w-oldpass.stop-recheck-verify-pending', path: ['actions', 'stop-recheck', 'state', 'workflow', 'unresolved'], operator: 'includes', expected: 'step:req-verify:pending', status: 'CONTROL' },
|
|
167
|
+
{ id: 'w-oldpass.pilot-credit-false', path: ['pilot', 'pilotCredit'], operator: 'equals', expected: false, status: 'CONTROL' },
|
|
168
|
+
{ id: 'w-oldpass.derive-appears', path: ['pilot', 'expectedMustIds'], operator: 'notEquals', expected: [], status: 'CONTROL', note: 'the newly governed content is derived and visible; the wiring credit for it is the W-credit case' },
|
|
169
|
+
],
|
|
170
|
+
} },
|
|
171
|
+
'W-strict-f3-pin': { kind: 'wiring', byMode: {
|
|
172
|
+
on: [
|
|
173
|
+
{ id: 'w-f3.doc-pass-exit', path: ['actions', 'doc-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
174
|
+
{ id: 'w-f3.review-pass-exit', path: ['actions', 'review-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
175
|
+
{ id: 'w-f3.verify-pass-refused', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 2, status: 'CONTROL', note: 'rename endpoints without execution evidence stay refused until the wired chain (W-credit) lands' },
|
|
176
|
+
{ id: 'w-f3.commit-mid-exit', path: ['actions', 'commit-mid', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
177
|
+
{ id: 'w-f3.stop-exit', path: ['actions', 'stop', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
178
|
+
{ id: 'w-f3.stop-not-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL' },
|
|
179
|
+
{ id: 'w-f3.derive-pinned-scope', path: ['pilot', 'expectedMustIds'], operator: 'notEquals', expected: [], status: 'CONTROL', note: 'scope keeps deriving from the pinned baseline and rename endpoints after the mid-workflow commit' },
|
|
180
|
+
],
|
|
181
|
+
} },
|
|
182
|
+
'W-strict-f5-gitdiag': { kind: 'wiring', byMode: {
|
|
183
|
+
off: [
|
|
184
|
+
{ id: 'w-f5.off.plan-exit', path: ['actions', 'plan', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
185
|
+
{ id: 'w-f5.off.verify-pass-exit', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL', note: 'legacy path completes without git reads' },
|
|
186
|
+
{ id: 'w-f5.off.pilot-null', path: ['pilot'], operator: 'equals', expected: null, status: 'CONTROL' },
|
|
187
|
+
{ id: 'w-f5.off.stop-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'equals', expected: 'satisfied', status: 'CONTROL' },
|
|
188
|
+
],
|
|
189
|
+
on: [
|
|
190
|
+
{ id: 'w-f5.on.plan-exit', path: ['actions', 'plan', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
191
|
+
{ id: 'w-f5.on.verify-pass-refused', path: ['actions', 'verify-pass', 'exitCode'], operator: 'equals', expected: 2, status: 'CONTROL', note: 'the assessment is refused, never crashed, when git itself is broken' },
|
|
192
|
+
{ id: 'w-f5.on.git-diagnosed', path: ['pilot', 'diagnostics'], operator: 'includes', expected: { code: 'baseline-unavailable', obligationId: null }, status: 'CONTROL', note: 'F5: git failure produces the baseline-unavailable diagnostic surface' },
|
|
193
|
+
{ id: 'w-f5.on.pilot-credit-false', path: ['pilot', 'pilotCredit'], operator: 'equals', expected: false, status: 'CONTROL' },
|
|
194
|
+
{ id: 'w-f5.on.stop-exit-0', path: ['actions', 'stop', 'exitCode'], operator: 'equals', expected: 0, status: 'CONTROL' },
|
|
195
|
+
{ id: 'w-f5.on.stop-not-satisfied', path: ['actions', 'stop', 'state', 'workflow', 'state'], operator: 'notEquals', expected: 'satisfied', status: 'CONTROL' },
|
|
196
|
+
],
|
|
197
|
+
} },
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Retired wiring assertions (F4-T1b triage): each names the F4 case and entry that carries its live RED.
|
|
201
|
+
const retiredEntries = [];
|
|
202
|
+
// In-process assertions retired by F4-T1b, with the F4 case and entry that carry their live RED.
|
|
203
|
+
const IN_PROCESS_SUPERSEDED = {
|
|
204
|
+
'ip-wiring.credit-granted': { case: 'F4-POS-body-edit', entry: 'pos.pilot-credit' },
|
|
205
|
+
'ip-wiring.step-accepted': { case: 'F4-POS-body-edit', entry: 'pos.verify-pass' },
|
|
206
|
+
};
|
|
207
|
+
const F4_CASES_FILE = path.join(__dirname, 'fixtures', 'doc-obligations', 'reconciliation-s2b', 'f4', 'cases.json');
|
|
208
|
+
const F4_SUITE_FILE = path.join(__dirname, 'mechanism-325-f4-projections.test.js');
|
|
209
|
+
let passCount = 0;
|
|
210
|
+
let failedCount = 0;
|
|
211
|
+
let infraCount = 0;
|
|
212
|
+
let redCount = 0;
|
|
213
|
+
const evidence = [];
|
|
214
|
+
|
|
215
|
+
function record(status, id, detail) {
|
|
216
|
+
const detailText = detail ? ` - ${detail}` : '';
|
|
217
|
+
evidence.push({ id, status, detail: detailText.trim() });
|
|
218
|
+
if (status === 'PASS') { passCount += 1; console.log(` PASS ${id}${detailText ? ` - ${detail}` : ''}`); }
|
|
219
|
+
else if (status === 'RED') { redCount += 1; console.log(` RED ${id}${detailText ? ` - ${detail}` : ''}`); }
|
|
220
|
+
else if (status === 'FAIL') { failedCount += 1; console.log(` FAIL ${id}${detailText ? ` - ${detail}` : ''}`); }
|
|
221
|
+
else { infraCount += 1; console.log(` INFRA ${id}${detailText ? ` - ${detail}` : ''}`); }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ---- Part A: replay surfaces (both legs) --------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
function replayWiringCorpus() {
|
|
227
|
+
console.log('\n== Part A1: wiring corpus replays through the real CLI/Stop entry points ==');
|
|
228
|
+
const corpus = fx.readCaseCorpus(path.join(WIRING_DIR, 'cases.json'));
|
|
229
|
+
for (const item of corpus.cases) {
|
|
230
|
+
for (const distribution of ['source', 'packaged']) {
|
|
231
|
+
const plan = PLAN[item.id];
|
|
232
|
+
for (const mode of WIRING_MODES[item.id] || ['off', 'on']) {
|
|
233
|
+
let root = null;
|
|
234
|
+
try {
|
|
235
|
+
root = fx.replayCase(item, distribution, mode === 'off' ? {} : { pilot: '1' });
|
|
236
|
+
} catch (error) {
|
|
237
|
+
record('INFRA', `${item.id}.${mode}@${distribution}`, `replay crash: ${error.message}`);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const faults = fx.infrastructureFaults(item, root, mode);
|
|
241
|
+
if (faults.length) { record('INFRA', `${item.id}.${mode}@${distribution}`, faults.map(f => `${f.actionId}: ${f.message}`).join('; ')); continue; }
|
|
242
|
+
const results = fx.evaluateAll(root, (plan.byMode[mode] || []).map(entry => ({ id: entry.id, path: entry.path, operator: entry.operator, expected: entry.expected })));
|
|
243
|
+
results.forEach((result, index) => {
|
|
244
|
+
const entry = plan.byMode[mode][index];
|
|
245
|
+
if (entry.status === 'RETIRED') {
|
|
246
|
+
// Not evaluated here: its behaviour is a live RED in the F4 corpus (see the retirement integrity check).
|
|
247
|
+
retiredEntries.push({ id: `${entry.id}@${distribution}`, supersededBy: entry.supersededBy });
|
|
248
|
+
} else if (entry.status === 'CONTROL') {
|
|
249
|
+
record(result.pass ? 'PASS' : 'FAIL', `${entry.id}@${distribution}`, result.pass ? '' : `expected ${JSON.stringify(entry.expected)} at ${entry.path.join('.')}, got ${JSON.stringify(result.actual)}`);
|
|
250
|
+
} else if (result.pass) {
|
|
251
|
+
record('FAIL', `${entry.id}@${distribution}`, `RED assertion unexpectedly passed now (expected to fail for the stated missing-implementation reason)`);
|
|
252
|
+
} else {
|
|
253
|
+
record('RED', `${entry.id}@${distribution}`, `${entry.reason || (entry.supersedes ? `supersedes ${entry.supersedes.join(', ')}` : 'wiring progression contract')}: actual ${JSON.stringify(result.actual).slice(0, 120)}`);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
partACustomChecks(item, root, distribution);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Deterministic post-checks the replay engine cannot express (pin values inside the replay only).
|
|
263
|
+
function partACustomChecks(item, root, distribution) {
|
|
264
|
+
if (item.id === 'W-strict-f3-pin') {
|
|
265
|
+
const start = root.actions.start.state.workflow.docReconciliationBaseline;
|
|
266
|
+
const stop = root.actions.stop.state.workflow.docReconciliationBaseline;
|
|
267
|
+
const pinned = Boolean(start) && Boolean(stop) && JSON.stringify(start) === JSON.stringify(stop);
|
|
268
|
+
record(pinned ? 'PASS' : 'FAIL', `w-f3.baseline-pinned@${distribution}`, pinned ? '' : `baseline at start ${JSON.stringify(start)} vs stop ${JSON.stringify(stop)}`);
|
|
269
|
+
}
|
|
270
|
+
if (item.id === 'W-strict-oldpass-governed') {
|
|
271
|
+
const requirements = (root.actions['stop-recheck'].state.obligations || {}).requirements || [];
|
|
272
|
+
const retained = requirements.some(step => step.id === 'req-code' && step.status === 'pass');
|
|
273
|
+
record(retained ? 'PASS' : 'FAIL', `w-oldpass.history-retained@${distribution}`, retained ? '' : 'the earlier non-document PASS history was not retained after the governed scope appeared');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function replayCommittedControls() {
|
|
278
|
+
console.log('\n== Part A2: committed control corpus rows replay unchanged ==');
|
|
279
|
+
const corpus = fx.readCaseCorpus(PREP_CORPUS_FILE);
|
|
280
|
+
for (const id of COMMITTED_CONTROL_IDS) {
|
|
281
|
+
const item = corpus.cases.find(k => k.id === id);
|
|
282
|
+
if (!item) { record('INFRA', `${id}`, 'committed control case missing from the prep corpus'); continue; }
|
|
283
|
+
for (const distribution of ['source', 'packaged']) {
|
|
284
|
+
for (const mode of ['off', 'on']) {
|
|
285
|
+
let root = null;
|
|
286
|
+
try {
|
|
287
|
+
root = fx.replayCase(item, distribution, mode === 'off' ? {} : { pilot: '1' });
|
|
288
|
+
} catch (error) {
|
|
289
|
+
record('INFRA', `${id}.${mode}@${distribution}`, `replay crash: ${error.message}`);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const faults = fx.infrastructureFaults(item, root, mode);
|
|
293
|
+
if (faults.length) { record('INFRA', `${id}.${mode}@${distribution}`, faults.map(f => `${f.actionId}: ${f.message}`).join('; ')); continue; }
|
|
294
|
+
const assertions = (item.expectations && item.expectations[mode]) || [];
|
|
295
|
+
const results = fx.evaluateAll(root, assertions);
|
|
296
|
+
results.forEach(result => {
|
|
297
|
+
record(result.pass ? 'PASS' : 'FAIL', `${id}.${result.id}@${distribution}`, result.pass ? '' : `expected ${JSON.stringify(result.expected)}, got ${JSON.stringify(result.actual).slice(0, 160)}`);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ---- Part B: OFF legacy byte-equivalence against the frozen golden -------------------------------
|
|
305
|
+
|
|
306
|
+
function legacyGolden() {
|
|
307
|
+
console.log('\n== Part B: OFF legacy byte-equivalence (frozen golden) ==');
|
|
308
|
+
let golden = null;
|
|
309
|
+
try {
|
|
310
|
+
golden = JSON.parse(fs.readFileSync(path.join(WIRING_DIR, 'legacy-off-golden.json'), 'utf8'));
|
|
311
|
+
} catch (error) {
|
|
312
|
+
record('INFRA', 'w-golden.load', `golden unreadable: ${error.message}`);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const corpus = fx.readCaseCorpus(path.join(WIRING_DIR, 'cases.json'));
|
|
316
|
+
const item = corpus.cases.find(k => k.id === 'W-off-legacy');
|
|
317
|
+
for (const distribution of ['source', 'packaged']) {
|
|
318
|
+
let root = null;
|
|
319
|
+
try {
|
|
320
|
+
root = fx.replayCase(item, distribution, {});
|
|
321
|
+
} catch (error) {
|
|
322
|
+
record('INFRA', `w-golden.replay@${distribution}`, `replay crash: ${error.message}`);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const actual = { workflow: fx.normalize((root.actions.stop.state || {}).workflow), obligations: fx.normalize((root.actions.stop.state || {}).obligations) };
|
|
326
|
+
const expected = golden[distribution];
|
|
327
|
+
const same = JSON.stringify(actual.workflow) === JSON.stringify(expected.workflow)
|
|
328
|
+
&& JSON.stringify(actual.obligations) === JSON.stringify(expected.obligations);
|
|
329
|
+
record(same ? 'PASS' : 'FAIL', `w-golden.byte-equivalence@${distribution}`, same ? '' : 'the OFF replay diverged from the frozen legacy golden');
|
|
330
|
+
record(root.actions['stop-generic'].exitCode === golden[distribution].stopGeneric.exitCode ? 'PASS' : 'FAIL', `w-golden.stop-generic-exit@${distribution}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ---- Part C: in-process chain and wiring seam (per leg) ------------------------------------------
|
|
335
|
+
|
|
336
|
+
function clearLegCache(lib) {
|
|
337
|
+
const cached = new Map();
|
|
338
|
+
for (const key of Object.keys(require.cache)) {
|
|
339
|
+
if (key === lib || key.startsWith(lib + path.sep)) { cached.set(key, require.cache[key]); delete require.cache[key]; }
|
|
340
|
+
}
|
|
341
|
+
return cached;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function restoreLegCache(lib, cached) {
|
|
345
|
+
for (const key of Object.keys(require.cache)) {
|
|
346
|
+
if (key === lib || key.startsWith(lib + path.sep)) delete require.cache[key];
|
|
347
|
+
}
|
|
348
|
+
for (const [key, value] of cached) require.cache[key] = value;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const GOVERNED_ADR_CONFIG = JSON.stringify({ governed: [{ path: 'docs/adr/**', role: 'adr' }], domains: ['GRPH'] }, null, 2) + '\n';
|
|
352
|
+
const ADR_BASE = '# GRPH-001 Checkout retry\n\nStatus: accepted\n\nCheckout MUST retry once.\n';
|
|
353
|
+
const ADR_CANDIDATE = '# GRPH-001 Checkout retry\n\nStatus: accepted\n\nCheckout MUST retry twice.\n';
|
|
354
|
+
const REQUIREMENTS = JSON.stringify([
|
|
355
|
+
{ id: 'req-docs', stepType: 'doc-change', summary: 'Update the ADR text', acceptance: 'normative ADR text is reviewed' },
|
|
356
|
+
{ id: 'req-verify', stepType: 'verification', summary: 'Verify the ADR change', acceptance: 'objective doc checks are recorded' },
|
|
357
|
+
]);
|
|
358
|
+
|
|
359
|
+
function git(cwd, args) {
|
|
360
|
+
const env = { ...process.env };
|
|
361
|
+
for (const key of Object.keys(env)) if (key.startsWith('GIT_')) delete env[key];
|
|
362
|
+
env.GIT_AUTHOR_DATE = '2026-04-01T12:00:00Z';
|
|
363
|
+
env.GIT_COMMITTER_DATE = '2026-04-01T12:00:00Z';
|
|
364
|
+
return execFileSync('git', ['-C', cwd, ...args], { env, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function writeFile(dir, relative, content) {
|
|
368
|
+
const target = path.join(dir, relative);
|
|
369
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
370
|
+
fs.writeFileSync(target, content, 'utf8');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Builds one in-process scenario workspace: governed ADR diff, provisioned contract, pinned baseline.
|
|
374
|
+
function seedInProcessScenario(leg, dir, modules) {
|
|
375
|
+
const { obligations, pilot } = modules;
|
|
376
|
+
const plan = { strategySelection: 'selected', tier: 'tier2', strategy: 'iterative-single' };
|
|
377
|
+
const sessionDir = path.join(dir, 'session');
|
|
378
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
379
|
+
writeFile(dir, '.agents/harness-everything/project-docs.json', GOVERNED_ADR_CONFIG);
|
|
380
|
+
writeFile(dir, 'docs/adr/GRPH-001.md', ADR_BASE);
|
|
381
|
+
git(dir, ['init', '-q']);
|
|
382
|
+
git(dir, ['add', '-A']);
|
|
383
|
+
git(dir, ['-c', 'user.name=harness-wiring', '-c', 'user.email=harness-wiring@example.com', '-c', 'commit.gpgsign=false', 'commit', '-q', '--no-verify', '-m', 'baseline']);
|
|
384
|
+
writeFile(dir, 'docs/adr/GRPH-001.md', ADR_CANDIDATE);
|
|
385
|
+
const context = {
|
|
386
|
+
sessionId: `s2b-wiring-${leg.id}`,
|
|
387
|
+
sessionDir,
|
|
388
|
+
root: dir,
|
|
389
|
+
workflow: {
|
|
390
|
+
workflowId: `wf-s2b-wiring-${leg.id}`,
|
|
391
|
+
revision: 1,
|
|
392
|
+
state: 'pending',
|
|
393
|
+
strategy: 'iterative-single',
|
|
394
|
+
workflowPlan: plan,
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
obligations.initializePlanningContract(context, plan);
|
|
398
|
+
obligations.recordPlanning(context, REQUIREMENTS, plan, 'iterative-single', 'two dependent requirements fit a bounded documentation loop');
|
|
399
|
+
obligations.materializeExecutionObligations(context, plan);
|
|
400
|
+
const loaded = obligations.loadObligationSet(context, plan);
|
|
401
|
+
if (!loaded.set) throw new Error(`[${leg.id}] obligation contract seeding failed: ${loaded.error}`);
|
|
402
|
+
pilot.captureBaseline(context);
|
|
403
|
+
return { context, plan, set: loaded.set };
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function countingProxy(inner) {
|
|
407
|
+
return {
|
|
408
|
+
contextCalls: 0,
|
|
409
|
+
eventCalls: 0,
|
|
410
|
+
resolveContext(request) { this.contextCalls += 1; return inner.resolveContext(request); },
|
|
411
|
+
resolveEvent(request) { this.eventCalls += 1; return inner.resolveEvent(request); },
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function buildProvider(leg, modules, captureOverrides = {}) {
|
|
416
|
+
const providerModule = modules.provider;
|
|
417
|
+
return providerModule.createClaudeOriginProvider({
|
|
418
|
+
hostId: 'claude-code',
|
|
419
|
+
sessionId: `s2b-wiring-${leg.id}`,
|
|
420
|
+
// The workflow-start pin is supplied by the caller at construction, as S2a contextFor requires.
|
|
421
|
+
...(captureOverrides.baseline ? { baseline: captureOverrides.baseline } : {}),
|
|
422
|
+
workspaceRoot: captureOverrides.workspaceRoot || '/tmp/nothing',
|
|
423
|
+
taskId: `task-s2b-wiring-${leg.id}`,
|
|
424
|
+
workflowId: `wf-s2b-wiring-${leg.id}`,
|
|
425
|
+
workflowRevision: 1,
|
|
426
|
+
principals: { author: `s2b-wiring-${leg.id}`, executors: [] },
|
|
427
|
+
captures: captureOverrides.captures || [],
|
|
428
|
+
// The doc's ONLY test-injection mechanism: the explicitly fake qualification via DI.
|
|
429
|
+
qualification: { source: 'fake-test-fixture', faked: true, ref: `wiring-${leg.id}`, toolUseIdPopulated: true, agentIdPopulated: true },
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function inProcessPart() {
|
|
434
|
+
console.log('\n== Part C: in-process chain and wiring seam (per leg) ==');
|
|
435
|
+
const pilotSwitch = process.env[SWITCH];
|
|
436
|
+
for (const leg of LEGS) {
|
|
437
|
+
// git reports the realpath of the toplevel (macOS: /private/var, not /var), and the producer compares against the
|
|
438
|
+
// baseline root it is given, so the fixture root is canonicalised the same way the runtime records it (retro 3.4).
|
|
439
|
+
const dir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), `harness-s2bwiring-${leg.id}-`)));
|
|
440
|
+
const cache = clearLegCache(leg.lib);
|
|
441
|
+
try {
|
|
442
|
+
process.env[SWITCH] = '1';
|
|
443
|
+
const modules = {
|
|
444
|
+
obligations: require(path.join(leg.lib, 'workflow-obligations.js')),
|
|
445
|
+
pilot: require(path.join(leg.lib, 'doc-reconciliation-pilot.js')),
|
|
446
|
+
producer: require(path.join(leg.lib, 'doc-reconciliation-producer.js')),
|
|
447
|
+
events: require(path.join(leg.lib, 'doc-reconciliation-events.js')),
|
|
448
|
+
core: require(path.join(leg.lib, 'doc-reconciliation-core.js')),
|
|
449
|
+
provider: require(path.join(leg.lib, 'doc-reconciliation-provider.js')),
|
|
450
|
+
};
|
|
451
|
+
const seeded = seedInProcessScenario(leg, dir, modules);
|
|
452
|
+
// -- Real Claude provider (faked qualification) drives the producer chain now already (S2a+provider
|
|
453
|
+
// modules are real); the wiring itself is the missing piece.
|
|
454
|
+
const pin = { root: dir, commit: git(dir, ['rev-parse', 'HEAD']).trim() };
|
|
455
|
+
const qualified = buildProvider(leg, modules, { workspaceRoot: dir, baseline: pin });
|
|
456
|
+
let produceState = null;
|
|
457
|
+
let produceDiag = '';
|
|
458
|
+
try {
|
|
459
|
+
const produced = modules.producer.produceDocSnapshot({
|
|
460
|
+
workspaceRoot: dir,
|
|
461
|
+
baseline: { root: dir, commit: git(dir, ['rev-parse', 'HEAD']).trim() },
|
|
462
|
+
workflow: { workflowId: seeded.context.workflow.workflowId, workflowRevision: 1, sessionId: seeded.context.sessionId },
|
|
463
|
+
task: { taskId: `task-s2b-wiring-${leg.id}`, requirements: JSON.parse(REQUIREMENTS) },
|
|
464
|
+
scope: { prdRoot: 'docs/prd/' },
|
|
465
|
+
activeHost: 'claude-code',
|
|
466
|
+
}, { originProvider: qualified });
|
|
467
|
+
produceState = produced.state;
|
|
468
|
+
produceDiag = (produced.diagnostics || []).map(d => d.code).join(',');
|
|
469
|
+
} catch (error) {
|
|
470
|
+
record('INFRA', `ip-wiring.produce@${leg.id}`, error.message);
|
|
471
|
+
}
|
|
472
|
+
// Strict GREEN (F4-T2): the provider binds the caller-supplied workflow-start pin, so the S2a chain is ready.
|
|
473
|
+
const producedReady = produceState === 'ready';
|
|
474
|
+
record(producedReady ? 'PASS' : 'FAIL', `ip-wiring.produce-ready@${leg.id}`, producedReady ? '' : `produceDocSnapshot state ${produceState || 'none'}${produceDiag ? `, ${produceDiag}` : ''}; the provider must bind the caller-supplied pin`);
|
|
475
|
+
// -- Wiring RED: the decision boundary must consume the declared DI provider chain.
|
|
476
|
+
const proxy = countingProxy(qualified);
|
|
477
|
+
let result = null;
|
|
478
|
+
try {
|
|
479
|
+
result = modules.pilot.assess(seeded.context, seeded.set, { originProvider: proxy });
|
|
480
|
+
} catch (error) {
|
|
481
|
+
record('INFRA', `ip-wiring.assess@${leg.id}`, `assess threw: ${error.message}`);
|
|
482
|
+
}
|
|
483
|
+
result = result || {};
|
|
484
|
+
record(proxy.contextCalls >= 1 ? 'PASS' : 'RED', `ip-wiring.provider-chain-invoked@${leg.id}`, proxy.contextCalls >= 1 ? '' : 'the credit boundary never invoked the declared origin provider (assess ignores the wiring seam)');
|
|
485
|
+
const expectedCredit = !result.withhold;
|
|
486
|
+
// RETIRED (F4-T1b): this in-process chain delivers no host events, and its ADR edit is outside the first positive scope.
|
|
487
|
+
if (expectedCredit) record('FAIL', `ip-wiring.credit-granted@${leg.id}`, 'RED assertion unexpectedly passed now');
|
|
488
|
+
else retiredEntries.push({ id: `ip-wiring.credit-granted@${leg.id}`, supersededBy: IN_PROCESS_SUPERSEDED['ip-wiring.credit-granted'] });
|
|
489
|
+
// -- N1 carry-over: a caller-fabricated accepted object must never become credit at the boundary.
|
|
490
|
+
const proxyN1 = countingProxy(qualified);
|
|
491
|
+
let resultN1 = null;
|
|
492
|
+
try {
|
|
493
|
+
resultN1 = modules.pilot.assess(seeded.context, seeded.set, { originProvider: proxyN1, injectedAccepted: { state: 'resolved', acceptedIndex: { forged: { artifactDigests: {} } }, diagnostics: [], rejected: [], checkerInputs: {} } });
|
|
494
|
+
} catch (error) {
|
|
495
|
+
record('INFRA', `ip-n1.assess@${leg.id}`, `assess threw: ${error.message}`);
|
|
496
|
+
}
|
|
497
|
+
resultN1 = resultN1 || {};
|
|
498
|
+
record(resultN1.withhold ? 'PASS' : 'FAIL', `ip-n1.forged-accepted-not-credited@${leg.id}`, resultN1.withhold ? '' : 'a caller-fabricated accepted object leaked past the boundary');
|
|
499
|
+
// -- Wiring RED: the step boundary consumes the same declared seam. The authored step and the
|
|
500
|
+
// verification binding are resolved first, so the refusal is exactly the pilot verification
|
|
501
|
+
// refusal that the wired chain must replace.
|
|
502
|
+
try {
|
|
503
|
+
modules.obligations.updateStep(seeded.context, 'req-docs', 'pass', { evidence: 'ADR text updated' });
|
|
504
|
+
} catch (error) {
|
|
505
|
+
record('INFRA', `ip-wiring.authored-pass@${leg.id}`, error.message);
|
|
506
|
+
}
|
|
507
|
+
try {
|
|
508
|
+
modules.obligations.updateBinding(seeded.context, 'req-verify', 'verification-loop', 'loaded', { evidence: 'verification loop skill located' });
|
|
509
|
+
} catch (error) {
|
|
510
|
+
record('INFRA', `ip-wiring.binding@${leg.id}`, error.message);
|
|
511
|
+
}
|
|
512
|
+
let caught = null;
|
|
513
|
+
try {
|
|
514
|
+
modules.obligations.updateStep(seeded.context, 'req-verify', 'pass', { evidence: 'objective doc checks with current host-origin reconciliation', originProvider: proxy });
|
|
515
|
+
} catch (error) {
|
|
516
|
+
caught = error;
|
|
517
|
+
}
|
|
518
|
+
// RETIRED (F4-T1b): with no delivered evidence this step can only be refused, so it is covered by the F4 live RED.
|
|
519
|
+
if (caught) retiredEntries.push({ id: `ip-wiring.step-accepted@${leg.id}`, supersededBy: IN_PROCESS_SUPERSEDED['ip-wiring.step-accepted'] });
|
|
520
|
+
else record('FAIL', `ip-wiring.step-accepted@${leg.id}`, 'RED assertion unexpectedly passed now');
|
|
521
|
+
inProcessChainProbes(leg, modules);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
record('INFRA', `ip-scenario@${leg.id}`, error.message);
|
|
524
|
+
} finally {
|
|
525
|
+
if (pilotSwitch === undefined) delete process.env[SWITCH]; else process.env[SWITCH] = pilotSwitch;
|
|
526
|
+
restoreLegCache(leg.lib, cache);
|
|
527
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// S2a-preserved chain semantics over the real provider/adapter/core modules (carry-over N2/N3/N4 and
|
|
533
|
+
// the A2 strict rows that the wiring must not weaken). Each keeps its current behavior at RED and at
|
|
534
|
+
// GREEN; GREEN only changes who feeds them.
|
|
535
|
+
function inProcessChainProbes(leg, modules) {
|
|
536
|
+
const H = require(path.join(__dirname, 'fixtures', 'doc-obligations', 'reconciliation-s2a', 'harness.js'));
|
|
537
|
+
const repo = H.makeRepo(H.vectorFiles('normative').base);
|
|
538
|
+
repo.root = fs.realpathSync(repo.root); // same canonical root the runtime records (see inProcessPart)
|
|
539
|
+
try {
|
|
540
|
+
H.writeFiles(repo.root, H.vectorFiles('normative').candidate);
|
|
541
|
+
const vec = H.VECTORS.vectors.normative;
|
|
542
|
+
// The fake origin binds the workflow-start pin, as the S2a producer suite does (contextFor requires it).
|
|
543
|
+
const origin = new H.FakeOrigin({ context: H.fakeContext({}, repo) });
|
|
544
|
+
const produced = modules.producer.produceDocSnapshot(H.producerInput(repo), { originProvider: origin });
|
|
545
|
+
if (!produced.snapshot) { record('INFRA', `ip-chain.produce@${leg.id}`, H.codesOf(produced).join(',')); return; }
|
|
546
|
+
const snapshot = produced.snapshot;
|
|
547
|
+
record('PASS', `ip-chain.produce-ready@${leg.id}`, H.codesOf(produced).join(','));
|
|
548
|
+
const events = H.buildEvents(snapshot, repo, vec);
|
|
549
|
+
for (const [ref, event] of Object.entries(events)) origin.issueEvent(ref, event);
|
|
550
|
+
const refs = Object.keys(events);
|
|
551
|
+
const accepted = modules.events.acceptDocEvents({ snapshot, eventRefs: refs }, { originProvider: origin });
|
|
552
|
+
record(accepted.state === 'ready' && Object.keys(accepted.acceptedIndex).length === refs.length ? 'PASS' : 'FAIL', `ip-chain.accepted-full@${leg.id}`, `state ${accepted.state}, index ${Object.keys(accepted.acceptedIndex).length}/${refs.length}`);
|
|
553
|
+
const decision = modules.core.checkAcceptedDocEvidence({ snapshot, accepted, mode: 'verification' });
|
|
554
|
+
record(decision.eligible === true ? 'PASS' : 'FAIL', `ip-chain.credit-full@${leg.id}`, H.codesOf(decision).join(',') || 'eligible');
|
|
555
|
+
const subsetRefs = refs.filter(ref => events[ref].kind === 'review').concat(refs.filter(ref => events[ref].kind === 'execution').slice(0, 1));
|
|
556
|
+
const acceptedSubset = modules.events.acceptDocEvents({ snapshot, eventRefs: subsetRefs }, { originProvider: origin });
|
|
557
|
+
const decisionSubset = modules.core.checkAcceptedDocEvidence({ snapshot, accepted: acceptedSubset, mode: 'verification' });
|
|
558
|
+
record(decisionSubset.eligible === false ? 'PASS' : 'FAIL', `ip-chain.subset-not-credited@${leg.id}`, H.codesOf(decisionSubset).join(','));
|
|
559
|
+
// N4: a mixed batch is rejected conservatively and a fresh retry recovers.
|
|
560
|
+
const mixedEvents = H.buildEvents(snapshot, repo, vec);
|
|
561
|
+
const mixedRefs = refs.filter(ref => events[ref].kind === 'review');
|
|
562
|
+
for (const [ref, event] of Object.entries(mixedEvents)) {
|
|
563
|
+
if (event.kind !== 'execution') continue;
|
|
564
|
+
event.artifactDigests = Object.fromEntries(Object.entries(event.artifactDigests).map(([p]) => [p, 'sha256:' + '0'.repeat(64)]));
|
|
565
|
+
origin.issueEvent(`bad-${ref}`, event);
|
|
566
|
+
mixedRefs.push(`bad-${ref}`);
|
|
567
|
+
}
|
|
568
|
+
const acceptedMixed = modules.events.acceptDocEvents({ snapshot, eventRefs: mixedRefs }, { originProvider: origin });
|
|
569
|
+
const mixedRejected = (acceptedMixed.rejected || []).length >= 1 && acceptedMixed.state === 'unresolved';
|
|
570
|
+
record(mixedRejected ? 'PASS' : 'FAIL', `ip-chain.mixed-batch-rejected@${leg.id}`, `state ${acceptedMixed.state}, rejected ${acceptedMixed.rejected.length}`);
|
|
571
|
+
const acceptedRetry = modules.events.acceptDocEvents({ snapshot, eventRefs: refs }, { originProvider: origin });
|
|
572
|
+
record(acceptedRetry.state === 'ready' && Object.keys(acceptedRetry.acceptedIndex).length === refs.length ? 'PASS' : 'FAIL', `ip-chain.fresh-retry-recovers@${leg.id}`);
|
|
573
|
+
// N2: a final-context provider outage stays snapshot-changed.
|
|
574
|
+
let calls = 0;
|
|
575
|
+
const flaky = new H.FakeOrigin({ context: H.fakeContext({}, repo) });
|
|
576
|
+
flaky.resolveContext = function () {
|
|
577
|
+
calls += 1;
|
|
578
|
+
if (calls >= 2) throw new Error('transient final-context outage');
|
|
579
|
+
return { status: 'accepted', context: H.clone(H.fakeContext({}, repo)), originRef: 'fake-origin:context' };
|
|
580
|
+
};
|
|
581
|
+
const producedFlaky = modules.producer.produceDocSnapshot(H.producerInput(repo), { originProvider: flaky });
|
|
582
|
+
record(producedFlaky.state === 'unavailable' && H.codesOf(producedFlaky).includes('snapshot-changed') ? 'PASS' : 'FAIL', `ip-chain.final-outage-labeled@${leg.id}`, H.codesOf(producedFlaky).join(','));
|
|
583
|
+
// N3: a candidate-side git attribute failure stays fail-closed with no credit.
|
|
584
|
+
const guardedRepo = { root: path.join(fs.realpathSync(os.tmpdir()), `harness-s2battr-${leg.id}`), commit: null };
|
|
585
|
+
fs.rmSync(guardedRepo.root, { recursive: true, force: true });
|
|
586
|
+
H.writeFiles(guardedRepo.root, Object.assign({ '.gitattributes': '*.bin filter=metal\n' }, H.vectorFiles('normative').base));
|
|
587
|
+
try {
|
|
588
|
+
git(guardedRepo.root, ['init', '-q']);
|
|
589
|
+
git(guardedRepo.root, ['add', '-A']);
|
|
590
|
+
git(guardedRepo.root, ['-c', 'user.name=harness-wiring', '-c', 'user.email=harness-wiring@example.com', '-c', 'commit.gpgsign=false', 'commit', '-q', '--no-verify', '-m', 'baseline']);
|
|
591
|
+
guardedRepo.commit = git(guardedRepo.root, ['rev-parse', 'HEAD']).trim();
|
|
592
|
+
H.writeFiles(guardedRepo.root, Object.assign({ '.gitattributes': '*.bin filter=metal\n' }, H.vectorFiles('normative').candidate, { 'assets/model.bin': 'BINARY-PLACEHOLDER' }));
|
|
593
|
+
const producedGuarded = modules.producer.produceDocSnapshot(H.producerInput({ root: guardedRepo.root, commit: guardedRepo.commit }), { originProvider: origin });
|
|
594
|
+
record(producedGuarded.state === 'unavailable' ? 'PASS' : 'FAIL', `ip-chain.candidate-failure-fail-closed@${leg.id}`, H.codesOf(producedGuarded).join(',') || 'unavailable');
|
|
595
|
+
} finally {
|
|
596
|
+
H.removeRepo(guardedRepo.root);
|
|
597
|
+
}
|
|
598
|
+
} finally {
|
|
599
|
+
H.removeRepo(repo.root);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// ---- Report -------------------------------------------------------------------------------------
|
|
604
|
+
|
|
605
|
+
// Every retired assertion must name an F4 case that exists and an entry the F4 suite really defines (CONTROL), so a
|
|
606
|
+
// retirement can never point at nothing.
|
|
607
|
+
function retirementIntegrity() {
|
|
608
|
+
console.log('\n== Part D: retired wiring assertions map to live F4 REDs ==');
|
|
609
|
+
const f4Ids = new Set(fx.readCaseCorpus(F4_CASES_FILE).cases.map(item => item.id));
|
|
610
|
+
const f4Source = fs.readFileSync(F4_SUITE_FILE, 'utf8');
|
|
611
|
+
const retired = [];
|
|
612
|
+
for (const entry of Object.values(PLAN)) {
|
|
613
|
+
for (const list of Object.values(entry.byMode || {})) {
|
|
614
|
+
for (const assertion of list) if (assertion.status === 'RETIRED') retired.push({ id: assertion.id, supersededBy: assertion.supersededBy });
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
for (const [id, supersededBy] of Object.entries(IN_PROCESS_SUPERSEDED)) retired.push({ id, supersededBy });
|
|
618
|
+
for (const item of retired) {
|
|
619
|
+
const { case: caseId, entry } = item.supersededBy;
|
|
620
|
+
const ok = f4Ids.has(caseId) && f4Source.includes(`id: '${entry}'`);
|
|
621
|
+
record(ok ? 'PASS' : 'FAIL', `retired.${item.id}->${caseId}:${entry}`, ok ? '' : 'superseding F4 case or entry is missing');
|
|
622
|
+
}
|
|
623
|
+
console.log(`retired assertions (superseded, each mapped to a live F4 RED): ${retired.length}`);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function main() {
|
|
627
|
+
const started = Date.now();
|
|
628
|
+
replayCommittedControls();
|
|
629
|
+
replayWiringCorpus();
|
|
630
|
+
legacyGolden();
|
|
631
|
+
inProcessPart();
|
|
632
|
+
retirementIntegrity();
|
|
633
|
+
const duration = ((Date.now() - started) / 1000).toFixed(1);
|
|
634
|
+
console.log('\n== S2b wiring RED evidence ==');
|
|
635
|
+
console.log(`controls passed: ${passCount}`);
|
|
636
|
+
console.log(`RED assertions confirmed: ${redCount}`);
|
|
637
|
+
console.log(`unexpected failures: ${failedCount}`);
|
|
638
|
+
console.log(`infrastructure faults: ${infraCount}`);
|
|
639
|
+
console.log(`duration: ${duration}s`);
|
|
640
|
+
const supersedes = [];
|
|
641
|
+
for (const entry of Object.values(PLAN)) {
|
|
642
|
+
for (const list of Object.values(entry.byMode || {})) {
|
|
643
|
+
for (const assertion of list) {
|
|
644
|
+
if (assertion.supersedes) supersedes.push({ id: assertion.id, supersedes: assertion.supersedes });
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
for (const item of supersedes) console.log(`supersedes: ${item.id} -> ${item.supersedes.join(', ')}`);
|
|
649
|
+
// Strict by default: a remaining RED is a failure, so the discovered suite cannot pass while the
|
|
650
|
+
// wiring is unimplemented. `--expect-red` qualifies the RED plan instead (RED stage only).
|
|
651
|
+
const expectRed = process.argv.includes('--expect-red');
|
|
652
|
+
if (!expectRed) {
|
|
653
|
+
if (infraCount === 0 && failedCount === 0 && redCount === 0) {
|
|
654
|
+
console.log('\nSTATUS: GREEN (all assertions passed)');
|
|
655
|
+
return 0;
|
|
656
|
+
}
|
|
657
|
+
console.log(`STATUS: NOT-GREEN (red ${redCount}, unexpected ${failedCount}, infra ${infraCount})`);
|
|
658
|
+
return 1;
|
|
659
|
+
}
|
|
660
|
+
if (infraCount === 0 && failedCount === 0) {
|
|
661
|
+
console.log('\nSTATUS: RED-PLAN-MATCHED (all controls passed, all RED assertions failed for their stated missing-implementation reasons)');
|
|
662
|
+
return 0;
|
|
663
|
+
}
|
|
664
|
+
console.log('STATUS: RED-PLAN-MISMATCH');
|
|
665
|
+
return 1;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
process.exitCode = main();
|