@stravica-ai/rcf-schemas 0.4.3 → 0.4.5

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 (25) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/docs/id-conventions.md +16 -0
  3. package/fixtures/invalid/fbs/fbs-013-standard-ids-non-slug.json +16 -0
  4. package/fixtures/invalid/manifest/manifest-018-blueprint-bad-slug.json +15 -0
  5. package/fixtures/invalid/manifest/manifest-019-standards-bad-id.json +17 -0
  6. package/fixtures/invalid/manifest/manifest-020-resolution-bad-id.json +20 -0
  7. package/fixtures/invalid/manifest/manifest-021-resolution-single-supersedes.json +19 -0
  8. package/fixtures/invalid/req/req-005-slug-prefix-uppercase.json +13 -0
  9. package/fixtures/invalid/user-story/us-005-slug-prefix-trailing-hyphen.json +20 -0
  10. package/fixtures/valid/build-sequence/bs-002-slug-prefix.json +8 -0
  11. package/fixtures/valid/fbs/fbs-007-standard-ids.json +18 -0
  12. package/fixtures/valid/manifest/manifest-008-blueprints-registered.json +32 -0
  13. package/fixtures/valid/manifest/manifest-009-standards-in-repo.json +18 -0
  14. package/fixtures/valid/manifest/manifest-010-standards-copied-in.json +26 -0
  15. package/fixtures/valid/manifest/manifest-011-preblueprint-chain-frozen.json +8 -0
  16. package/fixtures/valid/manifest/manifest-012-blueprint-topic-resolution.json +41 -0
  17. package/fixtures/valid/prd/prd-002-slug-prefix.json +12 -0
  18. package/fixtures/valid/req/req-002-slug-prefix.json +13 -0
  19. package/fixtures/valid/tad/tad-002-slug-prefix.json +14 -0
  20. package/fixtures/valid/test-suite/ts-005-slug-prefix.json +19 -0
  21. package/fixtures/valid/user-story/us-005-slug-prefix.json +20 -0
  22. package/package.json +6 -6
  23. package/schemas/common.schema.json +23 -13
  24. package/schemas/fbs.schema.json +6 -1
  25. package/schemas/manifest.schema.json +165 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,50 @@ 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.4.5 - 2026-08-19
8
+
9
+ Additive patch bump for the blueprint conflict-resolution mechanism landing in `rcf-lite` Phase 3.5. Adds the schema seam the `rcf blueprint supersede` and `rcf blueprint add --resolve` verbs key to, so a project can record an operator ruling that resolves a cross-blueprint conflict on a scope:global ADR topic. Every change is additive: every 0.4.4-valid document remains valid, and every existing id continues to validate byte-for-byte.
10
+
11
+ ### Added
12
+
13
+ - **`manifest.schema.json`**: new optional `resolutions[]` at top level, items `$defs.blueprintConflictResolution`. One entry per operator-authored resolution of a cross-blueprint conflict. Fields: `id` (`^res-YYYY-MM-DD-NNN$`), `createdAt`, `kind` (single-valued enum `globalAdrTopic`; the enum is deliberately single-valued so later minor bumps can add further resolution classes additively without breaking existing consumers), `topic` (the topic key the resolution applies to, matching both superseded blueprint ADRs), `resolvedByAdrId` (the project-level ADR id that supersedes the blueprint ADRs), `supersedes[]` (min 2 items, each `{ slug: blueprintSlug, adrId: string }`), and optional `reason` (operator note). Written by `rcf blueprint supersede` and `rcf blueprint add --resolve`; read by the conflict detector so a would-be conflict on a resolved topic is honoured and both blueprint ADRs may co-reside as superseded history.
14
+ - Fixtures (valid): `fixtures/valid/manifest/manifest-012-blueprint-topic-resolution.json` (two applied blueprints whose global auth ADRs collide, resolved by a project-level ADR that supersedes both).
15
+ - Fixtures (invalid): `fixtures/invalid/manifest/manifest-020-resolution-bad-id.json` (resolution id in the wrong shape), `fixtures/invalid/manifest/manifest-021-resolution-single-supersedes.json` (supersedes[] with a single entry, violating minItems 2).
16
+ - Tests: `resolutions[]` cases added to `manifest.test.js` covering the happy path (required fields, with reason, three superseded ADRs, additive composition alongside `blueprints[]` and `standards[]`), the reject-cases (bad id shape, missing required fields, unknown kind, `supersedes[]` minItems 2, uppercase slug in a `supersedes[]` entry, missing `adrId`, and an unrecognised additional property under `additionalProperties: false`), plus a pre-0.4.5 back-compat case that keeps a `blueprints[]`+`standards[]` manifest with no `resolutions[]` valid.
17
+
18
+ ### Notes
19
+
20
+ - Additive-only: every 0.4.4-valid document remains valid. The prior `blueprints[]` + `standards[]` shape is untouched.
21
+ - `back-compat-freeze.test.js` (added in 0.4.4) continues to assert the frozen pre-0.4.3 chain snapshot validates byte-for-byte; the 0.4.5 additions are new-fields-only and cannot affect existing document bytes.
22
+ - Canonical `$id` URLs stay at `v0.4.0`, following the patch-release precedent set at 0.2.1, 0.3.1, 0.4.1, 0.4.2, 0.4.3, and 0.4.4.
23
+ - Version choice: additive change, no existing document invalidated, no shape widened destructively — per repo precedent this bumps `0.4.4 -> 0.4.5` as a patch.
24
+
25
+ ## 0.4.4 - 2026-08-18
26
+
27
+ Additive patch bump for the blueprint-library mechanism landing in `rcf-build-lite`. Unblocks Phase 1 of the blueprint programme (`w-2026-08-18-016`) by adding the schema seams the mechanism keys to. Every change is additive: every 0.4.3-valid document remains valid, and every existing id continues to validate byte-for-byte.
28
+
29
+ ### Added
30
+
31
+ - **`common.schema.json`**: new `$defs.blueprintSlug` and `$defs.standardSlug`, both `^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$`. Shared shape for blueprint and standards-pack slugs; referenced from `manifest.blueprints[]`, `manifest.standards[]`, and `fbs.contextRequirements.standardIds`.
32
+ - **`manifest.schema.json`**: new optional `blueprints[]` at top level, items `$defs.appliedBlueprintRecord` (slug, version, appliedAt, source, optional namespace, optional contributions[] listing every doc id + path the blueprint contributed). Written by the `rcf blueprint` verb family (`add` on clean apply, `upgrade` on re-apply, `remove` deletes the entry). Composition (multiple applied blueprints) is expressed by multiple entries.
33
+ - **`manifest.schema.json`**: new optional `standards[]` at top level, items `$defs.standardsPackRecord` (id `^std-<slug>$`, slug, sourcePath, optional copyPath, tags[], optional summary, `testsProvidedBy` = `standard | agent | none`, `provenance` = `personal | corporate`). Records standards-pack registrations from `rcf init` and `rcf standards add`. `copyPath` is present only when the source lived outside the project root at registration time.
34
+ - **`fbs.schema.json`**: new optional `contextRequirements.standardIds[]`, items reference `common.standardSlug`. Host for the bundle assembler's agentic selective-retrieval step; an operator-authored value overrides the agentic selection.
35
+ - Fixtures (valid): `fixtures/valid/manifest/manifest-008-blueprints-registered.json` (two applied blueprints, one with contributions[]), `fixtures/valid/manifest/manifest-009-standards-in-repo.json` (in-repo standards pack, no copyPath), `fixtures/valid/manifest/manifest-010-standards-copied-in.json` (out-of-root pack with copyPath), `fixtures/valid/fbs/fbs-007-standard-ids.json` (FBS with agentically-populated standardIds), `fixtures/valid/req/req-002-slug-prefix.json`, `fixtures/valid/user-story/us-005-slug-prefix.json`, `fixtures/valid/prd/prd-002-slug-prefix.json`, `fixtures/valid/build-sequence/bs-002-slug-prefix.json`, `fixtures/valid/tad/tad-002-slug-prefix.json`, `fixtures/valid/test-suite/ts-005-slug-prefix.json`, plus `fixtures/valid/manifest/manifest-011-preblueprint-chain-frozen.json` (frozen pre-0.4.3 chain snapshot used by the byte-for-byte back-compat test).
36
+ - Fixtures (invalid): `fixtures/invalid/manifest/manifest-018-blueprint-bad-slug.json`, `fixtures/invalid/manifest/manifest-019-standards-bad-id.json`, `fixtures/invalid/fbs/fbs-013-standard-ids-non-slug.json`, `fixtures/invalid/req/req-003-slug-prefix-uppercase.json`, `fixtures/invalid/user-story/us-005-slug-prefix-trailing-hyphen.json`.
37
+ - Tests: prefix-id cases added to `req.test.js`, `user-story.test.js`, `prd.test.js`, `build-sequence.test.js`, `tad.test.js`, `test-suite.test.js`; blueprints[] and standards[] cases added to `manifest.test.js`; contextRequirements.standardIds cases added to `fbs.test.js`; new `back-compat-freeze.test.js` asserts the frozen pre-0.4.3 chain snapshot validates byte-for-byte (sha256 pin).
38
+
39
+ ### Changed
40
+
41
+ - **`common.schema.json`**: `prdId`, `reqId`, `usId`, `bsId`, `tadId`, `tsId` patterns widened to accept an optional lowercase kebab-slug prefix, `^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?<PREFIX>-\d{3,}$`. Numeric-only ids continue to validate unchanged. Slug prefixes are well-formed kebab (leading letter, lowercase alnum segments joined by single hyphens; leading, trailing, and double hyphens are rejected).
42
+
43
+ ### Notes
44
+
45
+ - Additive-only: every 0.4.3-valid document remains valid byte-for-byte. `back-compat-freeze.test.js` proves this with a hash-pinned fixture read as raw bytes.
46
+ - Id grammar is now mixed across types: **prefix** for REQ/US/PRD/BS/TAD/TS (this bump), **suffix** for ADR/TAC/FBS/CN (already the shape from 0.4.3). This is a minimal-delta choice tonight to unblock the blueprint mechanism without churning the four types whose suffix affordance already namespaces them. Unifying the grammar is a schemas follow-up; the mixed grammar is documented and the working tools accept both.
47
+ - The `acId` and `tcId` patterns are intentionally left unchanged. AC/TC ids are anchored to their parent US/TS chain, whose ids now carry the slug prefix; adding a redundant prefix on ACs and TCs was out of scope for tonight and adds no expressiveness.
48
+ - Canonical `$id` URLs stay at `v0.4.0`, following the patch-release precedent set at 0.2.1, 0.3.1, 0.4.1, 0.4.2, and 0.4.3.
49
+ - Version choice: per repo precedent (every prior additive change since 0.2.0 has bumped as a **patch**: 0.2.1, 0.3.1, 0.4.1, 0.4.2, 0.4.3), this bumps `0.4.3 -> 0.4.4`. Dave's Path A brief allowed for a minor bump if the repo convention read pattern-widening as minor; the repo convention does not: the 0.4.3 pattern-widening bump was itself a patch. Precedent wins.
50
+
7
51
  ## 0.4.3 - 2026-08-12
8
52
 
9
53
  Additive patch bump: car 1 of the `rcf-lite` 0.8.0 slug-train. Widens four id patterns to accept an optional kebab-case slug tail (per the slug design ratified on `w-2026-07-28-012`), widens the TS and TC id patterns to drop the 999 cap, adds a shared scope-tag vocabulary in `common.schema.json`, and exposes an optional `scope` field on ACs and TCs. Every change is additive; every existing id and every existing document continues to validate.
@@ -26,6 +26,22 @@ Both forms remain valid: `FBS-004` and `FBS-004-user-login` both validate. Exist
26
26
 
27
27
  Rationale: parallel authoring on branches can allocate the same number for different titles. The slug makes those distinct addresses at the filesystem and id layer, converting an add/add merge conflict into a clean co-existence. See the `rcf-lite` slug-train design for the full argument.
28
28
 
29
+ ## Optional slug prefix (0.4.4) — blueprint namespacing
30
+
31
+ Six families accept an optional kebab-case slug **prefix**: `PRD`, `REQ`, `US`, `BS`, `TAD`, `TS`. The full pattern is:
32
+
33
+ ```
34
+ ^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?<PREFIX>-\d{3,}$
35
+ ```
36
+
37
+ The prefix is a blueprint's slug (or any well-formed kebab slug) followed by a hyphen. Examples: `spa-REQ-001`, `spa-US-101`, `rest-BS-001`, `my-blueprint-TAD-002`. Existing numeric-only ids continue to validate; the prefix is purely opt-in.
38
+
39
+ This unblocks the blueprint mechanism landing in `rcf-build-lite`: blueprint-contributed docs carry the blueprint's slug as a namespace so multiple applied blueprints cannot collide on ids and every trace query names the provenance visibly.
40
+
41
+ **Mixed grammar (intentional, minimal-delta):** ADR/TAC/FBS/CN carry the slug in the **suffix** (0.4.3); PRD/REQ/US/BS/TAD/TS carry it in the **prefix** (0.4.4). ADR/TAC/FBS/CN were left untouched at 0.4.4 because their suffix affordance already namespaces blueprint contributions (`TAC-002-spa-tokens`, `ADR-005-rest-versioning`). Unifying the grammar is a schemas follow-up; the mixed grammar is documented and working tools accept both.
42
+
43
+ **Not extended:** `AC` and `TC` ids keep the numeric-only + AC-hierarchical / TC-slug forms. AC/TC ids are anchored to their parent US/TS chain, whose ids now carry the slug prefix; adding a redundant prefix on ACs and TCs adds no expressiveness.
44
+
29
45
  ## Prefix table
30
46
 
31
47
  | Prefix | Document | File? | Where defined |
@@ -0,0 +1,16 @@
1
+ {
2
+ "fbsId": "FBS-014",
3
+ "prdId": "PRD-001",
4
+ "bsId": "BS-001",
5
+ "buildOrder": 14,
6
+ "executionStatus": "notStarted",
7
+ "title": "Bad standardIds shape",
8
+ "summary": "standardIds carries an uppercase entry that is not a valid slug.",
9
+ "acIds": ["AC-001"],
10
+ "dependsOnFbsIds": [],
11
+ "contextRequirements": {
12
+ "standardIds": ["WSD-Naming"]
13
+ },
14
+ "createdAt": "2026-08-18T00:00:00Z",
15
+ "updatedAt": "2026-08-18T00:00:00Z"
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Invalid blueprint slug",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "blueprints": [
8
+ {
9
+ "slug": "SPA",
10
+ "version": "1.0.0",
11
+ "appliedAt": "2026-08-18T10:00:00Z",
12
+ "source": "@stravica-ai/rcf-blueprint-spa@1.0.0"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Invalid standards id",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "standards": [
8
+ {
9
+ "id": "wsd-naming",
10
+ "slug": "wsd-naming",
11
+ "sourcePath": "docs/standards/wsd-naming",
12
+ "tags": ["naming"],
13
+ "testsProvidedBy": "agent",
14
+ "provenance": "corporate"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Bad resolution id",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "resolutions": [
8
+ {
9
+ "id": "resolution-1",
10
+ "createdAt": "2026-08-19T10:15:00Z",
11
+ "kind": "globalAdrTopic",
12
+ "topic": "auth",
13
+ "resolvedByAdrId": "ADR-042",
14
+ "supersedes": [
15
+ { "slug": "spa", "adrId": "ADR-005-spa" },
16
+ { "slug": "rest", "adrId": "ADR-003-rest" }
17
+ ]
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Resolution with a single supersedes entry (minItems 2 violation)",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "resolutions": [
8
+ {
9
+ "id": "res-2026-08-19-001",
10
+ "createdAt": "2026-08-19T10:15:00Z",
11
+ "kind": "globalAdrTopic",
12
+ "topic": "auth",
13
+ "resolvedByAdrId": "ADR-042",
14
+ "supersedes": [
15
+ { "slug": "spa", "adrId": "ADR-005-spa" }
16
+ ]
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "reqId": "SPA-REQ-001",
3
+ "prdId": "PRD-001",
4
+ "title": "Uppercase slug prefix must be rejected",
5
+ "description": "Slug prefixes are lowercase kebab; upper-case must fail.",
6
+ "category": "functional",
7
+ "domain": "ui",
8
+ "priority": "must",
9
+ "version": "0.1.0",
10
+ "status": "draft",
11
+ "createdAt": "2026-08-18T00:00:00Z",
12
+ "updatedAt": "2026-08-18T00:00:00Z"
13
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "usId": "spa--US-101",
3
+ "prdId": "PRD-001",
4
+ "reqId": "REQ-001",
5
+ "version": "0.1.0",
6
+ "status": "draft",
7
+ "title": "Double-hyphen slug prefix must be rejected",
8
+ "asA": "user",
9
+ "iWant": "to see this fail",
10
+ "soThat": "the slug grammar rejects double hyphens",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-001",
14
+ "description": "n/a",
15
+ "testable": true
16
+ }
17
+ ],
18
+ "createdAt": "2026-08-18T00:00:00Z",
19
+ "updatedAt": "2026-08-18T00:00:00Z"
20
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "bsId": "spa-BS-001",
3
+ "prdId": "PRD-001",
4
+ "version": "0.1.0",
5
+ "status": "draft",
6
+ "createdAt": "2026-08-18T00:00:00Z",
7
+ "updatedAt": "2026-08-18T00:00:00Z"
8
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "fbsId": "FBS-014",
3
+ "prdId": "PRD-001",
4
+ "bsId": "BS-001",
5
+ "buildOrder": 14,
6
+ "executionStatus": "notStarted",
7
+ "title": "Wire error envelope on the POST /users endpoint",
8
+ "summary": "Introduce the RFC 7807 problem-details envelope on the POST /users error paths.",
9
+ "acIds": ["AC-014-1", "AC-014-2"],
10
+ "dependsOnFbsIds": [],
11
+ "contextRequirements": {
12
+ "tacIds": ["TAC-002-error-envelope"],
13
+ "adrIds": ["ADR-004-rfc7807"],
14
+ "standardIds": ["wsd-naming", "security-baseline"]
15
+ },
16
+ "createdAt": "2026-08-18T00:00:00Z",
17
+ "updatedAt": "2026-08-18T00:00:00Z"
18
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Composed SPA + REST project",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "blueprints": [
8
+ {
9
+ "slug": "spa",
10
+ "version": "1.0.0",
11
+ "appliedAt": "2026-08-18T10:00:00Z",
12
+ "source": "@stravica-ai/rcf-blueprint-spa@1.0.0",
13
+ "contributions": [
14
+ { "id": "spa-REQ-001", "path": "rcf/requirements/spa-req-001.json", "kind": "req" },
15
+ { "id": "spa-US-101", "path": "rcf/user-stories/spa-us-101.json", "kind": "us" },
16
+ { "id": "TAC-002-spa-tokens", "path": "rcf/tacs/tac-002-spa-tokens.json", "kind": "tac" },
17
+ { "id": "ADR-004-spa-theme", "path": "rcf/adrs/adr-004-spa-theme.json", "kind": "adr" }
18
+ ]
19
+ },
20
+ {
21
+ "slug": "rest",
22
+ "version": "1.0.0",
23
+ "appliedAt": "2026-08-18T10:00:05Z",
24
+ "source": "@stravica-ai/rcf-blueprint-rest@1.0.0",
25
+ "namespace": "rest",
26
+ "contributions": [
27
+ { "id": "rest-REQ-001", "path": "rcf/requirements/rest-req-001.json", "kind": "req" },
28
+ { "id": "ADR-005-rest-versioning", "path": "rcf/adrs/adr-005-rest-versioning.json", "kind": "adr" }
29
+ ]
30
+ }
31
+ ]
32
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "In-repo standards project",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "standards": [
8
+ {
9
+ "id": "std-wsd-naming",
10
+ "slug": "wsd-naming",
11
+ "sourcePath": "docs/standards/wsd-naming",
12
+ "tags": ["naming", "conventions"],
13
+ "summary": "Naming conventions for symbols, files and endpoints across WSD services.",
14
+ "testsProvidedBy": "agent",
15
+ "provenance": "corporate"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Out-of-root standards project",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "standards": [
8
+ {
9
+ "id": "std-security-baseline",
10
+ "slug": "security-baseline",
11
+ "sourcePath": "/Users/thefoot/personal/patterns/security-baseline",
12
+ "copyPath": "rcf/standards/security-baseline",
13
+ "tags": ["security", "logging"],
14
+ "testsProvidedBy": "standard",
15
+ "provenance": "personal"
16
+ },
17
+ {
18
+ "id": "std-http-errors",
19
+ "slug": "http-errors",
20
+ "sourcePath": "docs/patterns/http-errors",
21
+ "tags": ["api", "errors"],
22
+ "testsProvidedBy": "none",
23
+ "provenance": "corporate"
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Frozen pre-0.4.3 chain manifest",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "testCommand": "pnpm -r test"
8
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "projectName": "Composed SPA + REST project with a resolved auth conflict",
4
+ "prd": { "id": "PRD-001", "path": "rcf/prd.json" },
5
+ "tad": { "id": "TAD-001", "path": "rcf/tad.json" },
6
+ "bs": { "id": "BS-001", "path": "rcf/build-sequence.json" },
7
+ "blueprints": [
8
+ {
9
+ "slug": "spa",
10
+ "version": "1.0.0",
11
+ "appliedAt": "2026-08-19T10:00:00Z",
12
+ "source": "@stravica-ai/rcf-blueprint-spa@1.0.0",
13
+ "contributions": [
14
+ { "id": "ADR-005-spa", "path": "rcf/adrs/adr-005-spa.json", "kind": "adr", "scope": "global", "topic": "auth" }
15
+ ]
16
+ },
17
+ {
18
+ "slug": "rest",
19
+ "version": "1.0.0",
20
+ "appliedAt": "2026-08-19T10:00:05Z",
21
+ "source": "@stravica-ai/rcf-blueprint-rest@1.0.0",
22
+ "contributions": [
23
+ { "id": "ADR-003-rest", "path": "rcf/adrs/adr-003-rest.json", "kind": "adr", "scope": "global", "topic": "auth" }
24
+ ]
25
+ }
26
+ ],
27
+ "resolutions": [
28
+ {
29
+ "id": "res-2026-08-19-001",
30
+ "createdAt": "2026-08-19T10:15:00Z",
31
+ "kind": "globalAdrTopic",
32
+ "topic": "auth",
33
+ "resolvedByAdrId": "ADR-042",
34
+ "supersedes": [
35
+ { "slug": "spa", "adrId": "ADR-005-spa" },
36
+ { "slug": "rest", "adrId": "ADR-003-rest" }
37
+ ],
38
+ "reason": "Project auth model is documented in ADR-042; both blueprint auth ADRs remain on disk as superseded history."
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "prdId": "spa-PRD-001",
3
+ "productName": "Blueprint-owned PRD fragment",
4
+ "version": "0.1.0",
5
+ "status": "draft",
6
+ "problemStatement": "Blueprint-contributed PRD fragment attached to a wider project PRD.",
7
+ "objectives": [
8
+ "Cover the SPA-specific scope the blueprint owns."
9
+ ],
10
+ "createdAt": "2026-08-18T00:00:00Z",
11
+ "updatedAt": "2026-08-18T00:00:00Z"
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "reqId": "spa-REQ-001",
3
+ "prdId": "PRD-001",
4
+ "title": "Every route ships loading, empty, error and success states",
5
+ "description": "Blueprint-contributed requirement: every declared route in the SPA carries all four state visuals.",
6
+ "category": "functional",
7
+ "domain": "ui",
8
+ "priority": "must",
9
+ "version": "0.1.0",
10
+ "status": "draft",
11
+ "createdAt": "2026-08-18T00:00:00Z",
12
+ "updatedAt": "2026-08-18T00:00:00Z"
13
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "tadId": "spa-TAD-001",
3
+ "prdId": "PRD-001",
4
+ "version": "0.1.0",
5
+ "status": "draft",
6
+ "systemOverview": {
7
+ "executiveSummary": "Blueprint-contributed TAD fragment covering the SPA shell.",
8
+ "systemPurpose": "Frame the design tokens, nav shell and theme parity the SPA blueprint owns.",
9
+ "architecturalApproach": "Single-page application delivered light and dark by default.",
10
+ "keyCapabilities": ["Theme toggle", "Skeleton loaders", "Responsive layout"]
11
+ },
12
+ "createdAt": "2026-08-18T00:00:00Z",
13
+ "updatedAt": "2026-08-18T00:00:00Z"
14
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "id": "spa-TS-001",
3
+ "usId": "spa-US-101",
4
+ "title": "Loading-state coverage on every fetched route",
5
+ "purpose": "Assert every declared SPA route with a fetch shows a skeleton loader within 100ms.",
6
+ "testLevel": "unit",
7
+ "acIds": ["AC-001"],
8
+ "testCases": [
9
+ {
10
+ "id": "TC-001-happy-path",
11
+ "acId": "AC-001",
12
+ "description": "Skeleton renders synchronously for a route with a pending fetch.",
13
+ "status": "pending"
14
+ }
15
+ ],
16
+ "status": "draft",
17
+ "createdAt": "2026-08-18T00:00:00Z",
18
+ "updatedAt": "2026-08-18T00:00:00Z"
19
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "usId": "spa-US-101",
3
+ "prdId": "PRD-001",
4
+ "reqId": "spa-REQ-001",
5
+ "version": "0.1.0",
6
+ "status": "draft",
7
+ "title": "As a visitor I see a loading state on every fetch",
8
+ "asA": "first-time visitor",
9
+ "iWant": "to see a skeleton or spinner while data is loading",
10
+ "soThat": "I know the app is doing something instead of guessing whether it is broken",
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-001",
14
+ "description": "Every route with a fetch shows a skeleton within 100ms of navigation",
15
+ "testable": true
16
+ }
17
+ ],
18
+ "createdAt": "2026-08-18T00:00:00Z",
19
+ "updatedAt": "2026-08-18T00:00:00Z"
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stravica-ai/rcf-schemas",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
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",
@@ -19,6 +19,9 @@
19
19
  "LICENSE",
20
20
  "CHANGELOG.md"
21
21
  ],
22
+ "scripts": {
23
+ "test": "node --test test/*.test.js"
24
+ },
22
25
  "devDependencies": {
23
26
  "ajv": "^8.17.1",
24
27
  "ajv-formats": "^3.0.1"
@@ -37,8 +40,5 @@
37
40
  "json-schema",
38
41
  "specifications",
39
42
  "traceability"
40
- ],
41
- "scripts": {
42
- "test": "node --test test/*.test.js"
43
- }
44
- }
43
+ ]
44
+ }
@@ -2,22 +2,22 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json",
4
4
  "title": "RCF Shared Definitions",
5
- "description": "Shared $defs referenced via $ref from every other RCF schema. ID patterns, status enums, version string, timestamp format, and the docRef shape. This file is not a document schema; consumers register it alongside the 11 doc-type schemas at validator init.",
5
+ "description": "Shared $defs referenced via $ref from every other RCF schema. ID patterns, status enums, version string, timestamp format, and the docRef shape. This file is not a document schema; consumers register it alongside the 11 doc-type schemas at validator init. From 0.4.4 the reqId/usId/prdId/bsId/tadId/tsId patterns accept an optional lowercase kebab-slug prefix (for example, spa-REQ-001) so blueprint mechanisms can contribute namespaced doc ids without colliding with project-authored ids. Existing numeric-only ids remain valid. The adrId/tacId/fbsId/cnId patterns already carry an optional kebab-slug SUFFIX (0.4.3) and are intentionally left untouched: id grammar is mixed across types for tonight (prefix for REQ/US/PRD/BS/TAD/TS; suffix for ADR/TAC/FBS/CN); unifying is a schemas follow-up.",
6
6
  "$defs": {
7
7
  "prdId": {
8
8
  "type": "string",
9
- "pattern": "^PRD-\\d{3,}$",
10
- "description": "PRD identifier. Three-digit minimum, unbounded above."
9
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?PRD-\\d{3,}$",
10
+ "description": "PRD identifier. Three-digit minimum, unbounded above. An optional lowercase kebab-slug prefix (for example, spa-PRD-001) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
11
11
  },
12
12
  "reqId": {
13
13
  "type": "string",
14
- "pattern": "^REQ-\\d{3,}$",
15
- "description": "Requirement identifier."
14
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?REQ-\\d{3,}$",
15
+ "description": "Requirement identifier. An optional lowercase kebab-slug prefix (for example, spa-REQ-001) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
16
16
  },
17
17
  "usId": {
18
18
  "type": "string",
19
- "pattern": "^US-\\d{3,}$",
20
- "description": "User Story identifier."
19
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?US-\\d{3,}$",
20
+ "description": "User Story identifier. An optional lowercase kebab-slug prefix (for example, spa-US-101) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
21
21
  },
22
22
  "acId": {
23
23
  "type": "string",
@@ -26,8 +26,8 @@
26
26
  },
27
27
  "tadId": {
28
28
  "type": "string",
29
- "pattern": "^TAD-\\d{3,}$",
30
- "description": "Technical Architecture Document identifier."
29
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?TAD-\\d{3,}$",
30
+ "description": "Technical Architecture Document identifier. An optional lowercase kebab-slug prefix (for example, spa-TAD-001) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
31
31
  },
32
32
  "tacId": {
33
33
  "type": "string",
@@ -41,8 +41,8 @@
41
41
  },
42
42
  "bsId": {
43
43
  "type": "string",
44
- "pattern": "^BS-\\d{3,}$",
45
- "description": "Build Sequence identifier."
44
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?BS-\\d{3,}$",
45
+ "description": "Build Sequence identifier. An optional lowercase kebab-slug prefix (for example, spa-BS-001) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
46
46
  },
47
47
  "fbsId": {
48
48
  "type": "string",
@@ -51,8 +51,8 @@
51
51
  },
52
52
  "tsId": {
53
53
  "type": "string",
54
- "pattern": "^TS-\\d{3,}$",
55
- "description": "Test Suite identifier. Three-digit minimum, unbounded above."
54
+ "pattern": "^([a-z][a-z0-9]*(?:-[a-z0-9]+)*-)?TS-\\d{3,}$",
55
+ "description": "Test Suite identifier. Three-digit minimum, unbounded above. An optional lowercase kebab-slug prefix (for example, spa-TS-001) is permitted for blueprint-contributed docs; existing numeric-only ids remain valid."
56
56
  },
57
57
  "tcId": {
58
58
  "type": "string",
@@ -98,6 +98,16 @@
98
98
  "enum": ["library", "runtime", "deployed", "unclassified"],
99
99
  "description": "Scope tag classifying where a behaviour is observable. Shared between user-story.acceptanceCriteria[].scope and test-suite.testCases[].scope. library: observable in an isolated library or fixture. runtime: observable in the running product against local integration. deployed: observable on a booted artefact against real config and real network. unclassified: migration state for chains authored before the scope-tag vocabulary shipped; ruleset-enforcing consumers decide whether unclassified is currently accepted."
100
100
  },
101
+ "blueprintSlug": {
102
+ "type": "string",
103
+ "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
104
+ "description": "Blueprint slug in lowercase kebab (for example, spa, rest, msg-consumer). Same shape as the id-prefix slug that namespaces blueprint-contributed docs."
105
+ },
106
+ "standardSlug": {
107
+ "type": "string",
108
+ "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
109
+ "description": "Standards-pack slug in lowercase kebab (for example, wsd-naming, security-baseline). Used by manifest.standards[] and referenced by fbs.contextRequirements.standardIds."
110
+ },
101
111
  "docRef": {
102
112
  "type": "object",
103
113
  "additionalProperties": false,
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://schemas.stravica.io/rcf/v0.4.0/fbs.schema.json",
4
4
  "title": "RCF Functional Build Spec",
5
- "description": "Functional Build Specification. One per build session. Carries the mandatory bsId parent reference plus buildOrder and executionStatus. Owns its acIds[] scope (Acceptance Criteria delivered by this FBS) and its dependsOnFbsIds[] graph edge (other FBSs this one depends on).",
5
+ "description": "Functional Build Specification. One per build session. Carries the mandatory bsId parent reference plus buildOrder and executionStatus. Owns its acIds[] scope (Acceptance Criteria delivered by this FBS) and its dependsOnFbsIds[] graph edge (other FBSs this one depends on). From 0.4.4 the contextRequirements block carries an optional standardIds[] array. It is the host for the bundle assembler's selective-retrieval step: the assembler analyses the FBS work text against the manifest.standards[] tag vocabulary and populates standardIds for that bundle only, or honours an operator override authored on the FBS. Every added field is optional; pre-0.4.4 FBSes remain valid.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -57,6 +57,11 @@
57
57
  "type": "array",
58
58
  "items": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/adrId" }
59
59
  },
60
+ "standardIds": {
61
+ "type": "array",
62
+ "items": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/standardSlug" },
63
+ "description": "Standards-pack slugs (from manifest.standards[]) that apply to this FBS. Populated by the bundle assembler's agentic selective-retrieval step at bundle-assembly time; an operator-authored value overrides the agentic selection for that FBS. Empty or absent means no standards content is included in the bundle; the assembler never blocks on an empty selection."
64
+ },
60
65
  "existingModules": {
61
66
  "type": "array",
62
67
  "items": { "type": "string" }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://schemas.stravica.io/rcf/v0.4.0/manifest.schema.json",
4
4
  "title": "RCF Project Manifest",
5
- "description": "Project manifest. Roots-only shape: declares prd, tad, bs. Children are owned by their parents and discovered by walking from the roots. From 0.4.0 the manifest also carries optional records for pre-flight configuration, review audits, UI baselines, browser verification, baseline-AC opt-outs, intake classification, register-regression canaries, and the review-surface state. From 0.4.1 the manifest additionally carries optional shipWithoutVerified acknowledgements written by rcf finalise --ship-without-verified. From 0.4.2 the testTheatreFinding shape carries an optional anchorId and drops tsId from its required list when kind is uiBaselineDrift (the drift finding is not anchored on a test suite); every other kind still requires tsId, and any 0.4.0- or 0.4.1-valid record remains valid. Every added field is optional; pre-0.4.0 manifests remain valid.",
5
+ "description": "Project manifest. Roots-only shape: declares prd, tad, bs. Children are owned by their parents and discovered by walking from the roots. From 0.4.0 the manifest also carries optional records for pre-flight configuration, review audits, UI baselines, browser verification, baseline-AC opt-outs, intake classification, register-regression canaries, and the review-surface state. From 0.4.1 the manifest additionally carries optional shipWithoutVerified acknowledgements written by rcf finalise --ship-without-verified. From 0.4.2 the testTheatreFinding shape carries an optional anchorId and drops tsId from its required list when kind is uiBaselineDrift (the drift finding is not anchored on a test suite); every other kind still requires tsId, and any 0.4.0- or 0.4.1-valid record remains valid. From 0.4.4 the manifest carries two optional additive sections that host the blueprint-library mechanism: blueprints[] (applied-blueprints registry written by rcf blueprint add / remove / upgrade) and standards[] (standards-pack registry written at rcf init and rcf standards add). From 0.4.5 the manifest additionally carries an optional resolutions[] section: one entry per operator-authored resolution of a cross-blueprint conflict, keyed at first by the globalAdrTopic conflict class (two applied blueprints each contributing a scope:global ADR on the same topic, resolved by a project-level ADR that supersedes both). Written by rcf blueprint supersede and by rcf blueprint add --resolve; read by the conflict detector so the resolved conflict is honoured and both blueprint ADRs may co-reside as superseded history. Every added field is optional; pre-0.4.0 manifests remain valid.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": ["version", "projectName", "prd", "tad", "bs"],
@@ -55,6 +55,21 @@
55
55
  "type": "array",
56
56
  "items": { "$ref": "#/$defs/shipWithoutVerifiedRecord" },
57
57
  "description": "Operator acknowledgements recorded when rcf finalise --ship-without-verified acknowledges a MOCK-ONLY-DECLARED or BLOCKED-BY-DECLARATION verdict on the verify report and ships the FBS at complete without promoting to verified. One entry per acknowledgement (verification-integrity-cluster-spec section 5.2). The ack is durable and greppable at ship time."
58
+ },
59
+ "blueprints": {
60
+ "type": "array",
61
+ "items": { "$ref": "#/$defs/appliedBlueprintRecord" },
62
+ "description": "Applied-blueprints registry. One entry per rcf blueprint add / upgrade invocation on the project. Records the blueprint's slug, applied version, source, namespace and the ids and paths the blueprint contributed to the tree. Written by the rcf blueprint verb family; read by rcf blueprint list / remove / upgrade. Optional; projects that never call rcf blueprint have no entries. Composition (multiple applied blueprints) is expressed by multiple entries with distinct slugs."
63
+ },
64
+ "standards": {
65
+ "type": "array",
66
+ "items": { "$ref": "#/$defs/standardsPackRecord" },
67
+ "description": "Standards-pack registry. One entry per standards folder registered at rcf init (or later via rcf standards add). Records the pack's id, slug, source path, optional copy path (present only when the source lived outside the project root and was copied into rcf/standards/<slug>/ for portability), tag vocabulary, testsProvidedBy classification, and provenance. Read by the bundle assembler's selective-retrieval step when populating fbs.contextRequirements.standardIds. Optional; projects that register no standards have no entries."
68
+ },
69
+ "resolutions": {
70
+ "type": "array",
71
+ "items": { "$ref": "#/$defs/blueprintConflictResolution" },
72
+ "description": "Operator-authored resolutions of cross-blueprint conflicts. One entry per resolved conflict. Written by rcf blueprint supersede (which also scaffolds the project-level ADR that supersedes both blueprint ADRs) and by rcf blueprint add --resolve (which records the resolution declaratively on the add itself). Read by the conflict detector at rcf blueprint add: a resolution whose kind and key match a would-be conflict causes the detector to honour the resolution and let both blueprint ADRs co-reside as superseded history. Optional; projects with no cross-blueprint conflicts have no entries."
58
73
  }
59
74
  },
60
75
  "$defs": {
@@ -764,6 +779,155 @@
764
779
  "description": "Optional verify-supplied reason string carried through from the report entry."
765
780
  }
766
781
  }
782
+ },
783
+ "appliedBlueprintRecord": {
784
+ "type": "object",
785
+ "additionalProperties": false,
786
+ "required": ["slug", "version", "appliedAt", "source"],
787
+ "properties": {
788
+ "slug": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/blueprintSlug" },
789
+ "version": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/version" },
790
+ "appliedAt": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/timestamp" },
791
+ "source": {
792
+ "type": "string",
793
+ "minLength": 1,
794
+ "description": "Where the blueprint was resolved from at apply time (for example, a registry path, a git ref, or a local file path). Provenance for rcf blueprint upgrade."
795
+ },
796
+ "namespace": {
797
+ "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/blueprintSlug",
798
+ "description": "Doc-id namespace used for this blueprint's contributions. Defaults to slug when omitted; the field exists so an operator can rename the namespace at add-time to avoid a project-authored slug collision."
799
+ },
800
+ "contributions": {
801
+ "type": "array",
802
+ "items": { "$ref": "#/$defs/appliedBlueprintContribution" },
803
+ "description": "Every doc id and file path the blueprint contributed to the tree at apply time. Makes rcf blueprint remove and rcf blueprint upgrade mechanical: remove deletes exactly these paths and refuses when any project-authored doc references any of these ids; upgrade diffs the new contribution set against this one."
804
+ }
805
+ },
806
+ "description": "One applied-blueprint record. Written by rcf blueprint add on clean apply and rewritten by rcf blueprint upgrade; removed by rcf blueprint remove."
807
+ },
808
+ "appliedBlueprintContribution": {
809
+ "type": "object",
810
+ "additionalProperties": false,
811
+ "required": ["id", "path"],
812
+ "properties": {
813
+ "id": {
814
+ "type": "string",
815
+ "minLength": 1,
816
+ "description": "Contributed doc id (for example, spa-REQ-001, or TAC-002-spa-logging when the doc kind namespaces via kebab-suffix). Schema-wise a minLength: 1 string because the union of all doc-id patterns is enforced at the owning doc's schema."
817
+ },
818
+ "path": {
819
+ "type": "string",
820
+ "minLength": 1,
821
+ "description": "Project-relative path the contribution was written to (for example, rcf/requirements/spa-req-001.json)."
822
+ },
823
+ "kind": {
824
+ "enum": ["prd", "req", "us", "tad", "tac", "adr", "bs", "fbs", "ts", "cn"],
825
+ "description": "Optional doc-kind classifier. Purely informational; the id + path pair is authoritative."
826
+ },
827
+ "scope": {
828
+ "enum": ["global"],
829
+ "description": "ADR contributions only: marks a whole-project decision (auth model, error envelope, versioning strategy). Two applied blueprints each contributing a scope:global ADR on the same topic is a hard conflict, surfaced by rcf blueprint add. Absent for non-global contributions."
830
+ },
831
+ "topic": {
832
+ "type": "string",
833
+ "minLength": 1,
834
+ "description": "ADR contributions only, required in practice when scope=global: the topic key the conflict detector matches on (for example, 'versioning', 'auth', 'errorEnvelope'). Absent for non-global contributions."
835
+ }
836
+ }
837
+ },
838
+ "standardsPackRecord": {
839
+ "type": "object",
840
+ "additionalProperties": false,
841
+ "required": ["id", "slug", "sourcePath", "tags", "testsProvidedBy", "provenance"],
842
+ "properties": {
843
+ "id": {
844
+ "type": "string",
845
+ "pattern": "^std-[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
846
+ "description": "Standards-pack record id. Format: std-<slug>. Slug is repeated in the id so the record id is grep-friendly across the manifest."
847
+ },
848
+ "slug": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/standardSlug" },
849
+ "sourcePath": {
850
+ "type": "string",
851
+ "minLength": 1,
852
+ "description": "Path to the standards content. When the source lives inside the project root the pack is referenced in place (no copy is written); when outside, the pack is copied into rcf/standards/<slug>/ and copyPath records the copy destination."
853
+ },
854
+ "copyPath": {
855
+ "type": "string",
856
+ "minLength": 1,
857
+ "description": "Present only when sourcePath was outside the project root at registration time. Points at the in-tree mirror under rcf/standards/<slug>/. Absent for in-repo sources (reference-by-default)."
858
+ },
859
+ "tags": {
860
+ "type": "array",
861
+ "items": { "type": "string", "minLength": 1 },
862
+ "description": "Ordered tag vocabulary for this pack (for example, naming, security, logging, ui, api). Read by the bundle assembler's selective-retrieval step alongside the pack summary when scoring relevance to an FBS's work text."
863
+ },
864
+ "summary": {
865
+ "type": "string",
866
+ "description": "Short human-readable summary of the pack's scope. Read by the selective-retrieval step; omitted for guidance-only packs where the tags carry enough signal."
867
+ },
868
+ "testsProvidedBy": {
869
+ "enum": ["standard", "agent", "none"],
870
+ "description": "How adherence to this pack is expressed. standard: the pack ships adherence checks that convert into ACs in the tree at registration or standards add time. agent: the working agent derives adherence from the pack's prose during build. none: guidance-only; the pack contributes prose that lands in the bundle but no adherence tests."
871
+ },
872
+ "provenance": {
873
+ "enum": ["personal", "corporate"],
874
+ "description": "Records whether the pack is a personal pattern collection or a corporate standards library. Reads at bundle-time as informational; init records the distinction so a project-level report can name where each pack came from."
875
+ }
876
+ },
877
+ "description": "One standards-pack registration. Written by rcf init (during standards prompting) and rcf standards add; read by the bundle assembler's selective-retrieval step."
878
+ },
879
+ "blueprintConflictResolution": {
880
+ "type": "object",
881
+ "additionalProperties": false,
882
+ "required": ["id", "createdAt", "kind", "topic", "resolvedByAdrId", "supersedes"],
883
+ "properties": {
884
+ "id": {
885
+ "type": "string",
886
+ "pattern": "^res-\\d{4}-\\d{2}-\\d{2}-\\d{3}$",
887
+ "description": "Blueprint-conflict-resolution record id. Format: res-YYYY-MM-DD-NNN. Monotonic per project."
888
+ },
889
+ "createdAt": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/timestamp" },
890
+ "kind": {
891
+ "enum": ["globalAdrTopic"],
892
+ "description": "Which conflict class this record resolves. Currently the only kind is globalAdrTopic (two applied blueprints each contributing a scope:global ADR on the same topic). The enum is single-valued so a later minor bump can add further resolution classes additively without breaking existing consumers."
893
+ },
894
+ "topic": {
895
+ "type": "string",
896
+ "minLength": 1,
897
+ "description": "The topic key the resolution applies to (for example, 'auth', 'versioning', 'errorEnvelope'). Matches the topic on both superseded blueprint ADRs. Required for kind=globalAdrTopic; the conflict detector reads this to know which would-be conflict the record honours."
898
+ },
899
+ "resolvedByAdrId": {
900
+ "type": "string",
901
+ "minLength": 1,
902
+ "description": "The project-level ADR id that supersedes the blueprint ADRs (for example, ADR-042). Its file lives outside any applied blueprint's namespace and is authored at rcf blueprint supersede time. Provenance for the resolution; the conflict detector does not currently re-read the referenced ADR."
903
+ },
904
+ "supersedes": {
905
+ "type": "array",
906
+ "minItems": 2,
907
+ "items": { "$ref": "#/$defs/blueprintConflictResolutionSupersededAdr" },
908
+ "description": "The blueprint ADRs this resolution supersedes. Two entries at minimum: the two applied blueprints whose global ADRs collided on topic. Both blueprint ADRs co-reside on disk as superseded history; the resolvedByAdrId is the live decision."
909
+ },
910
+ "reason": {
911
+ "type": "string",
912
+ "minLength": 1,
913
+ "description": "Optional operator note recording why this resolution was chosen. Free text; the schema does not enforce a minimum floor here so the operator can record a terse one-liner when the resolvedByAdrId itself carries the reasoning."
914
+ }
915
+ },
916
+ "description": "One blueprint-conflict resolution. Written by rcf blueprint supersede (scaffolds the resolvedByAdrId and appends the record) and by rcf blueprint add --resolve (appends the record without scaffolding a new ADR). Read by the conflict detector to skip a would-be conflict when a resolution matches."
917
+ },
918
+ "blueprintConflictResolutionSupersededAdr": {
919
+ "type": "object",
920
+ "additionalProperties": false,
921
+ "required": ["slug", "adrId"],
922
+ "properties": {
923
+ "slug": { "$ref": "https://schemas.stravica.io/rcf/v0.4.0/common.schema.json#/$defs/blueprintSlug" },
924
+ "adrId": {
925
+ "type": "string",
926
+ "minLength": 1,
927
+ "description": "The blueprint-owned ADR id that is superseded (for example, spa-ADR-005 or ADR-005-spa). Kept as a free-string minLength: 1 so the shape does not have to encode the mixed prefix/suffix namespacing grammar."
928
+ }
929
+ },
930
+ "description": "One superseded blueprint ADR: the applied blueprint's slug plus the ADR id inside that blueprint's contribution set."
767
931
  }
768
932
  }
769
933
  }