baldart 4.92.1 → 4.93.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.93.0] - 2026-07-02
9
+
10
+ **`/prd` gate-hygiene wave — dai driver misurati (forensics di una sessione reale: 61.6M token, 48% del costo in fasi meccaniche, una famiglia di card con zero audit-trail, 96% del wall-clock in attesa umana).** Sette interventi chirurgici, nessuna nuova chiave di config:
11
+
12
+ - **Tool di misura onesto**: `scripts/new-session-audit.mjs` deduplica l'usage per `message.id` (sovracontava ~2.85× — 175M riportati vs 61.6M reali su FEAT-0061) e riconosce le sessioni `/prd` (`mode=prd`, anche quando la skill è invocata via Skill tool dopo un preambolo; backtrack `self`; confronto col reference FEAT-0041 saltato).
13
+ - **Severità assoluta evidence-anchored** (`prd` skill 1.2.0 + `plan-auditor`): via la quota posizionale "top 20% → HIGH must-apply" — fabbricava cicli di apply su piani puliti e demotava finding reali sui batch grandi. Zero-finding è un esito legittimo.
14
+ - **Validation eseguita, non recitata**: `validate-card-baseline.js --prd` (requirements condizionale PO1, epic `skip`, marker `[NEEDS CLARIFICATION]` bloccanti) + nuovo `framework/scripts/stamp-holistic-audit.js` (stamp `metadata.holistic_audit` deterministico, idempotente; chiamato da 6.9.4 e dal backstop 5b — i due gate-prosa che erano falliti insieme su FEAT-0064).
15
+ - **Context economy dell'orchestratore /prd**: contratto teammate audit estratto in `references/audit-teammate-prompt.md` e passato BY PATH (mai caricato dall'orchestratore; ~−9KB da audit-phase + regola generale per gli spec agent-facing incl. `api-perf-gate.md`); analisi mockup su file delegata a `ui-expert` read-only (misurati ~208KB di mockup in cache per ~300 eventi); Progress Bar solo ai phase-gate con riga compatta intra-fase (~20 righe × 30+ messaggi risparmiate; unifica la policy Codex già esistente).
16
+
17
+ **MINOR** — capability change su skill/agent/script condivisi; nessun cambio di layout install. **No new `baldart.config.yml` key** → la schema-change propagation rule NON si applica. **Codex parity: portable** (script node zero-dep; prosa skill condivisa ai due runtime; il branch file-backed Codex del teammate contract è documentato in-file).
18
+
8
19
  ## [4.92.1] - 2026-07-02
9
20
 
10
21
  **Review avversariale post-release del motore new2 (coerenza interna).** Tre reviewer indipendenti a contesto fresco (dataflow / edge-case / contratti) sull'onda v4.90–4.92; ogni finding ri-verificato contro il codice prima di agire: **11 confermati e fixati, 9 refutati con evidenza empirica** (tra i refutati: la "race" del worker-pool adattivo — simulata: 0 buchi; `verify-item.sh` su bash 3.2 reale — funziona; `parseInt` con CRLF; un CAP attribuito a `new2.js` che non esiste).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.92.1
1
+ 4.93.0
@@ -348,14 +348,15 @@ Consider:
348
348
 
349
349
  ## SEVERITY CALIBRATION (after challenge pass)
350
350
 
351
- After challenge pass, rank ALL surviving findings by impact:
352
-
353
- 1. List all surviving findings in order of impact (most impactful first).
354
- 2. Assign severity based on position:
355
- - Top 20% → **HIGH** (must fix before implementation)
356
- - Middle 40% → **MEDIUM** (should fix, mark `[MANUAL]` if ambiguous)
357
- - Bottom 40% → **LOW** (note only, do not edit structured fields)
358
- 3. **Exception**: data loss, security bypass, breaking change, claimed_path collision, ADR required missing = automatically **HIGH** regardless of position.
351
+ Severity is **ABSOLUTE, per finding, anchored to its evidenced consequence** — never a relative ranking, never a quota. (Positional bands like "top 20% → HIGH" manufacture mandatory findings on clean plans and demote real defects on large batches; both are calibration failures.)
352
+
353
+ For each surviving finding ask: *"what happens if the card is implemented exactly as written?"*
354
+
355
+ - **HIGH** (must fix before implementation) — implementing the card as written produces a defect: data loss, security bypass, breaking change, claimed_path collision, ADR required missing, wrong behavior against a stated AC, an unimplementable AC (e.g. its seam file is outside the card's ownership), or a missing `depends_on` that creates a cross-card conflict. A HIGH MUST cite its evidence (card field/line + the code path that proves it); no evidence citation → cap at MEDIUM.
356
+ - **MEDIUM** (should fix, mark `[MANUAL]` if ambiguous) — the card is implementable but a gap will plausibly cost a review cycle: missing doc/file in `files_likely_touched`, vague-but-inferable AC, missing validation command.
357
+ - **LOW** (note only, do not edit structured fields) — informational, no behavioral consequence.
358
+
359
+ Zero HIGH — or zero findings at all — on a well-formed card is a legitimate, reportable outcome. Do NOT stretch severities to fill bands.
359
360
 
360
361
  ## QUANTIFIED RISK SCORING (MANDATORY)
361
362
 
@@ -91,6 +91,14 @@ the card reaches `status: DONE`.
91
91
 
92
92
  6. **Populate `data_fields`** for every card that reads/writes the persistence layer (see Required Fields).
93
93
 
94
+ **Never guess silently — mark the ambiguity.** The grounding rule generalizes beyond field
95
+ names: whenever card material forces you to GUESS (an unresolved behavior, an unspecified
96
+ control/state, a value the PRD/Discovery never pinned down), do NOT pick a plausible answer
97
+ silently — write `[NEEDS CLARIFICATION: <the exact question>]` inline at the ambiguous spot.
98
+ The `/prd` validation gate (`validate-card-baseline.js --prd`) BLOCKS commit while any marker
99
+ is unresolved, so the ambiguity reaches a human instead of shipping as a hidden assumption.
100
+ A marker is a legitimate intermediate state, never a defect — the defect is the silent guess.
101
+
94
102
  ## Mission
95
103
 
96
104
  You receive:
@@ -2,6 +2,19 @@
2
2
 
3
3
  Formato: [Keep a Changelog](https://keepachangelog.com/) · [SemVer](https://semver.org/).
4
4
 
5
+ ## 1.2.0 — 2026-07-02
6
+
7
+ **Gate-hygiene wave** — dai driver misurati sul forensics di una sessione /prd reale (61.6M token; 48% del costo in fasi meccaniche a piena finestra; una famiglia di card spedita con zero audit-trail; ~20 righe di progress bar × 30+ messaggi):
8
+
9
+ - **Severità assoluta evidence-anchored** (`audit-phase.md` § Severity Calibration + `plan-auditor.md`): rimossa la calibrazione a quota posizionale ("top 20% → HIGH must-apply") che fabbricava finding HIGH su piani puliti e demotava finding reali sui batch grandi. HIGH ora richiede citazione dell'evidenza; zero-finding è un esito legittimo.
10
+ - **Validation ESEGUITA, non recitata** (`validation-phase.md` Step 6 item 0-i): il gate deterministico gira via `validate-card-baseline.js --prd` (enum, requirements condizionale PO1, epic `review_profile: skip`, matrice campi) — i check semantici restano in prosa (0-ii). Nuovo check bloccante: marker `[NEEDS CLARIFICATION: …]` irrisolti (l'ambiguità di planning è un artefatto gated, mai un'assunzione silenziosa; `prd-card-writer` istruito a marcare invece di indovinare).
11
+ - **Stamp holistic deterministico** (`framework/scripts/stamp-holistic-audit.js`, nuovo, zero-dep): `metadata.holistic_audit` scritto da script idempotente/additivo/epic-skipping/self-verifying, chiamato da `audit-phase.md` 6.9.4 E dal backstop `validation-phase.md` 5b (entrambi i call-site erano prosa e sono falliti INSIEME su un run reale).
12
+ - **Prompt agent-facing passati BY PATH** (context economy, ~−30KB dal contesto orchestratore): il contratto teammate dell'audit estratto in `references/audit-teammate-prompt.md` (letto dai teammate, MAI dall'orchestratore); `api-perf-gate.md` dichiarato agent-facing nella flow table (era già delegato, ma la regola "read before each phase" lo faceva caricare comunque); regola generale in SKILL.md.
13
+ - **Mockup mai nel contesto orchestratore** (`discovery-phase.md` 1.6.5): l'analisi mockup su file è DELEGATA a `ui-expert` read-only (ritorna solo lo YAML `mockup_analysis`); misurati ~208KB di mockup decodificato trascinati in cache per ~300 eventi. Eccezione: immagini incollate in chat (già in contesto).
14
+ - **Progress Bar ai phase-gate** (SKILL.md HARD RULE 11): tabella completa solo alle transizioni di fase; riga compatta sugli STOP intra-fase; niente sui messaggi tecnici — adottata su Claude la policy già scritta per Codex (unificazione, non fork).
15
+
16
+ Codex parity: portable (script node zero-dep + prosa skill condivisa; il branch Codex file-backed del teammate contract è documentato nel file stesso).
17
+
5
18
  ## 1.1.2 — 2026-07-01
6
19
 
7
20
  - Context economy: trimmed the HARD-RULES **Runtime portability** citation to a one-liner (cite, don't restate — the detail lives in `runtime-portability-protocol.md`). ~330 chars off the SKILL.md core, which sits in context every turn. No behavior change; RULE 4/11 Codex branches unchanged.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: prd
3
3
  effort: high
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  description: "Structured PRD creation skill. Use when the user says /prd, 'crea un prd', 'nuova funzionalita', 'pianifica feature', or wants to plan a new feature end-to-end. Also handles /prd-add, 'aggiungi requisito', 'serve anche', 'manca un endpoint' for change requests on active PRD sessions — runs ICIAS impact analysis to determine which phases need SKIP/PATCH/REDO. Produces PRD + UI design + backlog cards, all validated and committed. Multi-turn conversation: asks questions, waits for answers, iterates through discovery, design, spec writing, card creation, and validation phases."
6
6
  ---
7
7
 
@@ -46,14 +46,21 @@ message. You ask questions, wait for answers, and iterate.
46
46
  | 2.5 | Research (opzionale) | [research-phase.md](references/research-phase.md) |
47
47
  | 3 | UI Design (3a-3d) | [ui-design-phase.md](references/ui-design-phase.md) |
48
48
  | 4 | Write PRD | [prd-writing-phase.md](references/prd-writing-phase.md) |
49
- | 4.5 | API Performance Gate | [api-perf-gate.md](references/api-perf-gate.md) |
49
+ | 4.5 | API Performance Gate | [api-perf-gate.md](references/api-perf-gate.md) — **agent-facing**: passed BY PATH to `api-perf-cost-auditor` (spawn per prd-writing-phase § 4.5); the orchestrator does NOT read it |
50
50
  | 4b | Confirm Specs (§ "Present and Confirm") | [prd-writing-phase.md](references/prd-writing-phase.md) |
51
51
  | 5 | Backlog Cards | [backlog-phase.md](references/backlog-phase.md) |
52
52
  | 6 | Quality Audit | [validation-phase.md](references/validation-phase.md) |
53
53
  | 7 | Resolution, Commit & Merge | [validation-phase.md](references/validation-phase.md) |
54
54
  | 7.6 | Obsidian back-reference — FINAL (upgrades the 1.2 provisional block; only if a spec note was given) | [validation-phase.md](references/validation-phase.md) + [obsidian-backref.md](references/obsidian-backref.md) |
55
55
 
56
- **Before starting each phase, read the corresponding reference file.**
56
+ **Before starting each phase, read the corresponding reference file** — with ONE
57
+ exception class: **agent-facing specs are passed BY PATH to the agent that consumes
58
+ them and MUST NOT be loaded into the orchestrator context.** Today these are
59
+ `references/api-perf-gate.md` (read by `api-perf-cost-auditor` at Step 4.5 and at the
60
+ Step 6 audit) and `references/audit-teammate-prompt.md` (read by each Step 6.6 audit
61
+ teammate). Rationale: a spec loaded by a subagent costs one cheap Read in a disposable
62
+ context; the same spec in the orchestrator rides EVERY subsequent full-window API call
63
+ for the rest of the run.
57
64
 
58
65
  ---
59
66
 
@@ -73,7 +80,17 @@ message. You ask questions, wait for answers, and iterate.
73
80
  **Worktree-mode exception (HARD RULE 17):** when the PRD runs inside a docs worktree (default since v3.22.0), the session-start update is **SKIPPED** — writing `project-status.md` in the worktree wouldn't be visible to other terminals working on the main repo, and writing it on the main repo would pollute `git status` for parallel sessions (exactly what worktree isolation is meant to prevent). The at-commit update still applies and runs inside the worktree as the last write before rebase + merge — see [validation-phase.md](references/validation-phase.md) § Step 7.
74
81
  10. **STOP means STOP.** When you see `STOP`, end your message. Do not make more tool
75
82
  calls. Do not continue to the next step. Wait for the user.
76
- 11. **Progress visibility.** Claude Code: every message MUST end with the Progress Bar (no exceptions). **Codex**: the Progress Bar is OPTIONAL derive it on demand from the state file and show a compact summary at the phase gates (not after every technical/tool message, per `/new`'s context-economy precedent); update the state file after each phase either way. The discovery **user gates** (one question per message) stay conversational on both runtimes.
83
+ 11. **Progress visibility — at PHASE GATES, not on every message (context economy,
84
+ unified with the Codex policy).** Display the FULL Progress Bar table only at
85
+ **phase transitions**: entering/completing a numbered phase (1.6, 2, 2.5, 3, 4,
86
+ 4b, 5, 6, 7) and on the final message. On intra-phase STOP messages (e.g. each
87
+ discovery question) end with ONE compact line instead:
88
+ `📋 <slug> · Fase <N> <nome> · <indicatore> · Prossimo: <cosa>` (for discovery
89
+ the indicator is `X/11 dimensioni`). Technical/tool messages carry neither.
90
+ The state file is updated after each phase either way and stays the recovery
91
+ SSOT. (Measured driver: ~20 lines × 30+ messages of orchestrator output per
92
+ run bought no signal the compact line doesn't carry.) The discovery **user
93
+ gates** (one question per message) stay conversational on both runtimes.
77
94
  12. **Scope Expansion Detection.** During discovery (Step 2), after every user answer,
78
95
  check if the response introduces NEW structural entities (endpoints, collections,
79
96
  pages, roles, flows) not in the original feature description. If detected, pause
@@ -297,9 +314,12 @@ the value lives only in the state file `## Worktree` section.
297
314
 
298
315
  ---
299
316
 
300
- ## PROGRESS BAR — MANDATORY ON EVERY MESSAGE
317
+ ## PROGRESS BAR — AT PHASE GATES (see HARD RULE 11)
301
318
 
302
- At the END of every message (after all text, before stopping), display:
319
+ At the END of every **phase-transition** message (a numbered phase entered or
320
+ completed, and the final message), display the full table below. On intra-phase
321
+ STOP messages use only the compact line from HARD RULE 11; on technical/tool
322
+ messages display nothing.
303
323
 
304
324
  ```
305
325
  ---
@@ -324,7 +344,8 @@ Prossimo passo: <what happens next>
324
344
 
325
345
  Legend: ⬜ = da fare, 🔄 = in corso, ✅ = completato, ⏭️ = saltato (N/A)
326
346
 
327
- **If your message doesn't end with this table, you violated the skill rules.**
347
+ **If a phase-transition message doesn't end with this table or an intra-phase STOP
348
+ message lacks the compact line — you violated the skill rules.**
328
349
 
329
350
  ---
330
351
 
@@ -106,7 +106,7 @@ Use `TaskCreate` to create one task per audit agent per card:
106
106
 
107
107
  - For **N cards × M agent types**, create **N × M tasks** (one task per agent type per card; excluding Codex plan-audit — see 6.6d). In Step 6.6c, ONE teammate agent per type handles all N tasks in its queue — M agents run in parallel, not N×M.
108
108
  - Each task subject: `[CARD-ID] <agent-type> audit`
109
- - Each task description: full card YAML + adjacent card summaries + file paths + PRD path + instructions.
109
+ - Each task description: full card YAML + adjacent card summaries + file paths + PRD path. The audit instructions are NOT embedded — each teammate reads them from `audit-teammate-prompt.md` (see 6.6e).
110
110
 
111
111
  **Claim-lock (atomicity on the N×M fan-out)**: each task carries a `claimed_by` field, empty at creation. Before a teammate processes a task it MUST atomically set `claimed_by: <its name>` via `TaskUpdate` and re-read; if the field is already non-empty and not its own name, it SKIPS that task (another worker owns it). This prevents two workers — for example a re-spawn after a transient failure, or an overlapping re-audit (Step 6.9) — from both processing the same card+agent pair and producing duplicate findings. The teammate workflow (Step 6.6e) embeds the claim step.
112
112
 
@@ -259,138 +259,31 @@ Suppress findings where the strongest false-positive argument is convincing.
259
259
  - If `codebase-architect` was already spawned earlier this session (its summary is in the session tracker artifact registry), pass that summary in the prompt and instruct plan-auditor NOT to re-invoke `codebase-architect`.
260
260
  - If `security_review_needed: true` (security-reviewer already ran as a teammate), instruct plan-auditor NOT to spawn `security-reviewer`; its security findings are already in the task store and will be merged at Step 6.7. plan-auditor should rely on those rather than running an independent, un-merged second review.
261
261
 
262
- ### 6.6e. Teammate prompt template
262
+ ### 6.6e. Teammate prompt — passed BY PATH (context economy)
263
263
 
264
- Each teammate receives this prompt:
264
+ The full teammate contract identity, task-queue workflow (claim-lock included), the
265
+ per-role audit instructions, the output format with `[Target:]` tags, the challenge
266
+ pass, and the severity calibration — lives in
267
+ [audit-teammate-prompt.md](audit-teammate-prompt.md). That file is an **AGENT-FACING
268
+ spec**: each teammate reads it in ITS OWN context window; the orchestrator MUST NOT
269
+ load it into its own (in a teammate it costs one cheap Read — in the orchestrator it
270
+ would ride every subsequent full-window API call for the rest of the run).
265
271
 
266
- ```
267
- ## Identity
268
-
269
- You are a SKEPTICAL auditor for a pre-development audit team ("check-audit").
270
- Your default stance is that the card is NOT ready for implementation.
271
- Do not rationalize away issues. Do not give benefit of the doubt.
272
- If something COULD be a problem, flag it. The challenge pass (later) will filter false positives.
273
- Your job is RECALL, not precision — catch everything, filter later.
274
-
275
- ## Your Workflow
276
-
277
- 1. Call `TaskList` to see your assigned tasks.
278
- 2. For each task (in ID order):
279
- a. Call `TaskGet` to read the full task description (card YAML + adjacent cards + file paths).
280
- a2. **Claim the task**: if `claimed_by` is already set to a name other than yours, SKIP this task (another worker owns it). Otherwise set `claimed_by: <your name>` via `TaskUpdate`, then re-read via `TaskGet` to confirm your claim held; if a different name won the race, SKIP.
281
- b. Mark task as `in_progress` via `TaskUpdate`.
282
- c. Read any source files or PRDs referenced in the task (use Read tool).
283
- d. Perform your audit (see instructions below).
284
- e. Run the Challenge Pass on your findings (see below).
285
- f. Run Severity Calibration on surviving findings (see below).
286
- g. **Write findings into the task description** via `TaskUpdate` — append a `## FINDINGS` section.
287
- h. Send a brief notification to orchestrator via `SendMessage` (task ID + one-line summary only).
288
- i. Mark task as `completed` via `TaskUpdate`.
289
- 3. After all tasks: send "all tasks complete" to orchestrator.
290
-
291
- **IMPORTANT**: Always write findings to task description (step g) before notification (step h). Task description is durable; message is just a ping.
292
-
293
- ## Audit Instructions
294
-
295
- {AGENT_SPECIFIC_INSTRUCTIONS}
296
-
297
- ## Output Format (mandatory evidence quotes)
298
-
299
- For each card, return findings as:
300
-
301
- ### [CARD-ID] — {Agent Role} Findings
302
-
303
- - [ ] **Finding title** — Description of the issue, risk, or gap. (Severity: HIGH/MEDIUM/LOW) [Target: <field>]
304
- > **Evidence:** "<exact quote from the card YAML, PRD, or source file>"
305
- > **Source:** `<file path or field name>`
306
-
307
- **MANDATORY**: Every finding MUST include an evidence quote — a direct excerpt that grounds it. Findings without quotable evidence MUST be discarded. State: "Considered but discarded — no quotable evidence found."
308
-
309
- If no findings: "No issues found for [CARD-ID]."
310
-
311
- ### `[Target: <field>]` tag reference (mandatory on every finding)
312
-
313
- | Target tag | When to use |
314
- |---|---|
315
- | `[Target: requirements]` | Missing or wrong requirement text |
316
- | `[Target: acceptance_criteria]` | Missing AC, vague AC needing rewrite |
317
- | `[Target: definition_of_done]` | Missing DoD checkbox |
318
- | `[Target: files_likely_touched]` | Missing file path |
319
- | `[Target: depends_on]` | Missing dependency card ID |
320
- | `[Target: areas]` | Missing area entry (api, docs, data, ui) |
321
- | `[Target: git_strategy]` | `git_strategy: TBD` or wrong value |
322
- | `[Target: unknowns]` | Unresolved unknown to surface |
323
- | `[Target: existing_patterns]` | Missing or stale pattern reference |
324
- | `[Target: validation_commands]` | Missing verification command |
325
- | `[Target: anti_patterns]` | Missing DO NOT constraint |
326
- | `[Target: scope_boundaries]` | Missing scope boundary item |
327
- | `[Target: input_output_examples]` | Missing or incorrect I/O example |
328
- | `[Target: error_handling]` | Missing failure mode spec |
329
- | `[Target: reuse_analysis]` | Missing reuse opportunity or wrong path |
330
- | `[Target: notes]` | LOW severity only — informational |
331
-
332
- ## Challenge Pass (mandatory before reporting)
333
-
334
- After generating initial findings, challenge EACH one:
335
-
336
- "What is the strongest argument that this is a false positive?"
337
-
338
- Consider:
339
- - Is this already handled elsewhere in the codebase?
340
- - Is this a convention in this project I'm unfamiliar with?
341
- - Is the card intentionally deferring this to a later card?
342
- - Am I applying a generic best practice that doesn't fit this context?
343
-
344
- **Suppress the finding if the FP argument is convincing.** Record suppressed findings:
272
+ Spawn each teammate with this THIN prompt (fill the placeholders, nothing more):
345
273
 
346
- <details>
347
- <summary>Suppressed findings (N items challenge pass)</summary>
348
- - **Finding title** FP argument: <why suppressed>
349
- </details>
350
-
351
- ## Severity Calibration (after challenge pass)
352
-
353
- After challenge pass, rank ALL surviving findings relative to each other by impact:
354
-
355
- 1. List all surviving findings in order of impact (most impactful first).
356
- 2. Assign severity based on position:
357
- - Top 20% → HIGH (must apply)
358
- - Middle 40% → MEDIUM (should apply)
359
- - Bottom 40% → LOW (notes only)
360
- 3. Exception: data loss, security bypass, or breaking change = automatically HIGH regardless of position.
361
-
362
- ### Severity Calibration Examples
363
-
364
- **HIGH** (must fix before implementation):
365
- - "acceptance_criteria says 'user can see <list>' but doesn't specify pagination → unbounded persistence-layer read"
366
- > Evidence: "AC-2: <persona from identity.audience_segments[]> views <entity>" — no limit/pagination mentioned
367
-
368
- **MEDIUM** (should fix, skip if ambiguous):
369
- - "files_likely_touched missing the API route doc update"
370
- > Evidence: files_likely_touched lists "src/app/api/v1/<domain>/route.ts" but not "${paths.references_dir}/api/<domain>.md"
371
-
372
- **LOW** (note only):
373
- - "Card title could be more descriptive"
374
- > Evidence: title is "Booking API" — functional but generic
274
+ ```
275
+ You are teammate "<name>" (role: <agent-type>) in team "check-audit".
276
+ FIRST ACTION: Read <references-path>/audit-teammate-prompt.md and follow it exactly —
277
+ it defines your identity, task-queue workflow (TaskList/TaskGet/claim/TaskUpdate),
278
+ your role's audit instructions (§ "<agent-type>"), the output format, the challenge
279
+ pass, and the severity calibration. Then work your task queue until every task you
280
+ can claim is completed.
375
281
  ```
376
282
 
377
- ### Agent-specific instructions
378
-
379
- **plan-auditor**: **Handled by Codex adversarial audit (Step 6.6d).** Not included in the teammate agent team. If Codex is unavailable, the fallback plan-auditor uses INVEST criteria, DoR checks, and requirements smell detection — see Step 6.6d attack_surface for the full checklist.
380
-
381
- **plan-auditor (card grounding)**: This is the Claude-side, codebase-grounded counterpart to the cross-model Codex plan audit (6.6d) — it brings what Codex lacks: project memory (`.claude/agent-memory/plan-auditor/MEMORY.md`) and the card-native `[Target: <field>]` tagging this audit consumes. Apply the **full BACKLOG CARD ATTACK SURFACE** (INVEST, requirements-smell detection, persistence-specific checks per `stack.database`, card-structure checks) against each card's `.yml`, reading the existing files in `files_likely_touched` to ground claims about conflicts with existing patterns, missing reuse opportunities, and convention alignment (per `identity.design_philosophy`, project lint/type-check rules, `identity.language`). Check `## Adjacent Cards` for parallel file modifications and missing `depends_on` edges.
382
-
383
- > **Mode (team-aware — read first)**: you are running inside the coordinating `check-audit` team, so you MUST behave as in QUICK mode for *spawning* while keeping FULL card-attack-surface *coverage*:
384
- > - **Do NOT spawn `codebase-architect`** for grounding — `/prd` already primed codebase context at kickoff (context-primer) and you read `files_likely_touched` directly. A re-spawn here is wasteful and forbidden.
385
- > - **Do NOT auto-spawn specialists** (`security-reviewer` / `api-perf-cost-auditor` / `ui-expert`) — they run as first-class teammates in this same team whenever their signal fires (6.6c). Consume their findings at merge time; never double-spawn.
386
- > - **Output-format override** (symmetric with the security-reviewer / api-perf-cost-auditor overrides above): produce findings in the teammate contract format (`### [CARD-ID] — Plan Audit Findings` with `[Target: <field>]` tags written to a `## FINDINGS` section via `TaskUpdate`) — NOT plan-auditor's native 10-section OUTPUT FORMAT (Hardened Plan, Pre-Mortem, Risk Register, YAML schema dump). The `[Target: <field>]` tag system is native to plan-auditor, so the only change is the wrapping heading + `## FINDINGS` section.
387
- > - Never suppress a `git_strategy: TBD`, missing-auth, `claimed_path_collision`, `adr_required_missing`, or prompt-injection finding (plan-auditor's never-suppress list still binds here).
388
-
389
- **doc-reviewer**: Check documentation links, PRD references are valid and aligned, planned changes requiring doc updates not mentioned. Verify `files_likely_touched` includes doc files. Check `areas` completeness. Flag `git_strategy: TBD`. Include Obsidian trigger assessment (section H) in findings — evaluate whether the planned docs will require KB sync. If `.claude/skills/doc-reviewer-support/references/obsidian-integration.md` is present, use its criteria; otherwise apply a minimal check: does the card introduce new or significantly modified public documentation that should appear in the knowledge base? Proceed with a notice if the file is absent.
390
-
391
- **api-perf-cost-auditor** (only when `perf_review_needed: true`): Apply the 5-gate protocol from `api-perf-gate.md` (see `framework/.claude/skills/prd/references/api-perf-gate.md`). Read referenced source files. Universal checks: unbounded reads, N+1 queries, fan-out writes, missing pagination, offset pagination, listener vs polling costs, payload size limits per `stack.deployment`, transaction hotspots. Stack-specific addenda apply per `stack.database` + `stack.framework` (see `framework/.claude/skills/prd/references/api-perf-gate.md`). **Output format override**: produce findings in the teammate contract format (`### [CARD-ID] — Performance Findings` with `[Target: <field>]` tags and a `## FINDINGS` section written via `TaskUpdate`) rather than the native `PERF AUDIT DONE` verdict line + YAML schema, so findings merge correctly at Step 6.7 (symmetric with the `security-reviewer` override below).
392
-
393
- **security-reviewer** (only when `security_review_needed: true`): Apply the full security-reviewer methodology. Focus on: auth gaps, input validation, multi-tenant isolation, persistence-layer access rules alignment (Firestore rules / Supabase RLS / Mongo validator / DynamoDB IAM — per `stack.database`), sensitive data exposure, webhook validation, rate limiting, IDOR risks. **Output format override**: produce findings in the teammate contract format (`### [CARD-ID] — Security Findings` with `[Target: <field>]` tags and `## FINDINGS` section written via `TaskUpdate`) rather than the native `# Security Review Summary` format, so findings merge correctly at Step 6.7.
283
+ `<references-path>` = the absolute path of this skill's `references/` directory in this
284
+ install — the same directory you read THIS file from (in a consumer typically
285
+ `<repo>/.claude/skills/prd/references`). Do NOT paste the contract's content into the
286
+ spawn prompt or the task descriptions — the path IS the payload.
394
287
 
395
288
  ## Step 6.7 — Collect & Merge Findings
396
289
 
@@ -515,13 +408,23 @@ metadata:
515
408
 
516
409
  > **Fail-safe contract**: the block is an OPTIMIZATION hint for `/new`, never a *correctness* gate — if `audited_commit` is empty or the block is absent, `/new` Step 3d **and** the `implement.md` Phase-1 plan-auditor grounding (step 4, P1) simply RUN as before (redundant, never wrong). **But writing the block is MANDATORY whenever the audit ran.** It is the single most-omitted step under context pressure, and its absence is exactly what makes `/new` / `new2` spawn the plan-auditor on **every** freshly-authored card even when the batch is implemented immediately after this audit (nothing changed since). Do NOT skip it "to save a write". If git is genuinely unavailable, write `audited_commit: ""` **explicitly** — never omit the block. `validation-phase.md` Step 7 item 5b is the **deterministic backstop** that guarantees this lands before the PRD commit even if this per-card write is missed — but write it here too; the backstop is a safety net, not a license to skip.
517
410
 
411
+ **Deterministic writer — EXECUTE, don't hand-edit.** `framework/scripts/stamp-holistic-audit.js` mechanizes this write (idempotent, additive, epic-skipping, self-verifying). Run it ONCE for the whole card set after the per-card field edits:
412
+
413
+ ```bash
414
+ node .framework/framework/scripts/stamp-holistic-audit.js \
415
+ --at "$HOLISTIC_AUDITED_AT" --commit "$HOLISTIC_AUDITED_COMMIT" \
416
+ --set "<sorted child IDs, comma-separated>" ${CARD_PATHS}
417
+ ```
418
+
419
+ Hand-edit the YAML only when the script is genuinely unreachable in this install — and say so in the audit log.
420
+
518
421
  ### Per-card workflow
519
422
 
520
423
  For each card:
521
424
  1. Read persisted report → collect all findings for this card ID.
522
425
  2. Read current card YAML.
523
426
  3. Apply HIGH findings first, then MEDIUM, then write audit trail.
524
- 4. Write the `metadata.holistic_audit` provenance block (see "Holistic-audit provenance stamp" above) using the run-level values captured once. **MANDATORY when the audit ran** (see the Fail-safe contract above) — this is what lets `/new`/`new2` skip the per-card plan-auditor when the card is implemented right after `/prd`; `validation-phase.md` Step 7 item 5b deterministically backstops it, but do not rely on the backstop.
427
+ 4. Write the `metadata.holistic_audit` provenance block (see "Holistic-audit provenance stamp" above) **by EXECUTING `stamp-holistic-audit.js` once for the whole card set** (after the last card's field edits), not by hand-editing YAML. **MANDATORY when the audit ran** (see the Fail-safe contract above) — this is what lets `/new`/`new2` skip the per-card plan-auditor when the card is implemented right after `/prd`; `validation-phase.md` Step 7 item 5b deterministically backstops it, but do not rely on the backstop.
525
428
  5. Write updated card YAML.
526
429
  6. Re-read to verify edits landed correctly.
527
430
 
@@ -538,4 +441,4 @@ Every component in this audit encodes an assumption about what the model can't d
538
441
  - Remove one component at a time, measure audit quality delta.
539
442
  - If delta < 5% `[CALIBRATION-NEEDED: removal threshold is a heuristic; validate against a labelled audit-quality benchmark before treating it as a hard cutoff]`, remove permanently.
540
443
  - **Current load-bearing assumptions**: challenge pass, adjacent card retrieval, evidence quotes, adversarial evaluator tuning.
541
- - **Assumptions to re-test**: agent team separation (could single-agent handle N cards?), relative severity ranking (does absolute assignment work with better models?).
444
+ - **Assumptions to re-test**: agent team separation (could single-agent handle N cards?). (Relative severity ranking was retired in the gate-hygiene wave: severity is now absolute + evidence-anchored positional quotas manufactured mandatory findings on clean plans.)
@@ -0,0 +1,144 @@
1
+ # Audit Teammate Contract (Step 6.6) — AGENT-FACING SPEC
2
+
3
+ > **Who reads this file: the audit TEAMMATES** spawned at audit-phase Step 6.6c, in
4
+ > their own context windows. The `/prd` orchestrator passes this file **BY PATH** in
5
+ > the spawn prompt and MUST NOT load it into its own context — in a teammate this
6
+ > spec costs one cheap Read; in the orchestrator it would ride every subsequent
7
+ > full-window API call for the rest of the run (context economy).
8
+
9
+ ## Identity
10
+
11
+ You are a SKEPTICAL auditor for a pre-development audit team ("check-audit").
12
+ Your default stance is that the card is NOT ready for implementation.
13
+ Do not rationalize away issues. Do not give benefit of the doubt.
14
+ If something COULD be a problem, flag it. The challenge pass (later) will filter false positives.
15
+ Your job is RECALL, not precision — catch everything, filter later.
16
+
17
+ ## Your Workflow
18
+
19
+ 1. Call `TaskList` to see your assigned tasks.
20
+ 2. For each task (in ID order):
21
+ a. Call `TaskGet` to read the full task description (card YAML + adjacent cards + file paths).
22
+ a2. **Claim the task**: if `claimed_by` is already set to a name other than yours, SKIP this task (another worker owns it). Otherwise set `claimed_by: <your name>` via `TaskUpdate`, then re-read via `TaskGet` to confirm your claim held; if a different name won the race, SKIP.
23
+ b. Mark task as `in_progress` via `TaskUpdate`.
24
+ c. Read any source files or PRDs referenced in the task (use Read tool).
25
+ d. Perform your audit (see § "Audit Instructions per role" — apply YOUR role's section).
26
+ e. Run the Challenge Pass on your findings (see below).
27
+ f. Run Severity Calibration on surviving findings (see below).
28
+ g. **Write findings into the task description** via `TaskUpdate` — append a `## FINDINGS` section.
29
+ h. Send a brief notification to orchestrator via `SendMessage` (task ID + one-line summary only).
30
+ i. Mark task as `completed` via `TaskUpdate`.
31
+ 3. After all tasks: send "all tasks complete" to orchestrator.
32
+
33
+ **IMPORTANT**: Always write findings to task description (step g) before notification (step h). Task description is durable; message is just a ping.
34
+
35
+ > **Codex runtime**: when the run is file-backed (no task spine), the same workflow
36
+ > applies over the task files at `…/sessions/<slug>-audit/tasks/` — claim by writing
37
+ > `claimed_by`, persist findings to `audit/findings/<agent>-<CARD-ID>.json`. Binding:
38
+ > `framework/agents/runtime-portability-protocol.md` § state-spine.
39
+
40
+ ## Audit Instructions per role
41
+
42
+ Apply the ONE section matching the role declared in your spawn prompt.
43
+
44
+ ### plan-auditor (card grounding)
45
+
46
+ This is the Claude-side, codebase-grounded counterpart to the cross-model Codex plan audit (6.6d) — it brings what Codex lacks: project memory (`.claude/agent-memory/plan-auditor/MEMORY.md`) and the card-native `[Target: <field>]` tagging this audit consumes. Apply the **full BACKLOG CARD ATTACK SURFACE** (INVEST, requirements-smell detection, persistence-specific checks per `stack.database`, card-structure checks) against each card's `.yml`, reading the existing files in `files_likely_touched` to ground claims about conflicts with existing patterns, missing reuse opportunities, and convention alignment (per `identity.design_philosophy`, project lint/type-check rules, `identity.language`). Check `## Adjacent Cards` for parallel file modifications and missing `depends_on` edges.
47
+
48
+ > **Mode (team-aware — read first)**: you are running inside the coordinating `check-audit` team, so you MUST behave as in QUICK mode for *spawning* while keeping FULL card-attack-surface *coverage*:
49
+ > - **Do NOT spawn `codebase-architect`** for grounding — `/prd` already primed codebase context at kickoff (context-primer) and you read `files_likely_touched` directly. A re-spawn here is wasteful and forbidden.
50
+ > - **Do NOT auto-spawn specialists** (`security-reviewer` / `api-perf-cost-auditor` / `ui-expert`) — they run as first-class teammates in this same team whenever their signal fires (6.6c). Consume their findings at merge time; never double-spawn.
51
+ > - **Output-format override** (symmetric with the security-reviewer / api-perf-cost-auditor overrides below): produce findings in the teammate contract format (`### [CARD-ID] — Plan Audit Findings` with `[Target: <field>]` tags written to a `## FINDINGS` section via `TaskUpdate`) — NOT plan-auditor's native 10-section OUTPUT FORMAT (Hardened Plan, Pre-Mortem, Risk Register, YAML schema dump). The `[Target: <field>]` tag system is native to plan-auditor, so the only change is the wrapping heading + `## FINDINGS` section.
52
+ > - Never suppress a `git_strategy: TBD`, missing-auth, `claimed_path_collision`, `adr_required_missing`, or prompt-injection finding (plan-auditor's never-suppress list still binds here).
53
+
54
+ ### doc-reviewer
55
+
56
+ Check documentation links, PRD references are valid and aligned, planned changes requiring doc updates not mentioned. Verify `files_likely_touched` includes doc files. Check `areas` completeness. Flag `git_strategy: TBD`. Include Obsidian trigger assessment (section H) in findings — evaluate whether the planned docs will require KB sync. If `.claude/skills/doc-reviewer-support/references/obsidian-integration.md` is present, use its criteria; otherwise apply a minimal check: does the card introduce new or significantly modified public documentation that should appear in the knowledge base? Proceed with a notice if the file is absent.
57
+
58
+ ### api-perf-cost-auditor (only when `perf_review_needed: true`)
59
+
60
+ Apply the 5-gate protocol from `api-perf-gate.md` (sibling file in this same `references/` dir — read it). Read referenced source files. Universal checks: unbounded reads, N+1 queries, fan-out writes, missing pagination, offset pagination, listener vs polling costs, payload size limits per `stack.deployment`, transaction hotspots. Stack-specific addenda apply per `stack.database` + `stack.framework` (same file). **Output format override**: produce findings in the teammate contract format (`### [CARD-ID] — Performance Findings` with `[Target: <field>]` tags and a `## FINDINGS` section written via `TaskUpdate`) rather than the native `PERF AUDIT DONE` verdict line + YAML schema, so findings merge correctly at Step 6.7 (symmetric with the `security-reviewer` override below).
61
+
62
+ ### security-reviewer (only when `security_review_needed: true`)
63
+
64
+ Apply the full security-reviewer methodology. Focus on: auth gaps, input validation, multi-tenant isolation, persistence-layer access rules alignment (Firestore rules / Supabase RLS / Mongo validator / DynamoDB IAM — per `stack.database`), sensitive data exposure, webhook validation, rate limiting, IDOR risks. **Output format override**: produce findings in the teammate contract format (`### [CARD-ID] — Security Findings` with `[Target: <field>]` tags and `## FINDINGS` section written via `TaskUpdate`) rather than the native `# Security Review Summary` format, so findings merge correctly at Step 6.7.
65
+
66
+ ## Output Format (mandatory evidence quotes)
67
+
68
+ For each card, return findings as:
69
+
70
+ ### [CARD-ID] — {Agent Role} Findings
71
+
72
+ - [ ] **Finding title** — Description of the issue, risk, or gap. (Severity: HIGH/MEDIUM/LOW) [Target: <field>]
73
+ > **Evidence:** "<exact quote from the card YAML, PRD, or source file>"
74
+ > **Source:** `<file path or field name>`
75
+
76
+ **MANDATORY**: Every finding MUST include an evidence quote — a direct excerpt that grounds it. Findings without quotable evidence MUST be discarded. State: "Considered but discarded — no quotable evidence found."
77
+
78
+ If no findings: "No issues found for [CARD-ID]."
79
+
80
+ ### `[Target: <field>]` tag reference (mandatory on every finding)
81
+
82
+ | Target tag | When to use |
83
+ |---|---|
84
+ | `[Target: requirements]` | Missing or wrong requirement text |
85
+ | `[Target: acceptance_criteria]` | Missing AC, vague AC needing rewrite |
86
+ | `[Target: definition_of_done]` | Missing DoD checkbox |
87
+ | `[Target: files_likely_touched]` | Missing file path |
88
+ | `[Target: depends_on]` | Missing dependency card ID |
89
+ | `[Target: areas]` | Missing area entry (api, docs, data, ui) |
90
+ | `[Target: git_strategy]` | `git_strategy: TBD` or wrong value |
91
+ | `[Target: unknowns]` | Unresolved unknown to surface |
92
+ | `[Target: existing_patterns]` | Missing or stale pattern reference |
93
+ | `[Target: validation_commands]` | Missing verification command |
94
+ | `[Target: anti_patterns]` | Missing DO NOT constraint |
95
+ | `[Target: scope_boundaries]` | Missing scope boundary item |
96
+ | `[Target: input_output_examples]` | Missing or incorrect I/O example |
97
+ | `[Target: error_handling]` | Missing failure mode spec |
98
+ | `[Target: reuse_analysis]` | Missing reuse opportunity or wrong path |
99
+ | `[Target: notes]` | LOW severity only — informational |
100
+
101
+ ## Challenge Pass (mandatory before reporting)
102
+
103
+ After generating initial findings, challenge EACH one:
104
+
105
+ "What is the strongest argument that this is a false positive?"
106
+
107
+ Consider:
108
+ - Is this already handled elsewhere in the codebase?
109
+ - Is this a convention in this project I'm unfamiliar with?
110
+ - Is the card intentionally deferring this to a later card?
111
+ - Am I applying a generic best practice that doesn't fit this context?
112
+
113
+ **Suppress the finding if the FP argument is convincing.** Record suppressed findings:
114
+
115
+ <details>
116
+ <summary>Suppressed findings (N items — challenge pass)</summary>
117
+ - **Finding title** — FP argument: <why suppressed>
118
+ </details>
119
+
120
+ ## Severity Calibration (after challenge pass)
121
+
122
+ Severity is **ABSOLUTE, per finding, anchored to its evidenced consequence** — never a relative ranking, never a quota. (Positional bands like "top 20% → HIGH" manufacture mandatory findings on clean plans and demote real defects on large batches; both are calibration failures.)
123
+
124
+ For each surviving finding ask: *"what happens if the card is implemented exactly as written?"*
125
+
126
+ - **HIGH** — implementing the card as written produces a defect: data loss, security bypass, breaking change, wrong behavior against a stated AC, an unimplementable AC (e.g. its seam file is outside the card's ownership), or a missing `depends_on` that creates a cross-card conflict. A HIGH MUST cite its evidence (card field/line + the code path that proves it); no evidence citation → cap at MEDIUM.
127
+ - **MEDIUM** — the card is implementable but a gap will plausibly cost a review cycle: missing doc/file in `files_likely_touched`, vague-but-inferable AC, missing validation command.
128
+ - **LOW** — informational, no behavioral consequence (naming, style, nice-to-have).
129
+
130
+ Zero HIGH — or zero findings at all — on a well-formed card is a legitimate, reportable outcome. Do NOT stretch severities to fill bands.
131
+
132
+ ### Severity Calibration Examples
133
+
134
+ **HIGH** (must fix before implementation):
135
+ - "acceptance_criteria says 'user can see <list>' but doesn't specify pagination → unbounded persistence-layer read"
136
+ > Evidence: "AC-2: <persona from identity.audience_segments[]> views <entity>" — no limit/pagination mentioned
137
+
138
+ **MEDIUM** (should fix, skip if ambiguous):
139
+ - "files_likely_touched missing the API route doc update"
140
+ > Evidence: files_likely_touched lists "src/app/api/v1/<domain>/route.ts" but not "${paths.references_dir}/api/<domain>.md"
141
+
142
+ **LOW** (note only):
143
+ - "Card title could be more descriptive"
144
+ > Evidence: title is "Booking API" — functional but generic
@@ -589,17 +589,34 @@ user's own folder outside the worktree — never modify or clean it; only read.
589
589
 
590
590
  Then continue to Step 1.6.5 with the selected subset.
591
591
 
592
- ### 1.6.5 — Mockup analysis (MANDATORY before Discovery)
593
-
594
- Analyze ALL provided mockups (visual analysis for chat images, Read for copied files
595
- that are textual like HTML/SVG). Populate `## UI Design` in the state file using the
596
- **Mockup analysis schema** (see appendix at the end of this file).
597
-
598
- When `features.has_design_system: true`, BLOCKING reads of `${paths.design_system}/INDEX.md`
599
- and `${paths.design_system}/tokens-reference.md` apply BEFORE running the alignment
600
- check same protocol as Step 3 (UI Design). Flag every hardcoded value (hex / shadow /
601
- radius / spacing) that conflicts with a known token as a violation in
602
- `mockup_analysis.design_system_alignment.violations[]`.
592
+ ### 1.6.5 — Mockup analysis (MANDATORY before Discovery — DELEGATED, mockup bytes never in the orchestrator)
593
+
594
+ **HARD RULE the orchestrator MUST NOT Read the mockup files** (images OR HTML/SVG
595
+ bundles). A decoded mockup read in the main context rides EVERY subsequent
596
+ full-window API call for the rest of the run (measured on a real session: ~208KB
597
+ dragged through the cache for ~300 events). The only exception is a mockup pasted
598
+ directly in chat as an image — that is already in context; analyze it inline.
599
+
600
+ For all on-disk mockups, **spawn ONE `ui-expert` subagent in read-only analysis
601
+ mode** with this brief:
602
+ - the mockup file paths (`mockups.canonical_paths[]`) — the agent Reads them in ITS
603
+ context (it is multimodal: images render, HTML is read as text);
604
+ - the schema to fill: instruct it to open THIS file
605
+ (`references/discovery-phase.md`) and read ONLY the section
606
+ `## Appendix — Mockup analysis schema` (Grep the heading, Read from that offset);
607
+ - when `features.has_design_system: true`: the paths of
608
+ `${paths.design_system}/INDEX.md` and `${paths.design_system}/tokens-reference.md`
609
+ (BLOCKING reads for the agent — same protocol as Step 3), with the instruction to
610
+ flag every hardcoded value (hex / shadow / radius / spacing) that conflicts with a
611
+ known token as a violation in `mockup_analysis.design_system_alignment.violations[]`;
612
+ - **ROLE BOUNDARY**: analysis only — no code, no file writes, no Task spawns. Its
613
+ final message is the filled `mockup_analysis` YAML and NOTHING else (COMPACT
614
+ return contract).
615
+
616
+ The orchestrator persists the returned YAML into `## UI Design` in the state file
617
+ verbatim. If the agent's YAML is malformed, re-spawn once with the error; on a
618
+ second failure, fall back to inline analysis (and say so — the fallback is visible,
619
+ never silent).
603
620
 
604
621
  ### 1.6.6 — Output and handoff to Discovery
605
622
 
@@ -6,15 +6,26 @@
6
6
 
7
7
  Mark task 5 as `in_progress`.
8
8
 
9
- 0. **Agent Specialization Audit (runs FIRST, blocks if any failure)** — for each generated child card (epics are skipped):
9
+ 0. **Agent Specialization Audit (runs FIRST, blocks if any failure)** — two layers:
10
10
 
11
- a. **`owner_agent` enum check (BLOCKING)** read the `owner_agent` field. It MUST equal one of:
12
- ```
13
- coder | ui-expert | plan | visual-designer | motion-expert
14
- ```
15
- Empty string, missing field, `claude`, or any other value = **BLOCKER**.
16
- Message to the user: `"Card <ID> has owner_agent: '<value>' — must be one of {coder, ui-expert, plan, visual-designer, motion-expert}. Fix the card YAML before commit."`
17
- Halt the audit. No subsequent checks run on a card that fails this gate.
11
+ **0-i. Deterministic gate EXECUTED, never recited (BLOCKING).** Run the framework validator in `/prd` mode on EVERY generated card (epics included — it is profile-aware):
12
+
13
+ ```bash
14
+ node .framework/framework/scripts/validate-card-baseline.js --prd \
15
+ "$WORKTREE_PATH/${paths.backlog_dir}"/FEAT-XXXX-*.yml
16
+ ```
17
+ (resolve the script path for your install; only if it is genuinely unreachable, fall back to reciting the checks below and say so explicitly in the audit log).
18
+
19
+ Exit 1 = **BLOCKER**: print the per-field errors verbatim, fix the card YAML, re-run until exit 0. No subsequent checks run on a card while it fails this gate. The script covers deterministically:
20
+ - **`owner_agent` enum** — must be one of `{coder, ui-expert, plan, visual-designer, motion-expert}` (empty/missing/`claude` = blocker);
21
+ - **`review_profile` enum + epic `skip`** — `skip|light|balanced|deep`; missing/empty = blocker (the card-writer must compute it via `prd-card-writer.md § Rule C`); epics MUST be `skip`;
22
+ - **conditional `requirements` presence (PO1)** — a child/standalone card with non-empty `acceptance_criteria` + `scope` MUST carry `requirements` (a fresh `/prd` card without them shifts a measured ~3–4M-token back-fill into `/new`'s orchestrator — see `card-schema.md` § "Authoring completeness invariants");
23
+ - **unresolved `[NEEDS CLARIFICATION: …]` markers** — a card carrying a planning ambiguity is NOT implementable. Resolve each marker (with the user via `AskUserQuestion` when it needs a human answer, or from Discovery/PRD material when it does not), edit the card, re-run;
24
+ - the universal field-state matrix + remaining enums (`card-schema.md`).
25
+
26
+ **Why executed and not recited:** the prose version of this gate has already failed silently on a real run (a whole card family shipped with zero audit trail). A recited check degrades under context pressure; an executed one cannot.
27
+
28
+ **0-ii. Semantic checks (the model reads the cards — not scriptable):**
18
29
 
19
30
  b. **UI-only scope heuristic (WARN — soft gate, not blocking)** — for each card with `owner_agent: ui-expert`:
20
31
  - Concatenate `scope.summary`, `requirements[]`, and `acceptance_criteria[]` into one lowercase string.
@@ -24,23 +35,7 @@ Mark task 5 as `in_progress`.
24
35
  - The check is intentionally a soft gate: substrings like "API contract per il mock" or "consumes the auth state from `useAuth()`" are legitimate UI references. The WARN exists to prompt human review, not to block.
25
36
  - Exception (no WARN): the marker appears INSIDE a quoted string that explicitly says "consume", "mock", "contract reference", or "exposed by sibling card" — those are UI cards reading an upstream contract, which is expected. **[SEMANTIC — not purely deterministic]** Determining whether a marker substring is (a) inside a YAML quoted string and (b) that string contains one of the escape phrases requires contextual interpretation across multiple YAML quoting styles (single-quote, double-quote, block scalar). FP posture: when in doubt, log the WARN and let the human decide — do not suppress a WARN based on uncertain quoting analysis.
26
37
 
27
- c. **`review_profile` enum check (BLOCKING)**read the `review_profile` field on each child card. It MUST equal one of:
28
- ```
29
- skip | light | balanced | deep
30
- ```
31
- - **Missing or empty** = **BLOCKER** — the card-writer must compute it via `prd-card-writer.md § Rule C` (the SSOT mapping table). Message: `"Card <ID> has no review_profile — compute it from Rule C (skip|light|balanced|deep) before commit."`
32
- - **Out-of-enum value** = **BLOCKER**. Message: `"Card <ID> has review_profile: '<value>' — must be one of {skip, light, balanced, deep}."`
33
- - **Consistency WARN (soft)**: a `feature`/`enhancement` card with `review_profile: light` may violate Rule C. Log `"[REVIEW-PROFILE-WARN] Card <ID> is feature/enhancement but review_profile: light — verify against Rule C in prd-card-writer.md."` **Do NOT auto-bump the field** — `review_profile` is computed by `prd-card-writer` (Rule C); see `prd-card-writer.md` for the criteria. This is a soft gate: log the warning and surface it for human review.
34
- - **Epics**: `review_profile` MUST be `skip` (trackers have no code work). Any other value = WARN, normalize to `skip`.
35
-
36
- d. **`requirements` presence (BLOCKING — PO1)** — for each CHILD/STANDALONE card whose
37
- `acceptance_criteria` AND `scope` are both non-empty, `requirements` MUST be present and
38
- non-empty. A freshly authored `/prd` card with derivable material but no `requirements` is an
39
- authoring miss that shifts a measured ~3–4M-token back-fill into `/new`'s orchestrator context
40
- (see `card-schema.md` § "Authoring completeness invariants"). `/prd` fixes it now for free.
41
- Message: `"Card <ID> has acceptance_criteria + scope but no requirements — emit requirements
42
- (faithful restatement of AC + scope) before commit."` (The `/new` conditional back-fill remains
43
- only as the safety net for legacy / externally-authored cards.)
38
+ c. **Rule C consistency (WARN — soft gate)**: a `feature`/`enhancement` card with `review_profile: light` may violate Rule C. Log `"[REVIEW-PROFILE-WARN] Card <ID> is feature/enhancement but review_profile: light verify against Rule C in prd-card-writer.md."` **Do NOT auto-bump the field** — `review_profile` is computed by `prd-card-writer` (Rule C); see `prd-card-writer.md` for the criteria. This is a soft gate: log the warning and surface it for human review. (The enum/presence/epic-`skip` checks are handled deterministically by 0-i.)
44
39
 
45
40
  e. **files_likely_touched coverage (BLOCKING — P1/P2 closure)** — two sub-checks:
46
41
  - **⊆ coverage (P2):** every file path named in a card's `requirements` /
@@ -58,9 +53,10 @@ Mark task 5 as `in_progress`.
58
53
  no card — assign it to a card's files_likely_touched."`
59
54
  Both are SEMANTIC (path extraction from prose / ISA needs interpretation) — bias toward flagging.
60
55
 
61
- **Gate**: every card has `owner_agent` AND `review_profile` in their enums, `requirements` present when
62
- derivable (d), and full files_likely_touched coverage (e). WARN entries from checks (b)/(c) are noted in
63
- the audit log; user may accept them after review. The (d)/(e) BLOCKERs must be fixed before commit.
56
+ **Gate**: the 0-i validator exits 0 on every card (enums, conditional `requirements`, zero
57
+ `[NEEDS CLARIFICATION]` markers) AND full files_likely_touched coverage (e). WARN entries from
58
+ checks (b)/(c) are noted in the audit log; user may accept them after review. The 0-i and (e)
59
+ BLOCKERs must be fixed before commit.
64
60
 
65
61
  1. **Field Name Audit (runs after item 0 — only when item 0 passes for a given card; skipped for cards blocked in item 0)** — for each generated card:
66
62
 
@@ -132,37 +128,37 @@ created by Step 1 (HARD RULE 17). `$WORKTREE_PATH` is set in the state file.
132
128
  (`paths.metrics` default: `docs/metrics`), which must be part of the same commit.
133
129
  Non-blocking: if it fails, log "Metrics Log: SKIPPED" in the progress bar and continue.
134
130
 
135
- 5b. **Holistic-audit provenance backstop (BLOCKING on the STAMP, never on the PRD).**
136
- The per-card stamp write in `audit-phase.md` Step 6.9.4 is model-driven and is the
137
- single most-omitted step under context pressure. When it is skipped, every card
138
- ships WITHOUT `metadata.holistic_audit` — and `/new` (`implement.md` Phase 1 step 4,
139
- P1) + `new2` then spawn the plan-auditor on **every** card even when the batch is
140
- implemented immediately after this audit (nothing changed). Step 6 is complete (its
141
- gate passed), so the audit genuinely ran: this is the authoritative, deterministic
142
- point to guarantee the stamp lands. **Do NOT re-derive the semantics** reuse the
143
- run-level values and the YAML block DEFINED in `audit-phase.md` § "Holistic-audit
144
- provenance stamp".
145
- - Recompute the three run-level values ONCE (same snippet as audit-phase.md), inside
146
- `$WORKTREE_PATH`:
147
- ```bash
148
- HOLISTIC_AUDITED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
149
- HOLISTIC_AUDITED_COMMIT="$(git -C "$WORKTREE_PATH" merge-base HEAD "${git.trunk_branch}" 2>/dev/null || git -C "$WORKTREE_PATH" rev-parse "${git.trunk_branch}" 2>/dev/null || echo "")"
150
- # audited_set = the sorted Step-5 child card IDs (the joint cross-card scope).
151
- ```
152
- - For EACH **non-EPIC** card from Step 5: if it lacks `metadata.holistic_audit` with a
153
- non-empty `audited_commit`, WRITE the block (additive never overwrite other
154
- `metadata` keys). A card that already carries it (from Step 6.9.4) is untouched —
155
- **idempotent**. EPIC-parent cards are excluded (they carry `planning_session` only
156
- `card-schema.md`).
157
- - Re-read one backfilled card to verify the block landed. Log
158
- `holistic_audit provenance: N/N cards stamped (M backfilled here)`.
131
+ 5b. **Holistic-audit provenance backstop (BLOCKING on the STAMP, never on the PRD)
132
+ EXECUTED via script.** The per-card stamp write in `audit-phase.md` Step 6.9.4 is
133
+ model-driven and is the single most-omitted step under context pressure; when it is
134
+ skipped, every card ships WITHOUT `metadata.holistic_audit` — and `/new`
135
+ (`implement.md` Phase 1 step 4, P1) + `new2` then spawn the plan-auditor on **every**
136
+ card even when the batch is implemented immediately after this audit. Step 6 is
137
+ complete (its gate passed), so the audit genuinely ran: guarantee the stamp lands by
138
+ RUNNING the deterministic stamper (semantics defined in `audit-phase.md`
139
+ § "Holistic-audit provenance stamp" the script only mechanizes the write):
140
+ ```bash
141
+ HOLISTIC_AUDITED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
142
+ HOLISTIC_AUDITED_COMMIT="$(git -C "$WORKTREE_PATH" merge-base HEAD "${git.trunk_branch}" 2>/dev/null || git -C "$WORKTREE_PATH" rev-parse "${git.trunk_branch}" 2>/dev/null || echo "")"
143
+ # --set = the sorted Step-5 child card IDs (the joint cross-card scope), comma-separated.
144
+ node .framework/framework/scripts/stamp-holistic-audit.js \
145
+ --at "$HOLISTIC_AUDITED_AT" --commit "$HOLISTIC_AUDITED_COMMIT" \
146
+ --set "<ID1,ID2,...>" "$WORKTREE_PATH/${paths.backlog_dir}"/FEAT-XXXX-*.yml
147
+ ```
148
+ The script is **idempotent** (a card already stamped by Step 6.9.4 is untouched),
149
+ **additive** (never overwrites other `metadata` keys), skips EPIC cards (they carry
150
+ `planning_session` only `card-schema.md`), and verifies its own writes. Log its
151
+ summary line (`holistic_audit provenance: N/N non-epic cards stamped (M written
152
+ here, …)`) in the audit log. Only if the script is genuinely unreachable in this
153
+ install, fall back to the manual per-card write per `audit-phase.md` § "Holistic-audit
154
+ provenance stamp" and say so explicitly.
159
155
  **Fail-safe (unchanged contract):** the stamp is an OPTIMIZATION hint, never a
160
156
  *correctness* gate — if `HOLISTIC_AUDITED_COMMIT` resolves to `""` (git genuinely
161
- unavailable), write it explicitly as `""` so `/new` treats it as drift and RUNS the
162
- plan-auditor. **NEVER block or abort the PRD over the stamp**; the only thing this gate
163
- blocks is shipping cards with the stamp SILENTLY absent. Runtime-neutral (bash + YAML
164
- edits) → identical on Claude and Codex. The backfilled YAMLs are staged by item 6's
165
- existing `FEAT-XXXX-*.yml` glob.
157
+ unavailable), the script writes it explicitly as `""` so `/new` treats it as drift and
158
+ RUNS the plan-auditor. **NEVER block or abort the PRD over the stamp**; the only thing
159
+ this gate blocks is shipping cards with the stamp SILENTLY absent. Runtime-neutral
160
+ (node + YAML edits) → identical on Claude and Codex. The backfilled YAMLs are staged
161
+ by item 6's existing `FEAT-XXXX-*.yml` glob.
166
162
 
167
163
  6. Stage ONLY PRD session artefacts by explicit file name (NEVER `git add .`
168
164
  or `git add -A`):
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * stamp-holistic-audit.js — deterministic writer of the `metadata.holistic_audit`
4
+ * provenance block on backlog cards.
5
+ *
6
+ * Why this exists (/prd gate-hygiene wave): the per-card stamp write in
7
+ * audit-phase.md Step 6.9.4 and its backstop in validation-phase.md Step 7 item 5b
8
+ * were BOTH model-driven prose — and both failed together on a real run (a whole
9
+ * card family shipped with zero audit trail, so `/new` re-spawned the plan-auditor
10
+ * on every card). A prose gate degrades under context pressure; this script makes
11
+ * the stamp a single deterministic operation both call sites EXECUTE.
12
+ *
13
+ * Semantics are defined in audit-phase.md § "Holistic-audit provenance stamp" —
14
+ * this script only mechanizes the write:
15
+ * - idempotent: a card already carrying `holistic_audit` with a non-empty
16
+ * `audited_commit` is left untouched;
17
+ * - additive: never overwrites other `metadata` keys;
18
+ * - EPIC cards are skipped (they carry `planning_session` only — card-schema.md);
19
+ * - `--commit ""` is written EXPLICITLY (never omitted) so `/new` treats it as
20
+ * drift and runs its own plan-auditor (the fail-safe contract).
21
+ *
22
+ * Usage:
23
+ * node framework/scripts/stamp-holistic-audit.js \
24
+ * --at "2026-07-02T10:00:00Z" --commit "<sha-or-empty>" \
25
+ * --set "FEAT-0070-01,FEAT-0070-02" <card1.yml> [<card2.yml> ...]
26
+ *
27
+ * Exit 0 = every non-epic card carries the stamp afterwards; exit 1 = a write or
28
+ * parse failed (per-file errors printed). Zero-dep, node-core only.
29
+ */
30
+ 'use strict';
31
+
32
+ const fs = require('fs');
33
+ const path = require('path');
34
+ const { parseCardYaml, detectProfile } = require(path.join(__dirname, 'validate-card-baseline.js'));
35
+
36
+ function argValue(args, flag) {
37
+ const i = args.indexOf(flag);
38
+ return i > -1 && i + 1 < args.length ? args[i + 1] : null;
39
+ }
40
+
41
+ /** True when the card text already carries holistic_audit with a non-empty audited_commit. */
42
+ function alreadyStamped(text) {
43
+ const m = String(text).match(/^\s+holistic_audit:\s*$[\s\S]*?^\s+audited_commit:\s*"([^"]+)"/m);
44
+ return !!(m && m[1].trim() !== '');
45
+ }
46
+
47
+ /** Remove a pre-existing holistic_audit block (e.g. one with an empty commit) so the rewrite is clean. */
48
+ function stripExistingBlock(text) {
49
+ const lines = String(text).split('\n');
50
+ const start = lines.findIndex((l) => /^\s+holistic_audit:\s*$/.test(l));
51
+ if (start === -1) return text;
52
+ const indent = lines[start].length - lines[start].trimStart().length;
53
+ let end = start + 1;
54
+ while (end < lines.length) {
55
+ const l = lines[end];
56
+ if (l.trim() === '') { end++; continue; }
57
+ const li = l.length - l.trimStart().length;
58
+ if (li <= indent) break;
59
+ end++;
60
+ }
61
+ return lines.slice(0, start).concat(lines.slice(end)).join('\n');
62
+ }
63
+
64
+ function buildBlock(at, commit, set, childIndent) {
65
+ const pad = ' '.repeat(childIndent);
66
+ const inner = ' '.repeat(childIndent + 2);
67
+ const ids = set.map((s) => `"${s}"`).join(', ');
68
+ return [
69
+ `${pad}holistic_audit:`,
70
+ `${inner}audited_at: "${at}"`,
71
+ `${inner}audited_commit: "${commit}"`,
72
+ `${inner}audited_set: [${ids}]`,
73
+ ].join('\n');
74
+ }
75
+
76
+ function stampFile(file, at, commit, set) {
77
+ let text = fs.readFileSync(file, 'utf8');
78
+ let card;
79
+ try { card = parseCardYaml(text); } catch (e) { return { file, status: 'error', detail: `YAML parse error — ${e.message}` }; }
80
+ if (!card || typeof card !== 'object') return { file, status: 'error', detail: 'not a YAML mapping' };
81
+ if (detectProfile(card, path.basename(file)) === 'EPIC') return { file, status: 'epic-skipped' };
82
+ if (alreadyStamped(text)) return { file, status: 'already-stamped' };
83
+
84
+ text = stripExistingBlock(text);
85
+ const lines = text.split('\n');
86
+ const metaIdx = lines.findIndex((l) => /^metadata:\s*$/.test(l));
87
+ if (metaIdx > -1) {
88
+ // child indent = indent of the first existing metadata child, else 2 spaces
89
+ let childIndent = 2;
90
+ for (let j = metaIdx + 1; j < lines.length; j++) {
91
+ const l = lines[j];
92
+ if (l.trim() === '') continue;
93
+ const li = l.length - l.trimStart().length;
94
+ if (li > 0) childIndent = li;
95
+ break;
96
+ }
97
+ lines.splice(metaIdx + 1, 0, buildBlock(at, commit, set, childIndent));
98
+ text = lines.join('\n');
99
+ } else {
100
+ if (!text.endsWith('\n')) text += '\n';
101
+ text += `\nmetadata:\n${buildBlock(at, commit, set, 2)}\n`;
102
+ }
103
+ fs.writeFileSync(file, text);
104
+ // verify the write landed (the 5b "re-read one card" contract, made universal)
105
+ if (!alreadyStamped(fs.readFileSync(file, 'utf8')) && commit !== '') {
106
+ return { file, status: 'error', detail: 'post-write verification failed — stamp not found' };
107
+ }
108
+ return { file, status: 'stamped' };
109
+ }
110
+
111
+ function main(argv) {
112
+ const args = argv.slice(2);
113
+ const at = argValue(args, '--at');
114
+ const commit = argValue(args, '--commit'); // may legitimately be "" — must still be PASSED
115
+ const setRaw = argValue(args, '--set');
116
+ const files = [];
117
+ for (let i = 0; i < args.length; i++) {
118
+ if (args[i] === '--at' || args[i] === '--commit' || args[i] === '--set') { i++; continue; }
119
+ files.push(args[i]);
120
+ }
121
+ if (!at || commit === null || setRaw === null || !files.length) {
122
+ process.stderr.write('Usage: stamp-holistic-audit.js --at <iso8601> --commit <sha-or-empty> --set "ID1,ID2" <card.yml> [...]\n');
123
+ return 2;
124
+ }
125
+ const set = setRaw.split(',').map((s) => s.trim()).filter(Boolean).sort();
126
+ let failed = 0, stamped = 0, already = 0, epics = 0;
127
+ for (const f of files) {
128
+ let r;
129
+ try { r = stampFile(f, at, commit, set); } catch (e) { r = { file: f, status: 'error', detail: e.message }; }
130
+ if (r.status === 'error') { failed++; process.stdout.write(`✖ ${f}: ${r.detail}\n`); }
131
+ else if (r.status === 'stamped') { stamped++; process.stdout.write(`✓ ${f}: stamped\n`); }
132
+ else if (r.status === 'already-stamped') { already++; process.stdout.write(`· ${f}: already stamped\n`); }
133
+ else { epics++; process.stdout.write(`· ${f}: epic — skipped\n`); }
134
+ }
135
+ process.stdout.write(`holistic_audit provenance: ${stamped + already}/${files.length - epics} non-epic cards stamped (${stamped} written here, ${already} already present, ${epics} epic skipped)\n`);
136
+ return failed ? 1 : 0;
137
+ }
138
+
139
+ if (require.main === module) {
140
+ process.exit(main(process.argv));
141
+ }
142
+
143
+ module.exports = { stampFile, alreadyStamped, stripExistingBlock };
@@ -19,8 +19,18 @@
19
19
  *
20
20
  * Usage:
21
21
  * node framework/scripts/validate-card-baseline.js <card.yml> [<card2.yml> ...]
22
+ * node framework/scripts/validate-card-baseline.js --prd <card.yml> [...]
22
23
  * Exit 0 = all valid; exit 1 = at least one card has errors (printed per-field).
23
24
  *
25
+ * --prd (since the /prd gate-hygiene wave): adds the deterministic subset of the
26
+ * /prd validation-phase Step 6 item 0 checks, so the orchestrator EXECUTES them
27
+ * instead of reciting them (prose gates fail silently under context pressure):
28
+ * - conditional `requirements` (PO1): child/standalone with non-empty
29
+ * acceptance_criteria + scope MUST have non-empty requirements;
30
+ * - epic `review_profile` must be `skip`;
31
+ * - `[NEEDS CLARIFICATION: …]` ambiguity markers in the raw YAML are BLOCKERS —
32
+ * a card ships only when every planning ambiguity has been resolved.
33
+ *
24
34
  * Module API (for CI self-tests in scripts/check-card-baseline.js):
25
35
  * const { validateCard, detectProfile, loadSchema, loadEnums } = require(...)
26
36
  */
@@ -349,21 +359,56 @@ function validateCard(card, { matrix, enums, filename = '' } = {}) {
349
359
  return { profile, errors };
350
360
  }
351
361
 
362
+ // --- /prd deterministic gate additions (--prd) -------------------------------
363
+
364
+ /** Scan raw YAML text for unresolved planning-ambiguity markers. */
365
+ function scanAmbiguityMarkers(text) {
366
+ const out = [];
367
+ const lines = String(text).split('\n');
368
+ for (let i = 0; i < lines.length; i++) {
369
+ if (lines[i].includes('[NEEDS CLARIFICATION')) {
370
+ out.push(`line ${i + 1}: ${lines[i].trim().slice(0, 120)}`);
371
+ }
372
+ }
373
+ return out;
374
+ }
375
+
376
+ /**
377
+ * The deterministic subset of /prd validation-phase Step 6 item 0 (see file header).
378
+ * Returns string[] errors. `text` is the raw YAML (marker scan), `card` the parsed map.
379
+ */
380
+ function prdGateChecks(card, text, profile) {
381
+ const errors = [];
382
+ if (profile !== 'EPIC' && nonEmpty(card.acceptance_criteria) && nonEmpty(card.scope) && !nonEmpty(card.requirements)) {
383
+ errors.push("has acceptance_criteria + scope but no 'requirements' — emit requirements (faithful restatement of AC + scope) before commit (PO1)");
384
+ }
385
+ if (profile === 'EPIC' && nonEmpty(card.review_profile) && String(card.review_profile) !== 'skip') {
386
+ errors.push(`epic 'review_profile' must be 'skip' (got '${card.review_profile}') — trackers have no code work`);
387
+ }
388
+ for (const m of scanAmbiguityMarkers(text)) {
389
+ errors.push(`unresolved ambiguity marker — resolve with the user before commit: ${m}`);
390
+ }
391
+ return errors;
392
+ }
393
+
352
394
  // --- CLI --------------------------------------------------------------------
353
395
 
354
396
  function main(argv) {
355
- const files = argv.slice(2);
397
+ const args = argv.slice(2);
398
+ const prdMode = args.includes('--prd');
399
+ const files = args.filter((a) => a !== '--prd');
356
400
  if (!files.length) {
357
- process.stderr.write('Usage: validate-card-baseline.js <card.yml> [<card2.yml> ...]\n');
401
+ process.stderr.write('Usage: validate-card-baseline.js [--prd] <card.yml> [<card2.yml> ...]\n');
358
402
  return 2;
359
403
  }
360
404
  const matrix = loadSchema();
361
405
  const enums = loadEnums();
362
406
  let failed = 0;
363
407
  for (const file of files) {
364
- let card;
408
+ let text, card;
365
409
  try {
366
- card = parseCardYaml(fs.readFileSync(file, 'utf8'));
410
+ text = fs.readFileSync(file, 'utf8');
411
+ card = parseCardYaml(text);
367
412
  } catch (e) {
368
413
  process.stdout.write(`✖ ${file}: YAML parse error — ${e.message}\n`);
369
414
  failed++;
@@ -375,6 +420,7 @@ function main(argv) {
375
420
  continue;
376
421
  }
377
422
  const { profile, errors } = validateCard(card, { matrix, enums, filename: path.basename(file) });
423
+ if (prdMode) errors.push(...prdGateChecks(card, text, profile));
378
424
  if (errors.length) {
379
425
  failed++;
380
426
  process.stdout.write(`✖ ${file} [${profile}] — ${errors.length} issue(s):\n`);
@@ -390,4 +436,4 @@ if (require.main === module) {
390
436
  process.exit(main(process.argv));
391
437
  }
392
438
 
393
- module.exports = { validateCard, detectProfile, loadSchema, loadEnums, nonEmpty, parseCardYaml };
439
+ module.exports = { validateCard, detectProfile, loadSchema, loadEnums, nonEmpty, parseCardYaml, prdGateChecks, scanAmbiguityMarkers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.92.1",
3
+ "version": "4.93.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"