Skip to content

feat(gateway): update one worker from the gateway (#838) - #888

Merged
V3RON merged 42 commits into
task/837from
task/838
Oct 22, 2026
Merged

V3RON merged 42 commits into
task/837from
task/838

Conversation

@V3RON

@V3RON V3RON commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Closes #838

Status

Implement: done Review: passed, fix-check Hardware: n/a Gate: waiting for the stack
Next: joins the #825 stack

Done when

  • pnpm test:changed passes (209 files, 6929 tests, at b499f6c)
  • CI's check job passes
  • reference/cli.mdx and gateway/managing-workers.mdx document simlock worker update and the new list fields; reference/errors.mdx the 90 s message; the route is declared, so the OpenAPI reference lists it

Assumptions

  • Assumption: the worker view fields update, lastUpdateFailure and latestVersion are .nullable().optional(), so a freshly connected worker's view has none until its first status read.

  • Assumption: an updating worker counts as a taker in routing/serviceability.ts, so a request only that worker can serve waits instead of ending NO_CAPACITY.

  • Assumption: simlock worker update calls updateWorker first and reads worker.list after, so a stale lastUpdateFailure from an earlier run is already cleared by the answer; Ctrl-C ends the command by the process default.

  • Assumption: the gateway's update coordinator reaches DaemonServer through an optional update on the gateway arm of its options, so the existing result-file read and announce serve both roles. startDaemon gets two test-only options, updater and protocolVersion, for the gateway-update and incompatible-worker tests.

Review

Spec review: 1 blocking, 1 fixed, 0 notes. Code review: 4 blocking, 4 fixed, 1 notes. Claims review: 1 blocking, 1 fixed, 0 notes.
Rounds: 2. Tokens: 39.6M.
Runs: 14. Cost USD: 12.8636. Agent seconds: 7541.

Assessment: complete

Written by an agent.

V3RON added 20 commits October 22, 2026 15:58
@V3RON
V3RON added this pull request to stack #881 October 22, 2026 14:14
@V3RON

V3RON commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Review ledger

Round 1: e9c26f8
Round 2: 1948466
Round fix-check: b59ceba

Runs: 14. Cost USD: 12.8636. Agent seconds: 7541.
Tokens input 1006, output 265122, cache read 51081734, cache write 1330305.
- build implementer: claude-sonnet-5-5 1151 s $1.8163
- build implementer: claude-sonnet-5-5 1886 s $4.1316
- audit implementer: claude-sonnet-5-5 1448 s $1.1374
- fix implementer: claude-sonnet-5-5 129 s $0.1624
- review 1 reviewer: claude-sonnet-5-5 851 s $0.4213
- review 1 reviewer code: claude-opus-5-5 680 s $2.876
- review 1 reviewer spec: claude-sonnet-5-5 55 s $0.4215
- review 1 reviewer claims: claude-sonnet-5-5 83 s $0.2858
- fix 1 implementer: claude-sonnet-5-5 390 s $0.388
- review 2 reviewer: claude-sonnet-5-5 429 s $0.227
- review 2 reviewer code: claude-opus-5-5 272 s $0.6771
- review 2 reviewer claims: claude-sonnet-5-5 37 s $0.1084
- fix 2 implementer: claude-sonnet-5-5 66 s $0.1074
- review fix-check reviewer: claude-sonnet-5-5 64 s $0.1034
Finding outcomes: {"duplicate":1,"fixed":5,"nonblocking":1}. Classes: {"ADR section cite wrong":1,"assumption contradicts spec failure mode":1,"false user-facing message":1,"relayed worker error not translated":1,"test passes without refusal translation":1,"testing 1 title promises removed assertion":1,"wording parity omits worker version":1}.
{
 "findings": [
  {
   "id": "R1",
   "role": "code",
   "class": "relayed worker error not translated",
   "outcome": "fixed",
   "path": "src/gateway/dispatcher.ts",
   "round": "1",
   "fix": "1948466190bb01a0368984359de147cf44565170"
  },
  {
   "id": "R2",
   "role": "code",
   "class": "false user-facing message",
   "outcome": "fixed",
   "path": "src/cli/commands/worker.ts",
   "round": "1",
   "fix": "1948466190bb01a0368984359de147cf44565170"
  },
  {
   "id": "R3",
   "role": "code",
   "class": "testing 1 title promises removed assertion",
   "outcome": "fixed",
   "path": "src/http/app.test.ts",
   "round": "1",
   "fix": "1948466190bb01a0368984359de147cf44565170"
  },
  {
   "id": "R4",
   "role": "claims",
   "class": "ADR section cite wrong",
   "outcome": "fixed",
   "path": "src/daemon/main.ts",
   "round": "1",
   "fix": "1948466190bb01a0368984359de147cf44565170"
  },
  {
   "id": "R5",
   "role": "spec",
   "class": "assumption contradicts spec failure mode",
   "outcome": "duplicate",
   "canonicalId": "R1",
   "path": "src/gateway/dispatcher.ts",
   "round": "1"
  },
  {
   "id": "R6",
   "role": "code",
   "class": "test passes without refusal translation",
   "outcome": "fixed",
   "path": "src/gateway/dispatcher.test.ts",
   "round": "2",
   "fix": "b59cebaf"
  },
  {
   "id": "R7",
   "role": "code",
   "class": "wording parity omits worker version",
   "outcome": "nonblocking",
   "path": "src/cli/commands/worker.ts",
   "round": "2"
  }
 ]
}

Written by an agent.

@V3RON

V3RON commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Review notes

These do not block, and nobody has verified them. Each is one reviewer's claim.

  • code: src/cli/commands/worker.ts R7: the up-to-date message for a worker leaves out the version it runs, which simlock update prints.

Written by an agent.

@V3RON
V3RON marked this pull request as ready for review October 22, 2026 15:47
@V3RON V3RON mentioned this pull request Oct 22, 2026
10 of 11 tasks
@V3RON
V3RON merged commit c196f91 into main Oct 22, 2026
65 of 67 checks passed
@V3RON
V3RON deleted the task/838 branch October 22, 2026 20:39
V3RON added a commit that referenced this pull request Oct 22, 2026
Closes #839

### Status
Implement: done Review: passed, round 2 Hardware: n/a Gate: the stack
gate (`merge-pr.sh 896`)
Next: final stack sync, then the gate

### Done when

- [x] `pnpm exec vitest run --project unit` on the changed `ui/src` test
files passes with the lines above.
- [x] `pnpm test:console --project=chromium e2e/console/update.spec.ts`
passes.
- [ ] CI's `pnpm check` is green, the dependency rules included.
- [x] `console.mdx` documents the notice, the Update and Update now
items, the `updating` state, the failure banner, the Inbox item and the
footer notice.

### Completion conditions (#825)

- [x] `simlock update` with no leases installs the latest and `simlock
status` prints it: `e2e/update/update.e2e.test.ts` (real npm via
verdaccio, #885).
- [x] With a lease held the update waits, a new lease gets
`DAEMON_UPDATING`, releasing it lets the update go on:
`src/daemon/server.test.ts` `daemon.update` table (#885).
- [x] A failed install leaves the old daemon serving and `simlock
status` prints `Last update failed (installing)`: server.test.ts
failed-line case and `src/cli/index.test.ts` (#885).
- [x] A new version that does not start is rolled back and the failure
shows with stage `restarting`: `src/updater/index.test.ts` (#878) and
the server.test.ts result-file case (#885).
- [x] `simlock worker update` updates a connected and an incompatible
worker, routes around it, and keeps a drain:
`src/gateway/service.test.ts`, `src/daemon/gateway-fleet.e2e.test.ts`
(#888).
- [x] `simlock status` and `simlock worker list` show the latest after
the check, and nothing with `update.check: false`:
`src/daemon/main.test.ts` version-check cases, CLI tables (#887, #888).
- [x] The console shows `<latest> available`, Update…, `updating` with
its stage, the failure banner and Inbox item, and the sidebar notice:
`ui/src` model and screen tests and `e2e/console/update.spec.ts` (this
PR).

## Assumptions

- Assumption: Update now answers `upToDate` with `<name> already runs
<version>` (the spec lists the toast for the answer; the force action
had a fixed success title).
- Assumption: the footer notice is a `UpdateNotice` in `shell.tsx` and
`watchMode` takes a `clock`, so its 10-minute timer is testable with
fake time.

- Assumption: the row's stage line shows only while State reads
`updating` — a red finding (disconnected, failed) hides it, as it hides
the amber word.
- Assumption: Update… and Update now sit after Drain/Undrain in the menu
(the picked prototype's order), so the page's primary button stays
Drain.
- Assumption: the Inbox fact When reads `<duration> ago`, as the
disconnected item's Last seen does.
- Assumption: `isNewerVersion` is imported by `version-order.ts`'s own
path (the spec's value import); the `past-index` rule allows that one
file, because the index carries zod's `eval`, which breaks the console's
CSP (maintainer-authorized 2026-10-22, #825 Decisions).

## Review

Spec review: 1 blocking, 1 fixed, 0 notes. Code review: 1 blocking, 1
fixed, 1 notes. Claims review: 1 blocking, 1 fixed, 0 notes.
Rounds: 2. Tokens: 45.0M.
Runs: 11. Cost USD: 6.9344. Agent seconds: 3898.

Assessment: complete

*Written by an agent.*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A gateway updates a chosen worker, incompatible ones included, and routes around it meanwhile

1 participant