Files
hq/02-DECISIONS/0080-the-development-cycle-is-checked.md
T
jochen daa9f171ae
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
Issue reports carry only opened: the tracker holds every status, so no copy can drift
The import of slice 3 (ADR 0275) was checked against every folder: no report changed since the
commit it read, and the tracker holds each report's status, owner, fix, design amendment, replay
and closing day. The keys are removed from all 361 reports, cycle.py refuses them in any report,
and the playbooks, skills and READMEs that still pointed at them name the tracker instead.
2026-10-10 17:44:18 +02:00

80 lines
4.7 KiB
Markdown

---
topic: how we work
status: accepted
date: 2026-09-17
deciders: jochen
reconstructed: false
extends: 0019-how-this-repository-works.md
---
# 80. The development cycle is checked, not trusted
## Context
[ADR 0019](0019-how-this-repository-works.md) made this repository the source of truth, and the
process overview drew the flow work must follow: an idea or a symptom, a decision, a to-be design,
a build in a code repository, an as-is update on shipping. The playbooks describe every step, and
frontmatter carries every status.
But the flow itself was enforced by nothing. A design could appear citing no decision; a design
could sit `in-progress` naming no code; an issue could be `fixed` by nobody knows what. Each is
indistinguishable from correct work until somebody reads carefully — and the whole point of the
playbooks is that nobody should have to hold this repository in their head. A session that starts
cold (or an agent after a context clear) must be able to *find* the chain by following frontmatter
pointers, which only works if the pointers are reliably there.
## Decision
The development cycle is enforced mechanically, to the extent frontmatter can carry it:
- **No design without a decision** — every to-be design names at least one record in `decisions:`.
- **No development without a design that says where** — an `in-progress` or `implemented` design
names its owning code in `code:`.
- **No owner-less diagnosis, no fix-less fix** — an issue marked `located` or `fixed` names
`located-in:`; one marked `fixed` or `resolved` says `fixed-by:` (prose counts — "nothing, the
capability existed" is an answer).
- **No silent graduation** — a `graduated` research overview says what it `became:`, and the
targets exist.
- **No two records answering to one number** — added 2026-09-30; see the insight below.
> **Progressive insight — 2026-09-30.** The list above named four things `cycle.py` enforces, and
> now names five. Nothing enforced that two issue records hold different numbers: two machines
> filing issues within one hour both read `main`, both took "the next free number", and collided
> twice — the second collision reaching `main` with `records.py`, `cycle.py` and `index.py` all
> reporting success (04-ISSUES/155). A number is how every other record cites one, so two records
> answering to it is a citation that resolves to whichever folder the reader opened. `cycle.py`
> refuses it now. The decision here stands exactly as written: this is one more thing frontmatter
> and file names can carry, found by its absence rather than by reasoning.
> **Progressive insight — 2026-10-10.** The third rule above, no owner-less diagnosis and no fix-less
> fix, and the replay rule `cycle.py` took on under ADR 0237, moved out of `cycle.py` the day slice 3 of
> [ADR 0275](0275-the-mesh-numbers-and-tracks-its-issues-in-a-module-of-its-own-and-hq-keeps-only-the-narrative-of-a-design-or-governance-issue.md)
> landed: an issue's status lives in the issue tracker, whose `move` refuses at the write what the
> check refused at merge — `located` without an owner, `resolved` without a fix, a core issue without
> its replay, `wontfix` without a reason. Enforced mechanically still, one step earlier, in the one
> place the status is. `cycle.py` keeps the fifth rule, no two records answering to one number, and
> refuses a status key in a report opened after the import. The decision stands: the cycle is checked,
> not trusted; which program checks each rule is a fact that moved.
> **Progressive insight — 2026-10-10, later.** `cycle.py` refuses a status key in any report, not only one
> opened after the import: the keys the older reports carried were removed once the import was checked
> against every folder (ADR 0275's last note).
[`00-META/checks/cycle.py`](../00-META/checks/cycle.py) refuses violations, beside `records.py`
and `index.py`; all three run before any merge here. What frontmatter cannot see — that code work
actually started from a handoff — remains held by playbooks 04 and 07: a feature branch exists
because a design or an issue sent it, and a merge is a human checkpoint.
## Consequences
A `/clear` costs little: [`AGENTS.md`](../AGENTS.md) now carries the cycle and a where-to-look
table, and the chain a fresh session needs is guaranteed present in frontmatter rather than
reconstructed from memory. The checks are the floor, not the ceiling — they verify pointers exist,
not that their content is true; reading remains the job.
## References
- [`00-META/process/00-overview.md`](../00-META/process/00-overview.md) — the flow, and its new
"The cycle is checked" section.
- [ADR 0019](0019-how-this-repository-works.md) — the repository this disciplines.