Issues 292-293: a drill counted as a repair, a warning on a required check blocking a merge
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

This commit is contained in:
jochen
2026-10-07 13:56:39 +02:00
parent eef2c5e082
commit 9cf839c977
3 changed files with 121 additions and 1 deletions
@@ -419,6 +419,11 @@ not list. The table's test finds every verb the controller records and fails on
A `healer-wanted` already open for a decision clears on the next watchdog tick, as any condition its
row no longer sees.
**A drill is no repair.** Something broken on purpose to see the mesh raise and clear it is recorded by
`hand-act drill` (the seat's `drill`), cause `drill`, which the table lists as a person's decision;
`hand-act record` refuses that cause, so a repair cannot pass for a drill by the word it gives (issue
292; checked by the controller's S15 tests).
> **Progressive insight — 2026-10-06.** This paragraph said before: "except `retire-waiting` and
> `cleanup-waiting`: approving a retirement and deleting what was retired are a person's decision by
> design (ADR 0230), and no healer may take them over." The exception was keyed on two causes, and the
@@ -531,7 +536,11 @@ A changed file touches exactly the modules whose build reads it; a file no build
change reaching a module, or adding one, runs **the gate** on the build seat (`mesh/merge-gate`): the
touched manifests through `module check`, failing only what the change brings; every machine composed with
the definitions of the modules the plan moves or adds; the replays. Every repository of the mesh runs **its
own** `merge-check.sh` (`mesh/repo-check`) in the toolchain it declares, a warning when it has none. The
own** `merge-check.sh` (`mesh/repo-check`) in the toolchain it declares; one with none has "no repository
check defined", a success where the branch does not require `mesh/repo-check` and a failure for a person
where it does. **A note is never a warning on a required status**: the forge combines `warning` as a
failure, so a note — a wide rebuild, a problem already so on the base — is a success that says it, and only
what a person must decide fails (issue 293; checked by the forge module's status tests). The
check's result is the commit's **change plan** — the build plan, the deploy plan machine by machine with
what is not an ordinary send, and the verdict — posted on the pull request. The plan is one object with
a state machine, kept, followed by the release and written to the commit as a note; which parts are built
@@ -0,0 +1,52 @@
---
status: located
opened: 2026-10-07
located-in: [mesh-controller cmd/mesh-controller (handacts.go, signals.go S15)]
fixed-by: mesh-controller PR #109
amended-design: 03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md
---
# 292. A drill was counted as a repair
## Symptom
On 2026-10-07 S15 raised `mesh.hand-acts.drill.healer-wanted`. Its summary said that "drill" was
repaired by hand 2 times in 14 days, and that a healer is wanted for it. Both acts in the hand-act log
were deliberate drills of ADR 0240's module health check: a module stopped on purpose, then a module made
to crash on purpose. Each had operator approval. Both were recorded with `hand-act record --cause drill`,
because no verb existed for a drill.
## Diagnosis
S15 decides whether an act is a repair or a person's decision from **the verb that recorded it**
(to-be 45 §7, progressive insight of 2026-10-06), never from the cause word. `hand-act record` is the
verb for an act done outside the mesh. The mesh cannot tell a repair from a decision there, so every act
it records counts. A drill had no verb of its own, so it could only be recorded as a repair.
Keying the exemption on the cause `drill` was ruled out. Any repair could then avoid S15 by giving that
word.
## Fix
- A drill gets its own verb: `hand-act drill <what> --why <what it tests> [--condition <key>]`, which is
the controller seat's `drill`. It records the cause `drill`, and the controller's table of verbs lists
it as a person's decision. S15 never counts it, however often a drill is run.
- `hand-act record` now refuses the cause `drill` and names the drill verb. Once that refusal exists, the
only acts that `hand-act record` holds with that cause are the ones recorded before the drill verb. The
table exempts exactly those, so the open condition clears on the next tick. Any other verb that gives
`drill` as its cause still counts.
## How it is checked
mesh-controller tests:
- `TestADrillIsNoRepairAndItsHealerWantedClears` covers three cases. Repeated drills want no healer. The
cause word on another verb still counts. And the condition opened by the two acts of 2026-10-07 clears
on the next tick.
- `TestADrillIsRecordedThroughItsOwnVerb` checks that `hand-act record` refuses the cause `drill`, and it
checks the seat verb's command line.
- `TestEveryVerbThatRecordsAHandActIsInTheTable` fails on any verb that writes the log and is missing
from the table.
Live: once the build is rolled out, `mesh.hand-acts.drill.healer-wanted` closes within a watchdog tick.
Later drills are recorded with `mesh-controller.drill`.
@@ -0,0 +1,59 @@
---
status: located
opened: 2026-10-07
located-in: [mesh-catalog modules/gitea (pulls.ts, delivery.ts, index.ts)]
fixed-by: mesh-catalog PR #102
amended-design: 03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md
---
# 293. A warning on a required check blocked the merge
## Symptom
On 2026-10-07 branch protection began to require `mesh/merge-gate` on every repository of the mesh, and
`mesh/repo-check` on the core repositories as well. Administrators may not override either. On a pull
request whose statuses were success, warning and success, the forge's combined status was **failure**.
The forge treats `warning` as failing. So a required check that reported `warning` would block a merge
that nobody had decided to block.
## Diagnosis
The controller and the build seat give the merge check a verdict of `pass`, `warning`, `fail` or
`error`. The forge module turned each verdict into a forge state of the same name, `warning` included.
The controller says `warning` in four cases, and each one is a note, not a question for a person:
- the gate warns that a merge rebuilds a wide set of modules;
- the gate warns that the module check's problems were already present on the base branch;
- a repository's own `merge-check.sh` reports a warning;
- a repository has no `merge-check.sh` at all.
Separately, the forge module's status tool would set any `mesh/…` context, including both of the merge
check's.
The design said "a warning when it has none" for the repository check (to-be 45 §9, ADR 0237 as
narrowed by 0238). That was written before a required status could be anything but advisory.
## Fix
**A required status is success, or it blocks for a reason a person must act on.** The forge module now
maps verdicts like this:
- **A note** becomes `success`, and its description starts with "pass, with a note:".
- **A repository without a `merge-check.sh`, where the base branch does not require
`mesh/repo-check`,** becomes `success`, described as "no repository check defined".
- **A repository without a `merge-check.sh`, where `mesh/repo-check` is required (or the protection
cannot be read),** becomes `failure`. The description says that a person adds a check or lifts the
requirement.
- **`fail`** becomes `failure`.
- **`error`** becomes `error`, never a success.
The status tool now refuses both merge-check contexts: they are set by a verdict only.
## How it is checked
The forge module's `test/pulls.test.ts` runs every combination of verdict and repository-check facts.
It asserts that none sets `warning`, and that each case above lands where this report says.
`test/delivery.test.ts` asserts that the status tool refuses the merge-check contexts.
Live: the next pull request whose gate notes a wide rebuild shows `mesh/merge-gate` as success, and its
combined status is success.