The records pointed at branches that no longer exist, and two fixes had no sequel
Three issues named the branch that fixed them, and a branch is deleted when it merges — so every `fixed-by:` was a pointer that resolved to nothing by the time anyone followed it. They name commits and pull requests now, and playbook 03 says to. Two records were missing the thing a reader arrives for. 146 did not say that one of its fixes crash-looped the control plane on a running mesh, which is the whole reason the delivery subject carries the stream and the raise path was the only one exercised. 151 did not say that 152 removed the false reasons its roster moved, or that it stays open for the real ones. ADR 0080 enumerates what cycle.py enforces and named four things; it enforces five. A progressive insight names the fifth — the decision stands, the list had gone stale. The checks README and playbook 03 gained the same rule, and 155 points at all three.
This commit is contained in:
@@ -54,4 +54,6 @@ whose failure has never been observed is a guess about its own correctness.
|
||||
The development cycle, checked ([ADR 0080](../../02-DECISIONS/0080-the-development-cycle-is-checked.md)):
|
||||
a to-be design names a decision, an in-progress/implemented design names its owning code, a
|
||||
located/fixed issue names its owner, a fixed/resolved issue says what fixed it, a graduated
|
||||
research overview says what it became. `python3 00-META/checks/cycle.py`
|
||||
research overview says what it became, and no two issue records share a number (issue 155 — the
|
||||
number is how a record is cited, and `main` lags every open pull request, so two people reading it
|
||||
allocate the same one). `python3 00-META/checks/cycle.py`
|
||||
|
||||
@@ -21,7 +21,12 @@ incident someone must **clear**.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Take the next free number. Create `04-ISSUES/NNN-short-name/00-report.md`:
|
||||
1. Take the next free number — **across `main` and every open pull request**, not `main` alone.
|
||||
Work sits on unmerged branches for days, so two people both reading `main` allocate the same
|
||||
number; it happened twice in one hour between two machines, and the second collision reached
|
||||
`main` with every check passing (issue 155). `cycle.py` now refuses two records sharing a number,
|
||||
which catches a collision but does not prevent one. Create
|
||||
`04-ISSUES/NNN-short-name/00-report.md`:
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -42,6 +47,14 @@ incident someone must **clear**.
|
||||
## Rules
|
||||
|
||||
- Closed issues are never deleted — they are the mesh's symptom-to-component memory.
|
||||
- `fixed-by:` names something that will still exist: a commit or a pull request, never a branch. A
|
||||
branch is deleted when it merges, so a branch name there is a pointer that resolves to nothing by
|
||||
the time anybody follows it.
|
||||
- A fix that turns out to have broken something else is written back into the record that asked for
|
||||
it, pointing at the new issue. Somebody arriving at a record to learn why the code is the way it
|
||||
is must not have to already know there was a sequel.
|
||||
- Renumbering a collision happens once, in the branch that lands last. Renumbering a branch whose
|
||||
author is still pushing only moves the race.
|
||||
- An issue whose answer is a general lesson should also be written to the knowledge base, so
|
||||
the next person searching a symptom finds it. Both, not either.
|
||||
- `status: wontfix` is legitimate and requires a sentence saying why.
|
||||
|
||||
@@ -35,6 +35,16 @@ The development cycle is enforced mechanically, to the extent frontmatter can ca
|
||||
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.
|
||||
|
||||
[`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
|
||||
|
||||
+12
@@ -71,3 +71,15 @@ against a suite nobody can execute.
|
||||
- The lab rewrites a bundle's registry-prefixed third-party references to upstream ones for a
|
||||
machine with an uplink (`test/integration/harness.ts`); the new bundle's bus reference needed
|
||||
that rule added, which is done and is not this issue.
|
||||
|
||||
## What one of its fixes then did to a running mesh (2026-09-30)
|
||||
|
||||
The change that stopped the doubling — putting the stream into a push consumer's delivery subject —
|
||||
is correct on a foundation being raised and fatal on a mesh that is already running: the server will
|
||||
not move that subject while a subscriber is bound, and a node is bound to its declaration consumer
|
||||
the whole time it is up. The control plane crash-looped on the first build that carried it.
|
||||
|
||||
Recorded and fixed as [issue 156](../156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md).
|
||||
Noted here because this record is where somebody will arrive when reading why the subject carries the
|
||||
stream at all, and the answer is incomplete without it: **the raise path was the only one exercised,
|
||||
and it is the one path on which nothing is bound.**
|
||||
|
||||
@@ -57,6 +57,19 @@ The node-by-node migration adds names one module at a time. On ace alone that is
|
||||
each assignment moves the roster, each is a full restart of every hub service, and a rollback is
|
||||
another. The migration is paused on this.
|
||||
|
||||
## What has since been ruled out as a cause (2026-09-30)
|
||||
|
||||
The roster was also moving for a reason that was not a name changing at all: a node whose plan would
|
||||
not compose had its routed names silently dropped from the roster handed to every machine, so a
|
||||
briefly unreachable store withdrew and restored a name on alternating passes. That is
|
||||
[issue 152](../152-a-nodes-plan-failure-silently-drops-its-routed-names/00-report.md), and it is
|
||||
fixed — it is what made the churn on the control node repeat every six minutes for twenty-five
|
||||
minutes rather than once per operator action.
|
||||
|
||||
**It does not close this record.** A roster that changes for a real reason — a machine joining, a
|
||||
module assigned, a public domain set — still replaces every container on every machine that carries
|
||||
the list. 152 removed the false reasons; the question below is still open.
|
||||
|
||||
## What would be right (for diagnosis)
|
||||
|
||||
Keep 135's guarantee (no container runs with a stale address) without making the roster part of every
|
||||
|
||||
@@ -3,7 +3,7 @@ status: resolved
|
||||
opened: 2026-09-29
|
||||
located-in:
|
||||
- mesh-controller cmd/mesh-controller/plan.go (routeNamesInTheMesh skips a node whose plan will not compose)
|
||||
fixed-by: mesh-control fix/152-a-lookup-failure-is-not-an-absence
|
||||
fixed-by: mesh-controller 6c5dfd0 (PR 147)
|
||||
amended-design:
|
||||
---
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
status: resolved
|
||||
opened: 2026-09-29
|
||||
located-in: [hq 00-META/checks/cycle.py]
|
||||
fixed-by: hq issue/two-records-share-a-number-and-nothing-says-so
|
||||
fixed-by: hq f89aef9 (PR 192)
|
||||
amended-design:
|
||||
---
|
||||
|
||||
@@ -50,4 +50,9 @@ branch whose author is still pushing only moves the race.
|
||||
|
||||
**The check catches the collision; it does not prevent it.** Allocating a number still needs the open
|
||||
pull requests read as well as `main`. That is a habit the check now backstops rather than one it
|
||||
replaces.
|
||||
replaces, and playbook [03](../../00-META/process/03-issues.md) now says so at the step where the
|
||||
number is taken.
|
||||
|
||||
[ADR 0080](../../02-DECISIONS/0080-the-development-cycle-is-checked.md) enumerates what `cycle.py`
|
||||
enforces and named four things; it carries a progressive insight naming the fifth. The decision
|
||||
stands — this is one more thing frontmatter and file names can carry, found by its absence.
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ status: resolved
|
||||
opened: 2026-09-29
|
||||
located-in:
|
||||
- mesh-controller internal/broker/jetstream.go (EnsureConsumer)
|
||||
fixed-by: mesh-controller fix/156-a-consumer-that-works-is-not-replaced
|
||||
fixed-by: mesh-controller e7da39d (PR 148)
|
||||
amended-design:
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user