Writing a decision, and going back to one
What a decision is, what rests on it and what its states mean is What a decision is. This page is where an entry goes, how it is written, and what a later session adds to one.
Where an entry lives#
One decision is one file, named after its id, in the group its id names. The group is what the decision is about, and the prefix carries it, so a file's id decides its path and two entries cannot quietly share a number.
- audience/ — Who the server answers for, and how it says so
- discovery/ — Which installation is read, and how
- answers/ — What a lookup returns, and what decides it
- knowledge/ — What the corpus holds and how it is written
- versions/ — What a statement holds on
- catalog/ — The curated indexes and where their contract comes from
- scope/ — Core conventions where they apply, and nowhere else
- guides/ — What a returned draft is worth
- evidence/ — How this server is measured
- task-skills/ — What an installed workflow owes the task
- feedback/ — What the feedback channel has to stay usable for
- documentation/ — How what is written here is written
- code/ — How the source is laid out
The number is three digits wide, in the file name and in the id alike, because
that is what lists a group in the order it was written: unpadded, dis-10
sorts between dis-1 and dis-2 in every directory listing and in anything
that compares the ids as text. A requirement is numbered the same way, so one
habit covers both. bin/cli decisions:check fails on any other width.
Each group's readme.md says what that group is about, and the listing at the
foot of it is generated by bin/cli decisions:index, as is the listing at the
foot of decisions/readme.md, which carries the whole of it under a heading
per group. Inside a group the order is newest first; what was decided lately
across all of them is bin/cli decisions:list. The revoked entries keep a run
of their own at the foot, because mixed into the rest they looked exactly like
something to build on.
Prose above either listing may not use a third-level heading: that is what the command reads as the start of the generated half, and it would go with the next regeneration.
An id is never reused, and an entry is never deleted: a decision that turned out wrong is the one most worth reading, and it is revoked in place.
Renumbering one#
bin/cli decisions:renumber <decision> [<number>]bin/cli decisions:renumber <decision> [<number>]
Two sessions reading one main write one id, and the second one to come home
moves. The dangerous half is the move rather than the collision, so the command
splits the references in two: everything whose own line names the entry's file
is rewritten — the entry, its name, every link, and the reference definitions
the generated listings end with — and everything else is printed with its file,
its line and its text.
What is printed is what has to be read, one at a time. A bare id says
nothing about which entry it means, and both mis-pointings on record were one: a
requirement's restsOn:, where existence is checked and correctness is not,
and an id in a sentence, where neither is. git diff main -- <file> settles
it — a line this branch added means this branch's entry — and a search and
replace over the whole list is the failure this command exists to make visible,
not one it prevents.
D-DOC-015
is what the split was measured against.
Named no number, the entry takes the next one free in its group, which is one past the highest rather than the first gap. The generated listings are put back in order where they already carried the entry, because the number is what a group sorts on.
What an entry holds#
---
id: D-DIS-004
date: 2026-07-29
status: open
---
# D-DIS-004 — The version comes from the core package, not from the console
**The installed version is read from the core package's `Typo3Version` class
rather than asked of `bin/typo3 --version`.**
The catalogs are pinned to one revision and every answer was phrased as
timeless fact, while the server had the other number all along.
## Evidence
- What was measured or read at the time, with its numbers.
## Decided
- What was done, and what was rejected in doing it.
## Assumed
- What the decision rests on that nobody has verified.
## Wrong if
- What would show it to have been wrong, concretely enough that somebody could
notice it happening.
## Covered by
- `SomeTest::theMethodThatWouldCatchIt`---
id: D-DIS-004
date: 2026-07-29
status: open
---
# D-DIS-004 — The version comes from the core package, not from the console
**The installed version is read from the core package's `Typo3Version` class
rather than asked of `bin/typo3 --version`.**
The catalogs are pinned to one revision and every answer was phrased as
timeless fact, while the server had the other number all along.
## Evidence
- What was measured or read at the time, with its numbers.
## Decided
- What was done, and what was rejected in doing it.
## Assumed
- What the decision rests on that nobody has verified.
## Wrong if
- What would show it to have been wrong, concretely enough that somebody could
notice it happening.
## Covered by
- `SomeTest::theMethodThatWouldCatchIt`
- The title says what will be done, in the affirmative. Not the deficiency it corrects and not a negation: "The ladder needs an outcome that builds something", not "the ladder had no outcome that builds" and not "the ladder is not a filter". What was wrong is evidence and belongs in the paragraph under the bold sentence; a listing of 138 entries is read for what each one settled, and a title in the past tense or in the negative makes the reader reconstruct that. It is AGENTS.md's "say what is, not what it is not", applied where it is read most and followed least. It holds for every entry, revoked ones included: what a revoked entry preserves is its statement and its Revoked on section, and a listing where some titles name a fix and others name a gap is read as two kinds of entry when there is one.
- The bold first sentence is the decision. A reader who stops after it knows what was settled; everything under it is what settled it.
- The sections are a fixed set, in that order: Evidence, Decided,
Assumed, Wrong if, Covered by. Only Wrong if is required — an
entry that cannot say what would falsify it is not a decision worth recording.
dateis the day it was decided. - Each section holds one bullet per item. Half the entries decide more than one thing and a fifth rest on more than one assumption, which is why these are sections and not a bullet repeating its own label.
- Covered by is optional and lists the tests that would catch the Wrong
if happening, one per line. Most entries are about process and nothing runs
over them; where something does, naming it is what turns the promise into
something the suite keeps. Every test named anywhere in an entry has to exist
—
DecisionsTest::everyTestADecisionNamesExists.
The dated sections#
A dated section at the foot and nothing else: Confirmed on ``<date>`` where somebody went back and it held, Revoked on ``<date>`` where it did not, and Since then for what followed without a date of its own. Those carry prose rather than bullets, because each is an account of one reading.
revokedBy is what a revoked entry owes its reader: where to go instead. It
names one decision, only a revoked entry may carry it, and the generated listing
shows it, so nobody has to open a dead entry to find the live one.
Revoking a statement#
Revoking is not only for an entry that turned out wrong. An entry whose
statement no longer describes this server is revoked as well, and a new one
is written for what holds instead — because the reader of a listing has the
headline and the status and nothing else, and confirmed beside a sentence
that is no longer the case reads as a claim about today.
D-ANS-023
is the worked example. Its statement said that no manual this lookup indexes
documents a ViewHelper. That was true, the change it asked for was made the same
day, its three Wrong if were measured and none of them held — and from that
moment the statement described a lookup that no longer existed. It carries its
Confirmed on for the reading and a Revoked on below it for the
supersession, revokedBy points at
D-ANS-026,
and the successor is what a reader builds on.
The successor is a new entry rather than a rewrite of the old one, and it is worth being precise about why: its Wrong if is a different list. What can go wrong now is a book that moves, and what could go wrong before was a book that is missing. Rewriting the old entry would throw away the finding while keeping its number, and nothing afterwards could tell the two apart.
confirmed stays what it is for: an entry whose statement survives the
reading. A decision about the shape of an answer, or about which source a
question is put to, is as true after somebody goes back to it as before, and
that is the ordinary case.
What rests on one#
A requirement says which decisions it stands on, in its own front matter —
restsOn: [D-FBK-005]. That is the one crossing neither directory can see on
its own: a decision is revoked, the requirement written on top of it keeps its
held status and its passing test, and the reasoning under it is gone.
bin/cli unresolved:list reads that out; nothing fails on it, because whether
the requirement still stands is a judgement.
Going back to one#
Most decisions are open and stay that way, which is what makes the state easy to
stop seeing: a Wrong if written and never read is a promise, and nothing
says when to keep it. bin/cli unresolved:list counts them and names the
oldest — not because age disproves anything, but because that is the entry the
repository has moved furthest away from since. Going back to one and adding
Confirmed on or Revoked on is a legitimate task with no feature behind
it.
bin/cli decisions:check holds every file to the shape above, and
composer test runs the same check through DecisionsTest, except the
listing: that one is generated from every file in a group, so it can only be
true on a checkout that has all of them, and DecisionsTest would fail every
branch that adds an entry —
D-FBK-011.