@stravica-ai/rcf-schemas 0.7.0 → 0.8.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 (20) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/fixtures/invalid/user-story/us-009-ac-probe-unknown-property.json +24 -0
  3. package/fixtures/invalid/user-story/us-010-ac-probe-expect-body-both.json +27 -0
  4. package/fixtures/invalid/user-story/us-011-ac-probe-expect-status-600.json +24 -0
  5. package/fixtures/invalid/user-story/us-012-ac-probe-expect-header-missing-match.json +26 -0
  6. package/fixtures/invalid/user-story/us-013-ac-probe-missing-path.json +24 -0
  7. package/fixtures/invalid/user-story/us-014-ac-probe-expect-body-contains-whitespace.json +26 -0
  8. package/fixtures/invalid/user-story/us-015-ac-probe-expect-body-matches-whitespace.json +26 -0
  9. package/fixtures/invalid/user-story/us-016-ac-probe-expect-header-name-whitespace.json +27 -0
  10. package/fixtures/invalid/user-story/us-017-ac-probe-expect-header-match-whitespace.json +27 -0
  11. package/fixtures/invalid/user-story/us-018-ac-probe-selector-whitespace.json +24 -0
  12. package/fixtures/valid/user-story/us-007-ac-probe-minimal.json +24 -0
  13. package/fixtures/valid/user-story/us-008-ac-probe-full.json +39 -0
  14. package/fixtures/valid/user-story/us-009-ac-probe-expect-body-contains.json +27 -0
  15. package/fixtures/valid/user-story/us-010-ac-probe-expect-body-matches.json +26 -0
  16. package/fixtures/valid/user-story/us-011-ac-probe-expect-header-name.json +27 -0
  17. package/fixtures/valid/user-story/us-012-ac-probe-expect-header-match.json +27 -0
  18. package/fixtures/valid/user-story/us-013-ac-probe-selector.json +24 -0
  19. package/package.json +1 -1
  20. package/schemas/user-story.schema.json +79 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,63 @@ All notable changes to `@stravica-ai/rcf-schemas` are documented in this file.
4
4
 
5
5
  The format roughly follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-1.0 breaking changes are signalled by a minor bump per semver 0.x convention.
6
6
 
7
+ ## 0.8.0 - 2026-10-16
8
+
9
+ Minor release for rcf-lite FBS-218 (per-AC probe catalog, rcf-lite PR 370), review gate 3. A probe `{ "path": "/", "expectBody": { "contains": " " } }` validated under 0.7.1, because `minLength: 1` counts a single space, and a deterministic verify run resolved it to a vacuous pass. Every assertion string on the probe must now contain at least one non-whitespace character: `"pattern": "\\S"` alongside the existing `minLength: 1`.
10
+
11
+ Semver: URLs pinned at `v0.6.0`. This is a narrowing, not an addition: a user story whose probe carries a whitespace-only assertion string validated under 0.7.1 and is rejected under 0.8.0. Under this repo's rule (`CONTRIBUTING.md` and the `README.md` Versioning section) a narrowing is a minor bump, as 0.5.0 did for the `testPointer` `minLength: 1` tightening, so this ships as `0.8.0`. The only documents rejected are ones whose assertion string asserts nothing, which is the defect this release closes; rcf-lite pins the package exact and bumps on its FBS-218 branch.
12
+
13
+ ### Added
14
+
15
+ - **Fixtures (valid)**: `fixtures/valid/user-story/us-009-ac-probe-expect-body-contains.json` (`contains: "Welcome back"`), `fixtures/valid/user-story/us-010-ac-probe-expect-body-matches.json` (`matches` with a `\s*` class), `fixtures/valid/user-story/us-011-ac-probe-expect-header-name.json` (`name: "x-request-id"`), `fixtures/valid/user-story/us-012-ac-probe-expect-header-match.json` (`match: "public, max-age=60"`), `fixtures/valid/user-story/us-013-ac-probe-selector.json` (`selector` with a descendant combinator).
16
+ - **Fixtures (invalid)**: `fixtures/invalid/user-story/us-014-ac-probe-expect-body-contains-whitespace.json` (a single space, the gate 3 case), `fixtures/invalid/user-story/us-015-ac-probe-expect-body-matches-whitespace.json` (a tab), `fixtures/invalid/user-story/us-016-ac-probe-expect-header-name-whitespace.json` (two spaces), `fixtures/invalid/user-story/us-017-ac-probe-expect-header-match-whitespace.json` (a newline), `fixtures/invalid/user-story/us-018-ac-probe-selector-whitespace.json` (space, tab, space). Each fails on exactly one ajv error (`pattern`), and each validates under 0.7.1, so it exercises the new constraint alone.
17
+ - **Tests**: `test/user-story.test.js` gains 31 cases: the gate 3 regression probe; for each of the five fields, a whitespace-only value rejected on `pattern` across ten ASCII and Unicode whitespace strings, a real value accepted with inner, leading and trailing whitespace, a one-character value accepted (the `minLength: 1` boundary), and an empty string still rejected on `minLength`; and one case per new fixture, pinning its outcome and, for the invalid ones, the single `pattern` error at its instance path. Total suite grows from 402 to 433.
18
+
19
+ ### Changed
20
+
21
+ - **`user-story.schema.json`**: `$defs.acProbeExpectBody.contains`, `$defs.acProbeExpectBody.matches`, `$defs.acProbeExpectHeader.name`, `$defs.acProbeExpectHeader.match` and `$defs.acProbe.selector` each gain `"pattern": "\\S"` next to `minLength: 1`, and each `description` says so. The pattern is unanchored, so a real value with leading, trailing or inner whitespace still validates. ajv compiles patterns with the `u` flag, so `\S` also treats Unicode whitespace (no-break space, em space, byte-order mark, line separator) as whitespace.
22
+ - **Unchanged on purpose**: `$defs.acProbe.path` and `$defs.acProbe.parityEnv` keep `minLength: 1` only. They name the request target and the environment scope, not something the resolver checks the response against, so they sit outside this fix. `method` (enum), `expectStatus` (integer, 100..599), the `expectBody` exactly-one-of rule and every other def are untouched.
23
+
24
+ ### Migration
25
+
26
+ - **Existing chains on 0.7.1**: bump `@stravica-ai/rcf-schemas` to `0.8.0`. A document is rejected only when a probe carries a whitespace-only `expectBody.contains`, `expectBody.matches`, `expectHeader.name`, `expectHeader.match` or `selector`. Replace the value with the text the criterion actually asserts, or remove that assertion.
27
+ - **Consumers to bump**: `rcf-lite` (its `packages/rcf-lite/package.json` pins the schemas package exact, at `0.7.0` on `main` at this release). FBS-218 validates every probe against `$defs.acProbe`, so pinning `0.8.0` closes the whitespace-only case there without resolver-side trimming. This repo does not touch rcf-lite.
28
+
29
+ ### Notes
30
+
31
+ - Scripted back-compat pass at authoring time: every 0.7.1 fixture at main `c34bf96` (67 valid + 95 invalid = 162 total) validates to the same outcome, with the same ajv error list, against the 0.8.0 schemas: zero drift.
32
+ - Mutation check at authoring time: run against the 0.7.1 `user-story.schema.json`, the 11 new rejection cases fail, as does the existing invalid-fixture case for `user-story`; the 20 new acceptance and `minLength` cases pass on both.
33
+ - `docs/user-story.md` still does not describe `probe` (deferred at 0.7.1); this release is scoped to the schema, fixtures, tests, version and changelog.
34
+ - `back-compat-freeze.test.js` continues to pass.
35
+
36
+ ## 0.7.1 - 2026-10-16
37
+
38
+ Patch bump for rcf-lite issue 349 (per-AC probe catalog resolved by deterministic verify, rcf-lite TAC-4150 and FBS-218). Adds an additive, optional `probe` object on the inline `$defs.acceptanceCriterion` of the user story, so an acceptance criterion can carry a structured, deterministic probe that `rcf verify run --mode deterministic` resolves to pass, fail or skipped with evidence. An AC without a probe stays critique-only. Every change is additive: every 0.7.0-valid document keeps validating.
39
+
40
+ Patch semver convention: URLs pinned at `v0.6.0`. No breaking change; every 0.7.0-valid document keeps validating. rcf-lite TAC-4150 calls this change "the rcf-schemas minor"; under this repo's rule (`CONTRIBUTING.md` and the `README.md` Versioning section: additive changes are a patch bump, breaking changes a minor) an optional property on a closed object is additive, the same call 0.6.2 made for `ownerRef`, `disposition` and `vendorCitation` on the same record, so the release is `0.7.1`.
41
+
42
+ ### Added
43
+
44
+ - **`user-story.schema.json`**: new optional `probe` on the inline `$defs.acceptanceCriterion`, `$defs.acProbe`. Object, `additionalProperties: false`, only `path` required. Fields: `method` (string enum `GET | HEAD | POST | PUT | PATCH | DELETE | OPTIONS`; absence means GET, documented in the `description` rather than a JSON Schema `default`, since no schema in this repo uses `default`), `path` (min-length-1 string, a URL path relative to the run's `--url`), `expectStatus` (integer, 100..599), `expectHeader` (`$defs.acProbeExpectHeader`), `expectBody` (`$defs.acProbeExpectBody`), `selector` (min-length-1 string, a DOM selector that must be present), `parityEnv` (min-length-1 string, paired by the resolver with `rcf verify run --parity-env`). Shape follows the Probe record in rcf-lite TAC-4150.
45
+ - **`user-story.schema.json`**: new `$defs.acProbeExpectHeader`. Object with required `name` and `match` (both min-length-1 strings), `additionalProperties: false`. Match semantics belong to the consuming resolver; the schema constrains shape only.
46
+ - **`user-story.schema.json`**: new `$defs.acProbeExpectBody`. Object with optional `contains` (min-length-1 string, literal text) and `matches` (min-length-1 string, a regular expression source), `additionalProperties: false`, `minProperties: 1` and `maxProperties: 1`, so exactly one of the two is present.
47
+ - **Fixtures (valid)**: `fixtures/valid/user-story/us-007-ac-probe-minimal.json` (a probe with only `path`), `fixtures/valid/user-story/us-008-ac-probe-full.json` (a probe carrying every field, `expectBody.matches`).
48
+ - **Fixtures (invalid)**: `fixtures/invalid/user-story/us-009-ac-probe-unknown-property.json` (unknown `timeoutMs` on the probe), `fixtures/invalid/user-story/us-010-ac-probe-expect-body-both.json` (`expectBody` with both `contains` and `matches`), `fixtures/invalid/user-story/us-011-ac-probe-expect-status-600.json` (`expectStatus` 600), `fixtures/invalid/user-story/us-012-ac-probe-expect-header-missing-match.json` (`expectHeader` without `match`), `fixtures/invalid/user-story/us-013-ac-probe-missing-path.json` (probe without the required `path`). Each fails on exactly one ajv error.
49
+ - **Tests**: `test/user-story.test.js` gains 23 cases for `probe` (back-compat absent, minimal path-only, full shape, `expectBody.contains`, every method enum value, lowercase method rejected, missing and empty `path` rejected, unknown probe property rejected, bare-string probe rejected, `expectBody` with both, neither, an unknown property or an empty `contains` rejected, `expectStatus` 600, 99, 200.5 and "200" rejected, bounds 100 and 599 accepted, `expectHeader` missing `match`, missing `name` or carrying an unknown property rejected, empty `selector` and empty `parityEnv` rejected, probe alongside `scope`, `determinism`, `ownerRef`, `disposition` and `provenance`). Total suite grows from 379 to 402.
50
+
51
+ ### Migration
52
+
53
+ - **Existing chains on 0.7.0**: bump `@stravica-ai/rcf-schemas` to `0.7.1`. Every existing document keeps validating; `probe` is optional and unknown to pre-0.7.1 callers.
54
+ - **To adopt a probe on an AC**: add `probe: { path }` plus whichever expectations the criterion needs (`expectStatus`, `expectHeader`, `expectBody`, `selector`, `parityEnv`). An AC with no probe stays critique-only; the rcf-lite catalog file `rcf/verify-catalog.json` remains an alternative carrier, and an AC-level probe wins over a catalog entry (rcf-lite TAC-4150).
55
+ - **Consumers to bump**: `rcf-lite` (its `packages/rcf-lite/package.json` pins the schemas package exact, at `0.7.0` on `main` at this release). The pin bump to `0.7.1` is FBS-218's job: the build spec cannot merge until the pin lands. This repo does not touch rcf-lite.
56
+
57
+ ### Notes
58
+
59
+ - `expectBody` uses `minProperties` / `maxProperties` on a closed object rather than a `oneOf` of `required` arms: ajv strict mode (`strictRequired`, which this repo's test loader runs under) refuses a `required` keyword in an arm that does not declare the property locally, and the closed-object count expresses "exactly one of `contains` or `matches`" in one place with a direct error message.
60
+ - Scripted back-compat pass at authoring time: every 0.7.0 fixture at main `e721930` (65 valid + 90 invalid = 155 total) validates to the same outcome against the 0.7.1 schemas with zero drift.
61
+ - `docs/user-story.md` does not yet describe `probe`; this release was scoped to the schema, fixtures, tests, version and changelog, and the doc page catches up in a follow-up.
62
+ - `back-compat-freeze.test.js` continues to pass.
63
+
7
64
  ## 0.7.0 - 2026-10-11
8
65
 
9
66
  Minor bump for the discovery-UX gate: adds an optional `journeyStepIds[]` carrier on the FBS schema and a new `journeyStub` review-finding kind on `reviewAudit[].testTheatreFindings[].kind`. Both additions are additive at the shape level; every 0.6.3-valid document keeps validating. The bump is a minor (not a patch) because the review-kind enum is a shared vocabulary and the enum extension is a vocabulary change consumers may want to switch on, following the project's pre-1.0 convention. Canonical `$id` URLs are kept at `v0.6.0` on this release: no schema's `$id` or cross-file `$ref` changes, so every validator keyed to the `v0.6.0` URLs picks up the additions by file bytes alone. Rolling the URLs to `v0.7.0` is deferred to HQ at publish time if the convention calls for it.
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe with an unknown property is rejected",
8
+ "asA": "author",
9
+ "iWant": "the probe object to stay closed",
10
+ "soThat": "a typo in a probe field is a validation error, not a silent no-op",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "Probe carries an unknown timeoutMs field.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/healthz",
18
+ "timeoutMs": 500
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectBody with both contains and matches is rejected",
8
+ "asA": "author",
9
+ "iWant": "expectBody to carry exactly one assertion",
10
+ "soThat": "the resolver never has to pick between two body checks",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "expectBody carries both contains and matches.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/api/notes",
18
+ "expectBody": {
19
+ "contains": "notes",
20
+ "matches": "^\\{"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectStatus outside 100..599 is rejected",
8
+ "asA": "author",
9
+ "iWant": "expectStatus to be a real HTTP status code",
10
+ "soThat": "a typo in the expected status is caught at authoring time",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "expectStatus is 600.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/healthz",
18
+ "expectStatus": 600
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectHeader without match is rejected",
8
+ "asA": "author",
9
+ "iWant": "a header assertion to name both the header and the value",
10
+ "soThat": "a header probe always asserts something",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "expectHeader names the header but omits match.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/healthz",
18
+ "expectHeader": {
19
+ "name": "content-type"
20
+ }
21
+ }
22
+ }
23
+ ],
24
+ "createdAt": "2026-01-01T00:00:00Z",
25
+ "updatedAt": "2026-10-16T00:00:00Z"
26
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe without path is rejected",
8
+ "asA": "author",
9
+ "iWant": "every probe to name the path it requests",
10
+ "soThat": "the resolver always knows what to fetch",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "Probe omits the required path.",
15
+ "testable": true,
16
+ "probe": {
17
+ "method": "GET",
18
+ "expectStatus": 200
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectBody.contains as a single space is rejected",
8
+ "asA": "author",
9
+ "iWant": "a body assertion that asserts something",
10
+ "soThat": "a whitespace-only contains cannot resolve to a vacuous pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "expectBody.contains is a single space.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectBody": {
19
+ "contains": " "
20
+ }
21
+ }
22
+ }
23
+ ],
24
+ "createdAt": "2026-01-01T00:00:00Z",
25
+ "updatedAt": "2026-10-16T00:00:00Z"
26
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectBody.matches as a tab is rejected",
8
+ "asA": "author",
9
+ "iWant": "a body pattern that asserts something",
10
+ "soThat": "a whitespace-only regular expression source cannot resolve to a vacuous pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "expectBody.matches is a single tab.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectBody": {
19
+ "matches": "\t"
20
+ }
21
+ }
22
+ }
23
+ ],
24
+ "createdAt": "2026-01-01T00:00:00Z",
25
+ "updatedAt": "2026-10-16T00:00:00Z"
26
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectHeader.name as two spaces is rejected",
8
+ "asA": "author",
9
+ "iWant": "a header assertion keyed on a real header name",
10
+ "soThat": "a whitespace-only header name cannot resolve to a vacuous pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "expectHeader.name is two spaces.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectHeader": {
19
+ "name": " ",
20
+ "match": "application/json"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe expectHeader.match as a newline is rejected",
8
+ "asA": "author",
9
+ "iWant": "a header assertion with a real expected value",
10
+ "soThat": "a whitespace-only header value cannot resolve to a vacuous pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "expectHeader.match is a single newline.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectHeader": {
19
+ "name": "content-type",
20
+ "match": "\n"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "draft",
7
+ "title": "Probe selector as mixed whitespace is rejected",
8
+ "asA": "author",
9
+ "iWant": "a DOM assertion on a real selector",
10
+ "soThat": "a whitespace-only selector cannot resolve to a vacuous pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "selector is a space, a tab and a space.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "selector": " \t "
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Health endpoint answers on the deployed URL",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "an acceptance criterion to carry the smallest possible probe",
10
+ "soThat": "rcf verify run resolves it without a critique pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "The health endpoint answers on the deployed URL.",
15
+ "testable": true,
16
+ "scope": "deployed",
17
+ "probe": {
18
+ "path": "/healthz"
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "usId": "US-301",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-301",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Notes API returns JSON and the notes list renders",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "an acceptance criterion to carry a probe exercising every field",
10
+ "soThat": "rcf verify run resolves status, header, body, selector and environment in one pass",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-301-1",
14
+ "description": "Listing notes returns a JSON notes array, and the notes page renders its list.",
15
+ "testable": true,
16
+ "given": "a deployed notes service",
17
+ "when": "the client lists notes",
18
+ "then": "the response is JSON and the list renders",
19
+ "scope": "deployed",
20
+ "determinism": "deterministic",
21
+ "probe": {
22
+ "method": "GET",
23
+ "path": "/api/notes?limit=1",
24
+ "expectStatus": 200,
25
+ "expectHeader": {
26
+ "name": "content-type",
27
+ "match": "application/json"
28
+ },
29
+ "expectBody": {
30
+ "matches": "^\\{\"notes\":\\["
31
+ },
32
+ "selector": "[data-testid=\"notes-list\"]",
33
+ "parityEnv": "preview"
34
+ }
35
+ }
36
+ ],
37
+ "createdAt": "2026-01-01T00:00:00Z",
38
+ "updatedAt": "2026-10-16T00:00:00Z"
39
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Probe expectBody.contains carries real text with inner whitespace",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "a body assertion on literal text that includes spaces",
10
+ "soThat": "a real phrase passes while a whitespace-only string is refused",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "The home page greets the signed-in user.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectStatus": 200,
19
+ "expectBody": {
20
+ "contains": "Welcome back"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Probe expectBody.matches carries a real regular expression",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "a body assertion on a pattern that includes a whitespace class",
10
+ "soThat": "a real pattern passes while a whitespace-only source is refused",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "The notes page renders its heading.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/notes",
18
+ "expectBody": {
19
+ "matches": "<h1>\\s*Notes\\s*</h1>"
20
+ }
21
+ }
22
+ }
23
+ ],
24
+ "createdAt": "2026-01-01T00:00:00Z",
25
+ "updatedAt": "2026-10-16T00:00:00Z"
26
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Probe expectHeader.name carries a real header name",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "a header assertion keyed on a named response header",
10
+ "soThat": "a real header name passes while a whitespace-only name is refused",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "The health endpoint carries a request id header.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/healthz",
18
+ "expectHeader": {
19
+ "name": "x-request-id",
20
+ "match": "^[0-9a-f-]{36}$"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Probe expectHeader.match carries a real value with inner whitespace",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "a header assertion whose expected value includes a space",
10
+ "soThat": "a real header value passes while a whitespace-only value is refused",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "The public page is cacheable for a minute.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/",
18
+ "expectHeader": {
19
+ "name": "cache-control",
20
+ "match": "public, max-age=60"
21
+ }
22
+ }
23
+ }
24
+ ],
25
+ "createdAt": "2026-01-01T00:00:00Z",
26
+ "updatedAt": "2026-10-16T00:00:00Z"
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "usId": "US-302",
3
+ "prdId": "PRD-100",
4
+ "reqId": "REQ-302",
5
+ "version": "1.0.0",
6
+ "status": "approved",
7
+ "title": "Probe selector carries a real descendant selector",
8
+ "asA": "operator running deterministic verify",
9
+ "iWant": "a DOM assertion with a descendant combinator",
10
+ "soThat": "a real selector passes while a whitespace-only selector is refused",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-302-1",
14
+ "description": "The notes list renders inside the main landmark.",
15
+ "testable": true,
16
+ "probe": {
17
+ "path": "/notes",
18
+ "selector": "main [data-testid=\"notes-list\"]"
19
+ }
20
+ }
21
+ ],
22
+ "createdAt": "2026-01-01T00:00:00Z",
23
+ "updatedAt": "2026-10-16T00:00:00Z"
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stravica-ai/rcf-schemas",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "description": "JSON Schemas for the Requirements Confidence Framework (RCF). Language-neutral. The contract every RCF tool keys to.",
6
6
  "license": "Apache-2.0",
@@ -71,6 +71,7 @@
71
71
  "ownerRef": { "$ref": "#/$defs/acOwnerRef" },
72
72
  "disposition": { "$ref": "#/$defs/acDisposition" },
73
73
  "vendorCitation": { "$ref": "#/$defs/acVendorCitation" },
74
+ "probe": { "$ref": "#/$defs/acProbe" },
74
75
  "provenance": { "$ref": "#/$defs/acProvenance" }
75
76
  }
76
77
  },
@@ -111,6 +112,84 @@
111
112
  },
112
113
  "description": "Vendor citation for an acceptance criterion whose truth rests on a third-party platform fact. Optional at schema level; consumer rulesets may require it on any AC that asserts a vendor fact (for example, a platform migration keyword or a rate-limit value)."
113
114
  },
115
+ "acProbe": {
116
+ "type": "object",
117
+ "additionalProperties": false,
118
+ "required": ["path"],
119
+ "properties": {
120
+ "method": {
121
+ "type": "string",
122
+ "enum": ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
123
+ "description": "HTTP method of the probe request. Optional; absence means GET."
124
+ },
125
+ "path": {
126
+ "type": "string",
127
+ "minLength": 1,
128
+ "description": "URL path the probe requests, relative to the run's --url (for example /healthz or /api/notes?limit=1). The only required field."
129
+ },
130
+ "expectStatus": {
131
+ "type": "integer",
132
+ "minimum": 100,
133
+ "maximum": 599,
134
+ "description": "HTTP status code the response must carry."
135
+ },
136
+ "expectHeader": { "$ref": "#/$defs/acProbeExpectHeader" },
137
+ "expectBody": { "$ref": "#/$defs/acProbeExpectBody" },
138
+ "selector": {
139
+ "type": "string",
140
+ "minLength": 1,
141
+ "pattern": "\\S",
142
+ "description": "DOM selector that must be present in the rendered response. At least one non-whitespace character is required."
143
+ },
144
+ "parityEnv": {
145
+ "type": "string",
146
+ "minLength": 1,
147
+ "description": "Target environment the probe is scoped to; the consuming resolver pairs it with rcf verify run --parity-env."
148
+ }
149
+ },
150
+ "description": "Deterministic per-AC probe resolved by rcf verify run (rcf-lite issue 349). Absent means the criterion stays critique-only. Shape follows the Probe record in rcf-lite TAC-4150; the schema constrains shape only and the resolution semantics belong to the consumer."
151
+ },
152
+ "acProbeExpectHeader": {
153
+ "type": "object",
154
+ "additionalProperties": false,
155
+ "required": ["name", "match"],
156
+ "properties": {
157
+ "name": {
158
+ "type": "string",
159
+ "minLength": 1,
160
+ "pattern": "\\S",
161
+ "description": "Response header name. At least one non-whitespace character is required."
162
+ },
163
+ "match": {
164
+ "type": "string",
165
+ "minLength": 1,
166
+ "pattern": "\\S",
167
+ "description": "Value the named header must match. Match semantics belong to the consuming resolver. At least one non-whitespace character is required."
168
+ }
169
+ },
170
+ "description": "Response header assertion on an acceptance-criterion probe. Both name and match are required."
171
+ },
172
+ "acProbeExpectBody": {
173
+ "type": "object",
174
+ "additionalProperties": false,
175
+ "properties": {
176
+ "contains": {
177
+ "type": "string",
178
+ "minLength": 1,
179
+ "pattern": "\\S",
180
+ "description": "Literal text the response body must contain. At least one non-whitespace character is required."
181
+ },
182
+ "matches": {
183
+ "type": "string",
184
+ "minLength": 1,
185
+ "pattern": "\\S",
186
+ "description": "Regular expression source the response body must match. At least one non-whitespace character is required."
187
+ }
188
+ },
189
+ "minProperties": 1,
190
+ "maxProperties": 1,
191
+ "description": "Response body assertion on an acceptance-criterion probe. Exactly one of contains or matches: the object is closed to those two properties and carries exactly one of them."
192
+ },
114
193
  "acProvenance": {
115
194
  "type": "object",
116
195
  "additionalProperties": false,