rcf-lite 0.28.1 → 0.28.2
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 +99 -0
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +1 -1
- package/rcf/code-nodes/cn-602.json +3 -2
- package/rcf/fbs/fbs-181.json +3 -2
- package/rcf/tacs/tac-4103-feedback-redact.json +2 -2
- package/rcf/test-suites/ts-188.json +10 -2
- package/rcf/test-suites/ts-191.json +19 -5
- package/rcf/user-stories/us-15601.json +9 -0
- package/rcf/user-stories/us-15701.json +4 -4
- package/releases/releases.yaml +11 -1
- package/src/browser-verify/manifest-writer.js +9 -5
- package/src/cli/browser-verify.js +9 -1
- package/src/cli/feedback.js +190 -22
- package/src/cli/intake.js +25 -4
- package/src/cli/preflight.js +24 -3
- package/src/cli/review.js +9 -1
- package/src/cli/ui-baseline.js +14 -1
- package/src/core/store/index.js +5 -0
- package/src/core/store/validate-composed-record.js +95 -0
- package/src/feedback/gh.js +27 -1
- package/src/feedback/redact-allowlist.json +7 -0
- package/src/feedback/redact.js +31 -2
- package/src/feedback/render.js +34 -12
- package/src/intake/manifest-writer.js +6 -3
- package/src/intake/orchestrator.js +44 -7
- package/src/preflight/manifest-writer.js +11 -11
- package/src/req-baseline/sweep.js +34 -5
- package/src/ui-baseline/manifest-writer.js +11 -10
- package/src/view/doc-renderers/helpers.js +37 -0
- package/src/view/doc-renderers/tad.js +67 -6
- package/src/view/style.css +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,105 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.28.2] - 2026-09-22
|
|
10
|
+
|
|
11
|
+
Batched fix release for the seven defects Barry's WSD-lens dogfood on
|
|
12
|
+
0.28.1 surfaced (issues #229-#235), plus the three unreported dry-run
|
|
13
|
+
gaps Barry folded into the same release on 2026-09-21 (review,
|
|
14
|
+
ui-baseline init, browser-verify). Ships two chain amendments (the fold
|
|
15
|
+
rule on submit and a filename-token narrowing on the redactor's rule 4)
|
|
16
|
+
and five build diffs behind them.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **Submit no longer folds unrelated findings into one issue and no
|
|
21
|
+
longer replaces the report with a "+1" stub (#234).** Barry's
|
|
22
|
+
round-trip filed five distinct findings with four distinct
|
|
23
|
+
fingerprints; every one folded to a single pre-existing issue whose
|
|
24
|
+
fingerprint matched none of them, and every comment carried
|
|
25
|
+
`+1 from another reporter.` with no title, body or evidence. The
|
|
26
|
+
fix, per Barry's 2026-09-21 ruling on the fold rule: submit no
|
|
27
|
+
longer treats a `gh search issues` hit as a fold decision. For
|
|
28
|
+
every returned candidate it now re-reads the issue body via a new
|
|
29
|
+
`ghIssueGetBody` gh-adapter function and folds only when the body
|
|
30
|
+
carries `rcf-feedback-fingerprint: <fp>` on its own line AND the
|
|
31
|
+
anchor / kind / target markers agree with the entry's. The retired
|
|
32
|
+
`+1 from another reporter.` payload is gone: every fold comment
|
|
33
|
+
now carries the full report prefaced with "Apparent duplicate of
|
|
34
|
+
the issue subject; posting the full report so a human can judge."
|
|
35
|
+
Submit's stdout row names the outcome and the matched title so a
|
|
36
|
+
wrong fold is visible on the same line a human already sees
|
|
37
|
+
(`created #N <url>` vs `commented on #N (fingerprint match:
|
|
38
|
+
<title>) <url>`). Chain: US-15701 AC-15701-2 amended.
|
|
39
|
+
|
|
40
|
+
- **Redactor no longer rewrites `.md` filenames as hostnames (#233).**
|
|
41
|
+
Barry's evidence pointer
|
|
42
|
+
`rcf discover intake --artefact rcf/knowledge/docs/brief/Backstory-product-brief.md,...`
|
|
43
|
+
was rendered as `Backstory-<host>`, destroying the exact evidence
|
|
44
|
+
the verb asks for. Rule 4 gets two narrowings per design amendment
|
|
45
|
+
R5d: the bare-hostname regex's negative lookbehind now includes
|
|
46
|
+
`-` (so `product-brief.md` can never start a match after the
|
|
47
|
+
hyphen), and a candidate hostname whose trailing dot-label is on a
|
|
48
|
+
bundled `extensions` shortlist in `src/feedback/redact-allowlist.json`
|
|
49
|
+
is left intact with no ledger row. Bundled list covers the file
|
|
50
|
+
types rcf-lite feedback sees as evidence (md, mdx, json, yml,
|
|
51
|
+
yaml, txt, js, mjs, cjs, ts, tsx, html, css, png, svg, sh, csv,
|
|
52
|
+
log, lock). Operator overlay merges via `allowExtensions` on the
|
|
53
|
+
redact context. Chain: US-15601 AC-15601-6 added; TAC-4103
|
|
54
|
+
responsibility updated.
|
|
55
|
+
|
|
56
|
+
- **Dry-run and write now share one schema pass across the five
|
|
57
|
+
discover verbs (#230 and #232, folding review / ui-baseline init /
|
|
58
|
+
browser-verify per Barry's 2026-09-21 ruling).** Two direct
|
|
59
|
+
reproductions: `intake --input <file> --dry-run` accepted
|
|
60
|
+
`fidelity: briefRich` that the real run refused (#230); `preflight
|
|
61
|
+
--input <file> --dry-run` accepted a kebab-case service id that
|
|
62
|
+
the real run refused (#232). Same class in the three unreported
|
|
63
|
+
verbs. Fix: a shared `validateComposedRecord({ tree, record, verb
|
|
64
|
+
})` helper in `src/core/store/validate-composed-record.js`
|
|
65
|
+
synthesises the same nextManifest each writer builds, runs
|
|
66
|
+
`validateDocument`, and returns null or the same error the writer
|
|
67
|
+
would refuse on. Wired into every dry-run branch; exit code 3 on a
|
|
68
|
+
validation miss in every path. `intake --help` now advertises the
|
|
69
|
+
fidelity enum (`FIDELITY_LEVELS`); `preflight --help` names the
|
|
70
|
+
service id pattern (`^[a-z][a-zA-Z0-9]*$`).
|
|
71
|
+
|
|
72
|
+
- **`discover intake` no longer emits the same finding once per
|
|
73
|
+
artefact (#229).** Two artefacts that both trip the same branch
|
|
74
|
+
(`impliedButNotStated` on a web UI with no sign-in surface) landed
|
|
75
|
+
as two byte-identical findings in the record. Findings are now
|
|
76
|
+
material-scoped (deduped by `<kind>::<detail>` before timestamping)
|
|
77
|
+
and operator-supplied `validationFindings` on `--input` survive
|
|
78
|
+
regardless of kind (previously only `otherDeclared` was folded,
|
|
79
|
+
silently dropping `impliedButNotStated` / `contradiction` /
|
|
80
|
+
`missingLoadBearingConstraint`). A scan hit and an operator-authored
|
|
81
|
+
finding of the same (kind, detail) coalesce with the operator's
|
|
82
|
+
response preserved. Build-only per the RCA.
|
|
83
|
+
|
|
84
|
+
- **`req-baseline sweep --yes` no longer assigns duplicate AC ids
|
|
85
|
+
across a batch (#231).** Accepting two or more baseline candidates
|
|
86
|
+
for one user story in one sweep refused the write with
|
|
87
|
+
`Duplicate id AC-<usNum>-<N>`. Fix: extract the ordinal allocator
|
|
88
|
+
into `makeAcIdAllocator(usDoc)`; `applySweepDecisions` creates one
|
|
89
|
+
allocator per US and passes each allocated id into
|
|
90
|
+
`composeBaselineAc` via a new optional `idOverride` parameter.
|
|
91
|
+
`nextAcId` and the single-candidate call shape stay
|
|
92
|
+
backwards-compatible. Build-only per the RCA.
|
|
93
|
+
|
|
94
|
+
- **TAD renderer no longer dumps `JSON.stringify(x)` for structured
|
|
95
|
+
fields (#235).** Barry's review surface showed 14 raw single-line
|
|
96
|
+
JSON blobs across `dataStores`, `coreEntities` and
|
|
97
|
+
`externalSystems`. A new `fieldObjectTable(label, rows, columns)`
|
|
98
|
+
helper renders each schema-known structured field as a table with
|
|
99
|
+
the columns the TAD schema documents. Empty columns are dropped so
|
|
100
|
+
schema-optional fields do not surface as blank columns; every cell
|
|
101
|
+
is escaped. `renderOptionalSections` picks the table renderer for
|
|
102
|
+
`dataArchitecture.dataStores`, `dataArchitecture.coreEntities`,
|
|
103
|
+
`integrationArchitecture.externalSystems`; everything else keeps
|
|
104
|
+
the scalar / array-of-string treatment. `style.css` gets a
|
|
105
|
+
lightweight `.field-list table.field-table` rule matching the
|
|
106
|
+
existing cadence. Build-only per the RCA.
|
|
107
|
+
|
|
9
108
|
## [0.28.1] - 2026-09-17
|
|
10
109
|
|
|
11
110
|
Feedback defects surfaced by the first WSD-lens round-trip on 0.28.0. Fixes both a destination bug that silently misrouted library-owned findings to `Stravica/rcf-lite`, and a redactor over-fold that mangled the docs URL and any prose using the canonical noun `agent`. Includes a package-rename disclosure banner in the README so a colleague hitting `npm i -g @stravica-ai/rcf-build-lite` on the retired scoped name knows what to do.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"registerCanary": [
|
|
3
3
|
{
|
|
4
|
-
"id": "rc-2026-09-
|
|
5
|
-
"createdAt": "2026-09-
|
|
6
|
-
"buildVersion": "0.28.
|
|
4
|
+
"id": "rc-2026-09-22-001",
|
|
5
|
+
"createdAt": "2026-09-22T08:35:47.450Z",
|
|
6
|
+
"buildVersion": "0.28.2-mockdriver",
|
|
7
7
|
"fixturePromptId": "canary-prompt-01",
|
|
8
8
|
"responseWordCount": 55,
|
|
9
9
|
"grades": {
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"shipDespiteFailReason": "mock canary driver used; no real subagent was dispatched. This record verifies canary infrastructure only, not the register itself."
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
|
-
"id": "rc-2026-09-
|
|
38
|
-
"createdAt": "2026-09-
|
|
39
|
-
"buildVersion": "0.28.
|
|
37
|
+
"id": "rc-2026-09-22-002",
|
|
38
|
+
"createdAt": "2026-09-22T08:35:47.451Z",
|
|
39
|
+
"buildVersion": "0.28.2-mockdriver",
|
|
40
40
|
"fixturePromptId": "canary-prompt-02",
|
|
41
41
|
"responseWordCount": 55,
|
|
42
42
|
"grades": {
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"shipDespiteFailReason": "mock canary driver used; no real subagent was dispatched. This record verifies canary infrastructure only, not the register itself."
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
|
-
"id": "rc-2026-09-
|
|
71
|
-
"createdAt": "2026-09-
|
|
72
|
-
"buildVersion": "0.28.
|
|
70
|
+
"id": "rc-2026-09-22-003",
|
|
71
|
+
"createdAt": "2026-09-22T08:35:47.451Z",
|
|
72
|
+
"buildVersion": "0.28.2-mockdriver",
|
|
73
73
|
"fixturePromptId": "canary-prompt-03",
|
|
74
74
|
"responseWordCount": 55,
|
|
75
75
|
"grades": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rcf-lite",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "One-install tooling for the Requirements Confidence Framework (RCF): the unified `rcf` CLI grouped into the five RCF tool groups (discover, define, build, verify, audit) plus a small core set (init, doctor, guidance, mcp), an MCP server, the live tree viewer and the fresh-context adversarial ship-gate verifier. Consumes @stravica-ai/rcf-schemas.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
"AC-15601-2",
|
|
7
7
|
"AC-15601-3",
|
|
8
8
|
"AC-15601-4",
|
|
9
|
-
"AC-15601-5"
|
|
9
|
+
"AC-15601-5",
|
|
10
|
+
"AC-15601-6"
|
|
10
11
|
],
|
|
11
12
|
"dependencies": [],
|
|
12
13
|
"version": "0.1.0",
|
|
13
14
|
"status": "draft",
|
|
14
15
|
"createdAt": "2026-09-16T15:27:35Z",
|
|
15
|
-
"updatedAt": "2026-09-
|
|
16
|
+
"updatedAt": "2026-09-22T00:00:00Z"
|
|
16
17
|
}
|
package/rcf/fbs/fbs-181.json
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"AC-15601-3",
|
|
14
14
|
"AC-15601-4",
|
|
15
15
|
"AC-15601-5",
|
|
16
|
-
"AC-15701-1"
|
|
16
|
+
"AC-15701-1",
|
|
17
|
+
"AC-15601-6"
|
|
17
18
|
],
|
|
18
19
|
"dependsOnFbsIds": [
|
|
19
20
|
"FBS-180"
|
|
@@ -42,5 +43,5 @@
|
|
|
42
43
|
"estimatedHours": 16,
|
|
43
44
|
"notes": "Fingerprint decision confined to this slice via ADR-4102; the labels half of that ADR pays off in slice 4.",
|
|
44
45
|
"createdAt": "2026-09-16T13:45:23.000Z",
|
|
45
|
-
"updatedAt": "2026-09-
|
|
46
|
+
"updatedAt": "2026-09-22T00:00:00Z"
|
|
46
47
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"Apply the eight redaction rules from design section 5 to title, body and evidence strings",
|
|
11
11
|
"Return a ledger of { rule, before, after, count } entries for the operator disclosure",
|
|
12
12
|
"Refuse on residual-secret matches (second pass) with a line pointer so the offending body is not sent",
|
|
13
|
-
"Ship a bundled allowlist of vendor hosts and
|
|
13
|
+
"Ship a bundled allowlist of vendor hosts and an `extensions` shortlist on src/feedback/redact-allowlist.json (Barry ruling 2026-09-21); the operator's rcf/feedback-settings.json may still supply additional host and extension entries which are merged at call time (design amendment R5d)",
|
|
14
14
|
"Guard operator-identity substitution with a RESERVED_IDENTITY_TOKENS stopword list (agent, user, admin, api, code, system, etc.) so a common noun in the operator's identity name never folds; substitution still fires for real given names in the identity"
|
|
15
15
|
],
|
|
16
16
|
"internalStructure": "src/feedback/redact.js is a pure module: redact(text, context) -> { text, ledger[] } plus small per-rule helpers. src/feedback/redact-allowlist.json ships the vendor host set; the extension array is merged at call time.",
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"tradeoffs": "Rule-based redaction is testable with a fixture corpus and deterministic under review; the cost is that it will occasionally over-redact (a benign name that matches an entropy rule), which is what the disclosure ledger exists to catch.",
|
|
37
37
|
"notes": "The stored entry is never mutated by redaction; the rendered output is what leaves.",
|
|
38
38
|
"createdAt": "2026-09-16T13:45:23.000Z",
|
|
39
|
-
"updatedAt": "2026-09-
|
|
39
|
+
"updatedAt": "2026-09-22T00:00:00Z"
|
|
40
40
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"createdAt": "2026-09-16T15:27:35Z",
|
|
3
|
-
"updatedAt": "2026-09-
|
|
3
|
+
"updatedAt": "2026-09-22T00:00:00Z",
|
|
4
4
|
"purpose": "Cover AC-15601-1 (rcf feedback preview renders each pending entry as the title and body that would be filed, lists the destination, and prints the redaction ledger over the full eight-rule vocabulary), AC-15601-2 (preview marks residual-secret findings so the operator sees before consenting; the submit half of AC-15601-2 lands with slice 4), AC-15601-3 (preview never mutates the stored entries.jsonl), AC-15601-4 (a final whole-text residual-secret pass on the fully rendered and normalised issue body and each bundle refuses submit on any hit) and AC-15701-1 (a stable 12-hex fingerprint is attached per entry, folds across blueprint versions when the anchor+class match, and falls back to normalised-title tokens with a warning when the anchor is absent).",
|
|
5
5
|
"testLevel": "integration",
|
|
6
6
|
"acIds": [
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"AC-15601-3",
|
|
10
10
|
"AC-15601-4",
|
|
11
11
|
"AC-15701-1",
|
|
12
|
-
"AC-15601-5"
|
|
12
|
+
"AC-15601-5",
|
|
13
|
+
"AC-15601-6"
|
|
13
14
|
],
|
|
14
15
|
"id": "TS-188",
|
|
15
16
|
"usId": "US-15601",
|
|
@@ -168,6 +169,13 @@
|
|
|
168
169
|
"description": "Cover AC-15601-5 via the unit test: redact runs over a body containing the docs URL 'https://stravica.ai/docs/rcf/how-the-agent-files-feedback', the prose 'when the agent stops the queue' and the personal name 'Alice reviewed this', with operatorName seeded as 'The Agent Alice'; the docs URL is emitted verbatim; the prose 'when the agent stops the queue' is emitted verbatim; 'Alice' folds to <operator>; no operator-identity ledger row names 'agent' or 'the'.",
|
|
169
170
|
"status": "pending",
|
|
170
171
|
"testPointer": "test/feedback/redact.test.js::AC-15601-5 operator-identity stopword guard: common nouns in the identity string are never folded; real given names still fold"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "TC-188-redact-filename-extensions-allowlist",
|
|
175
|
+
"acId": "AC-15601-6",
|
|
176
|
+
"description": "Cover AC-15601-6 via the unit test: redact runs over a body containing 'Backstory-product-brief.md', 'intake.json', 'report.log', 'foo.example.com', 'foo.example.com/path', 'Backstory-example.com' and 'a.b.c'; the three filename tokens survive verbatim with no hostname ledger row; foo.example.com folds to <host>; foo.example.com/path folds via the URL rule; Backstory-example.com folds; a.b.c folds; extending redact-allowlist.json extensions with 'xyz' also lets 'file.xyz' survive.",
|
|
177
|
+
"status": "pending",
|
|
178
|
+
"testPointer": "test/feedback/redact.test.js::AC-15601-6 filename tokens carrying a known extension survive rule 4"
|
|
171
179
|
}
|
|
172
180
|
],
|
|
173
181
|
"status": "draft"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"createdAt": "2026-09-16T17:23:12Z",
|
|
3
|
-
"updatedAt": "2026-09-
|
|
3
|
+
"updatedAt": "2026-09-22T00:00:00Z",
|
|
4
4
|
"purpose": "Cover AC-15701-2 (submit calls gh search + create/comment per the zero/one/many hit table) and AC-15701-3 (search unavailable falls through to create with dedupe: unchecked; closed-state hit stamps a previously reported reference into the create body). Slice 4 arm of US-15701.",
|
|
5
5
|
"testLevel": "integration",
|
|
6
6
|
"acIds": [
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
{
|
|
22
22
|
"id": "TC-191-submit-one-hit-comments",
|
|
23
23
|
"acId": "AC-15701-2",
|
|
24
|
-
"description": "Cover AC-15701-2 (one-hit arm) via the CLI test: with
|
|
24
|
+
"description": "Cover AC-15701-2 (one-hit verified arm, 0.28.2 #234) via the CLI test: with the fake returning one search match whose body carries the same fingerprint line, submit calls ghIssueGetBody to verify, then ghIssueComment on that number with the full report; no ghIssueCreate.",
|
|
25
25
|
"status": "pending",
|
|
26
|
-
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2:
|
|
26
|
+
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2: a verified fingerprint match folds via comment; comment body carries the full report; stdout names the matched title"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"id": "TC-191-submit-many-hit-comment-lowest",
|
|
30
30
|
"acId": "AC-15701-2",
|
|
31
|
-
"description": "Cover AC-15701-2 (many
|
|
31
|
+
"description": "Cover AC-15701-2 (many verified matches arm, 0.28.2 #234) via the CLI test: with three matches whose bodies all carry the entry's fingerprint line, submit comments on the lowest number and the comment body carries the full report + mentions of the other numbers.",
|
|
32
32
|
"status": "pending",
|
|
33
|
-
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2: many
|
|
33
|
+
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2: many verified fingerprint matches fold on the lowest number and mention the others"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"id": "TC-191-submit-search-unchecked",
|
|
@@ -45,6 +45,20 @@
|
|
|
45
45
|
"description": "Cover AC-15701-3 (closed-hit arm) via the CLI test: with open search empty and closed search returning #88, submit creates a new issue whose body carries 'Previously reported and closed as #88'.",
|
|
46
46
|
"status": "pending",
|
|
47
47
|
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-3: closed-state hit produces a create with previously reported reference"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "TC-191-submit-fingerprint-mismatch-creates",
|
|
51
|
+
"acId": "AC-15701-2",
|
|
52
|
+
"description": "Cover AC-15701-2 (fingerprint-verification arm, 0.28.2 #234) via the CLI test: a search hit whose body carries a DIFFERENT fingerprint line is a non-match; submit falls through to create rather than comment.",
|
|
53
|
+
"status": "pending",
|
|
54
|
+
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2: a search hit whose body carries a DIFFERENT fingerprint is a non-match; submit creates rather than comments"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "TC-191-submit-anchor-mismatch-creates",
|
|
58
|
+
"acId": "AC-15701-2",
|
|
59
|
+
"description": "Cover AC-15701-2 (refuse fold across differing anchor/target arm, 0.28.2 #234) via the CLI test: a fingerprint match against a candidate whose anchor disagrees is refused; submit creates rather than comments.",
|
|
60
|
+
"status": "pending",
|
|
61
|
+
"testPointer": "test/cli/feedback-submit.test.js::AC-15701-2: a fingerprint match against a candidate whose anchor disagrees is refused; submit creates rather than comments"
|
|
48
62
|
}
|
|
49
63
|
],
|
|
50
64
|
"status": "draft"
|
|
@@ -53,6 +53,15 @@
|
|
|
53
53
|
"then": "the docs URL survives verbatim; the prose 'when the agent stops the queue' survives verbatim; the personal name 'Alice' folds to <operator>; the ledger records an operator-identity row for 'Alice' but no row for 'agent' or 'the'",
|
|
54
54
|
"testable": true,
|
|
55
55
|
"scope": "runtime"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "AC-15601-6",
|
|
59
|
+
"description": "The rule-4 bare-hostname redactor treats filename tokens carrying a known file extension as NOT hostnames. A candidate hostname match whose trailing dot-label is in a bundled FILE_EXTENSIONS set (initially md, mdx, json, yml, yaml, txt, js, mjs, cjs, ts, tsx, html, css, png, svg, sh, csv, log, lock) is left intact and no ledger row is written for it (design amendment R5d). The negative lookbehind on the hostname regex additionally excludes '-' so that filename fragments embedded in a larger identifier (`Backstory-product-brief.md`) cannot start a match after a hyphen. The extension shortlist is merged at call time from an `extensions` array on src/feedback/redact-allowlist.json alongside the existing `hosts` field, so operators can extend it the same way they extend hosts.",
|
|
60
|
+
"given": "a fixture project with a body containing the tokens 'Backstory-product-brief.md', 'intake.json', 'report.log', 'foo.example.com', 'foo.example.com/path', 'Backstory-example.com', and 'a.b.c'",
|
|
61
|
+
"when": "the redactor runs over the body with the default allowlist",
|
|
62
|
+
"then": "'Backstory-product-brief.md', 'intake.json' and 'report.log' survive verbatim with no ledger row for a hostname substitution on their basename; 'foo.example.com' folds to <host> via rule 4; 'foo.example.com/path' folds via the URL rule; 'Backstory-example.com' folds to '<host>' (the trailing label is not in the extension set); 'a.b.c' folds to <host>. Extending the allowlist with `extensions: [\"xyz\"]` in redact-allowlist.json (or the operator overlay) makes 'file.xyz' also survive.",
|
|
63
|
+
"testable": true,
|
|
64
|
+
"scope": "runtime"
|
|
56
65
|
}
|
|
57
66
|
],
|
|
58
67
|
"createdAt": "2026-09-16T13:45:23.000Z",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"id": "AC-15701-2",
|
|
23
|
-
"description": "On submit, per pending entry, gh search issues is called for the destination repo with query \"rcf-feedback-fingerprint: <fp>\", --match body, --state open, --limit 5.
|
|
24
|
-
"given": "a fake gh module (via RCF_FEEDBACK_GH_MODULE) whose
|
|
25
|
-
"when": "rcf feedback submit --yes runs
|
|
26
|
-
"then": "the zero-hit case
|
|
23
|
+
"description": "On submit, per pending entry, gh search issues is called for the destination repo with query \"rcf-feedback-fingerprint: <fp>\", --match body, --state open, --limit 5. For every returned candidate, submit re-reads the candidate issue body via gh issue view --json body (ghIssueGetBody) and folds ONLY if the body contains a line exactly matching \"rcf-feedback-fingerprint: <fp>\" on its own; a search hit whose body does not carry that exact line is a NON-MATCH and is discarded. Anchor and target must also match the entry's anchor and target; folding across a differing anchor or target is refused even when the fingerprint lines are equal. Zero verified hits: gh issue create; the stdout row reports \"created #N (<title>)\". One or more verified hits: gh issue comment on the lowest-numbered verified issue, mention any other verified hits in the comment body, and post the FULL rendered report (title as a \"## Report\" heading, then the redacted body, then evidence and environment tables, then the fingerprint line), labelled as \"Apparent duplicate of the issue subject; posting the full report so a human can judge.\" The retired \"+1 from another reporter.\" payload is never posted. The stdout row on the fold path reports \"commented on #N (fingerprint match: <title>)\" so a wrong match is visible on the same line a human already sees.",
|
|
24
|
+
"given": "a fake gh module (via RCF_FEEDBACK_GH_MODULE) whose ghIssueSearch stub yields zero, one and two hits in three sequential invocations, and one pending entry per case; and a second fixture where ghIssueSearch returns a candidate whose ghIssueGetBody body carries a DIFFERENT fingerprint line to the entry; and a third fixture where the candidate body's fingerprint matches but the candidate's anchor or target field differs from the entry's",
|
|
25
|
+
"when": "rcf feedback submit --yes runs against each fixture",
|
|
26
|
+
"then": "the zero-hit case creates and prints \"created #N (<title>)\"; the one-hit case with a verified fingerprint match comments on the returned number, the comment body carries the full rendered report (title + body + evidence + environment + fingerprint), the string \"+1 from another reporter.\" is absent, and the stdout row prints \"commented on #N (fingerprint match: <title>)\"; the two-hit case comments on the smaller number and mentions the other verified number; the different-fingerprint fixture and the differing-anchor/target fixture both fall through to create rather than comment",
|
|
27
27
|
"testable": true,
|
|
28
28
|
"scope": "runtime"
|
|
29
29
|
},
|
package/releases/releases.yaml
CHANGED
|
@@ -40,8 +40,18 @@
|
|
|
40
40
|
# `npm install rcf-lite`.
|
|
41
41
|
|
|
42
42
|
feedVersion: 1
|
|
43
|
-
latest: "0.28.
|
|
43
|
+
latest: "0.28.2"
|
|
44
44
|
releases:
|
|
45
|
+
- version: "0.28.2"
|
|
46
|
+
date: "2026-09-22"
|
|
47
|
+
breaking: false
|
|
48
|
+
headlines:
|
|
49
|
+
- "rcf-lite 0.28.2 is a batched fix release for the seven defects Barry's WSD-lens dogfood on 0.28.1 surfaced, plus three unreported dry-run gaps folded into the same release. Feedback submit no longer folds unrelated findings into one issue and no longer replaces the report with a +1 stub. Submit re-reads every candidate issue body and folds only on a verified fingerprint match, refusing to fold across differing anchor or target; every fold comment now carries the full report. The redactor also stops rewriting .md filenames as hostnames: a candidate whose trailing dot-label is on a bundled extensions shortlist in redact-allowlist.json is left intact."
|
|
50
|
+
- "The five discover verbs share one schema pass across --dry-run and the write path (intake, preflight, review, ui-baseline init, browser-verify). A preview now reports the same validation error the real run would refuse on, so intake --dry-run --input catches a fidelity enum miss and preflight --dry-run --input catches a kebab-case service id. intake and preflight --help advertise their allowed values."
|
|
51
|
+
- "Three more build defects ride along: discover intake dedupes findings before writing the record so a shared branch that fires on two artefacts lands as one finding, req-baseline sweep --yes now allocates distinct AC ids across a batch on one user story, and the TAD review surface renders dataStores, coreEntities and externalSystems as tables instead of raw JSON.stringify blobs."
|
|
52
|
+
minAgentAction: null
|
|
53
|
+
notesUrl: "https://stravica.ai/docs/rcf/changelog/"
|
|
54
|
+
|
|
45
55
|
- version: "0.28.1"
|
|
46
56
|
date: "2026-09-17"
|
|
47
57
|
breaking: false
|
|
@@ -5,7 +5,7 @@ import { mkdir, rename, unlink, writeFile } from 'node:fs/promises';
|
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
6
|
|
|
7
7
|
import { rcfError } from '#core/errors';
|
|
8
|
-
import { validateDocument } from '#core/store';
|
|
8
|
+
import { buildNextManifest, validateDocument } from '#core/store';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Compute the next `bv-<fbsId>-<n>` id: monotonic per FBS.
|
|
@@ -181,10 +181,14 @@ function stripSeverity(check) {
|
|
|
181
181
|
* @returns {Promise<{ record: object } | import('#core/errors').RcfError>}
|
|
182
182
|
*/
|
|
183
183
|
export async function writeBrowserVerificationRecord({ projectRoot, tree, record, options = {} }) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
nextManifest
|
|
184
|
+
// 0.28.2 (Codex review follow-up on the shared helper): compose via
|
|
185
|
+
// the shared `buildNextManifest` helper so write and dry-run
|
|
186
|
+
// produce the same shape and the same schema pass runs on both.
|
|
187
|
+
const nextManifest = buildNextManifest({
|
|
188
|
+
manifest: tree.manifest ?? {},
|
|
189
|
+
record,
|
|
190
|
+
verb: 'browserVerify',
|
|
191
|
+
});
|
|
188
192
|
|
|
189
193
|
const relPath = 'rcf/manifest.json';
|
|
190
194
|
const validation = validateDocument({ doc: nextManifest, kind: 'manifest', filePath: relPath });
|
|
@@ -20,7 +20,7 @@ import { parseArgs } from 'node:util';
|
|
|
20
20
|
import process from 'node:process';
|
|
21
21
|
import { isAbsolute, resolve } from 'node:path';
|
|
22
22
|
|
|
23
|
-
import { walkTree } from '#core/store';
|
|
23
|
+
import { walkTree, validateComposedRecord } from '#core/store';
|
|
24
24
|
import { writeUnexpectedFailure, rcfError } from '#core/errors';
|
|
25
25
|
|
|
26
26
|
import { findProjectRoot } from '../view/index.js';
|
|
@@ -270,6 +270,14 @@ export async function main(argv, deps = {}) {
|
|
|
270
270
|
if (flags.json) stdout.write(`${JSON.stringify(record, null, 2)}\n`);
|
|
271
271
|
|
|
272
272
|
if (flags['dry-run']) {
|
|
273
|
+
// 0.28.2 (folded into #230): dry-run runs the same schema pass
|
|
274
|
+
// the writer runs so a preview reports the same validation error
|
|
275
|
+
// the write path would refuse.
|
|
276
|
+
const dryValidation = validateComposedRecord({ tree, record, verb: 'browserVerify' });
|
|
277
|
+
if (dryValidation) {
|
|
278
|
+
stderr.write(`[error] ${dryValidation.kind} ${dryValidation.message}\n`);
|
|
279
|
+
return 3;
|
|
280
|
+
}
|
|
273
281
|
if (!flags.quiet) {
|
|
274
282
|
renderSummary({ stdout, record });
|
|
275
283
|
}
|