Spec insights
What the spec corpus looks like in aggregate: how many requirements exist and in what state, how well they are tested and documented, and what the advisory effort and value estimates add up to.
Every number — and every chart — is derived at build time from the files in specs/ — the same source the matrix reads, so the two can never disagree. Counted facts and advisory estimates are kept in separate sections on purpose: an estimate is a judgement, and mixing the two would lend it an authority it has not earned.
The counted section charts each spec's requirements by status in the same colors as the status badges. The advisory section plots customer value against effort for every scored feature: the S16 tier bands sit behind the dots and the diagonal guides mark constant RICE, so value-per-effort reads as slope. The per-spec RICE ranking itself lives on the matrix page, whose RICE column sorts and carries a proportional bar — this page deliberately does not repeat it.
Two further charts join artifacts the repository already keeps but never plotted together: each S13 estimate's committed size snapshot against the size of that code today, which surfaces the estimates that have aged out of their band, and the S08 demo registry against the value ranking, which surfaces the features nothing demonstrates.
Recording what broke
Conventional Commits already marks which commits are fixes; what it never captured is what they fixed. Every fix: commit now names the requirement it repaired in a trailer, checked by the same commit-msg hook that runs commitlint:
fix(auth): treat an unauthenticated GitHub 404 as auth-required
Fixes: F07-FR-03The hook rejects a fix: with no trailer, a malformed id, or an id that is not in the traceability matrix. Dependency patches are exempt — use the deps scope, since patching an advisory repairs no requirement of this project. There is no other escape hatch: if a fix repairs behaviour no requirement describes, the requirement gets written first, because behaviour here is specified before it is built.
Attribution was not backfilled onto existing history, and it is not inferred from the files a commit touched. That inference was tried and measured: the 8 fix commits in the history touch files claimed by 29 different specs, correlating 0.89 with raw commit churn — it measures which files are shared, not which requirements break. Counts come from git log on each docs build, and the count of unattributed fixes is always shown beside them so an empty column reads as "not recorded yet" rather than "never breaks".
Test strength
Line coverage is gated at 80% on all four axes and every spec clears it, sitting between 90% and 99% — the gate working, but also a measurement with no range left to rank anything by. The mutation score replaces it as the test-strength axis: it mutates the source and asks whether the tests notice, so it measures whether tests assert rather than merely execute.
Because a full mutation run takes orders of magnitude longer than the commit gate, it is never part of npm run verify. Refresh it on demand:
npm run test:mutation # runs Stryker, writes reports/mutation/mutation.json
npm run mutation:score # distils it into mutation-score.jsonThat committed artifact stores the mutant tallies per file alongside the derived score, so the number can be audited and recomputed rather than taken on trust, and it records the date it was generated — the score is a snapshot of code that keeps moving, so the charts show its age. If the artifact is absent the site reports the score as not measured; a missing measurement is never drawn as a zero.
Counted facts
Everything in this section is a count taken from the spec files and the traceability matrix at build time.
Requirements by status
444 implemented168 manual
One bar per spec, segments colored like the badges above; bar length compares requirement counts across specs. Hover a segment for its exact count.
Requirement lifecycle
How long requirements sit specified before they are built, from the S11 stamps. These are deliberately not backfilled: the matrix was populated in one commit long after most requirements were written, so a git-derived date would record when the matrix learned of a requirement and pass it off as when the requirement was specified.
Where the fixes land
Every fix: commit names the requirement it repaired in a Fixes: trailer (S19), enforced by the commit hook. Counts are read from git log on each build, so they cannot drift from the history.
Advisory estimates
These are judgements, not measurements. Effort comes from the S13 rubric and value from S16; neither feeds the maturity score, which is built from observable facts only.
Value against effort
Each dot is a scored feature spec (dots sharing the same estimates are merged — hover for the spec ids). Height is the S16 value score with its tier bands; the diagonals are constant RICE, so steeper-than-a-guide means more value per point. The full per-spec numbers live in the matrix, sortable by RICE.
Are the effort estimates still current?
Each estimate committed the implementation size it was written against (S13). Plotted against the size today, anything on the diagonal has not moved; anything above it has grown since. The horizontal lines are the rubric's own LOC band boundaries, so a dot that has crossed one is an estimate whose band no longer matches its code — the same specs npm run check:spec-effort warns about, from the same function.
This chart deliberately does not plot effort points against implementation size: points are derived from that size by the band table, so the two cannot help but agree, and reading the agreement as calibration would be circular.
8 of 47 estimates have aged out of their band — F09, F15, F23, S01, S09, S10, S14, S15. Drift is a prompt to re-estimate, never a failure: the checker warns and the build stays green.
Value against test strength
Mutation score (S18) rather than line coverage: every spec clears the 80% coverage gate and sits in a 90–99% band, so coverage ranks nothing. Mutation testing asks whether the tests assert, which still varies. A feature toward the bottom-right is worth a lot and thinly tested. Scores measured 2026-07-26; they age as the code moves.
1 feature scoring 10 or better falls below the 60% break threshold — F02 (53.7%). The gate measures the whole suite at once, so a spec below the line is invisible to it while the total stays above. 1 scored feature has no mutated implementation file and so no score.
Which features have never been demonstrated
Feature specs by customer value, marked with whether an end-to-end demo exercises them — read from S08's demo registry, the same file the GIF pipeline and release-time change detection use. Whether a demo exists is a counted fact; only the ordering is an estimate. 19 of 47 specs carry one.
The gap is not evenly spread: 2 features scoring 10 or better have no demo — F12 (15.4), F08 (10.6).