@dzhechkov/skills-feature-adr 1.5.0 → 1.5.1
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/.dz-manifest.json +6 -6
- package/CHANGELOG.md +18 -0
- package/README.md +19 -0
- package/package.json +1 -1
- package/sbom.json +5 -5
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +26 -12
- package/templates/.claude/workflows/feature-adr.js +57 -43
package/.dz-manifest.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": "CHANGELOG.md",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "88e0389016f697b90731ee8743a35e523f0ccb079426d59861d894f33e516392"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "LICENSE",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "README.md",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "47f9402d4c3954d6d5a75ad906ec7b592010fdfd80f347d4a87dd14dd9e300ce"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "bin/cli.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"path": "package.json",
|
|
28
|
-
"sha256": "
|
|
28
|
+
"sha256": "3fbe9ef86c9f6fa7c86bbe7760729094e80edb67577e397678b2d98dca1c2034"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "scripts/sync-templates.js",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"path": "templates/.claude/skills/feature-adr/modules/08-qe.md",
|
|
168
|
-
"sha256": "
|
|
168
|
+
"sha256": "bd5b5809142c12fa1378de446b68027a0c342a7a91ad17e4fb3395ca8f6a8508"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"path": "templates/.claude/skills/feature-adr/modules/09-fleet-qe.md",
|
|
@@ -321,7 +321,7 @@
|
|
|
321
321
|
},
|
|
322
322
|
{
|
|
323
323
|
"path": "templates/.claude/workflows/feature-adr.js",
|
|
324
|
-
"sha256": "
|
|
324
|
+
"sha256": "0c74e8995d82bb986ef3233e91beebfa0e761aae4434f24554077bb05d2199e9"
|
|
325
325
|
},
|
|
326
326
|
{
|
|
327
327
|
"path": "templates/lib/memory-protocol.md",
|
|
@@ -349,5 +349,5 @@
|
|
|
349
349
|
}
|
|
350
350
|
]
|
|
351
351
|
},
|
|
352
|
-
"signature": "
|
|
352
|
+
"signature": "9WVoqK2D8eKSnmhhMqHPt31NedxwZCHiHyxJ5VLMxSVMecMqyXgrCJ2GQ3OOfIeiquB2D01bh7QjZW/EMVM9Aw=="
|
|
353
353
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.1] - 2026-08-21
|
|
4
|
+
|
|
5
|
+
### Changed — the Step-8 amendment gate is a COMMAND, and the durable writers are witnessed
|
|
6
|
+
|
|
7
|
+
- `AMENDMENT_GATE` no longer asks the QE agent to judge whether every `AM-N` row names a real test.
|
|
8
|
+
It runs `dz amendment-check --slug <slug> --json` and reports the parsed verdict; the old judgement
|
|
9
|
+
wording is REMOVED from both workflow copies and all four `modules/08-qe.md` copies, not
|
|
10
|
+
accompanied. MEASURED 2026-08-21: `features/qe-scoped-review` shipped with five named amendment
|
|
11
|
+
test ids of which none existed, while its plan recorded `## Amendments: None`.
|
|
12
|
+
- the run-cost ledger and the training-pair capture (including backfill) stop handing a subagent a
|
|
13
|
+
pre-baked shell string carrying their payload — the shape a security classifier blocked nine times
|
|
14
|
+
in one run. Both now call `dz feature-adr-record`. The `sed` that rewrote `"date":null` / `"ts":null`
|
|
15
|
+
inside an already-serialised document is gone: the command stamps before serialising.
|
|
16
|
+
- a record failure still NEVER fails the run, but now survives it: `recordFailures` is returned from
|
|
17
|
+
every exit instead of scrolling past inside one log line.
|
|
18
|
+
|
|
19
|
+
Requires `@dzhechkov/harness-core >= 0.6.1`.
|
|
20
|
+
|
|
3
21
|
## [1.5.0] - 2026-08-21
|
|
4
22
|
|
|
5
23
|
### Changed — feature `qe-scoped-review`
|
package/README.md
CHANGED
|
@@ -169,6 +169,25 @@ refused BY NAME: `path traversal ('..' segment)`, `degenerate path segment`, `em
|
|
|
169
169
|
`illegal character '<c>'`, `empty stem after the leading dot`. The old substring traversal test also
|
|
170
170
|
rejected the ordinary filename `foo..bar.ts`; it is a segment test now.
|
|
171
171
|
|
|
172
|
+
### The Step-8 amendment gate runs a command instead of judging (v1.5.1)
|
|
173
|
+
|
|
174
|
+
Every `AM-N` row must resolve to a test found INSIDE the file the row names, and the check is
|
|
175
|
+
`dz amendment-check --slug <slug> --json` rather than a paragraph asking the reviewer to confirm it.
|
|
176
|
+
MEASURED 2026-08-21: `features/qe-scoped-review` shipped with five named amendment test ids of which
|
|
177
|
+
none existed, while its plan recorded `## Amendments: None`. The gate did not fail — a prompt cannot.
|
|
178
|
+
|
|
179
|
+
The PLAN is authoritative when it carries rows (Step 6 owes "carry AM-N into the plan verbatim"), and
|
|
180
|
+
the rule that keeps that honest is coverage: an amendment the plan drops — or rewords under the same
|
|
181
|
+
id — is a failure. Renaming the TEST stays legitimate; tests are named later than ideation guesses.
|
|
182
|
+
|
|
183
|
+
The durable writers were migrated in the same release: the run-cost ledger and the training-pair
|
|
184
|
+
capture no longer hand a subagent a pre-baked shell string with their payload baked in — the shape a
|
|
185
|
+
security classifier blocked nine times in one run. Both call `dz feature-adr-record`, which refuses
|
|
186
|
+
before writing and verifies the append by re-reading the tail. A record failure still never fails the
|
|
187
|
+
run; it now survives it in `recordFailures`.
|
|
188
|
+
|
|
189
|
+
Requires `@dzhechkov/harness-core >= 0.6.1`.
|
|
190
|
+
|
|
172
191
|
### Step 0 writes the assessment down, and the acid check gets its input back (v1.5.0)
|
|
173
192
|
|
|
174
193
|
Step 0 classifies the feature and now **writes `00_complexity_assessment.md` before it returns** — the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/skills-feature-adr",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Adaptive Feature Development skill pack for Claude Code — 11-step pipeline with Complexity Router (S/M/L/XL), ADR-driven architecture, 15 agentic-qe skills, multi-agent fleet QE. Supports --full-qe, --full-qe-extended, --with-learning, and --knowledge-extractor modes.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skills-feature-adr": "./bin/cli.js"
|
package/sbom.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"hashes": [
|
|
16
16
|
{
|
|
17
17
|
"alg": "SHA-256",
|
|
18
|
-
"content": "
|
|
18
|
+
"content": "88e0389016f697b90731ee8743a35e523f0ccb079426d59861d894f33e516392"
|
|
19
19
|
}
|
|
20
20
|
]
|
|
21
21
|
},
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"hashes": [
|
|
36
36
|
{
|
|
37
37
|
"alg": "SHA-256",
|
|
38
|
-
"content": "
|
|
38
|
+
"content": "47f9402d4c3954d6d5a75ad906ec7b592010fdfd80f347d4a87dd14dd9e300ce"
|
|
39
39
|
}
|
|
40
40
|
]
|
|
41
41
|
},
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"hashes": [
|
|
66
66
|
{
|
|
67
67
|
"alg": "SHA-256",
|
|
68
|
-
"content": "
|
|
68
|
+
"content": "3fbe9ef86c9f6fa7c86bbe7760729094e80edb67577e397678b2d98dca1c2034"
|
|
69
69
|
}
|
|
70
70
|
]
|
|
71
71
|
},
|
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
"hashes": [
|
|
416
416
|
{
|
|
417
417
|
"alg": "SHA-256",
|
|
418
|
-
"content": "
|
|
418
|
+
"content": "bd5b5809142c12fa1378de446b68027a0c342a7a91ad17e4fb3395ca8f6a8508"
|
|
419
419
|
}
|
|
420
420
|
]
|
|
421
421
|
},
|
|
@@ -805,7 +805,7 @@
|
|
|
805
805
|
"hashes": [
|
|
806
806
|
{
|
|
807
807
|
"alg": "SHA-256",
|
|
808
|
-
"content": "
|
|
808
|
+
"content": "0c74e8995d82bb986ef3233e91beebfa0e761aae4434f24554077bb05d2199e9"
|
|
809
809
|
}
|
|
810
810
|
]
|
|
811
811
|
},
|
|
@@ -160,18 +160,32 @@ The Confirmation-to-test link is load-bearing. If absent, grade no better than C
|
|
|
160
160
|
|
|
161
161
|
### 3b. Amendment Gate (P2 — amendments inherit the Confirmation discipline)
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
163
|
+
**Do not judge this yourself — RUN the check.** Resolution of every `AM-N` row to a real test is a
|
|
164
|
+
deterministic question, and a deterministic question must not live in prose (cost-of-detection ladder).
|
|
165
|
+
It used to live here, and `features/qe-scoped-review` shipped with five named amendment test ids of
|
|
166
|
+
which none existed, while its plan recorded `## Amendments: None`.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
dz amendment-check --slug <feature-slug> --json # or --feature-dir <abs path>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
| Outcome | Exit | What it means for the gate |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| `pass` | 0 | every row resolves to a test found inside the file the row names |
|
|
175
|
+
| `skip` | 0 | no `## Amendments` section — an absence, stated, never a silent pass |
|
|
176
|
+
| `fail` | 1 | a HIGH gap: quote every reason verbatim into the QE report |
|
|
177
|
+
| `not-established` | 3 | the grammar matched nothing, or the inputs were unreadable — **never a pass** |
|
|
178
|
+
|
|
179
|
+
Empty stdout, a crash, or a missing `dz` is `not-established`, not a clean gate.
|
|
180
|
+
|
|
181
|
+
**What the command does NOT prove:** that a resolved test discriminates. Vacuity stays yours, in the
|
|
182
|
+
SAME `dz discrimination-check --test <f1,f2,...> --base HEAD --json` run as the ADR property test — an
|
|
183
|
+
amendment test that stays green at pre-feature base proves nothing about its amendment. A **safeguard**
|
|
184
|
+
amendment additionally needs its test to prove the safeguard FIRES on a real input: a structurally-dead
|
|
185
|
+
safeguard passes an existence check and never fires in production.
|
|
186
|
+
|
|
187
|
+
This closes the distance between "we caught the design flaw" (challenge-panel/QCSD) and "we proved the
|
|
188
|
+
fix works".
|
|
175
189
|
|
|
176
190
|
### 3c. I/O-on-pure-path + fixture-swap hunt (P5)
|
|
177
191
|
|
|
@@ -459,6 +459,10 @@ const TP_MAX_IO = 48000
|
|
|
459
459
|
const TP_DIR = REPO + '/.dz/fa-training/' + SLUG
|
|
460
460
|
const TP_MARK_DIR = REPO + '/.dz/fa-training/.backfill-marks'
|
|
461
461
|
const LEDGER_FILE = REPO + '/.dz/feature-adr/run-cost-ledger.jsonl'
|
|
462
|
+
// ADR-003: a record failure NEVER fails the run — a cost row is observability, and observability must
|
|
463
|
+
// not take a six-hour run down with it. But today's silence is not "secondary", it is invisible: one
|
|
464
|
+
// log line among thousands. Failures accumulate here and are RETURNED, so they survive the run.
|
|
465
|
+
const recordFailures = []
|
|
462
466
|
const TP_README = REPO + '/.dz/fa-training/README.md'
|
|
463
467
|
const TP_BACKFILL_OK = 'TP-BACKFILL-OK'
|
|
464
468
|
const TP_BACKFILL_SKIP = 'TP-BACKFILL-SKIP'
|
|
@@ -554,40 +558,49 @@ async function capturePairs(stage, phaseName, records, resumeGuardStage) {
|
|
|
554
558
|
const markStage = String(stage).replace(/\.\./g, '_').replace(/\//g, '_')
|
|
555
559
|
// The workflow pair line carries the stable feature SLUG, so this content key stays stable across resumes.
|
|
556
560
|
const mark = TP_MARK_DIR + '/' + markStage + '-' + fnv1a64(stage + '\0' + lines.join('\n'))
|
|
557
|
-
|
|
558
|
-
//
|
|
561
|
+
// WITNESSED WRITE (ADR-001), backfill mode. The mark is still an atomic mkdir — but it is the
|
|
562
|
+
// COMMAND that takes it, so the same invocation that claims the mark is the one that validates
|
|
563
|
+
// and writes. The old form claimed the mark in a shell pipeline the courier never inspected.
|
|
559
564
|
if (mode === 'backfill') {
|
|
560
|
-
|
|
565
|
+
let outcome = 'written'
|
|
561
566
|
for (let i = 0; i < lines.length; i++) {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
} else {
|
|
576
|
-
log('training-pair: ' + stage + ' backfill UNVERIFIED (no TP-BACKFILL readback) — the pair may be missing on disk (non-blocking; the run continues)')
|
|
577
|
-
captureFailures.push(captureFailureRecord(stage, mode, 'backfill-unverified', 'no TP-BACKFILL-OK or TP-BACKFILL-SKIP readback'))
|
|
567
|
+
const cmdOne = DZ + ' feature-adr-record --kind training-pair --slug ' + shq(SLUG) + ' --stage ' + shq(stage)
|
|
568
|
+
+ ' --project ' + shq(REPO) + ' --mark ' + shq(markStage + '-' + fnv1a64(stage + '\0' + lines.join('\n')) + '-' + i)
|
|
569
|
+
+ ' --once --pair ' + shq(lines[i]) + ' --json'
|
|
570
|
+
const out = await agent('Run this command via your Bash tool and reply with only its stdout: ' + cmdOne, { label: 'trainpair:backfill:' + stage, phase: phaseName, effort: 'low' })
|
|
571
|
+
const readback = String(out == null ? '' : out)
|
|
572
|
+
const m = /"verdict"\s*:\s*"(written|duplicate|skipped)"/.exec(readback)
|
|
573
|
+
if (m === null) {
|
|
574
|
+
outcome = 'unverified'
|
|
575
|
+
captureFailures.push(captureFailureRecord(stage, mode, 'backfill-unverified', readback === '' ? 'no output from the record command' : readback.slice(0, 200)))
|
|
576
|
+
recordFailures.push({ kind: 'training-pair', stage: stage, reason: 'backfill: ' + (readback === '' ? 'no output from the record command' : readback.slice(0, 300)) })
|
|
577
|
+
break
|
|
578
|
+
}
|
|
579
|
+
if (m[1] !== 'written' && outcome === 'written') outcome = m[1]
|
|
578
580
|
}
|
|
581
|
+
if (outcome === 'written') log('training-pair: ' + stage + ' missing pair backfilled from the checkpoint')
|
|
582
|
+
else if (outcome === 'duplicate') log('training-pair: ' + stage + ' another run already captured this pair (nothing written)')
|
|
583
|
+
else if (outcome === 'skipped') log('training-pair: ' + stage + ' pair already existed (nothing written)')
|
|
584
|
+
else log('training-pair: ' + stage + ' backfill NOT WRITTEN (non-blocking; the run continues)')
|
|
579
585
|
return
|
|
580
586
|
}
|
|
587
|
+
// WITNESSED WRITE (ADR-001): one command invocation per pair, data passed as an ARGUMENT. The
|
|
588
|
+
// `sed` that used to rewrite `"ts":null` inside an already-serialised document is gone — the
|
|
589
|
+
// command stamps the timestamp BEFORE serialising, so no text surgery touches a JSON value.
|
|
590
|
+
let allWritten = true
|
|
581
591
|
for (const line of lines) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
592
|
+
const cmdOne = DZ + ' feature-adr-record --kind training-pair --slug ' + shq(SLUG) + ' --stage ' + shq(stage)
|
|
593
|
+
+ ' --project ' + shq(REPO) + ' --pair ' + shq(line) + ' --json'
|
|
594
|
+
const out = await agent('Run this command via your Bash tool and reply with only its stdout: ' + cmdOne, { label: 'trainpair:' + stage, phase: phaseName, effort: 'low' })
|
|
595
|
+
const readback = String(out == null ? '' : out)
|
|
596
|
+
if (!/"verdict"\s*:\s*"(written|duplicate|skipped)"/.test(readback)) {
|
|
597
|
+
allWritten = false
|
|
598
|
+
captureFailures.push(captureFailureRecord(stage, mode, 'unverified', readback === '' ? 'no output from the record command' : readback.slice(0, 200)))
|
|
599
|
+
recordFailures.push({ kind: 'training-pair', stage: stage, reason: readback === '' ? 'no output from the record command' : readback.slice(0, 300) })
|
|
600
|
+
}
|
|
585
601
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if (!/TP-OK/.test(String(out == null ? '' : out))) {
|
|
589
|
-
log('training-pair: ' + stage + ' capture UNVERIFIED (no TP-OK readback) — the pair may be missing on disk (non-blocking; the run continues)')
|
|
590
|
-
captureFailures.push(captureFailureRecord(stage, mode, 'unverified', 'no TP-OK readback'))
|
|
602
|
+
if (!allWritten) {
|
|
603
|
+
log('training-pair: ' + stage + ' capture NOT WRITTEN for at least one pair (non-blocking; the run continues)')
|
|
591
604
|
}
|
|
592
605
|
} catch (e) {
|
|
593
606
|
const message = e && e.message ? e.message : String(e)
|
|
@@ -615,17 +628,18 @@ async function appendRunCostRow(stage, phaseName) {
|
|
|
615
628
|
auto: true,
|
|
616
629
|
mode: (typeof MODE === 'string' && MODE !== '') ? MODE : null,
|
|
617
630
|
})
|
|
618
|
-
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
+ '
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
631
|
+
// WITNESSED WRITE (ADR-001): the subagent RUNS a command with data arguments; it is no longer
|
|
632
|
+
// handed a shell pipeline with the row baked in. The command refuses a malformed row, stamps the
|
|
633
|
+
// date BEFORE serialising (no sed over a serialised document) and verifies the append by
|
|
634
|
+
// re-reading the tail. A courier could do none of those three.
|
|
635
|
+
const cmd = DZ + ' feature-adr-record --kind ledger --stage ' + shq(stage) + ' --project ' + shq(REPO)
|
|
636
|
+
+ ' --row ' + shq(line) + ' --json'
|
|
637
|
+
const out = await agent('Run this command via your Bash tool and reply with only its stdout: ' + cmd, { label: 'ledger:append', phase: phaseName, effort: 'low' })
|
|
638
|
+
const readback = String(out == null ? '' : out)
|
|
639
|
+
if (!/"verdict"\s*:\s*"written"/.test(readback)) {
|
|
640
|
+
// ADR-003: SECONDARY — never fails the run — but the failure now SURVIVES it.
|
|
641
|
+
recordFailures.push({ kind: 'ledger', stage: stage, reason: readback === '' ? 'no output from the record command' : readback.slice(0, 300) })
|
|
642
|
+
log('run-cost ledger: ' + stage + ' row NOT WRITTEN (SECONDARY; the run continues) — ' + readback.slice(0, 200))
|
|
629
643
|
}
|
|
630
644
|
} catch (e) {
|
|
631
645
|
log('run-cost ledger: ' + stage + ' append failed (SECONDARY; non-blocking): ' + (e && e.message ? e.message : String(e)))
|
|
@@ -1895,7 +1909,7 @@ const DISCRIMINATION_GATE = '\u00a742 TEST-DISCRIMINATION GATE (run right after
|
|
|
1895
1909
|
// shape (a linter can assert the `→ test ` token); Step-8 verifies existence + non-vacuity via the SAME
|
|
1896
1910
|
// dz discrimination-check that guards the ADR property (cost-of-detection ladder: judgment → step gate).
|
|
1897
1911
|
const AMENDMENT_RULE = 'AMENDMENT CONFIRMATION DISCIPLINE (every amendment is a mini-ADR): whenever a correction/amendment is folded in (a QCSD CONDITIONAL condition, a challenge-panel confirmed finding, or a user checkpoint steer), record it in a `## Amendments` section as a fixed-shape row: `AM-N (source): <change>. Confirmation: <property> → test `test_name` (fails if reverted).` — naming the test that would FAIL if the amendment were reverted/broken. For a SAFEGUARD amendment (a warning/guard/fallback), the named test must prove the safeguard actually TRIGGERS on a real input — not merely that its code path exists (a structurally-dead safeguard passes an existence test and never fires in production).'
|
|
1898
|
-
const AMENDMENT_GATE = 'AMENDMENT GATE (P2):
|
|
1912
|
+
const AMENDMENT_GATE = 'AMENDMENT GATE (P2): do NOT judge this yourself — RUN the check and report what it says. Via Bash run EXACTLY `' + DZ + ' amendment-check --slug ' + SLUG + ' --json` (add `--feature-dir ' + FDIR + '` if the slug does not resolve from your CWD). Parse the JSON and report `amendments: {outcome, counts, reasons}` in your return object. outcome `pass` or `skip` clears the gate; `fail` is a HIGH gap and every reason must be quoted verbatim into the QE report; `not-established` means the check could not be run or the grammar matched nothing — that is NEVER a pass, report it as inconclusive with the tool error. Empty stdout, a crash, or a missing `dz` is `not-established`, not a clean gate. This check proves each amendment RESOLVES to a real test; it does NOT prove the test discriminates — vacuity stays with the discrimination gate above. ' +
|
|
1899
1913
|
'IO-ON-PURE-PATH + FIXTURE-SWAP HUNT (P5): in the test diff, hunt for replacements of broken/unbound fixtures with healthy ones — the old fixture was probably a NEGATIVE CONTROL proving a path was I/O-free; each such swap requires a compensating negative resource-down test. If the code diff adds I/O (DB/network/file) to a previously-pure path — especially startup/lifespan/health — require a negative resource-down test (broken/unbound resource → the path degrades per its declared contract: fail-open for advisory, explicit fail-fast for load-bearing). Missing → HIGH gap.'
|
|
1900
1914
|
|
|
1901
1915
|
// Step 0: Router + MANDATORY self-learning recall
|
|
@@ -2172,7 +2186,7 @@ if (!fanVerdict.complete) {
|
|
|
2172
2186
|
// invisible to cost analysis, which is how a stage that keeps dying stays cheap-looking.
|
|
2173
2187
|
// (coderUsed/qe are the outer bindings, both still null here, so the row reports null honestly.)
|
|
2174
2188
|
await appendRunCostRow('design-gate', 'Design')
|
|
2175
|
-
return { tier: tier, phase: 'design-incomplete', slug: SLUG, artifactsDir: FDIR, missingSubstages: fanVerdict.missingSubstages, missingArtifacts: fanVerdict.missingArtifacts, reason: fanVerdict.reason, modelsUsed: modelsUsed, gates: { design: fanVerdict.reason === 'probe-not-established' ? 'not-established' : 'incomplete', plan: 'not-run', planCompleteness: 'not-run', challengePanel: 'not-run', code: 'not-run', qe: 'not-run' }, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'REFUSED at the Step-5/6 boundary: ' + what + ', so the design is incomplete and Step 6 was NOT dispatched. Planning off a partial design produces a plan with no ADR behind it. ' + repair + ' If a sibling died on a Claude limit, add usage-adaptive routing or route that stage to Codex first (args.models). To rebuild the whole design from scratch instead, re-invoke with args.resume=\'never\'.' }
|
|
2189
|
+
return { tier: tier, phase: 'design-incomplete', slug: SLUG, artifactsDir: FDIR, missingSubstages: fanVerdict.missingSubstages, missingArtifacts: fanVerdict.missingArtifacts, reason: fanVerdict.reason, modelsUsed: modelsUsed, gates: { design: fanVerdict.reason === 'probe-not-established' ? 'not-established' : 'incomplete', plan: 'not-run', planCompleteness: 'not-run', challengePanel: 'not-run', code: 'not-run', qe: 'not-run' }, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, recordFailures: recordFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'REFUSED at the Step-5/6 boundary: ' + what + ', so the design is incomplete and Step 6 was NOT dispatched. Planning off a partial design produces a plan with no ADR behind it. ' + repair + ' If a sibling died on a Claude limit, add usage-adaptive routing or route that stage to Codex first (args.models). To rebuild the whole design from scratch instead, re-invoke with args.resume=\'never\'.' }
|
|
2176
2190
|
}
|
|
2177
2191
|
|
|
2178
2192
|
// Step 6: Plan — optionally routed to Codex's top model (opt-in via args.planner='codex').
|
|
@@ -2320,7 +2334,7 @@ if (planGate.verdict !== 'pass') {
|
|
|
2320
2334
|
// NAMED REFUSAL — the run stops here and the coder is never dispatched. This precedes the L/XL
|
|
2321
2335
|
// checkpoint deliberately: an incomplete plan is not something to steer, it is something to fix.
|
|
2322
2336
|
await appendRunCostRow('plan-gate', 'Plan')
|
|
2323
|
-
return { tier: tier, phase: 'plan-gate-failed', slug: SLUG, artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: modelsUsed, planGate: planGate, gates: { plan: (plan ? 'produced' : 'missing'), planCompleteness: planGate.verdict, challengePanel: 'not-run', code: 'not-run', qe: 'not-run' }, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: refusalNoteFor(planGate, SLUG) }
|
|
2337
|
+
return { tier: tier, phase: 'plan-gate-failed', slug: SLUG, artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: modelsUsed, planGate: planGate, gates: { plan: (plan ? 'produced' : 'missing'), planCompleteness: planGate.verdict, challengePanel: 'not-run', code: 'not-run', qe: 'not-run' }, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, recordFailures: recordFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: refusalNoteFor(planGate, SLUG) }
|
|
2324
2338
|
}
|
|
2325
2339
|
|
|
2326
2340
|
// Hybrid checkpoint for L/XL
|
|
@@ -2341,7 +2355,7 @@ if (stopHere) {
|
|
|
2341
2355
|
// presence), never from prose, so a skipped gate shows as 'not-run' instead of being silently forgotten.
|
|
2342
2356
|
const planGates = { plan: (plan ? 'produced' : 'missing'), planCompleteness: planGate.verdict, challengePanel: (challengeVerdict ? 'ran' : 'not-run'), code: 'not-run', qe: 'not-run' }
|
|
2343
2357
|
await appendRunCostRow('plan', 'Plan')
|
|
2344
|
-
return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, challengeVerdict: challengeVerdict, gates: planGates, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'L/XL checkpoint - review the ADR + plan (+ the planned code/qe/fleet models) + the challenge panel verdict (advisory) + the gates line, then re-invoke with args.stopAfter="none" to implement + QE (durable checkpoints make the re-invoke resume router+design+plan instead of re-running them). Present the gates map as a `🚦 Gates:` line in the checkpoint banner, rendering the planCompleteness entry as `K2 plan-completeness ✓` (pass) / `✗` (fail) / `inconclusive`.' }
|
|
2358
|
+
return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, challengeVerdict: challengeVerdict, gates: planGates, resumedStages: resumedStages, checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off', trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off', captureFailures: captureFailures, recordFailures: recordFailures, usageEvents: usageEvents, usageThreshold: USAGE_THRESHOLD, polymorphism: POLY.hasManifest ? POLY.report : null, note: 'L/XL checkpoint - review the ADR + plan (+ the planned code/qe/fleet models) + the challenge panel verdict (advisory) + the gates line, then re-invoke with args.stopAfter="none" to implement + QE (durable checkpoints make the re-invoke resume router+design+plan instead of re-running them). Present the gates map as a `🚦 Gates:` line in the checkpoint banner, rendering the planCompleteness entry as `K2 plan-completeness ✓` (pass) / `✗` (fail) / `inconclusive`.' }
|
|
2345
2359
|
}
|
|
2346
2360
|
|
|
2347
2361
|
// Step 7: Code (optional Codex fallback on Claude-limit exhaustion)
|
|
@@ -2974,7 +2988,7 @@ return {
|
|
|
2974
2988
|
resumedStages: resumedStages,
|
|
2975
2989
|
checkpointing: CHECKPOINTS_ON ? RESUME_MODE : 'off',
|
|
2976
2990
|
trainingPairs: CAPTURE_PAIRS ? TP_DIR : 'off',
|
|
2977
|
-
captureFailures: captureFailures,
|
|
2991
|
+
captureFailures: captureFailures, recordFailures: recordFailures,
|
|
2978
2992
|
reqeDue: reqeDue,
|
|
2979
2993
|
brain: BRAIN,
|
|
2980
2994
|
polymorphism: POLY.hasManifest ? POLY.report : null,
|