@stravica-ai/rcf-schemas 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/LICENSE +202 -0
- package/README.md +165 -0
- package/docs/README.md +37 -0
- package/docs/adr.md +42 -0
- package/docs/build-sequence.md +44 -0
- package/docs/common.md +43 -0
- package/docs/fbs.md +75 -0
- package/docs/file-layout.md +62 -0
- package/docs/id-conventions.md +60 -0
- package/docs/manifest.md +70 -0
- package/docs/prd.md +64 -0
- package/docs/req.md +57 -0
- package/docs/tac.md +49 -0
- package/docs/tad.md +76 -0
- package/docs/test-suite.md +56 -0
- package/docs/user-story.md +61 -0
- package/fixtures/invalid/adr/adr-001-authoring-status.json +13 -0
- package/fixtures/invalid/adr/adr-002-supersededBy-bad-id.json +14 -0
- package/fixtures/invalid/adr/adr-003-missing-tadId.json +12 -0
- package/fixtures/invalid/build-sequence/bs-001-legacy-fbs-array.json +11 -0
- package/fixtures/invalid/build-sequence/bs-002-missing-prdId.json +7 -0
- package/fixtures/invalid/fbs/fbs-001-storyScope-wrapper.json +16 -0
- package/fixtures/invalid/fbs/fbs-002-empty-acIds.json +13 -0
- package/fixtures/invalid/fbs/fbs-003-authoring-status.json +13 -0
- package/fixtures/invalid/fbs/fbs-004-plain-int-acId.json +13 -0
- package/fixtures/invalid/fbs/fbs-005-missing-buildOrder.json +12 -0
- package/fixtures/invalid/fbs/fbs-006-buildOrder-zero.json +13 -0
- package/fixtures/invalid/manifest/manifest-001-userStories-array.json +10 -0
- package/fixtures/invalid/manifest/manifest-002-legacy-buildSequence.json +7 -0
- package/fixtures/invalid/manifest/manifest-003-wrong-version.json +7 -0
- package/fixtures/invalid/prd/prd-001-typoed-status.json +10 -0
- package/fixtures/invalid/prd/prd-002-legacy-requirementIds.json +11 -0
- package/fixtures/invalid/prd/prd-003-missing-objectives.json +9 -0
- package/fixtures/invalid/req/req-001-bad-prefix.json +13 -0
- package/fixtures/invalid/req/req-002-unknown-category.json +13 -0
- package/fixtures/invalid/req/req-003-missing-prdId.json +12 -0
- package/fixtures/invalid/tac/tac-001-empty-responsibilities.json +12 -0
- package/fixtures/invalid/tac/tac-002-bad-dependency-kind.json +15 -0
- package/fixtures/invalid/tac/tac-003-missing-tadId.json +11 -0
- package/fixtures/invalid/tad/tad-001-legacy-componentIds.json +16 -0
- package/fixtures/invalid/tad/tad-002-partial-deployment.json +17 -0
- package/fixtures/invalid/test-suite/ts-001-missing-usId.json +18 -0
- package/fixtures/invalid/test-suite/ts-002-empty-acIds.json +19 -0
- package/fixtures/invalid/test-suite/ts-003-bad-tc-id.json +19 -0
- package/fixtures/invalid/test-suite/ts-004-bad-tc-status.json +19 -0
- package/fixtures/invalid/test-suite/ts-005-bad-test-level.json +12 -0
- package/fixtures/invalid/user-story/us-001-empty-acs.json +14 -0
- package/fixtures/invalid/user-story/us-002-ac-missing-testable.json +19 -0
- package/fixtures/valid/adr/adr-001-minimal.json +13 -0
- package/fixtures/valid/adr/adr-002-comprehensive.json +27 -0
- package/fixtures/valid/adr/adr-003-draft-status.json +13 -0
- package/fixtures/valid/build-sequence/bs-001-minimal.json +8 -0
- package/fixtures/valid/build-sequence/bs-002-comprehensive.json +11 -0
- package/fixtures/valid/fbs/fbs-001-minimal.json +13 -0
- package/fixtures/valid/fbs/fbs-002-comprehensive.json +34 -0
- package/fixtures/valid/manifest/manifest-001-minimal.json +7 -0
- package/fixtures/valid/manifest/manifest-002-with-description.json +8 -0
- package/fixtures/valid/prd/prd-001-minimal.json +12 -0
- package/fixtures/valid/prd/prd-002-comprehensive.json +34 -0
- package/fixtures/valid/req/req-001-minimal.json +13 -0
- package/fixtures/valid/req/req-002-comprehensive.json +15 -0
- package/fixtures/valid/tac/tac-001-minimal.json +15 -0
- package/fixtures/valid/tac/tac-002-comprehensive.json +49 -0
- package/fixtures/valid/tad/tad-001-minimal.json +14 -0
- package/fixtures/valid/tad/tad-002-comprehensive.json +71 -0
- package/fixtures/valid/test-suite/ts-001-minimal.json +19 -0
- package/fixtures/valid/test-suite/ts-002-comprehensive.json +32 -0
- package/fixtures/valid/user-story/us-001-minimal.json +20 -0
- package/fixtures/valid/user-story/us-002-hierarchical-acs.json +40 -0
- package/package.json +44 -0
- package/schemas/adr.schema.json +58 -0
- package/schemas/build-sequence.schema.json +22 -0
- package/schemas/common.schema.json +103 -0
- package/schemas/fbs.schema.json +90 -0
- package/schemas/manifest.schema.json +17 -0
- package/schemas/prd.schema.json +49 -0
- package/schemas/req.schema.json +39 -0
- package/schemas/tac.schema.json +73 -0
- package/schemas/tad.schema.json +162 -0
- package/schemas/test-suite.schema.json +61 -0
- package/schemas/user-story.schema.json +56 -0
package/docs/fbs.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# fbs.schema.json
|
|
2
|
+
|
|
3
|
+
Functional Build Specification. One per build session. **Outside the traceability chain**: FBS owns `acIds[]` for build-time work assignment but is not load-bearing for "did REQ-001 get tested?" queries. See `id-conventions.md` for the chain detail.
|
|
4
|
+
|
|
5
|
+
Structurally, each FBS carries the mandatory `bsId` back-reference plus `buildOrder` and `executionStatus`. The walker computes the ordered per-BS FBS list by loading every FBS under `rcf/fbs/`, filtering by `bsId`, and sorting by `buildOrder`.
|
|
6
|
+
|
|
7
|
+
## Canonical `$id`
|
|
8
|
+
|
|
9
|
+
`https://schemas.stravica.io/rcf/v0.2.0/fbs.schema.json`
|
|
10
|
+
|
|
11
|
+
## Required fields
|
|
12
|
+
|
|
13
|
+
| Field | Type | Notes |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `fbsId` | `^FBS-\d{3,}$` | This FBS's identifier. |
|
|
16
|
+
| `prdId` | `^PRD-\d{3,}$` | Root PRD. |
|
|
17
|
+
| `bsId` | `^BS-\d{3,}$` | Parent Build Sequence. |
|
|
18
|
+
| `buildOrder` | integer >= 1 | Position in the ordered sequence for this BS. Duplicates within one BS are a walker-time validation error. |
|
|
19
|
+
| `executionStatus` | `executionStatus` enum | `notStarted`, `inProgress`, `complete`, `verified`. |
|
|
20
|
+
| `title` | string, min 1 | One-line title. |
|
|
21
|
+
| `summary` | string, min 1 | One-paragraph "what is this build doing". |
|
|
22
|
+
| `acIds` | array of `acId`, min 1 | The ACs this build session delivers. Flat top-level array. |
|
|
23
|
+
| `dependsOnFbsIds` | array of `fbsId`, min 0 | Other FBS items this one depends on. The build tool builds a DAG from these. Empty array is allowed. |
|
|
24
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
25
|
+
|
|
26
|
+
## Optional fields
|
|
27
|
+
|
|
28
|
+
| Field | Type | Purpose |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `approach` | string | "How to think about this build" narrative, distinct from `summary` (what) and `notes` (gotchas). |
|
|
31
|
+
| `contextRequirements` | object | What the SDD adapter needs to walk for the BUILD prompt. See below. |
|
|
32
|
+
| `estimatedSize` | enum: `small`, `medium`, `large` | Rough sizing. |
|
|
33
|
+
| `estimatedHours` | number, 0.5..16 | Tighter estimate. |
|
|
34
|
+
| `deliverables` | array of strings | Concrete artefacts expected from the build session. |
|
|
35
|
+
| `riskLevel` | enum: `low`, `medium`, `high` | Risk classification. |
|
|
36
|
+
| `domain` | string | Free-form domain label. |
|
|
37
|
+
| `notes` | string | FBS-specific gotchas. |
|
|
38
|
+
|
|
39
|
+
## `contextRequirements` shape
|
|
40
|
+
|
|
41
|
+
Tells the SDD adapter (Phase 6 of `rcf-build-lite`) what to walk when assembling the BUILD prompt:
|
|
42
|
+
|
|
43
|
+
| Field | Type | Purpose |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `prdSections` | array of strings | PRD section names to inline. |
|
|
46
|
+
| `tadSections` | array of strings | TAD section names to inline. |
|
|
47
|
+
| `tacIds` | array of `tacId` | Specific TACs to inline. |
|
|
48
|
+
| `adrIds` | array of `adrId` | Specific ADRs to inline. |
|
|
49
|
+
| `existingModules` | array of strings | Source files the build should be aware of. |
|
|
50
|
+
| `schemas` | array of strings | Schema files relevant to this build. |
|
|
51
|
+
| `externalDocs` | array of strings | Third-party docs (URLs or paths). |
|
|
52
|
+
| `other` | array of strings | Anything else. |
|
|
53
|
+
|
|
54
|
+
## Renamed fields in 0.2.0
|
|
55
|
+
|
|
56
|
+
- `status` -> `executionStatus`. Same enum, more explicit name (disambiguates from authoring status used elsewhere).
|
|
57
|
+
- `dependencies` -> `dependsOnFbsIds`. Same shape, mandatory with `minItems: 0`.
|
|
58
|
+
|
|
59
|
+
## Why flat `acIds[]`
|
|
60
|
+
|
|
61
|
+
Round-3 had `storyScope: [{ acIds: [...] }]`. The wrapping object served no purpose: the parent US is derivable from each AC id (each AC lives inside its US doc's `acceptanceCriteria[]`). Strict-by-default discipline: if it's derivable, don't store it.
|
|
62
|
+
|
|
63
|
+
## Why FBS is outside the traceability chain
|
|
64
|
+
|
|
65
|
+
The RCF traceability chain is `PRD -> REQ -> US -> AC -> TS -> TC`. FBS is a build-time work artefact, useful for "what's being built this session" but not for "did REQ-001 get tested?" Phase 5 traceability tooling in `rcf-build-lite` walks the chain without going through FBS.
|
|
66
|
+
|
|
67
|
+
## What's NOT here
|
|
68
|
+
|
|
69
|
+
- **`testableOutcomes`** dropped. Derivable from referenced ACs (each AC's `then` clause IS the testable outcome). SSoT: AC is the source.
|
|
70
|
+
- **`constraints`** dropped. Architectural constraints live in TAC / ADR (referenced via `contextRequirements`). FBS-specific gotchas go in `notes`.
|
|
71
|
+
- **Markdown narrative.** The schema is pure JSON. The BUILD-phase markdown prompt is assembled at build time by the SDD adapter from JSON FBS + walked references.
|
|
72
|
+
|
|
73
|
+
## SDD adapter (informative, not in this repo)
|
|
74
|
+
|
|
75
|
+
`rcf build FBS-XXX` reads the FBS JSON, walks `acIds[]` to parent US ACs, walks `contextRequirements.tacIds[]` and `adrIds[]` to TAC/ADR files, and assembles a single markdown prompt for the coding LLM. The adapter lives in `rcf-build-lite` (Phase 6 of that project). The schemas repo's job is to make sure the FBS schema carries every field the adapter needs.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# File layout (recommended)
|
|
2
|
+
|
|
3
|
+
The schemas validate documents by content, not by where they sit on disk. This page documents the **recommended canonical layout**. Adopters may deviate; nothing here is schema-enforced.
|
|
4
|
+
|
|
5
|
+
## Recommendation
|
|
6
|
+
|
|
7
|
+
Put all RCF docs under a `rcf/` top-level folder at project root. Test Suites live under `rcf/test-suites/`.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
project-root/
|
|
11
|
+
|-- rcf/
|
|
12
|
+
| |-- rcf-manifest.json
|
|
13
|
+
| |-- prd.json
|
|
14
|
+
| |-- requirements/
|
|
15
|
+
| | |-- REQ-001.json
|
|
16
|
+
| | `-- REQ-002.json
|
|
17
|
+
| |-- user-stories/
|
|
18
|
+
| | |-- US-101.json
|
|
19
|
+
| | `-- US-102.json
|
|
20
|
+
| |-- tad.json
|
|
21
|
+
| |-- tacs/
|
|
22
|
+
| | |-- TAC-001.json
|
|
23
|
+
| | `-- TAC-002.json
|
|
24
|
+
| |-- adrs/
|
|
25
|
+
| | |-- ADR-001.json
|
|
26
|
+
| | `-- ADR-002.json
|
|
27
|
+
| |-- build-sequence.json
|
|
28
|
+
| |-- fbs/
|
|
29
|
+
| | |-- FBS-001.json
|
|
30
|
+
| | `-- FBS-002.json
|
|
31
|
+
| `-- test-suites/
|
|
32
|
+
| |-- ts-001.json
|
|
33
|
+
| `-- ts-002.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Why everything lives under `rcf/`
|
|
37
|
+
|
|
38
|
+
A single top-level folder keeps structured RCF artefacts cleanly separable from source code. Tools that walk the RCF tree (linters, query tools, the `rcf view` viewer) have a single boundary to read from.
|
|
39
|
+
|
|
40
|
+
The Test Suite JSON is the *spec* of what the tests do; the *executable* test file (Jest, pytest, JUnit, ...) lives with the implementation and is linked from a TC's optional `testPointer` field (`filePath::testName`). This keeps the spec walkable by tooling without prescribing where executable tests live.
|
|
41
|
+
|
|
42
|
+
## Conventions, not constraints
|
|
43
|
+
|
|
44
|
+
The schema does not enforce file naming or directory layout. Adopters can:
|
|
45
|
+
|
|
46
|
+
- Pick different filenames (`prd-2026.json` instead of `prd.json`).
|
|
47
|
+
- Co-locate FBS files with the source they build (legal; the recommendation just keeps them under `rcf/fbs/` for discoverability).
|
|
48
|
+
|
|
49
|
+
Tooling MAY enforce a layout per project, but the schemas repo deliberately does not.
|
|
50
|
+
|
|
51
|
+
## Convention-derived paths from id
|
|
52
|
+
|
|
53
|
+
Tools that walk from the manifest roots can resolve child paths by convention:
|
|
54
|
+
|
|
55
|
+
- REQ-001 -> `rcf/requirements/REQ-001.json`
|
|
56
|
+
- US-101 -> `rcf/user-stories/US-101.json`
|
|
57
|
+
- TAC-001 -> `rcf/tacs/TAC-001.json`
|
|
58
|
+
- ADR-001 -> `rcf/adrs/ADR-001.json`
|
|
59
|
+
- FBS-001 -> `rcf/fbs/FBS-001.json`
|
|
60
|
+
- TS-001 -> `rcf/test-suites/ts-001.json`
|
|
61
|
+
|
|
62
|
+
A future minor bump may introduce an optional `paths` override block on the manifest for adopters who deviate from the recommendation; 0.2.0 ships convention-only.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# ID conventions
|
|
2
|
+
|
|
3
|
+
The pattern, the prefix table, the AC sub-id form, and the file/nested asymmetry.
|
|
4
|
+
|
|
5
|
+
## The pattern
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
^<PREFIX>-\d{3,}$
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Three-digit minimum, unbounded above. `PRD-001` through `PRD-999` use the clean visual; `PRD-1000+` works without a schema migration. A single digit (`PRD-1`) is rejected.
|
|
12
|
+
|
|
13
|
+
Two families deviate from the family default and are documented alongside their prefix below: `TS-\d{3}` (exactly three digits) and `TC-\d{3}-<slug>` (three-digit TS suffix plus a lowercase alphanumeric slug).
|
|
14
|
+
|
|
15
|
+
## Prefix table
|
|
16
|
+
|
|
17
|
+
| Prefix | Document | File? | Where defined |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `PRD` | Product Requirements Document | yes | `prd.schema.json` |
|
|
20
|
+
| `REQ` | Requirement | yes | `req.schema.json` |
|
|
21
|
+
| `US` | User Story | yes | `user-story.schema.json` |
|
|
22
|
+
| `AC` | Acceptance Criterion | no (nested in US) | `user-story.schema.json $defs.acceptanceCriterion` |
|
|
23
|
+
| `TAD` | Technical Architecture Document | yes | `tad.schema.json` |
|
|
24
|
+
| `TAC` | Technical Architecture Component | yes | `tac.schema.json` |
|
|
25
|
+
| `ADR` | Architectural Decision Record | yes | `adr.schema.json` |
|
|
26
|
+
| `BS` | Build Sequence | yes | `build-sequence.schema.json` |
|
|
27
|
+
| `FBS` | Functional Build Specification | yes | `fbs.schema.json` |
|
|
28
|
+
| `TS` | Test Suite | yes (one file per suite, sequential id `TS-\d{3}`) | `test-suite.schema.json` |
|
|
29
|
+
| `TC` | Test Case | no (nested in TS, id `TC-<TS-suffix>-<slug>`) | `test-suite.schema.json` |
|
|
30
|
+
|
|
31
|
+
All prefixes are defined exactly once in `common.schema.json#/$defs` and referenced via `$ref` everywhere.
|
|
32
|
+
|
|
33
|
+
## AC ids: flat or hierarchical
|
|
34
|
+
|
|
35
|
+
The `acId` pattern is `^AC-\d{3,}(-\d+)?$`. Two forms are accepted:
|
|
36
|
+
|
|
37
|
+
- **Flat:** `AC-001`, `AC-201` - single numeric space, fine for small projects.
|
|
38
|
+
- **Hierarchical:** `AC-101-1`, `AC-101-2` - encodes the parent US id (`US-101`) in the prefix. Useful for FBS scope queries and grep.
|
|
39
|
+
|
|
40
|
+
Pick per project; the schema does not enforce either form. The published `Stravica/rcf-examples` `comprehensive-product` tree uses the hierarchical form for clarity.
|
|
41
|
+
|
|
42
|
+
## TS ids
|
|
43
|
+
|
|
44
|
+
`^TS-\d{3}$`. Sequential, not parent-grouped: a US may have multiple TSs across levels (unit, integration, e2e, ...) and a parent-grouped id would collide. Recommended path: `rcf/test-suites/ts-001.json`.
|
|
45
|
+
|
|
46
|
+
## TC ids
|
|
47
|
+
|
|
48
|
+
`^TC-\d{3}-[a-z0-9-]+$`. TCs are nested in their parent TS's `testCases[]`. The pattern is `TC-<TS-suffix>-<slug>` where slug is a lowercase alphanumeric identifier chosen by the author (hyphens allowed). Examples: `TC-001-happy-path`, `TC-001-rejects-empty`, `TC-042-integration-boundary`. Slug uniqueness is within-TS, not global.
|
|
49
|
+
|
|
50
|
+
Rationale: sequential numbering for TCs is brittle if you renumber; slug-based ids give readable pointers in test-suite bodies and traceability queries.
|
|
51
|
+
|
|
52
|
+
## File-level vs nested-level: the asymmetry
|
|
53
|
+
|
|
54
|
+
| Lives in its own file | Lives nested inside a parent |
|
|
55
|
+
|---|---|
|
|
56
|
+
| PRD, REQ, US, TAD, TAC, ADR, BS, FBS, TS | AC (inside US), TC (inside TS) |
|
|
57
|
+
|
|
58
|
+
**The rule:** narrative-heavy structured documents that grow over time live in their own files (per-doc git history, parallel-safe authoring, no merge conflict on append). Tightly-coupled child structures (AC inside US, TC inside TS) stay nested, splitting them multiplies file counts without benefit.
|
|
59
|
+
|
|
60
|
+
An AC outside its US has no meaning, the Given/When/Then only makes sense in the context of the asA / iWant / soThat triple. Same for TCs.
|
package/docs/manifest.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# manifest.schema.json
|
|
2
|
+
|
|
3
|
+
Project manifest. Roots-only shape: declares `prd`, `tad`, `bs`. Children are owned by their parents and discovered by walking from the roots.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/manifest.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `version` | string, `const: "2.0.0"` | Bundle major version. Lets tools dispatch on it. |
|
|
14
|
+
| `projectName` | string, min 1 | Human-readable project name. |
|
|
15
|
+
| `prd` | `docRef` | Root PRD. Singular. |
|
|
16
|
+
| `tad` | `docRef` | Root TAD. Singular. |
|
|
17
|
+
| `bs` | `docRef` | Root Build Sequence. Singular. |
|
|
18
|
+
|
|
19
|
+
## Optional fields
|
|
20
|
+
|
|
21
|
+
| Field | Type | Purpose |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `description` | string | Short project description. |
|
|
24
|
+
|
|
25
|
+
## `docRef` shape
|
|
26
|
+
|
|
27
|
+
Defined once in `common.schema.json`:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"id": "<doc-id>",
|
|
32
|
+
"path": "<relative-path-to-file>"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Both fields are required.
|
|
37
|
+
|
|
38
|
+
## What's NOT here
|
|
39
|
+
|
|
40
|
+
Singular by design; no child arrays:
|
|
41
|
+
|
|
42
|
+
- No `userStories[]`, `tacs[]`, `adrs[]`, `fbs[]`, `testSuites[]`, `requirements[]`.
|
|
43
|
+
- No `prds: [...]` array (single-PRD per project).
|
|
44
|
+
- No `activePrdId` (multi-PRD assumption retired).
|
|
45
|
+
- No `buildSequence` (renamed to `bs` for abbreviation consistency with `prd`, `tad`, `fbs`, `tac`, `adr`).
|
|
46
|
+
|
|
47
|
+
## Why roots-only
|
|
48
|
+
|
|
49
|
+
SSoT discipline. Every parent-child edge is encoded exactly once, on the child, as a mandatory `<parent>Id` field:
|
|
50
|
+
|
|
51
|
+
- Each **REQ** carries `prdId`; the walker inverts these to produce the PRD's requirement list.
|
|
52
|
+
- Each **TAC** carries `tadId`; likewise for the TAD's component list.
|
|
53
|
+
- Each **ADR** carries `tadId`; likewise for the TAD's decision list.
|
|
54
|
+
- Each **FBS** carries `bsId` (plus `buildOrder` and `executionStatus`); the walker computes the ordered per-BS FBS list by filter + sort.
|
|
55
|
+
- Each **US** carries `reqId`; the set of USs under a REQ is `childrenByParent.get(reqId)`.
|
|
56
|
+
- Each **TS** carries `usId` and the `acIds[]` it verifies; the walker inverts these into cross-link maps.
|
|
57
|
+
|
|
58
|
+
Enumerating children in the manifest as well would create two sources of truth; pick one. The child owns the reference. The manifest stays small (~8 properties) and a new US / TAC / ADR / FBS / REQ / TS never requires a manifest edit.
|
|
59
|
+
|
|
60
|
+
## Example
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"version": "2.0.0",
|
|
65
|
+
"projectName": "Acme Notes",
|
|
66
|
+
"prd": { "id": "PRD-001", "path": "rcf/prd.json" },
|
|
67
|
+
"tad": { "id": "TAD-001", "path": "rcf/tad.json" },
|
|
68
|
+
"bs": { "id": "BS-001", "path": "rcf/build-sequence.json" }
|
|
69
|
+
}
|
|
70
|
+
```
|
package/docs/prd.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# prd.schema.json
|
|
2
|
+
|
|
3
|
+
Product Requirements Document. One per project. Pure shell document; REQ bodies live in [req.schema.json](./req.md) files and each REQ carries the mandatory `prdId` back-reference. The walker computes the PRD's requirement list by inverting `REQ.prdId` at load time.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/prd.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `prdId` | `^PRD-\d{3,}$` | The PRD identifier. |
|
|
14
|
+
| `productName` | string, min 1 | Human-readable product name. |
|
|
15
|
+
| `version` | semver string | Per-document version, independent of the schema bundle's. |
|
|
16
|
+
| `status` | `authoringStatus` enum | `draft`, `review`, `needsRevision`, `approved`, `superseded`. |
|
|
17
|
+
| `problemStatement` | string, min 1 | One-paragraph framing of the problem the product solves. |
|
|
18
|
+
| `objectives` | array, min 1 | Outcomes the product is judged on. |
|
|
19
|
+
| `createdAt` | ISO 8601 date-time | First creation. |
|
|
20
|
+
| `updatedAt` | ISO 8601 date-time | Last update. |
|
|
21
|
+
|
|
22
|
+
## Optional fields
|
|
23
|
+
|
|
24
|
+
| Field | Type | Purpose |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `executiveSummary` | string | One-paragraph summary above the fold. |
|
|
27
|
+
| `targetUsers` | array of strings | The user populations the product addresses. |
|
|
28
|
+
| `inScope` | array of strings | What is included in this product. |
|
|
29
|
+
| `outOfScope` | array of strings | What is deliberately left out, to head off scope creep. |
|
|
30
|
+
| `constraints` | array of strings | Hard limits (budget, technology, regulatory). |
|
|
31
|
+
|
|
32
|
+
## What's NOT here
|
|
33
|
+
|
|
34
|
+
- **REQ bodies.** The PRD is a shell. REQ content lives in [req.schema.json](./req.md) files; each REQ carries the mandatory `prdId` back-reference. The walker inverts these to produce the PRD's requirement list.
|
|
35
|
+
- **`requirementIds[]`.** Removed in 0.2.0; parents no longer store child lists.
|
|
36
|
+
- **Architecture.** That belongs in [tad.schema.json](./tad.md).
|
|
37
|
+
- **Test suites.** Those live per US, see [test-suite.schema.json](./test-suite.md).
|
|
38
|
+
|
|
39
|
+
## Example
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"prdId": "PRD-001",
|
|
44
|
+
"productName": "Acme Notes",
|
|
45
|
+
"version": "0.1.0",
|
|
46
|
+
"status": "draft",
|
|
47
|
+
"problemStatement": "Users keep losing track of meeting notes scattered across tools.",
|
|
48
|
+
"objectives": ["Single home for personal notes across devices."],
|
|
49
|
+
"createdAt": "2026-01-01T00:00:00Z",
|
|
50
|
+
"updatedAt": "2026-01-01T00:00:00Z"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Fuller and minimal valid examples: `fixtures/valid/prd/`. Invalid examples illustrating common rejection cases: `fixtures/invalid/prd/`.
|
|
55
|
+
|
|
56
|
+
## Traceability
|
|
57
|
+
|
|
58
|
+
A PRD is the root of the requirements chain.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
PRD -> REQ -> US -> AC -> TS -> TC
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Each REQ carries `prdId`; the walker inverts these into a `childrenByParent` map to walk PRD -> REQ. Each US in turn carries `reqId` for the next hop.
|
package/docs/req.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# req.schema.json
|
|
2
|
+
|
|
3
|
+
Individual Requirement within a PRD. One file per REQ. Recommended path: `rcf/requirements/REQ-001.json`.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/req.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `reqId` | `^REQ-\d{3,}$` | This requirement's identifier. |
|
|
14
|
+
| `prdId` | `^PRD-\d{3,}$` | The parent PRD. |
|
|
15
|
+
| `title` | string, min 1 | One-line title. |
|
|
16
|
+
| `description` | string, min 1 | One-paragraph description. |
|
|
17
|
+
| `category` | enum: `functional`, `nonFunctional`, `technical`, `security` | Per-doc-type enum; lives local to this schema. |
|
|
18
|
+
| `domain` | string, min 1 | Free-form domain label (`auth`, `sync`, `billing`, etc.). Authors pick conventions per project. |
|
|
19
|
+
| `priority` | enum: `must`, `should`, `could`, `wont` | MoSCoW. |
|
|
20
|
+
| `version` | semver string | Per-document version. |
|
|
21
|
+
| `status` | `authoringStatus` enum | `draft`, `review`, `needsRevision`, `approved`, `superseded`. |
|
|
22
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
23
|
+
|
|
24
|
+
## Optional fields
|
|
25
|
+
|
|
26
|
+
| Field | Type | Purpose |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `rationale` | string | Why this REQ exists. |
|
|
29
|
+
| `tags` | array of strings | Free-form tags for grouping or filtering. |
|
|
30
|
+
|
|
31
|
+
## Why REQ is its own file
|
|
32
|
+
|
|
33
|
+
REQs grow over time, and a single PRD can carry hundreds. Inline REQ bodies on the PRD shell hit the GitHub API 1 MB file-fetch limit on rich PRDs and create merge-conflict pressure on the PRD whenever any REQ is edited. One file per REQ gives per-REQ git history, parallel-safe authoring, and a shell PRD that stays small. Same reasoning as ADR-per-file, TAC-per-file, FBS-per-file, US-per-file.
|
|
34
|
+
|
|
35
|
+
## Cross-doc consistency
|
|
36
|
+
|
|
37
|
+
The schema validates each REQ in isolation. Whether the `prdId` back-reference resolves to a loaded PRD is a walker-time referential-integrity check (Phase 5 traceability in `rcf-build-lite`), not a schema one.
|
|
38
|
+
|
|
39
|
+
## Example
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"reqId": "REQ-001",
|
|
44
|
+
"prdId": "PRD-001",
|
|
45
|
+
"title": "Capture markdown notes",
|
|
46
|
+
"description": "The system must let a user write a markdown note and persist it.",
|
|
47
|
+
"category": "functional",
|
|
48
|
+
"domain": "capture",
|
|
49
|
+
"priority": "must",
|
|
50
|
+
"version": "0.1.0",
|
|
51
|
+
"status": "draft",
|
|
52
|
+
"createdAt": "2026-01-01T00:00:00Z",
|
|
53
|
+
"updatedAt": "2026-01-01T00:00:00Z"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Fuller example in `fixtures/valid/req/req-002-comprehensive.json`; invalid cases in `fixtures/invalid/req/`.
|
package/docs/tac.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# tac.schema.json
|
|
2
|
+
|
|
3
|
+
Technical Architecture Component. One file per architectural component. Verbose per-component descriptions are fine; the schema does not constrain length.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/tac.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `tacId` | `^TAC-\d{3,}$` | This component's identifier. |
|
|
14
|
+
| `prdId` | `^PRD-\d{3,}$` | Root PRD. |
|
|
15
|
+
| `tadId` | `^TAD-\d{3,}$` | Parent TAD. |
|
|
16
|
+
| `version` | semver | Per-document version. |
|
|
17
|
+
| `status` | `authoringStatus` enum | Lifecycle status. |
|
|
18
|
+
| `name` | string, min 1 | Human-readable component name. |
|
|
19
|
+
| `purpose` | string, min 1 | One-paragraph statement of what this component is for. |
|
|
20
|
+
| `responsibilities` | array of strings, min 1 | What the component owns. |
|
|
21
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
22
|
+
|
|
23
|
+
## Optional fields
|
|
24
|
+
|
|
25
|
+
| Field | Type | Purpose |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `internalStructure` | string | Module breakdown, sub-component shape, key data types described in prose. |
|
|
28
|
+
| `interfaces` | array of `interfaceDef` | What the component exposes (APIs, events, CLIs, web components, daemons, etc.). |
|
|
29
|
+
| `dependencies` | array of `dependencyRef` | What this component depends on (other TACs or external systems). |
|
|
30
|
+
| `tradeoffs` | string | Design trade-offs accepted. |
|
|
31
|
+
| `notes` | string | Free-form notes the schema has no opinion on. |
|
|
32
|
+
|
|
33
|
+
## Sub-schemas
|
|
34
|
+
|
|
35
|
+
### `interfaceDef`
|
|
36
|
+
|
|
37
|
+
Required: `name`, `kind`. Optional: `description`.
|
|
38
|
+
|
|
39
|
+
`kind` is an **open string**, not an enum. Enumerating every kind of interface a component can expose (api, event, library, cli, SPA, web component, cron, daemon, microservice, batch...) is doomed; heavy `"other"` use in a closed enum signals the enum doesn't fit. The open string preserves the field for implementation-level filtering without imposing a brittle constraint.
|
|
40
|
+
|
|
41
|
+
### `dependencyRef`
|
|
42
|
+
|
|
43
|
+
Required: `name`, `kind`. Optional: `tacId` (when `kind` is `tac`), `description`.
|
|
44
|
+
|
|
45
|
+
`kind` IS a closed enum here: `tac` (internal TAC-to-TAC dependency) or `external` (third-party services, libraries, infrastructure). The internal/external split is genuinely binary at the schema level, so the enum fits.
|
|
46
|
+
|
|
47
|
+
## Example
|
|
48
|
+
|
|
49
|
+
See `fixtures/valid/tac/tac-002-comprehensive.json` for a fuller TAC with multiple interfaces, mixed internal and external dependencies, and trade-offs called out.
|
package/docs/tad.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# tad.schema.json
|
|
2
|
+
|
|
3
|
+
Master Technical Architecture Document. One per project. Pure shell for cross-cutting concerns; TAC and ADR each carry the mandatory `tadId` back-reference. The walker computes the TAD's component and decision lists by inverting `TAC.tadId` and `ADR.tadId` at load time. The schema defines the FULL set of possible sections; what's required for a given project is a tooling decision.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/tad.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `tadId` | `^TAD-\d{3,}$` | TAD identifier. |
|
|
14
|
+
| `prdId` | `^PRD-\d{3,}$` | Root PRD. |
|
|
15
|
+
| `version` | semver | Per-document version. |
|
|
16
|
+
| `status` | `authoringStatus` enum | Lifecycle status. |
|
|
17
|
+
| `systemOverview` | object | See sub-schema below. |
|
|
18
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
19
|
+
|
|
20
|
+
## Optional sections (all top-level)
|
|
21
|
+
|
|
22
|
+
When present, each section's own required fields apply.
|
|
23
|
+
|
|
24
|
+
| Field | When useful |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `architecturePrinciples` | If the project codifies design principles. |
|
|
27
|
+
| `dataArchitecture` | For systems with non-trivial data stores or flows. |
|
|
28
|
+
| `integrationArchitecture` | For systems with external APIs or events. |
|
|
29
|
+
| `securityArchitecture` | For systems with non-trivial auth or threat models. |
|
|
30
|
+
| `deploymentArchitecture` | For systems with deployment topology worth describing. |
|
|
31
|
+
| `operationalConcerns` | For long-running services. |
|
|
32
|
+
|
|
33
|
+
## Sub-schemas (in `$defs`)
|
|
34
|
+
|
|
35
|
+
### `systemOverview` (required)
|
|
36
|
+
|
|
37
|
+
`executiveSummary`, `systemPurpose`, `architecturalApproach`, `keyCapabilities[]` (all required, non-empty).
|
|
38
|
+
|
|
39
|
+
### `principle`
|
|
40
|
+
|
|
41
|
+
Used inside `architecturePrinciples[]`. Required: `name`, `description`, `rationale`.
|
|
42
|
+
|
|
43
|
+
### `dataArchitecture`
|
|
44
|
+
|
|
45
|
+
Required: `dataStores[]` (each `{name, kind, purpose?}`), `coreEntities[]` (each `{name, description?}`). Optional: `dataFlow`, `retention`.
|
|
46
|
+
|
|
47
|
+
### `integrationArchitecture`
|
|
48
|
+
|
|
49
|
+
Required: `apiDesign`. Optional: `externalSystems[]`, `eventModel`.
|
|
50
|
+
|
|
51
|
+
### `securityArchitecture`
|
|
52
|
+
|
|
53
|
+
Required: `authenticationPattern`, `authorizationModel`. Optional: `secretsManagement`, `threatModel`, `complianceRequirements[]`.
|
|
54
|
+
|
|
55
|
+
### `deploymentArchitecture`
|
|
56
|
+
|
|
57
|
+
Required: `targetEnvironment`. Optional: `topology`, `scaling`, `cicd`.
|
|
58
|
+
|
|
59
|
+
### `operationalConcerns`
|
|
60
|
+
|
|
61
|
+
Required: `healthChecks`, `logging`. Optional: `metrics`, `alerting`, `backup`, `disasterRecovery`.
|
|
62
|
+
|
|
63
|
+
## TAD decomposition
|
|
64
|
+
|
|
65
|
+
TAD + TAC + ADR is intentional. The v1 monolithic TAD ran to thousands of lines and produced useless git history. Decomposition gives:
|
|
66
|
+
|
|
67
|
+
- **TAD** - project-wide architecture (overview + cross-cutting concerns).
|
|
68
|
+
- **TAC** (`tac.schema.json`) - one per architectural component, verbose descriptions OK. Each TAC carries `tadId`.
|
|
69
|
+
- **ADR** (`adr.schema.json`) - one per architectural decision, one file each (Nygard convention). Each ADR carries `tadId`.
|
|
70
|
+
|
|
71
|
+
## What's NOT here
|
|
72
|
+
|
|
73
|
+
- **Component bodies.** Live in [tac.schema.json](./tac.md); each TAC carries the mandatory `tadId` back-reference. The walker inverts these to produce the TAD's TAC list.
|
|
74
|
+
- **Decision bodies.** Live in [adr.schema.json](./adr.md); each ADR carries the mandatory `tadId` back-reference. The walker inverts these to produce the TAD's ADR list.
|
|
75
|
+
- **`componentIds[]` and `architecturalDecisionIds[]`.** Removed in 0.2.0; parents no longer store child lists.
|
|
76
|
+
- **Generation metadata.** LLM call counts, token usage, generation timestamps belong to tooling (e.g. `.rcf/generation-log.json` sidecar). The schema describes the document only.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# test-suite.schema.json
|
|
2
|
+
|
|
3
|
+
Test Suite. One file per Test Suite. The JSON specification of what Test Cases exist for one or more Acceptance Criteria on a single User Story.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/test-suite.schema.json`
|
|
8
|
+
|
|
9
|
+
## TS-as-JSON: what this schema is for
|
|
10
|
+
|
|
11
|
+
The TS schema validates the *specification* of the test cases (id, description, AC covered, authored status). It is the **contract for the test-writer** (human or AI). The executable test (Jest, pytest, JUnit, ...) is the *implementation* of that spec; the optional `testCase.testPointer` field points to the executable location.
|
|
12
|
+
|
|
13
|
+
The JSON form is what lets Phase 5 traceability tooling walk `AC -> TS -> TC` programmatically, without parsing source-language test code. Whether the executable test file matches its TS spec is a separate concern (a test-of-the-test, owned by Phase 5 or the test-writer's own discipline).
|
|
14
|
+
|
|
15
|
+
## TS file location
|
|
16
|
+
|
|
17
|
+
Recommended path under the RCF tree: `rcf/test-suites/ts-001.json`. The schema validates the JSON shape; location is an implementation choice and is not enforced by schema or enumerated by manifest.
|
|
18
|
+
|
|
19
|
+
## Required fields
|
|
20
|
+
|
|
21
|
+
| Field | Type | Notes |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `id` | `^TS-\d{3}$` | Test Suite identifier. Sequential, not parent-grouped (a US can have multiple TSs across levels). |
|
|
24
|
+
| `usId` | `^US-\d{3,}$` | Parent User Story. Mandatory back-reference. |
|
|
25
|
+
| `title` | string, min 1 | Human-readable suite title. |
|
|
26
|
+
| `purpose` | string, min 1 | One-paragraph "what this suite is testing and why". |
|
|
27
|
+
| `testLevel` | enum | `unit`, `integration`, `e2e`, `contract`, `manual`. |
|
|
28
|
+
| `acIds` | array of `acId`, min 1 | The ACs this suite verifies. TS holds the reference; ACs stay clean of downstream references. |
|
|
29
|
+
| `testCases` | array of `testCase`, min 0 | Inline TCs. Empty array allowed (a suite may be a purpose-only skeleton pre-authoring). |
|
|
30
|
+
| `status` | `authoringStatus` enum | Lifecycle status of the suite itself. |
|
|
31
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
32
|
+
|
|
33
|
+
## Test case shape
|
|
34
|
+
|
|
35
|
+
Each entry in `testCases[]`:
|
|
36
|
+
|
|
37
|
+
| Field | Type | Required | Purpose |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| `id` | `^TC-\d{3}-[a-z0-9-]+$` | yes | TC identifier. `TC-<TS-suffix>-<slug>`; slug is a lowercase alphanumeric identifier (hyphens allowed). Slug uniqueness is within-TS, not global. |
|
|
40
|
+
| `acId` | `^AC-\d{3,}(-\d+)?$` | yes | Which AC on the parent US this TC verifies. |
|
|
41
|
+
| `description` | string, min 1 | yes | What the TC covers. |
|
|
42
|
+
| `testPointer` | string | no | Pointer to the executable test, `filePath::testName` format. |
|
|
43
|
+
| `status` | enum | yes | `pending`, `passing`, `failing`, `skipped`. Authored in 0.2.0; derived from real test runs in Phase 6+. |
|
|
44
|
+
|
|
45
|
+
## What changed in 0.2.0
|
|
46
|
+
|
|
47
|
+
The 0.1.0 shape was per-AC (`acId` + `prdId` + `version` + `testCases[given/when/then]`). 0.2.0 makes the suite per-US-and-across-ACs, keeps the TS id in `common.schema.json` (`tsId`), and moves the Given/When/Then verbiage into the TC's `description` (specialised BDD-style step language belongs in the executable test, not the JSON spec).
|
|
48
|
+
|
|
49
|
+
## What's NOT here
|
|
50
|
+
|
|
51
|
+
- **`given/when/then` on the TC.** The `description` field carries the intent; the executable test carries the BDD step language.
|
|
52
|
+
- **`prdId` on the TS.** Removed in 0.2.0. Walk `usId` -> `US.reqId` -> `REQ.prdId` if you need the PRD.
|
|
53
|
+
|
|
54
|
+
## Why TCs stay nested
|
|
55
|
+
|
|
56
|
+
A TC outside its TS (and its AC) is meaningless. TCs are small; inline is the natural shape. `testPointer` links out to the executable location without hoisting the TC into a separate file.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# user-story.schema.json
|
|
2
|
+
|
|
3
|
+
User Story document. One file per US. Contains Acceptance Criteria inline as `acceptanceCriteria[]`.
|
|
4
|
+
|
|
5
|
+
## Canonical `$id`
|
|
6
|
+
|
|
7
|
+
`https://schemas.stravica.io/rcf/v0.2.0/user-story.schema.json`
|
|
8
|
+
|
|
9
|
+
## Required fields
|
|
10
|
+
|
|
11
|
+
| Field | Type | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `usId` | `^US-\d{3,}$` | This story's identifier. |
|
|
14
|
+
| `prdId` | `^PRD-\d{3,}$` | The root PRD. |
|
|
15
|
+
| `reqId` | `^REQ-\d{3,}$` | The parent REQ. |
|
|
16
|
+
| `version` | semver | Per-document version. |
|
|
17
|
+
| `status` | `authoringStatus` enum | Lifecycle status. |
|
|
18
|
+
| `title` | string, min 1 | One-line title. |
|
|
19
|
+
| `asA` | string, min 1 | "As a {asA}..." |
|
|
20
|
+
| `iWant` | string, min 1 | "...I want {iWant}..." |
|
|
21
|
+
| `soThat` | string, min 1 | "...so that {soThat}." |
|
|
22
|
+
| `acceptanceCriteria` | array of `acceptanceCriterion`, min 1 | The testable conditions for this story. |
|
|
23
|
+
| `createdAt` / `updatedAt` | ISO 8601 date-time | Lifecycle timestamps. |
|
|
24
|
+
|
|
25
|
+
## Optional fields
|
|
26
|
+
|
|
27
|
+
| Field | Type | Purpose |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `description` | string | Additional narrative beyond the asA / iWant / soThat triple. |
|
|
30
|
+
|
|
31
|
+
## Acceptance criterion shape
|
|
32
|
+
|
|
33
|
+
Each AC inside `acceptanceCriteria[]`:
|
|
34
|
+
|
|
35
|
+
| Field | Type | Required | Purpose |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `id` | `acId` | yes | `AC-201` (flat) or `AC-101-1` (hierarchical). |
|
|
38
|
+
| `description` | string, min 1 | yes | One-line description. |
|
|
39
|
+
| `given` | string | no | Given/When/Then preamble. |
|
|
40
|
+
| `when` | string | no | Trigger. |
|
|
41
|
+
| `then` | string | no | Observable outcome. |
|
|
42
|
+
| `testable` | boolean | yes | Author declares the AC is testable. |
|
|
43
|
+
|
|
44
|
+
The Given/When/Then triple is optional at the schema level so non-Gherkin teams aren't forced into it; the `testable` boolean is required to make authors stop and confirm the AC can actually be tested.
|
|
45
|
+
|
|
46
|
+
## Why ACs stay nested
|
|
47
|
+
|
|
48
|
+
An AC outside its US is meaningless, the AC's Given/When/Then only makes sense in the context of the asA / iWant / soThat triple. Splitting would multiply file counts 5-10x with no benefit. Granular ids (`AC-101-1`) keep cross-doc references precise.
|
|
49
|
+
|
|
50
|
+
## Example
|
|
51
|
+
|
|
52
|
+
See `fixtures/valid/user-story/us-002-hierarchical-acs.json` for a US with three Given/When/Then ACs in the `AC-101-N` hierarchical form.
|
|
53
|
+
|
|
54
|
+
## AC id form: flat or hierarchical
|
|
55
|
+
|
|
56
|
+
The pattern `^AC-\d{3,}(-\d+)?$` accepts both:
|
|
57
|
+
|
|
58
|
+
- **Flat** (`AC-001`, `AC-201`) - fine for projects with a single numeric space.
|
|
59
|
+
- **Hierarchical** (`AC-101-1`, `AC-101-2`) - encodes the parent US id, useful for FBS scope queries and grep.
|
|
60
|
+
|
|
61
|
+
Pick per project; the schema does not enforce either.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-001",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "x",
|
|
8
|
+
"context": "y",
|
|
9
|
+
"decision": "z",
|
|
10
|
+
"consequences": "w",
|
|
11
|
+
"createdAt": "2026-01-01T00:00:00Z",
|
|
12
|
+
"updatedAt": "2026-01-01T00:00:00Z"
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-001",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"status": "superseded",
|
|
7
|
+
"title": "x",
|
|
8
|
+
"context": "y",
|
|
9
|
+
"decision": "z",
|
|
10
|
+
"consequences": "w",
|
|
11
|
+
"supersededBy": "TAC-002",
|
|
12
|
+
"createdAt": "2026-01-01T00:00:00Z",
|
|
13
|
+
"updatedAt": "2026-01-01T00:00:00Z"
|
|
14
|
+
}
|