On this page

Validate it · docs/validation/traceability-matrix.md

Traceability matrix

Document CS-VAL-05
Generated by node scripts/trace.ts from requirements.json and the test sources. Do not edit by hand.

Each user requirement (UR) is met by one or more functional requirements (FR); each functional requirement is verified by the automated tests or walkthrough steps whose names carry its identifier. Running the tests therefore produces the evidence for this matrix (see OQ protocol).

Requirements: 15 user, 115 functional. Unverified: 0.

UR-01

The system holds records of the types our business needs, with the fields we define, without programming.

Functional requirement Risk Statement Verified by In
FR-CFG-01 medium A configuration document is checked completely before use. automated test lib/engine.test.ts
FR-CFG-05 medium Without a configuration no record can be created. automated test lib/engine.test.ts
FR-HIER-01 medium A record type may nest inside itself and a parent may be optional; other cycles between types stay refused. automated test lib/engine.test.ts
FR-HIER-02 high No record becomes its own ancestor: on create, edit, approval and when an approval is revoked, pending changes included. automated test lib/engine.test.ts
FR-VAL-01 medium Required fields must be filled. automated test lib/engine.test.ts
FR-VAL-02 medium Values must have the field's type. automated test lib/engine.test.ts
FR-VAL-03 medium Numbers stay inside their range and text matches its pattern. automated test lib/engine.test.ts
FR-VAL-04 medium Unique fields are unique among records that are not removed, pending values included. automated test lib/engine.test.ts
FR-VAL-05 medium References must point at live records of the right type. automated test lib/engine.test.ts
FR-VAL-06 medium Fields the configuration does not know are refused. automated test lib/engine.test.ts
FR-VAL-07 medium Data is checked again when it is confirmed and when it is approved. automated test lib/engine.test.ts

UR-02

No change to a record takes effect until a second, authorised person has approved it.

Functional requirement Risk Statement Verified by In
FR-CFG-08 high A proposed configuration takes effect only when a different person with the configure permission approves it. automated test lib/engine.test.ts
FR-WF-01 high A new record starts as version 1, Created, with the next id of its type. automated test lib/engine.test.ts
FR-WF-02 high Only its author can edit a Created version, and the version number stays. automated test lib/engine.test.ts
FR-WF-03 high Only its author can confirm a version. automated test lib/engine.test.ts
FR-WF-04 high Four eyes: nobody approves a version they wrote or confirmed. automated test lib/engine.test.ts
FR-WF-05 high Approval needs the approve permission for the record type. automated test lib/engine.test.ts
FR-WF-06 high Only a Confirmed version can be approved, and the signature states its meaning. automated test lib/engine.test.ts
FR-WF-07 high A Confirmed version is locked against edits. automated test lib/engine.test.ts
FR-WF-08 high Step back moves one stage: Confirmed to Created, Approved to Confirmed. automated test lib/engine.test.ts
FR-WF-09 high Step back, retire, remove and changing an approved record need a reason. automated test lib/engine.test.ts

UR-03

Every version of every record is kept, and the approved version stays in effect until its successor is approved.

Functional requirement Risk Statement Verified by In
FR-VER-01 high Editing an approved record opens a new Confirmed version; the approved one stays in effect. automated test lib/engine.test.ts
FR-VER-02 high Once the new version is approved it is in effect and the old one is kept as superseded. automated test lib/engine.test.ts
FR-VER-03 high Revoking an approval brings the previous approved version back, or leaves none in effect. automated test lib/engine.test.ts

UR-04

Every action is recorded with who did it, when, what changed from what to what, and why; the record of actions cannot be changed or deleted.

Functional requirement Risk Statement Verified by In
FR-AUD-01 high Every command that succeeds writes exactly one complete entry. automated test lib/engine.test.ts
FR-AUD-02 high A refused command writes nothing and changes nothing. automated test lib/engine.test.ts
FR-AUD-03 high Entries are in time order: an action dated before the newest entry is refused. automated test lib/engine.test.ts
FR-AUD-04 high How the person was identified is part of the entry and of its hash. automated test lib/engine.test.ts
FR-STO-04 high The database itself refuses to change or delete entries. automated test server/server.test.ts

UR-05

Any alteration of the record of actions, by anyone including administrators, can be detected.

Functional requirement Risk Statement Verified by In
FR-CFG-12 high The waiting proposal is rebuilt by replay, and a trail written before proposals existed replays to the same hashes. automated test lib/engine.test.ts
FR-INT-01 high Every entry carries the hash of the one before it. automated test lib/engine.test.ts
FR-INT-02 high An entry changed after it was written is found. automated test lib/engine.test.ts
FR-INT-03 high A forged entry with a freshly computed hash is caught when its command is re-run. automated test lib/engine.test.ts
FR-INT-04 high A missing, reordered or inserted entry is found. automated test lib/engine.test.ts
FR-INT-05 high The hash does not depend on the order of keys a store returns. automated test lib/engine.test.ts
FR-INT-06 high Replaying a whole history reproduces the same state, for every demo domain. automated test lib/engine.test.ts

UR-06

People can only do what their role allows, per record type and per level.

Functional requirement Risk Statement Verified by In
FR-ACC-01 high A role writes only the record types and option levels it is given. automated test lib/engine.test.ts
FR-ACC-02 high A person without a role, or with roles the configuration does not know, can change nothing. automated test lib/engine.test.ts
FR-ACC-03 high Importing and configuring are separate permissions that "*" does not include. automated test lib/engine.test.ts

UR-07

People are identified by our identity provider; an approval is an electronic signature that requires the person to have authenticated recently.

Functional requirement Risk Statement Verified by In
FR-CFG-13 high Over HTTP one person proposes a configuration change and another approves it; the approval is a signature and needs a recent sign-in. automated test server/server.test.ts
FR-SIG-01 high A session cookie that was altered, re-signed with another key, or has expired is not accepted. automated test server/server.test.ts
FR-SIG-02 high Sign-in is the OpenID Connect code flow with PKCE, state and nonce, and yields a session. automated test server/server.test.ts
FR-SIG-03 high A sign-in answer that fails any check gives no session. automated test server/server.test.ts
FR-SIG-04 high Roles come from the token's claims, through the role map. automated test server/server.test.ts
FR-SIG-05 high A signature needs a recent sign-in: an approval with an old one is refused until the person signs in again. automated test server/server.test.ts
FR-SIG-06 high Nothing is readable or writable without signing in. automated test server/server.test.ts
FR-SIG-07 high Writes are accepted only from the application's own pages. automated test server/server.test.ts
FR-SIG-08 high The web interface cannot import or set a configuration in one step, and takes the actor only from the session. automated test server/server.test.ts
FR-SIG-09 high Behind an authenticating proxy, identity headers count only with the shared secret. automated test server/server.test.ts
FR-SIG-10 high Demo sign-in exists only when it is switched on explicitly. automated test server/server.test.ts

UR-08

Settings can be defined once and set at any level of the hierarchy; for every record it is clear which value applies and where it comes from.

Functional requirement Risk Statement Verified by In
FR-HIER-03 high Options are inherited down every level of a nested branch: the nearest ancestor wins, then the levels above, then the default. automated test lib/engine.test.ts
FR-OPT-01 medium An option definition must be consistent: type, choices, range, default. automated test lib/engine.test.ts
FR-OPT-02 medium Option names are unique. automated test lib/engine.test.ts
FR-OPT-03 medium An option value fits its definition, is set once per record, and keeps its target. automated test lib/engine.test.ts
FR-OPT-04 medium The effective value is the most specific approved one, with its source. automated test lib/engine.test.ts
FR-OPT-05 medium Only approved, active values count; pending changes are reported beside them. automated test lib/engine.test.ts
FR-OPT-06 medium A definition cannot change in a way that strands values in use. automated test lib/engine.test.ts
FR-OPT-07 medium An approved value that no longer fits its definition is skipped and reported, not applied. automated test lib/engine.test.ts

UR-09

Records can be taken out of use without losing their history.

Functional requirement Risk Statement Verified by In
FR-HIER-04 medium A record cannot be retired or removed while records sit under it, at any level of a nested branch. automated test lib/engine.test.ts
FR-LIFE-01 medium Retiring is a new version that takes effect only when someone else approves it. automated test lib/engine.test.ts
FR-LIFE-02 medium Removing an approved record needs approval; afterwards it accepts no command and keeps its history. automated test lib/engine.test.ts
FR-LIFE-03 medium A record that was never approved is removed at once, by its author or an approver, and cannot be retired. automated test lib/engine.test.ts
FR-LIFE-04 medium A record that others refer to cannot be retired or removed. automated test lib/engine.test.ts

UR-10

The data is kept in a database we operate, safely shared by several application servers.

Functional requirement Risk Statement Verified by In
FR-STO-01 high Entries are appended and read back in order, unchanged. automated test server/server.test.ts
FR-STO-02 high An entry that does not continue the chain is refused. automated test server/server.test.ts
FR-STO-03 high The trail survives a restart. automated test server/server.test.ts
FR-STO-04 high The database itself refuses to change or delete entries. automated test server/server.test.ts
FR-STO-05 high Two servers writing at once cannot fork the trail. automated test server/server.test.ts

UR-11

Records can be brought over from the system we use today, with their origin recorded and the transfer reconciled.

Functional requirement Risk Statement Verified by In
FR-HIER-05 medium A record type that nests inside itself is migrated parents first; a row whose parent comes later in the file is refused, not waited for. automated test lib/migrate.test.ts
FR-MIG-01 medium An imported record arrives approved, marked with where it came from. automated test lib/engine.test.ts
FR-MIG-02 medium The same source record cannot be imported twice. automated test lib/engine.test.ts
FR-MIG-03 medium Imported data must pass the same checks as data entered by hand. automated test lib/engine.test.ts
FR-MIG-04 medium Rows are imported parents first, with references and values converted to the configured types. automated test lib/migrate.test.ts
FR-MIG-05 medium Every source row is accounted for: imported or refused with the reason. automated test lib/migrate.test.ts
FR-MIG-06 medium Running a migration again imports only what is not there yet. automated test lib/migrate.test.ts
FR-MIG-07 medium In review mode migrated records wait as Confirmed for an approver here. automated test lib/migrate.test.ts
FR-MIG-08 medium Source files are read as CSV with quotes, semicolons and line ends handled. automated test lib/migrate.test.ts
FR-MIG-09 medium The data model of the system that is replaced is read from SQL definitions and Prisma schemas, with keys, references and code lists. automated test lib/adopt/adopt.test.ts
FR-MIG-10 medium A drafted configuration and mapping are valid, every source table and column gets a stated fate, and every rule-of-thumb choice is listed as a decision. automated test lib/adopt/adopt.test.ts
FR-MIG-11 medium Capabilities and settings of the old system are reported with where they were seen and how Countersign stands on them; no setting's value is carried. automated test lib/adopt/adopt.test.ts
FR-MIG-12 medium After an import every mapped field of every imported record is compared with its source, and each difference or missing record is reported. automated test lib/adopt/adopt.test.ts
FR-MIG-13 medium Each step of the migration assistant is journaled with the checksums of its inputs and outputs in a chain that reveals later changes. automated test lib/adopt/adopt.test.ts
FR-MIG-14 medium The assistant exports the old data read-only by recorded queries and rehearses import and verification in a scratch store. automated test lib/adopt/adopt.test.ts

UR-12

Changes to the system's own configuration are controlled, attributable and part of the record of actions.

Functional requirement Risk Statement Verified by In
FR-CFG-02 medium The first configuration is audit entry #1 and carries the configuration's hash. automated test lib/engine.test.ts
FR-CFG-03 medium Changing the configuration needs the permission, a reason and a second person. automated test lib/engine.test.ts
FR-CFG-04 medium A configuration change cannot orphan existing records. automated test lib/engine.test.ts
FR-CFG-06 medium A new configuration applies from its entry on, and the history still replays. automated test lib/engine.test.ts
FR-CFG-07 high A person with the configure permission proposes a configuration change with a reason; it is one entry and changes nothing yet. automated test lib/engine.test.ts
FR-CFG-08 high A proposed configuration takes effect only when a different person with the configure permission approves it. automated test lib/engine.test.ts
FR-CFG-09 medium A proposal can be rejected with a reason by a second person or withdrawn by its proposer; neither changes the configuration. automated test lib/engine.test.ts
FR-CFG-10 high A proposal that would strand existing data is refused, naming the records, when it is proposed and again when it is approved. automated test lib/engine.test.ts
FR-CFG-11 medium A field may become required while records lack it: they stay in effect, are reported, and must be completed with their next change. automated test lib/engine.test.ts
FR-CFG-12 high The waiting proposal is rebuilt by replay, and a trail written before proposals existed replays to the same hashes. automated test lib/engine.test.ts
FR-CFG-13 high Over HTTP one person proposes a configuration change and another approves it; the approval is a signature and needs a recent sign-in. automated test server/server.test.ts
FR-UI-11 medium The configuration editor checks the draft as it is edited, shows every problem next to its cause, and shows the changes and their effect on existing records before a change can be proposed. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-12 medium A proposed configuration change is shown with its changes on the configuration page and in the inbox of those who may decide; its proposer is not offered the approval. end-to-end walkthrough scripts/guide-shots.mjs

UR-13

The record of actions and the records can be exported in open formats.

Functional requirement Risk Statement Verified by In
FR-EXP-01 low The audit trail exports as CSV with one line per entry and no executable cells. automated test lib/engine.test.ts
FR-UI-06 medium The audit trail can be searched and filtered by action, record type and person, and exported as CSV and JSON. end-to-end walkthrough scripts/guide-shots.mjs

UR-14

The system can be monitored and verified by its operators, and stops accepting changes if its record of actions is damaged.

Functional requirement Risk Statement Verified by In
FR-OPS-01 medium An empty store is initialised with the configuration as its first entry, once. automated test server/server.test.ts
FR-OPS-02 medium Entries altered in the store are detected on reading, and from then on every change is refused. automated test server/server.test.ts
FR-OPS-03 medium Entries removed or rewritten while the server runs are detected. automated test server/server.test.ts
FR-OPS-04 medium The server stamps entries with its own clock, never earlier than the newest entry. automated test server/server.test.ts
FR-OPS-05 medium Without storage settings the app is the demo; with them, missing secrets stop the server. automated test server/server.test.ts
FR-OPS-06 medium The health endpoint reports store, head hash, configuration and integrity. automated test server/server.test.ts
FR-OPS-07 medium The engine's refusal reaches the browser as a 422 with the reason. automated test server/server.test.ts

UR-15

The user interface shows the state of every record truthfully and guides people through the workflow.

Functional requirement Risk Statement Verified by In
FR-UI-01 medium Every record shows what is in effect, what is pending, and its state, in the tree and on its page. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-02 medium The signature panel shows the change, who wrote it, the signer's name and role and the meaning of the signature before it is signed. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-03 medium Actions a person may not take are not offered, and the reason is shown; the buttons are decided by the same engine that enforces the rules. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-04 medium Every record shows its complete version history and its own audit trail. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-05 medium The effective value of every option is shown with its source, what it overrides and what is pending. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-06 medium The audit trail can be searched and filtered by action, record type and person, and exported as CSV and JSON. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-07 medium The integrity page verifies the hash chain in the browser and shows the head hash. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-08 medium Reasons are asked for in a dialog that cannot be submitted empty. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-09 medium The tree shows nested records to any depth, with records that have no parent at the top; a record's page shows the path above it and the records directly under it. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-10 medium The parent picker of a nested record never offers the record itself or a record under it. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-11 medium The configuration editor checks the draft as it is edited, shows every problem next to its cause, and shows the changes and their effect on existing records before a change can be proposed. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-12 medium A proposed configuration change is shown with its changes on the configuration page and in the inbox of those who may decide; its proposer is not offered the approval. end-to-end walkthrough scripts/guide-shots.mjs
FR-UI-13 medium A record that does not meet the configuration in effect is marked with the reason. end-to-end walkthrough scripts/guide-shots.mjs
FR-DOC-01 low The documentation site builds a search index from the same Markdown files it shows: one entry per section of every document, with the document's title, the section's heading, the heading's address on the page and the section's text. automated test server/server.test.ts
FR-DOC-02 low The documentation search finds the sections that contain every word of the query, ranks a match in a heading or title above a match in the text, links each result to its heading and marks the matched words. automated test server/server.test.ts
FR-DOC-03 low Every document page lists its second- and third-level headings as "On this page", each with an address that exists on the page. automated test server/server.test.ts
FR-DOC-04 low A Mermaid block of a Markdown document is shown as a diagram; its source text is in the page and stays readable where the diagram cannot be drawn. automated test server/server.test.ts