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.
- package/CHANGELOG.md +317 -0
- package/bin/rcf.js +8 -0
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/define-draft-shapes.md +89 -0
- package/guidance/define-intake.md +97 -0
- package/guidance/define-intent.md +107 -0
- package/guidance/discover-prototype.md +67 -0
- package/guidance/discovery-prototypes.md +69 -0
- package/guidance/harness-template.md +34 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +34 -0
- package/guidance/manifest.json +9 -2
- package/package.json +1 -1
- package/rcf/adrs/adr-4120-canonical-json-hashing.json +30 -0
- package/rcf/adrs/adr-4121-define-sidecars.json +30 -0
- package/rcf/adrs/adr-4122-define-gates-blocking-and-optout.json +30 -0
- package/rcf/adrs/adr-4123-readiness-single-object.json +30 -0
- package/rcf/adrs/adr-4124-define-freeze-verb.json +30 -0
- package/rcf/adrs/adr-4126-persona-tagged-blockers-two-levels.json +40 -0
- package/rcf/adrs/adr-4127-readiness-tab-order-and-register.json +40 -0
- package/rcf/adrs/adr-4129-questions-harness-driven-loop.json +25 -0
- package/rcf/adrs/adr-4130-intake-harness-split-tool-scanned.json +20 -0
- package/rcf/adrs/adr-4132-prototypes-in-discovery-as-evidence.json +20 -0
- package/rcf/adrs/adr-4133-dag-dependency-depth-layout.json +40 -0
- package/rcf/adrs/adr-4134-index-json-route.json +35 -0
- package/rcf/adrs/adr-4135-readiness-po-register-and-adapter.json +35 -0
- package/rcf/adrs/adr-4136-embedding-host-fixture.json +35 -0
- package/rcf/code-nodes/cn-700.json +23 -0
- package/rcf/code-nodes/cn-701.json +14 -0
- package/rcf/code-nodes/cn-702.json +14 -0
- package/rcf/code-nodes/cn-703.json +16 -0
- package/rcf/code-nodes/cn-720.json +15 -0
- package/rcf/code-nodes/cn-721.json +15 -0
- package/rcf/code-nodes/cn-722.json +15 -0
- package/rcf/code-nodes/cn-723.json +18 -0
- package/rcf/code-nodes/cn-724.json +14 -0
- package/rcf/code-nodes/cn-725.json +37 -0
- package/rcf/code-nodes/cn-726.json +25 -0
- package/rcf/code-nodes/cn-727.json +23 -0
- package/rcf/code-nodes/cn-728.json +37 -0
- package/rcf/code-nodes/cn-729.json +26 -0
- package/rcf/code-nodes/cn-730.json +24 -0
- package/rcf/code-nodes/cn-731.json +20 -0
- package/rcf/code-nodes/cn-732.json +14 -0
- package/rcf/code-nodes/cn-733.json +14 -0
- package/rcf/code-nodes/cn-734.json +14 -0
- package/rcf/code-nodes/cn-735.json +20 -0
- package/rcf/code-nodes/cn-736.json +14 -0
- package/rcf/code-nodes/cn-737.json +14 -0
- package/rcf/code-nodes/cn-738.json +14 -0
- package/rcf/code-nodes/cn-739.json +18 -0
- package/rcf/code-nodes/cn-740.json +19 -0
- package/rcf/code-nodes/cn-741.json +16 -0
- package/rcf/code-nodes/cn-742.json +16 -0
- package/rcf/code-nodes/cn-743.json +15 -0
- package/rcf/code-nodes/cn-744.json +22 -0
- package/rcf/code-nodes/cn-745.json +16 -0
- package/rcf/code-nodes/cn-746.json +14 -0
- package/rcf/code-nodes/cn-747.json +18 -0
- package/rcf/code-nodes/cn-748.json +16 -0
- package/rcf/code-nodes/cn-749.json +16 -0
- package/rcf/code-nodes/cn-750.json +15 -0
- package/rcf/code-nodes/cn-751.json +18 -0
- package/rcf/code-nodes/cn-752.json +14 -0
- package/rcf/fbs/fbs-190.json +37 -0
- package/rcf/fbs/fbs-191.json +34 -0
- package/rcf/fbs/fbs-192.json +17 -0
- package/rcf/fbs/fbs-193.json +37 -0
- package/rcf/fbs/fbs-194.json +35 -0
- package/rcf/fbs/fbs-195.json +37 -0
- package/rcf/fbs/fbs-196.json +45 -0
- package/rcf/fbs/fbs-197.json +41 -0
- package/rcf/fbs/fbs-198.json +42 -0
- package/rcf/fbs/fbs-199.json +59 -0
- package/rcf/fbs/fbs-200.json +46 -0
- package/rcf/fbs/fbs-201.json +49 -0
- package/rcf/fbs/fbs-202.json +110 -0
- package/rcf/fbs/fbs-203.json +100 -0
- package/rcf/requirements/req-001.json +2 -1
- package/rcf/requirements/req-002.json +3 -2
- package/rcf/requirements/req-003.json +2 -1
- package/rcf/requirements/req-004.json +2 -1
- package/rcf/requirements/req-005.json +2 -1
- package/rcf/requirements/req-006.json +2 -1
- package/rcf/requirements/req-007.json +2 -1
- package/rcf/requirements/req-008.json +2 -1
- package/rcf/requirements/req-009.json +2 -1
- package/rcf/requirements/req-010.json +5 -2
- package/rcf/requirements/req-011.json +2 -1
- package/rcf/requirements/req-012.json +2 -1
- package/rcf/requirements/req-013.json +2 -1
- package/rcf/requirements/req-014.json +2 -1
- package/rcf/requirements/req-015.json +2 -1
- package/rcf/requirements/req-016.json +5 -2
- package/rcf/requirements/req-017.json +6 -2
- package/rcf/requirements/req-018.json +5 -2
- package/rcf/requirements/req-019.json +5 -2
- package/rcf/requirements/req-020.json +5 -2
- package/rcf/requirements/req-021.json +5 -2
- package/rcf/requirements/req-022.json +5 -2
- package/rcf/requirements/req-023.json +6 -4
- package/rcf/requirements/req-024.json +5 -2
- package/rcf/requirements/req-025.json +5 -2
- package/rcf/requirements/req-026.json +5 -2
- package/rcf/requirements/req-027.json +5 -2
- package/rcf/requirements/req-028.json +5 -2
- package/rcf/requirements/req-029.json +5 -2
- package/rcf/requirements/req-030.json +5 -2
- package/rcf/requirements/req-040.json +5 -2
- package/rcf/requirements/req-041.json +5 -2
- package/rcf/requirements/req-042.json +5 -2
- package/rcf/requirements/req-043.json +5 -2
- package/rcf/requirements/req-050.json +5 -2
- package/rcf/requirements/req-051.json +5 -2
- package/rcf/requirements/req-052.json +5 -2
- package/rcf/requirements/req-053.json +5 -2
- package/rcf/requirements/req-054.json +5 -2
- package/rcf/requirements/req-060.json +5 -2
- package/rcf/requirements/req-061.json +5 -2
- package/rcf/requirements/req-062.json +5 -2
- package/rcf/requirements/req-063.json +5 -2
- package/rcf/requirements/req-070.json +5 -2
- package/rcf/requirements/req-071.json +5 -2
- package/rcf/requirements/req-072.json +5 -2
- package/rcf/requirements/req-073.json +5 -2
- package/rcf/requirements/req-074.json +5 -2
- package/rcf/requirements/req-075.json +5 -2
- package/rcf/requirements/req-076.json +5 -2
- package/rcf/requirements/req-077.json +5 -2
- package/rcf/requirements/req-080.json +5 -2
- package/rcf/requirements/req-081.json +5 -2
- package/rcf/requirements/req-082.json +5 -2
- package/rcf/requirements/req-083.json +5 -2
- package/rcf/requirements/req-084.json +5 -2
- package/rcf/requirements/req-085.json +5 -2
- package/rcf/requirements/req-086.json +5 -2
- package/rcf/requirements/req-090.json +5 -2
- package/rcf/requirements/req-091.json +5 -2
- package/rcf/requirements/req-092.json +5 -2
- package/rcf/requirements/req-093.json +5 -2
- package/rcf/requirements/req-094.json +5 -2
- package/rcf/requirements/req-100.json +5 -2
- package/rcf/requirements/req-101.json +5 -2
- package/rcf/requirements/req-102.json +5 -2
- package/rcf/requirements/req-103.json +5 -2
- package/rcf/requirements/req-104.json +5 -2
- package/rcf/requirements/req-110.json +5 -2
- package/rcf/requirements/req-111.json +5 -2
- package/rcf/requirements/req-112.json +5 -2
- package/rcf/requirements/req-113.json +5 -2
- package/rcf/requirements/req-114.json +5 -2
- package/rcf/requirements/req-115.json +5 -2
- package/rcf/requirements/req-120.json +5 -2
- package/rcf/requirements/req-121.json +5 -2
- package/rcf/requirements/req-122.json +5 -2
- package/rcf/requirements/req-123.json +5 -2
- package/rcf/requirements/req-124.json +5 -2
- package/rcf/requirements/req-125.json +5 -2
- package/rcf/requirements/req-130.json +6 -2
- package/rcf/requirements/req-131.json +6 -2
- package/rcf/requirements/req-132.json +6 -2
- package/rcf/requirements/req-133.json +6 -2
- package/rcf/requirements/req-134.json +6 -2
- package/rcf/requirements/req-140.json +5 -2
- package/rcf/requirements/req-145.json +5 -2
- package/rcf/requirements/req-150.json +6 -2
- package/rcf/requirements/req-151.json +6 -2
- package/rcf/requirements/req-152.json +6 -2
- package/rcf/requirements/req-153.json +6 -2
- package/rcf/requirements/req-154.json +5 -2
- package/rcf/requirements/req-155.json +4 -1
- package/rcf/requirements/req-156.json +4 -1
- package/rcf/requirements/req-157.json +4 -1
- package/rcf/requirements/req-158.json +4 -1
- package/rcf/requirements/req-159.json +4 -1
- package/rcf/requirements/req-160.json +4 -1
- package/rcf/requirements/req-161.json +4 -1
- package/rcf/requirements/req-162.json +4 -1
- package/rcf/requirements/req-163.json +5 -2
- package/rcf/requirements/req-164.json +5 -2
- package/rcf/requirements/req-165.json +5 -2
- package/rcf/requirements/req-170.json +33 -0
- package/rcf/requirements/req-171.json +44 -0
- package/rcf/requirements/req-172.json +25 -0
- package/rcf/requirements/req-173.json +25 -0
- package/rcf/requirements/req-174.json +31 -0
- package/rcf/requirements/req-175.json +31 -0
- package/rcf/requirements/req-176.json +25 -0
- package/rcf/requirements/req-180.json +31 -0
- package/rcf/requirements/req-181.json +31 -0
- package/rcf/requirements/req-182.json +25 -0
- package/rcf/requirements/req-186.json +25 -0
- package/rcf/requirements/req-187.json +31 -0
- package/rcf/requirements/req-188.json +25 -0
- package/rcf/tacs/tac-4120-define-delta-and-freeze.json +21 -0
- package/rcf/tacs/tac-4121-define-ledgers.json +35 -0
- package/rcf/tacs/tac-4122-define-gates.json +61 -0
- package/rcf/tacs/tac-4123-define-readiness.json +61 -0
- package/rcf/tacs/tac-4124-define-freeze.json +28 -0
- package/rcf/tacs/tac-4127-readiness-view.json +49 -0
- package/rcf/tacs/tac-4128-define-guidance.json +53 -0
- package/rcf/tacs/tac-4129-define-questions.json +45 -0
- package/rcf/tacs/tac-4130-define-intake-brief.json +35 -0
- package/rcf/tacs/tac-4131-build-dag-view.json +39 -0
- package/rcf/tacs/tac-4132-id-lookup.json +42 -0
- package/rcf/tacs/tac-4133-readiness-po-layer.json +37 -0
- package/rcf/tacs/tac-4134-wespa-host-fixture.json +54 -0
- package/rcf/test-suites/ts-016.json +3 -3
- package/rcf/test-suites/ts-204.json +30 -0
- package/rcf/test-suites/ts-205.json +22 -0
- package/rcf/test-suites/ts-206.json +22 -0
- package/rcf/test-suites/ts-207.json +22 -0
- package/rcf/test-suites/ts-208.json +22 -0
- package/rcf/test-suites/ts-209.json +22 -0
- package/rcf/test-suites/ts-210.json +22 -0
- package/rcf/test-suites/ts-211.json +22 -0
- package/rcf/test-suites/ts-212.json +22 -0
- package/rcf/test-suites/ts-213.json +50 -0
- package/rcf/test-suites/ts-214.json +74 -0
- package/rcf/test-suites/ts-215.json +211 -0
- package/rcf/test-suites/ts-216.json +94 -0
- package/rcf/test-suites/ts-217.json +62 -0
- package/rcf/test-suites/ts-218.json +78 -0
- package/rcf/test-suites/ts-219.json +70 -0
- package/rcf/test-suites/ts-220.json +78 -0
- package/rcf/test-suites/ts-221.json +78 -0
- package/rcf/test-suites/ts-222.json +100 -0
- package/rcf/test-suites/ts-223.json +94 -0
- package/rcf/test-suites/ts-224.json +70 -0
- package/rcf/test-suites/ts-225.json +78 -0
- package/rcf/test-suites/ts-226.json +158 -0
- package/rcf/test-suites/ts-227.json +38 -0
- package/rcf/test-suites/ts-228.json +86 -0
- package/rcf/test-suites/ts-229.json +83 -0
- package/rcf/user-stories/us-15601.json +4 -4
- package/rcf/user-stories/us-17001.json +27 -0
- package/rcf/user-stories/us-17002.json +22 -0
- package/rcf/user-stories/us-17003.json +22 -0
- package/rcf/user-stories/us-17004.json +22 -0
- package/rcf/user-stories/us-17005.json +22 -0
- package/rcf/user-stories/us-17006.json +21 -0
- package/rcf/user-stories/us-17007.json +21 -0
- package/rcf/user-stories/us-17008.json +22 -0
- package/rcf/user-stories/us-17101.json +22 -0
- package/rcf/user-stories/us-17102.json +22 -0
- package/rcf/user-stories/us-17201.json +38 -0
- package/rcf/user-stories/us-17301.json +38 -0
- package/rcf/user-stories/us-17302.json +50 -0
- package/rcf/user-stories/us-17401.json +70 -0
- package/rcf/user-stories/us-17402.json +55 -0
- package/rcf/user-stories/us-17403.json +60 -0
- package/rcf/user-stories/us-17501.json +48 -0
- package/rcf/user-stories/us-17502.json +60 -0
- package/rcf/user-stories/us-17503.json +65 -0
- package/rcf/user-stories/us-17601.json +58 -0
- package/rcf/user-stories/us-18001.json +55 -0
- package/rcf/user-stories/us-18002.json +35 -0
- package/rcf/user-stories/us-18101.json +35 -0
- package/rcf/user-stories/us-18202.json +40 -0
- package/rcf/user-stories/us-18601.json +55 -0
- package/rcf/user-stories/us-18602.json +50 -0
- package/rcf/user-stories/us-18603.json +45 -0
- package/rcf/user-stories/us-18701.json +50 -0
- package/rcf/user-stories/us-18702.json +50 -0
- package/rcf/user-stories/us-18801.json +45 -0
- package/rcf/user-stories/us-204.json +59 -0
- package/rcf/user-stories/us-205.json +64 -0
- package/rcf/user-stories/us-206.json +54 -0
- package/releases/releases.yaml +31 -1
- package/src/cli/feedback.js +126 -10
- package/src/cli/freeze.js +730 -0
- package/src/cli/help.js +23 -0
- package/src/cli/ledger.js +615 -0
- package/src/cli/questions.js +288 -0
- package/src/cli/readiness.js +498 -0
- package/src/cli/view.js +29 -0
- package/src/core/store/writer.js +86 -6
- package/src/define/freeze-record.js +247 -0
- package/src/define/ledgers.js +712 -0
- package/src/feedback/redact.js +105 -19
- package/src/intake/index.js +1 -1
- package/src/intake/orchestrator.js +117 -0
- package/src/mcp/tools.js +354 -0
- package/src/query/delta.js +282 -0
- package/src/query/gates.js +1107 -0
- package/src/query/index.js +50 -0
- package/src/query/questions.js +438 -0
- package/src/query/readiness.js +574 -0
- package/src/server/index.js +60 -1
- package/src/server/routes.js +133 -4
- package/src/setup/identity-seed.js +17 -0
- package/src/view/build-dag.js +563 -0
- package/src/view/components/badge.js +41 -0
- package/src/view/components/diff.js +72 -0
- package/src/view/components/doc-row.js +62 -0
- package/src/view/components/empty-state.js +35 -0
- package/src/view/components/entity-selector.js +137 -0
- package/src/view/components/filter-bar.js +97 -0
- package/src/view/components/findings-list.js +49 -0
- package/src/view/components/index.js +12 -0
- package/src/view/components/pill.js +46 -0
- package/src/view/components/sub-tab-strip.js +43 -0
- package/src/view/components/toast.js +25 -0
- package/src/view/components-fixture.js +265 -0
- package/src/view/doc-renderers/architecture.js +304 -0
- package/src/view/doc-renderers/build.js +160 -0
- package/src/view/doc-renderers/helpers.js +2 -2
- package/src/view/doc-renderers/index.js +2 -0
- package/src/view/doc-renderers/prd.js +35 -6
- package/src/view/doc-renderers/req.js +10 -2
- package/src/view/doc-renderers/user-story.js +10 -5
- package/src/view/html-page.js +717 -300
- package/src/view/index.js +109 -3
- package/src/view/live-client.js +61 -8
- package/src/view/needs-work.js +79 -0
- package/src/view/page-init.js +2193 -0
- package/src/view/product-map.js +751 -0
- package/src/view/readiness/phrasebook.js +115 -0
- package/src/view/readiness/po-layer.js +288 -0
- package/src/view/readiness/question-adapter.js +329 -0
- package/src/view/readiness/stage-legend.js +71 -0
- package/src/view/readiness.js +505 -0
- package/src/view/style.css +2279 -266
- package/src/view/test-host/embed-client.js +121 -0
- package/src/view/test-host/fixture.js +183 -0
- package/src/view/test-host/lints.js +220 -0
- 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
|
+
}
|
package/releases/releases.yaml
CHANGED
|
@@ -40,8 +40,38 @@
|
|
|
40
40
|
# `npm install rcf-lite`.
|
|
41
41
|
|
|
42
42
|
feedVersion: 1
|
|
43
|
-
latest: "0.
|
|
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
|
package/src/cli/feedback.js
CHANGED
|
@@ -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 }`.
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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 {
|