← RCF

Concept

The document chainCopy link

A Y-shape, not a line. Intent comes down the left arm, architecture down the right, and the two meet at the build chain. Each layer points up to what justifies it, down to what proves it, and out to the code that implements it.

Last updated

The RCF document chain is the set of linked artefacts that runs from product intent to working code: one arm carries intent (PRD, requirements, user stories, acceptance criteria), the other carries architecture (TAD, components, ADRs), and they meet at the build. Every artefact points at its neighbours, so the chain is walkable in both directions.

Most software documentation is shaped wrong. There’s usually too much of it, organised by who wrote it rather than by what it’s for, and the connections between documents are stored in people’s heads instead of on the page. By the time you need to ask “why does this function exist,” half the relevant documents have rotted past usefulness and the other half are describing a version of the product that was deprecated six months ago.

RCF’s document chain is the set of artefacts that closes that gap, with the relationships between them made explicit. The chain has two upstream arms that meet at the build:

The intent arm The architecture arm
PRD → requirements → user stories → acceptance criteria TAD → components → ADRs
What must be true The system in which it must be true

The two arms converge at the build chain: build sequence → functional build specification. From there, each in-scope acceptance criterion runs two short lanes side by side: a test suite (and its test cases) that proves it, and a code node that implements it. The FBS is the explicit join point. It pulls in the in-scope ACs from the intent arm and the in-scope TAD components and ADRs from the architecture arm, and turns the two into a buildable slice. This is also the point in the chain where spec-driven development (SDD) typically starts; RCF inherits SDD’s spec-as-primary-artefact framing but anchors the spec earlier, in the requirements layer of the intent arm, so the spec-of-intent runs from PRD all the way through to the FBS rather than appearing only at the build boundary.

The artefacts the chain is built from are listed below in reading order. The PRD and TAD originate upstream of RCF as currently scoped. The scoping page covers what that means and what work is coming to address it. From the PRD-and-TAD-agreed point onwards, the chain runs the same shape on every project.

The RCF document chain A Y-shaped diagram of the RCF document chain. Two upstream arms converge at the build chain. The intent arm runs down the left: PRD (product requirements document), REQ (requirement), US (user story), AC (acceptance criterion). The architecture arm runs down the right: TAD (technical architecture document), TAC (technical architecture component), ADR (architectural decision record). Both arms converge at the FBS (functional build specification), shown in signal-filled treatment as the load-bearing join. The build sequence sits above the FBS, the directed acyclic graph that orchestrates which FBS runs next. Below the FBS the test lane runs through the proof artefacts: TS (test suite, one per AC) and TC (test case). The acceptance criterion is a fork: a second lane leaves it for CN (code node), the eleventh and newest RCF document kind. CN is the source code that implements the AC; it sits alongside the chain, anchored to the AC, level with the test suite, not appended after the test case. Each card carries its document type acronym and its ID-prefix format. PRD. Product requirements document. The top of the intent arm. One per product. States what the product is, who it is for, what it does, and what it deliberately does not. PRD PRD-01 REQ. Requirement. An atomic, testable statement of what the product must do. Listed inside the PRD; each REQ breaks down into one or more user stories. REQ REQ-01 US. User story. The human shape of a requirement. As a role, I want an action, so that an outcome. Carries one or more acceptance criteria. US US-01 AC. Acceptance criterion. A Given/When/Then sentence: the contract for done. The fork in the chain: one test suite is built from the AC text, one to one, and the code that implements the AC anchors to it too, which several code nodes may do. AC AC-01-01 TAD. Technical architecture document. The top of the architecture arm. Sibling to the PRD; describes the services, data stores, integrations, and cross-cutting decisions the product needs to live in. TAD TAD-01 TAC. Technical architecture component. A named moving part of the architecture: a service, a data store, a queue, an integration, a shared module. TACs carry their own IDs and are referenced from FBSs by ID, the way ACs are. TAC TAC-01 ADR. Architectural decision record. Captures one consequential choice: context, decision, alternatives, consequences. References the TAD and the components it constrains. FBSs reference ADRs as build context. ADR ADR-01 Build sequence. The directed acyclic graph of FBSs. Each node is one functional build specification; each edge is a dependency. The build sequence orchestrates which FBS runs next. Build sequence FBS. Functional build specification. The convergence point. Pulls the in-scope ACs from the intent arm and the in-scope TAD components and ADRs from the architecture arm, plus the surrounding context the worker needs, and turns the two arms into one buildable slice. FBS FBS-01 TS. Test suite. One per AC; the implementation of the criterion in code. Contains the test cases that together prove the criterion is met. TS TS-01-01 TC. Test case. One scenario inside a test suite: a happy path, a named edge case, a failure mode. TC TC-01-01 CN. Code node. The eleventh and newest RCF document kind, added to bridge the chain to source code. It forks off the acceptance criterion through implementsAcIds; its identity is the file path, optionally a symbol, not a parent slot. rcf validate walks the link, so a rename or move that breaks it surfaces as a stale edge. The link to an AC may be empty, which is a legitimate state for utility or glue code. CN CN-01 The RCF document chain (Y-shape, narrow layout) A narrow-viewport rendering of the RCF document chain Y-shape. Intent arm down the left (PRD, REQ, US, AC); architecture arm down the right (TAD, TAC, ADR); both converge at the FBS in the centre. The build sequence pill sits above the FBS. Below the FBS the diagram forks: the test lane runs TS then TC on the right, and a code lane forks off the acceptance criterion to CN (code node), the eleventh RCF document kind and the source code that implements the AC, sitting alongside the chain rather than after the test case. PRD. Product requirements document. The top of the intent arm. PRD PRD-01 REQ. Requirement. Atomic, testable statement inside the PRD. REQ REQ-01 US. User story. The human shape of a requirement. US US-01 AC. Acceptance criterion. The contract for done, and the fork: the test suite and the code that implements it both anchor here. AC AC-01-01 TAD. Technical architecture document. Top of the architecture arm. TAD TAD-01 TAC. Technical architecture component. A named moving part of the architecture, referenced from FBSs by ID. TAC TAC-01 ADR. Architectural decision record. Captures one consequential choice. ADR ADR-01 Build sequence. The DAG of FBSs; picks which FBS runs next. Build sequence FBS. Functional build specification. The convergence point. Pulls in-scope ACs, components, and ADRs into a single buildable slice. FBS FBS-01 TS. Test suite. One per AC. TS TS-01-01 TC. Test case. One scenario inside a test suite. TC TC-01-01 CN. Code node. The eleventh RCF document kind; the source code that implements the AC, forked off it through implementsAcIds and walked by rcf validate, so a rename or move that breaks the link surfaces as a stale edge. CN CN-01
Intent & architecture → FBS → tests  ·  AC → CN

The intent armCopy link

PRD: the productCopy link

The product requirements document sits at the top of the intent arm. It says what the product is, who it’s for, what it does, and what it deliberately doesn’t. The out-of-scope section is a record of decisions the team took to leave certain things out: items the team considered and deliberately chose not to do, with the reasoning attached. That’s different from a defence against change. Scope decisions don’t survive a six-month project intact. They get revisited, sometimes reversed, and they should. The out-of-scope record makes the reversal a deliberate act, with an audit trail of what changed and why, rather than a quiet drift the team rationalises later.

Inside the PRD lives the requirements list. Each requirement is a short statement of what the product must do, with a category (functional, non-functional, regulatory), a priority (must, should, could), and a domain (auth, billing, search, whatever the product is made of). Requirements aren’t where you describe how something works. They’re where you commit to what works.

User stories: the human shape of a requirementCopy link

A requirement on its own is hard to build against. It’s a statement of intent, not a description of behaviour. So each requirement breaks down into user stories, the familiar “as a [role] I want [action] so that [outcome]” shape.

The story’s job is to give the requirement a human shape. A requirement that says “the product supports OAuth sign-in” might break into stories about first-time signup, returning sign-in, account linking, and sign-out, each with its own actor and outcome. The stories are what a product owner thinks in. The requirement is what they commit to.

Acceptance criteria: the contractCopy link

Each story carries one or more acceptance criteria. The AC is where things get specific. A criterion is a Given/When/Then sentence: given a precondition, when an event happens, then an observable thing must be true. AC text is what tests are built from, one to one.

ACs are the central primitive of the methodology, and they get their own page: Acceptance criteria as the contract. The short version is that AC is the layer at which intent becomes verifiable. Most ACs are verified by an automated test suite, and that’s the default the methodology is built around. A few land on a human-attested check instead: a k8s cluster following a naming convention, a deployed manifest matching a target shape, anything where the verification step is a human reviewer reading a real artefact against the rule. The rule is verifiability, not test-automation. If the criterion can’t be verified at all, it isn’t a real AC.

The architecture armCopy link

The architecture arm runs in parallel to the intent arm and produces the system the requirements have to be true in. Same Y-shape, same chain discipline, different content.

TAD: the system the requirements needCopy link

The technical architecture document is the top of the architecture arm. It describes the systems and components the product needs: services, data stores, external integrations, the cross-cutting decisions about how data flows and where state lives. One per product, sibling to the PRD.

The TAD’s job is to make sure that when somebody builds a slice, they build it against a system that exists. It does for the architecture what the PRD does for intent: it’s the artefact that the rest of the arm hangs from.

TAD components: the moving partsCopy link

Under the TAD sit its components: the named services, data stores, queues, integrations, and shared modules the architecture is made of. Each one is a technical architecture component, with its own opaque ID prefixed TAC-, so it sits next to TAD and ADR in the chain’s ID scheme rather than under an ad-hoc letter of its own. TACs get referenced from FBSs by ID, the same way ACs do. A TAC is the architecture-arm equivalent of a story on the intent arm: the named unit the build slice depends on.

ADRs: the decisions that shaped the systemCopy link

Architectural Decision Records sit at the bottom of the architecture arm. Each ADR captures one consequential choice: the context, the decision, the alternatives considered, the consequences. All in a form that survives the conversation that produced it. ADRs reference the TAD they sit under and the components they constrain. FBSs reference them as build context the worker needs. The ADR pages are at architectural decisions.

The build chainCopy link

Both arms feed into the build chain. The FBS is the explicit join: it takes the in-scope ACs from the intent arm and the in-scope TAD components and ADRs from the architecture arm, and turns them into a slice the agent or team can build. From the FBS downwards, the chain is linear again.

Build sequence: the planCopy link

The build sequence is the directed acyclic graph that gets you from nothing to shipped. Each node on the graph is a functional build specification, a slice of the product you can build, test, and ship in one go. Each edge is a dependency: this FBS can’t start until that one is done.

Sequencing matters more than people think. A well-shaped build sequence ships vertical slices that prove the product works end to end as soon as possible. A badly-shaped one ships horizontal layers that look like progress on a status report but produce no shippable behaviour for weeks. The build sequence is where that gets decided.

Functional build specification: where the arms meetCopy link

A functional build specification is the brief the worker actually executes against, and the explicit convergence point of the two arms. It pulls together both sides into one buildable slice. From the intent arm: which stories and ACs are in scope, which PRD sections the worker needs to read. From the architecture arm: which TAD components and ADRs the slice depends on, which modules and schemas the work will touch. Plus the surrounding context the worker needs to do the slice well: dependencies on other FBSs that must finish first, the relevant business patterns, standards, style guidelines, and instructions.

The FBS carries a list of testable outcomes, which is the restatement of the in-scope ACs in the worker’s terms. The testable outcomes are the AC-level commitments the slice will be marked against; they’re what makes the AC text actionable inside one build cycle.

The FBS is also where the build context lives: the curated set of references that a worker (human or agent) needs to do the slice without grepping for orientation. That context isn’t a generic dump of the codebase. It’s the specific PRD sections, TAD components, ADRs, code modules, and external docs that the slice depends on. Getting this right is most of why AI agents do good work on RCF projects when they’d otherwise produce nonsense.

Test suite and test case: where intent becomes behaviourCopy link

Each acceptance criterion gets one test suite. One to one, no exceptions. The suite implements the criterion in code. The suite is made up of test cases, the individual scenarios that, together, prove the criterion is met: the happy path, the named edge cases, the failure modes.

The one-to-one rule between AC and suite is what makes traceability possible. Run a single command and you can ask “is AC-042-03 passing” or “which tests would I need to look at if requirement REQ-014 changed.” The answers are mechanical because the structure is mechanical.

Code nodes: where the chain reaches the codeCopy link

Everything to this point stops at the spec. The test suite proves an acceptance criterion in code, but the chain has no handle on the source file that actually implements it. A code node is that handle, and it is the eleventh RCF document kind: the one that reaches past the test suite into the source itself.

A code node forks off the acceptance criterion, alongside the test suite rather than after the test case. Where the suite is the lane that proves the AC, the code node is the lane that implements it. Its identity is a path, src/store/validator.js, optionally narrowed to a symbol with src/store/validator.js#getAjv, and it names the ACs it implements in an implementsAcIds field, the same way an FBS anchors through its ACs. This relationship isn’t one-to-one like AC and test suite. Several code nodes can implement one criterion, one node can implement several, and a node can implement none at all: a utility, a piece of glue, or wiring with no direct spec anchor is a normal, common state, not an error.

The question that usually follows: is the code node linked to the test case too? Deliberately not. The test case and the code node both anchor to the same acceptance criterion, and the tooling joins them through it; that is how coverage can report a criterion as implemented but uncovered (code exists, no test yet). A direct code-to-test edge would go stale every time a criterion change regenerated its tests, and it would say nothing the shared anchor doesn’t already say. The criterion is the contract; the test proves it, the code implements it, and they meet there.

What the code node buys you is that the source is now inside the graph. The same rcf validate that checks every spec pointer resolves also checks every code node’s path against the working tree. Move or delete the file, rename the symbol, and validation fails with a named staleCode error you fix in one field. There is an honest limit to it. A code node proves the path and the symbol still exist, not that the code behind them still does what the criterion says. It catches the refactor that breaks the link; it doesn’t catch the gutted function that keeps its name.

Reading the chain end to endCopy link

Start with a business decision. The product needs to support exporting user data. On the intent arm, that decision becomes REQ-019 in the PRD, functional, should-have, domain: privacy. REQ-019 generates US-088: as a user I want to download my data so that I can take it elsewhere. US-088 carries three acceptance criteria, AC-088-01 through AC-088-03, covering the happy path, the size cap, and the format.

On the architecture arm, TAD-001 establishes a background job service for long-running work, with ADR-014 recording the decision to route exports through it (alternatives considered: synchronous endpoint, separate worker pool). Components on the arm: the job service, the storage service, the identity service.

The two arms meet at FBS-051. The FBS’s storyScope is { US-088: [AC-088-01, AC-088-02, AC-088-03] }. Its buildContext points to TAD-001 Section 4 (Jobs), the storage service component, and ADR-014. The build sequence places FBS-051 after FBS-016, which stood up the job service. When a worker picks FBS-051 up, they have one document that names what must be true (the ACs) and what system it must be true in (the TAD components and ADR). They write three test suites, then they write the code and record its code nodes against the ACs, then everything goes green, then FBS-051 closes. REQ-019 is now satisfied, and the satisfaction is provable from the chain.

Reading the chain bottom up works just as well, and a code node makes it a command rather than a manual hunt. Point rcf trace at a function in the export handler and it resolves the path to its code node, then walks back: code node → the AC it implements → the story that holds the AC → the requirement the story serves → the business decision the requirement encodes. From the same starting point you can still cross into the architecture arm, through the FBS that named the slice: which TAD components the code is part of, which ADRs constrained how it was built. Each step is one hop, and each hop is mechanical.

Why this many layers and not fewerCopy link

The obvious objection is that this is a lot of layers. It is. The shorter version, requirement → test → code, would be cleaner, and now that a code node makes the code a real node on the chain, that shorthand is closer to literal than it used to be: requirement to test to code is three hops of one query. But the layers the shorthand skips are each there because the layer above and below can’t do its job otherwise.

On the intent arm: requirements need stories because a requirement is too abstract to test. Stories need ACs because a story is too vague to test directly. ACs need test suites because behaviour needs implementing in code, not in prose.

On the architecture arm: the TAD needs components because the system is made of named parts that get referenced individually. Components need ADRs because the consequential choices about each part need to outlive the conversation that produced them.

In the middle: the build sequence and FBS exist because somebody has to decide what gets built when, with what dependencies, drawing what from each arm, or the work fragments.

At the code end: the code node is there because a passing test and the code that passes it are two different claims. Without it, the source sits outside the graph, tied in only by an annotation string that a rename turns into a lie with nothing to catch it. The code node makes that link a node the validator walks, so a refactor that breaks it surfaces as a failure instead of a surprise.

Each layer is a place where one specific kind of decision gets made and pinned down. Compress the layers and decisions either get made in the wrong place, or stop getting made at all, or get made silently by the worker on the spot. None of those are decisions you want.

The chain is also context engineering at the team scale. Each layer is the context the next layer needs. The agent gets the right slice of intent at the right point in the build, instead of a generic dump of the codebase or a crammed prompt that hopes for the best. That’s the methodology earning its keep on the agent’s behalf as well as the team’s.

Vocabulary, ID schemes, and what to look up nextCopy link

Every document type has an ID. PRD-001. REQ-014. US-042. AC-042-03. TAD-001. TAC-007. ADR-014. FBS-027. TS-088-01. CN-006. The IDs are opaque strings, never renumbered, never reused. They’re how traceability happens at the system level: a test suite ID matches an AC ID, a work item ID points at an FBS ID. The code node is the one that carries a path as well as an ID, naming the AC IDs it implements and pointing at the source file that implements them, so the code is a node the chain can walk to rather than a string grep has to chase. The lookup key is still the ID.

A word about toolingCopy link

The chain runs on plain text. The methodology itself is JSON for the documents, markdown for the build specs, and git for the history. Git is the system of record: every artefact, every ID, every state change in the chain lives in commits, and the history of the project is the history of its requirements. Every ID-pointer relationship the chain depends on is greppable from a terminal.

In practice, that base layer needs a little help even for a basic implementation. A small CRUD CLI to query and validate the chain, and a handful of coding-agent commands to drive the build cycle, are the minimum: several artefact types with opaque IDs and one-to-one mappings across a two-hundred-FBS product isn’t a comfortable manual job, and the build cycle goes a lot smoother when the agent knows the stage names. Stravica publishes that CRUD layer as rcf-lite, an open Apache-2.0 package on npm that gives you the rcf CLI. Beyond it, the integration and enablement layer is wide open, anything up to a full generative agent that drafts artefacts against the standards and runs the diff against the gap. That’s where Stravica builds, because the leverage compounds at scale. The methodology is what’s stable; the tooling is how you make it tractable.

Full vocabulary is in the glossary. ID schemes per document type are catalogued on the document types page. For the next concept in the reading order, see Acceptance criteria as the contract.