novox/hq issue 740. The gitea module's watcher and its tools run as two processes on one kept token file; both minted at 21:29:54 and the forge held two tokens named mesh-tools, so the replace by name failed with 422 for ever and every forge tool call failed. A replace now lists every page of the account's tokens and deletes each one named mesh-tools by its id, then mints; a lock file beside the kept token lets one process mint at a time (a dead holder's lock, or one older than 120 s, is taken over), and the holder reads the kept file again and reuses a token the other process minted. Three new tests fail on main. Reviewed before push (approved at d1debdc). Follow-up from the review: an abort timeout under 120 s on the mint's fetch.
novox/hq issue 740. The gitea module's watcher and its tools run as two processes on one kept token file; both minted at 21:29:54 and the forge held two tokens named mesh-tools, so the replace by name failed with 422 for ever and every forge tool call failed. A replace now lists every page of the account's tokens and deletes each one named mesh-tools by its id, then mints; a lock file beside the kept token lets one process mint at a time (a dead holder's lock, or one older than 120 s, is taken over), and the holder reads the kept file again and reuses a token the other process minted. Three new tests fail on main. Reviewed before push (approved at d1debdc). Follow-up from the review: an abort timeout under 120 s on the mint's fetch.
mesh/merge-gate head d1debdcce816 merged into trunk 0e7d9e74d22a — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head d1debdcce816 merged into trunk 0e7d9e74d22a — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The runtime starts the watcher and the tools as two processes over one kept
token. Both minted at once on 2026-10-14 and left two tokens named
mesh-tools; gitea refuses a delete by a name held twice, so every mint
failed and every forge tool with it. A replace now deletes each token by
the name by its id, from the account's whole list, and a mint holds a lock
file beside the kept token and reuses what another process minted.
Deliverynovox/mesh-catalog@d1debdcce816 — delivered since 2026-10-14T21:05:53Z
Delivery plan — builds gitea → novox; no bus step
tier 0: gitea
novox: receives gitea
gitea provides npm-package-registry, git: its consumers are sent again after it
gitea keeps data (ADR 0233): what it holds is backed up before it moves
Machines
gitea on every machine running it: sent
Transitions
2026-10-14 20:57 (new) → proposed (announced): novox/mesh-catalog#306's head announced
2026-10-14 21:03 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-14 21:03 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-14 21:03 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-14 21:03 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-14 21:05 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@d1debdcce816` — **delivered** since 2026-10-14T21:05:53Z
**Delivery plan** — builds gitea → novox; no bus step
- tier 0: gitea
- novox: receives gitea
- gitea provides npm-package-registry, git: its consumers are sent again after it
- gitea keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- gitea on every machine running it: sent
**Transitions**
- 2026-10-14 20:57 (new) → proposed (announced): novox/mesh-catalog#306's head announced
- 2026-10-14 21:03 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-14 21:03 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-14 21:03 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-14 21:03 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-14 21:05 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Merge check at d1debdcc
Judged: head d1debdcce816 merged into trunk 0e7d9e74d22a; read beside it: mesh-controller 86057f455194, mesh-controller-main 60cc9ec363df, mesh-host 1a2677882380, mesh-tools 5d70eb3e35a9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
Delivery plan — builds gitea → novox; no bus step
tier 0: gitea
novox: receives gitea
gitea provides npm-package-registry, git: its consumers are sent again after it
gitea keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as build-1792011472786875874 (builds --log build-1792011472786875874).
--- the gate: gitea
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T20:36:53Z 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-14T20:36:53Z
modules the change moves:
- gitea (changed)
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-delivery, 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 1 module(s) in 1 tier(s): gitea
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.042s
words: 12 retired words and 70 daemons' lines, none in the 47278 strings of 722 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.014s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.007s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.468s
testing modules/gitea
ok gitea/cmd/forge 2.355s
ok gitea/cmd/npm-registry 2.691s
? gitea/internal/forgehttp [no test files]
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (59.240083ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (418.823622ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (10.999575ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (69.433297ms)
✔ a pull request's ready mark is read: the label and the head the newest listed ready comment names (87.402586ms)
✔ a ready comment by an account not listed is ignored, and said (0.495072ms)
✔ a ready comment older than the latest push, or than the label, never counts (170.193883ms)
[gitea] f cannot be read (gone); only mesh-admin may mark a pull request ready
[gitea] f names no account that may mark a pull request ready; only mesh-admin may
✔ a long thread hides nothing: every page of the timeline is read (77.824835ms)
✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (8.083858ms)
✔ the newest status of each context is kept, with what it said, when and by whom (20.649836ms)
✔ a commit merges only when every required status is a success; a warning blocks (1.129243ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.28528ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (2.358615ms)
✔ a note line is appended once, as the forge's user, in its own repository (16.354927ms)
✔ a note that cannot be written is said, never read as written (0.861532ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.783682ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (51.692596ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (12.412189ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.403003ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.678172ms)
✔ a start heard after the verdict writes nothing (0.462231ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.579681ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.242913ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (3.434398ms)
✔ a rechecked head says where its new run is: building on which machine (1.310143ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.802642ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.788932ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.573661ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.736842ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.27681ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.401951ms)
✔ a repository as the mesh clones it is told from another (0.315261ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (7.157036ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (125.924993ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (95.635865ms)
✔ gitea_api still writes what an author writes (19.621394ms)
✔ gitea_branch_protection_set only strengthens (31.26634ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (125.606123ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (397.145624ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (45.098971ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (32.741093ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (65.527338ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (132.405268ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (53.3717ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (17.084729ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.779158ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (41.406433ms)
✔ a repository owner or name is never another path (0.382781ms)
✔ the judges, without a forge (3.417488ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (10.683504ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (6.096494ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (9.957772ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (240.781391ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (2.706846ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (67.084401ms)
✔ a lookup the forge refuses is thrown, not read as no module (52.498898ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (77.179554ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (179.274363ms)
✔ a pass pages until it reaches back past its floor, and no further (115.845091ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (11.632116ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.401951ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (31.995412ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.112453ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (2.315615ms)
✔ no verdict sets warning on a required check; only a person's decision fails (2.134645ms)
✔ a commit status is set on the commit, under the merge check's context (213.22877ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (19.680705ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.412831ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (17.100818ms)
✔ a consumer that asks nothing, or write, publishes: the package team (24.577865ms)
✔ a consumer that asks to read joins the readers, who write no package (10.154733ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.590331ms)
✔ a publisher is made and put on the package team, as before (0.21937ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (57.93985ms)
✔ second start: reuses the kept token, mints nothing (53.304059ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (85.666572ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (73.532595ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (82.995427ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (32.039122ms)
✔ concurrent first calls share one mint (35.70208ms)
✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (32.198753ms)
✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (86.505595ms)
✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (13.023679ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (26.936101ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (1.849624ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (30.583139ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (3.264328ms)
✔ nothing to mint with and no token: the client says what is missing (0.23844ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-X3GLNv/state/token
✔ the tools register once there is a way to a token, and the first call mints it (18.952873ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-sVrDQW/state/token
✔ a pull request can be closed, read and cleaned up through the tools (44.32666ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-controller's feat/57-config-and-provisioning moved from eeeeeeeeeeee to d28ca95ccccc: 1 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (23.541803ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (22.940221ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (20.896357ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (1.064192ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (1.590353ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.381271ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.336721ms)
✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (2.028995ms)
✔ a signed event is published on the bus and acted on once (250.863744ms)
✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (135.527435ms)
✔ an event and the poll seeing the same head announce it once (0.551271ms)
✔ each forge event is named in the module's stream and trimmed (0.735931ms)
✔ the system webhook is made when none points at the receiver, and corrected when one does (2.459566ms)
✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (5.847993ms)
ℹ tests 104
ℹ suites 0
ℹ pass 104
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1964.583719
**Merge check** at `d1debdcc`
Judged: head `d1debdcce816` merged into trunk `0e7d9e74d22a`; read beside it: mesh-controller `86057f455194`, mesh-controller-main `60cc9ec363df`, mesh-host `1a2677882380`, mesh-tools `5d70eb3e35a9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
**Delivery plan** — builds gitea → novox; no bus step
- tier 0: gitea
- novox: receives gitea
- gitea provides npm-package-registry, git: its consumers are sent again after it
- gitea keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as `build-1792011472786875874` (`builds --log build-1792011472786875874`).
```
--- the gate: gitea
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T20:36:53Z 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-14T20:36:53Z
modules the change moves:
- gitea (changed)
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-delivery, 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 1 module(s) in 1 tier(s): gitea
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.042s
words: 12 retired words and 70 daemons' lines, none in the 47278 strings of 722 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.014s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.007s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.468s
testing modules/gitea
ok gitea/cmd/forge 2.355s
ok gitea/cmd/npm-registry 2.691s
? gitea/internal/forgehttp [no test files]
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (59.240083ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (418.823622ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (10.999575ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (69.433297ms)
✔ a pull request's ready mark is read: the label and the head the newest listed ready comment names (87.402586ms)
✔ a ready comment by an account not listed is ignored, and said (0.495072ms)
✔ a ready comment older than the latest push, or than the label, never counts (170.193883ms)
[gitea] f cannot be read (gone); only mesh-admin may mark a pull request ready
[gitea] f names no account that may mark a pull request ready; only mesh-admin may
✔ a long thread hides nothing: every page of the timeline is read (77.824835ms)
✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (8.083858ms)
✔ the newest status of each context is kept, with what it said, when and by whom (20.649836ms)
✔ a commit merges only when every required status is a success; a warning blocks (1.129243ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.28528ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (2.358615ms)
✔ a note line is appended once, as the forge's user, in its own repository (16.354927ms)
✔ a note that cannot be written is said, never read as written (0.861532ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.783682ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (51.692596ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (12.412189ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.403003ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.678172ms)
✔ a start heard after the verdict writes nothing (0.462231ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.579681ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.242913ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (3.434398ms)
✔ a rechecked head says where its new run is: building on which machine (1.310143ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.802642ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.788932ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.573661ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.736842ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.27681ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.401951ms)
✔ a repository as the mesh clones it is told from another (0.315261ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (7.157036ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (125.924993ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (95.635865ms)
✔ gitea_api still writes what an author writes (19.621394ms)
✔ gitea_branch_protection_set only strengthens (31.26634ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (125.606123ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (397.145624ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (45.098971ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (32.741093ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (65.527338ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (132.405268ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (53.3717ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (17.084729ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.779158ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (41.406433ms)
✔ a repository owner or name is never another path (0.382781ms)
✔ the judges, without a forge (3.417488ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (10.683504ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (6.096494ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (9.957772ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (240.781391ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (2.706846ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (67.084401ms)
✔ a lookup the forge refuses is thrown, not read as no module (52.498898ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (77.179554ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (179.274363ms)
✔ a pass pages until it reaches back past its floor, and no further (115.845091ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (11.632116ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.401951ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (31.995412ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.112453ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (2.315615ms)
✔ no verdict sets warning on a required check; only a person's decision fails (2.134645ms)
✔ a commit status is set on the commit, under the merge check's context (213.22877ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (19.680705ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.412831ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (17.100818ms)
✔ a consumer that asks nothing, or write, publishes: the package team (24.577865ms)
✔ a consumer that asks to read joins the readers, who write no package (10.154733ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.590331ms)
✔ a publisher is made and put on the package team, as before (0.21937ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (57.93985ms)
✔ second start: reuses the kept token, mints nothing (53.304059ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (85.666572ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (73.532595ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (82.995427ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (32.039122ms)
✔ concurrent first calls share one mint (35.70208ms)
✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (32.198753ms)
✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (86.505595ms)
✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (13.023679ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (26.936101ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (1.849624ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (30.583139ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (3.264328ms)
✔ nothing to mint with and no token: the client says what is missing (0.23844ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-X3GLNv/state/token
✔ the tools register once there is a way to a token, and the first call mints it (18.952873ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-sVrDQW/state/token
✔ a pull request can be closed, read and cleaned up through the tools (44.32666ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-controller's feat/57-config-and-provisioning moved from eeeeeeeeeeee to d28ca95ccccc: 1 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (23.541803ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (22.940221ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (20.896357ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (1.064192ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (1.590353ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.381271ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.336721ms)
✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (2.028995ms)
✔ a signed event is published on the bus and acted on once (250.863744ms)
✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (135.527435ms)
✔ an event and the poll seeing the same head announce it once (0.551271ms)
✔ each forge event is named in the module's stream and trimmed (0.735931ms)
✔ the system webhook is made when none points at the receiver, and corrected when one does (2.459566ms)
✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (5.847993ms)
ℹ tests 104
ℹ suites 0
ℹ pass 104
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1964.583719
```
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 740. The gitea module's watcher and its tools run as two processes on one kept token file; both minted at 21:29:54 and the forge held two tokens named mesh-tools, so the replace by name failed with 422 for ever and every forge tool call failed. A replace now lists every page of the account's tokens and deletes each one named mesh-tools by its id, then mints; a lock file beside the kept token lets one process mint at a time (a dead holder's lock, or one older than 120 s, is taken over), and the holder reads the kept file again and reuses a token the other process minted. Three new tests fail on main. Reviewed before push (approved at
d1debdc). Follow-up from the review: an abort timeout under 120 s on the mint's fetch.ready at
d1debdcce8Delivery
novox/mesh-catalog@d1debdcce816— delivered since 2026-10-14T21:05:53ZDelivery plan — builds gitea → novox; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
d1debdccJudged: head
d1debdcce816merged into trunk0e7d9e74d22a; read beside it: mesh-controller86057f455194, mesh-controller-main60cc9ec363df, mesh-host1a2677882380, mesh-tools5d70eb3e35a9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)Delivery plan — builds gitea → novox; no bus step
Run by the build seat on novox as
build-1792011472786875874(builds --log build-1792011472786875874).