Feature agents-write-git, step 2: git over SSH with a key made on each machine (issue 955) #340

Merged
mesh-tools merged 14 commits from feat/agents-write-git-ssh into main 2026-10-16 22:31:17 +00:00
Member

Issue 955, under ADR 0399 and ADR 0400 (accepted 2026-10-16).

ssh-client (every machine): its tools bundle keeps ~/.ssh/mesh_ed25519 for the machine's account, made there when missing and never overwritten, and writes the public half and fingerprint to its own state keys at <node>.<account> (no private material). It requires forge-account, and its templates fill a marked block in known_hosts, ~/.ssh/config.d/10-forge, and a marked block in ~/.config/git/config that rewrites https://git.novox.be/ to ssh://git@novox.internal:222/.

gitea: a new forge-account-provider (SDK provider.New, with gitea's own idempotent Make and Gone) reads ssh-client.keys through a reads grant, keeps agent-<node> in the agents' team, registers exactly the reported key under the title mesh:<node>.<account> (removing earlier mesh: keys, never another key), and serves user, ssh_host, ssh_port, known_host, ssh_base and https_base in its bound entry. It removes nothing until the key state has been read once. The agent-account code moves to internal/forgeaccount, shared with agent-token.

Not in this step: retiring the claude-code token (ADR 0399 §4, step 3).

Review: 3 rounds by the reviewer on the larger model, approved at 6f45570d4c. Integration tests S4 (key process over a real bus) and F5 (provider over a real bus, fake forge) run in the merge check.

Opened along the way: 965, 966, 967.

One delivery group with novox/hq feat/agents-write-git-ssh (design 29).

Issue 955, under ADR 0399 and ADR 0400 (accepted 2026-10-16). **ssh-client** (every machine): its tools bundle keeps `~/.ssh/mesh_ed25519` for the machine's account, made there when missing and never overwritten, and writes the public half and fingerprint to its own state `keys` at `<node>.<account>` (no private material). It requires `forge-account`, and its templates fill a marked block in `known_hosts`, `~/.ssh/config.d/10-forge`, and a marked block in `~/.config/git/config` that rewrites `https://git.novox.be/` to `ssh://git@novox.internal:222/`. **gitea**: a new `forge-account-provider` (SDK `provider.New`, with gitea's own idempotent Make and Gone) reads `ssh-client.keys` through a `reads` grant, keeps `agent-<node>` in the agents' team, registers exactly the reported key under the title `mesh:<node>.<account>` (removing earlier `mesh:` keys, never another key), and serves `user`, `ssh_host`, `ssh_port`, `known_host`, `ssh_base` and `https_base` in its `bound` entry. It removes nothing until the key state has been read once. The agent-account code moves to `internal/forgeaccount`, shared with agent-token. Not in this step: retiring the claude-code token (ADR 0399 §4, step 3). Review: 3 rounds by the reviewer on the larger model, approved at 6f45570d4c23f5248144e2ffef5d4c7e920ba086. Integration tests S4 (key process over a real bus) and F5 (provider over a real bus, fake forge) run in the merge check. Opened along the way: 965, 966, 967. One delivery group with novox/hq feat/agents-write-git-ssh (design 29).
mesh-tools added 13 commits 2026-10-16 20:58:34 +00:00
Do not remove keys or entries before the machines' keys are read (issue 955 F)
mesh/merge-gate head 6f45570d4c23 merged into trunk 017b729bc95d — fail: builds gitea, ssh-client → ace, g14, novox, shanks; no bus step; 4 problem(s) the …
mesh/repo-check head 6f45570d4c23 merged into trunk 017b729bc95d — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery-group group feat/agents-write-git-ssh rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request
6f45570d4c
Author
Member

Delivery novox/mesh-catalog@ae9cda8531b3 — failed since 2026-10-16T22:32:35Z

Covered: covered after its failure: a later walk that contains it was delivered: plan-1792195559895153198 (novox/mesh-catalog at 82df3bd5 into main, done, contains its merge 734a77f5)

Delivery plan — builds gitea, ssh-client → ace, g14, novox, shanks; no bus step

  • tier 0: gitea, ssh-client
  • ace: receives ssh-client
  • g14: receives ssh-client
  • novox: receives gitea, ssh-client
  • shanks: receives ssh-client
  • gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • ssh-client keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine

Group feat/agents-write-git-ssh, in order: novox/hq@24701df23e → novox/mesh-catalog@ae9cda8531

  • composed together: pass — every machine composes with the change as it did without (4 of 4 compose)

Transitions

  • 2026-10-16 22:05 (new) → proposed (announced): novox/mesh-catalog#340's head announced
  • 2026-10-16 22:08 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-16 22:08 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-16 22:31 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-16 22:31 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-16 22:32 delivering → failed (failed): its walk failed, carrying its own commit: a gate on a first machine (what it carried put back), a build, a machine

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-catalog@ae9cda8531b3` — **failed** since 2026-10-16T22:32:35Z **Covered**: covered after its failure: a later walk that contains it was delivered: plan-1792195559895153198 (novox/mesh-catalog at 82df3bd5 into main, done, contains its merge 734a77f5) **Delivery plan** — builds gitea, ssh-client → ace, g14, novox, shanks; no bus step - tier 0: gitea, ssh-client - ace: receives ssh-client - g14: receives ssh-client - novox: receives gitea, ssh-client - shanks: receives ssh-client - gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - ssh-client keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine **Group** `feat/agents-write-git-ssh`, in order: novox/hq@24701df23e8a → novox/mesh-catalog@ae9cda8531b3 - composed together: pass — every machine composes with the change as it did without (4 of 4 compose) **Transitions** - 2026-10-16 22:05 (new) → proposed (announced): novox/mesh-catalog#340's head announced - 2026-10-16 22:08 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-16 22:08 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-16 22:31 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-16 22:31 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-16 22:32 delivering → failed (failed): its walk failed, carrying its own commit: a gate on a first machine (what it carried put back), a build, a machine The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Author
Member

Merge check at 6f45570d
Judged: head 6f45570d4c23 merged into trunk 017b729bc95d; read beside it: mesh-controller 53a3c91f53ce, mesh-controller-main 1cdf12df00b5, mesh-host cd13f7726ef0, mesh-tools 7412c5b6c9c5

  • mesh/merge-gate: FAIL — 4 problem(s) the change brings; the first: a machine (f35): nothing could be sent to it with this change — ssh-client asks its forge-account binding for "known_host", and what answers it says "address", "as", "at" or "from" (modules: gitea, ssh-client)
  • 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, ssh-client → ace, g14, novox, shanks; no bus step

  • tier 0: gitea, ssh-client
  • ace: receives ssh-client
  • g14: receives ssh-client
  • novox: receives gitea, ssh-client
  • shanks: receives ssh-client
  • gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • ssh-client keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine
  • read by no module's build: modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go, modules/ssh-client/cmd/ssh-client-tools/keykeeper_test.go, modules/ssh-client/cmd/ssh-client-tools/templates_test.go

Run by the build seat on shanks as build-1792184317773818513 (builds --log build-1792184317773818513).

✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (0.996036ms)
✔ the newest status of each context is kept, with what it said, when and by whom (29.49776ms)
✔ a commit merges only when every required status is a success; a warning blocks (1.750482ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.327742ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.983136ms)
✔ a note line is appended once, as the forge's user, in its own repository (21.307318ms)
✔ a note that cannot be written is said, never read as written (0.537074ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.779275ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (37.301421ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (6.700263ms)
[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.43382ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.628414ms)
✔ a start heard after the verdict writes nothing (0.611684ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.804865ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.128977ms)
[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.056779ms)
✔ a rechecked head says where its new run is: building on which machine (1.184608ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.832626ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.665614ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.598733ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.590877ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.408703ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (1.52964ms)
✔ a repository as the mesh clones it is told from another (0.361912ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.1449ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (55.81583ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (30.288405ms)
✔ gitea_api still writes what an author writes (9.915634ms)
✔ gitea_branch_protection_set only strengthens (20.1742ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (50.631746ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (150.49121ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.699374ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (13.628448ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.294584ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (57.836283ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (21.050976ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.622374ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.291017ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (13.722928ms)
✔ a repository owner or name is never another path (0.309732ms)
✔ the judges, without a forge (0.381263ms)
✔ main's protection is never weakened in its push or its merge whitelist (issue 948, ADR 0398 §2) (0.248002ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (1.783772ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.503066ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.113573ms)
✔ gitea_merge_pull_request merges a verdict that read siblings only with its group passed and each sibling head reviewed (89.879421ms)
✔ a verdict put out of date by a sibling's move is refused in its own words, and asked again once (23.793683ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (39.192863ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.614393ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (18.087636ms)
✔ a lookup the forge refuses is thrown, not read as no module (5.740277ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (9.399361ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (75.930099ms)
✔ a pass pages until it reaches back past its floor, and no further (31.20745ms)
✔ gitea_branch_protection_get answers every rule, read with the administrator account the tools' token cannot read with (29.149917ms)
✔ gitea_branch_protection_get answers the rule for a branch, null when it has none (10.188606ms)
✔ gitea_branch_protection_set still gets the forge's refusal, as the tools' account (4.105636ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (5.421895ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.394442ms)
✔ main's body always refuses pushes and lets only the tools' account merge, whatever is asked (0.858655ms)
✔ another branch's body carries no merge whitelist (0.287392ms)
✔ the rule main is put right in the forge's own words: the body a setup sends carries no status checks of its own (0.394792ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (20.358261ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (0.955257ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (1.013266ms)
✔ no verdict sets warning on a required check; only a person's decision fails (0.922646ms)
✔ a commit status is set on the commit, under the merge check's context (43.049537ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.571763ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.350792ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.573667ms)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 at bbbbbbbbbbbb, it is now at dddddddddddd: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was closed unmerged: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 merged onto cccccccccccc, its main is now eeeeeeeeeeee: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-host's main moved from 444444444444 to 333333333333: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses name the siblings the verdict read, keeping the verdict word and the start of its reason within 140 characters (2.593177ms)
✔ a verdict that could not learn its siblings says so on the status and in the comment, and names none (0.428613ms)
✔ a verdict without siblings is said exactly as before (an older controller) (0.856436ms)
✔ the siblings a verdict names are kept per member, replaced by its next verdict, and removed by one that read none (1.009537ms)
✔ a sibling's new head puts both statuses of the member back to pending, with the reason, and runs nothing (3.916835ms)
✔ a sibling closed unmerged puts the member's verdict out of date (0.503023ms)
✔ a move of the sibling's base puts it out of date, naming both commits (0.508053ms)
✔ the sibling's own merge of the head read onto the base read does not, in either order of the two merges (0.690205ms)
✔ a merge of another head, or onto another base, is a move (1.148408ms)
✔ only the members whose verdict names the sibling are touched, and a member that moved on is dropped (0.850135ms)
✔ a trunk that moved tells the siblings' weighing; one first seen does not (0.859435ms)
✔ the group rule names every missing thing: the group status at each head read, and each sibling head's review (1.073487ms)
✔ a merged or closed member's entry is dropped, so a sibling's later push never re-pends its merged head (0.270672ms)
✔ a consumer that asks nothing, or write, publishes: the package team (2.224155ms)
✔ a consumer that asks to read joins the readers, who write no package (0.720095ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.549103ms)
✔ a publisher is made and put on the package team, as before (0.224721ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (44.501937ms)
✔ second start: reuses the kept token, mints nothing (28.982286ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (28.976037ms)
✔ 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 (32.020797ms)
✔ 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 (27.696079ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (25.309174ms)
✔ concurrent first calls share one mint (16.507176ms)
✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (16.284155ms)
✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (62.02393ms)
✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (6.028509ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (17.449353ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.814335ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (22.728606ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.704307ms)
✔ nothing to mint with and no token: the client says what is missing (0.213322ms)
[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-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-dT9Z6L/state/token
✔ the tools register once there is a way to a token, and the first call mints it (29.48841ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-pR2QPr/state/token
✔ a pull request can be closed, read and cleaned up through the tools (37.673513ms)
[gitea] no token kept — minting one
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-V03qOP/state/token
✔ the tools' token is minted for an account of their own, which is no administrator and writes through its team (93.23407ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-6UD3o4/state/token
✔ with the tools' token, the forge writes a status and refuses a protection edit — the forge itself, not a guard (62.276681ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-2Ym0YR/state/token
✔ what a base's protection asks is read from the branch, which the tools' account may read, not from the rules' list it may not (50.752207ms)
[gitea] the kept token was minted with other scopes than the tools take now — minting one with them
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-aXncVG/state/token
[gitea] deleted 1 token(s) named "mesh-tools" the admin account "mesh-admin" held: the tools act as "mesh-tools" now
✔ the administrator's token from before goes: a kept admin token is minted again for the tools' account, and the forge drops the old one (52.544168ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-S7FEmb/state/token
✔ a tools' account someone made an administrator is made a plain account again at the next mint (38.297558ms)
✔ the tools never act as the administrator: MESH_GITEA_TOOLS_USER naming it is refused (1.012227ms)
✔ the manifest hands the tools their account, and the merge-ready authors name it rather than the administrator (1.042757ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-RH9eMW/state/token
✔ a repository check said as a warning on a head without merge-check.sh reads the base's protection from the branch (41.591149ms)
[gitea] no token kept — minting one
✔ a mint that fails leaves the administrator's old token in place: the tools are never left without one (31.326852ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-u4A0Fu/state/token
[gitea] FAILED to delete the token(s) named "mesh-tools" the admin account "mesh-admin" holds — tried again at the next start: Gitea DELETE /users/mesh-admin/tokens/902 (named mesh-tools): 500 {"message":"the forge is not well"}
✔ an old token that cannot be deleted after the mint is said, the new token kept, and deleted at the next start (49.043327ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-eVEpdU/state/token
✔ a team another process made between the look and the create is found, not a failure (42.530485ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-z9RksA/state/token
✔ setting the tools' account up puts main's rule right in every repository: no push, only the tools' account merges (issue 948) (38.526369ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Dnd9F7/state/token
✔ a glob rule covering main keeps its statuses when main is given a rule of its own name (issue 948, review round 1) (38.187117ms)
✔ a start with the token kept still puts main's rules right: the module's start asks for it each time (issue 948, review round 1) (13.581238ms)
[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 (2.495656ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.4566ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (5.841468ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.951097ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.585294ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.345292ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.446332ms)
✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (1.464999ms)
✔ a signed event is published on the bus and acted on once (67.290554ms)
✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (39.054402ms)
✔ an event and the poll seeing the same head announce it once (0.563423ms)
✔ each forge event is named in the module's stream and trimmed (0.735795ms)
✔ the webhook is made a system webhook, which the forge sends every repository's events to (1.47756ms)
✔ default webhooks left at the receiver by an earlier start are replaced by one system webhook (1.428569ms)
✔ a repository's copy of a default webhook at the receiver is deleted, on every page, and said (5.287073ms)
✔ a forge that makes no system webhook is said, never taken as heard (0.993257ms)
✔ the receiver tells what it verified and what it refused (10.845129ms)
✔ a forge that never delivers is said loudly once, and unhealthy, when the poll finds what no event said (1.365349ms)
✔ a forge whose events stop after one delivery is said loudly once per silent spell, and refusals are unhealthy (0.532724ms)
✔ without a receiver by configuration the polls alone watch, healthy; a receiver that failed is unhealthy (0.434543ms)
✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (0.258161ms)
ℹ tests 147
ℹ suites 0
ℹ pass 147
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 849.901758
**Merge check** at `6f45570d` Judged: head `6f45570d4c23` merged into trunk `017b729bc95d`; read beside it: mesh-controller `53a3c91f53ce`, mesh-controller-main `1cdf12df00b5`, mesh-host `cd13f7726ef0`, mesh-tools `7412c5b6c9c5` - `mesh/merge-gate`: **FAIL** — 4 problem(s) the change brings; the first: a machine (f35): nothing could be sent to it with this change — ssh-client asks its forge-account binding for "known_host", and what answers it says "address", "as", "at" or "from" (modules: gitea, ssh-client) - `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, ssh-client → ace, g14, novox, shanks; no bus step - tier 0: gitea, ssh-client - ace: receives ssh-client - g14: receives ssh-client - novox: receives gitea, ssh-client - shanks: receives ssh-client - gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - ssh-client keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine - read by no module's build: modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go, modules/ssh-client/cmd/ssh-client-tools/keykeeper_test.go, modules/ssh-client/cmd/ssh-client-tools/templates_test.go Run by the build seat on shanks as `build-1792184317773818513` (`builds --log build-1792184317773818513`). ``` ✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (0.996036ms) ✔ the newest status of each context is kept, with what it said, when and by whom (29.49776ms) ✔ a commit merges only when every required status is a success; a warning blocks (1.750482ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.327742ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.983136ms) ✔ a note line is appended once, as the forge's user, in its own repository (21.307318ms) ✔ a note that cannot be written is said, never read as written (0.537074ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.779275ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (37.301421ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (6.700263ms) [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.43382ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.628414ms) ✔ a start heard after the verdict writes nothing (0.611684ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.804865ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.128977ms) [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.056779ms) ✔ a rechecked head says where its new run is: building on which machine (1.184608ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.832626ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.665614ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.598733ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.590877ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.408703ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (1.52964ms) ✔ a repository as the mesh clones it is told from another (0.361912ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.1449ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (55.81583ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (30.288405ms) ✔ gitea_api still writes what an author writes (9.915634ms) ✔ gitea_branch_protection_set only strengthens (20.1742ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (50.631746ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (150.49121ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.699374ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (13.628448ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.294584ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (57.836283ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (21.050976ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.622374ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.291017ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (13.722928ms) ✔ a repository owner or name is never another path (0.309732ms) ✔ the judges, without a forge (0.381263ms) ✔ main's protection is never weakened in its push or its merge whitelist (issue 948, ADR 0398 §2) (0.248002ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (1.783772ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.503066ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.113573ms) ✔ gitea_merge_pull_request merges a verdict that read siblings only with its group passed and each sibling head reviewed (89.879421ms) ✔ a verdict put out of date by a sibling's move is refused in its own words, and asked again once (23.793683ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (39.192863ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.614393ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (18.087636ms) ✔ a lookup the forge refuses is thrown, not read as no module (5.740277ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (9.399361ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (75.930099ms) ✔ a pass pages until it reaches back past its floor, and no further (31.20745ms) ✔ gitea_branch_protection_get answers every rule, read with the administrator account the tools' token cannot read with (29.149917ms) ✔ gitea_branch_protection_get answers the rule for a branch, null when it has none (10.188606ms) ✔ gitea_branch_protection_set still gets the forge's refusal, as the tools' account (4.105636ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (5.421895ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.394442ms) ✔ main's body always refuses pushes and lets only the tools' account merge, whatever is asked (0.858655ms) ✔ another branch's body carries no merge whitelist (0.287392ms) ✔ the rule main is put right in the forge's own words: the body a setup sends carries no status checks of its own (0.394792ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (20.358261ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (0.955257ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (1.013266ms) ✔ no verdict sets warning on a required check; only a person's decision fails (0.922646ms) ✔ a commit status is set on the commit, under the merge check's context (43.049537ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.571763ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.350792ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.573667ms) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 at bbbbbbbbbbbb, it is now at dddddddddddd: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was closed unmerged: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 merged onto cccccccccccc, its main is now eeeeeeeeeeee: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-host's main moved from 444444444444 to 333333333333: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses name the siblings the verdict read, keeping the verdict word and the start of its reason within 140 characters (2.593177ms) ✔ a verdict that could not learn its siblings says so on the status and in the comment, and names none (0.428613ms) ✔ a verdict without siblings is said exactly as before (an older controller) (0.856436ms) ✔ the siblings a verdict names are kept per member, replaced by its next verdict, and removed by one that read none (1.009537ms) ✔ a sibling's new head puts both statuses of the member back to pending, with the reason, and runs nothing (3.916835ms) ✔ a sibling closed unmerged puts the member's verdict out of date (0.503023ms) ✔ a move of the sibling's base puts it out of date, naming both commits (0.508053ms) ✔ the sibling's own merge of the head read onto the base read does not, in either order of the two merges (0.690205ms) ✔ a merge of another head, or onto another base, is a move (1.148408ms) ✔ only the members whose verdict names the sibling are touched, and a member that moved on is dropped (0.850135ms) ✔ a trunk that moved tells the siblings' weighing; one first seen does not (0.859435ms) ✔ the group rule names every missing thing: the group status at each head read, and each sibling head's review (1.073487ms) ✔ a merged or closed member's entry is dropped, so a sibling's later push never re-pends its merged head (0.270672ms) ✔ a consumer that asks nothing, or write, publishes: the package team (2.224155ms) ✔ a consumer that asks to read joins the readers, who write no package (0.720095ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.549103ms) ✔ a publisher is made and put on the package team, as before (0.224721ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (44.501937ms) ✔ second start: reuses the kept token, mints nothing (28.982286ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (28.976037ms) ✔ 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 (32.020797ms) ✔ 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 (27.696079ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (25.309174ms) ✔ concurrent first calls share one mint (16.507176ms) ✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (16.284155ms) ✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (62.02393ms) ✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (6.028509ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (17.449353ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.814335ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (22.728606ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.704307ms) ✔ nothing to mint with and no token: the client says what is missing (0.213322ms) [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-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-dT9Z6L/state/token ✔ the tools register once there is a way to a token, and the first call mints it (29.48841ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-pR2QPr/state/token ✔ a pull request can be closed, read and cleaned up through the tools (37.673513ms) [gitea] no token kept — minting one [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-V03qOP/state/token ✔ the tools' token is minted for an account of their own, which is no administrator and writes through its team (93.23407ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-6UD3o4/state/token ✔ with the tools' token, the forge writes a status and refuses a protection edit — the forge itself, not a guard (62.276681ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-2Ym0YR/state/token ✔ what a base's protection asks is read from the branch, which the tools' account may read, not from the rules' list it may not (50.752207ms) [gitea] the kept token was minted with other scopes than the tools take now — minting one with them [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-aXncVG/state/token [gitea] deleted 1 token(s) named "mesh-tools" the admin account "mesh-admin" held: the tools act as "mesh-tools" now ✔ the administrator's token from before goes: a kept admin token is minted again for the tools' account, and the forge drops the old one (52.544168ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-S7FEmb/state/token ✔ a tools' account someone made an administrator is made a plain account again at the next mint (38.297558ms) ✔ the tools never act as the administrator: MESH_GITEA_TOOLS_USER naming it is refused (1.012227ms) ✔ the manifest hands the tools their account, and the merge-ready authors name it rather than the administrator (1.042757ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-RH9eMW/state/token ✔ a repository check said as a warning on a head without merge-check.sh reads the base's protection from the branch (41.591149ms) [gitea] no token kept — minting one ✔ a mint that fails leaves the administrator's old token in place: the tools are never left without one (31.326852ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-u4A0Fu/state/token [gitea] FAILED to delete the token(s) named "mesh-tools" the admin account "mesh-admin" holds — tried again at the next start: Gitea DELETE /users/mesh-admin/tokens/902 (named mesh-tools): 500 {"message":"the forge is not well"} ✔ an old token that cannot be deleted after the mint is said, the new token kept, and deleted at the next start (49.043327ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-eVEpdU/state/token ✔ a team another process made between the look and the create is found, not a failure (42.530485ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-z9RksA/state/token ✔ setting the tools' account up puts main's rule right in every repository: no push, only the tools' account merges (issue 948) (38.526369ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Dnd9F7/state/token ✔ a glob rule covering main keeps its statuses when main is given a rule of its own name (issue 948, review round 1) (38.187117ms) ✔ a start with the token kept still puts main's rules right: the module's start asks for it each time (issue 948, review round 1) (13.581238ms) [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 (2.495656ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.4566ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (5.841468ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.951097ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.585294ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.345292ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.446332ms) ✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (1.464999ms) ✔ a signed event is published on the bus and acted on once (67.290554ms) ✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (39.054402ms) ✔ an event and the poll seeing the same head announce it once (0.563423ms) ✔ each forge event is named in the module's stream and trimmed (0.735795ms) ✔ the webhook is made a system webhook, which the forge sends every repository's events to (1.47756ms) ✔ default webhooks left at the receiver by an earlier start are replaced by one system webhook (1.428569ms) ✔ a repository's copy of a default webhook at the receiver is deleted, on every page, and said (5.287073ms) ✔ a forge that makes no system webhook is said, never taken as heard (0.993257ms) ✔ the receiver tells what it verified and what it refused (10.845129ms) ✔ a forge that never delivers is said loudly once, and unhealthy, when the poll finds what no event said (1.365349ms) ✔ a forge whose events stop after one delivery is said loudly once per silent spell, and refusals are unhealthy (0.532724ms) ✔ without a receiver by configuration the polls alone watch, healthy; a receiver that failed is unhealthy (0.434543ms) ✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (0.258161ms) ℹ tests 147 ℹ suites 0 ℹ pass 147 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 849.901758 ```
mesh-tools added 1 commit 2026-10-16 22:05:53 +00:00
Hand ssh-client's forge files to the provisioner client (issue 955)
mesh/merge-gate head ae9cda8531b3 merged into trunk 017b729bc95d — pass: builds gitea, ssh-client → ace, g14, novox, shanks; no bus step; every machine com…
mesh/repo-check head ae9cda8531b3 merged into trunk 017b729bc95d — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792195559895153198 (novox/mesh-catalog at 82df3bd5 into main,…
mesh/delivery-group group feat/agents-write-git-ssh delivered: every member is delivered
ae9cda8531
Author
Member

Merge check at ae9cda85
Judged: head ae9cda8531b3 merged into trunk 017b729bc95d; read beside it: mesh-controller 6a62a7e552ea, mesh-controller-main 6a62a7e552ea, mesh-host cd13f7726ef0, mesh-tools 7412c5b6c9c5

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, ssh-client)
  • 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, ssh-client → ace, g14, novox, shanks; no bus step

  • tier 0: gitea, ssh-client
  • ace: receives ssh-client
  • g14: receives ssh-client
  • novox: receives gitea, ssh-client
  • shanks: receives ssh-client
  • gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • ssh-client keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine
  • read by no module's build: modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go, modules/ssh-client/cmd/ssh-client-tools/keykeeper_test.go, modules/ssh-client/cmd/ssh-client-tools/templates_test.go

Run by the build seat on ace as build-1792188355270468326 (builds --log build-1792188355270468326).

✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (0.837457ms)
✔ the newest status of each context is kept, with what it said, when and by whom (27.33629ms)
✔ a commit merges only when every required status is a success; a warning blocks (0.70645ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.293242ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (3.279455ms)
✔ a note line is appended once, as the forge's user, in its own repository (9.826752ms)
✔ a note that cannot be written is said, never read as written (0.374956ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.505021ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (19.394717ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (5.007638ms)
[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 (0.816768ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.403239ms)
✔ a start heard after the verdict writes nothing (0.380046ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.45158ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.681524ms)
[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 (1.472322ms)
✔ a rechecked head says where its new run is: building on which machine (0.582597ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.625958ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.406816ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.381058ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (4.598768ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.263265ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (3.490441ms)
✔ a repository as the mesh clones it is told from another (0.300256ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.16096ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (49.20173ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (21.621479ms)
✔ gitea_api still writes what an author writes (7.22888ms)
✔ gitea_branch_protection_set only strengthens (15.910648ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (46.303702ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (152.22756ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.530587ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (11.115259ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.213382ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (55.950085ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (21.62735ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.93563ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.08646ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (14.221748ms)
✔ a repository owner or name is never another path (0.216357ms)
✔ the judges, without a forge (0.351722ms)
✔ main's protection is never weakened in its push or its merge whitelist (issue 948, ADR 0398 §2) (0.231065ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.399949ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (1.218965ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (4.534938ms)
✔ gitea_merge_pull_request merges a verdict that read siblings only with its group passed and each sibling head reviewed (79.695274ms)
✔ a verdict put out of date by a sibling's move is refused in its own words, and asked again once (23.101406ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (25.81226ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.608005ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (13.623351ms)
✔ a lookup the forge refuses is thrown, not read as no module (4.554185ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (6.472246ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (57.27486ms)
✔ a pass pages until it reaches back past its floor, and no further (18.338178ms)
✔ gitea_branch_protection_get answers every rule, read with the administrator account the tools' token cannot read with (24.685128ms)
✔ gitea_branch_protection_get answers the rule for a branch, null when it has none (5.954061ms)
✔ gitea_branch_protection_set still gets the forge's refusal, as the tools' account (3.029203ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (4.267545ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.319021ms)
✔ main's body always refuses pushes and lets only the tools' account merge, whatever is asked (0.793344ms)
✔ another branch's body carries no merge whitelist (0.252385ms)
✔ the rule main is put right in the forge's own words: the body a setup sends carries no status checks of its own (0.335622ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (14.618004ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.034728ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.704687ms)
✔ no verdict sets warning on a required check; only a person's decision fails (1.042683ms)
✔ a commit status is set on the commit, under the merge check's context (40.63518ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.569222ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.369105ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (3.009777ms)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 at bbbbbbbbbbbb, it is now at dddddddddddd: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was closed unmerged: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 merged onto cccccccccccc, its main is now eeeeeeeeeeee: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382)
[gitea] novox/mesh-host's main moved from 444444444444 to 333333333333: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses name the siblings the verdict read, keeping the verdict word and the start of its reason within 140 characters (2.115433ms)
✔ a verdict that could not learn its siblings says so on the status and in the comment, and names none (0.319161ms)
✔ a verdict without siblings is said exactly as before (an older controller) (0.740134ms)
✔ the siblings a verdict names are kept per member, replaced by its next verdict, and removed by one that read none (0.890507ms)
✔ a sibling's new head puts both statuses of the member back to pending, with the reason, and runs nothing (7.392118ms)
✔ a sibling closed unmerged puts the member's verdict out of date (0.411285ms)
✔ a move of the sibling's base puts it out of date, naming both commits (0.379083ms)
✔ the sibling's own merge of the head read onto the base read does not, in either order of the two merges (0.620157ms)
✔ a merge of another head, or onto another base, is a move (0.771583ms)
✔ only the members whose verdict names the sibling are touched, and a member that moved on is dropped (1.823874ms)
✔ a trunk that moved tells the siblings' weighing; one first seen does not (0.683487ms)
✔ the group rule names every missing thing: the group status at each head read, and each sibling head's review (1.00898ms)
✔ a merged or closed member's entry is dropped, so a sibling's later push never re-pends its merged head (0.268997ms)
✔ a consumer that asks nothing, or write, publishes: the package team (1.125389ms)
✔ a consumer that asks to read joins the readers, who write no package (0.369696ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.542031ms)
✔ a publisher is made and put on the package team, as before (0.160812ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (38.699715ms)
✔ second start: reuses the kept token, mints nothing (23.396783ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (22.307321ms)
✔ 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 (25.942255ms)
✔ 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 (25.438236ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (22.747009ms)
✔ concurrent first calls share one mint (11.037461ms)
✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (13.03344ms)
✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (58.902484ms)
✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (6.852602ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (16.569057ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.740084ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (19.470681ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.313185ms)
✔ nothing to mint with and no token: the client says what is missing (0.189216ms)
[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-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-g4HfEx/state/token
✔ the tools register once there is a way to a token, and the first call mints it (26.93814ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-1Qqrag/state/token
✔ a pull request can be closed, read and cleaned up through the tools (36.589723ms)
[gitea] no token kept — minting one
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-ByUaYi/state/token
✔ the tools' token is minted for an account of their own, which is no administrator and writes through its team (70.799354ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-M3zXJl/state/token
✔ with the tools' token, the forge writes a status and refuses a protection edit — the forge itself, not a guard (48.430046ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-0qm1CV/state/token
✔ what a base's protection asks is read from the branch, which the tools' account may read, not from the rules' list it may not (49.305635ms)
[gitea] the kept token was minted with other scopes than the tools take now — minting one with them
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-FJ9Q2j/state/token
[gitea] deleted 1 token(s) named "mesh-tools" the admin account "mesh-admin" held: the tools act as "mesh-tools" now
✔ the administrator's token from before goes: a kept admin token is minted again for the tools' account, and the forge drops the old one (42.872422ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-TwIXjX/state/token
✔ a tools' account someone made an administrator is made a plain account again at the next mint (36.937157ms)
✔ the tools never act as the administrator: MESH_GITEA_TOOLS_USER naming it is refused (0.8763ms)
✔ the manifest hands the tools their account, and the merge-ready authors name it rather than the administrator (1.044717ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Cpae4b/state/token
✔ a repository check said as a warning on a head without merge-check.sh reads the base's protection from the branch (37.45392ms)
[gitea] no token kept — minting one
✔ a mint that fails leaves the administrator's old token in place: the tools are never left without one (27.773352ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-zmQCEc/state/token
[gitea] FAILED to delete the token(s) named "mesh-tools" the admin account "mesh-admin" holds — tried again at the next start: Gitea DELETE /users/mesh-admin/tokens/902 (named mesh-tools): 500 {"message":"the forge is not well"}
✔ an old token that cannot be deleted after the mint is said, the new token kept, and deleted at the next start (43.762187ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-h2lcrr/state/token
✔ a team another process made between the look and the create is found, not a failure (38.936211ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-p8E6kK/state/token
✔ setting the tools' account up puts main's rule right in every repository: no push, only the tools' account merges (issue 948) (37.47518ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Vk5wtD/state/token
✔ a glob rule covering main keeps its statuses when main is given a rule of its own name (issue 948, review round 1) (35.260179ms)
✔ a start with the token kept still puts main's rules right: the module's start asks for it each time (issue 948, review round 1) (13.215432ms)
[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 (1.48711ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (0.806289ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (2.970192ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.287672ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.385335ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.231306ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.213181ms)
✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (0.408589ms)
✔ a signed event is published on the bus and acted on once (52.481775ms)
✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (31.605187ms)
✔ an event and the poll seeing the same head announce it once (0.305576ms)
✔ each forge event is named in the module's stream and trimmed (0.46733ms)
✔ the webhook is made a system webhook, which the forge sends every repository's events to (1.113676ms)
✔ default webhooks left at the receiver by an earlier start are replaced by one system webhook (0.990175ms)
✔ a repository's copy of a default webhook at the receiver is deleted, on every page, and said (3.078197ms)
✔ a forge that makes no system webhook is said, never taken as heard (0.675772ms)
✔ the receiver tells what it verified and what it refused (7.665953ms)
✔ a forge that never delivers is said loudly once, and unhealthy, when the poll finds what no event said (1.20583ms)
✔ a forge whose events stop after one delivery is said loudly once per silent spell, and refusals are unhealthy (0.724263ms)
✔ without a receiver by configuration the polls alone watch, healthy; a receiver that failed is unhealthy (0.343116ms)
✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (0.187533ms)
ℹ tests 147
ℹ suites 0
ℹ pass 147
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 751.836759
**Merge check** at `ae9cda85` Judged: head `ae9cda8531b3` merged into trunk `017b729bc95d`; read beside it: mesh-controller `6a62a7e552ea`, mesh-controller-main `6a62a7e552ea`, mesh-host `cd13f7726ef0`, mesh-tools `7412c5b6c9c5` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, ssh-client) - `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, ssh-client → ace, g14, novox, shanks; no bus step - tier 0: gitea, ssh-client - ace: receives ssh-client - g14: receives ssh-client - novox: receives gitea, ssh-client - shanks: receives ssh-client - gitea provides npm-package-registry, git, gitea-read: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - ssh-client keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before ssh-client is judged on its first machine - read by no module's build: modules/ssh-client/cmd/ssh-client-tools/keykeeper_bus_test.go, modules/ssh-client/cmd/ssh-client-tools/keykeeper_test.go, modules/ssh-client/cmd/ssh-client-tools/templates_test.go Run by the build seat on ace as `build-1792188355270468326` (`builds --log build-1792188355270468326`). ``` ✔ the accounts that may mark are the setting's, and only the mesh's own when it cannot be read (0.837457ms) ✔ the newest status of each context is kept, with what it said, when and by whom (27.33629ms) ✔ a commit merges only when every required status is a success; a warning blocks (0.70645ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.293242ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (3.279455ms) ✔ a note line is appended once, as the forge's user, in its own repository (9.826752ms) ✔ a note that cannot be written is said, never read as written (0.374956ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.505021ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (19.394717ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (5.007638ms) [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 (0.816768ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.403239ms) ✔ a start heard after the verdict writes nothing (0.380046ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.45158ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.681524ms) [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 (1.472322ms) ✔ a rechecked head says where its new run is: building on which machine (0.582597ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.625958ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.406816ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.381058ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (4.598768ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.263265ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (3.490441ms) ✔ a repository as the mesh clones it is told from another (0.300256ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.16096ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (49.20173ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (21.621479ms) ✔ gitea_api still writes what an author writes (7.22888ms) ✔ gitea_branch_protection_set only strengthens (15.910648ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (46.303702ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (152.22756ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.530587ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (11.115259ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.213382ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (55.950085ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (21.62735ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.93563ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.08646ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (14.221748ms) ✔ a repository owner or name is never another path (0.216357ms) ✔ the judges, without a forge (0.351722ms) ✔ main's protection is never weakened in its push or its merge whitelist (issue 948, ADR 0398 §2) (0.231065ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.399949ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (1.218965ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (4.534938ms) ✔ gitea_merge_pull_request merges a verdict that read siblings only with its group passed and each sibling head reviewed (79.695274ms) ✔ a verdict put out of date by a sibling's move is refused in its own words, and asked again once (23.101406ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (25.81226ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.608005ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (13.623351ms) ✔ a lookup the forge refuses is thrown, not read as no module (4.554185ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (6.472246ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (57.27486ms) ✔ a pass pages until it reaches back past its floor, and no further (18.338178ms) ✔ gitea_branch_protection_get answers every rule, read with the administrator account the tools' token cannot read with (24.685128ms) ✔ gitea_branch_protection_get answers the rule for a branch, null when it has none (5.954061ms) ✔ gitea_branch_protection_set still gets the forge's refusal, as the tools' account (3.029203ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (4.267545ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.319021ms) ✔ main's body always refuses pushes and lets only the tools' account merge, whatever is asked (0.793344ms) ✔ another branch's body carries no merge whitelist (0.252385ms) ✔ the rule main is put right in the forge's own words: the body a setup sends carries no status checks of its own (0.335622ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (14.618004ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.034728ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.704687ms) ✔ no verdict sets warning on a required check; only a person's decision fails (1.042683ms) ✔ a commit status is set on the commit, under the merge check's context (40.63518ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.569222ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.369105ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (3.009777ms) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 at bbbbbbbbbbbb, it is now at dddddddddddd: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was closed unmerged: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 merged onto cccccccccccc, its main is now eeeeeeeeeeee: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-controller#346: its verdict was judged beside mesh-host#114 was merged otherwise than its head bbbbbbbbbbbb onto cccccccccccc: out of date, nothing run (novox/hq ADR 0382) [gitea] novox/mesh-host's main moved from 444444444444 to 333333333333: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses name the siblings the verdict read, keeping the verdict word and the start of its reason within 140 characters (2.115433ms) ✔ a verdict that could not learn its siblings says so on the status and in the comment, and names none (0.319161ms) ✔ a verdict without siblings is said exactly as before (an older controller) (0.740134ms) ✔ the siblings a verdict names are kept per member, replaced by its next verdict, and removed by one that read none (0.890507ms) ✔ a sibling's new head puts both statuses of the member back to pending, with the reason, and runs nothing (7.392118ms) ✔ a sibling closed unmerged puts the member's verdict out of date (0.411285ms) ✔ a move of the sibling's base puts it out of date, naming both commits (0.379083ms) ✔ the sibling's own merge of the head read onto the base read does not, in either order of the two merges (0.620157ms) ✔ a merge of another head, or onto another base, is a move (0.771583ms) ✔ only the members whose verdict names the sibling are touched, and a member that moved on is dropped (1.823874ms) ✔ a trunk that moved tells the siblings' weighing; one first seen does not (0.683487ms) ✔ the group rule names every missing thing: the group status at each head read, and each sibling head's review (1.00898ms) ✔ a merged or closed member's entry is dropped, so a sibling's later push never re-pends its merged head (0.268997ms) ✔ a consumer that asks nothing, or write, publishes: the package team (1.125389ms) ✔ a consumer that asks to read joins the readers, who write no package (0.369696ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.542031ms) ✔ a publisher is made and put on the package team, as before (0.160812ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (38.699715ms) ✔ second start: reuses the kept token, mints nothing (23.396783ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (22.307321ms) ✔ 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 (25.942255ms) ✔ 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 (25.438236ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (22.747009ms) ✔ concurrent first calls share one mint (11.037461ms) ✔ two tokens hold the name (two mints raced): both are deleted by their id, and one fresh token is minted (13.03344ms) ✔ two processes on one kept file, both without a token, mint once: the second waits for the first and reuses it (58.902484ms) ✔ a lock left by a process that died mid-mint is taken over, not waited on for ever (6.852602ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (16.569057ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.740084ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (19.470681ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.313185ms) ✔ nothing to mint with and no token: the client says what is missing (0.189216ms) [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-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-g4HfEx/state/token ✔ the tools register once there is a way to a token, and the first call mints it (26.93814ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-1Qqrag/state/token ✔ a pull request can be closed, read and cleaned up through the tools (36.589723ms) [gitea] no token kept — minting one [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-ByUaYi/state/token ✔ the tools' token is minted for an account of their own, which is no administrator and writes through its team (70.799354ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-M3zXJl/state/token ✔ with the tools' token, the forge writes a status and refuses a protection edit — the forge itself, not a guard (48.430046ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-0qm1CV/state/token ✔ what a base's protection asks is read from the branch, which the tools' account may read, not from the rules' list it may not (49.305635ms) [gitea] the kept token was minted with other scopes than the tools take now — minting one with them [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-FJ9Q2j/state/token [gitea] deleted 1 token(s) named "mesh-tools" the admin account "mesh-admin" held: the tools act as "mesh-tools" now ✔ the administrator's token from before goes: a kept admin token is minted again for the tools' account, and the forge drops the old one (42.872422ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-TwIXjX/state/token ✔ a tools' account someone made an administrator is made a plain account again at the next mint (36.937157ms) ✔ the tools never act as the administrator: MESH_GITEA_TOOLS_USER naming it is refused (0.8763ms) ✔ the manifest hands the tools their account, and the merge-ready authors name it rather than the administrator (1.044717ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Cpae4b/state/token ✔ a repository check said as a warning on a head without merge-check.sh reads the base's protection from the branch (37.45392ms) [gitea] no token kept — minting one ✔ a mint that fails leaves the administrator's old token in place: the tools are never left without one (27.773352ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-zmQCEc/state/token [gitea] FAILED to delete the token(s) named "mesh-tools" the admin account "mesh-admin" holds — tried again at the next start: Gitea DELETE /users/mesh-admin/tokens/902 (named mesh-tools): 500 {"message":"the forge is not well"} ✔ an old token that cannot be deleted after the mint is said, the new token kept, and deleted at the next start (43.762187ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-h2lcrr/state/token ✔ a team another process made between the look and the create is found, not a failure (38.936211ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-p8E6kK/state/token ✔ setting the tools' account up puts main's rule right in every repository: no push, only the tools' account merges (issue 948) (37.47518ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-tools" (write:repository, write:issue, read:user), kept at /tmp/gitea-tools-account-Vk5wtD/state/token ✔ a glob rule covering main keeps its statuses when main is given a rule of its own name (issue 948, review round 1) (35.260179ms) ✔ a start with the token kept still puts main's rules right: the module's start asks for it each time (issue 948, review round 1) (13.215432ms) [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 (1.48711ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (0.806289ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (2.970192ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.287672ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.385335ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.231306ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.213181ms) ✔ a release branch's move puts every open pull request into it out of date, as a trunk's does (ADR 0358 §5) (0.408589ms) ✔ a signed event is published on the bus and acted on once (52.481775ms) ✔ an unsigned event, or one whose signature does not verify, is refused and published nowhere (31.605187ms) ✔ an event and the poll seeing the same head announce it once (0.305576ms) ✔ each forge event is named in the module's stream and trimmed (0.46733ms) ✔ the webhook is made a system webhook, which the forge sends every repository's events to (1.113676ms) ✔ default webhooks left at the receiver by an earlier start are replaced by one system webhook (0.990175ms) ✔ a repository's copy of a default webhook at the receiver is deleted, on every page, and said (3.078197ms) ✔ a forge that makes no system webhook is said, never taken as heard (0.675772ms) ✔ the receiver tells what it verified and what it refused (7.665953ms) ✔ a forge that never delivers is said loudly once, and unhealthy, when the poll finds what no event said (1.20583ms) ✔ a forge whose events stop after one delivery is said loudly once per silent spell, and refusals are unhealthy (0.724263ms) ✔ without a receiver by configuration the polls alone watch, healthy; a receiver that failed is unhealthy (0.343116ms) ✔ the polls look every 30 s until events are heard, every five minutes while they are, and 30 s again on a miss (0.187533ms) ℹ tests 147 ℹ suites 0 ℹ pass 147 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 751.836759 ```
mesh-tools added the mesh/ready label 2026-10-16 22:14:59 +00:00
Author
Member

ready at ae9cda8531

Reviewed by lead-57@novox: Phase 2 approved 6f45570 (round 3, opus); 40e40bd (ssh-client moved, same tree as ae9cda8) approved in review round 2 of issue 969; merge-gate and repo-check pass at this head on the controller with issue 969 delivered. Marked through mesh-delivery.mark-ready (novox/hq issue 913).

ready at ae9cda8531b3fbf7d7c240f15bafef8856822c4b Reviewed by lead-57@novox: Phase 2 approved 6f45570 (round 3, opus); 40e40bd (ssh-client moved, same tree as ae9cda8) approved in review round 2 of issue 969; merge-gate and repo-check pass at this head on the controller with issue 969 delivered. Marked through mesh-delivery.mark-ready (novox/hq issue 913).
mesh-tools merged commit 734a77f5a9 into main 2026-10-16 22:31:17 +00:00
mesh-tools deleted branch feat/agents-write-git-ssh 2026-10-16 22:31:17 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#340