validation-report-template.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <!DOCTYPE html>
  2. <!--
  3. PRD Validation Report — skeleton template.
  4. This file is a starter the synthesis pass fills in directly. There is no
  5. substitution engine. The LLM:
  6. 1. Reads {doc_workspace}/review-rubric.md and every review-{slug}.md from
  7. additional reviewers.
  8. 2. Copies this skeleton.
  9. 3. Replaces the placeholder content (everything between TEMPLATE markers)
  10. with the consolidated review, preserving the structure and CSS.
  11. 4. Writes the result to {doc_workspace}/validation-report.html.
  12. 5. Writes a markdown twin to {doc_workspace}/validation-report.md.
  13. Visual rules the LLM must preserve:
  14. - The container width, the color tokens, the typography.
  15. - One dimension = one collapsible <section class="dimension">.
  16. - Verdict pill uses the verdict-* class matching its judgment.
  17. - Severity badge uses the sev-* class matching its level.
  18. - Each extra reviewer (adversarial, etc.) gets its own collapsible section
  19. below the rubric dimensions.
  20. - The footer always shows the artifact paths and timestamp.
  21. -->
  22. <html lang="en">
  23. <head>
  24. <meta charset="utf-8">
  25. <title>PRD Validation: TEMPLATE_PRD_NAME</title>
  26. <style>
  27. :root {
  28. --bg: #fafaf9;
  29. --surface: #ffffff;
  30. --border: #e7e5e4;
  31. --text: #1c1917;
  32. --muted: #78716c;
  33. --verdict-strong: #16a34a;
  34. --verdict-adequate: #65a30d;
  35. --verdict-thin: #d97706;
  36. --verdict-broken: #dc2626;
  37. --sev-low: #64748b;
  38. --sev-medium: #ca8a04;
  39. --sev-high: #ea580c;
  40. --sev-critical: #dc2626;
  41. --grade-exc: #16a34a;
  42. --grade-good: #65a30d;
  43. --grade-fair: #d97706;
  44. --grade-poor: #dc2626;
  45. }
  46. * { box-sizing: border-box; }
  47. html, body { margin: 0; padding: 0; }
  48. body {
  49. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
  50. background: var(--bg);
  51. color: var(--text);
  52. line-height: 1.6;
  53. font-size: 15px;
  54. }
  55. .container { max-width: 960px; margin: 0 auto; padding: 32px 24px 64px; }
  56. header.report-header {
  57. display: flex;
  58. align-items: flex-start;
  59. justify-content: space-between;
  60. gap: 24px;
  61. padding-bottom: 16px;
  62. border-bottom: 1px solid var(--border);
  63. margin-bottom: 24px;
  64. }
  65. .title h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
  66. .title .subtitle { color: var(--muted); font-size: 13px; margin-top: 4px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
  67. .grade {
  68. padding: 10px 18px;
  69. border-radius: 8px;
  70. font-weight: 600;
  71. color: white;
  72. font-size: 15px;
  73. white-space: nowrap;
  74. }
  75. .grade-excellent { background: var(--grade-exc); }
  76. .grade-good { background: var(--grade-good); }
  77. .grade-fair { background: var(--grade-fair); }
  78. .grade-poor { background: var(--grade-poor); }
  79. .synthesis {
  80. background: var(--surface);
  81. border: 1px solid var(--border);
  82. border-left: 3px solid var(--muted);
  83. border-radius: 8px;
  84. padding: 18px 22px;
  85. margin-bottom: 24px;
  86. font-size: 15.5px;
  87. }
  88. .synthesis p { margin: 0 0 10px; }
  89. .synthesis p:last-child { margin-bottom: 0; }
  90. .dimension-summary {
  91. display: grid;
  92. grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  93. gap: 10px;
  94. margin-bottom: 24px;
  95. }
  96. .dim-card {
  97. background: var(--surface);
  98. border: 1px solid var(--border);
  99. border-radius: 8px;
  100. padding: 12px 14px;
  101. }
  102. .dim-card .dim-name { font-size: 13px; color: var(--muted); margin-bottom: 6px; }
  103. .dim-card .dim-verdict { font-size: 14px; font-weight: 600; }
  104. section.dimension, section.reviewer-section { margin-bottom: 14px; }
  105. section.dimension details, section.reviewer-section details {
  106. background: var(--surface);
  107. border: 1px solid var(--border);
  108. border-radius: 8px;
  109. overflow: hidden;
  110. }
  111. section summary {
  112. padding: 14px 20px;
  113. cursor: pointer;
  114. user-select: none;
  115. list-style: none;
  116. display: flex;
  117. align-items: center;
  118. gap: 12px;
  119. }
  120. section summary::-webkit-details-marker { display: none; }
  121. section summary::before {
  122. content: "▸";
  123. display: inline-block;
  124. color: var(--muted);
  125. transition: transform 0.15s ease;
  126. }
  127. section details[open] summary::before { transform: rotate(90deg); }
  128. section summary h2 {
  129. display: inline;
  130. margin: 0;
  131. font-size: 16px;
  132. font-weight: 600;
  133. letter-spacing: -0.005em;
  134. flex: 1;
  135. }
  136. .verdict-pill {
  137. font-size: 11px;
  138. padding: 3px 10px;
  139. border-radius: 999px;
  140. font-weight: 600;
  141. text-transform: uppercase;
  142. letter-spacing: 0.04em;
  143. color: white;
  144. }
  145. .verdict-strong { background: var(--verdict-strong); }
  146. .verdict-adequate { background: var(--verdict-adequate); }
  147. .verdict-thin { background: var(--verdict-thin); }
  148. .verdict-broken { background: var(--verdict-broken); }
  149. .dim-body { padding: 4px 20px 18px; }
  150. .dim-judgment { color: var(--text); font-size: 14.5px; }
  151. .dim-judgment p { margin: 0 0 10px; }
  152. .findings-list { padding: 0 20px 4px; }
  153. article.finding {
  154. padding: 14px 0;
  155. border-top: 1px solid var(--border);
  156. }
  157. article.finding:first-child { border-top: none; }
  158. article.finding header {
  159. display: flex;
  160. align-items: center;
  161. gap: 10px;
  162. flex-wrap: wrap;
  163. margin-bottom: 6px;
  164. }
  165. .badge {
  166. font-size: 10.5px;
  167. padding: 3px 8px;
  168. border-radius: 4px;
  169. font-weight: 600;
  170. text-transform: uppercase;
  171. letter-spacing: 0.04em;
  172. line-height: 1.4;
  173. }
  174. .badge-sev-low { background: rgba(100, 116, 139, 0.12); color: var(--sev-low); }
  175. .badge-sev-medium { background: rgba(202, 138, 4, 0.14); color: var(--sev-medium); }
  176. .badge-sev-high { background: rgba(234, 88, 12, 0.14); color: var(--sev-high); }
  177. .badge-sev-critical { background: rgba(220, 38, 38, 0.14); color: var(--sev-critical); }
  178. .finding-title { margin: 0; font-size: 15px; font-weight: 500; flex: 1; min-width: 200px; }
  179. .finding-location { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; color: var(--muted); }
  180. .finding-note, .finding-fix { margin-top: 6px; font-size: 14px; }
  181. .finding-fix strong { color: var(--muted); font-weight: 500; }
  182. .reviewer-source {
  183. font-size: 12px;
  184. color: var(--muted);
  185. font-family: ui-monospace, "SF Mono", Menlo, monospace;
  186. }
  187. .mechanical {
  188. background: var(--surface);
  189. border: 1px solid var(--border);
  190. border-radius: 8px;
  191. padding: 16px 20px;
  192. margin-top: 24px;
  193. font-size: 14px;
  194. }
  195. .mechanical h3 { margin: 0 0 10px; font-size: 14px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
  196. .mechanical ul { margin: 0; padding-left: 20px; }
  197. .mechanical li { margin-bottom: 4px; color: var(--text); }
  198. footer.report-footer {
  199. margin-top: 40px;
  200. padding-top: 16px;
  201. border-top: 1px solid var(--border);
  202. font-size: 12px;
  203. color: var(--muted);
  204. font-family: ui-monospace, "SF Mono", Menlo, monospace;
  205. }
  206. footer .meta { display: flex; gap: 24px; flex-wrap: wrap; }
  207. </style>
  208. </head>
  209. <body>
  210. <div class="container">
  211. <!-- TEMPLATE: header. Fill prd name, prd path, grade text & class. -->
  212. <header class="report-header">
  213. <div class="title">
  214. <h1>TEMPLATE_PRD_NAME — Validation Report</h1>
  215. <div class="subtitle">TEMPLATE_PRD_PATH</div>
  216. </div>
  217. <div class="grade TEMPLATE_GRADE_CLASS">TEMPLATE_GRADE</div>
  218. </header>
  219. <!-- TEMPLATE: overall synthesis paragraphs. Lift directly from
  220. review-rubric.md "Overall verdict" section; expand if extra reviewers
  221. materially shift the picture. Wrap each paragraph in <p>. -->
  222. <div class="synthesis">
  223. <p>TEMPLATE_SYNTHESIS_PARAGRAPH</p>
  224. </div>
  225. <!-- TEMPLATE: dimension summary cards. One per rubric dimension. The
  226. dim-verdict text uses one of: strong | adequate | thin | broken. -->
  227. <div class="dimension-summary">
  228. <div class="dim-card">
  229. <div class="dim-name">Decision-readiness</div>
  230. <div class="dim-verdict" style="color: var(--verdict-TEMPLATE_VERDICT)">TEMPLATE_VERDICT_TEXT</div>
  231. </div>
  232. <!-- repeat for each of the seven dimensions -->
  233. </div>
  234. <!-- TEMPLATE: one section per rubric dimension. Skip a dimension entirely
  235. if the rubric review marked it n/a for this PRD (e.g. downstream
  236. usability for a standalone PRD). Open the section by default if
  237. verdict is thin or broken. -->
  238. <section class="dimension">
  239. <details open>
  240. <summary>
  241. <h2>Decision-readiness</h2>
  242. <span class="verdict-pill verdict-TEMPLATE_VERDICT">TEMPLATE_VERDICT_TEXT</span>
  243. </summary>
  244. <div class="dim-body">
  245. <div class="dim-judgment">
  246. <p>TEMPLATE_DIMENSION_JUDGMENT</p>
  247. </div>
  248. </div>
  249. <div class="findings-list">
  250. <!-- TEMPLATE: zero or more findings -->
  251. <article class="finding">
  252. <header>
  253. <span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
  254. <h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
  255. <span class="finding-location">TEMPLATE_LOCATION</span>
  256. </header>
  257. <div class="finding-note">TEMPLATE_FINDING_NOTE</div>
  258. <div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
  259. </article>
  260. </div>
  261. </details>
  262. </section>
  263. <!-- TEMPLATE: one section per extra reviewer that ran (adversarial, etc.).
  264. Skip this block entirely if only the rubric walker ran. -->
  265. <section class="reviewer-section">
  266. <details>
  267. <summary>
  268. <h2>Adversarial review</h2>
  269. <span class="reviewer-source">TEMPLATE_REVIEWER_SOURCE_FILE</span>
  270. </summary>
  271. <div class="dim-body">
  272. <div class="dim-judgment">
  273. <p>TEMPLATE_REVIEWER_PREAMBLE</p>
  274. </div>
  275. </div>
  276. <div class="findings-list">
  277. <article class="finding">
  278. <header>
  279. <span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
  280. <h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
  281. <span class="finding-location">TEMPLATE_LOCATION</span>
  282. </header>
  283. <div class="finding-note">TEMPLATE_FINDING_NOTE</div>
  284. <div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
  285. </article>
  286. </div>
  287. </details>
  288. </section>
  289. <!-- TEMPLATE: mechanical notes — short, bulleted. Skip if there are none. -->
  290. <div class="mechanical">
  291. <h3>Mechanical notes</h3>
  292. <ul>
  293. <li>TEMPLATE_MECHANICAL_NOTE</li>
  294. </ul>
  295. </div>
  296. <footer class="report-footer">
  297. <div class="meta">
  298. <span>Rubric: TEMPLATE_RUBRIC_PATH</span>
  299. <span>Generated: TEMPLATE_TIMESTAMP</span>
  300. </div>
  301. </footer>
  302. </div>
  303. </body>
  304. </html>