@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 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.50",
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
- return { tier: tier, phase: 'checkpoint-after-plan', artifactsDir: FDIR, planner: (plan ? plan.planner : null), plan: (plan ? plan.summary : null), modelsUsed: plannedModels, 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), then re-invoke with args.stopAfter="none" to implement + QE.' }
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)