diff --git a/00-META/checks/README.md b/00-META/checks/README.md index f8ff5cd..0689690 100644 --- a/00-META/checks/README.md +++ b/00-META/checks/README.md @@ -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` diff --git a/00-META/process/03-issues.md b/00-META/process/03-issues.md index fcf19f1..b6cc010 100644 --- a/00-META/process/03-issues.md +++ b/00-META/process/03-issues.md @@ -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. diff --git a/02-DECISIONS/0080-the-development-cycle-is-checked.md b/02-DECISIONS/0080-the-development-cycle-is-checked.md index a090efd..1497bb4 100644 --- a/02-DECISIONS/0080-the-development-cycle-is-checked.md +++ b/02-DECISIONS/0080-the-development-cycle-is-checked.md @@ -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 diff --git a/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/00-report.md b/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/00-report.md index ff8c3ce..4fcdb58 100644 --- a/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/00-report.md +++ b/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/00-report.md @@ -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.** diff --git a/04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md b/04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md index bf44ae6..1cb325e 100644 --- a/04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md +++ b/04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md @@ -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 diff --git a/04-ISSUES/152-a-nodes-plan-failure-silently-drops-its-routed-names/00-report.md b/04-ISSUES/152-a-nodes-plan-failure-silently-drops-its-routed-names/00-report.md index 6dcd31f..a0491b4 100644 --- a/04-ISSUES/152-a-nodes-plan-failure-silently-drops-its-routed-names/00-report.md +++ b/04-ISSUES/152-a-nodes-plan-failure-silently-drops-its-routed-names/00-report.md @@ -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: --- diff --git a/04-ISSUES/155-two-records-may-share-a-number-and-nothing-says-so/00-report.md b/04-ISSUES/155-two-records-may-share-a-number-and-nothing-says-so/00-report.md index ec19f6e..4e2e4bb 100644 --- a/04-ISSUES/155-two-records-may-share-a-number-and-nothing-says-so/00-report.md +++ b/04-ISSUES/155-two-records-may-share-a-number-and-nothing-says-so/00-report.md @@ -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. diff --git a/04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md b/04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md index a371fe4..c4143d7 100644 --- a/04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md +++ b/04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md @@ -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: ---