harness-everything 0.37.0 → 0.38.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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +16 -0
- package/ci/fixtures/doc-obligations/reconciliation-prep/cases.json +70 -11
- package/ci/fixtures/doc-obligations/reconciliation-prep/pending-red.json +24 -556
- package/ci/fixtures/doc-obligations/reconciliation-s1/cases.json +6842 -0
- package/ci/fixtures/doc-obligations/reconciliation-s1/fail-session-writes.js +116 -0
- package/ci/lib/doc-reconciliation-prep-fixtures.js +116 -10
- package/ci/mechanism-325-3b-preparation.test.js +8 -8
- package/ci/mechanism-325-3b-s1-review.test.js +831 -0
- package/ci/mechanism-325-3b-s1.test.js +188 -0
- package/ci/prep/doc-reconciliation-red.js +2 -1
- package/docs/doc-workflow-reconciliation.md +217 -26
- package/docs/document-lifecycle.md +4 -4
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/scripts/doc-lifecycle.js +1 -1
- package/hooks/scripts/lib/doc-reconciliation-pilot.js +152 -0
- package/hooks/scripts/lib/workflow-obligations.js +44 -0
- package/hooks/scripts/workflow-disposition.js +2 -0
- package/hooks/scripts/workflow-stop-gate.js +24 -1
- 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-pilot.js +152 -0
- package/plugins/harness-everything/hooks/scripts/lib/workflow-obligations.js +44 -0
- package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +2 -0
- package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +24 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/scripts/doc-lifecycle.js +1 -1
- package/sbom.cdx.json +7 -7
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// #325 Phase 3b S1 strict suite: switch, trusted scope and fail-closed no-credit gate (RED).
|
|
5
|
+
//
|
|
6
|
+
// Every assertion in reconciliation-s1/cases.json is a strict S1 contract assertion, run against the real CLI, hook and
|
|
7
|
+
// Stop entry points on both legs (source and packaged) and both modes (OFF and ON with the switch set to exactly "1").
|
|
8
|
+
// Each assertion is tagged s1Kind:
|
|
9
|
+
// retired one of the 26 S1 retire IDs in docs/doc-workflow-reconciliation.md; expected to FAIL on the current base
|
|
10
|
+
// control behaviour that must PASS now and after GREEN (P06, P07u, P02d, OFF legacy, Stop exit 0, switch values)
|
|
11
|
+
// additional a named S1 contract case beyond the retire table (governed scope, direct aggregate, OFF-seeded, ON->OFF->ON)
|
|
12
|
+
// This suite grants no pilot credit and never consults the prep registry: a FAIL here is a real gap, not a qualified one.
|
|
13
|
+
// Infrastructure faults (spawn error, deadline, output bound, exit outside the declared policy, malformed output) are
|
|
14
|
+
// reported as INFRA and are distinct from assertion FAIL. Exit 1 means at least one assertion FAILED; exit 2 means
|
|
15
|
+
// infrastructure. The suite cannot pass until GREEN lands; that is the RED contract.
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fx = require('./lib/doc-reconciliation-prep-fixtures');
|
|
19
|
+
|
|
20
|
+
const CORPUS_FILE = path.join(__dirname, 'fixtures', 'doc-obligations', 'reconciliation-s1', 'cases.json');
|
|
21
|
+
const corpus = fx.readCaseCorpus(CORPUS_FILE);
|
|
22
|
+
const LEGS = ['source', 'packaged'];
|
|
23
|
+
const MODES = ['off', 'on'];
|
|
24
|
+
const ALLOWED_OPERATORS = new Set(['equals', 'notEquals', 'includes', 'absent']);
|
|
25
|
+
const S1_KINDS = new Set(['retired', 'control', 'additional']);
|
|
26
|
+
const REQUIRED_CASE_FIELDS = ['id', 'family', 'description', 'topology', 'requirements', 'input', 'actions', 'expectations'];
|
|
27
|
+
|
|
28
|
+
// The doc's "S1 retire" table: 26 IDs × 2 legs, by case. Any drift between this list and the corpus is a failure.
|
|
29
|
+
const RETIRED_BY_CASE = {
|
|
30
|
+
P01: ['verify-exit-refused', 'verify-obligation-pending', 'stop-unsatisfied', 'stop-reports-verification'],
|
|
31
|
+
P04: ['direct-execute-refused', 'direct-verify-refused', 'verify-obligation-pending'],
|
|
32
|
+
P02a: ['verify-pass-exit', 'stop-state', 'stop-reports'],
|
|
33
|
+
P02b: ['verify-pass-exit', 'stop-state', 'stop-reports'],
|
|
34
|
+
P02c: ['verify-pass-exit', 'stop-state', 'stop-reports'],
|
|
35
|
+
P02g: ['verify-pass-exit', 'stop-state', 'stop-reports'],
|
|
36
|
+
P02f: ['verify-pass-exit', 'stop-state', 'stop-reports'],
|
|
37
|
+
P03: ['verify-pass-exit'],
|
|
38
|
+
'P07-fable-staged': ['pilot-status-unavailable'],
|
|
39
|
+
'P07-fable-parallel': ['pilot-status-unavailable'],
|
|
40
|
+
'P07-fable-multi-agent-workspace': ['pilot-status-unavailable']
|
|
41
|
+
};
|
|
42
|
+
const RETIRED_COUNT = Object.values(RETIRED_BY_CASE).reduce((total, ids) => total + ids.length, 0);
|
|
43
|
+
|
|
44
|
+
let passed = 0;
|
|
45
|
+
let failed = 0;
|
|
46
|
+
let infra = 0;
|
|
47
|
+
const failures = [];
|
|
48
|
+
const infrastructure = [];
|
|
49
|
+
|
|
50
|
+
const show = value => (value === undefined ? 'undefined' : JSON.stringify(value));
|
|
51
|
+
|
|
52
|
+
// The reason a FAIL names, in the terms the doc uses: "exit 0 where 2 desired", "state satisfied where running desired".
|
|
53
|
+
function reasonFor(assertion, actual) {
|
|
54
|
+
const last = assertion.path[assertion.path.length - 1];
|
|
55
|
+
const label = ({ exitCode: 'exit', state: 'state', unresolved: 'unresolved', pilotStatus: 'pilot status',
|
|
56
|
+
pilotReportOrigin: 'pilot origin', pilot: 'pilot' })[last]
|
|
57
|
+
|| (assertion.path.includes('obligations') && last === 'status' ? 'obligation status' : null)
|
|
58
|
+
|| (assertion.path.includes('requirements') && last === 'status' ? 'step status' : null)
|
|
59
|
+
|| assertion.path.slice(-2).join('.');
|
|
60
|
+
const absent = actual && typeof actual === 'object' && actual.kind === 'absent';
|
|
61
|
+
if (assertion.operator === 'includes') {
|
|
62
|
+
return absent ? `${label} absent where ${show(assertion.expected)} desired`
|
|
63
|
+
: `${label} ${show(actual)} lacks ${show(assertion.expected)}`;
|
|
64
|
+
}
|
|
65
|
+
if (assertion.operator === 'notEquals') return `${label} ${show(actual)} where a value other than ${show(assertion.expected)} desired`;
|
|
66
|
+
if (assertion.operator === 'absent') return `${label} present where absent desired`;
|
|
67
|
+
if (absent) return `${label} absent where ${show(assertion.expected)} desired`;
|
|
68
|
+
return `${label} ${show(actual)} where ${show(assertion.expected)} desired`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function record(status, id, detail) {
|
|
72
|
+
if (status === 'PASS') passed += 1;
|
|
73
|
+
else if (status === 'FAIL') { failed += 1; failures.push(id); }
|
|
74
|
+
else { infra += 1; infrastructure.push(id); }
|
|
75
|
+
console.log(` ${status} ${id}${detail ? ` — ${detail}` : ''}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Parity between the two legs for one replay, mirroring the prep runner's comparable() view.
|
|
79
|
+
function comparable(root) {
|
|
80
|
+
const entries = Object.entries(root.actions).map(([id, action]) => [id, {
|
|
81
|
+
exitCode: action.exitCode,
|
|
82
|
+
signal: action.signal,
|
|
83
|
+
stdout: action.json === null ? action.stdout : null,
|
|
84
|
+
json: action.json,
|
|
85
|
+
stderr: action.stderr,
|
|
86
|
+
state: action.state
|
|
87
|
+
}]);
|
|
88
|
+
return fx.normalize(Object.fromEntries([...entries, ['$final', root.state]]));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log('=== #325 3b S1: strict switch, trusted scope and fail-closed no-credit suite (RED) ===');
|
|
92
|
+
|
|
93
|
+
// ---- Inventory: the corpus is well formed and marks exactly the doc's retire table -----------------------------
|
|
94
|
+
{
|
|
95
|
+
const problems = [];
|
|
96
|
+
const caseIds = corpus.cases.map(item => item.id);
|
|
97
|
+
if (new Set(caseIds).size !== caseIds.length) problems.push('case ids are not unique');
|
|
98
|
+
for (const item of corpus.cases) {
|
|
99
|
+
for (const field of REQUIRED_CASE_FIELDS) {
|
|
100
|
+
if (item[field] === undefined) problems.push(`${item.id} lacks ${field}`);
|
|
101
|
+
}
|
|
102
|
+
const actionIds = item.actions.map(action => action.id);
|
|
103
|
+
if (new Set(actionIds).size !== actionIds.length) problems.push(`${item.id} action ids are not unique`);
|
|
104
|
+
for (const action of item.actions) {
|
|
105
|
+
if (!fx.ALL_OPS.has(action.op)) problems.push(`${item.id}.${action.id} op ${action.op} is not allowed`);
|
|
106
|
+
for (const mode of MODES) {
|
|
107
|
+
try { fx.exitPolicy(action, mode); } catch (error) { problems.push(error.message); }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const mode of MODES) {
|
|
111
|
+
const ids = item.expectations[mode].map(assertion => assertion.id);
|
|
112
|
+
if (new Set(ids).size !== ids.length) problems.push(`${item.id}.${mode} assertion ids are not unique`);
|
|
113
|
+
for (const assertion of item.expectations[mode]) {
|
|
114
|
+
if (!ALLOWED_OPERATORS.has(assertion.operator)) problems.push(`${item.id}.${assertion.id} operator ${assertion.operator}`);
|
|
115
|
+
if (!Array.isArray(assertion.path) || assertion.path.length === 0) problems.push(`${item.id}.${assertion.id} has no path`);
|
|
116
|
+
if (!S1_KINDS.has(assertion.s1Kind)) problems.push(`${item.id}.${assertion.id} lacks a valid s1Kind`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const retired = [];
|
|
121
|
+
for (const item of corpus.cases) {
|
|
122
|
+
for (const assertion of item.expectations.on) {
|
|
123
|
+
if (assertion.s1Kind === 'retired') retired.push(`${item.id}:${assertion.id}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const expected = Object.entries(RETIRED_BY_CASE).flatMap(([caseId, ids]) => ids.map(id => `${caseId}:${id}`));
|
|
127
|
+
const missing = expected.filter(entry => !retired.includes(entry));
|
|
128
|
+
const extra = retired.filter(entry => !expected.includes(entry));
|
|
129
|
+
if (missing.length || extra.length) problems.push(`retired set differs from the doc table: missing ${show(missing)} extra ${show(extra)}`);
|
|
130
|
+
if (expected.length !== RETIRED_COUNT || RETIRED_COUNT !== 26) problems.push(`the doc table names ${RETIRED_COUNT} IDs, not 26`);
|
|
131
|
+
if (problems.length) record('FAIL', 'inventory: corpus is well formed and marks the 26 S1 retire IDs', problems.join('; '));
|
|
132
|
+
else record('PASS', `inventory: corpus is well formed and marks the ${RETIRED_COUNT} S1 retire IDs`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ---- Replays: every case, both legs, both modes ----------------------------------------------------------------
|
|
136
|
+
for (const item of corpus.cases) {
|
|
137
|
+
for (const mode of MODES) {
|
|
138
|
+
const roots = {};
|
|
139
|
+
for (const leg of LEGS) {
|
|
140
|
+
let root;
|
|
141
|
+
try {
|
|
142
|
+
root = fx.scrubReplay(fx.replayCase(item, leg, mode === 'on' ? { pilot: '1' } : undefined));
|
|
143
|
+
} catch (error) {
|
|
144
|
+
infrastructure.push(`${item.id}.${mode} [${leg}]`);
|
|
145
|
+
infra += 1;
|
|
146
|
+
console.log(` INFRA ${item.id}.${mode} [${leg}] — replay failed: ${error.message.split('\n')[0]}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
roots[leg] = root;
|
|
150
|
+
const faults = fx.infrastructureFaults(item, root, mode);
|
|
151
|
+
if (faults.length) {
|
|
152
|
+
infra += 1;
|
|
153
|
+
infrastructure.push(`${item.id}.${mode} [${leg}]`);
|
|
154
|
+
for (const fault of faults) console.log(` INFRA ${item.id}.${mode} [${leg}] ${fault.actionId}: ${fault.message}`);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
for (const assertion of item.expectations[mode]) {
|
|
158
|
+
const result = fx.evaluateAssertion(root, assertion);
|
|
159
|
+
const id = `${item.id}.${mode}.${assertion.id} [${leg}]`;
|
|
160
|
+
const tag = `(${assertion.s1Kind})`;
|
|
161
|
+
if (result.pass) record('PASS', id, tag);
|
|
162
|
+
else record('FAIL', id, `${tag} ${reasonFor(assertion, result.actual)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (roots.source && roots.packaged && !fx.infrastructureFaults(item, roots.source, mode).length
|
|
166
|
+
&& !fx.infrastructureFaults(item, roots.packaged, mode).length) {
|
|
167
|
+
const same = JSON.stringify(comparable(roots.source)) === JSON.stringify(comparable(roots.packaged));
|
|
168
|
+
const id = `${item.id}.${mode}.parity [source=packaged]`;
|
|
169
|
+
if (same) record('PASS', id, '(control)');
|
|
170
|
+
else record('FAIL', id, '(control) source and packaged legs disagree');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ---- Summary -----------------------------------------------------------------------------------------------------
|
|
176
|
+
console.log(`\nS1 strict summary: ${passed} PASS, ${failed} FAIL, ${infra} INFRA across ${corpus.cases.length} cases (pilotCredit: false)`);
|
|
177
|
+
if (failures.length) console.log(`FAILED assertions (${failures.length}):\n ${failures.join('\n ')}`);
|
|
178
|
+
if (infrastructure.length) console.log(`INFRASTRUCTURE (${infrastructure.length}):\n ${infrastructure.join('\n ')}`);
|
|
179
|
+
|
|
180
|
+
if (infra > 0) {
|
|
181
|
+
console.error('S1 suite: infrastructure faults present; these are not assertion results.');
|
|
182
|
+
process.exitCode = 2;
|
|
183
|
+
} else if (failed > 0) {
|
|
184
|
+
console.error('S1 suite: assertion FAIL present (expected on the RED base; GREEN must clear every FAIL).');
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
} else {
|
|
187
|
+
console.log('S1 suite: all assertions PASS.');
|
|
188
|
+
}
|
|
@@ -38,7 +38,8 @@ const ENTRY_KEYS = ['caseId', 'assertionId', 'distribution', 'baselineSha', 'act
|
|
|
38
38
|
const FINGERPRINT_FILES = [
|
|
39
39
|
'hooks/scripts/lib/workflow-obligations.js',
|
|
40
40
|
'hooks/scripts/workflow-disposition.js',
|
|
41
|
-
'hooks/scripts/workflow-stop-gate.js'
|
|
41
|
+
'hooks/scripts/workflow-stop-gate.js',
|
|
42
|
+
'hooks/scripts/lib/doc-reconciliation-pilot.js'
|
|
42
43
|
];
|
|
43
44
|
const CANDIDATE_FILE = 'ci/fixtures/doc-obligations/reconciliation-prep/pending-red.candidate.json';
|
|
44
45
|
const UNREVIEWED_REASON = 'needs-reason';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# Document workflow reconciliation — Phase 3b
|
|
1
|
+
# Document workflow reconciliation — Phase 3b S1 runtime
|
|
2
2
|
|
|
3
|
-
**Status:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
**Status: S1 runtime ships default OFF; opt in with `HARNESS_DOC_RECONCILIATION_PILOT=1`.
|
|
4
|
+
S1 grants no positive document verification credit. S2/S3 are pending; E1 has not started.**
|
|
5
|
+
This document refines the [document lifecycle contract](document-lifecycle.md#phase-3b--narrow-integration-contract-s1-shipped-default-off-positive-reconciliation-not-shipped).
|
|
6
|
+
The [accepted E0](https://github.com/dyphn1/Harness-everything/issues/341#issuecomment-6308604128)
|
|
7
|
+
permits this limited, reversible consumer under the
|
|
8
|
+
[owner's E0/E1 decision](https://github.com/dyphn1/Harness-everything/issues/325#issuecomment-6283237637).
|
|
9
|
+
Current evidence establishes deterministic mechanism/package behavior, not live-host loading or E1 GO.
|
|
8
10
|
|
|
9
11
|
## Entry gates and ownership
|
|
10
12
|
|
|
@@ -112,7 +114,7 @@ capabilities, host requirements and existing binding/tool locators; it does not
|
|
|
112
114
|
or load SKILL.md content. Candidates are optional. Swapping or omitting a provider cannot alter
|
|
113
115
|
expected obligations, authorize a tool, or convert missing evidence to PASS. Existing binding
|
|
114
116
|
resolution handles a chosen provider; independent valid evidence can satisfy a MUST without it.
|
|
115
|
-
An unsupported host reports unavailable capability/reason. H1/H2 runtime proof
|
|
117
|
+
An unsupported host reports unavailable capability/reason. S3 provider integration and its H1/H2 runtime proof remain pending.
|
|
116
118
|
|
|
117
119
|
## S3 — advisory provider suggestions
|
|
118
120
|
|
|
@@ -227,16 +229,16 @@ live-host loading, E1 GO or #320 promotion. No S1 implementation is a dependency
|
|
|
227
229
|
|
|
228
230
|
## One switch and rollback
|
|
229
231
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
232
|
+
S1 reads `HARNESS_DOC_RECONCILIATION_PILOT=1`; missing, `0`, or any other value is OFF.
|
|
233
|
+
OFF returns before pilot collection or state/report writes. Test children explicitly set or remove
|
|
234
|
+
the variable; ON invokes the S1 runtime's scope assessment and no-credit gate.
|
|
233
235
|
|
|
234
|
-
|
|
236
|
+
OFF preserves legacy disposition and grants zero pilot verification credit. Legacy
|
|
235
237
|
`pass` or `satisfied` is not relabeled as document verification. Rollback removes the opt-in,
|
|
236
238
|
records that pilot credit is disabled, and preserves session/evidence history. ON→OFF→ON MUST
|
|
237
239
|
recollect/reconcile rather than trust any persisted pilot or legacy PASS. Withholding pilot
|
|
238
|
-
credit never rejects Stop or changes host authorization.
|
|
239
|
-
the switch
|
|
240
|
+
credit never rejects Stop or changes host authorization. Accepted E0 permits the limited S1 opt-in;
|
|
241
|
+
the switch does not authorize expansion or replace E1 GO.
|
|
240
242
|
|
|
241
243
|
## Preparation harness handoff
|
|
242
244
|
|
|
@@ -262,12 +264,12 @@ replay cases:
|
|
|
262
264
|
| P07 | `P07-fable-staged`, `P07-fable-parallel`, `P07-fable-multi-agent-workspace`, `P07u` | Three Fable strategies and the untyped compatibility control |
|
|
263
265
|
|
|
264
266
|
P08 is the suite-level source/package parity check across every replay and the shared runtime bytes;
|
|
265
|
-
it is not a separate `cases.json` record. The 16 cases currently produce 13 `
|
|
266
|
-
and three `
|
|
267
|
+
it is not a separate `cases.json` record. The 16 prep cases currently produce 13 `CONTROL_PASS`
|
|
268
|
+
cases and three `EXPECTED_RED` cases (`P02e`, `P03`, and `P05`); all replay legs must agree. These
|
|
267
269
|
statuses qualify the preparation harness only and do not grant document credit.
|
|
268
270
|
|
|
269
271
|
The [pending-red.json registry](../ci/fixtures/doc-obligations/reconciliation-prep/pending-red.json)
|
|
270
|
-
records
|
|
272
|
+
records 10 exact source/packaged S2 gaps (five assertion IDs × two distributions), after 52 S1 entries were retired. Its root records `schemaVersion`, `phase`, `baselineSha`,
|
|
271
273
|
`runtimeFingerprint`, and `entries`. The runner validates schema version, a 40-hex capture
|
|
272
274
|
`baselineSha`, a 64-hex `runtimeFingerprint`, and the entry array. Each entry has exactly
|
|
273
275
|
`caseId`, `assertionId`, `distribution`, `baselineSha`, `actual`, `desired`, `blocker`, and
|
|
@@ -323,16 +325,205 @@ identifies its `leg` (`source` or `packaged`), `mode` (`off` or `on`), full asse
|
|
|
323
325
|
classification `status`, and `actual`, with `desired`/`registered` values when applicable. Case
|
|
324
326
|
statuses are `EXPECTED_RED`, `CONTROL_PASS`, `INFRASTRUCTURE`, `NOT_RUN`, or `FAIL`; assertion statuses distinguish
|
|
325
327
|
passing controls, unexpected passes, qualified gaps, unqualified gaps, and registry mismatches.
|
|
326
|
-
`pilotCredit` is always false.
|
|
327
|
-
(`runtime` only for an actual runtime report, otherwise `harness` for a synthesized marker)
|
|
328
|
-
|
|
328
|
+
`pilotCredit` is always false. The replay records origin in `pilotReportOrigin`
|
|
329
|
+
(`runtime` only for an actual runtime report, otherwise `harness` for a synthesized marker).
|
|
330
|
+
Preparation assertion rows do not carry `reportOrigin`; the S1 runtime report carries its own origin. A harness-synthesized unavailable
|
|
329
331
|
marker is never presented as a production report.
|
|
332
|
+
## S1 — switch, trusted scope and fail-closed no-credit gate
|
|
333
|
+
|
|
334
|
+
**S1 runtime ships default OFF (`HARNESS_DOC_RECONCILIATION_PILOT=1` opts in). It grants no positive document verification credit; S2/S3 are pending and E1 has not started.**
|
|
335
|
+
The [accepted E0](https://github.com/dyphn1/Harness-everything/issues/341#issuecomment-6308604128)
|
|
336
|
+
permits this limited implementation; the [posted execution plan](https://github.com/dyphn1/Harness-everything/issues/325)
|
|
337
|
+
orders Docs → RED → GREEN → independent review → green CI for each slice. S1 is a temporary
|
|
338
|
+
negative-credit slice. S2 supplies trusted producer records, independent review provenance,
|
|
339
|
+
positive reconciliation and freshness; only then can E1 observation begin. S3 adds optional
|
|
340
|
+
provider suggestions. None of these slices authorizes wider #320 integration.
|
|
341
|
+
|
|
342
|
+
### Switch and scope decision
|
|
343
|
+
|
|
344
|
+
Only the exact string `1` enables `HARNESS_DOC_RECONCILIATION_PILOT`. Unset, `0`, `true`,
|
|
345
|
+
whitespace and every other value are OFF. OFF MUST return before any pilot collection or
|
|
346
|
+
report mutation and preserve ordinary output, status and evidence history. Legacy PASS earns
|
|
347
|
+
zero pilot credit. Each ON assessment recollects current scope, including ON→OFF→ON; persisted
|
|
348
|
+
pilot reports or legacy PASS cannot substitute for collection. No discovery runs a generator,
|
|
349
|
+
verifier or network fetch.
|
|
350
|
+
|
|
351
|
+
On supported non-Fable typed workflows (`stepBindingsEnabled === true`), doc-governed means
|
|
352
|
+
current trusted task/config/baseline/candidate facts establish an applicable document MUST,
|
|
353
|
+
or cannot exclude one. Governed/legacy paths and document roles are evaluated at both old and
|
|
354
|
+
new endpoints, so deletion or rename cannot erase scope. D6.5 facts also include declared derived
|
|
355
|
+
sources, normative content and REQ-citing tests. Use the union of derived obligations; a path
|
|
356
|
+
suffix or an authored step name alone is not a scope assessment. A declared `doc-change` MAY
|
|
357
|
+
request assessment but is neither sufficient nor required for governed applicability. Omitted,
|
|
358
|
+
unknown, incomplete or unavailable scope MUST be treated as governed for withholding credit;
|
|
359
|
+
it cannot establish an empty expected set or opt out. Only a trusted non-document assessment
|
|
360
|
+
retains legacy behavior (P06). Unknown applicability remains unresolved, N/A needs its derivation
|
|
361
|
+
reason, and SHOULD is not a gate.
|
|
362
|
+
|
|
363
|
+
- **Config authority (PR #351 review P1).** Derivation uses the current config, so a candidate config edit could de-scope a baseline-governed path. Before deriving, S1 compares the exact bytes of every config source the resolver can select (`.agents/harness-everything/project-docs.json` and each host `harness-everything/manifest.json`) at the recorded baseline commit and in the candidate, including additions and removals. Any difference fails closed with reason `config-scope-changed`; it never establishes trusted non-document scope. S2 replaces this with a full `configDigest` binding.
|
|
364
|
+
- A code-only diff (changed code with no changed REQ-citing test) yields `requirement-sync` applicability `unknown` (a MUST), so it is withheld under ON. This is the unknown-applicability cost the Docuvia pilot measures in E1; see [#350](https://github.com/dyphn1/Harness-everything/issues/350) for the false-rejection measurement.
|
|
365
|
+
|
|
366
|
+
The following anchors are **source-traced at S1 base `5f9726c`**, not runtime or live-host proof:
|
|
367
|
+
|
|
368
|
+
| Input / boundary | Existing seam and limit | S1 requirement |
|
|
369
|
+
| --- | --- | --- |
|
|
370
|
+
| Config selection | `harness-everything/scripts/project-docs-resolver.js:352` (`resolveDocsConfig`) selects/validates project or host config; active-host, absent and ambiguous branches at `:395–447`. `resolveProjectDocs` at `:607` resolves project paths, not a complete evidence identity | Reuse resolver authority and diagnostics; invalid/ambiguous config, or absent config with governed-scope uncertainty, cannot establish trusted non-doc scope. Parsed config and the bytes selected must agree |
|
|
371
|
+
| Baseline / candidate collection | `harness-everything/scripts/doc-lifecycle.js:1534` (`readGitBaseInventory`) reads Git base blobs/config scope; candidate stored-byte walk at `:1398–1425`; lifecycle baseline consumption at `:1971`. These are lifecycle internals, not an exported workflow scope collector (`:2399`) | Reuse existing stored-byte semantics, but establish current task scope and complete baseline/candidate inventories, including untracked, deletion and rename endpoints; no caller-supplied fixture map is runtime authority |
|
|
372
|
+
| Facts / obligations | `harness-everything/scripts/doc-obligations.js:1375` (`deriveDocFacts`) accepts snapshots/config, not host/VCS collection; `:1065` classifies governed paths; `:1390–1420` evaluates both endpoints; `:1508–1543` (`deriveDocObligations`) handles applicable/unknown capabilities | Reuse these pure APIs unchanged after trusted collection. Input shape validity is not provenance or inventory completeness |
|
|
373
|
+
| Verification-step PASS | `hooks/scripts/workflow-disposition.js:279–296` delegates to `updateStep`; `hooks/scripts/lib/workflow-obligations.js:617–645` validates active step/bindings then writes status | Collect current config and diff scope after ordinary validation, before writing verification PASS |
|
|
374
|
+
| Direct aggregate PASS | `hooks/scripts/workflow-disposition.js:240–258` delegates to `updateObligation`; `hooks/scripts/lib/workflow-obligations.js:513–539` accepts evidence text and writes the aggregate | Assess scope before direct `execute` or `verify` PASS, even after every authored step has passed |
|
|
375
|
+
| Completion | `hooks/scripts/lib/workflow-obligations.js:648–682` reports only current active-step evidence; `hooks/scripts/workflow-stop-gate.js:36–64` checks unresolved items then may persist satisfied | Recollect config and diff scope before every completion decision, including already-satisfied and all-PASS plans |
|
|
376
|
+
|
|
377
|
+
### S1 pilot-local scope collector
|
|
378
|
+
|
|
379
|
+
The minimal collector ships in S1 at the seams above, enabled only by the opt-in switch.
|
|
380
|
+
Its deterministic mechanism/package coverage does not establish live-host loading or positive credit.
|
|
381
|
+
|
|
382
|
+
| Input / decision | S1 contract |
|
|
383
|
+
| --- | --- |
|
|
384
|
+
| Baseline capture | With the switch ON at workflow `plan`, record the repository top-level and the `git rev-parse HEAD` commit in workflow state; ON `start` captures them if the plan lacked a baseline. OFF returns early and records nothing |
|
|
385
|
+
| Baseline unavailable | Not a Git repository, a Git failure or a missing baseline record means baseline `unavailable`; scope cannot be excluded and is treated as governed, withholding credit. An OFF-planned workflow first assessed ON at a credit boundary therefore withholds, including OFF-seeded legacy PASS→ON |
|
|
386
|
+
| Candidate | Collect the current working tree, including non-ignored untracked files, deletions and renames against the recorded baseline commit. Reuse the existing `doc-lifecycle.js` readers / `readGitBaseInventory` and stored-byte semantics; do not re-implement byte normalization. Incomplete inventory means unknown scope, treated as governed |
|
|
387
|
+
| Config | Use existing `resolveDocsConfig` at the candidate. Invalid or ambiguous selection, or absent config with governed-scope uncertainty, cannot establish trusted non-document scope. S1 does not yet bind `configDigest` or the task identity tuple; freshness/provenance binding belongs to S2 |
|
|
388
|
+
| Decision | Feed collected snapshots/config into unchanged `deriveDocFacts` → `deriveDocObligations`. Doc-governed means any applicable or unknown document MUST. Trusted non-document scope requires complete collection and no applicable or unknown document MUST |
|
|
389
|
+
|
|
390
|
+
Do not use HEAD at assessment as the baseline: a commit during the workflow could erase the
|
|
391
|
+
governed diff and bypass withholding by appearing non-document.
|
|
392
|
+
|
|
393
|
+
After baseline capture at plan/start, scope collection runs only at verification PASS writes,
|
|
394
|
+
direct aggregate PASS writes and completion. It never runs generators, verifiers or network
|
|
395
|
+
operations. Each boundary recollects candidate/config against the recorded baseline; ON→OFF→ON
|
|
396
|
+
cannot replace that baseline with the latest HEAD or trust a persisted PASS.
|
|
397
|
+
|
|
398
|
+
**Harness materialization:** prep replays create a temporary workspace, materialize non-empty
|
|
399
|
+
`input.baseFiles` as a committed Git baseline before `plan`, then materialize
|
|
400
|
+
`input.candidateFiles` as the working tree. This lets P06 establish trusted non-document scope
|
|
401
|
+
and governed cases exercise actual diffs. Fixtures without `baseFiles` remain non-Git, so their
|
|
402
|
+
baseline is unavailable and credit is withheld. Fixture maps alone are not runtime authority.
|
|
403
|
+
|
|
404
|
+
- **Accepted S1 residual (gitignored paths):** ignored, untracked candidate content is outside the non-ignored inventory. S1 grants no positive credit either way; the S2 producer must close this gap or explicitly re-accept it.
|
|
405
|
+
|
|
406
|
+
### Refusal and completion contract
|
|
407
|
+
|
|
408
|
+
| Attempt with ON + supported governed/unknown scope | Required S1 result |
|
|
409
|
+
| --- | --- |
|
|
410
|
+
| Authored `doc-change` or review PASS | Remains reachable under existing binding/authorization rules; later missing verification does not reject earlier authored work |
|
|
411
|
+
| Verification-step PASS | Exit `2`; verification status remains pending; no positive document credit |
|
|
412
|
+
| Direct aggregate `obligation --obligation-id execute\|verify --disposition pass` | Exit `2`; requested aggregate stays pending; direct text cannot bypass the gate |
|
|
413
|
+
| Stop / completion, including persisted or legacy PASS | Withhold current completion credit; report `step:<verify>:pending` for the verification step even if no step is active; aggregate verify is effectively pending and workflow cannot remain credited as satisfied |
|
|
414
|
+
|
|
415
|
+
**Persistence failure (PR #351 review P2).** The withholding decision is applied in memory first: aggregate
|
|
416
|
+
verify becomes pending, a `satisfied` workflow becomes `running`, and `step:<verify>:pending` is reported.
|
|
417
|
+
Persisting that state is best-effort afterwards. A write failure adds the diagnostic `withhold-persist-failed`
|
|
418
|
+
and a reminder; it never leaves the credit decision unapplied, never lets a persisted `satisfied`/PASS count as
|
|
419
|
+
credit, and never makes Stop exit non-zero. Every later ON assessment recollects regardless of what is on disk.
|
|
420
|
+
|
|
421
|
+
**Unwritable session store (PR #351 follow-up).** S1 cannot durably downgrade a store it cannot write: if both the
|
|
422
|
+
obligations write and Stop's `saveWorkflow()` fail, the files on disk may still say `satisfied` / `verify: pass`.
|
|
423
|
+
S1 therefore guarantees the following **read/credit contract** rather than durable invalidation:
|
|
424
|
+
|
|
425
|
+
| Guarantee | S1 behaviour when every session write fails |
|
|
426
|
+
| --- | --- |
|
|
427
|
+
| Persisted state is never credit under ON | Every ON verification, direct aggregate and Stop assessment recollects scope and re-derives the decision; a stored `satisfied`, `verify: pass` or old pilot report is never read as document credit. `pilotCredit` is always `false` in S1. |
|
|
428
|
+
| The decision is still emitted | Stop still prints the `Unresolved workflow evidence: … step:<verify>:pending` reminder and a `withhold-persist-failed` diagnostic, after the failed `saveWorkflow()` rather than instead of it. |
|
|
429
|
+
| Stop stays non-blocking | Stop exits `0`; no lock, no retry loop. |
|
|
430
|
+
| Not claimed | A durable on-disk downgrade, or that a non-pilot reader (OFF, or another tool) will see `running`. With the switch OFF, stored legacy state is legacy state. |
|
|
431
|
+
|
|
432
|
+
A successful in-memory downgrade is **not** counted as durable invalidation.
|
|
433
|
+
|
|
434
|
+
**Scope of the recovery (PR #351 re-review).** Stop's local persistence recovery and the `withhold-persist-failed`
|
|
435
|
+
diagnostic apply **only** when this Stop run made an actual ON, supported, withheld pilot decision. With the switch
|
|
436
|
+
OFF, and for Fable or persisted untyped workflows, a failing `saveWorkflow()` keeps the pre-S1 path unchanged: the
|
|
437
|
+
error reaches Stop's outer handler, exactly as legacy behaviour, and no pilot diagnostic is emitted.
|
|
438
|
+
|
|
439
|
+
Withholding persisted credit MUST NOT reset authored `doc-change`, review, bindings or evidence
|
|
440
|
+
history merely to manufacture an active step. Compute current unresolved verification independently
|
|
441
|
+
of saved PASS; do not trust old aggregate status. Test OFF-completed→ON and an all-PASS typed plan
|
|
442
|
+
that acquires governed scope. Both `hooks/scripts/workflow-stop-gate.js:12–65` and
|
|
443
|
+
`hooks/scripts/stop-gate.js:14–47` MUST still exit `0`, including collector errors. Reminders never
|
|
444
|
+
reject Stop, authorize a tool or introduce a tool lock. Only disposition PASS attempts return `2`.
|
|
445
|
+
Existing binding/authorization diagnostics precede pilot refusal (P02d).
|
|
446
|
+
|
|
447
|
+
### Runtime pilot report and unsupported paths
|
|
448
|
+
|
|
449
|
+
The S1 runtime report uses the shape specified in
|
|
450
|
+
[trust-contract.json](../ci/fixtures/doc-obligations/reconciliation-prep/trust-contract.json):
|
|
451
|
+
`schemaVersion`, `pilotStatus`, `pilotCredit`, `identity`, `expectedMustIds`, `results`,
|
|
452
|
+
`unsatisfied`, `diagnostics`. Each unsatisfied item contains `obligationId`, `state`, `reasonCode`.
|
|
453
|
+
S1 always reports `pilotCredit: false`; it cannot emit `verified`. Missing producer identity is
|
|
454
|
+
`null`; unknown expected scope stays diagnostic/unresolved, never an inferred empty-set PASS.
|
|
455
|
+
`results` retain checker observation/outcome enums unchanged. Supported withheld scope reports
|
|
456
|
+
`unavailable` when collection/producer support is absent, otherwise `unresolved`; known MUSTs
|
|
457
|
+
remain listed without pretending that producer evidence exists. S1 reason codes are
|
|
458
|
+
`unknown-applicability` for an unknown MUST, `producer-unavailable` for an applicable MUST
|
|
459
|
+
without the S2 producer, `baseline-unavailable`, `config-unavailable`, `scope-unavailable`
|
|
460
|
+
for missing baseline/config or incomplete inventory, and `collector-unavailable` for other
|
|
461
|
+
collector failures. Unsupported paths diagnose `unsupported-workflow`; a complete assessment
|
|
462
|
+
with no applicable/unknown MUST diagnoses `trusted-non-document-scope`.
|
|
463
|
+
|
|
464
|
+
An actual runtime report MUST carry `reportOrigin: runtime`; replay extraction sets
|
|
465
|
+
`pilotReportOrigin: runtime` only for that captured report. The helper's
|
|
466
|
+
`ci/lib/doc-reconciliation-prep-fixtures.js:runtimePilotOf()` reads the emitted report;
|
|
467
|
+
missing reports retain `pilot: null` and origin `harness`, never a synthesized runtime marker.
|
|
468
|
+
OFF does not produce or mutate a pilot report.
|
|
469
|
+
|
|
470
|
+
With ON, loaded `fable-staged`, `fable-parallel`, `fable-multi-agent-workspace` and persisted
|
|
471
|
+
untyped workflows report `unavailable`, with no credit and a reason. Fable stage bindings,
|
|
472
|
+
including a correlated loaded stage binding, cannot become document verification; preserve
|
|
473
|
+
existing stage lifecycle rather than entering generic typed-step reconciliation. A **new invalid
|
|
474
|
+
untyped plan** is different: P07u still rejects plan creation with exit `2` and `pilot === null`.
|
|
475
|
+
The separate persisted-untyped fixture covers loaded records. Unsupported paths add no Stop lock.
|
|
476
|
+
|
|
477
|
+
### Registry staging and independent RED handoff
|
|
478
|
+
|
|
479
|
+
S1 has **52 entries retired / 10 kept**, each assertion ID counted separately for
|
|
480
|
+
`source` and `packaged`. Strict runtime assertions cover the retired entries; the reviewed prep
|
|
481
|
+
registry retains these five S2 assertion IDs × two distributions:
|
|
482
|
+
|
|
483
|
+
| S1 retire: 26 IDs × 2 | Assertion suffixes under `<case>.on.` |
|
|
484
|
+
| --- | --- |
|
|
485
|
+
| P01 | `verify-exit-refused`, `verify-obligation-pending`, `stop-unsatisfied`, `stop-reports-verification` |
|
|
486
|
+
| P04 | `direct-execute-refused`, `direct-verify-refused`, `verify-obligation-pending` |
|
|
487
|
+
| Each of P02a, P02b, P02c, P02f, P02g | `verify-pass-exit`, `stop-state`, `stop-reports` |
|
|
488
|
+
| P03 | `verify-pass-exit` |
|
|
489
|
+
| Each of the three P07 Fable cases | `pilot-status-unavailable` |
|
|
490
|
+
| **S2 keep: 5 IDs × 2** | **Assertion suffixes under `<case>.on.`** |
|
|
491
|
+
| P02e | `review-pass-exit`, `stop-reports` |
|
|
492
|
+
| P03 | `verify-retry-exit` |
|
|
493
|
+
| P05 | `stop-on-2-withheld`, `stop-on-3-withheld` |
|
|
494
|
+
|
|
495
|
+
- Move retired gaps into strict runtime assertions. Declare intentional ON exit `2` in each
|
|
496
|
+
action's `expectExit`; do not weaken crash, output, deadline or other infrastructure policies
|
|
497
|
+
(`ci/lib/doc-reconciliation-prep-fixtures.js:298–352`). Preserve explicit Stop exit `0` checks.
|
|
498
|
+
- P02e independent review provenance belongs to S2. Do not reject review by matching self-review
|
|
499
|
+
prose or because later verifier evidence is absent. P03 first review remains reachable; its
|
|
500
|
+
first verification is refused, and retry remains RED in S1. S2 changes retry ON `expectExit`
|
|
501
|
+
from `2` to `0` when real evidence can earn credit.
|
|
502
|
+
- P05's initial ON positive verification and `stop-on-1` cannot pass in S1. Preserve a distinct S2
|
|
503
|
+
positive-credit case and its approved desired outcomes; add a separate OFF-seeded legacy PASS→ON
|
|
504
|
+
withholding case for S1. Merely changing exit policy introduces an unregistered initial-state gap.
|
|
505
|
+
- Deliberately review/recapture the changed baseline and registry actual/desired qualification;
|
|
506
|
+
include the newly imported pilot module in the ordered runtime fingerprint. Then exactly the
|
|
507
|
+
targeted entries retire and the remaining `--expect-red` run must qualify on that reviewed S1
|
|
508
|
+
baseline. Deleting registry rows alone proves nothing.
|
|
509
|
+
- Additional strict S1 cases: governed diff without authored `doc-change`, direct aggregate PASS
|
|
510
|
+
after authored completion, correlated Fable stage binding, persisted untyped workflow, legacy
|
|
511
|
+
PASS and ON→OFF→ON recollection. These additions are not part of the 52 existing entries.
|
|
512
|
+
- Preserve P06 with trusted non-doc scope, P07u, P02d ordering, OFF controls and source/package
|
|
513
|
+
parity. Require the relevant deterministic gates plus `npm run verify:all -- --fast`, independent
|
|
514
|
+
review with no open P1/P2, and full green CI including Windows on the PR head.
|
|
515
|
+
|
|
516
|
+
S1 proves only its tested no-credit mechanism. It does not prove positive reconciliation,
|
|
517
|
+
independent producer provenance, live-host loading, H1–H4 effectiveness or E1 GO. Registry empty
|
|
518
|
+
is a later strict-prep gate, not proof of any of those evidence layers.
|
|
519
|
+
|
|
330
520
|
## Implementation and acceptance after E0
|
|
331
521
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
freshness check, source/package compatibility, negative cases and
|
|
336
|
-
Windows.
|
|
337
|
-
|
|
338
|
-
|
|
522
|
+
S1 ships the default-OFF switch, narrow disposition/completion no-credit integration and runtime
|
|
523
|
+
status reporting. S2's trusted producer, positive reconciliation and freshness remain pending;
|
|
524
|
+
S3's optional provider adapter remains pending. Require every expected applicable MUST and
|
|
525
|
+
freshness check before positive credit, plus source/package compatibility, negative cases and
|
|
526
|
+
relevant green CI including Windows. The S1 suites establish their tested mechanism/package
|
|
527
|
+
contracts; they do not establish independent host provenance, live-host loading or architectural
|
|
528
|
+
benefit. E1 has not started and begins only after a creditable S2; E1 GO and H1–H4/paired evidence
|
|
529
|
+
remain separate gates.
|
|
@@ -15,19 +15,19 @@ This table distinguishes merged mechanism code from end-to-end workflow integrat
|
|
|
15
15
|
| 2 — roles, IDs, aliases, legacy, supersession, index, D6.9 PRD revisions | **Merged** in #327; do not rebuild this lifecycle logic for Phase 3 |
|
|
16
16
|
| Step-type prerequisite (#326) | **Complete:** PR #328 merged; Harness-owned `doc-change` is explicitly declared, has no implicit TDD binding, and is not auto-inserted by router/System One |
|
|
17
17
|
| 3a — document facts, obligations and evidence producer | **Merged** in #334: `harness-everything/scripts/doc-obligations.js` and `doc-evidence.js`. H3/H4 have *partial deterministic mechanism* coverage, not integrated workflow evidence. Known limitations: caller-attested envelope; `configDigest` presence-only; `candidateDigest` restricted to `docs/prd/`; missing independent task-scope binding. Deleted and old rename paths are bound to trusted per-path baseline evidence ([doc-evidence-baseline-binding.md](doc-evidence-baseline-binding.md), #335 fixed by #342), with workflow-disposition reconciliation left out of scope |
|
|
18
|
-
| 3b — pilot-local provider suggestions and workflow evidence reconciliation | **
|
|
18
|
+
| 3b — pilot-local provider suggestions and workflow evidence reconciliation | **S1 runtime ships default OFF** (opt in with `HARNESS_DOC_RECONCILIATION_PILOT=1`), with trusted scope assessment and fail-closed withholding; **no positive document verification credit**. See [S1 switch, trusted scope and no-credit contract](doc-workflow-reconciliation.md#s1--switch-trusted-scope-and-fail-closed-no-credit-gate). **S3 pure advisory provider suggestions shipped in 0.37.0 (not wired); S2 trusted producer/positive reconciliation/freshness is pending; E1 has not started.** Accepted #341 E0 permits this limited reversible consumer. Current evidence is deterministic mechanism/package coverage, not live-host loading or E1 GO; preserve existing required-binding compatibility |
|
|
19
19
|
| 3c — H1–H4 and paired-task evaluation | **Not started.** Mechanism tests alone are insufficient for architecture promotion; compare frozen baseline and treatment on real bounded tasks, success/failure first, then conditional cost and latency |
|
|
20
20
|
| 1b — shared documentation craft and family metadata | **Splittable.** Shared references and thin skill consumers can proceed independently. A small optional logical-family metadata seam may be piloted; physical skill directory moves remain blocked on #320 identity/path separation |
|
|
21
21
|
| 4 — derived-view generators and `describes:` drift | **Not started.** Preserve generator authorization, deterministic regenerate-equals and scoped reminder semantics |
|
|
22
22
|
|
|
23
|
-
### Phase 3b — narrow integration contract (
|
|
23
|
+
### Phase 3b — narrow integration contract (S1 shipped default OFF; positive reconciliation not shipped)
|
|
24
24
|
|
|
25
25
|
The preparation design, test-only provider/trust contracts, and qualified RED replay are complete:
|
|
26
26
|
[Document workflow reconciliation](doc-workflow-reconciliation.md),
|
|
27
27
|
[case corpus](../ci/fixtures/doc-obligations/reconciliation-prep/cases.json),
|
|
28
28
|
[pending-RED registry](../ci/fixtures/doc-obligations/reconciliation-prep/pending-red.json), and
|
|
29
|
-
[preparation suite](../ci/mechanism-325-3b-preparation.test.js).
|
|
30
|
-
|
|
29
|
+
[preparation suite](../ci/mechanism-325-3b-preparation.test.js). #341 E0 is accepted; S1 ships the
|
|
30
|
+
default-OFF no-credit gate only. Positive reconciliation (S2) remains unshipped.
|
|
31
31
|
|
|
32
32
|
- **Inputs:** explicit active `doc-change` step, D6.5 diff facts, Phase 3a obligations/evidence, available provider *metadata*, and host capabilities.
|
|
33
33
|
- **Entry and activation gates (#341):** parallel preparatory work — provider metadata, adapter/interface design and RED fixtures — may proceed while #341 Phase 0A–0C runs, but the **runtime** Evidence Reconciliation must not merge or activate until **#341 E0** is reviewed and accepted (initial evidence read/binding/outcome conformance, mutation and read-order compatibility, source/package parity, zero false MUST PASS on applicable adversarial cases, and applicable green CI including Windows). After E0, only the **bounded, opt-in, reversible** documentation consumer is eligible for runtime integration at the existing verification/disposition path (no second router, forced provider, new lock, or weakened authorization, with a documented rollback), and it supplies the observed exposure for **#341 E1** (initial target 2–3 genuine development/review cycles with sufficient case mix, not elapsed time). **#341 E1 GO / REVISE / NO-GO gates expansion beyond the limited pilot, not the pilot's own observation** (missing or unrepresentative exposure is `UNCHECKED`, never an automatic GO). The H1–H4 paired-task architectural gate below stays required for any #320 promotion in addition to E1. Shared evidence-read/binding/decision defects route to #341 (fixture-first correction, regression replay, re-observation); documentation policy and the trusted host/VCS producer remain #325 deliverables here.
|
|
@@ -2396,6 +2396,6 @@ function main(argv = process.argv.slice(2)) {
|
|
|
2396
2396
|
return analysis.diagnostics.some(item => item.severity === 'error') ? 1 : 0;
|
|
2397
2397
|
}
|
|
2398
2398
|
|
|
2399
|
-
module.exports = { parseFrontmatter, parseRequirementBlocks, collectDocs, analyzeDocs, resolveRef, lintDocs, buildIndex, diffRevisions };
|
|
2399
|
+
module.exports = { readGitBaseInventory, scanWorkspaceFiles, parseFrontmatter, parseRequirementBlocks, collectDocs, analyzeDocs, resolveRef, lintDocs, buildIndex, diffRevisions };
|
|
2400
2400
|
|
|
2401
2401
|
if (require.main === module) process.exitCode = main();
|