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
@@ -0,0 +1,64 @@
1
+ {
2
+ "usId": "US-205",
3
+ "prdId": "PRD-001",
4
+ "reqId": "REQ-002",
5
+ "version": "0.1.0",
6
+ "status": "draft",
7
+ "title": "An engineer jumps to any document or AC by id",
8
+ "description": "A SearchButton to the right of the tabstrip and the Cmd/Ctrl+F keyboard binding open a LookupModal with type-ahead over a server-built `./index.json` carrying every document id and every AC. Id matches rank first (exact, prefix, contains), then every query word must match title or snippet, title above snippet; a single character searches ids only; 20 results. A pick sets `#tab=<tab>&entity=<id>`; the Router activates the tab, opens every ancestor DocRow and flashes the target. `embed` and `theme` survive every hash write. See viewer UI refresh design doc section 6.",
9
+ "asA": "an engineer looking at any tab of the review surface",
10
+ "iWant": "a modal that lets me jump to any document or AC by typing part of its id or title",
11
+ "soThat": "I can navigate the tree by id without hunting through the tabs",
12
+ "acceptanceCriteria": [
13
+ {
14
+ "id": "AC-205-1",
15
+ "description": "[happy] Given the review surface, when the SearchButton is pressed or Cmd/Ctrl+F is typed from any tab, then the LookupModal opens; typing an exact id (`REQ-002`) or a prefix (`REQ-00`) ranks that id first and the first result row is pre-highlighted.",
16
+ "testable": true
17
+ },
18
+ {
19
+ "id": "AC-205-2",
20
+ "description": "[happy] Given the LookupModal, when a word query matches a document's title and another document's snippet, then the title match ranks above the snippet match.",
21
+ "testable": true
22
+ },
23
+ {
24
+ "id": "AC-205-3",
25
+ "description": "[happy] Given the LookupModal, when a query of exactly one character is typed, then only ids whose identifier contains that character rank, and the title / snippet word-match pass is skipped.",
26
+ "testable": true
27
+ },
28
+ {
29
+ "id": "AC-205-4",
30
+ "description": "[happy] Given a pre-highlighted result for `US-304`, when Enter is pressed, then the hash becomes `#tab=requirements&entity=US-304`, the Router activates the Requirements tab, opens the REQ-003 ancestor DocRow and the US-304 row, scrolls the target into view and flashes it.",
31
+ "testable": true
32
+ },
33
+ {
34
+ "id": "AC-205-5",
35
+ "description": "[happy] Given a mount URL `?tab=requirements&entity=US-304`, when the shell first paints, then the Router lands on the same position: Requirements tab active, REQ-003 and US-304 DocRows open, US-304 scrolled into view.",
36
+ "testable": true
37
+ },
38
+ {
39
+ "id": "AC-205-6",
40
+ "description": "[happy] Given `?embed=1&theme=dark` on the viewer URL, when a result is picked from the LookupModal, then the resulting URL still carries `embed=1` and `theme=dark` in the query string and the hash is `#tab=<tab>&entity=<id>`.",
41
+ "testable": true
42
+ },
43
+ {
44
+ "id": "AC-205-7",
45
+ "description": "[failure] Given a `./index.json` fetch that returns a non-2xx status or a malformed body, when the LookupModal is opened, then an empty state renders with a reload affordance that re-fetches the index, and no result rows show.",
46
+ "testable": true
47
+ },
48
+ {
49
+ "id": "AC-205-8",
50
+ "description": "[must-not] Given the LookupModal, when the user types a query, picks a result or closes the modal, then no `postMessage` is sent to the parent window, no outbound network request beyond the `./index.json` fetch is made, and no search term is written to `localStorage` / `sessionStorage` / cookies.",
51
+ "testable": true
52
+ }
53
+ ],
54
+ "tacIds": [
55
+ "TAC-4132-id-lookup"
56
+ ],
57
+ "tags": [
58
+ "view",
59
+ "lookup",
60
+ "navigation"
61
+ ],
62
+ "createdAt": "2026-10-02T19:00:00Z",
63
+ "updatedAt": "2026-10-02T19:00:00Z"
64
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "usId": "US-206",
3
+ "prdId": "PRD-001",
4
+ "reqId": "REQ-002",
5
+ "version": "0.1.0",
6
+ "status": "draft",
7
+ "title": "wespa's embedding contract is proved by a CI host fixture",
8
+ "description": "A same-origin test-host fixture served by the viewer's dev server (route `/test-host.html` behind a `--test-host` flag or an env guard; off by default so wespa's proxy allow-list is unaffected) mimics the wespa shell: a 56px header, a resizable sidebar (64px collapsed, 200-400px expanded, user-resizable live via a drag handle), a content pane carrying an `<iframe src=\"./?embed=1&theme=light\">`. The host posts `{ type: \"rcf-view-theme\", theme: \"light\"|\"dark\" }` on a toggle control; it stores no theme itself so a passing run proves the iframe reads the message. The viewer sends no outbound postMessage. Three lints run in the test suite: (1) framing lint (`GET /` returns no `X-Frame-Options`, no CSP `frame-ancestors` that forbids same-origin, and the fixture loads the iframe without a browser error); (2) target lint (no `target=\"_top\"` string in the server-rendered HTML); (3) localStorage namespace lint (every `localStorage.{setItem,getItem,removeItem}` and shared `storage.*` call site in `src/view/**` uses a key starting with `rcf-view:v1:`). See viewer UI refresh design doc section 9 and Dex's wespa requirements of 2026-10-02.",
9
+ "asA": "Dex integrating the rcf-lite viewer behind wespa's reverse proxy",
10
+ "iWant": "a CI host fixture that proves the viewer honours the embedding contract and three lints that keep framing, target='_top' and localStorage namespace in place over time",
11
+ "soThat": "regressions in the embedding contract are caught in the viewer's own suite before they reach wespa",
12
+ "acceptanceCriteria": [
13
+ {
14
+ "id": "AC-206-1",
15
+ "description": "[happy] Given the test-host fixture at `/test-host.html`, when the page loads with the viewer served from the same origin, then the iframe `src` is `./?embed=1&theme=light`, the title block and footer of the iframed viewer are hidden (`<html data-embed=\"1\">`), the tab nav is visible and the host's 56px header plus the resizable sidebar render around it.",
16
+ "testable": true
17
+ },
18
+ {
19
+ "id": "AC-206-2",
20
+ "description": "[happy] Given the test-host fixture with the iframe loaded, when the host's theme toggle posts `{ type: \"rcf-view-theme\", theme: \"dark\" }` to the iframe's `contentWindow`, then the iframe's `<html data-theme>` flips to `dark` without a reload and the content repaints in the dark token set.",
21
+ "testable": true
22
+ },
23
+ {
24
+ "id": "AC-206-3",
25
+ "description": "[happy] Given the test-host fixture with the iframe loaded at `./?embed=1&theme=dark`, when a hash-only navigation inside the iframe writes `#tab=requirements&entity=REQ-002`, then the iframe's query still carries `embed=1` and `theme=dark` and the viewer's inner `<html data-embed=\"1\" data-theme=\"dark\">` is preserved.",
26
+ "testable": true
27
+ },
28
+ {
29
+ "id": "AC-206-4",
30
+ "description": "[failure] Given the viewer page listening for `rcf-view-theme` postMessages, when a message with `event.origin` different from `window.location.origin` is delivered, then the message is ignored and `<html data-theme>` is not changed.",
31
+ "testable": true
32
+ },
33
+ {
34
+ "id": "AC-206-5",
35
+ "description": "[must-not] Given the viewer's `GET /` response, when the three lints run in the test suite, then (a) no `X-Frame-Options` header is set and no CSP `frame-ancestors` directive forbids same-origin framing, (b) `target=\"_top\"` appears zero times in the rendered HTML across every tab, (c) every `localStorage.{setItem,getItem,removeItem}` and shared `storage.*` call site under `src/view/**` uses a key starting with `rcf-view:v1:`.",
36
+ "testable": true
37
+ },
38
+ {
39
+ "id": "AC-206-6",
40
+ "description": "[must-not] Given the test-host fixture and the viewer page, when either is loaded, then neither posts any outbound message beyond the host's `rcf-view-theme`; the viewer sends no `postMessage` of any shape, and the test-host adds no new postMessage shape.",
41
+ "testable": true
42
+ }
43
+ ],
44
+ "tacIds": [
45
+ "TAC-4134-wespa-host-fixture"
46
+ ],
47
+ "tags": [
48
+ "view",
49
+ "embedding",
50
+ "lint"
51
+ ],
52
+ "createdAt": "2026-10-02T20:00:00Z",
53
+ "updatedAt": "2026-10-02T20:00:00Z"
54
+ }
@@ -40,8 +40,38 @@
40
40
  # `npm install rcf-lite`.
41
41
 
42
42
  feedVersion: 1
43
- latest: "0.28.2"
43
+ latest: "0.29.0"
44
44
  releases:
45
+ - version: "0.29.0"
46
+ date: "2026-10-03"
47
+ breaking: true
48
+ headlines:
49
+ - "rcf-lite 0.29.0 lands the viewer UI refresh train in one release: a rebuilt shell with the Stravica brand tokens, light and dark theme and an embed contract; shared components across Requirements, Architecture, Build and Readiness; a Build DAG sub-tab with click-to-highlight closure, dependency inspector and an unconnected lane; fast ID lookup over a new ./index.json served from the viewer root (Cmd/Ctrl+F from any tab); the Readiness tab Product Owner redesign; and a same-origin test-host fixture that pins the embedding contract with three in-suite guards. For wespa embedders, the reverse-proxy allow-list for /rcf-viewer/* MUST add /page-init.js and /index.json before the version pin bump; /test-host.html and /test-host.js stay 404 by default so the allow-list is unchanged by the embedding-proof fixture."
50
+ - "The DEFINE readiness persona split arrives too: every gate check carries a persona (product owner or engineer), two readiness levels (intent-complete, ready-to-build), the Readiness tab moves to tab one, and rcf define readiness gains --level and --persona flags with a persona-grouped text report."
51
+ - "The first three DEFINE step 3 PRs ship: document intake into the brief ledger via a statement file parser and the mechanical intake scans; a new rcf define ledger <name> update <id> subverb with a closed resolvedBy pointer grammar (REQ-nnn, TAD.entity:<name>, PRD.user:<name>, TAD.system:<name>, TAC-nnnn, omitted:<reason>) and the D2 skeleton:resolvedBy title-hit fallback dropped; a rcf define questions verb with three new MCP tools and two argument-free prompts for the harness-driven loop; and the [draft] shapes gate across TAC purpose, interface and core-entity homes with a DISCOVERY prototypes doctrine."
52
+ minAgentAction: rerun-init
53
+ notesUrl: "https://stravica.ai/docs/rcf/changelog/"
54
+
55
+ - version: "0.28.4"
56
+ date: "2026-09-30"
57
+ breaking: false
58
+ headlines:
59
+ - "rcf-lite 0.28.4 fixes user story minting on legacy trees that carry flat sequential ids. On a tree migrated in from a v1 project, minting a new user story under a requirement now extends the flat sequence (US-163 to US-164) instead of jumping to an encoded slot such as US-5301; a tree that mixes both id shapes is refused with a message naming one example of each so the operator can normalise it first. Acceptance criteria minting is unchanged."
60
+ - "The 0.28.3 fixes ship in this release, because 0.28.3 was written up on 22 September but never tagged or published. Those are the feedback redactor no longer folding git protocol sentinels as emails, a visible warning when identity folding is disabled, and the live-view server snapshotting its static assets at startup."
61
+ - "The DEFINE workflow foundations arrive ahead of the 0.29.0 train: delta detection, freeze records, four sidecar ledgers with rcf define ledger, stage gates D1 to D8, and rcf define readiness, plus the Product Map tab on the review surface."
62
+ minAgentAction: null
63
+ notesUrl: "https://stravica.ai/docs/rcf/changelog/"
64
+
65
+ - version: "0.28.3"
66
+ date: "2026-09-22"
67
+ breaking: false
68
+ headlines:
69
+ - "rcf-lite 0.28.3 is a small batched fix release for the residuals Dex's 0.28.2 round-trip surfaced and one HQ-side viewer bug caught the same day. The feedback redactor no longer folds the git protocol sentinel git@<host> inside git+ssh, ssh or git URLs as an email, so an evidence pointer copied verbatim from a git remote or clone URL survives as evidence. Bare git remotes and single-letter trailing labels like a.b.c are also protected as URI userinfo and filename fragments; real emails in surrounding prose still fold."
70
+ - "The redactor emits a visible stderr warning when identity folding is disabled, so an operator whose rcf/.identity/profile.md is missing, empty, a placeholder, or contains only reserved nouns is no longer left thinking their identity is in force when it silently is not. Feedback status --json now exposes the destination source field the preview surface already prints, and --evidence pointers now render with the label matching their shape (command / path:line / id) rather than always (command)."
71
+ - "The live-view server snapshots its shipped static assets (style.css, mermaid.min.js, live-client.js) at startup instead of reading them from disk per request, so a checkout branch switch during the server's lifetime can no longer silently change the served CSS."
72
+ minAgentAction: null
73
+ notesUrl: "https://stravica.ai/docs/rcf/changelog/"
74
+
45
75
  - version: "0.28.2"
46
76
  date: "2026-09-22"
47
77
  breaking: false
@@ -54,7 +54,7 @@ import {
54
54
  emitSessionStart,
55
55
  shouldAsk,
56
56
  } from '../feedback/hook.js';
57
- import { redact, allowedHosts, findResidualSecrets } from '../feedback/redact.js';
57
+ import { redact, allowedHosts, findResidualSecrets, RESERVED_IDENTITY_TOKENS } from '../feedback/redact.js';
58
58
  import { fingerprint } from '../feedback/fingerprint.js';
59
59
  import { renderIssue, renderComment, renderBundle } from '../feedback/render.js';
60
60
  import { resolve as resolveDestination, listUnresolvedLibraries, findBlueprintRecord } from '../feedback/destination.js';
@@ -477,17 +477,58 @@ async function handleAdd(argv, ctx) {
477
477
  }
478
478
 
479
479
  /**
480
- * Classify an evidence pointer into `{ kind, value }`. A colon-separated
481
- * `path:line` pattern is 'file'; a bare identifier that looks like an
482
- * upper-cased id is 'id'; anything else is 'command'. The classification
483
- * is best-effort and does not gate the write.
480
+ * Classify an evidence pointer into `{ kind, value }`. The help text
481
+ * promises three shapes: command / path:line / id. The classifier
482
+ * distinguishes them by cheap shape rules:
483
+ *
484
+ * - `id`: a canonical uppercase-prefix RCF artefact id (`AC-15501-1`,
485
+ * `REQ-155`, `FBS-181`, `US-15701`).
486
+ * - `file`: `path:line` (a non-space token ending in `:<digits>`) OR
487
+ * a bare filesystem path shape - a slash-bearing, non-whitespace
488
+ * token that ends in a known file extension. This is the shape a
489
+ * `--evidence rcf/.blueprint-libraries/wsd/1.0.0/library.json`
490
+ * argument carries (issue #245).
491
+ * - `command`: anything else. This is the fallback shape for a bare
492
+ * verb invocation like `rcf feedback preview` or `pnpm --filter
493
+ * rcf-lite test`.
494
+ *
495
+ * Classification is best-effort and never gates the write; the value
496
+ * itself is always preserved verbatim. The rendered preview label
497
+ * uses this kind so the operator sees which shape the pointer carries
498
+ * without having to re-run it.
484
499
  *
485
500
  * @param {string} value
486
501
  * @returns {{ kind: 'file' | 'id' | 'command', value: string }}
487
502
  */
503
+ // 0.28.3 (issue #245): extension shortlist used by `classifyEvidence`
504
+ // to recognise bare file-path evidence. Kept in lockstep with the
505
+ // redactor's default extension allowlist so operators see the same
506
+ // treatment on both sides. Duplicated deliberately (not imported) to
507
+ // keep the CLI light on cross-module reads for a per-call classifier.
508
+ const EVIDENCE_FILE_EXTENSIONS = new Set([
509
+ 'md', 'mdx', 'json', 'yml', 'yaml', 'txt',
510
+ 'js', 'mjs', 'cjs', 'ts', 'tsx',
511
+ 'html', 'css', 'png', 'svg', 'sh', 'csv', 'log', 'lock',
512
+ ]);
513
+
488
514
  export function classifyEvidence(value) {
515
+ if (typeof value !== 'string' || value.length === 0) return { kind: 'command', value };
516
+ // Canonical RCF id shape: uppercase prefix, then digits (e.g. AC-15501-1).
489
517
  if (/^[A-Z]+-\d[\w-]*$/.test(value)) return { kind: 'id', value };
490
- if (/^[^\s].*:\d+$/.test(value)) return { kind: 'file', value };
518
+ // path:line - a non-whitespace token ending in ":<digits>".
519
+ if (/^[^\s]+:\d+$/.test(value)) return { kind: 'file', value };
520
+ // Bare filesystem path or filename: no whitespace, ends in a known
521
+ // extension (issue #245). Whitespace anywhere disqualifies the
522
+ // candidate; that is almost certainly a shell command. A bare
523
+ // filename without a slash still counts because a --evidence
524
+ // pointer to README.md or CHANGELOG.md is common.
525
+ if (!/\s/.test(value)) {
526
+ const lastDot = value.lastIndexOf('.');
527
+ if (lastDot > 0 && lastDot < value.length - 1) {
528
+ const ext = value.slice(lastDot + 1).toLowerCase();
529
+ if (EVIDENCE_FILE_EXTENSIONS.has(ext)) return { kind: 'file', value };
530
+ }
531
+ }
491
532
  return { kind: 'command', value };
492
533
  }
493
534
 
@@ -624,6 +665,14 @@ async function handleStatus(argv, ctx) {
624
665
  visibility: dest.visibility ?? 'unresolved',
625
666
  derived: !!dest.derived,
626
667
  reason: dest.reason ?? null,
668
+ // Issue #244 (0.28.3): the preview surface prints
669
+ // `source: <library-manifest|package-bugs-url|derived|...>` so
670
+ // the operator can see WHICH resolver path picked the destination.
671
+ // The --json surface must expose the same field for programmatic
672
+ // verifiers per AC-15502-2 (--json emits the same as text). The
673
+ // field is null when the resolver did not attach one (e.g. an
674
+ // unresolved library).
675
+ source: dest.source ?? null,
627
676
  });
628
677
  }
629
678
 
@@ -672,6 +721,12 @@ async function handleStatus(argv, ctx) {
672
721
  ? `${row.repo} (${row.visibility}${row.derived ? ', derived' : ''})`
673
722
  : `(unresolved${row.reason ? `: ${row.reason}` : ''})`;
674
723
  stdout.write(` - ${row.ref} -> ${cell}\n`);
724
+ // Issue #244 (0.28.3): print the resolver source so text and
725
+ // --json carry the same disclosure. Preview already prints this;
726
+ // status now matches per AC-15502-2 parity.
727
+ if (row.source) {
728
+ stdout.write(` source: ${row.source}\n`);
729
+ }
675
730
  }
676
731
  }
677
732
  return 0;
@@ -1003,15 +1058,76 @@ async function handlePreview(argv, ctx) {
1003
1058
  */
1004
1059
  async function buildRedactionContext(projectRoot) {
1005
1060
  let operatorName;
1061
+ // 0.28.3 (R5g, issue #246): track why identity folding might be
1062
+ // disabled so we can emit exactly one visible stderr warning
1063
+ // instead of leaving the operator to guess. `disabledReason` is
1064
+ // one of 'no-profile' (rcf/.identity/profile.md is missing or
1065
+ // unreadable), 'no-name-line' (present but no `## Name` heading),
1066
+ // 'blank-name' (whitespace-only), 'placeholder' (matches the
1067
+ // placeholder/todo regex), 'stopword-only' (Name contains only
1068
+ // reserved-noun tokens), or null when a foldable identity was
1069
+ // extracted.
1070
+ let disabledReason = 'no-profile';
1006
1071
  try {
1007
1072
  const profile = await readFile(resolve(projectRoot, 'rcf', '.identity', 'profile.md'), 'utf8');
1008
- const m = profile.match(/^##\s+Name\s*\n([^\n]+)/m);
1009
- if (m) {
1010
- const n = m[1].trim();
1011
- if (n && !/placeholder|todo|your name/i.test(n)) operatorName = n;
1073
+ // Codex P1-2: extract the Name-section body up to the next `## `
1074
+ // heading or EOF, using ONLY horizontal whitespace on the heading
1075
+ // line so an empty section (`## Name\n\n## Role\n...`) does not
1076
+ // greedy-match into the next section's heading. Bind the search
1077
+ // to the first `## Name` header only.
1078
+ // JS regex has no `\Z`; use a lookahead for the next `## ` header
1079
+ // OR end of string. `[\s\S]*?` is lazy so it stops at the first
1080
+ // matching lookahead.
1081
+ const nameSection = profile.match(/^##[ \t]+Name[ \t]*\n([\s\S]*?)(?=^##[ \t]+|$(?![\s\S]))/m);
1082
+ if (!nameSection) {
1083
+ disabledReason = 'no-name-line';
1084
+ } else {
1085
+ // The first non-empty non-comment line inside the Name section is
1086
+ // the operator's identity. Strip whitespace and leading/trailing
1087
+ // markdown emphasis so a shipped placeholder like
1088
+ // `_(who you are; how you want the agent to address you)_` is
1089
+ // seen as text, not folded as a name token.
1090
+ const nonEmpty = nameSection[1].split('\n').map((l) => l.trim()).filter((l) => l.length > 0);
1091
+ const first = nonEmpty[0];
1092
+ if (!first) {
1093
+ disabledReason = 'blank-name';
1094
+ } else if (/^_\(.*\)_$/i.test(first) || /placeholder|todo|your name/i.test(first) || /^_.*(who you are|how you want).*_$/i.test(first)) {
1095
+ // Codex P1-3: recognise the shipped seed placeholder shape
1096
+ // `_(who you are; how you want the agent to address you)_`
1097
+ // as a placeholder so the untouched generated profile emits
1098
+ // the disabled-folding warning rather than folding the
1099
+ // placeholder text as a name.
1100
+ disabledReason = 'placeholder';
1101
+ } else {
1102
+ operatorName = first;
1103
+ const rawTokens = first.split(/\s+/);
1104
+ const foldable = rawTokens.filter((t) => t.length > 3 && !RESERVED_IDENTITY_TOKENS.has(t.toLowerCase()));
1105
+ if (foldable.length === 0) {
1106
+ disabledReason = 'stopword-only';
1107
+ } else {
1108
+ disabledReason = null;
1109
+ }
1110
+ }
1012
1111
  }
1013
1112
  } catch { /* absent is fine */ }
1014
1113
 
1114
+ // Emit the one-line warning once per context build. All disabled
1115
+ // reasons carry the same fix pointer so the operator knows how to
1116
+ // arm folding without having to read the source.
1117
+ if (disabledReason) {
1118
+ const path = 'rcf/.identity/profile.md';
1119
+ const detail = {
1120
+ 'no-profile': `${path} is missing`,
1121
+ 'no-name-line': `${path} has no \`## Name\` heading`,
1122
+ 'blank-name': `${path} \`## Name\` line is empty`,
1123
+ 'placeholder': `${path} \`## Name\` line is a placeholder`,
1124
+ 'stopword-only': `${path} \`## Name\` line contains only reserved nouns`,
1125
+ }[disabledReason] ?? path;
1126
+ process.stderr.write(
1127
+ `[warn] operator-identity: ${detail}; identity folding is disabled. Add a real \`## Name\` line to arm the redactor.\n`
1128
+ );
1129
+ }
1130
+
1015
1131
  let projectName;
1016
1132
  const remotes = new Set();
1017
1133
  try {