rcf-lite 0.28.2 → 0.29.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.
Files changed (327) hide show
  1. package/CHANGELOG.md +317 -0
  2. package/bin/rcf.js +8 -0
  3. package/fixtures/canary-manifest.json +9 -9
  4. package/guidance/define-draft-shapes.md +89 -0
  5. package/guidance/define-intake.md +97 -0
  6. package/guidance/define-intent.md +107 -0
  7. package/guidance/discover-prototype.md +67 -0
  8. package/guidance/discovery-prototypes.md +69 -0
  9. package/guidance/harness-template.md +34 -0
  10. package/guidance/managed/agent-instructions-block.hash +1 -1
  11. package/guidance/managed/agent-instructions-block.md +34 -0
  12. package/guidance/manifest.json +9 -2
  13. package/package.json +1 -1
  14. package/rcf/adrs/adr-4120-canonical-json-hashing.json +30 -0
  15. package/rcf/adrs/adr-4121-define-sidecars.json +30 -0
  16. package/rcf/adrs/adr-4122-define-gates-blocking-and-optout.json +30 -0
  17. package/rcf/adrs/adr-4123-readiness-single-object.json +30 -0
  18. package/rcf/adrs/adr-4124-define-freeze-verb.json +30 -0
  19. package/rcf/adrs/adr-4126-persona-tagged-blockers-two-levels.json +40 -0
  20. package/rcf/adrs/adr-4127-readiness-tab-order-and-register.json +40 -0
  21. package/rcf/adrs/adr-4129-questions-harness-driven-loop.json +25 -0
  22. package/rcf/adrs/adr-4130-intake-harness-split-tool-scanned.json +20 -0
  23. package/rcf/adrs/adr-4132-prototypes-in-discovery-as-evidence.json +20 -0
  24. package/rcf/adrs/adr-4133-dag-dependency-depth-layout.json +40 -0
  25. package/rcf/adrs/adr-4134-index-json-route.json +35 -0
  26. package/rcf/adrs/adr-4135-readiness-po-register-and-adapter.json +35 -0
  27. package/rcf/adrs/adr-4136-embedding-host-fixture.json +35 -0
  28. package/rcf/code-nodes/cn-700.json +23 -0
  29. package/rcf/code-nodes/cn-701.json +14 -0
  30. package/rcf/code-nodes/cn-702.json +14 -0
  31. package/rcf/code-nodes/cn-703.json +16 -0
  32. package/rcf/code-nodes/cn-720.json +15 -0
  33. package/rcf/code-nodes/cn-721.json +15 -0
  34. package/rcf/code-nodes/cn-722.json +15 -0
  35. package/rcf/code-nodes/cn-723.json +18 -0
  36. package/rcf/code-nodes/cn-724.json +14 -0
  37. package/rcf/code-nodes/cn-725.json +37 -0
  38. package/rcf/code-nodes/cn-726.json +25 -0
  39. package/rcf/code-nodes/cn-727.json +23 -0
  40. package/rcf/code-nodes/cn-728.json +37 -0
  41. package/rcf/code-nodes/cn-729.json +26 -0
  42. package/rcf/code-nodes/cn-730.json +24 -0
  43. package/rcf/code-nodes/cn-731.json +20 -0
  44. package/rcf/code-nodes/cn-732.json +14 -0
  45. package/rcf/code-nodes/cn-733.json +14 -0
  46. package/rcf/code-nodes/cn-734.json +14 -0
  47. package/rcf/code-nodes/cn-735.json +20 -0
  48. package/rcf/code-nodes/cn-736.json +14 -0
  49. package/rcf/code-nodes/cn-737.json +14 -0
  50. package/rcf/code-nodes/cn-738.json +14 -0
  51. package/rcf/code-nodes/cn-739.json +18 -0
  52. package/rcf/code-nodes/cn-740.json +19 -0
  53. package/rcf/code-nodes/cn-741.json +16 -0
  54. package/rcf/code-nodes/cn-742.json +16 -0
  55. package/rcf/code-nodes/cn-743.json +15 -0
  56. package/rcf/code-nodes/cn-744.json +22 -0
  57. package/rcf/code-nodes/cn-745.json +16 -0
  58. package/rcf/code-nodes/cn-746.json +14 -0
  59. package/rcf/code-nodes/cn-747.json +18 -0
  60. package/rcf/code-nodes/cn-748.json +16 -0
  61. package/rcf/code-nodes/cn-749.json +16 -0
  62. package/rcf/code-nodes/cn-750.json +15 -0
  63. package/rcf/code-nodes/cn-751.json +18 -0
  64. package/rcf/code-nodes/cn-752.json +14 -0
  65. package/rcf/fbs/fbs-190.json +37 -0
  66. package/rcf/fbs/fbs-191.json +34 -0
  67. package/rcf/fbs/fbs-192.json +17 -0
  68. package/rcf/fbs/fbs-193.json +37 -0
  69. package/rcf/fbs/fbs-194.json +35 -0
  70. package/rcf/fbs/fbs-195.json +37 -0
  71. package/rcf/fbs/fbs-196.json +45 -0
  72. package/rcf/fbs/fbs-197.json +41 -0
  73. package/rcf/fbs/fbs-198.json +42 -0
  74. package/rcf/fbs/fbs-199.json +59 -0
  75. package/rcf/fbs/fbs-200.json +46 -0
  76. package/rcf/fbs/fbs-201.json +49 -0
  77. package/rcf/fbs/fbs-202.json +110 -0
  78. package/rcf/fbs/fbs-203.json +100 -0
  79. package/rcf/requirements/req-001.json +2 -1
  80. package/rcf/requirements/req-002.json +3 -2
  81. package/rcf/requirements/req-003.json +2 -1
  82. package/rcf/requirements/req-004.json +2 -1
  83. package/rcf/requirements/req-005.json +2 -1
  84. package/rcf/requirements/req-006.json +2 -1
  85. package/rcf/requirements/req-007.json +2 -1
  86. package/rcf/requirements/req-008.json +2 -1
  87. package/rcf/requirements/req-009.json +2 -1
  88. package/rcf/requirements/req-010.json +5 -2
  89. package/rcf/requirements/req-011.json +2 -1
  90. package/rcf/requirements/req-012.json +2 -1
  91. package/rcf/requirements/req-013.json +2 -1
  92. package/rcf/requirements/req-014.json +2 -1
  93. package/rcf/requirements/req-015.json +2 -1
  94. package/rcf/requirements/req-016.json +5 -2
  95. package/rcf/requirements/req-017.json +6 -2
  96. package/rcf/requirements/req-018.json +5 -2
  97. package/rcf/requirements/req-019.json +5 -2
  98. package/rcf/requirements/req-020.json +5 -2
  99. package/rcf/requirements/req-021.json +5 -2
  100. package/rcf/requirements/req-022.json +5 -2
  101. package/rcf/requirements/req-023.json +6 -4
  102. package/rcf/requirements/req-024.json +5 -2
  103. package/rcf/requirements/req-025.json +5 -2
  104. package/rcf/requirements/req-026.json +5 -2
  105. package/rcf/requirements/req-027.json +5 -2
  106. package/rcf/requirements/req-028.json +5 -2
  107. package/rcf/requirements/req-029.json +5 -2
  108. package/rcf/requirements/req-030.json +5 -2
  109. package/rcf/requirements/req-040.json +5 -2
  110. package/rcf/requirements/req-041.json +5 -2
  111. package/rcf/requirements/req-042.json +5 -2
  112. package/rcf/requirements/req-043.json +5 -2
  113. package/rcf/requirements/req-050.json +5 -2
  114. package/rcf/requirements/req-051.json +5 -2
  115. package/rcf/requirements/req-052.json +5 -2
  116. package/rcf/requirements/req-053.json +5 -2
  117. package/rcf/requirements/req-054.json +5 -2
  118. package/rcf/requirements/req-060.json +5 -2
  119. package/rcf/requirements/req-061.json +5 -2
  120. package/rcf/requirements/req-062.json +5 -2
  121. package/rcf/requirements/req-063.json +5 -2
  122. package/rcf/requirements/req-070.json +5 -2
  123. package/rcf/requirements/req-071.json +5 -2
  124. package/rcf/requirements/req-072.json +5 -2
  125. package/rcf/requirements/req-073.json +5 -2
  126. package/rcf/requirements/req-074.json +5 -2
  127. package/rcf/requirements/req-075.json +5 -2
  128. package/rcf/requirements/req-076.json +5 -2
  129. package/rcf/requirements/req-077.json +5 -2
  130. package/rcf/requirements/req-080.json +5 -2
  131. package/rcf/requirements/req-081.json +5 -2
  132. package/rcf/requirements/req-082.json +5 -2
  133. package/rcf/requirements/req-083.json +5 -2
  134. package/rcf/requirements/req-084.json +5 -2
  135. package/rcf/requirements/req-085.json +5 -2
  136. package/rcf/requirements/req-086.json +5 -2
  137. package/rcf/requirements/req-090.json +5 -2
  138. package/rcf/requirements/req-091.json +5 -2
  139. package/rcf/requirements/req-092.json +5 -2
  140. package/rcf/requirements/req-093.json +5 -2
  141. package/rcf/requirements/req-094.json +5 -2
  142. package/rcf/requirements/req-100.json +5 -2
  143. package/rcf/requirements/req-101.json +5 -2
  144. package/rcf/requirements/req-102.json +5 -2
  145. package/rcf/requirements/req-103.json +5 -2
  146. package/rcf/requirements/req-104.json +5 -2
  147. package/rcf/requirements/req-110.json +5 -2
  148. package/rcf/requirements/req-111.json +5 -2
  149. package/rcf/requirements/req-112.json +5 -2
  150. package/rcf/requirements/req-113.json +5 -2
  151. package/rcf/requirements/req-114.json +5 -2
  152. package/rcf/requirements/req-115.json +5 -2
  153. package/rcf/requirements/req-120.json +5 -2
  154. package/rcf/requirements/req-121.json +5 -2
  155. package/rcf/requirements/req-122.json +5 -2
  156. package/rcf/requirements/req-123.json +5 -2
  157. package/rcf/requirements/req-124.json +5 -2
  158. package/rcf/requirements/req-125.json +5 -2
  159. package/rcf/requirements/req-130.json +6 -2
  160. package/rcf/requirements/req-131.json +6 -2
  161. package/rcf/requirements/req-132.json +6 -2
  162. package/rcf/requirements/req-133.json +6 -2
  163. package/rcf/requirements/req-134.json +6 -2
  164. package/rcf/requirements/req-140.json +5 -2
  165. package/rcf/requirements/req-145.json +5 -2
  166. package/rcf/requirements/req-150.json +6 -2
  167. package/rcf/requirements/req-151.json +6 -2
  168. package/rcf/requirements/req-152.json +6 -2
  169. package/rcf/requirements/req-153.json +6 -2
  170. package/rcf/requirements/req-154.json +5 -2
  171. package/rcf/requirements/req-155.json +4 -1
  172. package/rcf/requirements/req-156.json +4 -1
  173. package/rcf/requirements/req-157.json +4 -1
  174. package/rcf/requirements/req-158.json +4 -1
  175. package/rcf/requirements/req-159.json +4 -1
  176. package/rcf/requirements/req-160.json +4 -1
  177. package/rcf/requirements/req-161.json +4 -1
  178. package/rcf/requirements/req-162.json +4 -1
  179. package/rcf/requirements/req-163.json +5 -2
  180. package/rcf/requirements/req-164.json +5 -2
  181. package/rcf/requirements/req-165.json +5 -2
  182. package/rcf/requirements/req-170.json +33 -0
  183. package/rcf/requirements/req-171.json +44 -0
  184. package/rcf/requirements/req-172.json +25 -0
  185. package/rcf/requirements/req-173.json +25 -0
  186. package/rcf/requirements/req-174.json +31 -0
  187. package/rcf/requirements/req-175.json +31 -0
  188. package/rcf/requirements/req-176.json +25 -0
  189. package/rcf/requirements/req-180.json +31 -0
  190. package/rcf/requirements/req-181.json +31 -0
  191. package/rcf/requirements/req-182.json +25 -0
  192. package/rcf/requirements/req-186.json +25 -0
  193. package/rcf/requirements/req-187.json +31 -0
  194. package/rcf/requirements/req-188.json +25 -0
  195. package/rcf/tacs/tac-4120-define-delta-and-freeze.json +21 -0
  196. package/rcf/tacs/tac-4121-define-ledgers.json +35 -0
  197. package/rcf/tacs/tac-4122-define-gates.json +61 -0
  198. package/rcf/tacs/tac-4123-define-readiness.json +61 -0
  199. package/rcf/tacs/tac-4124-define-freeze.json +28 -0
  200. package/rcf/tacs/tac-4127-readiness-view.json +49 -0
  201. package/rcf/tacs/tac-4128-define-guidance.json +53 -0
  202. package/rcf/tacs/tac-4129-define-questions.json +45 -0
  203. package/rcf/tacs/tac-4130-define-intake-brief.json +35 -0
  204. package/rcf/tacs/tac-4131-build-dag-view.json +39 -0
  205. package/rcf/tacs/tac-4132-id-lookup.json +42 -0
  206. package/rcf/tacs/tac-4133-readiness-po-layer.json +37 -0
  207. package/rcf/tacs/tac-4134-wespa-host-fixture.json +54 -0
  208. package/rcf/test-suites/ts-016.json +3 -3
  209. package/rcf/test-suites/ts-204.json +30 -0
  210. package/rcf/test-suites/ts-205.json +22 -0
  211. package/rcf/test-suites/ts-206.json +22 -0
  212. package/rcf/test-suites/ts-207.json +22 -0
  213. package/rcf/test-suites/ts-208.json +22 -0
  214. package/rcf/test-suites/ts-209.json +22 -0
  215. package/rcf/test-suites/ts-210.json +22 -0
  216. package/rcf/test-suites/ts-211.json +22 -0
  217. package/rcf/test-suites/ts-212.json +22 -0
  218. package/rcf/test-suites/ts-213.json +50 -0
  219. package/rcf/test-suites/ts-214.json +74 -0
  220. package/rcf/test-suites/ts-215.json +211 -0
  221. package/rcf/test-suites/ts-216.json +94 -0
  222. package/rcf/test-suites/ts-217.json +62 -0
  223. package/rcf/test-suites/ts-218.json +78 -0
  224. package/rcf/test-suites/ts-219.json +70 -0
  225. package/rcf/test-suites/ts-220.json +78 -0
  226. package/rcf/test-suites/ts-221.json +78 -0
  227. package/rcf/test-suites/ts-222.json +100 -0
  228. package/rcf/test-suites/ts-223.json +94 -0
  229. package/rcf/test-suites/ts-224.json +70 -0
  230. package/rcf/test-suites/ts-225.json +78 -0
  231. package/rcf/test-suites/ts-226.json +158 -0
  232. package/rcf/test-suites/ts-227.json +38 -0
  233. package/rcf/test-suites/ts-228.json +86 -0
  234. package/rcf/test-suites/ts-229.json +83 -0
  235. package/rcf/user-stories/us-15601.json +4 -4
  236. package/rcf/user-stories/us-17001.json +27 -0
  237. package/rcf/user-stories/us-17002.json +22 -0
  238. package/rcf/user-stories/us-17003.json +22 -0
  239. package/rcf/user-stories/us-17004.json +22 -0
  240. package/rcf/user-stories/us-17005.json +22 -0
  241. package/rcf/user-stories/us-17006.json +21 -0
  242. package/rcf/user-stories/us-17007.json +21 -0
  243. package/rcf/user-stories/us-17008.json +22 -0
  244. package/rcf/user-stories/us-17101.json +22 -0
  245. package/rcf/user-stories/us-17102.json +22 -0
  246. package/rcf/user-stories/us-17201.json +38 -0
  247. package/rcf/user-stories/us-17301.json +38 -0
  248. package/rcf/user-stories/us-17302.json +50 -0
  249. package/rcf/user-stories/us-17401.json +70 -0
  250. package/rcf/user-stories/us-17402.json +55 -0
  251. package/rcf/user-stories/us-17403.json +60 -0
  252. package/rcf/user-stories/us-17501.json +48 -0
  253. package/rcf/user-stories/us-17502.json +60 -0
  254. package/rcf/user-stories/us-17503.json +65 -0
  255. package/rcf/user-stories/us-17601.json +58 -0
  256. package/rcf/user-stories/us-18001.json +55 -0
  257. package/rcf/user-stories/us-18002.json +35 -0
  258. package/rcf/user-stories/us-18101.json +35 -0
  259. package/rcf/user-stories/us-18202.json +40 -0
  260. package/rcf/user-stories/us-18601.json +55 -0
  261. package/rcf/user-stories/us-18602.json +50 -0
  262. package/rcf/user-stories/us-18603.json +45 -0
  263. package/rcf/user-stories/us-18701.json +50 -0
  264. package/rcf/user-stories/us-18702.json +50 -0
  265. package/rcf/user-stories/us-18801.json +45 -0
  266. package/rcf/user-stories/us-204.json +59 -0
  267. package/rcf/user-stories/us-205.json +64 -0
  268. package/rcf/user-stories/us-206.json +54 -0
  269. package/releases/releases.yaml +31 -1
  270. package/src/cli/feedback.js +126 -10
  271. package/src/cli/freeze.js +730 -0
  272. package/src/cli/help.js +23 -0
  273. package/src/cli/ledger.js +615 -0
  274. package/src/cli/questions.js +288 -0
  275. package/src/cli/readiness.js +498 -0
  276. package/src/cli/view.js +29 -0
  277. package/src/core/store/writer.js +86 -6
  278. package/src/define/freeze-record.js +247 -0
  279. package/src/define/ledgers.js +712 -0
  280. package/src/feedback/redact.js +105 -19
  281. package/src/intake/index.js +1 -1
  282. package/src/intake/orchestrator.js +117 -0
  283. package/src/mcp/tools.js +354 -0
  284. package/src/query/delta.js +282 -0
  285. package/src/query/gates.js +1107 -0
  286. package/src/query/index.js +50 -0
  287. package/src/query/questions.js +438 -0
  288. package/src/query/readiness.js +574 -0
  289. package/src/server/index.js +60 -1
  290. package/src/server/routes.js +133 -4
  291. package/src/setup/identity-seed.js +17 -0
  292. package/src/view/build-dag.js +563 -0
  293. package/src/view/components/badge.js +41 -0
  294. package/src/view/components/diff.js +72 -0
  295. package/src/view/components/doc-row.js +62 -0
  296. package/src/view/components/empty-state.js +35 -0
  297. package/src/view/components/entity-selector.js +137 -0
  298. package/src/view/components/filter-bar.js +97 -0
  299. package/src/view/components/findings-list.js +49 -0
  300. package/src/view/components/index.js +12 -0
  301. package/src/view/components/pill.js +46 -0
  302. package/src/view/components/sub-tab-strip.js +43 -0
  303. package/src/view/components/toast.js +25 -0
  304. package/src/view/components-fixture.js +265 -0
  305. package/src/view/doc-renderers/architecture.js +304 -0
  306. package/src/view/doc-renderers/build.js +160 -0
  307. package/src/view/doc-renderers/helpers.js +2 -2
  308. package/src/view/doc-renderers/index.js +2 -0
  309. package/src/view/doc-renderers/prd.js +35 -6
  310. package/src/view/doc-renderers/req.js +10 -2
  311. package/src/view/doc-renderers/user-story.js +10 -5
  312. package/src/view/html-page.js +717 -300
  313. package/src/view/index.js +109 -3
  314. package/src/view/live-client.js +61 -8
  315. package/src/view/needs-work.js +79 -0
  316. package/src/view/page-init.js +2193 -0
  317. package/src/view/product-map.js +751 -0
  318. package/src/view/readiness/phrasebook.js +115 -0
  319. package/src/view/readiness/po-layer.js +288 -0
  320. package/src/view/readiness/question-adapter.js +329 -0
  321. package/src/view/readiness/stage-legend.js +71 -0
  322. package/src/view/readiness.js +505 -0
  323. package/src/view/style.css +2279 -266
  324. package/src/view/test-host/embed-client.js +121 -0
  325. package/src/view/test-host/fixture.js +183 -0
  326. package/src/view/test-host/lints.js +220 -0
  327. package/src/view/view-index.js +323 -0
@@ -4,7 +4,28 @@
4
4
  // GET /style.css -> shipped stylesheet
5
5
  // GET /mermaid.min.js-> vendored mermaid runtime
6
6
  // GET /live-client.js-> phase 3.8 live client script
7
+ // GET /page-init.js -> viewer UI refresh PR 1 shell / router script
8
+ // (Dex / wespa 2026-10-02 #263; release-noted so
9
+ // the proxy's route allow-list is extended).
7
10
  // GET /scope.json -> deep-link scope resolver (w-2026-08-30-dave-020)
11
+ // GET /index.json -> viewer UI refresh PR 7 ID lookup index built
12
+ // from BuiltTreeModel on every rewalk; `{ rows }`
13
+ // with one row per document id plus one per AC
14
+ // (ADR-4134; release-noted).
15
+ // GET /_fixtures/components -> viewer UI refresh PR 2 component
16
+ // fixture page (release-noted). Static page, no
17
+ // live-walk coupling, so it is always available
18
+ // even before the first rewalk completes.
19
+ // GET /test-host.html -> viewer UI refresh PR 9 wespa host fixture
20
+ // page (TAC-4134, ADR-4136). Only served when
21
+ // `deps.testHost === true`; 404 otherwise so
22
+ // wespa's reverse-proxy allow-list is unaffected.
23
+ // Mimics the wespa shell (56px header, resizable
24
+ // sidebar) and iframes the viewer at `./?embed=1
25
+ // &theme=light`. Test-suite proof only; not a
26
+ // shipped UI.
27
+ // GET /test-host.js -> viewer UI refresh PR 9 wespa host fixture
28
+ // client script. Same testHost gate as the HTML.
8
29
  // Everything else -> 404 text/plain.
9
30
  //
10
31
  // No CORS headers, no cache headers on static assets beyond what the
@@ -12,16 +33,36 @@
12
33
 
13
34
  import { readFile, stat } from 'node:fs/promises';
14
35
 
36
+ import { renderComponentsFixturePage } from '../view/components-fixture.js';
37
+ import { renderTestHostPage } from '../view/test-host/fixture.js';
38
+
39
+ // Issue #248 (0.28.3): the shipped static assets (style.css,
40
+ // mermaid.min.js, live-client.js) MUST be resolved once at server
41
+ // startup, not read from disk on every HTTP request. If the checkout
42
+ // switches branches or the file mutates while the server runs, per-
43
+ // request reads return the new bytes even though the HTML that
44
+ // references them was rendered from a walk taken at startup. The
45
+ // asymmetry produced the 2026-09-22 Product Map "unstyled preview"
46
+ // regression: HTML from the store walker was old, style.css was
47
+ // current, and the browser combined them.
48
+ //
49
+ // `deps.styleAsset`, `deps.mermaidAsset` and `deps.liveClientAsset`
50
+ // carry `{ buffer, size, contentType }` snapshotted at startup. The
51
+ // legacy `stylePath`/`mermaidPath`/`liveClientPath` props are kept
52
+ // for backwards compatibility with tests that pass a path; the
53
+ // router reads on-demand in that fallback path.
54
+
15
55
  const MIME = {
16
56
  html: 'text/html; charset=utf-8',
17
57
  css: 'text/css; charset=utf-8',
18
58
  js: 'application/javascript; charset=utf-8',
59
+ json: 'application/json; charset=utf-8',
19
60
  txt: 'text/plain; charset=utf-8',
20
61
  };
21
62
 
22
63
  /**
23
64
  * @typedef {object} RouterDeps
24
- * @property {() => { fullPageHtml: string, contentHtml: string, version: number } | null} currentState
65
+ * @property {() => { fullPageHtml: string, contentHtml: string, version: number, indexJson?: string } | null} currentState
25
66
  * @property {ReturnType<typeof import('./sse.js').createSseHub>} sse
26
67
  * @property {string} stylePath
27
68
  * @property {string} mermaidPath
@@ -68,15 +109,75 @@ export function createRouter(deps) {
68
109
  return;
69
110
  }
70
111
  if (path === '/style.css') {
71
- serveFile(res, deps.stylePath, MIME.css).catch((err) => fail(res, err));
112
+ serveAsset(res, deps.styleAsset, deps.stylePath, MIME.css).catch((err) => fail(res, err));
72
113
  return;
73
114
  }
74
115
  if (path === '/mermaid.min.js') {
75
- serveFile(res, deps.mermaidPath, MIME.js).catch((err) => fail(res, err));
116
+ serveAsset(res, deps.mermaidAsset, deps.mermaidPath, MIME.js).catch((err) => fail(res, err));
76
117
  return;
77
118
  }
78
119
  if (path === '/live-client.js') {
79
- serveFile(res, deps.liveClientPath, MIME.js).catch((err) => fail(res, err));
120
+ serveAsset(res, deps.liveClientAsset, deps.liveClientPath, MIME.js).catch((err) => fail(res, err));
121
+ return;
122
+ }
123
+ if (path === '/page-init.js') {
124
+ serveAsset(res, deps.pageInitAsset, deps.pageInitPath, MIME.js).catch((err) => fail(res, err));
125
+ return;
126
+ }
127
+ if (path.startsWith('/product-map/')) {
128
+ const state = deps.currentState();
129
+ if (!state || !state.pmPartials) {
130
+ res.writeHead(503, { 'content-type': MIME.txt });
131
+ res.end('view server initialising\n');
132
+ return;
133
+ }
134
+ const group = path.slice('/product-map/'.length);
135
+ const html = state.pmPartials[group];
136
+ if (typeof html !== 'string') {
137
+ res.writeHead(404, { 'content-type': MIME.txt });
138
+ res.end('unknown grouping\n');
139
+ return;
140
+ }
141
+ res.writeHead(200, { 'content-type': MIME.html, 'cache-control': 'no-store' });
142
+ res.end(html);
143
+ return;
144
+ }
145
+ if (path === '/_fixtures/components') {
146
+ res.writeHead(200, { 'content-type': MIME.html, 'cache-control': 'no-store' });
147
+ res.end(renderComponentsFixturePage());
148
+ return;
149
+ }
150
+ if (path === '/test-host.html' && deps.testHost) {
151
+ // Viewer UI refresh PR 9 (TAC-4134, ADR-4136): the wespa host
152
+ // fixture is only mounted when the server was started with
153
+ // testHost: true. No X-Frame-Options, no CSP; the viewer's
154
+ // framing lint asserts the same on GET /.
155
+ res.writeHead(200, { 'content-type': MIME.html, 'cache-control': 'no-store' });
156
+ res.end(renderTestHostPage());
157
+ return;
158
+ }
159
+ if (path === '/test-host.js' && deps.testHost) {
160
+ serveAsset(res, deps.testHostClientAsset, deps.testHostClientPath, MIME.js).catch((err) => fail(res, err));
161
+ return;
162
+ }
163
+ if (path === '/index.json') {
164
+ // Viewer UI refresh PR 7 (TAC-4132, ADR-4134): the ID lookup
165
+ // index is built once per rewalk and lives on `state.indexJson`
166
+ // as a pre-stringified payload, so this handler never touches
167
+ // disk and content-length matches the exact bytes served.
168
+ const state = deps.currentState();
169
+ if (!state || typeof state.indexJson !== 'string') {
170
+ res.writeHead(503, { 'content-type': MIME.txt });
171
+ res.end('view server initialising\n');
172
+ return;
173
+ }
174
+ const body = state.indexJson;
175
+ res.writeHead(200, {
176
+ 'content-type': MIME.json,
177
+ 'content-length': String(Buffer.byteLength(body)),
178
+ 'cache-control': 'no-store',
179
+ });
180
+ res.end(body);
80
181
  return;
81
182
  }
82
183
  if (path === '/scope.json') {
@@ -94,6 +195,34 @@ export function createRouter(deps) {
94
195
  };
95
196
  }
96
197
 
198
+ /**
199
+ * Issue #248 (0.28.3): serve a snapshotted asset when the server has
200
+ * one, otherwise fall through to the legacy per-request read. The
201
+ * happy path never touches the filesystem after startup, so a checkout
202
+ * switch during the server's lifetime cannot change what gets served.
203
+ *
204
+ * @param {import('node:http').ServerResponse} res
205
+ * @param {{ buffer: Buffer, size: number, contentType?: string } | undefined | null} asset
206
+ * @param {string | undefined} fallbackPath
207
+ * @param {string} contentType
208
+ */
209
+ async function serveAsset(res, asset, fallbackPath, contentType) {
210
+ if (asset && asset.buffer) {
211
+ res.writeHead(200, {
212
+ 'content-type': asset.contentType ?? contentType,
213
+ 'content-length': String(asset.size),
214
+ });
215
+ res.end(asset.buffer);
216
+ return;
217
+ }
218
+ if (fallbackPath) {
219
+ await serveFile(res, fallbackPath, contentType);
220
+ return;
221
+ }
222
+ res.writeHead(404, { 'content-type': MIME.txt });
223
+ res.end('not found\n');
224
+ }
225
+
97
226
  async function serveFile(res, path, contentType) {
98
227
  let body;
99
228
  let size;
@@ -75,6 +75,23 @@ escalation.)_
75
75
 
76
76
  unstated
77
77
 
78
+ ## Surface
79
+
80
+ _(how the agent frames its review-ready output when a slice closes.
81
+ One of the three values below on a single line; the seeded default is
82
+ \`prDiff\` and a hand-edit is one word away.)_
83
+
84
+ - \`viewer\`: the slice is reviewed in a rendered viewer surface (an
85
+ HTML preview, a Readiness tab, a dashboard). The agent lands on a
86
+ URL the operator opens.
87
+ - \`runningApp\`: the slice is reviewed by running the app and
88
+ observing behaviour. The agent lands on a one-line reproduction
89
+ recipe.
90
+ - \`prDiff\`: the slice is reviewed as a pull-request diff on the
91
+ shared repo. The agent lands on a PR link with the chain IDs listed.
92
+
93
+ prDiff
94
+
78
95
  ## Project-scoped notes
79
96
 
80
97
  _(anything specific to this project that would be useful for the agent