@dzhechkov/skills-feature-adr 1.3.50 → 1.3.52
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/README.md +19 -0
- package/package.json +1 -1
- package/templates/.claude/skills/challenge-panel/SKILL.md +81 -0
- package/templates/.claude/skills/configure-feature-adr/SKILL.md +75 -0
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +15 -0
- package/templates/.claude/workflows/feature-adr.js +72 -1
package/README.md
CHANGED
|
@@ -410,6 +410,25 @@ Fixed roles map to fixed stages (`product-vision`→design+QE, `critic`→QE, `b
|
|
|
410
410
|
open `extra` list adds guidance to any stage. `dz project-skills` prints the who-injected report. Absent ⇒ a
|
|
411
411
|
normal generic run. (See `dz mr-rakes --gen-critic` to auto-generate the `critic` skill from your recurring rakes.)
|
|
412
412
|
|
|
413
|
+
### Adversarial plan-gate at the L/XL checkpoint (needs `dz` ≥ 0.3.117)
|
|
414
|
+
|
|
415
|
+
Cross-model QE (Step 8) catches problems *after* the code is written. At the **checkpoint-after-plan** the
|
|
416
|
+
pipeline now also runs an adversarial **challenge panel** on the plan itself — a FRESH reviewer that did **not**
|
|
417
|
+
write the plan tries to BREAK it across a fixed C1-C8 owner-question set (arch-anti-cement, prod-ready, test
|
|
418
|
+
sufficiency + honesty, overengineering, silent decisions, runtime consistency, scope, executability):
|
|
419
|
+
|
|
420
|
+
- **Panel ≠ plan author** (hard invariant): if Claude wrote the plan the adversary is Codex (honest `codex exec`,
|
|
421
|
+
never a fire-and-forget stub); if Codex wrote it the adversary is a fresh Claude. An unknown family never
|
|
422
|
+
silently claims cross-family.
|
|
423
|
+
- **Every P0/P1 is cross-validated** by a second independent agent, matched by index (never by title), and the
|
|
424
|
+
non-validated ones are dropped — theory never reaches you. If the validator can't cover them, they are
|
|
425
|
+
surfaced **UNVALIDATED**, never silently dropped.
|
|
426
|
+
- **Advisory** — the verdict returns as `challengeVerdict` alongside the ADR + plan; it **never auto-blocks**.
|
|
427
|
+
- Calibrated by `architecture/vision.md` + `testing.md` + `map.json` + `architecture/degradations.md` (a
|
|
428
|
+
deviation from a pattern registered in the degradations file is **not** flagged). Run it ad-hoc with
|
|
429
|
+
`dz challenge --plan <plan.md>` or the `challenge-panel` skill; scaffold the degradations registry via
|
|
430
|
+
`dz feature-adr-setup --from-spec <spec with {"degradations":true}> --apply`.
|
|
431
|
+
|
|
413
432
|
### ADR quality gate (Step 3 generates → Step 8 enforces)
|
|
414
433
|
|
|
415
434
|
Step 3 and Step 8 share an ADR best-practices contract distilled from the
|
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.52",
|
|
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"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: challenge-panel
|
|
3
|
+
description: >-
|
|
4
|
+
Adversarial plan-gate. BEFORE code, a FRESH reviewer (never the plan author) tries to BREAK an
|
|
5
|
+
implementation plan across a fixed C1-C8 owner-question set, every serious finding is cross-validated,
|
|
6
|
+
and the verdict is surfaced as ADVICE — never an auto-block. Trigger on "прогони challenge", "челлендж
|
|
7
|
+
плана", "challenge the plan", "adversarial review of this plan", or from the feature-adr plan checkpoint.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Challenge Panel — adversarial plan-gate
|
|
11
|
+
|
|
12
|
+
feature-adr's cross-model QE (Step 8) catches problems AFTER the code is written. The most expensive
|
|
13
|
+
mistakes — overengineering, silent decisions, cemented degradations, test-theater, unrealistic scope —
|
|
14
|
+
cement at the PLAN stage, and the plan's author structurally cannot find their own gaps (author bias).
|
|
15
|
+
This skill runs a "break the plan, don't confirm it" panel at the plan stage, by a FRESH agent that did
|
|
16
|
+
NOT write the plan, with cross-validated findings. **Advise, not block.**
|
|
17
|
+
|
|
18
|
+
## Hard invariant (never relax)
|
|
19
|
+
|
|
20
|
+
**The panel is NEVER the plan's own author.** Dispatch the adversary on a DIFFERENT model family than the
|
|
21
|
+
one that wrote the plan:
|
|
22
|
+
- plan written by Claude → adversary = Codex (cross-family). Run it through the honest synchronous path
|
|
23
|
+
(`codex exec` / `safeCodexAgent`), never a fire-and-forget wrapper — a stub reads exactly like a clean
|
|
24
|
+
review. If Codex is unavailable, fall back LOUDLY to a fresh Claude agent and say it was NOT cross-family.
|
|
25
|
+
- plan written by Codex → adversary = a fresh Claude agent (already cross-family).
|
|
26
|
+
- ad-hoc / unknown author → a fresh agent that did not participate in writing the plan.
|
|
27
|
+
|
|
28
|
+
`dz challenge --author <model>` prints which cross-family adversary to dispatch.
|
|
29
|
+
|
|
30
|
+
## Protocol
|
|
31
|
+
|
|
32
|
+
1. **Assemble the WIDE context (deterministic).** Run:
|
|
33
|
+
```bash
|
|
34
|
+
dz challenge --plan <path/to/06_implementation_plan.md>
|
|
35
|
+
```
|
|
36
|
+
This prints the challenge brief: the plan + `architecture/vision.md` + `architecture/testing.md` +
|
|
37
|
+
`architecture/map.json` + `architecture/degradations.md` inlined (missing docs degrade gracefully) +
|
|
38
|
+
the fixed C1-C8 questions + the verdict JSON schema. A WIDE context is load-bearing — hand a reviewer a
|
|
39
|
+
narrow slice and you get findings about the slice.
|
|
40
|
+
- `--context-only` shows just what the panel will read (and the chosen adversary).
|
|
41
|
+
- `--json` emits the context + brief + adversary as JSON for a subagent.
|
|
42
|
+
|
|
43
|
+
2. **Fire the panel (fresh adversary ≠ author).** Dispatch a subagent on the cross-family model with the
|
|
44
|
+
brief. It answers C1-C8 in "break it" mode and returns the verdict JSON:
|
|
45
|
+
| # | Question |
|
|
46
|
+
|---|----------|
|
|
47
|
+
| C1 | Architecture anti-cement — cements a NEW bad pattern/boundary? (deviating from a REGISTERED accepted degradation is NOT a finding) |
|
|
48
|
+
| C2 | Production-ready — where does it fall over? name the concrete input/condition |
|
|
49
|
+
| C3 | Test sufficiency + honesty BOTH ways — an ADR-named "never X" with no falsifying test? tests that are theater? |
|
|
50
|
+
| C4 | Overengineering sweep — built for a requirement nobody stated? the simpler thing? |
|
|
51
|
+
| C5 | Silent decisions — a policy made without surfacing it as a decision the owner could refuse |
|
|
52
|
+
| C6 | Runtime consistency — contradicts an existing convention (error shape, config source, ESM, naming)? |
|
|
53
|
+
| C7 | Scope — > ~1.5× what the request needs? the concrete cut list |
|
|
54
|
+
| C8 | Executability — could a non-author complete every step without coming back to ask? |
|
|
55
|
+
|
|
56
|
+
Each finding: `c` (C-number), `severity` (P0/P1/P2), `title`, `why` (a concrete failing input/condition —
|
|
57
|
+
never a general worry), optional `where`.
|
|
58
|
+
|
|
59
|
+
3. **Cross-validate every P0/P1 (mandatory anti-noise).** Dispatch a SECOND, independent agent: for each
|
|
60
|
+
P0/P1, "real and reachable, or FP/theory?" — default to false when uncertain. **Drop** every P0/P1 that
|
|
61
|
+
is not confirmed. Theory never reaches the owner (a false gate kills trust). P2 pass through.
|
|
62
|
+
|
|
63
|
+
4. **Surface the verdict — ADVISE, never block.** Present the cross-validated P0/P1 prominently + P2 as
|
|
64
|
+
notes. Do NOT auto-abort. The owner decides whether to revise the plan, accept a finding into
|
|
65
|
+
`architecture/degradations.md`, or proceed.
|
|
66
|
+
|
|
67
|
+
## Calibration docs (optional, improve precision)
|
|
68
|
+
|
|
69
|
+
- `architecture/vision.md` — boundaries + principles (what the product deliberately does NOT do).
|
|
70
|
+
- `architecture/testing.md` — what "done" and an honest test mean here.
|
|
71
|
+
- `architecture/degradations.md` — the accepted-degradations registry: patterns you KNOW are imperfect but
|
|
72
|
+
keep on purpose. **C1 does not flag a deviation from anything registered here.** Scaffold a starter with
|
|
73
|
+
`dz feature-adr-setup --from-spec <spec with {"degradations":true}> --apply`.
|
|
74
|
+
|
|
75
|
+
Absent docs never error — the panel simply runs with less calibration.
|
|
76
|
+
|
|
77
|
+
## In the feature-adr pipeline
|
|
78
|
+
|
|
79
|
+
At the L/XL **checkpoint-after-plan**, feature-adr runs this panel automatically (a fresh adversary ≠ the
|
|
80
|
+
Step-6 planner), cross-validates, and returns `challengeVerdict` alongside the ADR + plan — advisory. In
|
|
81
|
+
**plain** `/feature-adr`, offer the panel at the planning checkpoint before coding.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: configure-feature-adr
|
|
3
|
+
description: |
|
|
4
|
+
Guided, conversational setup that makes feature-adr aware of THIS product — vision, architecture map,
|
|
5
|
+
testing/verification rules, and (optionally) a review critic — WITHOUT the user knowing any manifest schema.
|
|
6
|
+
Complex inside, simple outside.
|
|
7
|
+
|
|
8
|
+
TRIGGERS: "настрой feature-adr под мой продукт", "помоги настроить feature-adr", "configure feature-adr
|
|
9
|
+
for my product", "какие документы нужны для feature-adr и куда их добавить", "onboard feature-adr".
|
|
10
|
+
|
|
11
|
+
Uses the deterministic engine `dz feature-adr-setup` (plan → scaffold-from-spec, propose-confirm,
|
|
12
|
+
augment-never-clobber). Reuses `dz architecture` (map) and `dz mr-rakes --gen-critic` (auto critic).
|
|
13
|
+
allowed-tools: Bash, Read, Write, Edit, AskUserQuestion
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Configure feature-adr for this product
|
|
17
|
+
|
|
18
|
+
Turn a generic feature-adr into a **project-aware** one by scaffolding four committed files under
|
|
19
|
+
`architecture/` and wiring `project-skills.json` — through a short conversation, not a schema lesson.
|
|
20
|
+
|
|
21
|
+
**Golden rule:** you NEVER hand-write manifest JSON in front of the user, and you NEVER overwrite an existing
|
|
22
|
+
file. The engine scaffolds; you interview only for what can't be auto-derived.
|
|
23
|
+
|
|
24
|
+
## Protocol
|
|
25
|
+
|
|
26
|
+
### 1. Read the current state (never writes)
|
|
27
|
+
```bash
|
|
28
|
+
dz feature-adr-setup --plan --json
|
|
29
|
+
```
|
|
30
|
+
Report in plain language: which of `vision.md` / `subsystems.manifest.json` / `testing.md` /
|
|
31
|
+
`project-skills.json` already exist, how many workspace packages were discovered (a map can be
|
|
32
|
+
auto-scaffolded), and whether a review corpus exists (a critic can be auto-generated). Tell the user exactly
|
|
33
|
+
which documents are still missing — this is the "which docs, and where?" answer.
|
|
34
|
+
|
|
35
|
+
### 2. Auto-derive what you can (confirm, don't dictate)
|
|
36
|
+
- **Map:** take the discovered packages and propose a starter subsystem grouping (foundation / arsenal / your
|
|
37
|
+
app subsystems). Show it; ask the user to rename/split to their real subsystems. (Their product, their call.)
|
|
38
|
+
- **Critic (optional):** if a review corpus exists, offer to run `dz mr-rakes --gen-critic
|
|
39
|
+
architecture/project-critic/SKILL.md --apply` to generate the critic role from their recurring rakes.
|
|
40
|
+
|
|
41
|
+
### 3. Short interview — only the un-derivable
|
|
42
|
+
Ask, ONE topic at a time (this is the whole point of the skill — keep it to a handful of questions):
|
|
43
|
+
- **Product vision** — what the product IS (one paragraph), where it's going, and 1-3 things it consciously
|
|
44
|
+
does NOT do. Seed your draft from the repo README's "why/what" section, then confirm.
|
|
45
|
+
- **Testing / verification** — the commands that prove "done" here (e.g. `pnpm test -- --run`), what "done"
|
|
46
|
+
means in this project, and any required gates (coverage, lint, typecheck). This becomes the `testing` role.
|
|
47
|
+
- **Optional roles** — ask briefly whether they have a code implementation bar (`impl-bar`) or brand/UI rules
|
|
48
|
+
(`brand`) to point at; skip if not.
|
|
49
|
+
|
|
50
|
+
### 4. Fill the SPEC and scaffold (propose-confirm)
|
|
51
|
+
Write the collected answers to a spec file, then preview:
|
|
52
|
+
```bash
|
|
53
|
+
# spec shape: { vision:{core,direction?,boundaries?[],principles?[]}, testing:{commands?[],doneDefinition?,gates?[]},
|
|
54
|
+
# subsystems:[…], roles:{critic?:"auto"|path, brand?:path, "impl-bar"?:path}, extra?:[…] }
|
|
55
|
+
dz feature-adr-setup --from-spec /tmp/feature-adr-spec.json # preview: create / augment / unchanged per file
|
|
56
|
+
```
|
|
57
|
+
Show the preview. An **existing file is `unchanged` (never clobbered)**; a structured file is **augmented**
|
|
58
|
+
(existing content kept, new added). On the user's explicit "yes":
|
|
59
|
+
```bash
|
|
60
|
+
dz feature-adr-setup --from-spec /tmp/feature-adr-spec.json --apply
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 5. Verify + hand off
|
|
64
|
+
```bash
|
|
65
|
+
dz project-skills # confirm the roles resolve (product-vision, testing, critic, …)
|
|
66
|
+
dz architecture --revise # confirm no drift
|
|
67
|
+
```
|
|
68
|
+
Tell the user: from now on every `/feature-adr` in this repo folds their vision into design + QE, their
|
|
69
|
+
testing rules into Step 8, and their critic into review — automatically. Re-run this skill any time the
|
|
70
|
+
product grows; it only augments (new packages, fresh rakes), never overwrites.
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
- **Re-run = update.** The same flow, idempotent: step 1 surfaces only what's new.
|
|
74
|
+
- **Nothing is written without the user's confirmation**, and no hand-edited file is ever overwritten.
|
|
75
|
+
- If `dz` is not set up, install it first (`npm i -g @dzhechkov/harness-cli`); the engine needs `dz` ≥ 0.3.116.
|
|
@@ -169,6 +169,21 @@ Estimated {K} files to create/modify
|
|
|
169
169
|
═══════════════════════════════════════════════════════
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
## Challenge panel (adversarial plan-gate — before coding)
|
|
173
|
+
|
|
174
|
+
Before leaving the plan checkpoint for code (especially L/XL), offer the **`challenge-panel`** skill — a
|
|
175
|
+
FRESH adversary (never the plan author) tries to BREAK the plan across the fixed C1-C8 owner questions,
|
|
176
|
+
every P0/P1 is cross-validated, and the verdict is ADVISORY (never an auto-block):
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
dz challenge --plan features/<slug>/06_implementation_plan.md --author <planner-model>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Dispatch the panel on the CROSS-FAMILY model (`--author` prints which): plan by Claude → Codex adversary
|
|
183
|
+
(honest `codex exec`, never a stub); plan by Codex → fresh Claude. Drop any P0/P1 the cross-validator does
|
|
184
|
+
not confirm. A finding the owner accepts can be recorded in `architecture/degradations.md` so C1 stops
|
|
185
|
+
re-flagging it. In the ultracode workflow this врезка runs automatically and returns `challengeVerdict`.
|
|
186
|
+
|
|
172
187
|
## Quality Gates
|
|
173
188
|
|
|
174
189
|
- [ ] Every task has clear done criteria
|
|
@@ -663,6 +663,73 @@ if (plan === null) {
|
|
|
663
663
|
plan = claudePlan ? { wrote: claudePlan.wrote, summary: claudePlan.summary, planner: planIsCodex ? 'claude-fallback' : 'claude' } : null
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
+
// ── R6 challenge panel: adversarial plan-gate at the checkpoint (ADVISE, never block) ──
|
|
667
|
+
// The panel is NEVER the plan's own author (ADR §1 hard invariant): author=Claude → a cross-family Codex
|
|
668
|
+
// adversary via the HONEST synchronous codex exec path (safeCodexAgent — a stub would read as a clean
|
|
669
|
+
// review, so it is never used for this data-returning verdict); author=Codex → a FRESH Claude adversary.
|
|
670
|
+
// The adversary loads the WIDE context via `dz challenge` (plan + vision + testing + map + degradations),
|
|
671
|
+
// answers C1-C8 in break-it mode, then every P0/P1 is cross-validated by an independent agent and the
|
|
672
|
+
// non-validated ones are dropped (anti-noise). Failure anywhere degrades LOUDLY to a fresh Claude panel.
|
|
673
|
+
const CHALLENGE_SCHEMA = { type: 'object', additionalProperties: false, required: ['findings', 'summary'], properties: { findings: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['c', 'severity', 'title', 'why'], properties: { c: { type: 'string' }, severity: { type: 'string', enum: ['P0', 'P1', 'P2'] }, title: { type: 'string' }, why: { type: 'string' }, where: { type: 'string' } } } }, summary: { type: 'string' } } }
|
|
674
|
+
const CHALLENGE_CIDS = new Set(['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8'])
|
|
675
|
+
// sh-quote for safe interpolation into a Bash string (QE #13 injection via REPO path / dzBin).
|
|
676
|
+
function shq(s) { return "'" + String(s).replace(/'/g, "'\\''") + "'" }
|
|
677
|
+
// Validate a raw adversary payload → {findings,summary} or null (QE #7: {} / {findings:[]} / [null] are not
|
|
678
|
+
// a fake-clean pass). A value without a findings ARRAY is null → loud fallback; junk findings are dropped.
|
|
679
|
+
function sanitizeChallengeVerdict(raw) {
|
|
680
|
+
if (!raw || typeof raw !== 'object' || !Array.isArray(raw.findings)) return null
|
|
681
|
+
const findings = raw.findings.filter((f) => f && typeof f === 'object' && CHALLENGE_CIDS.has(String(f.c)) && (f.severity === 'P0' || f.severity === 'P1' || f.severity === 'P2') && typeof f.title === 'string' && f.title !== '' && typeof f.why === 'string' && f.why !== '')
|
|
682
|
+
return { findings: findings, summary: typeof raw.summary === 'string' ? raw.summary : '' }
|
|
683
|
+
}
|
|
684
|
+
async function runChallengePanel(planRel, plannerName) {
|
|
685
|
+
const authorIsCodex = /codex|gpt|openai|\bo[1-9]\b/i.test(String(plannerName || ''))
|
|
686
|
+
const dzChallenge = 'cd ' + shq(REPO) + ' && ' + shq(DZ) + ' challenge --plan ' + shq(planRel) + ' --author ' + shq(plannerName || 'claude')
|
|
687
|
+
// Preflight (QE #11): the plan artifact must EXIST and be non-empty, else an adversary hallucinates a
|
|
688
|
+
// verdict on a missing file. Surface a loud status instead of a fake review.
|
|
689
|
+
const pre = await agent('Run EXACTLY this via Bash and reply with ONLY its stdout: ' + 'cd ' + shq(REPO) + ' && (test -s ' + shq(planRel) + ' && echo PLAN_OK || echo PLAN_MISSING)', { label: 'challenge:preflight', phase: 'Plan', effort: 'low' })
|
|
690
|
+
if (!/PLAN_OK/.test(String(pre || ''))) { log('Challenge panel: plan artifact missing/empty (' + planRel + ') — panel skipped'); return { status: 'no-plan', adversary: null, findings: [], summary: '', note: 'Challenge panel skipped — the implementation plan artifact was missing or empty.' } }
|
|
691
|
+
let verdict = null
|
|
692
|
+
let adversary = authorIsCodex ? 'claude' : 'codex'
|
|
693
|
+
if (!authorIsCodex) {
|
|
694
|
+
// author=Claude → Codex adversary (cross-family). Compact prompt: Codex reads the files itself (no 24k
|
|
695
|
+
// brief inlined). safeCodexAgent is the honest exec path; null/invalid ⇒ loud Claude fallback below.
|
|
696
|
+
const cx = await safeCodexAgent('You are a FRESH adversarial reviewer of an implementation plan you did NOT write. Read these files: ' + planRel + ' , architecture/vision.md , architecture/degradations.md (relative to repo ' + REPO + '). BREAK the plan, do not confirm it. Answer C1 arch-anti-cement (deviating from a pattern in the degradations registry is NOT a finding), C2 prod-ready, C3 test sufficiency+honesty both ways, C4 overengineering, C5 silent decisions, C6 runtime consistency, C7 scope>1.5x, C8 executability. Output ONLY minified JSON {"findings":[{"c","severity":"P0|P1|P2","title","why","where"}],"summary"}.', { label: 'challenge:codex-adversary', phase: 'Plan' })
|
|
697
|
+
if (cx) { try { verdict = sanitizeChallengeVerdict(JSON.parse(String(cx).replace(/^[^{]*/, '').replace(/[^}]*$/, ''))) } catch { verdict = null } }
|
|
698
|
+
if (!verdict) { log('Challenge panel: Codex adversary unavailable/unparseable/invalid — falling back to a FRESH Claude panel (NOT cross-family; run `dz challenge` + codex manually for a cross-family pass)'); adversary = 'claude-fallback' }
|
|
699
|
+
}
|
|
700
|
+
if (!verdict) {
|
|
701
|
+
// Claude adversary (fresh instance ≠ the author): loads the WIDE brief via dz, then answers the schema.
|
|
702
|
+
const raw = await agent('You are a FRESH adversarial reviewer. You did NOT write this plan. First run EXACTLY this via Bash to load the wide challenge brief (plan + vision + testing + map + degradations + the C1-C8 questions): ' + dzChallenge + '\nThen BREAK the plan per C1-C8 (do NOT confirm it): a finding is a concrete failing input/condition, never a general worry; deviating from a pattern in the degradations registry is NOT a finding. Return the verdict.', { label: 'challenge:claude-adversary', phase: 'Plan', schema: CHALLENGE_SCHEMA })
|
|
703
|
+
verdict = sanitizeChallengeVerdict(raw)
|
|
704
|
+
}
|
|
705
|
+
if (!verdict) { log('Challenge panel: no usable verdict from any adversary — surfacing unavailable status (advisory)'); return { status: 'adversary-unavailable', adversary: adversary, findings: [], summary: '', note: 'Challenge panel could not produce a verdict — run `dz challenge` + the panel manually.' } }
|
|
706
|
+
// Cross-validate P0/P1 by INDEX (QE #5: never by title — duplicate titles cross-contaminate). Deterministic
|
|
707
|
+
// sorted order shared with the validator; results[i] aligns to pp[i].
|
|
708
|
+
const rank = { P0: 3, P1: 2, P2: 1 }
|
|
709
|
+
const pp = verdict.findings.filter((f) => f.severity === 'P0' || f.severity === 'P1').sort((a, b) => (rank[b.severity] - rank[a.severity]) || (a.c < b.c ? -1 : a.c > b.c ? 1 : 0))
|
|
710
|
+
let confirmed = verdict.findings.filter((f) => f.severity === 'P2')
|
|
711
|
+
let status = 'ok'
|
|
712
|
+
if (pp.length > 0) {
|
|
713
|
+
const numbered = pp.map((f, i) => ({ i: i, c: f.c, severity: f.severity, title: f.title, why: f.why }))
|
|
714
|
+
const cv = await agent('Independently CROSS-VALIDATE these adversarial plan findings against the plan at ' + planRel + ' (repo ' + REPO + '). For EACH by its "i" index, decide if it is REAL and reachable, or FP/theory. Default to real=false when uncertain. Findings JSON (with stable index i): ' + JSON.stringify(numbered) + '\nReturn {"results":[{"i":<the index>,"real":true|false}...]} covering EVERY index exactly once.', { label: 'challenge:cross-validate', phase: 'Plan', schema: { type: 'object', additionalProperties: false, required: ['results'], properties: { results: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['i', 'real'], properties: { i: { type: 'number' }, real: { type: 'boolean' } } } } } } })
|
|
715
|
+
const realByIndex = new Map((cv && Array.isArray(cv.results) ? cv.results : []).map((r) => [Number(r.i), r.real === true]))
|
|
716
|
+
// QE #8: a validator OUTAGE (missing indices) must NOT read as "clean" — do not silently drop the P0/P1.
|
|
717
|
+
const covered = pp.every((_, i) => realByIndex.has(i))
|
|
718
|
+
if (!covered) {
|
|
719
|
+
status = 'cross-validation-incomplete'
|
|
720
|
+
log('Challenge panel: cross-validator did not cover every P0/P1 — surfacing them UNVALIDATED (not dropped, not confirmed)')
|
|
721
|
+
for (const f of pp) confirmed.push(Object.assign({}, f, { crossValidated: false, unvalidated: true }))
|
|
722
|
+
} else {
|
|
723
|
+
pp.forEach((f, i) => { if (realByIndex.get(i) === true) confirmed.push(Object.assign({}, f, { crossValidated: true })) })
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
confirmed.sort((a, b) => (rank[b.severity] - rank[a.severity]) || (a.c < b.c ? -1 : a.c > b.c ? 1 : 0))
|
|
727
|
+
const note = status === 'cross-validation-incomplete'
|
|
728
|
+
? 'ADVISORY — cross-validation was INCOMPLETE; P0/P1 shown are UNVALIDATED (verify manually). Nothing blocks.'
|
|
729
|
+
: 'ADVISORY — the owner decides; nothing blocks. Cross-validated P0/P1 + all P2 shown.'
|
|
730
|
+
return { status: status, adversary: adversary, findings: confirmed, summary: verdict.summary, note: note }
|
|
731
|
+
}
|
|
732
|
+
|
|
666
733
|
// Hybrid checkpoint for L/XL
|
|
667
734
|
const stopHere = STOP_AFTER === 'plan' || (isLplus && STOP_AFTER !== 'none')
|
|
668
735
|
if (stopHere) {
|
|
@@ -673,7 +740,11 @@ if (stopHere) {
|
|
|
673
740
|
const qePlanned = qeShouldUseCodex() ? modelLabel(resolveStageModel('qe')) : modelLabel(mergeOpts({ agentType: 'qe-code-reviewer' }, resolveStageModel('qe')))
|
|
674
741
|
const plannedModels = mergeOpts(modelsUsed, { code: codePlanned + ' (planned)', qe: qePlanned + ' (planned)' })
|
|
675
742
|
if (isLplus) plannedModels.fleet = modelLabel(resolveStageModel('fleet')) + ' (planned)'
|
|
676
|
-
|
|
743
|
+
// R6 врезка: adversarial plan-gate (advise). Panel ≠ plan author; wrapped so a panel failure never blocks the checkpoint.
|
|
744
|
+
let challengeVerdict = null
|
|
745
|
+
try { challengeVerdict = plan ? await runChallengePanel('features/' + SLUG + '/06_implementation_plan.md', plan.planner) : null }
|
|
746
|
+
catch (e) { log('Challenge panel errored (advisory, ignored): ' + (e && e.message ? e.message : String(e))) }
|
|
747
|
+
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.' }
|
|
677
748
|
}
|
|
678
749
|
|
|
679
750
|
// Step 7: Code (optional Codex fallback on Claude-limit exhaustion)
|