@dzhechkov/skills-feature-adr 1.3.64 → 1.3.66
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 +11 -7
- package/README.md +16 -2
- package/package.json +1 -1
- package/sbom.json +16 -6
- package/templates/.claude/skills/feature-adr/SKILL.md +39 -7
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +48 -4
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +14 -1
- package/templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs +166 -0
- package/templates/.claude/workflows/feature-adr.js +918 -77
package/.dz-manifest.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "README.md",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "5cca2d4a5337177ee9a072d49d14f73386af75398f52d907d757d4c052afdf81"
|
|
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": "b76f1b1d1ce3d8b22be0c2354fe3bd22833513da8b418c7c93423ae75f4018ae"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "scripts/sync-templates.js",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"path": "templates/.claude/skills/feature-adr/SKILL.md",
|
|
124
|
-
"sha256": "
|
|
124
|
+
"sha256": "02d2a081e4bc9e7f5d42e55a4e21a68484af8b45216ff74fe5fc4322cb689a96"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"path": "templates/.claude/skills/feature-adr/examples/sample-feature-output.md",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"path": "templates/.claude/skills/feature-adr/modules/06-implementation-plan.md",
|
|
160
|
-
"sha256": "
|
|
160
|
+
"sha256": "443043f6f3a3c2ebdcc4d40f9d13d799581056fb37890a2bb1fa61662825229b"
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"path": "templates/.claude/skills/feature-adr/modules/07-code.md",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"path": "templates/.claude/skills/feature-adr/modules/08-qe.md",
|
|
168
|
-
"sha256": "
|
|
168
|
+
"sha256": "97e9a7bc54f196b381c4ef71258cddcb2fb48f216df1ba015927c176bad57084"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"path": "templates/.claude/skills/feature-adr/modules/09-fleet-qe.md",
|
|
@@ -255,6 +255,10 @@
|
|
|
255
255
|
"path": "templates/.claude/skills/feature-adr/references/qe-checklist.md",
|
|
256
256
|
"sha256": "238d8896996dc53559f58b24aa7eca966cc8845c3b9dda6d982c717c657b91e4"
|
|
257
257
|
},
|
|
258
|
+
{
|
|
259
|
+
"path": "templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs",
|
|
260
|
+
"sha256": "41d85b012a9d6cc172eaa5d7777294f2c01fb54b752ed61c7cbe2d2cd7b79b67"
|
|
261
|
+
},
|
|
258
262
|
{
|
|
259
263
|
"path": "templates/.claude/skills/frontend-design/LICENSE.txt",
|
|
260
264
|
"sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594"
|
|
@@ -317,7 +321,7 @@
|
|
|
317
321
|
},
|
|
318
322
|
{
|
|
319
323
|
"path": "templates/.claude/workflows/feature-adr.js",
|
|
320
|
-
"sha256": "
|
|
324
|
+
"sha256": "4904cf2040f024647c561fb5bd11aab5c7c0b70190dc4505b1bd69572cf25072"
|
|
321
325
|
},
|
|
322
326
|
{
|
|
323
327
|
"path": "templates/lib/memory-protocol.md",
|
|
@@ -345,5 +349,5 @@
|
|
|
345
349
|
}
|
|
346
350
|
]
|
|
347
351
|
},
|
|
348
|
-
"signature": "
|
|
352
|
+
"signature": "nKR64NSSz41u0CCXl4HdsXqTmS5QUqIIYZdRn4xVoEj/wuzF7Vb7X21mte94etpLINVimxi1pTdUQYOO5GlyCw=="
|
|
349
353
|
}
|
package/README.md
CHANGED
|
@@ -274,8 +274,13 @@ Workflow({ scriptPath: '.claude/workflows/feature-adr.js',
|
|
|
274
274
|
|
|
275
275
|
> Note: under the override, coder **and** QE both run on Codex — the cross-model self-QE guard is
|
|
276
276
|
> consciously suspended (a Claude QE reviewer is exactly the agent that dies under limit pressure). The
|
|
277
|
-
> ` (usage-switched)` suffix + `usageEvents` keep it auditable
|
|
278
|
-
>
|
|
277
|
+
> ` (usage-switched)` suffix + `usageEvents` keep it auditable — and since v1.3.65 the suspension is a
|
|
278
|
+
> **machine debt**, not a note: the run writes `features/<slug>/.fa-state/reqe-due.json` (idempotent,
|
|
279
|
+
> run-stamped, crash-resume-safe) and returns `reqeDue: true`; after limits reset, `dz usage` shows a
|
|
280
|
+
> `re-QE due:` line, `dz reqe --slug <s>` prints the cross-family review brief, and
|
|
281
|
+
> `dz reqe --slug <s> --done --report <f>` settles FAIL-CLOSED — only against an existing graded
|
|
282
|
+
> report, never the run's own 08_qe_report.md (real-path and inode compared). RU: «перепроверь другой
|
|
283
|
+
> семьёй потом» стало долгом на диске с полным жизненным циклом.
|
|
279
284
|
|
|
280
285
|
---
|
|
281
286
|
|
|
@@ -526,6 +531,15 @@ gate > reviewer judgment > memory). A miss usually means a check lived one layer
|
|
|
526
531
|
control that proved the path was I/O-free. The bundled role-default skills gained the matching entries
|
|
527
532
|
(`code-impl` P25, `code-critic` AP14).
|
|
528
533
|
|
|
534
|
+
- **No-stubs gate** (backlog 0b403a0106103901, Karpathy-Michaels rule XI). Step 8 greps the files THE RUN
|
|
535
|
+
touched for unfinished-stub markers — `TODO` / `FIXME` / `HACK` / `XXX` / `PLACEHOLDER` (case-sensitive,
|
|
536
|
+
word-bounded: `hackathon`/`todos` never fire) plus the `implement later` phrase — **any unwaived match =
|
|
537
|
+
the task shipped incomplete** (HIGH gap naming file:line). A line may carry an inline
|
|
538
|
+
`no-stubs: <reason>` waiver; a waiver **without** a reason is itself a HIGH gap, never an exemption. The
|
|
539
|
+
same scan runs mechanically at publish time as the SOFT `no-stubs` rule in `dz guard check --op publish`
|
|
540
|
+
(change-set scoped — a deliberate design: a tree-wide scan measured ~78% ancient-marker noise). Markers
|
|
541
|
+
quoted in the QE report are backticked so the report itself scans clean.
|
|
542
|
+
|
|
529
543
|
Both forms carry all of it: the interactive skill (step modules + banner template) and the deterministic
|
|
530
544
|
workflow (stage prompts + derived `gates` in its returns) — same shapes, same vocabulary.
|
|
531
545
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/skills-feature-adr",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.66",
|
|
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
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"hashes": [
|
|
36
36
|
{
|
|
37
37
|
"alg": "SHA-256",
|
|
38
|
-
"content": "
|
|
38
|
+
"content": "5cca2d4a5337177ee9a072d49d14f73386af75398f52d907d757d4c052afdf81"
|
|
39
39
|
}
|
|
40
40
|
]
|
|
41
41
|
},
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"hashes": [
|
|
66
66
|
{
|
|
67
67
|
"alg": "SHA-256",
|
|
68
|
-
"content": "
|
|
68
|
+
"content": "b76f1b1d1ce3d8b22be0c2354fe3bd22833513da8b418c7c93423ae75f4018ae"
|
|
69
69
|
}
|
|
70
70
|
]
|
|
71
71
|
},
|
|
@@ -305,7 +305,7 @@
|
|
|
305
305
|
"hashes": [
|
|
306
306
|
{
|
|
307
307
|
"alg": "SHA-256",
|
|
308
|
-
"content": "
|
|
308
|
+
"content": "02d2a081e4bc9e7f5d42e55a4e21a68484af8b45216ff74fe5fc4322cb689a96"
|
|
309
309
|
}
|
|
310
310
|
]
|
|
311
311
|
},
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"hashes": [
|
|
396
396
|
{
|
|
397
397
|
"alg": "SHA-256",
|
|
398
|
-
"content": "
|
|
398
|
+
"content": "443043f6f3a3c2ebdcc4d40f9d13d799581056fb37890a2bb1fa61662825229b"
|
|
399
399
|
}
|
|
400
400
|
]
|
|
401
401
|
},
|
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
"hashes": [
|
|
416
416
|
{
|
|
417
417
|
"alg": "SHA-256",
|
|
418
|
-
"content": "
|
|
418
|
+
"content": "97e9a7bc54f196b381c4ef71258cddcb2fb48f216df1ba015927c176bad57084"
|
|
419
419
|
}
|
|
420
420
|
]
|
|
421
421
|
},
|
|
@@ -639,6 +639,16 @@
|
|
|
639
639
|
}
|
|
640
640
|
]
|
|
641
641
|
},
|
|
642
|
+
{
|
|
643
|
+
"type": "file",
|
|
644
|
+
"name": "templates/.claude/skills/feature-adr/scripts/check-plan-completeness.mjs",
|
|
645
|
+
"hashes": [
|
|
646
|
+
{
|
|
647
|
+
"alg": "SHA-256",
|
|
648
|
+
"content": "41d85b012a9d6cc172eaa5d7777294f2c01fb54b752ed61c7cbe2d2cd7b79b67"
|
|
649
|
+
}
|
|
650
|
+
]
|
|
651
|
+
},
|
|
642
652
|
{
|
|
643
653
|
"type": "file",
|
|
644
654
|
"name": "templates/.claude/skills/frontend-design/LICENSE.txt",
|
|
@@ -795,7 +805,7 @@
|
|
|
795
805
|
"hashes": [
|
|
796
806
|
{
|
|
797
807
|
"alg": "SHA-256",
|
|
798
|
-
"content": "
|
|
808
|
+
"content": "4904cf2040f024647c561fb5bd11aab5c7c0b70190dc4505b1bd69572cf25072"
|
|
799
809
|
}
|
|
800
810
|
]
|
|
801
811
|
},
|
|
@@ -100,6 +100,9 @@ ROUTER → REQUIREMENTS → RESEARCH → ADR → QCSD SWARM
|
|
|
100
100
|
SPARC-GOAP PLAN
|
|
101
101
|
(all)
|
|
102
102
|
│
|
|
103
|
+
K2 PLAN-COMPLETENESS GATE
|
|
104
|
+
(all — exit 0 or Step 7 waits)
|
|
105
|
+
│
|
|
103
106
|
Step 7
|
|
104
107
|
CODE
|
|
105
108
|
(all)
|
|
@@ -144,6 +147,26 @@ Step | S | M | L | XL | Model | Agentic QE Skill
|
|
|
144
147
|
10 Delivery Gate (OPT-IN) | o | o | o | o | cross-family of coder | 4 planes: regressions ‖ security ‖ code-quality ‖ product-honesty (o = runs only when explicitly requested; absent ⇒ byte-identical) |
|
|
145
148
|
```
|
|
146
149
|
|
|
150
|
+
### K2 plan-completeness gate (Step-6/7 boundary, MANDATORY, all tiers)
|
|
151
|
+
|
|
152
|
+
Step 7 does not start until the plan passes a SCRIPT — not a reviewer's impression:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
node .claude/skills/feature-adr/scripts/check-plan-completeness.mjs features/<slug>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Pass the run's tier (`--tier=S|M|L|XL`): M/L/XL with no `03_adr/` FAILS rather than skipping C1/C2.
|
|
159
|
+
Every tier — S included — writes a real `06_implementation_plan.md`; an inline-only S-tier checklist
|
|
160
|
+
cannot be gated and is no longer permitted.
|
|
161
|
+
|
|
162
|
+
`exit 0` → proceed to Step 7 · `exit 1` → return to Step 6 and fix every `FAIL C*` line · `exit 3`
|
|
163
|
+
→ INCONCLUSIVE (inputs unreadable) — fix them and rerun. **Never proceed on a non-zero exit, and
|
|
164
|
+
never read empty output as a pass**: the verdict is the last line
|
|
165
|
+
(`K2 plan-completeness: PASS|FAIL|NOT-ESTABLISHED`), and its absence is not a verdict. The checkpoint
|
|
166
|
+
banner's Gates line carries it: `🚦 Gates: K2 plan-completeness ✓ | ✗ | inconclusive`. Details and the
|
|
167
|
+
per-check list: `modules/06-implementation-plan.md`. In the ultracode workflow the gate runs
|
|
168
|
+
automatically and a non-PASS returns `phase: 'plan-gate-failed'` without dispatching the coder.
|
|
169
|
+
|
|
147
170
|
## DAG Dependencies
|
|
148
171
|
|
|
149
172
|
Steps are NOT purely linear. The DAG defines what can run in parallel:
|
|
@@ -321,10 +344,17 @@ Two flags for integrating with the full agentic-qe package:
|
|
|
321
344
|
|
|
322
345
|
| Flag | Mode | What it does |
|
|
323
346
|
|------|------|-------------|
|
|
324
|
-
| (none) | Reference | Condensed copies of 9 core skills, no install needed |
|
|
325
|
-
| `--full-qe` | Direct | Full agentic-qe protocols for
|
|
347
|
+
| (none) | Reference | Condensed copies of 9 core skills, no install needed — the **no-install fallback** |
|
|
348
|
+
| `--full-qe` | Direct | **RECOMMENDED DEFAULT when agentic-qe is installed.** Full agentic-qe protocols for the 9 core skills, and BOTH halves of the learning loop run: Step-0 recall = `memory_query("patterns/feature-adr/*")` **+** `dz recall`; Step-8 teach = the aqe `qe-outcome` store **+** `dz teach` |
|
|
326
349
|
| `--full-qe-extended` | Direct Extended | Full protocols + 6 additional skills (chaos, security, performance, mutation, TDD, production-swarm) |
|
|
327
350
|
|
|
351
|
+
**Which one to run:** if `aqe` is installed (`which aqe` or `node_modules/agentic-qe/`), run
|
|
352
|
+
`--full-qe` — it is the recommended default at every tier, because the aqe pattern memory only
|
|
353
|
+
contributes when the Direct half of the loop is active. Reference mode is the honest fallback for a
|
|
354
|
+
machine without agentic-qe; it is not a lesser-quality choice there, it is the only correct one.
|
|
355
|
+
This is a RECOMMENDATION about which flag to pass — the mode LOGIC is unchanged (flag + installed →
|
|
356
|
+
direct; flag without install → WARN + reference).
|
|
357
|
+
|
|
328
358
|
### Installation
|
|
329
359
|
|
|
330
360
|
```bash
|
|
@@ -338,8 +368,8 @@ cd your-project && aqe init --auto
|
|
|
338
368
|
### Activation
|
|
339
369
|
|
|
340
370
|
```
|
|
341
|
-
/feature-adr [описание фичи]
|
|
342
|
-
/feature-adr
|
|
371
|
+
/feature-adr --full-qe [описание фичи] # RECOMMENDED when agentic-qe is installed
|
|
372
|
+
/feature-adr [описание фичи] # Reference Mode: the no-install fallback
|
|
343
373
|
/feature-adr --full-qe-extended [описание фичи] # Direct Extended: full protocols + extra skills
|
|
344
374
|
```
|
|
345
375
|
|
|
@@ -454,7 +484,8 @@ each step records the live panel via `dz statusline --fa-record`. This half NEVE
|
|
|
454
484
|
|
|
455
485
|
The **agentic-qe MCP layer below is an ADDITIONAL enrichment, active only in Direct modes**
|
|
456
486
|
(`--full-qe` / `--full-qe-extended`, needs `fleet_init`) — it adds semantic in-session recall on top of
|
|
457
|
-
the always-on dz loop.
|
|
487
|
+
the always-on dz loop. This is why `--full-qe` is the RECOMMENDED default wherever agentic-qe is
|
|
488
|
+
installed: only then do BOTH recall halves run at Step 0 and BOTH teach halves at Step 8.
|
|
458
489
|
|
|
459
490
|
When `{AGENTIC_QE_MODE}` = `direct` | `direct-extended`, the pipeline ALSO runs a recall → store cycle
|
|
460
491
|
over agentic-qe's MCP pattern memory (`namespace: "learning"`, `fleet_init` first):
|
|
@@ -537,8 +568,9 @@ Everything from `--full-qe` plus 6 additional skills and up to 3 extra agents in
|
|
|
537
568
|
|
|
538
569
|
| Scenario | Mode |
|
|
539
570
|
|----------|------|
|
|
540
|
-
|
|
|
541
|
-
|
|
|
571
|
+
| agentic-qe installed (any tier) | `--full-qe` — the recommended default |
|
|
572
|
+
| agentic-qe NOT installed | Reference (the fallback; the dz half of the loop still runs) |
|
|
573
|
+
| S/M tier, agentic-qe installed | `--full-qe` |
|
|
542
574
|
| L tier, high QE maturity | `--full-qe` |
|
|
543
575
|
| XL tier features | `--full-qe` recommended |
|
|
544
576
|
| XL + security-critical (banking, ФЗ-152) | `--full-qe-extended` recommended |
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## When
|
|
6
6
|
|
|
7
|
-
Always runs.
|
|
8
|
-
- **S:**
|
|
7
|
+
Always runs, and ALWAYS writes `features/<slug>/06_implementation_plan.md` — every tier. Depth adapts:
|
|
8
|
+
- **S:** minimal plan FILE (3-5 tasks + an `EXPECTED_CODE_TARGETS:` block). An inline-only checklist is
|
|
9
|
+
no longer permitted: the K2 gate below is mandatory at every tier and it reads the file, so a plan
|
|
10
|
+
that exists only in the conversation makes the gate answer NOT-ESTABLISHED and the run stops. The
|
|
11
|
+
file must clear the gate's own floor: >200 characters and a non-empty targets block.
|
|
9
12
|
- **M/L/XL:** Full structured plan document
|
|
10
13
|
|
|
11
14
|
## Model
|
|
@@ -134,13 +137,17 @@ This gap-check loop ensures the implementation plan is complete before coding be
|
|
|
134
137
|
|
|
135
138
|
## Output
|
|
136
139
|
|
|
137
|
-
### S-tier (inline)
|
|
138
|
-
|
|
140
|
+
### S-tier (minimal file — NOT inline-only)
|
|
141
|
+
Write `features/<slug>/06_implementation_plan.md` with the checklist plus the machine-read block, and
|
|
142
|
+
show the same checklist inline at the checkpoint:
|
|
139
143
|
```
|
|
140
144
|
Implementation plan:
|
|
141
145
|
- [ ] {task 1}
|
|
142
146
|
- [ ] {task 2}
|
|
143
147
|
- [ ] {task 3}
|
|
148
|
+
|
|
149
|
+
EXPECTED_CODE_TARGETS:
|
|
150
|
+
- {repo-relative path Step 7 will create or modify}
|
|
144
151
|
```
|
|
145
152
|
|
|
146
153
|
### M/L/XL
|
|
@@ -157,6 +164,41 @@ Create `features/<slug>/06_implementation_plan.md` with:
|
|
|
157
164
|
|
|
158
165
|
Set `{IMPL_PLAN}` variable.
|
|
159
166
|
|
|
167
|
+
## K2 plan-completeness gate (MANDATORY — Step 7 does not start until it exits 0)
|
|
168
|
+
|
|
169
|
+
After the plan is written, run the gate. It is a script, not a judgement call:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
node .claude/skills/feature-adr/scripts/check-plan-completeness.mjs features/<slug>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Exit | Verdict | What you do |
|
|
176
|
+
|------|---------|-------------|
|
|
177
|
+
| `0` | PASS | proceed to Step 7 |
|
|
178
|
+
| `1` | FAIL | **return to Step 6** — fix the plan for every `FAIL C*` line, rerun the gate |
|
|
179
|
+
| `3` | NOT-ESTABLISHED | **INCONCLUSIVE** — the gate could not read its inputs (no plan, plan under the size floor, ADR claims it cannot see). Fix the inputs and rerun. Never proceed. |
|
|
180
|
+
|
|
181
|
+
Never proceed on a non-zero exit, and never treat empty output as a pass — the last line
|
|
182
|
+
(`K2 plan-completeness: PASS|FAIL|NOT-ESTABLISHED`) is the verdict, and its absence is not one.
|
|
183
|
+
What it checks: C1 every ADR has a plan task citing it · C2 every ADR Confirmation test path is named
|
|
184
|
+
in the plan · C3 the `EXPECTED_CODE_TARGETS:` block parses line by line · C4 the feature's declared
|
|
185
|
+
acid corpus is named · C5 (WARN) the `Inputs read:` line. An S-tier run with no `03_adr/` skips C1/C2
|
|
186
|
+
with a note (it cannot be failed for ADRs it never had) — unless the plan itself cites `ADR-<n>`,
|
|
187
|
+
which is NOT-ESTABLISHED. C1 is a grep: it catches "forgot entirely", not "mentioned but not tasked".
|
|
188
|
+
|
|
189
|
+
Pass the run's tier so the check cannot be dodged: `--tier=S|M|L|XL`. An M/L/XL feature with no
|
|
190
|
+
`03_adr/` FAILS C1/C2 (an M+ feature owes ADRs); only `--tier=S` — or no tier at all, and then the
|
|
191
|
+
skip note says so — takes the skip. A declared-but-malformed acid table (lowercase `| a1 |`, a header
|
|
192
|
+
with no parsable rows) FAILS as `C4-malformed`; it is not a skip.
|
|
193
|
+
|
|
194
|
+
**If the gate fails in the ultracode workflow:** the run returns `phase: 'plan-gate-failed'` and the
|
|
195
|
+
plan stage is CHECKPOINTED, so a bare re-invoke resumes the same failing plan. Repair it from outside:
|
|
196
|
+
edit `features/<slug>/06_implementation_plan.md` to fix each `FAIL` line and re-invoke (the checkpoint
|
|
197
|
+
is keyed on run INPUTS, not on the file, so your edit survives), or re-invoke with `args.resume:
|
|
198
|
+
'never'` (or delete `features/<slug>/.fa-state/`) to force a fresh plan.
|
|
199
|
+
|
|
200
|
+
The checkpoint banner's Gates line carries the verdict: `K2 plan-completeness ✓ | ✗ | inconclusive`.
|
|
201
|
+
|
|
160
202
|
## Checkpoint Format
|
|
161
203
|
|
|
162
204
|
```
|
|
@@ -167,6 +209,7 @@ Tier: {COMPLEXITY_TIER}
|
|
|
167
209
|
|
|
168
210
|
{N} tasks in {M} parallel groups
|
|
169
211
|
Estimated {K} files to create/modify
|
|
212
|
+
🚦 Gates: K2 plan-completeness ✓ (exit 0) ← ✗/inconclusive ⇒ do NOT start Step 7
|
|
170
213
|
|
|
171
214
|
• "ок" — start coding
|
|
172
215
|
• "разбей [TASK-N]" — split task further
|
|
@@ -196,3 +239,4 @@ re-flagging it. In the ultracode workflow this врезка runs automatically a
|
|
|
196
239
|
- [ ] Parallel groups correctly identified
|
|
197
240
|
- [ ] Each task touches identifiable files
|
|
198
241
|
- [ ] Total file count matches complexity tier expectation
|
|
242
|
+
- [ ] `check-plan-completeness.mjs features/<slug>` exited 0 (its output quoted at the checkpoint)
|
|
@@ -152,7 +152,7 @@ Fail the ADR gate for any miss:
|
|
|
152
152
|
| Follow-up discipline | Consequences link follow-up ADRs or state none; after-action review is scheduled |
|
|
153
153
|
| Confirmation stanza | Names verification method, monitoring, success metric, and owner |
|
|
154
154
|
| Confirmation-to-test link | The named load-bearing property has a real automated test/fitness check by file/name |
|
|
155
|
-
| No placeholders | No TODO
|
|
155
|
+
| No placeholders | No `TODO`, template hint text, raw prompt/generation scaffold, or empty tail sections |
|
|
156
156
|
|
|
157
157
|
Reject explainer-masquerading-as-ADR: if the document describes a problem space or technology landscape but has no concrete `Decision`, record a BLOCKER.
|
|
158
158
|
|
|
@@ -182,6 +182,19 @@ paths — especially startup/lifespan/health: require a negative resource-down t
|
|
|
182
182
|
path degrades per its declared contract: fail-open for advisory, explicit fail-fast for load-bearing).
|
|
183
183
|
Missing → HIGH gap.
|
|
184
184
|
|
|
185
|
+
### 3d. No-stubs gate (backlog 0b403a0106103901 — layer 1 of the cost-of-detection ladder)
|
|
186
|
+
|
|
187
|
+
Over the files THIS RUN touched (the Step-7 change list; for a Codex coder, the landed-barrier file
|
|
188
|
+
list), grep for unfinished-stub markers: `TODO` / `FIXME` / `HACK` / `XXX` / `PLACEHOLDER`
|
|
189
|
+
(case-SENSITIVE, word-bounded — never add `-i`; `hackathon`/`todos` must not fire) plus the phrase
|
|
190
|
+
`implement later` (case-insensitive). **Any match = the task shipped incomplete** → HIGH gap naming
|
|
191
|
+
file:line, UNLESS the line carries an inline `no-stubs: <reason>` waiver WITH a non-empty reason, or
|
|
192
|
+
`.dz/guard.json` `stubWaivers` lists the path WITH a reason. A REASONLESS waiver is itself a HIGH gap,
|
|
193
|
+
never an exemption. Cross-check mechanically: `dz guard check --op publish --json` runs the same scan
|
|
194
|
+
as the SOFT `no-stubs` rule over the working-tree diff. When you QUOTE a marker in `08_qe_report.md`,
|
|
195
|
+
backtick it so the report itself scans clean (the claim-check forbidden-phrase convention). Record the
|
|
196
|
+
verdict in the ADR Fitness section.
|
|
197
|
+
|
|
185
198
|
### 4. Multi-Agent Review Panel (L/XL)
|
|
186
199
|
|
|
187
200
|
For L/XL features, spawn 3 parallel review agents using brutal-honesty modes:
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// K2 — machine plan-completeness gate for /feature-adr, run BETWEEN Step 6 (plan) and Step 7 (code).
|
|
3
|
+
// Generalized from features/wave1-instrument-repair/check-plan-completeness.mjs (that copy is the
|
|
4
|
+
// historical artifact of its run and stays untouched); this one is parameterized by feature dir.
|
|
5
|
+
//
|
|
6
|
+
// USAGE: node .claude/skills/feature-adr/scripts/check-plan-completeness.mjs [<feature-dir>] [--tier=M] [--acid=A1,A2]
|
|
7
|
+
// <feature-dir> defaults to the current working directory.
|
|
8
|
+
// --tier=S|M|L|XL closes the ADR-less dodge (see S-TIER HONESTY); omitting it keeps the
|
|
9
|
+
// heuristic, and the skip note then names the dodge out loud.
|
|
10
|
+
//
|
|
11
|
+
// VERDICT CONTRACT (unchanged from the proven copy — never a silent pass):
|
|
12
|
+
// PASS exit 0 last line: `K2 plan-completeness: PASS (...)`
|
|
13
|
+
// FAIL exit 1 last line: `K2 plan-completeness: FAIL (...)`
|
|
14
|
+
// NOT-ESTABLISHED exit 3 last line: `K2 plan-completeness: NOT-ESTABLISHED — <reason>`
|
|
15
|
+
// (the wave1 copy printed the exit-3 line as `K2: NOT-ESTABLISHED — …`; the prefix is unified here so
|
|
16
|
+
// ONE regex parses all three verdicts — the exit codes and their meanings are identical.)
|
|
17
|
+
// Set difference over IDENTIFIERS, not text similarity.
|
|
18
|
+
//
|
|
19
|
+
// KNOWN LIMITATION (measured on the discrimination twin, 2026-08-19): C1 is a grep — a PROSE
|
|
20
|
+
// mention of "ADR-002" satisfies it exactly like a task reference. The real N14 (backlog
|
|
21
|
+
// 3dbd2851-adjacent) must parse task structure. Kept honest here: C1 catches "forgot entirely",
|
|
22
|
+
// not "mentioned but not tasked".
|
|
23
|
+
//
|
|
24
|
+
// Checks:
|
|
25
|
+
// C1 every ADR file in 03_adr/ has >=1 task line in 06_implementation_plan.md citing it (ADR-00N)
|
|
26
|
+
// C2 every Confirmation-numbered check in each ADR is named in the plan (by its test-file path)
|
|
27
|
+
// C3 the plan carries an EXPECTED_CODE_TARGETS: block, non-empty, and EVERY line parses to a
|
|
28
|
+
// plausible repo-relative path (no spaces unless quoted, no traversal, no markdown residue)
|
|
29
|
+
// — SFDIPOT condition: line-level validation, reject-with-reason, not just block presence
|
|
30
|
+
// C4 the plan names the feature's OWN acid corpus (see "acid corpus" below)
|
|
31
|
+
// C5 the plan has an 'Inputs read:' line naming 03_adr, 05_architecture (wave-2 seam, cheap here)
|
|
32
|
+
//
|
|
33
|
+
// S-TIER HONESTY (no 03_adr/): an S-tier run legitimately has no ADR files, and forcing it to fail a
|
|
34
|
+
// plan gate it can never satisfy would make the gate a nuisance to route around. So:
|
|
35
|
+
// - no ADR files BUT the plan cites `ADR-<digits>` → NOT-ESTABLISHED (exit 3): the plan claims
|
|
36
|
+
// decisions the gate cannot see, so its completeness is unknown — that is never a pass.
|
|
37
|
+
// - no ADR files AND --tier is M/L/XL → FAIL: an M+ feature owes ADRs, and skipping C1/C2 for it
|
|
38
|
+
// would let a whole tier dodge the check by simply not writing 03_adr/ (G-F3).
|
|
39
|
+
// - no ADR files AND (--tier=S or no --tier) AND the plan claims no ADR work
|
|
40
|
+
// → C1 + C2 are SKIPPED-with-note (printed as SKIP lines; the run can still PASS on C3-C5).
|
|
41
|
+
// Without --tier the skip note NAMES the dodge, because the gate cannot tell an honest S-run
|
|
42
|
+
// from an M+ run that deleted its ADR directory.
|
|
43
|
+
//
|
|
44
|
+
// ECHO SAFETY (G-F1, reproduced by execution): this script echoes plan-controlled content (rejected
|
|
45
|
+
// target lines, acid tokens, the feature path). A plan line carrying the literal verdict marker was
|
|
46
|
+
// echoed verbatim and a first-match parser upstream read the PLANT instead of the real verdict. Every
|
|
47
|
+
// echoed value now goes through `safe()`, which defangs the marker and the exit trailer and truncates,
|
|
48
|
+
// so the only spellable verdict line in this stream is the one this script writes last.
|
|
49
|
+
//
|
|
50
|
+
// ACID CORPUS (C4): the wave1 copy hard-coded ITS run's tokens. Here the corpus is DISCOVERED from
|
|
51
|
+
// the feature's own `00_complexity_assessment.md` acid-case table (rows shaped `| A<N> | … |`), or
|
|
52
|
+
// supplied explicitly with `--acid=T1,T2,…`. If neither establishes a corpus, C4 is SKIPPED-with-note
|
|
53
|
+
// (a feature that declared no acid cases cannot be failed for not naming them).
|
|
54
|
+
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
55
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
56
|
+
|
|
57
|
+
const argv = process.argv.slice(2);
|
|
58
|
+
const acidArg = argv.find((a) => a.startsWith('--acid='));
|
|
59
|
+
const tierArg = argv.find((a) => a.startsWith('--tier='));
|
|
60
|
+
const TIER = tierArg ? tierArg.slice('--tier='.length).trim().toUpperCase() : null;
|
|
61
|
+
const TIER_REQUIRES_ADR = TIER === 'M' || TIER === 'L' || TIER === 'XL';
|
|
62
|
+
const dirArg = argv.find((a) => !a.startsWith('--'));
|
|
63
|
+
const FDIR = resolve(dirArg && dirArg !== '' ? (isAbsolute(dirArg) ? dirArg : join(process.cwd(), dirArg)) : process.cwd());
|
|
64
|
+
const planPath = join(FDIR, '06_implementation_plan.md');
|
|
65
|
+
const adrDir = join(FDIR, '03_adr');
|
|
66
|
+
const complexityPath = join(FDIR, '00_complexity_assessment.md');
|
|
67
|
+
|
|
68
|
+
// Defang any value this script echoes back: a plan (or a path, or an ADR) must never be able to spell
|
|
69
|
+
// the verdict marker or the exit trailer into this stream. Truncated so one hostile line cannot bury
|
|
70
|
+
// the verdict either. The offender stays READABLE — defanged, not dropped.
|
|
71
|
+
const safe = (v) => String(v)
|
|
72
|
+
.replace(/K2 plan-completeness:/g, 'K2 plan-completeness[echoed]:')
|
|
73
|
+
.replace(/K2_EXIT=/g, 'K2_EXIT[echoed]=')
|
|
74
|
+
.replace(/[\r\n]+/g, ' ')
|
|
75
|
+
.slice(0, 300);
|
|
76
|
+
const out = (s) => console.log(s);
|
|
77
|
+
const notEstablished = (why) => { out(`K2 plan-completeness: NOT-ESTABLISHED — ${safe(why)}`); process.exit(3); };
|
|
78
|
+
let failures = [], warnings = [], skips = [];
|
|
79
|
+
|
|
80
|
+
if (!existsSync(FDIR)) notEstablished(`feature dir absent: ${FDIR}`);
|
|
81
|
+
if (!existsSync(planPath)) notEstablished('06_implementation_plan.md absent');
|
|
82
|
+
const plan = readFileSync(planPath, 'utf-8');
|
|
83
|
+
if (plan.trim().length < 200) notEstablished('plan suspiciously small (<200 chars)');
|
|
84
|
+
const adrFiles = existsSync(adrDir) ? readdirSync(adrDir).filter(f => f.endsWith('.md')).sort() : [];
|
|
85
|
+
const planClaimsAdrWork = /\bADR-\d+/.test(plan);
|
|
86
|
+
if (adrFiles.length === 0 && planClaimsAdrWork) notEstablished('no ADR files under 03_adr/, yet the plan cites ADR-<n> — completeness cannot be established');
|
|
87
|
+
|
|
88
|
+
if (adrFiles.length === 0 && TIER_REQUIRES_ADR) {
|
|
89
|
+
failures.push(`C1: tier ${TIER} has NO ADR files under 03_adr/ — an M/L/XL feature owes at least one ADR; the plan cannot be complete against decisions that were never written`);
|
|
90
|
+
failures.push(`C2: tier ${TIER} has no 03_adr/ — no Confirmation test can be checked`);
|
|
91
|
+
} else if (adrFiles.length === 0) {
|
|
92
|
+
skips.push(`C1: no 03_adr/ and the plan claims no ADR work — ADR-coverage check SKIPPED${TIER === 'S' ? ' (--tier=S, the legitimate S-tier shape)' : ' (NO --tier supplied: an M/L/XL run that simply never wrote 03_adr/ would dodge C1/C2 here — pass --tier to close it)'}`);
|
|
93
|
+
skips.push('C2: no 03_adr/ — Confirmation-test coverage check SKIPPED');
|
|
94
|
+
} else {
|
|
95
|
+
// C1 — ADR ids referenced by plan tasks
|
|
96
|
+
for (const f of adrFiles) {
|
|
97
|
+
const m = f.match(/^(\d{3})-/); if (!m) { warnings.push(`C1: unparseable ADR filename ${safe(f)}`); continue; }
|
|
98
|
+
const id = `ADR-${m[1]}`;
|
|
99
|
+
const re = new RegExp(`ADR-0*${Number(m[1])}\\b`);
|
|
100
|
+
if (!re.test(plan)) failures.push(`C1: ${id} (${safe(f)}) has NO task in the plan referencing it`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// C2 — every Confirmation-listed test file path appears in the plan
|
|
104
|
+
const testPathRe = /(?:packages\/[\w@/.-]+\/test\/[\w./-]+\.test\.(?:ts|mjs|js)|tests?\/[\w./-]+\.test\.(?:ts|mjs|js))/g;
|
|
105
|
+
for (const f of adrFiles) {
|
|
106
|
+
const adr = readFileSync(join(adrDir, f), 'utf-8');
|
|
107
|
+
const confIdx = adr.search(/^##+\s*Confirmation/mi);
|
|
108
|
+
if (confIdx < 0) { failures.push(`C2: ${safe(f)} has no Confirmation section`); continue; }
|
|
109
|
+
const conf = adr.slice(confIdx);
|
|
110
|
+
const paths = [...new Set((conf.match(testPathRe) ?? []))];
|
|
111
|
+
if (paths.length === 0) { failures.push(`C2: ${safe(f)} Confirmation names no test file paths`); continue; }
|
|
112
|
+
for (const p of paths) if (!plan.includes(p)) failures.push(`C2: ${safe(f)} Confirmation test ${safe(p)} NOT named in the plan`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// C3 — EXPECTED_CODE_TARGETS block, line-level validation
|
|
117
|
+
const blockM = plan.match(/EXPECTED_CODE_TARGETS:\s*\n((?:\s*[-*]\s*.+\n?)+)/);
|
|
118
|
+
if (!blockM) failures.push('C3: no EXPECTED_CODE_TARGETS: block in the plan');
|
|
119
|
+
else {
|
|
120
|
+
const lines = blockM[1].split('\n').map(s => s.trim()).filter(Boolean);
|
|
121
|
+
if (lines.length === 0) failures.push('C3: EXPECTED_CODE_TARGETS block is empty');
|
|
122
|
+
for (const ln of lines) {
|
|
123
|
+
const path = ln.replace(/^[-*]\s*/, '').replace(/`/g, '').trim();
|
|
124
|
+
const reasons = [];
|
|
125
|
+
if (/\s/.test(path)) reasons.push('contains whitespace');
|
|
126
|
+
if (/\.\./.test(path)) reasons.push('path traversal');
|
|
127
|
+
if (/[*#\[\]()]/.test(path)) reasons.push('markdown residue');
|
|
128
|
+
if (!/^[\w@][\w@/.-]*$/.test(path)) reasons.push('not a plain repo-relative path');
|
|
129
|
+
if (reasons.length) failures.push(`C3: target line rejected: "${safe(ln)}" — ${reasons.join(', ')}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// C4 — the feature's OWN acid corpus is named in the plan (discovered, or --acid=…)
|
|
134
|
+
// G-F5: a corpus that was DECLARED but declared BADLY (lowercase `| a1 |`, a row with trailing junk,
|
|
135
|
+
// or an acid-case table header with no parsable rows) is a FAILURE, not a skip. Silently skipping it
|
|
136
|
+
// let a malformed declaration buy the same green as an honest "no acid cases here". The strict row
|
|
137
|
+
// shape is `| A<digits> |`; anything that LOOKS like an acid row under the loose shape but is not
|
|
138
|
+
// strict is reported by name. (Honest scope: rows that look nothing like an acid row — a defect table
|
|
139
|
+
// `| D1 |`, say — are not acid candidates and are left alone.)
|
|
140
|
+
let acidTokens = [];
|
|
141
|
+
let acidSource = null;
|
|
142
|
+
if (acidArg) {
|
|
143
|
+
acidTokens = acidArg.slice('--acid='.length).split(',').map(s => s.trim()).filter(Boolean);
|
|
144
|
+
acidSource = '--acid';
|
|
145
|
+
if (acidTokens.length === 0) failures.push('C4-malformed: --acid was passed but declares no tokens');
|
|
146
|
+
} else if (existsSync(complexityPath)) {
|
|
147
|
+
const complexity = readFileSync(complexityPath, 'utf-8');
|
|
148
|
+
acidTokens = [...new Set((complexity.match(/^\|\s*(A\d+)\s*\|/gm) ?? []).map(r => r.replace(/[|\s]/g, '')))];
|
|
149
|
+
if (acidTokens.length) acidSource = '00_complexity_assessment.md acid-case table';
|
|
150
|
+
const loose = [...new Set((complexity.match(/^\|\s*([Aa]\d+[A-Za-z]?)\s*\|/gm) ?? []).map(r => r.replace(/[|\s]/g, '')))];
|
|
151
|
+
for (const cand of loose) if (!acidTokens.includes(cand)) failures.push(`C4-malformed: acid row "${safe(cand)}" does not match the required \`| A<n> |\` shape (case-sensitive, digits only) — it is declared but uncheckable`);
|
|
152
|
+
const declaresTable = /\|\s*Acid case\s*\|/i.test(complexity);
|
|
153
|
+
if (declaresTable && acidTokens.length === 0) failures.push('C4-malformed: 00_complexity_assessment.md declares an acid-case table but NO `| A<n> |` row parsed from it');
|
|
154
|
+
}
|
|
155
|
+
if (acidTokens.length === 0) skips.push('C4: no acid corpus declared (no --acid, no `| A<n> |` table in 00_complexity_assessment.md) — acid-naming check SKIPPED');
|
|
156
|
+
else for (const t of acidTokens) if (!new RegExp(`\\b${t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i').test(plan)) failures.push(`C4: acid token "${safe(t)}" (from ${acidSource}) not named in the plan`);
|
|
157
|
+
|
|
158
|
+
// C5 — Inputs read line
|
|
159
|
+
if (!/Inputs read:/i.test(plan)) warnings.push('C5: no "Inputs read:" line (wave-2 seam, WARN only)');
|
|
160
|
+
else for (const need of ['03_adr','05_architecture']) if (!plan.includes(need)) warnings.push(`C5: Inputs read line missing ${need}`);
|
|
161
|
+
|
|
162
|
+
for (const s of skips) out('SKIP ' + s);
|
|
163
|
+
for (const w of warnings) out('WARN ' + w);
|
|
164
|
+
for (const f of failures) out('FAIL ' + f);
|
|
165
|
+
out(`K2 plan-completeness: ${failures.length === 0 ? 'PASS' : 'FAIL'} (${failures.length} failure(s), ${warnings.length} warning(s), ${skips.length} skip(s)) over ${adrFiles.length} ADRs, tier ${TIER === null ? '(unspecified)' : safe(TIER)}, in ${safe(FDIR)}`);
|
|
166
|
+
process.exit(failures.length === 0 ? 0 : 1);
|