Symptom.plans showed a plan as "building for 1s", then "4s", then "9s" over several minutes. Its build had been asked minutes before and was still queued.
Cause.
planLineWith, planStatuses and openPlans counted from p.Updated. The store stamps that to now() on every save, and LATE compared it against a fixed 30m. The stalled watchdog (S3) counts from TierEntered, against the measured bound max(tierAtLeast, 3*p90).
advanceHeld saved every plan after every step, even when advanceOnce reported no move. It runs every 30s and after every build outcome on the mesh. Each run bumped the revision and said plan-moved on the bus. A plan waiting on a queued build changes nothing on a step, so these writes were needless.
Fix.
inTierSince(p) gives the start time. It is TierEntered, or the delivery's go if that came later. A waiting walk uses Created, as S16 does. A plan without the stamp falls back to Updated. The line, status --json (since/late), the late count and the watchdog all use it.
tierBounds / measuredTierBounds give one bound for the watchdog, plans and status, so LATE is the stalled condition said on the line. A waiting walk is never called late; S16 is its watchdog.
advanceHeld compares a snapshot of the plan before and after each step, and saves only if it changed. The snapshot leaves out the fields the store stamps.
Tests.plan_clock_test.go. Both tests were shown to fail with the fix reverted:
A plan saved 3s ago and in its tier 40m reads "building for 40m0s" and LATE. LATE agrees with watchPlans on both sides of a measured bound.
Against the store, three advances of a plan waiting on its build leave revision and updated unchanged. Before the fix the revision went from 3 to 6.
sh merge-check.sh passed locally with the race detector, except internal/broker's genesis-template test. That test reads the sibling mesh-host checkout, which was 23 commits behind locally. It passes against mesh-host origin/main.
novox/hq issue 296.
**Symptom.** `plans` showed a plan as "building for 1s", then "4s", then "9s" over several minutes. Its build had been asked minutes before and was still queued.
**Cause.**
1. `planLineWith`, `planStatuses` and `openPlans` counted from `p.Updated`. The store stamps that to `now()` on every save, and LATE compared it against a fixed 30m. The stalled watchdog (S3) counts from `TierEntered`, against the measured bound `max(tierAtLeast, 3*p90)`.
2. `advanceHeld` saved every plan after every step, even when `advanceOnce` reported no move. It runs every 30s and after every build outcome on the mesh. Each run bumped the revision and said `plan-moved` on the bus. A plan waiting on a queued build changes nothing on a step, so these writes were needless.
**Fix.**
- `inTierSince(p)` gives the start time. It is `TierEntered`, or the delivery's go if that came later. A waiting walk uses `Created`, as S16 does. A plan without the stamp falls back to `Updated`. The line, `status --json` (`since`/`late`), the late count and the watchdog all use it.
- `tierBounds` / `measuredTierBounds` give one bound for the watchdog, `plans` and `status`, so LATE is the stalled condition said on the line. A waiting walk is never called late; S16 is its watchdog.
- `advanceHeld` compares a snapshot of the plan before and after each step, and saves only if it changed. The snapshot leaves out the fields the store stamps.
**Tests.** `plan_clock_test.go`. Both tests were shown to fail with the fix reverted:
- A plan saved 3s ago and in its tier 40m reads "building for 40m0s" and LATE. LATE agrees with `watchPlans` on both sides of a measured bound.
- Against the store, three advances of a plan waiting on its build leave revision and `updated` unchanged. Before the fix the revision went from 3 to 6.
`sh merge-check.sh` passed locally with the race detector, except `internal/broker`'s genesis-template test. That test reads the sibling mesh-host checkout, which was 23 commits behind locally. It passes against mesh-host origin/main.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Machines
mesh-controller on novox: judging — carried by release-1791400043872652570
Transitions
2026-10-07 18:47 (new) → proposed (announced): novox/mesh-controller#119's head announced
2026-10-07 18:57 proposed → checked (checked): the verdict names this commit
2026-10-07 18:57 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-07 19:15 ready → held (hold): something holds it for a person: its group's composed check did not pass for the heads that merged, or it merged and no walk was opened for it
2026-10-09 07:31 held → covered (covered): covered: a later merge that contains it was delivered: novox/mesh-controller@bf11a8baac (merged as 96c34c52 into main, walk plan-1791400660610297560): build-agent, mesh-controller, route-proxy
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@ea92af2a7d77` — **covered** since 2026-10-09T07:31:59Z
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- mesh-controller on novox: judging — carried by release-1791400043872652570
**Transitions**
- 2026-10-07 18:47 (new) → proposed (announced): novox/mesh-controller#119's head announced
- 2026-10-07 18:57 proposed → checked (checked): the verdict names this commit
- 2026-10-07 18:57 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-07 19:15 ready → held (hold): something holds it for a person: its group's composed check did not pass for the heads that merged, or it merged and no walk was opened for it
- 2026-10-09 07:31 held → covered (covered): covered: a later merge that contains it was delivered: novox/mesh-controller@bf11a8baacda (merged as 96c34c52 into main, walk plan-1791400660610297560): build-agent, mesh-controller, route-proxy
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on g14 as build-1791396503732010736 (builds --log build-1791396503732010736).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 46 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-07T18:01:12Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-07T18:01:12Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.032s
ok github.com/novox/mesh-controller/cmd/mesh-controller 187.991s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.008s
ok github.com/novox/mesh-controller/examples/route-proxy 1.259s
ok github.com/novox/mesh-controller/internal/artifacts 1.035s
ok github.com/novox/mesh-controller/internal/broker 2.371s
ok github.com/novox/mesh-controller/internal/builder 1.253s
ok github.com/novox/mesh-controller/internal/catalogue 3.625s
ok github.com/novox/mesh-controller/internal/conditions 1.954s
ok github.com/novox/mesh-controller/internal/envfile 1.028s
ok github.com/novox/mesh-controller/internal/facts 1.030s
ok github.com/novox/mesh-controller/internal/identity 6.430s
ok github.com/novox/mesh-controller/internal/inventory 97.725s
ok github.com/novox/mesh-controller/internal/lease 17.679s
ok github.com/novox/mesh-controller/internal/licences 5.882s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.007s
ok github.com/novox/mesh-controller/internal/link 48.184s
ok github.com/novox/mesh-controller/internal/lint 1.748s
ok github.com/novox/mesh-controller/internal/outward 1.041s
ok github.com/novox/mesh-controller/internal/overlay 1.021s
ok github.com/novox/mesh-controller/internal/secrets 1.432s
ok github.com/novox/mesh-controller/internal/store 4.203s
ok github.com/novox/mesh-controller/internal/testbus 1.176s
ok github.com/novox/mesh-controller/internal/token 1.016s
**Merge check** at `3bab5b06`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Change plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on g14 as `build-1791396503732010736` (`builds --log build-1791396503732010736`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 46 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-07T18:01:12Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-07T18:01:12Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.032s
ok github.com/novox/mesh-controller/cmd/mesh-controller 187.991s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.008s
ok github.com/novox/mesh-controller/examples/route-proxy 1.259s
ok github.com/novox/mesh-controller/internal/artifacts 1.035s
ok github.com/novox/mesh-controller/internal/broker 2.371s
ok github.com/novox/mesh-controller/internal/builder 1.253s
ok github.com/novox/mesh-controller/internal/catalogue 3.625s
ok github.com/novox/mesh-controller/internal/conditions 1.954s
ok github.com/novox/mesh-controller/internal/envfile 1.028s
ok github.com/novox/mesh-controller/internal/facts 1.030s
ok github.com/novox/mesh-controller/internal/identity 6.430s
ok github.com/novox/mesh-controller/internal/inventory 97.725s
ok github.com/novox/mesh-controller/internal/lease 17.679s
ok github.com/novox/mesh-controller/internal/licences 5.882s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.007s
ok github.com/novox/mesh-controller/internal/link 48.184s
ok github.com/novox/mesh-controller/internal/lint 1.748s
ok github.com/novox/mesh-controller/internal/outward 1.041s
ok github.com/novox/mesh-controller/internal/overlay 1.021s
ok github.com/novox/mesh-controller/internal/secrets 1.432s
ok github.com/novox/mesh-controller/internal/store 4.203s
ok github.com/novox/mesh-controller/internal/testbus 1.176s
ok github.com/novox/mesh-controller/internal/token 1.016s
```
plans said a build queued for minutes had been building for a few seconds: the line counted from
the last save, and every advance saved the plan whether or not it moved, bumping its revision and
saying plan-moved on the bus. The line, status and LATE now count from when the plan entered its
tier with the stalled condition's bound, and an advance that changes nothing writes nothing.
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-controller@bf11a8baacda (merged as 96c34c52 into main, walk plan-17914006…
A refused step was logged on every 30-second tick with the same words; it is said, and kept,
when it is new. The refusal named the retired "release plan".
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on shanks as build-1791398825954994514 (builds --log build-1791398825954994514).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 46 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-07T18:46:45Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-07T18:46:45Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.033s
ok github.com/novox/mesh-controller/cmd/mesh-controller 485.001s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.025s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.037s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.030s
ok github.com/novox/mesh-controller/examples/route-proxy 1.222s
ok github.com/novox/mesh-controller/internal/artifacts 1.047s
ok github.com/novox/mesh-controller/internal/broker 2.618s
ok github.com/novox/mesh-controller/internal/builder 1.630s
ok github.com/novox/mesh-controller/internal/catalogue 4.235s
ok github.com/novox/mesh-controller/internal/conditions 2.027s
ok github.com/novox/mesh-controller/internal/envfile 1.052s
ok github.com/novox/mesh-controller/internal/facts 1.059s
ok github.com/novox/mesh-controller/internal/identity 48.082s
ok github.com/novox/mesh-controller/internal/inventory 283.760s
ok github.com/novox/mesh-controller/internal/lease 17.686s
ok github.com/novox/mesh-controller/internal/licences 46.463s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.050s
ok github.com/novox/mesh-controller/internal/link 85.436s
ok github.com/novox/mesh-controller/internal/lint 1.938s
ok github.com/novox/mesh-controller/internal/outward 1.079s
ok github.com/novox/mesh-controller/internal/overlay 1.062s
ok github.com/novox/mesh-controller/internal/secrets 1.515s
ok github.com/novox/mesh-controller/internal/store 22.839s
ok github.com/novox/mesh-controller/internal/testbus 1.232s
ok github.com/novox/mesh-controller/internal/token 1.013s
**Merge check** at `ea92af2a`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on shanks as `build-1791398825954994514` (`builds --log build-1791398825954994514`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 46 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-07T18:46:45Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-07T18:46:45Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.033s
ok github.com/novox/mesh-controller/cmd/mesh-controller 485.001s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.025s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.037s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.030s
ok github.com/novox/mesh-controller/examples/route-proxy 1.222s
ok github.com/novox/mesh-controller/internal/artifacts 1.047s
ok github.com/novox/mesh-controller/internal/broker 2.618s
ok github.com/novox/mesh-controller/internal/builder 1.630s
ok github.com/novox/mesh-controller/internal/catalogue 4.235s
ok github.com/novox/mesh-controller/internal/conditions 2.027s
ok github.com/novox/mesh-controller/internal/envfile 1.052s
ok github.com/novox/mesh-controller/internal/facts 1.059s
ok github.com/novox/mesh-controller/internal/identity 48.082s
ok github.com/novox/mesh-controller/internal/inventory 283.760s
ok github.com/novox/mesh-controller/internal/lease 17.686s
ok github.com/novox/mesh-controller/internal/licences 46.463s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.050s
ok github.com/novox/mesh-controller/internal/link 85.436s
ok github.com/novox/mesh-controller/internal/lint 1.938s
ok github.com/novox/mesh-controller/internal/outward 1.079s
ok github.com/novox/mesh-controller/internal/overlay 1.062s
ok github.com/novox/mesh-controller/internal/secrets 1.515s
ok github.com/novox/mesh-controller/internal/store 22.839s
ok github.com/novox/mesh-controller/internal/testbus 1.232s
ok github.com/novox/mesh-controller/internal/token 1.013s
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
novox/hq issue 296.
Symptom.
plansshowed a plan as "building for 1s", then "4s", then "9s" over several minutes. Its build had been asked minutes before and was still queued.Cause.
planLineWith,planStatusesandopenPlanscounted fromp.Updated. The store stamps that tonow()on every save, and LATE compared it against a fixed 30m. The stalled watchdog (S3) counts fromTierEntered, against the measured boundmax(tierAtLeast, 3*p90).advanceHeldsaved every plan after every step, even whenadvanceOncereported no move. It runs every 30s and after every build outcome on the mesh. Each run bumped the revision and saidplan-movedon the bus. A plan waiting on a queued build changes nothing on a step, so these writes were needless.Fix.
inTierSince(p)gives the start time. It isTierEntered, or the delivery's go if that came later. A waiting walk usesCreated, as S16 does. A plan without the stamp falls back toUpdated. The line,status --json(since/late), the late count and the watchdog all use it.tierBounds/measuredTierBoundsgive one bound for the watchdog,plansandstatus, so LATE is the stalled condition said on the line. A waiting walk is never called late; S16 is its watchdog.advanceHeldcompares a snapshot of the plan before and after each step, and saves only if it changed. The snapshot leaves out the fields the store stamps.Tests.
plan_clock_test.go. Both tests were shown to fail with the fix reverted:watchPlanson both sides of a measured bound.updatedunchanged. Before the fix the revision went from 3 to 6.sh merge-check.shpassed locally with the race detector, exceptinternal/broker's genesis-template test. That test reads the sibling mesh-host checkout, which was 23 commits behind locally. It passes against mesh-host origin/main.Delivery
novox/mesh-controller@ea92af2a7d77— covered since 2026-10-09T07:31:59ZDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Machines
Transitions
96c34c52into main, walk plan-1791400660610297560): build-agent, mesh-controller, route-proxyThe commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
3bab5b06mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedChange plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on g14 as
build-1791396503732010736(builds --log build-1791396503732010736).3bab5b06e9toea92af2a7dMerge check at
ea92af2amesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on shanks as
build-1791398825954994514(builds --log build-1791398825954994514).