Story 4.2: Fix lint errors and code review findings

- Remove unused StripOverlayLayer import and stripOverlayLayer variable from module.js
- Add comprehensive JSDoc annotations to FoundryAdapter.js methods (settings, socket, users, scenes, notifications, hooks)
- Add /* global Dialog */ comment to PlayerPrivacyPanel.js for ESLint
- Remove unused _force parameter from GMPlayerPrivacySelector.js render() method
- Fix PlayerPrivacyPanelMenu.js: add constructor() to fallback class and call super()

All 862 unit tests passing. All Story 4.2 acceptance criteria met.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-05-24 01:25:30 +02:00
parent 2d898f6818
commit 20d13fc678
460 changed files with 68054 additions and 22 deletions
@@ -0,0 +1,76 @@
# Headless Mode JSON Schemas
Every headless run ends with one of these payloads. Omit keys for artifacts not produced.
## Common fields
- `status``"complete"`, `"blocked"`, or `"partial"`
- `intent``"create"`, `"update"`, or `"validate"` (matches the detected intent)
- `reason` — required when `status` is `"blocked"`; one-sentence explanation
- `assumptions` — array of inferred values that were not directly confirmed by inputs
- `open_questions` — array of items that need a human decision before the artifact can be considered final
## Create
```json
{
"status": "complete",
"intent": "create",
"prd": "{doc_workspace}/prd.md",
"addendum": "{doc_workspace}/addendum.md",
"decision_log": "{doc_workspace}/.decision-log.md",
"open_questions": [],
"assumptions": [],
"external_handoffs": [
{"directive": "Confluence upload", "tool": "corp:confluence_upload", "url": "https://confluence.corp/PROD/123", "status": "ok"}
]
}
```
## Update
```json
{
"status": "complete",
"intent": "update",
"prd": "{doc_workspace}/prd.md",
"decision_log": "{doc_workspace}/.decision-log.md",
"changes_summary": "1-3 sentences describing what changed and why",
"conflicts_with_prior_decisions": [],
"open_questions": [],
"external_handoffs": [
{"directive": "Confluence upload", "tool": "corp:confluence_upload", "url": "https://confluence.corp/PROD/123", "status": "ok"}
]
}
```
## Validate
```json
{
"status": "complete",
"intent": "validate",
"validation_report": "{doc_workspace}/validation-report.md",
"findings_summary": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0
},
"offer_to_update": true
}
```
`validation_report` is always written for Validate intent — the path here is required, not optional.
## Blocked
```json
{
"status": "blocked",
"intent": "update",
"reason": "Change signal ambiguous — could be a scope expansion or a clarification; no inferred direction"
}
```
Always include the intent (best-guess if not certain) and a one-sentence `reason`.
@@ -0,0 +1,168 @@
# PRD Template
## Essential Spine *(almost always present)*
```markdown
---
title: {Product Name}
created: {YYYY-MM-DD}
updated: {YYYY-MM-DD}
---
# PRD: {Product Name}
*Working title — confirm.*
## 0. Document Purpose
[1 paragraph: who this PRD is for (PM, stakeholders, downstream workflow owners), how it's structured (Glossary-anchored vocabulary, features grouped with FRs nested, assumptions tagged inline and indexed). If UX work or other inputs already exist, name them here and reference where they live — this PRD builds on them, it does not duplicate.]
## 1. Vision
[2-3 paragraphs: what this is, what it does for the user, why it matters. Compelling enough to stand alone.]
## 2. Target User
### 2.1 Primary Persona
[Vivid but tight. Who they are, how this product fits their context.]
### 2.2 Jobs To Be Done
[Bulleted. Emotional, social, functional, contextual — whichever apply. Even "this is for me as the builder" is a valid persona for a hobby project.]
### 2.3 Non-Users (v1) *(add when the audience boundary is non-obvious)*
[Who this is explicitly not for in v1.]
### 2.4 Key User Journeys
*Named-persona narratives the product enables. Numbered globally as UJ-1 through UJ-N. FRs reference journeys by ID inline ("realizes UJ-3"); SMs may also cross-reference. If a UX doc already exists, mirror its UJ IDs here and point to the source.*
**Default shape:** a named scene with entry state, path, climax, and resolution. Each beat forces specificity the team would otherwise leave implicit — auth assumptions, screen order, what tells the user value landed. Read together as a short narrative; the example below shows the form.
- **UJ-1. {One-line title — persona doing the thing.}**
- **Persona + context:** one line, grounded enough to explain the *why*.
- **Entry state:** authenticated? which surface? coming from where?
- **Path:** 3-5 concrete beats — taps, screens, decisions.
- **Climax:** the moment value is delivered and how the user knows.
- **Resolution:** state they're left in, what's next.
- **Edge case** *(optional)*: one real failure mode and what the user does next.
*Written out, that becomes:*
> **UJ-3. Priya checks the trip damage before she's even home.**
> Priya, budgeting on a single income with a new baby, finishes a grocery run and gets in the car. Already authenticated via biometric on a previous session. She opens the app, taps the FAB camera, and scans the receipt. The app OCRs the total and shows a single-screen overlay: this trip $84.20, weekly cap $250, $172.10 remaining, three days left in the week. She closes the app and drives home. **Edge case:** if she scanned a receipt earlier today, the app asks whether this replaces or adds to that trip before counting it against the cap.
- **UJ-2. ...**
**Scope dial:**
- **Lighter** — hobby/solo, library/CLI, or when the UJ is essentially a JTBD restated: a single sentence works (`{Persona}, {context}, {what they do and why}.`).
- **Heavier** — auth, multi-device handoff, complex navigation, or anything feeding downstream UX/architecture: add a numbered Flow, an Edge cases list, and a capability → FR mapping (`The system must {capability}. → FR-N`).
## 3. Glossary
*Downstream workflows and readers must use these terms exactly. FRs, UJs, and SMs use Glossary terms verbatim; introducing a synonym anywhere in the PRD is a discipline violation. If §4 introduces a new domain noun, add it to the Glossary in the same pass.*
- **Term** — Definition. Relationships to other Glossary terms. Cardinality where relevant.
- **Term** — ...
[Every domain noun the rest of the document uses. Defined once. No synonyms anywhere else in the PRD.]
## 4. Features
*Each subsection is a coherent feature: behavioral description first, FRs nested under it, optional feature-specific NFRs and notes. FRs are numbered globally (FR-1 through FR-N) so downstream artifacts have stable references even if features get reorganized. Reference user journeys by ID inline ("realizes UJ-2") where the chain matters.*
### 4.1 {Feature Name}
**Description:** [Behavioral narrative — how this feature works, who uses it, the user experience, edge cases. Realizes UJ-X, UJ-Y. Use Glossary terms exactly. Embed inline `[ASSUMPTION: ...]` tags where you inferred without confirmation.]
**Functional Requirements:**
#### FR-1: {Short capability name}
[Actor] can [capability] [under conditions]. Realizes UJ-X.
**Consequences (testable):**
- {Specific testable condition, e.g. "System returns HTTP 429 when request rate exceeds 100/sec per merchant."}
- {Another testable condition.}
**Out of Scope:** *(optional — what this FR explicitly does NOT cover)*
- {bound}
#### FR-2: ...
**Feature-specific NFRs:** *(only if any apply uniquely to this feature)*
- Performance / security / accessibility / etc. specific to this feature.
**Notes:** *(optional — open questions specific to this feature, `[NOTE FOR PM]` callouts)*
### 4.2 {Feature Name}
...
## 5. Non-Goals (Explicit)
[Bulleted. What this product is *not* and what it will *not* do in v1. Does outsized work for downstream readers and workflows — prevents the "let me also add this nearby thing" failure mode at every level (epic, ticket, code). Inline `[NON-GOAL for MVP]` callouts within §4 Features cover deferred items within features; this section captures the broader "we are not building X / we are not becoming Y" statements.]
## 6. MVP Scope
### 6.1 In Scope
[Bulleted, crisp.]
### 6.2 Out of Scope for MVP
[Bulleted. Each item with a one-line reason if the reason matters. Mark items deferred to v2/v3 explicitly. Add `[NOTE FOR PM]` callouts where a deferred item is emotionally load-bearing — flags it for revisit if timeline permits.]
## 7. Success Metrics
*Each SM cross-references the FR(s) it validates. Counter-metrics counterbalance specific primary or secondary metrics.*
**Primary**
- **SM-1**: Metric — definition, target. Validates FR-X, FR-Y.
**Secondary**
- **SM-2**: Metric — definition, target. Validates FR-Z.
**Counter-metrics (do not optimize)**
- **SM-C1**: Metric — why this should *not* be optimized. Counterbalances SM-1.
[Length scales with stakes. Hobby/utility PRD: a single sentence may be enough ("Success: I use this weekly and don't abandon it after a month"). Public launch / enterprise: full quantitative breakdown with measurement methods. Counter-metrics are as load-bearing as primary metrics — they prevent the architect from optimizing the wrong thing and the dev from gaming the wrong target.]
## 8. Open Questions
[Numbered. Things still unknown — they become future tickets or follow-up research, not silent gaps.]
## 9. Assumptions Index
*Every `[ASSUMPTION]` from the document, surfaced for explicit confirmation:*
- Inline assumption from §X.Y — short description.
- ...
```
---
## Adapt-In Menu *(add the clusters the product calls for)*
### Cross-cutting quality and shape *(most non-trivial PRDs)*
- **Cross-Cutting NFRs** — system-wide non-functional requirements not tied to a single feature (performance, security, reliability, observability). Add when system-wide quality attributes are meaningful.
- **Constraints and Guardrails** — Safety, Privacy, Cost. Subsection per cluster. Add when any of these are real concerns.
- **Why Now** — add when timing is load-bearing (a market shift, a technology enabler, a regulatory deadline). Drop when timing is incidental.
### Consumer / branded products
- **Aesthetic and Tone** — visual references, anti-references, voice/tone for any product-generated text.
- **Information Architecture** — top-level surfaces, navigation, screens.
- **Monetization** — free vs. paid, pricing assumptions, ads policy.
- **Platform** — web, mobile, PWA, native, v1 vs. v2+.
### Enterprise initiatives
- **Stakeholders and Approvals** — who must sign off, at what stage.
- **Risk and Mitigations** — operational, security, business, reputational risk register.
- **ROI / Business Case** — quantified benefit, cost, payback period.
- **Operational Requirements** — SLAs, RTO/RPO, support tier, on-call expectations.
- **Integration and Dependencies** — SSO, existing enterprise systems, data sources, downstream consumers.
- **Rollout and Change Management** — phased rollout plan, training, internal communication.
- **Data Governance** — residency, sovereignty, classification, retention.
- **Audit Trail / Decision Provenance** — formal documentation requirements for regulated environments.
### Regulated domains
- **Compliance and Regulatory** — HIPAA, PCI-DSS, GDPR, SOX, SOC 2, Section 508 / WCAG 2.1 AA, FedRAMP, etc. — whichever apply. If any item needs depth, add a `[NOTE FOR PM]` callout to revisit or move to an addendum.
### Developer products (libraries, APIs, CLIs, SDKs)
- **API Contracts / Public Surface** — endpoint shapes, breaking change policy.
- **Versioning and Deprecation Policy**.
- **Performance Budgets** — latency, throughput, resource use.
- **Language / Runtime Targets and Dependency Policy**.
### Embedded / hardware
- **Hardware Constraints** — memory, power, form factor.
- **Deployment and Update Mechanism** — OTA, manual, image-based.
- **Environmental and Reliability Requirements**.
### Small-scope all-inclusive *(use when scope is 1-2 stories' worth and the user wants a single captured artifact — chosen during the Right-skill check in Discovery)*
- **Stories** — story-level specs listed inline at the end of the doc. Each story: *"As a [persona], I can [action] [under conditions]. Acceptance: [testable criteria]."* Numbered Story-1, Story-2, ... for reference. Pair with very lean §1 Vision, §2 Target User (often just JTBD + one UJ), §3 Glossary (handful of terms), §4 Features (often a single feature), §6 MVP Scope (in/out very tight). The whole doc fits on a page or two and captures intent + implementable stories in one place. If the user doesn't want the captured artifact at all, `bmad-quick-dev` is the better path — this cluster is only for "I want a doc *and* the stories."
@@ -0,0 +1,135 @@
# PRD Quality Rubric
A judgment rubric for the validator subagent. Walk the PRD with these dimensions in mind and write substantive findings — not box-ticking. The goal is a review that tells the user whether this PRD is *good*, not whether it has the right section headers.
Most PRDs do not need every dimension scrutinized equally. Calibrate to the agreed stakes, the PRD's shape (consumer product, internal tool, regulatory update, technical capability spec), and what the PRD itself is trying to do. Be specific — cite locations, quote phrases, name what's missing. Abstract criticism is failure of nerve.
## How to use this rubric
1. Read the full PRD (and addendum.md if present) before writing anything.
2. For each of the seven dimensions below, form a judgment — *strong / adequate / thin / broken* — backed by specifics from the PRD.
3. Write findings only where they add information. A `strong` dimension may need no findings; a `broken` one needs concrete, fixable ones.
4. Severity ranks impact on the PRD's usefulness, not how easy the fix is. A vague Vision statement is *critical* even though it's a one-paragraph fix; a glossary drift might be *low* even though it appears in many places.
5. The overall verdict is your synthesis — 23 sentences that name what holds up and what's at risk. Earn it with the dimension judgments.
## Output format
Write findings to `{doc_workspace}/review-rubric.md`:
```markdown
# PRD Quality Review — {prd_name}
## Overall verdict
[23 sentences. What holds up, what's at risk. Earned by the dimension judgments below.]
## Decision-readiness — [strong | adequate | thin | broken]
[13 paragraphs of judgment with specific PRD locations.]
### Findings
- **[critical|high|medium|low]** [Title] (§ location) — [Note]. *Fix:* [suggested fix].
## Substance over theater — [verdict]
...
(repeat for each dimension)
## Mechanical notes
[Glossary drift, ID continuity, broken cross-refs, Assumptions Index roundtrip. Lighter weight — these matter for downstream but don't drive the overall verdict.]
```
## The seven dimensions
### 1. Decision-readiness
Can a decision-maker act on this PRD? Are the trade-offs surfaced honestly, or has the PRD smoothed everything to neutral? Would someone pushing back find their objection acknowledged or dodged?
Look for:
- Decisions that are stated as decisions, not buried as "considerations."
- Trade-offs named with what was given up, not just what was chosen.
- Open Questions that are actually open — not rhetorical questions with an answer in the next sentence.
- `[NOTE FOR PM]` callouts at real tensions, not at safe checkpoints.
Red flag: a PRD where every choice "balances" everything, every NFR is "important," every persona "values" the product.
### 2. Substance over theater
Is the content earned, or is it furniture? Distinguish:
- **Persona theater** — Personas that don't drive a single decision in the PRD. More than four personas. Personas whose only function is to make the PRD look thorough.
- **Innovation theater** — claimed novelty that isn't novel. Differentiation sections written because the template had one, not because Discovery surfaced something.
- **NFR theater** — copied boilerplate ("system must be scalable / secure / reliable") without product-specific thresholds.
- **Vision theater** — a Vision statement that could swap into any PRD in this category without change.
Flag what reads like furniture, even if it's well-written furniture.
### 3. Strategic coherence
Does the PRD have a thesis? Do the features serve a unified arc, or is it a list of capabilities someone wanted?
Look for:
- A stated thesis the PRD bets on (problem framing, user insight, market move).
- Feature prioritization that follows from the thesis — not from "what's easy first."
- Success Metrics that validate the thesis, not metrics that just measure activity (DAU/MAU when the thesis is about engagement quality is a tell).
- Counter-metrics named when SMs exist.
- Coherent MVP scope kind — problem-solving, experience, platform, or revenue — with scope logic that matches.
Red flag: a PRD that reads as a backlog with section headings.
### 4. Done-ness clarity
Would an engineer reading this PRD know what "done" looks like for each FR?
Look for:
- FRs with at least one testable consequence per FR — verifiable condition, measurable outcome.
- "System handles X gracefully," "reasonable performance," "user-friendly" — flag every one.
- Acceptance criteria implied or explicit. Sometimes the FR's consequences carry this; sometimes the PRD genuinely needs an Acceptance section.
- For non-functional sections (UX, performance, security): bounds, not adjectives.
This is the dimension downstream story creation will lean on hardest. Be unforgiving here.
### 5. Scope honesty
Are omissions explicit, or is the reader meant to infer them?
Look for:
- A Non-Goals section where it would do real work — and `[NON-GOAL for MVP]` callouts where omissions could be silently assumed.
- `[ASSUMPTION: …]` tags on inferences the user didn't directly confirm, indexed at the end.
- `[NOTE FOR PM]` callouts at deferred decisions and unresolved tensions.
- De-scoping proposed honestly, not done silently.
Open-items density: count Open Questions + `[ASSUMPTION]` + `[NOTE FOR PM]` callouts relative to stakes. High counts on a low-stakes PRD is fine; high counts on a green-light-to-build PRD is a blocker.
### 6. Downstream usability
If this PRD feeds UX, architecture, or story creation, can those workflows source-extract from it cleanly?
Look for:
- Glossary present; every domain noun used identically across FRs, UJs, SM definitions.
- FR / UJ / SM IDs contiguous, unique, and cross-references that resolve.
- Each section makes sense pulled out alone — cross-references via Glossary terms, not "see above."
- UJs each name a persona from §2 by exact label; no floating UJs.
For standalone PRDs (no downstream), this dimension matters less — say so.
### 7. Shape fit
Has the PRD been forced into a shape that doesn't match the product?
- Consumer product / multi-stakeholder B2B / meaningful UX → UJs and personas are load-bearing.
- Internal tool, single-operator role → capability spec shape; UJs may be overhead; SMs may be operational rather than user-facing.
- Regulatory or compliance update → constraint traceability is non-negotiable; UJs may be irrelevant.
- Hobby / solo → rigor light, substance bar still applies.
- Brownfield → existing-code references must be accurate; new UJs and existing UJs must be distinguished.
- Chain-top (feeds UX → architecture → stories) → downstream usability matters more; standalone PRDs can be lighter on traceability.
Flag PRDs that are over-formalized (UJ density for a single-operator tool) or under-formalized (consumer product with no personas or UJs).
## Mechanical notes
Cover these as a tail section, not a primary dimension. They matter for downstream but don't drive the verdict on whether the PRD is good.
- Glossary drift (case, plural, synonyms across the PRD).
- ID continuity (gaps, duplicates, unresolved cross-references).
- Assumptions Index roundtrip (every inline `[ASSUMPTION]` indexed; index entries all appear inline).
- UJ persona linkage (each UJ names a defined persona by exact label).
- Required sections present for the agreed stakes and product type.
@@ -0,0 +1,325 @@
<!DOCTYPE html>
<!--
PRD Validation Report — skeleton template.
This file is a starter the synthesis pass fills in directly. There is no
substitution engine. The LLM:
1. Reads {doc_workspace}/review-rubric.md and every review-{slug}.md from
additional reviewers.
2. Copies this skeleton.
3. Replaces the placeholder content (everything between TEMPLATE markers)
with the consolidated review, preserving the structure and CSS.
4. Writes the result to {doc_workspace}/validation-report.html.
5. Writes a markdown twin to {doc_workspace}/validation-report.md.
Visual rules the LLM must preserve:
- The container width, the color tokens, the typography.
- One dimension = one collapsible <section class="dimension">.
- Verdict pill uses the verdict-* class matching its judgment.
- Severity badge uses the sev-* class matching its level.
- Each extra reviewer (adversarial, etc.) gets its own collapsible section
below the rubric dimensions.
- The footer always shows the artifact paths and timestamp.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title>PRD Validation: TEMPLATE_PRD_NAME</title>
<style>
:root {
--bg: #fafaf9;
--surface: #ffffff;
--border: #e7e5e4;
--text: #1c1917;
--muted: #78716c;
--verdict-strong: #16a34a;
--verdict-adequate: #65a30d;
--verdict-thin: #d97706;
--verdict-broken: #dc2626;
--sev-low: #64748b;
--sev-medium: #ca8a04;
--sev-high: #ea580c;
--sev-critical: #dc2626;
--grade-exc: #16a34a;
--grade-good: #65a30d;
--grade-fair: #d97706;
--grade-poor: #dc2626;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
font-size: 15px;
}
.container { max-width: 960px; margin: 0 auto; padding: 32px 24px 64px; }
header.report-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border);
margin-bottom: 24px;
}
.title h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.title .subtitle { color: var(--muted); font-size: 13px; margin-top: 4px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
.grade {
padding: 10px 18px;
border-radius: 8px;
font-weight: 600;
color: white;
font-size: 15px;
white-space: nowrap;
}
.grade-excellent { background: var(--grade-exc); }
.grade-good { background: var(--grade-good); }
.grade-fair { background: var(--grade-fair); }
.grade-poor { background: var(--grade-poor); }
.synthesis {
background: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--muted);
border-radius: 8px;
padding: 18px 22px;
margin-bottom: 24px;
font-size: 15.5px;
}
.synthesis p { margin: 0 0 10px; }
.synthesis p:last-child { margin-bottom: 0; }
.dimension-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 10px;
margin-bottom: 24px;
}
.dim-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px 14px;
}
.dim-card .dim-name { font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.dim-card .dim-verdict { font-size: 14px; font-weight: 600; }
section.dimension, section.reviewer-section { margin-bottom: 14px; }
section.dimension details, section.reviewer-section details {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
section summary {
padding: 14px 20px;
cursor: pointer;
user-select: none;
list-style: none;
display: flex;
align-items: center;
gap: 12px;
}
section summary::-webkit-details-marker { display: none; }
section summary::before {
content: "▸";
display: inline-block;
color: var(--muted);
transition: transform 0.15s ease;
}
section details[open] summary::before { transform: rotate(90deg); }
section summary h2 {
display: inline;
margin: 0;
font-size: 16px;
font-weight: 600;
letter-spacing: -0.005em;
flex: 1;
}
.verdict-pill {
font-size: 11px;
padding: 3px 10px;
border-radius: 999px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
color: white;
}
.verdict-strong { background: var(--verdict-strong); }
.verdict-adequate { background: var(--verdict-adequate); }
.verdict-thin { background: var(--verdict-thin); }
.verdict-broken { background: var(--verdict-broken); }
.dim-body { padding: 4px 20px 18px; }
.dim-judgment { color: var(--text); font-size: 14.5px; }
.dim-judgment p { margin: 0 0 10px; }
.findings-list { padding: 0 20px 4px; }
article.finding {
padding: 14px 0;
border-top: 1px solid var(--border);
}
article.finding:first-child { border-top: none; }
article.finding header {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.badge {
font-size: 10.5px;
padding: 3px 8px;
border-radius: 4px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
line-height: 1.4;
}
.badge-sev-low { background: rgba(100, 116, 139, 0.12); color: var(--sev-low); }
.badge-sev-medium { background: rgba(202, 138, 4, 0.14); color: var(--sev-medium); }
.badge-sev-high { background: rgba(234, 88, 12, 0.14); color: var(--sev-high); }
.badge-sev-critical { background: rgba(220, 38, 38, 0.14); color: var(--sev-critical); }
.finding-title { margin: 0; font-size: 15px; font-weight: 500; flex: 1; min-width: 200px; }
.finding-location { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; color: var(--muted); }
.finding-note, .finding-fix { margin-top: 6px; font-size: 14px; }
.finding-fix strong { color: var(--muted); font-weight: 500; }
.reviewer-source {
font-size: 12px;
color: var(--muted);
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.mechanical {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px 20px;
margin-top: 24px;
font-size: 14px;
}
.mechanical h3 { margin: 0 0 10px; font-size: 14px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.mechanical ul { margin: 0; padding-left: 20px; }
.mechanical li { margin-bottom: 4px; color: var(--text); }
footer.report-footer {
margin-top: 40px;
padding-top: 16px;
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--muted);
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
footer .meta { display: flex; gap: 24px; flex-wrap: wrap; }
</style>
</head>
<body>
<div class="container">
<!-- TEMPLATE: header. Fill prd name, prd path, grade text & class. -->
<header class="report-header">
<div class="title">
<h1>TEMPLATE_PRD_NAME — Validation Report</h1>
<div class="subtitle">TEMPLATE_PRD_PATH</div>
</div>
<div class="grade TEMPLATE_GRADE_CLASS">TEMPLATE_GRADE</div>
</header>
<!-- TEMPLATE: overall synthesis paragraphs. Lift directly from
review-rubric.md "Overall verdict" section; expand if extra reviewers
materially shift the picture. Wrap each paragraph in <p>. -->
<div class="synthesis">
<p>TEMPLATE_SYNTHESIS_PARAGRAPH</p>
</div>
<!-- TEMPLATE: dimension summary cards. One per rubric dimension. The
dim-verdict text uses one of: strong | adequate | thin | broken. -->
<div class="dimension-summary">
<div class="dim-card">
<div class="dim-name">Decision-readiness</div>
<div class="dim-verdict" style="color: var(--verdict-TEMPLATE_VERDICT)">TEMPLATE_VERDICT_TEXT</div>
</div>
<!-- repeat for each of the seven dimensions -->
</div>
<!-- TEMPLATE: one section per rubric dimension. Skip a dimension entirely
if the rubric review marked it n/a for this PRD (e.g. downstream
usability for a standalone PRD). Open the section by default if
verdict is thin or broken. -->
<section class="dimension">
<details open>
<summary>
<h2>Decision-readiness</h2>
<span class="verdict-pill verdict-TEMPLATE_VERDICT">TEMPLATE_VERDICT_TEXT</span>
</summary>
<div class="dim-body">
<div class="dim-judgment">
<p>TEMPLATE_DIMENSION_JUDGMENT</p>
</div>
</div>
<div class="findings-list">
<!-- TEMPLATE: zero or more findings -->
<article class="finding">
<header>
<span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
<h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
<span class="finding-location">TEMPLATE_LOCATION</span>
</header>
<div class="finding-note">TEMPLATE_FINDING_NOTE</div>
<div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
</article>
</div>
</details>
</section>
<!-- TEMPLATE: one section per extra reviewer that ran (adversarial, etc.).
Skip this block entirely if only the rubric walker ran. -->
<section class="reviewer-section">
<details>
<summary>
<h2>Adversarial review</h2>
<span class="reviewer-source">TEMPLATE_REVIEWER_SOURCE_FILE</span>
</summary>
<div class="dim-body">
<div class="dim-judgment">
<p>TEMPLATE_REVIEWER_PREAMBLE</p>
</div>
</div>
<div class="findings-list">
<article class="finding">
<header>
<span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
<h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
<span class="finding-location">TEMPLATE_LOCATION</span>
</header>
<div class="finding-note">TEMPLATE_FINDING_NOTE</div>
<div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
</article>
</div>
</details>
</section>
<!-- TEMPLATE: mechanical notes — short, bulleted. Skip if there are none. -->
<div class="mechanical">
<h3>Mechanical notes</h3>
<ul>
<li>TEMPLATE_MECHANICAL_NOTE</li>
</ul>
</div>
<footer class="report-footer">
<div class="meta">
<span>Rubric: TEMPLATE_RUBRIC_PATH</span>
<span>Generated: TEMPLATE_TIMESTAMP</span>
</div>
</footer>
</div>
</body>
</html>