Skip to content

docs(governance): a requirement written after the work, and a gate that called it absent - #115

Merged
lessevv merged 1 commit into
mainfrom
docs/a-requirement-that-arrived-after-the-work
Sep 13, 2026
Merged

lessevv merged 1 commit into
mainfrom
docs/a-requirement-that-arrived-after-the-work

Conversation

@lessevv

@lessevv lessevv commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Eleven requirements locked into the v2.0 manifest are cited by nothing in the
product repository. Nine of them never could have been: the requirement was
written to describe work that had already merged, so no trailer on the
implementing commit could have named it. Two are measurable to the second —
E2-R22's implementation merged at 20:31:49 and the identifier was minted at
21:02:33; E5-R27's merged twenty-six seconds after the specification change
that created it.

Three parts, and none of them is the whole answer.

A record satisfies the citation box where a citation was impossible

GOV-R26, and a new When the requirement postdates the work section in
40-quality/definition-of-done.md.
Where the identifier did not exist on this repository's default branch when the
work merged, a record in the implementing repository — naming the identifier,
the seam that implements it, and the commit that merged it — ticks the citation
box for that requirement.

It is not a citation and does not pretend to be. The implementing change stays
uncited and the gate's answer about it does not change. What it buys is the
thing that was genuinely missing: an identifier appearing nowhere cannot be told
apart from one nobody implemented, and separating them otherwise costs every
future audit a hand re-derivation of all eleven seams — two of which already
came back different from the audit that had attributed them.

What does not qualify is enumerated rather than implied, because the risk is
that this becomes a way to skip citing work that could have cited: a trailer
that could have carried the identifier and did not; work still in flight; the
record and the work in the same pull request; an entry naming no commit or the
wrong one; a record standing in for the requirement itself.

The ordering rule, restated about the requirement

GOV-R27, in
50-governance/change-lifecycle.md
beside GOV-R4, which is where a reader asking about order already goes.
GOV-R4 orders a behavioural change; a requirement written only to describe
existing behaviour is not one, which is exactly the gap nine of the eleven
walked through. Neither rule is machine-checked and both pages now say so about
themselves.

The gate names what it read

GOV-R28. spec_check.py kept only identifiers on a line matching
^\s*Spec:, so A3-R23, E5-R27, E6-R14 and E6-R16 read as uncited purely
for being named in a sentence — a guard keyed on a line format reclassifying
documented differently as not documented.

The trailer stays the only form that passes: "unlike A3-R23" and "superseded
by A3-R23"
name an identifier while citing none of it, and a gate that accepted
them would grade changes as cited on a reading no reviewer agreed to. What
changed is that prose is now read and reported distinctly.

Planted, against a body naming ids only in prose and against one naming none:

$ spec_check.py --text-file prose-only.txt          # "Cites A3-R22 and A3-R23."
::error::no `Spec:` trailer found; the text names A3-R22, A3-R23 outside one
A citation is read from a line beginning `Spec:` and from nowhere else, so this
text cites nothing. What it does name, in prose, the specification defines:
A3-R22, A3-R23. If this change implements that, the fix is the trailer — on a
commit and in the pull-request body:

    Spec: A3-R22, A3-R23
[exit 1]

$ spec_check.py --text-file cites-nothing.txt
::error::no `Spec:` citation found
[exit 1]

Before this change both printed the identical no Spec: citation found. On
the passing path a trailer that lost a sibling to a squash now warns rather than
passing in silence:

$ spec_check.py --text-file trailer-plus-prose.txt  # Spec: A3-R22, prose names A3-R23
spec-check: OK — cites A3-R22
::warning::named but not cited: A3-R23 — named outside a `Spec:` line, so this
change does not cite it. Add it to the trailer if this change implements it.
[exit 0]

What this deliberately does not close

A3-R23 and the second half of E6-R14 are slips, not inversions: the
identifier existed and the trailer left it out. GOV-R26 refuses them by
design. They need a later change on the same seam carrying the trailer, or a
recorded override.

No merged commit is amended. 70-operations/versions/2.0.0.toml and its status
are untouched.

Gates run locally: integrity.py, manifest_check.py, commit_lint.py,
dco_check.py, typos, markdownlint-cli2, lychee — all clean.

Spec: GOV-R26, GOV-R27, GOV-R28, ADR-0034, GOV-R11, Q-R23

…at called it absent

Eleven requirements locked into the v2.0 manifest are cited by nothing in the
product repository, and nine of them never could have been: the requirement was
written to describe work that had already merged, so no trailer on the
implementing commit could have named it. Two are measurable to the second —
E2-R22's implementation merged at 20:31:49 and the identifier was minted at
21:02:33; E5-R27's merged twenty-six seconds after the specification change that
created it.

Three parts, and none of them is the whole answer.

A record satisfies the citation box where a citation was impossible (GOV-R26).
Where the identifier did not exist when the work merged, a record in the
implementing repository naming the identifier, the seam and the commit ticks the
definition of done's first box for that requirement. It is not a citation and
does not pretend to be: the implementing change stays uncited and the gate's
answer about it does not change. What it buys is the thing that was genuinely
missing — an identifier appearing nowhere cannot be told apart from one nobody
implemented, and separating them otherwise costs every future audit a hand
re-derivation of all eleven seams. Two of the eleven derivations already came
back different from the audit that had attributed them.

What does not qualify is enumerated rather than implied, because the risk is
that this becomes a way to skip citing work that could have cited: a trailer
that could have carried the identifier and did not, work still in flight, a
record in the same pull request as the work, an entry naming no commit or the
wrong one, and a record standing in for the requirement itself.

The ordering rule is restated about the requirement rather than the change
(GOV-R27). GOV-R4 ordered a behavioural change; a requirement written only to
describe existing behaviour is not one, which is exactly the gap nine of the
eleven walked through. It sits in change-lifecycle.md beside GOV-R4 because that
is where a reader asking about order already goes. Neither rule is machine-
checked, and both pages now say so about themselves.

The gate names what it read (GOV-R28). spec_check.py kept only identifiers on a
line matching ^\s*Spec:, so four of the eleven — A3-R23, E5-R27, E6-R14, E6-R16
— read as uncited purely for being named in a sentence instead of a trailer: a
guard keyed on a line format reclassifying documented differently as not
documented. The trailer stays the only form that passes, because "unlike A3-R23"
and "superseded by A3-R23" name an identifier while citing none of it. What
changed is that prose is now read and reported distinctly — a failing run names
the identifiers it found outside a trailer and prints the trailer to add, and a
passing run warns about identifiers named but left out of the Spec: line, which
is the case that let a squash trim four ids to one in silence.

Two of the eleven are slips, not inversions, and this deliberately does not
close them. A3-R23 and the second half of E6-R14 had the identifier available
and left it out of the trailer; they need a later change on the same seam
carrying it, or a recorded override. No merged commit is amended and no version
status moves.

Spec: GOV-R26, GOV-R27, GOV-R28, ADR-0034, GOV-R11, Q-R23
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Wessel Verheij <info@nightworks.io>
@github-actions github-actions Bot added documentation Docs only ci Pipelines, workflows, and release engineering governance The rules of change architecture labels Sep 13, 2026
@sonarqubecloud

Copy link
Copy Markdown

@github-actions github-actions Bot added the awaiting-maintainer Green PR with no review — a maintainer needs to act label Sep 13, 2026
@lessevv
lessevv merged commit 545694b into main Sep 13, 2026
13 checks passed
@lessevv
lessevv deleted the docs/a-requirement-that-arrived-after-the-work branch September 13, 2026 18:00
@github-actions github-actions Bot added awaiting-maintainer Green PR with no review — a maintainer needs to act and removed awaiting-maintainer Green PR with no review — a maintainer needs to act labels Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

architecture awaiting-maintainer Green PR with no review — a maintainer needs to act ci Pipelines, workflows, and release engineering documentation Docs only governance The rules of change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant