@dzhechkov/skills-feature-adr 1.3.56 → 1.3.58

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/bin/cli.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/skills-feature-adr",
3
- "version": "1.3.56",
3
+ "version": "1.3.58",
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"
@@ -13,10 +13,6 @@
13
13
  "CHANGELOG.md",
14
14
  "docs/"
15
15
  ],
16
- "scripts": {
17
- "test": "node --test \"test/**/*.test.js\"",
18
- "prepack": "node -e \"const fs=require('fs');const bad=['.claude','.skills-feature-adr.json'].filter(p=>fs.existsSync(p));if(bad.length){console.error('prepack guard: stray init artifacts in package dir: '+bad.join(', ')+' — remove before packing');process.exit(1)}\""
19
- },
20
16
  "keywords": [
21
17
  "claude",
22
18
  "claude-code",
@@ -61,5 +57,8 @@
61
57
  },
62
58
  "publishConfig": {
63
59
  "access": "public"
60
+ },
61
+ "scripts": {
62
+ "test": "node --test \"test/**/*.test.js\""
64
63
  }
65
- }
64
+ }
@@ -83,3 +83,31 @@ After completion:
83
83
  - Code changes live in the actual codebase (not just in `features/`)
84
84
  - `features/<slug>/` contains the design artifacts (ADRs, diagrams, reports)
85
85
  - These artifacts serve as documentation for the feature
86
+ ## The cost-of-detection ladder (place every check on its cheapest reliable layer)
87
+
88
+ For every quality check the pipeline performs, put it on the **strongest layer that can express it**
89
+ (strong = cheap to run, deterministic, silent-proof). A miss almost always means a check lived one layer
90
+ too weak for its nature:
91
+
92
+ ```
93
+ STRONGEST (cheap, catches 100%, no model needed)
94
+ 1. CI / deterministic test wc -l cap, sha256 pin, grep-guard, dz guard rule
95
+ 2. always-loaded role file architecture/*.md, project-critic — read EVERY run
96
+ 3. pipeline step gate Step-8 QE, claim-check, discrimination-check, amendment gate
97
+ 4. skill judgment "the reviewer will notice" — runs if invoked well
98
+ 5. agent memory / vibes "I should remember to…" — runs if recalled
99
+ WEAKEST (probabilistic, model-dependent, silent when it lapses)
100
+ ```
101
+
102
+ Design rule when adding ANY new check:
103
+ - Deterministic (size, presence, absence, format) → a **repo test / dz guard rule** (layer 1).
104
+ - Structural-but-contextual (a named property must have a proving test) → a **step gate** with a
105
+ machine-checkable output (layer 3) — e.g. the ADR Confirmation link, the amendment gate,
106
+ `dz discrimination-check`.
107
+ - Semantic/adversarial (honesty, product-fit, exploitability) → a **review plane run by an independent
108
+ model** (layer 3, model-backed) — e.g. cross-model QE, challenge-panel. Never leave it to layer-4.
109
+
110
+ Anti-pattern: "the critic/QE agent will catch it" for anything a 5-line test could catch. Every such push
111
+ from layer 1 up to layer 4 turns a deterministic guarantee into a probabilistic one — a future silent miss.
112
+ (Origin: fa-improvements 2026-07-18 — a 700-line cap enforced by reviewer judgment caught one file and
113
+ missed its sibling in the same merge request; `wc -l` catches both, always.)
@@ -723,6 +723,33 @@ rollback semantics are lost; recovery becomes case-by-case repair.
723
723
  operation, not inside its parts. If parts must commit separately,
724
724
  name why and ensure each is independently retryable."
725
725
 
726
+ ### AP14. I/O added to a previously-pure path without a negative resource-down test (HIGH)
727
+
728
+ **Principle:** a change that introduces I/O (DB, network, file) into a
729
+ previously I/O-free path — especially startup/lifespan/health — must
730
+ carry a negative resource-down test proving the declared degradation
731
+ contract (fail-open for advisory, explicit fail-fast for load-bearing),
732
+ not only a happy-path test.
733
+
734
+ **Detection cue:** the code diff adds a DB/network/file call to a
735
+ module that previously imported no I/O; the TEST diff replaces a
736
+ broken/unbound fixture with a healthy one (fixture-swap — the old
737
+ fixture was likely a negative control) with no compensating
738
+ resource-down test; a new I/O call in a startup path has no
739
+ try/except and no test with a dead resource handle.
740
+
741
+ **FP exception:** the path already performed I/O (the change only adds
742
+ another call of the same kind); the new call is wrapped and a negative
743
+ test exists elsewhere covering the same contract (name it).
744
+
745
+ **Why bad:** a resource outage takes down the whole path — including
746
+ health checks — for the sake of the new feature; healthy test fixtures
747
+ hide exactly this case, so it surfaces first in production.
748
+
749
+ **Suggestion direction:** "Keep both tests: healthy fixture (new
750
+ behavior) + broken fixture (degradation contract). State the contract:
751
+ fail-open or fail-fast — and prove it with a dead resource handle."
752
+
726
753
  ---
727
754
 
728
755
  ## Section E. Type / contract issues
@@ -583,6 +583,23 @@ boundary (validator + retry, normalizer) — not a fourth, sterner
583
583
  prompt. Models also send `null` where the schema says `"none"` —
584
584
  tolerate real model behavior at the parsing boundary.
585
585
 
586
+ ### P25. I/O added to a previously-pure path needs a negative resource-down test
587
+
588
+ If your change introduces I/O (DB, network, file) into a path that was
589
+ previously I/O-free — above all a startup, lifespan, or health path —
590
+ the happy-path test is not enough. Also write the NEGATIVE test: a
591
+ broken/unbound resource handle → the path degrades per its declared
592
+ contract (fail-open for an advisory feature, explicit fail-fast for a
593
+ load-bearing one). Otherwise an outage of that resource takes down the
594
+ whole path — including health checks — for the sake of an advisory
595
+ feature, and healthy fixtures will hide it until production.
596
+
597
+ Corollary — the fixture-swap smell: if making new code pass required
598
+ replacing a "broken" test fixture with a healthy one, stop. The old
599
+ fixture was probably a negative control proving the path was I/O-free.
600
+ Keep BOTH tests (healthy = new behavior, broken = degradation
601
+ contract); never silently delete the case that proved the old property.
602
+
586
603
  ---
587
604
 
588
605
  ## Section 7. Decision discipline
@@ -589,6 +589,7 @@ npx @dzhechkov/skills-feature-adr init --with-learning --knowledge-extractor
589
589
  <promise>[PROMISE_TAG]</promise>
590
590
  Tier: {COMPLEXITY_TIER} | Active Steps: {ACTIVE_STEPS}
591
591
  🎓 Learning: {recalled} patterns recalled for this feature, {stored} new stored this run
592
+ 🚦 Gates: challenge-panel ✓ · claim-check ✓ · discrimination not-run · amendments ✓ · fleet —
592
593
 
593
594
  [2-3 line summary]
594
595
  Artifacts: [list] ✅
@@ -598,3 +599,16 @@ Artifacts: [list] ✅
598
599
  • "[feedback]" — adjust
599
600
  ═══════════════════════════════════════════════════════
600
601
  ```
602
+
603
+ ### The 🚦 Gates line (mandatory, DERIVED — never asserted from memory)
604
+
605
+ Every checkpoint banner carries a `🚦 Gates:` line listing each gate relevant to the run so far. Symbols:
606
+ `✓` ran and passed · `✗` ran and failed · `not-run` pending · `—` N/A for this tier/slice (say why once).
607
+ Each value is **derived from machine-checkable state** — an artifact's existence, a command's JSON verdict, a
608
+ test result — never from what the orchestrator remembers doing. The line does not make a gate run; it makes
609
+ NOT running one loud: a skipped gate shows as `not-run` by construction instead of being silently forgotten
610
+ (cost-of-detection ladder: the banner is the one surface emitted at EVERY step boundary, so strapping the
611
+ checklist to it is the cheapest way to harden orchestrator judgment). Gate sources: challenge-panel → its
612
+ verdict exists; claim-check → its JSON counts (`high-findings` vs `clean`); discrimination → the
613
+ `dz discrimination-check` aggregate; amendments → every `AM-N` row carries its `→ test` and it was checked;
614
+ fleet → the 09 artifact (L/XL only, else `—`).
@@ -119,7 +119,8 @@ After all agents complete, apply decision logic:
119
119
  | Critical Risks | > 2 | 1-2 | 0 |
120
120
 
121
121
  - **NO-GO**: BLOCK. Requirements/ADR need rework. Return to Step 1 or Step 3.
122
- - **CONDITIONAL**: Proceed with warnings. Pass findings to Steps 6-8 as advisory context.
122
+ - **CONDITIONAL**: Proceed with warnings. Each condition becomes an **amendment row** in a `## Amendments`
123
+ section (see below) — not loose advisory prose.
123
124
  - **GO**: Full confidence. Proceed to Step 6.
124
125
 
125
126
  ### 5. Synthesis Report
@@ -132,6 +133,26 @@ Generate consolidated `03.5_ideation_report.md` with:
132
133
  5. Test ideas (categorized: unit / integration / E2E)
133
134
  6. Conditional agent findings (if any)
134
135
  7. Recommendations prioritized by risk × impact
136
+ 8. `## Amendments` — on a CONDITIONAL verdict, every condition as a fixed-shape row (see below)
137
+
138
+ ### Amendment Confirmation discipline (every amendment is a mini-ADR)
139
+
140
+ Amendments are where the sharpest design corrections land — and, historically, the least-tested part of a
141
+ run: they arrive as prose AFTER the ADR's Confirmation discipline already ran, so a coder can implement one
142
+ with no test proving it works. Therefore every amendment carries a one-line **Confirmation**, in a fixed,
143
+ machine-checkable shape:
144
+
145
+ ```
146
+ AM-N (source): <change>. Confirmation: <property> → test `test_name` (fails if reverted).
147
+ ```
148
+
149
+ - `source` names where it came from (qcsd | challenge-panel | user-steer).
150
+ - The named test must FAIL if the amendment were reverted/broken (non-vacuous — Step 8 verifies via
151
+ `dz discrimination-check`).
152
+ - For a **safeguard** amendment (a warning/guard/fallback): the test must prove the safeguard actually
153
+ **TRIGGERS on a real input** — not merely that its code path exists. A structurally-dead safeguard passes
154
+ an existence test and never fires in production.
155
+ - A cheap lint holds the shape: every `AM-N` line must contain a `→ test ` token naming a test that exists.
135
156
 
136
157
  ## Output
137
158
 
@@ -149,6 +149,11 @@ Create `features/<slug>/06_implementation_plan.md` with:
149
149
  - Parallel groups
150
150
  - Checkpoint schedule
151
151
  - Risk assessment (L/XL)
152
+ - `## Amendments` — every correction folded into this plan (a Step-3.5 CONDITIONAL condition, a
153
+ challenge-panel confirmed finding, a user checkpoint steer) as a fixed-shape row:
154
+ `AM-N (source): <change>. Confirmation: <property> → test `test_name` (fails if reverted).`
155
+ A safeguard amendment's named test must prove it TRIGGERS on a real input, not merely that its code
156
+ path exists. Step 8 verifies every named test exists and is non-vacuous (`dz discrimination-check`).
152
157
 
153
158
  Set `{IMPL_PLAN}` variable.
154
159
 
@@ -31,6 +31,24 @@ Before writing any code:
31
31
  - [ ] Identify import patterns and module structure
32
32
  - [ ] Identify error handling patterns
33
33
  - [ ] Identify test patterns
34
+ - [ ] Plan carries `## Amendments`? → implement every AM-N row AND its named Confirmation test (a
35
+ safeguard amendment needs a test proving it FIRES on a real input)
36
+ - [ ] Does the diff add I/O (DB/network/file) to a previously-pure path — especially
37
+ startup/lifespan/health? → name the NEGATIVE resource-down test, or justify N/A
38
+
39
+ ### The I/O-on-pure-path rule (and the fixture-swap smell)
40
+
41
+ If a change introduces I/O into a path that was previously I/O-free — above all a startup, lifespan, or
42
+ health path — the happy-path test is NOT enough. Also write a **negative resource-down test**: a
43
+ broken/unbound resource handle (dead DB, missing table, exhausted pool) → the path degrades per its
44
+ declared contract — **fail-open** for an advisory feature, **explicit fail-fast** for a load-bearing one.
45
+ Without it, an outage of the resource takes down the whole path (including health checks) for the sake of
46
+ an advisory feature — and healthy test fixtures will hide it.
47
+
48
+ **Fixture-swap smell:** if making the new code pass required replacing a "broken" test fixture with a
49
+ healthy one — stop. The old fixture was probably a negative control proving the path was I/O-free. Keep
50
+ BOTH tests: the healthy one (new behavior) and the broken one (degradation contract). Never silently
51
+ delete the case that proved the old property.
34
52
 
35
53
  ### 2. Execute Tasks per Plan
36
54
 
@@ -158,6 +158,30 @@ Reject explainer-masquerading-as-ADR: if the document describes a problem space
158
158
 
159
159
  The Confirmation-to-test link is load-bearing. If absent, grade no better than C and record a blocker gap; for architecture dependency/layering/interface rules, recommend an ArchUnit or ArchUnitTS fitness function.
160
160
 
161
+ ### 3b. Amendment Gate (P2 — amendments inherit the Confirmation discipline)
162
+
163
+ Read the `## Amendments` sections of `03.5_ideation_report.md` and `06_implementation_plan.md` (skip
164
+ silently if absent). For EVERY `AM-N` row verify:
165
+ 1. the row contains a `→ test ` token naming a real test (the fixed shape);
166
+ 2. the named test **exists** in the suite;
167
+ 3. it is **non-vacuous** — include the amendment test files in the SAME
168
+ `dz discrimination-check --test <f1,f2,...> --base HEAD --json` run as the ADR property test. An
169
+ amendment test that stays green at pre-feature base proves nothing about its amendment;
170
+ 4. a **safeguard** amendment's test proves the safeguard FIRES on a real input (a structurally-dead
171
+ safeguard passes an existence test and never fires in production).
172
+
173
+ A missing, unnamed, or vacuous amendment test is a HIGH gap. This closes the distance between "we caught
174
+ the design flaw" (challenge-panel/QCSD) and "we proved the fix works".
175
+
176
+ ### 3c. I/O-on-pure-path + fixture-swap hunt (P5)
177
+
178
+ In the TEST diff, hunt for replacements of broken/unbound fixtures with healthy ones — the old fixture was
179
+ probably a **negative control** proving a path was I/O-free; each such swap requires a compensating
180
+ negative resource-down test. In the CODE diff, hunt for new I/O (DB/network/file) on previously-pure
181
+ paths — especially startup/lifespan/health: require a negative resource-down test (broken resource → the
182
+ path degrades per its declared contract: fail-open for advisory, explicit fail-fast for load-bearing).
183
+ Missing → HIGH gap.
184
+
161
185
  ### 4. Multi-Agent Review Panel (L/XL)
162
186
 
163
187
  For L/XL features, spawn 3 parallel review agents using brutal-honesty modes:
@@ -555,6 +555,19 @@ const PROJECT_SKILLS = { type: 'object', additionalProperties: false, required:
555
555
  const QE = { type: 'object', additionalProperties: false, required: ['grade', 'gaps', 'codeTestsAdequate', 'docTestsPresent'], properties: { grade: { type: 'string' }, codeTestsAdequate: { type: 'boolean' }, docTestsPresent: { type: 'boolean' }, gaps: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['sev', 'what'], properties: { sev: { type: 'string' }, what: { type: 'string' } } } }, claimCheck: { type: 'object', additionalProperties: false, properties: { findings: { type: 'number' }, high: { type: 'number' }, medium: { type: 'number' } } } } }
556
556
  const ADR_TEMPLATE_GUIDE = 'ADR best-practices for Step 3: emit exactly one decision per ADR with the invariant core Title, Status, Context, Decision, Consequences. Template weight is tier-routed: S/M use Nygard/ITD-lightweight form but still include decision drivers, considered options, rationale, consequences, and Confirmation; L/XL use MADR structure plus an NHS Wales Confirmation stanza. Confirmation MUST name verification method, monitoring, success metric, and owner, and its load-bearing safety property MUST be tied to a Step-8 automated test/fitness function. Use status vocabulary proposed/accepted/rejected/deprecated/superseded plus a reversibility clause. Context must be neutral and appear before Decision. Considered Options must include rejected options with symmetric pros/cons. Rationale points must map to stated drivers and explain why losers were rejected. Consequences must include positive and negative outcomes/accepted downsides, follow-up ADR links, an after-action review schedule, and supersession discipline: supersession mints a new ADR and never edits accepted/rejected ADR content in place. Decision must be concrete/testable with exact names, versions, formats, paths, commands, or APIs. Reject explainer-masquerading-as-ADR: a domain overview with no concrete Decision is not an ADR. File names under 03_adr MUST be sequential NNN-{decision-slug}.md with lowercase kebab-case, dateless, ticketless slugs (the auto-001 ADR tracks the feature slug, so the present-tense imperative signal lives in the ADR Title; model-named additional ADRs use imperative slugs). Add a ## Links traceability block (requirements, driving use case, related ADRs) and a one-line provenance note (model-generated, edited for clarity); for a long ADR include a top-of-file table of contents.'
557
557
  const ADR_FITNESS_CHECKLIST = 'ADR fitness checklist for Step 8: read every ' + FDIR + '/03_adr/NNN-*.md ADR and fail the QE gate for any miss. Required checks: (1) filename is 03_adr/NNN-{decision-slug}.md where the slug is lowercase kebab-case, imperative, dateless, and ticketless; (2) title is decision-shaped and the ADR records one decision only; (3) Status is non-empty controlled vocabulary proposed/accepted/rejected/deprecated/superseded and includes a reversibility/revisit clause; (4) Context is neutral, problem-first, and appears before Decision; (5) Decision Drivers are stated and ranked/weighted; (6) Considered Options include the chosen and rejected options, each with symmetric pros and cons; (7) Rationale maps each point back to a driver and explains why rejected options lost; (8) Decision is concrete/testable with exact names, versions, formats, paths, commands, or APIs; (9) Consequences include positive and negative outcomes/accepted downsides, follow-up ADR links, and an after-action review schedule; (10) Confirmation names verification method, monitoring, success metric, and owner, then links the load-bearing safety property to an automated test/fitness function; (11) no placeholder text, template hints, raw generation scaffolding, or fake Markdown structure; (12) reject explainer-masquerading-as-ADR: describing a space with no concrete Decision is a blocker; (13) a Related/Links traceability block maps the ADR to its requirements, driving use case, and related ADRs. The ADR Confirmation check is load-bearing: assert the named safety property has a real test by file/name; if absent, grade no better than C and record a blocker gap.'
558
+ // §42 test-discrimination gate (feature step8-discrimination-gate, grounded in cve-bench/evaluate.mjs). Asserting
559
+ // the property HAS a test is presence; this asserts it DISCRIMINATES. Advisory — a false green is a HIGH gap, never
560
+ // an auto-abort (dz's rule: a false gate kills trust). Byte-inlined guidance; the safe worktree/run lives in `dz
561
+ // discrimination-check` (harness-core/src/discrimination-gate.ts).
562
+ const DISCRIMINATION_GATE = '§42 TEST-DISCRIMINATION GATE (run right after asserting the property has a test): the ADR Confirmation names `Required automated check: <test file>` for the load-bearing property. Prove that test DISCRIMINATES, not just that it is green — via Bash run EXACTLY `dz discrimination-check --test <that test file> --base HEAD --json` (the Step-7 feature diff is UNCOMMITTED, so HEAD is the pre-feature base). It runs the property test in an isolated git worktree at HEAD (no feature diff) and reports {aggregate, finding}. Parse it: `NON_DISCRIMINATING` = the test PASSES even without the fix (a false green that would stay green if the property regressed) → record a HIGH gap "property test does not discriminate: <file>" but do NOT drop the grade to a blocker on that alone (advisory — the owner decides). `DISCRIMINATES` (red by assertion) and `DISCRIMINATES_VIA_ERROR` (could not load at base — inferred, note it) both PASS. `CANNOT_ISOLATE` folds into the existing "property untested" finding. Record the verdict in the 08_qe_report.md ADR Fitness section. If `dz discrimination-check` is unavailable, note it and continue — never block on the tool.'
563
+ // P2 (amendment-confirmation-discipline, fa-improvements 2026-07-18): amendments are where the SHARPEST design
564
+ // corrections land (challenge-panel/QCSD) and were the least-tested — prose deltas with no proving test. Every
565
+ // amendment is a mini-ADR: it carries a one-line Confirmation naming the test that falsifies it. Machine-checkable
566
+ // shape (a linter can assert the `→ test ` token); Step-8 verifies existence + non-vacuity via the SAME
567
+ // dz discrimination-check that guards the ADR property (cost-of-detection ladder: judgment → step gate).
568
+ 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).'
569
+ const AMENDMENT_GATE = 'AMENDMENT GATE (P2): read the `## Amendments` sections of ' + FDIR + '/03.5_ideation_report.md and ' + FDIR + '/06_implementation_plan.md (skip silently if absent). EVERY `AM-N` row must contain a `→ test ` token naming a real test. Verify: (a) the named test EXISTS in the suite; (b) it is NON-VACUOUS — include the amendment test files in the SAME `dz discrimination-check --test <f1,f2,...> --base HEAD --json` run as the ADR property test (an amendment test that stays green at pre-feature base proves nothing); (c) a safeguard amendment\'s test proves the safeguard FIRES on a real input. A missing, unnamed, or vacuous amendment test is a HIGH gap. ' +
570
+ '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.'
558
571
 
559
572
  // Step 0: Router + MANDATORY self-learning recall
560
573
  phase('Router')
@@ -651,7 +664,7 @@ modelsUsed.ddd = modelLabel(archOpts)
651
664
  designThunks.push(() => designStage('Step 1 (Requirements)' + (isLplus ? ' + Step 2 (Research)' : '') + ' of /feature-adr for "' + DESC + '" (tier ' + tier + ', slug ' + SLUG + '). Code: ' + CODE_HINT + '. APPLY these Step-0 recalled LEARNED PATTERNS (fold the applicable ones into requirements/constraints - the loop paying off): ' + LEARNED + '. Write ' + FDIR + '/01_requirements.md (functional + non-functional requirements, acceptance criteria, constraints, and an "Applied learned patterns" note).' + reqExtra + ' Return wrote[] + a 1-line summary.' + PS_GUIDANCE('design'), reqOpts, FDIR + '/01_requirements.md', 'requirements'))
652
665
  if (isMplus) {
653
666
  designThunks.push(() => designStage('Step 3 (ADR + shift-left testability) of /feature-adr for "' + DESC + '" (' + SLUG + '). READ the actual code (' + CODE_HINT + ') to ground it. ' + ADR_TEMPLATE_GUIDE + ' Write ' + FDIR + '/03_adr/001-' + SLUG + '.md as a MADR-structured ADR that PASSES the Step-8 ADR fitness checklist (do NOT emit the legacy shape). Emit ALL of these sections, in order: a decision-shaped # Title (present-tense imperative verb — the auto-filename tracks the feature slug, so the IMPERATIVE signal lives in the title); ## Status (proposed/accepted/rejected/deprecated/superseded + a reversibility/revisit clause); ## Context (neutral, problem-first, BEFORE the Decision); ## Decision Drivers (ranked/weighted D1, D2, …); ## Considered Options (frame the CHOSEN approach as one option ALONGSIDE the rejected ones, each with symmetric Pros:/Cons:); ## Decision (concrete/testable — exact names, versions, paths, commands); ## Rationale (map each point to a driver Dn + why the losers lost); ## Consequences (Positive + Negative/Accepted Downsides + Follow-up ADRs + After-action Review with owner + date); a REQUIRED ## Confirmation stanza with Method:, Monitoring:, Success metric:, Owner:, Load-bearing property:, and Required automated check: `<test file>` NAMING the load-bearing property that MUST have a Step-8 test (the recurring lesson: the key safety property is often the untested one); and a ## Links traceability block (requirements, driving use case, related ADRs). Add a one-line provenance note (model-generated, edited for clarity) and, for a long ADR, a top-of-file table of contents. Do NOT use an "Alternatives considered" or "Testability/shift-left" heading in place of Considered Options / Confirmation. When creating ADDITIONAL ADRs, name them 03_adr/NNN-{decision-slug}.md with a lowercase-kebab, present-tense imperative, dateless, ticketless slug. Return wrote[] + summary.', adrOpts, FDIR + '/03_adr/001-' + SLUG + '.md', 'adr'))
654
- designThunks.push(() => designStage('Step 3.5 (QCSD ideation swarm - HTSM quality criteria + SFDIPOT risk) of /feature-adr for "' + DESC + '" (' + SLUG + '). Assess quality criteria + product-factors risk. Write ' + FDIR + '/03.5_ideation_report.md with a GO/CONDITIONAL/NO-GO verdict + top quality risks for QE. Return wrote[] + summary.', qcsdOpts, FDIR + '/03.5_ideation_report.md', 'qcsd'))
667
+ designThunks.push(() => designStage('Step 3.5 (QCSD ideation swarm - HTSM quality criteria + SFDIPOT risk) of /feature-adr for "' + DESC + '" (' + SLUG + '). Assess quality criteria + product-factors risk. Write ' + FDIR + '/03.5_ideation_report.md with a GO/CONDITIONAL/NO-GO verdict + top quality risks for QE. On a CONDITIONAL verdict, write each condition as an amendment row in a `## Amendments` section. ' + AMENDMENT_RULE + ' Return wrote[] + summary.', qcsdOpts, FDIR + '/03.5_ideation_report.md', 'qcsd'))
655
668
  const archExtra = isLplus ? ' Also ' + FDIR + '/04_domain_model.md (DDD).' : ''
656
669
  designThunks.push(() => designStage((isLplus ? 'Step 4 (DDD) + ' : '') + 'Step 5 (Architecture) of /feature-adr for "' + DESC + '" (' + SLUG + '). READ the code. Write ' + FDIR + '/05_architecture.md (components, data flow, integration points, the emit/merge/wiring shape).' + archExtra + ' Return wrote[] + summary.', archOpts, FDIR + '/05_architecture.md', 'architecture'))
657
670
  }
@@ -663,7 +676,7 @@ const design = await parallel(designThunks)
663
676
  // unavailable/errors — the pipeline never blocks on Codex.
664
677
  phase('Plan')
665
678
  await usageProbe('Plan')
666
- const planPrompt = 'Step 6 (SPARC-GOAP implementation plan) of /feature-adr for "' + DESC + '" (' + SLUG + ', tier ' + tier + '). Given the requirements + ADR + architecture in ' + FDIR + ', decompose into milestones + concrete tasks with success metrics. Write ' + FDIR + '/06_implementation_plan.md. Return wrote[] + summary.' + ABSOLUTE_PATH_NOTE
679
+ const planPrompt = 'Step 6 (SPARC-GOAP implementation plan) of /feature-adr for "' + DESC + '" (' + SLUG + ', tier ' + tier + '). Given the requirements + ADR + architecture in ' + FDIR + ', decompose into milestones + concrete tasks with success metrics. Write ' + FDIR + '/06_implementation_plan.md. If any corrections from Step 3.5 (a CONDITIONAL verdict) or other sources are folded into this plan, carry them in a `## Amendments` section. ' + AMENDMENT_RULE + ' Return wrote[] + summary.' + ABSOLUTE_PATH_NOTE
667
680
  // Resolve the plan model. args.models.plan wins; else the planner:'codex' knob (via routingRequested +
668
681
  // DEFAULT_MODELS/coder-fold) or the DEFAULT_MODELS.plan ('sonnet') under routing; else {} (BC).
669
682
  const planModel = resolveStageModel('plan')
@@ -774,13 +787,16 @@ if (stopHere) {
774
787
  let challengeVerdict = null
775
788
  try { challengeVerdict = plan ? await runChallengePanel('features/' + SLUG + '/06_implementation_plan.md', plan.planner) : null }
776
789
  catch (e) { log('Challenge panel errored (advisory, ignored): ' + (e && e.message ? e.message : String(e))) }
777
- return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, challengeVerdict: challengeVerdict, 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), then re-invoke with args.stopAfter="none" to implement + QE.' }
790
+ // P4 (checkpoint-gate-line): a DERIVED gates map each entry comes from machine state (artifact/verdict
791
+ // presence), never from prose, so a skipped gate shows as 'not-run' instead of being silently forgotten.
792
+ const planGates = { plan: (plan ? 'produced' : 'missing'), challengePanel: (challengeVerdict ? 'ran' : 'not-run'), code: 'not-run', qe: 'not-run' }
793
+ 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, 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. Present the gates map as a `🚦 Gates:` line in the checkpoint banner.' }
778
794
  }
779
795
 
780
796
  // Step 7: Code (optional Codex fallback on Claude-limit exhaustion)
781
797
  phase('Code')
782
798
  await usageProbe('Code')
783
- const codePrompt = 'Step 7 (Code) of /feature-adr for "' + DESC + '" (' + SLUG + '). Implement the feature per the plan + ADR + architecture in ' + FDIR + '. Write the ACTUAL production code + its tests (mirror the closest existing implementation named in research/architecture). Follow repo conventions; build must pass. Write a change manifest ' + FDIR + '/07_code_changes/change_manifest.md listing every file touched. Return wrote[] (incl. real source files) + summary.' + ABSOLUTE_PATH_NOTE + PS_GUIDANCE('code')
799
+ const codePrompt = 'Step 7 (Code) of /feature-adr for "' + DESC + '" (' + SLUG + '). Implement the feature per the plan + ADR + architecture in ' + FDIR + '. Write the ACTUAL production code + its tests (mirror the closest existing implementation named in research/architecture). If the plan carries a `## Amendments` section, implement every AM-N row AND its named Confirmation test (for a safeguard amendment: a test proving it FIRES on a real input). IO-ON-PURE-PATH RULE: if your diff adds I/O (DB/network/file) to a previously-pure path — especially a startup/lifespan/health path — also write a NEGATIVE resource-down test (broken/unbound resource handle → the path degrades per its declared contract: fail-open for an advisory feature, explicit fail-fast for a load-bearing one) alongside the happy-path test; never fix a failing test by swapping a broken fixture for a healthy one without keeping BOTH cases. Follow repo conventions; build must pass. Write a change manifest ' + FDIR + '/07_code_changes/change_manifest.md listing every file touched. Return wrote[] (incl. real source files) + summary.' + ABSOLUTE_PATH_NOTE + PS_GUIDANCE('code')
784
800
  // Resolve the coder model. args.models.code wins (a direct 'codex' spec = codex-first); else the legacy
785
801
  // CODER knob drives it (with its codex-fallback null-guard). resolveStageModel('code') folds both via the
786
802
  // code:null sentinel → resolveCoderSpec(). A Claude resolution merges {model} onto the Claude branch;
@@ -822,7 +838,7 @@ if (needsCodeLandedBarrier(coderUsed)) {
822
838
  // Step 8: QE (brutal-honesty, agentic-qe) + MANDATORY teach
823
839
  phase('QE')
824
840
  await usageProbe('QE')
825
- const qePrompt = 'Step 8 (QE - brutal-honesty review, agentic-qe) of /feature-adr for "' + DESC + '" (' + SLUG + '). Adversarially review the SHIPPED code (read it): correctness, edge cases, error handling, and the LOAD-BEARING property the ADR named (ASSERT it has a test - the recurring lesson). Run this ADR gate before final grading: ' + ADR_FITNESS_CHECKLIST + ' Grade A/B/C/D honestly. Assess code-test adequacy + doc-test presence. List CONFIRMED gaps with severity. Write ' + FDIR + '/08_qe_report.md with an ADR Fitness Checklist section showing PASS/FAIL per ADR and evidence for the Confirmation-linked test. MANDATORY SELF-LEARNING STORE (close the loop, never skip): compare every candidate lesson against the Step-0 recalled LEARNED patterns above. Teach ONLY lessons NOT covered by Step-0 recall. On overlap, run `dz teach --reinforce "<recalled pattern id or exact text>" --project ' + BRAIN + '` instead of minting a near-duplicate; if --reinforce is unavailable, skip the duplicate teach and report `reinforced existing pattern <id>` in the QE report. Store every genuinely new lesson in the CANONICAL BRAIN store at `' + BRAIN + '` so it is NOT lost to a target repo you may have cd`d into. Via Bash run EXACTLY `' + DZ_TEACH('<a durable reusable lesson from this feature - a rule/pattern/pitfall, NOT a checkpoint echo>', '<0.7-0.95>', '<area>') + '` for each genuine NEW lesson (1-3 max, high-signal) — the `cd ' + BRAIN + ' &&` prefix + `--project ' + BRAIN + '` pin guarantee the lesson lands in the brain regardless of your CWD. Then run `' + DZ + ' statusline --fa-record --slug ' + SLUG + ' --step "Step 8 QE" --recalled 3 --stored <count taught> --reinforced <count reinforced> --mode ' + MODE + ' --project ' + REPO + '` (run it verbatim via Bash, do not skip). Do NOT teach trivia or invent gaps. AUTHORING-TIME CLAIM-CHECK (Deliverable of claim-check-authoring-time): after writing ' + FDIR + '/08_qe_report.md, run EXACTLY `dz claim-check ' + FDIR + '/08_qe_report.md --json --fail-on none` via Bash, parse the {ok, findings, scanned} JSON, and report claimCheck: {findings: N, high: N, medium: N} (counts by severity) in your return object. TAG EVERY QUANTITATIVE CLAIM you write in the report using the convention the checker recognizes as honest — write "1131 tests pass (MEASURED — `npx vitest run`)", never a bare "1131 tests pass" — and where you QUOTE a forbidden phrase as an example (e.g. the retracted "100% passing" framing), backtick the literal so it reads as code, not an assertion, so your own compliant report scans clean. Return {grade, gaps, codeTestsAdequate, docTestsPresent, claimCheck}.' + ABSOLUTE_PATH_NOTE + landedNote + PS_GUIDANCE('qe')
841
+ const qePrompt = 'Step 8 (QE - brutal-honesty review, agentic-qe) of /feature-adr for "' + DESC + '" (' + SLUG + '). Adversarially review the SHIPPED code (read it): correctness, edge cases, error handling, and the LOAD-BEARING property the ADR named (ASSERT it has a test - the recurring lesson). Run this ADR gate before final grading: ' + ADR_FITNESS_CHECKLIST + ' ' + DISCRIMINATION_GATE + ' ' + AMENDMENT_GATE + ' Grade A/B/C/D honestly. Assess code-test adequacy + doc-test presence. List CONFIRMED gaps with severity. Write ' + FDIR + '/08_qe_report.md with an ADR Fitness Checklist section showing PASS/FAIL per ADR and evidence for the Confirmation-linked test. MANDATORY SELF-LEARNING STORE (close the loop, never skip): compare every candidate lesson against the Step-0 recalled LEARNED patterns above. Teach ONLY lessons NOT covered by Step-0 recall. On overlap, run `dz teach --reinforce "<recalled pattern id or exact text>" --project ' + BRAIN + '` instead of minting a near-duplicate; if --reinforce is unavailable, skip the duplicate teach and report `reinforced existing pattern <id>` in the QE report. Store every genuinely new lesson in the CANONICAL BRAIN store at `' + BRAIN + '` so it is NOT lost to a target repo you may have cd`d into. Via Bash run EXACTLY `' + DZ_TEACH('<a durable reusable lesson from this feature - a rule/pattern/pitfall, NOT a checkpoint echo>', '<0.7-0.95>', '<area>') + '` for each genuine NEW lesson (1-3 max, high-signal) — the `cd ' + BRAIN + ' &&` prefix + `--project ' + BRAIN + '` pin guarantee the lesson lands in the brain regardless of your CWD. Then run `' + DZ + ' statusline --fa-record --slug ' + SLUG + ' --step "Step 8 QE" --recalled 3 --stored <count taught> --reinforced <count reinforced> --mode ' + MODE + ' --project ' + REPO + '` (run it verbatim via Bash, do not skip). Do NOT teach trivia or invent gaps. AUTHORING-TIME CLAIM-CHECK (Deliverable of claim-check-authoring-time): after writing ' + FDIR + '/08_qe_report.md, run EXACTLY `dz claim-check ' + FDIR + '/08_qe_report.md --json --fail-on none` via Bash, parse the {ok, findings, scanned} JSON, and report claimCheck: {findings: N, high: N, medium: N} (counts by severity) in your return object. TAG EVERY QUANTITATIVE CLAIM you write in the report using the convention the checker recognizes as honest — write "1131 tests pass (MEASURED — `npx vitest run`)", never a bare "1131 tests pass" — and where you QUOTE a forbidden phrase as an example (e.g. the retracted "100% passing" framing), backtick the literal so it reads as code, not an assertion, so your own compliant report scans clean. Return {grade, gaps, codeTestsAdequate, docTestsPresent, claimCheck}.' + ABSOLUTE_PATH_NOTE + landedNote + PS_GUIDANCE('qe')
826
842
  // CROSS-MODEL QE (load-bearing): resolveStageModel('qe') derives the OTHER family than the resolved
827
843
  // coder when args.models.qe is unset (coder-codex ⇒ opus; coder-Claude ⇒ codex, or opus if codex absent).
828
844
  // An explicit args.models.qe wins. A Claude qe spec is merged onto the qe-code-reviewer base (role
@@ -969,5 +985,12 @@ return {
969
985
  polymorphism: POLY.hasManifest ? POLY.report : null,
970
986
  claimGate: claimGate,
971
987
  autoCost: Object.keys(AUTOCOST).length ? AUTOCOST : null,
988
+ // P4 (checkpoint-gate-line): DERIVED gate map for the final banner — from actual run state, never prose.
989
+ gates: {
990
+ code: (code ? 'produced' : 'missing'),
991
+ qe: (qe ? (qe.grade || 'ran') : 'not-run'),
992
+ claimCheck: (qe && qe.claimCheck ? (qe.claimCheck.high > 0 ? 'high-findings' : 'clean') : 'not-run'),
993
+ fleet: (isLplus ? (fleet ? 'ran' : 'not-run') : 'n/a'),
994
+ },
972
995
  promiseTags: tags,
973
996
  }