baldart 4.92.0 → 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 +25 -0
- package/VERSION +1 -1
- package/framework/.claude/agents/plan-auditor.md +9 -8
- package/framework/.claude/agents/prd-card-writer.md +8 -0
- package/framework/.claude/skills/e2e-review/CHANGELOG.md +10 -0
- package/framework/.claude/skills/e2e-review/SKILL.md +11 -4
- package/framework/.claude/skills/new2/CHANGELOG.md +16 -0
- package/framework/.claude/skills/new2/SKILL.md +32 -11
- package/framework/.claude/skills/prd/CHANGELOG.md +13 -0
- package/framework/.claude/skills/prd/SKILL.md +28 -7
- package/framework/.claude/skills/prd/references/audit-phase.md +33 -130
- package/framework/.claude/skills/prd/references/audit-teammate-prompt.md +144 -0
- package/framework/.claude/skills/prd/references/discovery-phase.md +28 -11
- package/framework/.claude/skills/prd/references/validation-phase.md +53 -57
- package/framework/.claude/skills/ui-implement/CHANGELOG.md +5 -0
- package/framework/.claude/skills/ui-implement/SKILL.md +7 -2
- package/framework/.claude/workflows/new2.js +49 -16
- package/framework/scripts/stamp-holistic-audit.js +143 -0
- package/framework/scripts/structural-compare.mjs +7 -2
- package/framework/scripts/validate-card-baseline.js +51 -5
- package/package.json +1 -1
|
@@ -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
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
`
|
|
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)** —
|
|
9
|
+
0. **Agent Specialization Audit (runs FIRST, blocks if any failure)** — two layers:
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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.
|
|
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**:
|
|
62
|
-
|
|
63
|
-
the audit log; user may accept them after review. The (
|
|
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
|
|
137
|
-
single most-omitted step under context pressure
|
|
138
|
-
ships WITHOUT `metadata.holistic_audit` — and `/new`
|
|
139
|
-
P1) + `new2` then spawn the plan-auditor on **every**
|
|
140
|
-
implemented immediately after this audit
|
|
141
|
-
gate passed), so the audit genuinely ran:
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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),
|
|
162
|
-
plan-auditor. **NEVER block or abort the PRD over the stamp**; the only thing
|
|
163
|
-
blocks is shipping cards with the stamp SILENTLY absent. Runtime-neutral
|
|
164
|
-
edits) → identical on Claude and Codex. The backfilled YAMLs are staged
|
|
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`):
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Formato: [Keep a Changelog](https://keepachangelog.com/) · [SemVer](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## 1.1.1 — 2026-07-02
|
|
6
|
+
|
|
7
|
+
- Return Contract (SKILL.md): documentati i campi `bindings` + `lane_coverage`/`lanes`
|
|
8
|
+
del JSON programmatico (lo schema resta SSOT in references/integration.md).
|
|
9
|
+
|
|
5
10
|
## 1.1.0 — 2026-07-02
|
|
6
11
|
|
|
7
12
|
- **Binding-compliance gate (Step 5b)**: nuovo script deterministico
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ui-implement
|
|
3
3
|
effort: medium
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
description: >
|
|
6
6
|
Implement an ALREADY-APPROVED mockup into the codebase end-to-end and
|
|
7
7
|
self-verify its fidelity. Takes a mockup in any channel — a Claude Design
|
|
@@ -233,7 +233,12 @@ older install), `/new` falls back to an inline **coarse** build brief + a direct
|
|
|
233
233
|
|
|
234
234
|
**Mode:** COMPACT (default). Your final message is bounded — verdict
|
|
235
235
|
(`passed | blocked | overridden | skipped | error`) + the chosen build workflow +
|
|
236
|
-
key findings as `path:line` + `Report: <path>`.
|
|
236
|
+
key findings as `path:line` + `Report: <path>`. The programmatic JSON ALSO carries
|
|
237
|
+
(since 1.1.1): `bindings` (the Step 5b `check-bindings.mjs` one-line result, when
|
|
238
|
+
the card has `component_bindings`) and `lane_coverage` + `lanes` (forwarded from
|
|
239
|
+
the internal `/e2e-review` report) — full schema:
|
|
240
|
+
[references/integration.md](references/integration.md) § Return contract (the
|
|
241
|
+
SSOT; do not restate it here). Persist the long form (the
|
|
237
242
|
`/e2e-review` report + tracker), return the short form. FULL narrative only when the
|
|
238
243
|
user invoked you directly. Schema + persist-then-summarize rule:
|
|
239
244
|
`framework/agents/return-contract-protocol.md`.
|
|
@@ -283,7 +283,7 @@ try {
|
|
|
283
283
|
preflight = await agentSafe(
|
|
284
284
|
`You are the deterministic PRE-FLIGHT for an autonomous /new batch (variant new2). Follow ${REF}/setup.md (Phase 0 + Pre-flight) and ${REF}/implement.md (Phase 1 depends-on gate) for the SEMANTICS, but replace EVERY AskUserQuestion with the deterministic policy below. You run all git/bash yourself (the workflow cannot).\n\n` +
|
|
285
285
|
`${projectBrief}\n\nCards in batch (Read each YAML):\n${cardPaths.join('\n')}\nCard IDs: ${cardIds.join(' ')}\n\n` +
|
|
286
|
-
`Create/maintain the recovery tracker at "$(git -C ${MAIN} rev-parse --git-common-dir)/baldart/run/batch-tracker-${firstCard}.md" (mkdir -p its dir first; per setup.md § Context Tracking — DURABLE location, v4.91.0: /tmp is volatile and a paused/overnight run lost it — B4).\n\n` +
|
|
286
|
+
`Create/maintain the recovery tracker at "$(git -C "${MAIN}" rev-parse --git-common-dir)/baldart/run/batch-tracker-${firstCard}.md" (mkdir -p its dir first; per setup.md § Context Tracking — DURABLE location, v4.91.0: /tmp is volatile and a paused/overnight run lost it — B4).\n\n` +
|
|
287
287
|
`ROLE BOUNDARY (specialization integrity): you are the OPS/GIT agent. You NEVER edit source or doc files — any needed content change belongs to the coder specialist; report it instead.\n\n` +
|
|
288
288
|
`DETERMINISTIC GATE POLICIES (NO user prompts):\n` +
|
|
289
289
|
`• G1 dirty-tree (main repo ${MAIN}): partition framework-managed noise exactly as setup.md step 3 ($METRICS=${METRICS}, .baldart/generated|state.json|skill-conflicts.json — NOT overlays/). Genuine user work → auto-stash 'baldart-new2-${firstCard}' (main checkout) and record the label. Never commit/abort/prompt.\n` +
|
|
@@ -614,7 +614,7 @@ async function runCard(cardId, cardPath) {
|
|
|
614
614
|
`Return: { epic, buildBlocked, blockedGate, unmetACs:[{n,text}], scopeFiles, mayEditPaths, revertedOutOfOwnership:[paths], fileDiffViolation, note }`,
|
|
615
615
|
{ label: `implement:${cardId}`, phase: 'Implement', agentType: ownerAgent,
|
|
616
616
|
schema: { type: 'object', required: ['epic', 'buildBlocked', 'unmetACs', 'scopeFiles'], additionalProperties: true,
|
|
617
|
-
properties: { epic: { type: 'boolean' }, buildBlocked: { type: 'boolean' }, blockedGate: { type: 'string' }, unmetACs: { type: 'array', items: { type: 'object', additionalProperties: true } }, scopeFiles: { type: 'array', items: { type: 'string' } }, mayEditPaths: { type: 'array', items: { type: 'string' } }, revertedOutOfOwnership: { type: 'array', items: { type: 'string' } }, fileDiffViolation: { type: 'boolean' }, note: { type: 'string' } } } }
|
|
617
|
+
properties: { epic: { type: 'boolean' }, buildBlocked: { type: 'boolean' }, blockedGate: { type: 'string' }, unmetACs: { type: 'array', items: { type: 'object', additionalProperties: true } }, scopeFiles: { type: 'array', items: { type: 'string' } }, mayEditPaths: { type: 'array', items: { type: 'string' } }, revertedOutOfOwnership: { type: 'array', items: { type: 'string' } }, fileDiffViolation: { type: 'boolean' }, note: { type: 'string' }, bindingCheck: { type: 'object', additionalProperties: true, description: 'check-bindings.mjs one-line JSON (mockup+bindings cards only)' } } } }
|
|
618
618
|
)
|
|
619
619
|
} catch (e) {
|
|
620
620
|
if (e && e.transientExhausted) { noteDegraded('outage'); return { card: cardId, status: 'pending', gates } }
|
|
@@ -653,6 +653,23 @@ async function runCard(cardId, cardPath) {
|
|
|
653
653
|
if (r.status !== 'resolved') { deferredOpen = true; deferredClasses.add(r.deferralClass || 'unresolved') }
|
|
654
654
|
}
|
|
655
655
|
|
|
656
|
+
// --- R1-F2 (v4.92.1): the binding gate result is CONSUMED, not write-only. The agent
|
|
657
|
+
// was already told to run check-bindings.mjs and fix before returning; here the workflow
|
|
658
|
+
// verifies the report: violations survive the agent's own pass → resolve (ui domain);
|
|
659
|
+
// report absent on a bindings card → fail-open but LEDGERED (audit trail, never silent).
|
|
660
|
+
if (node.hasMockup && node.hasBindings) {
|
|
661
|
+
const bc = impl && impl.bindingCheck
|
|
662
|
+
const bcViol = (bc && Array.isArray(bc.violations)) ? bc.violations : []
|
|
663
|
+
if (!bc) g('binding-gate', 'NOT-REPORTED', 'agent returned no bindingCheck — fail-open (script may be absent on older installs), recorded for audit')
|
|
664
|
+
else if (bcViol.length) {
|
|
665
|
+
g('binding-gate', 'VIOLATIONS', bcViol.map((v) => v.component).join(', '))
|
|
666
|
+
for (const v of bcViol) {
|
|
667
|
+
const r = await resolve('blocker', cardId, `binding-not-honored: region "${v.region || ''}" is bound action:${v.action || 'reuse'} → ${v.component}, but the component appears in NO touched implementation file — the binding map is authoritative (card-schema.md § component_bindings)`, { mayEditPaths: mayEdit, scopeFiles, domain: 'ui' })
|
|
668
|
+
if (r.status !== 'resolved') { deferredOpen = true; deferredClasses.add(r.deferralClass || 'unresolved') }
|
|
669
|
+
}
|
|
670
|
+
} else g('binding-gate', 'OK', `${(bc && bc.honored) || 0}/${(bc && bc.checked) || 0} bindings honored`)
|
|
671
|
+
}
|
|
672
|
+
|
|
656
673
|
// --- T1.A (v4.90.0): route-free structural fidelity lane — the new2 parallel of
|
|
657
674
|
// /e2e-review Phase 2.7. new2 has NO browser lanes (visual/quality verify runs only on
|
|
658
675
|
// the /new path), so the code-form structural check is its ONE per-card fidelity lane.
|
|
@@ -664,26 +681,42 @@ async function runCard(cardId, cardPath) {
|
|
|
664
681
|
const structSrc = node.designSrcDir
|
|
665
682
|
? { level: 'design_src', design_src_dir: node.designSrcDir }
|
|
666
683
|
: { level: 'html', mockup_path: node.designHtml }
|
|
684
|
+
const spawnMfv = () => agentSafe(
|
|
685
|
+
`Compare the implementation's code structure against the mockup's code structure and return JSON per your output schema (route-free — no browser, no dev server; cd into ${sharedCtx.worktreePath}).\n\nInput payload:\n${JSON.stringify({ card_id: cardId, route: '(card-level)', mockup_source: structSrc, implementation_files: scopeFiles, tolerance: 'strict' })}\n\nReturn STRICT JSON only: { status, findings:[{category,severity,description,expected,actual,fix_hint}] }`,
|
|
686
|
+
{ label: `fidelity:${cardId}:structural`, phase: 'Implement', agentType: 'markup-fidelity-verifier',
|
|
687
|
+
schema: { type: 'object', required: ['findings'], additionalProperties: true, properties: { status: { type: 'string' }, findings: { type: 'array', items: { type: 'object', additionalProperties: true } } } } }
|
|
688
|
+
)
|
|
667
689
|
let mfv = null
|
|
668
|
-
try {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
if (e && e.transientExhausted) noteDegraded('outage')
|
|
676
|
-
}
|
|
677
|
-
if (!mfv) {
|
|
678
|
-
g('fidelity-structural', 'UNDERRUN', 'planned lane never executed (verifier unavailable) — verification-coverage-gap, card cannot auto-DONE')
|
|
690
|
+
try { mfv = await spawnMfv() } catch (e) { if (e && e.transientExhausted) noteDegraded('outage') }
|
|
691
|
+
// R1-F1 (v4.92.1): a verifier that RETURNS but self-reports `status:"skipped"`
|
|
692
|
+
// (no_structural_ground_truth — unreadable mockup / no layout-bearing impl) is an
|
|
693
|
+
// under-run exactly like an unavailable verifier, NEVER a PASS.
|
|
694
|
+
const mfvSkipped = mfv && /skip/i.test(String(mfv.status || ''))
|
|
695
|
+
if (!mfv || mfvSkipped) {
|
|
696
|
+
g('fidelity-structural', 'UNDERRUN', `planned lane did not verify (${!mfv ? 'verifier unavailable' : 'verifier skipped: ' + String((mfv && mfv.reason) || 'no_structural_ground_truth')}) — verification-coverage-gap, card cannot auto-DONE`)
|
|
679
697
|
deferredOpen = true; deferredClasses.add('unresolved')
|
|
680
|
-
residuals.push({ card: cardId, kind: 'verification-coverage-gap', evidence:
|
|
698
|
+
residuals.push({ card: cardId, kind: 'verification-coverage-gap', evidence: `structural fidelity lane planned but did not verify (${!mfv ? 'markup-fidelity-verifier unavailable' : 'verifier skipped'})`, materialized: false })
|
|
681
699
|
} else {
|
|
682
|
-
const
|
|
700
|
+
const gatingOf = (x) => ((x && x.findings) || []).filter((f) => /critical|major/i.test(String(f.severity || '')))
|
|
701
|
+
const gating = gatingOf(mfv)
|
|
683
702
|
g('fidelity-structural', gating.length ? 'BLOCKED' : 'PASS', gating.length ? `${gating.length} gating structural finding(s)` : `ran — ${(mfv.findings || []).length} finding(s), none gating`)
|
|
703
|
+
let anyResolved = false
|
|
684
704
|
for (const f of gating) {
|
|
685
705
|
const r = await resolve('blocker', cardId, `structural fidelity (${f.category || 'layout'}): ${f.description || ''} — expected: ${f.expected || '(see mockup)'}`, { mayEditPaths: mayEdit, scopeFiles, domain: 'ui' })
|
|
686
706
|
if (r.status !== 'resolved') { deferredOpen = true; deferredClasses.add(r.deferralClass || 'unresolved') }
|
|
707
|
+
else anyResolved = true
|
|
708
|
+
}
|
|
709
|
+
// R1-F3 (v4.92.1): a resolved structural fix is RE-VERIFIED by the deterministic
|
|
710
|
+
// verifier once (mirror of /e2e-review Phase 5b step 2 — a fixer's self-report is
|
|
711
|
+
// not the verifier's confirmation). Single re-check, no loop: still-gating after
|
|
712
|
+
// the re-run → deferral (the follow-up carries it), never a second fix pass here.
|
|
713
|
+
if (anyResolved) {
|
|
714
|
+
let mfvRe = null
|
|
715
|
+
try { mfvRe = await spawnMfv() } catch (e) { if (e && e.transientExhausted) noteDegraded('outage') }
|
|
716
|
+
const reGating = mfvRe && !/skip/i.test(String(mfvRe.status || '')) ? gatingOf(mfvRe) : null
|
|
717
|
+
if (reGating === null) { g('fidelity-structural-reverify', 'UNDERRUN', 're-verify did not run — treated as unresolved'); deferredOpen = true; deferredClasses.add('unresolved') }
|
|
718
|
+
else if (reGating.length) { g('fidelity-structural-reverify', 'STILL-BLOCKED', `${reGating.length} gating finding(s) survive the fix — deferred`); deferredOpen = true; deferredClasses.add('unresolved'); residuals.push({ card: cardId, kind: 'blocker', domain: 'ui', evidence: `structural fidelity still failing after fix: ${reGating.map((f) => f.category).join(', ')}`, materialized: false }) }
|
|
719
|
+
else g('fidelity-structural-reverify', 'PASS', 'fix confirmed by the verifier')
|
|
687
720
|
}
|
|
688
721
|
}
|
|
689
722
|
}
|
|
@@ -1152,7 +1185,7 @@ if (!committed.length) {
|
|
|
1152
1185
|
} else {
|
|
1153
1186
|
try {
|
|
1154
1187
|
mergeResult = await agentSafe(
|
|
1155
|
-
`Auto-merge the batch worktree to ${TRUNK} per ${REF}/merge-cleanup.md: Phase 6 via the DETERMINISTIC script merge-worktree.sh, then Phase 6b status reconciliation + Phase 6c hygiene. Run git yourself.\n\n${projectBrief}\nWorktree: ${sharedCtx.worktreePath}\nBranch: ${sharedCtx.branch}\nmerge_strategy: ${mergeStrategy}\nCommitted cards: ${committed.map((r) => r.card).join(' ')}\nPhase-0 stash to restore (if any): see "$(git -C ${MAIN} rev-parse --git-common-dir)/baldart/run/batch-tracker-${firstCard}.md".\n\n` +
|
|
1188
|
+
`Auto-merge the batch worktree to ${TRUNK} per ${REF}/merge-cleanup.md: Phase 6 via the DETERMINISTIC script merge-worktree.sh, then Phase 6b status reconciliation + Phase 6c hygiene. Run git yourself.\n\n${projectBrief}\nWorktree: ${sharedCtx.worktreePath}\nBranch: ${sharedCtx.branch}\nmerge_strategy: ${mergeStrategy}\nCommitted cards: ${committed.map((r) => r.card).join(' ')}\nPhase-0 stash to restore (if any): see "$(git -C "${MAIN}" rev-parse --git-common-dir)/baldart/run/batch-tracker-${firstCard}.md".\n\n` +
|
|
1156
1189
|
`PHASE 6 — run the SSOT script (the merge analogue of setup-worktree.sh; NOT a hand-rolled merge, NOT /mw inline):\n` +
|
|
1157
1190
|
` MERGE_SH="$(ls .framework/framework/.claude/skills/worktree-manager/scripts/merge-worktree.sh .claude/skills/worktree-manager/scripts/merge-worktree.sh 2>/dev/null | head -1)"\n` +
|
|
1158
1191
|
` bash "$MERGE_SH" --worktree ${sharedCtx.worktreePath} --manifest /tmp/new2-merge-status-${firstCard}.txt --skip-checks\n` +
|