agl 40.5.1 → 41.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/changelog.md +43 -0
  2. package/dist_serve/bundle.js +3514 -3357
  3. package/dist_serve/bundle.js.map +2 -2
  4. package/dist_serve/bundle.js.third-party-notices.json +58 -32
  5. package/dist_serve/bundle.js.third-party-notices.txt +108 -33
  6. package/dist_ts/00_commitinfo_data.js +1 -1
  7. package/dist_ts/aglapi/aglapisurface.document.js +64 -37
  8. package/dist_ts/classes.aglhome.d.ts +5 -0
  9. package/dist_ts/classes.aglhome.js +2 -1
  10. package/dist_ts/classes.authstore.js +5 -1
  11. package/dist_ts/classes.controller.d.ts +8 -0
  12. package/dist_ts/classes.controller.js +119 -22
  13. package/dist_ts/classes.controllereventdelivery.d.ts +72 -0
  14. package/dist_ts/classes.controllereventdelivery.js +233 -0
  15. package/dist_ts/classes.flexmodels.public.js +4 -1
  16. package/dist_ts/classes.flexprojectionreader.d.ts +6 -0
  17. package/dist_ts/classes.flexprojectionreader.js +29 -5
  18. package/dist_ts/classes.flexservice.d.ts +2 -1
  19. package/dist_ts/classes.flexservice.js +34 -6
  20. package/dist_ts/classes.flexstore.d.ts +41 -4
  21. package/dist_ts/classes.flexstore.js +266 -203
  22. package/dist_ts/classes.inferencegateway.d.ts +35 -1
  23. package/dist_ts/classes.inferencegateway.js +86 -26
  24. package/dist_ts/classes.inferenceservice.d.ts +4 -2
  25. package/dist_ts/classes.inferenceservice.js +5 -4
  26. package/dist_ts/classes.proxycontrol.d.ts +58 -4
  27. package/dist_ts/classes.proxycontrol.js +23 -44
  28. package/dist_ts/classes.proxycontrolclient.d.ts +15 -5
  29. package/dist_ts/classes.proxycontrolclient.js +67 -17
  30. package/dist_ts/classes.proxydaemon.d.ts +22 -3
  31. package/dist_ts/classes.proxydaemon.js +73 -12
  32. package/dist_ts/classes.proxyleaseholder.d.ts +43 -14
  33. package/dist_ts/classes.proxyleaseholder.js +66 -22
  34. package/dist_ts/classes.proxystore.d.ts +9 -0
  35. package/dist_ts/classes.proxystore.js +15 -7
  36. package/dist_ts/classes.ticketnotifier.js +4 -2
  37. package/dist_ts/classes.ticketstore.d.ts +50 -2
  38. package/dist_ts/classes.ticketstore.js +195 -78
  39. package/dist_ts/classes.workercallerbindings.d.ts +66 -0
  40. package/dist_ts/classes.workercallerbindings.js +211 -0
  41. package/dist_ts/classes.workercallers.d.ts +63 -2
  42. package/dist_ts/classes.workercallers.js +430 -65
  43. package/dist_ts/driver/classes.drivereventrelay.d.ts +13 -1
  44. package/dist_ts/driver/classes.drivereventrelay.js +99 -6
  45. package/dist_ts/driver/functions.driverinstructions.d.ts +1 -1
  46. package/dist_ts/driver/functions.driverinstructions.js +1 -1
  47. package/dist_ts/driver/functions.drivertools.d.ts +11 -2
  48. package/dist_ts/driver/functions.drivertools.js +19 -9
  49. package/dist_ts/fleet/classes.boardpump.d.ts +8 -2
  50. package/dist_ts/fleet/classes.boardpump.js +38 -20
  51. package/dist_ts/fleet/classes.ticketeffects.d.ts +17 -2
  52. package/dist_ts/fleet/classes.ticketeffects.js +16 -10
  53. package/dist_ts/fleet/classes.workerlaunches.d.ts +12 -5
  54. package/dist_ts/fleet/classes.workerlaunches.js +25 -19
  55. package/dist_ts/fleet/classes.workers.d.ts +21 -0
  56. package/dist_ts/fleet/classes.workers.js +110 -17
  57. package/dist_ts/fleet/functions.workervalidation.js +2 -2
  58. package/dist_ts/functions.flexprivatesnapshot.d.ts +102 -0
  59. package/dist_ts/functions.flexprivatesnapshot.js +461 -0
  60. package/dist_ts/functions.inferencecli.d.ts +3 -2
  61. package/dist_ts/functions.inferencecli.js +67 -5
  62. package/dist_ts/functions.inferencecliarguments.d.ts +6 -2
  63. package/dist_ts/functions.inferencecliarguments.js +29 -2
  64. package/dist_ts/functions.inferencelaunch.d.ts +24 -0
  65. package/dist_ts/functions.inferencelaunch.js +42 -2
  66. package/dist_ts/functions.mcptickettools.d.ts +3 -0
  67. package/dist_ts/functions.mcptickettools.js +2 -2
  68. package/dist_ts/functions.proxycontract.d.ts +11 -0
  69. package/dist_ts/functions.proxycontract.js +12 -1
  70. package/dist_ts/functions.proxysocket.d.ts +6 -0
  71. package/dist_ts/functions.proxysocket.js +46 -0
  72. package/dist_ts/functions.ticketcli.d.ts +1 -1
  73. package/dist_ts/functions.ticketcli.js +8 -4
  74. package/dist_ts/functions.ticketvalidation.d.ts +3 -0
  75. package/dist_ts/functions.ticketvalidation.js +7 -4
  76. package/dist_ts/functions.workerprocessproof.d.ts +6 -0
  77. package/dist_ts/functions.workerprocessproof.js +28 -4
  78. package/dist_ts/interfaces.flexipc.d.ts +21 -2
  79. package/dist_ts/interfaces.flexipc.js +33 -16
  80. package/dist_ts_interfaces/fleetworkers.d.ts +6 -0
  81. package/dist_ts_interfaces/interfaces.d.ts +1 -1
  82. package/dist_ts_interfaces/interfaces.js +1 -1
  83. package/dist_ts_interfaces/requests.tickets.d.ts +8 -12
  84. package/dist_ts_interfaces/tickets.d.ts +37 -9
  85. package/dist_ts_interfaces/tickets.js +7 -1
  86. package/dist_ts_interfaces/workercallers.d.ts +43 -4
  87. package/package.json +7 -7
  88. package/readme.md +156 -23
  89. package/ts/00_commitinfo_data.ts +1 -1
  90. package/ts/aglapi/aglapisurface.document.ts +63 -36
  91. package/ts/classes.aglhome.ts +6 -0
  92. package/ts/classes.authstore.ts +4 -0
  93. package/ts/classes.controller.ts +141 -32
  94. package/ts/classes.controllereventdelivery.ts +289 -0
  95. package/ts/classes.flexmodels.public.ts +10 -0
  96. package/ts/classes.flexprojectionreader.ts +30 -3
  97. package/ts/classes.flexservice.ts +33 -5
  98. package/ts/classes.flexstore.ts +381 -246
  99. package/ts/classes.inferencegateway.ts +104 -23
  100. package/ts/classes.inferenceservice.ts +6 -3
  101. package/ts/classes.proxycontrol.ts +76 -39
  102. package/ts/classes.proxycontrolclient.ts +72 -20
  103. package/ts/classes.proxydaemon.ts +85 -15
  104. package/ts/classes.proxyleaseholder.ts +84 -28
  105. package/ts/classes.proxystore.ts +16 -5
  106. package/ts/classes.ticketnotifier.ts +3 -1
  107. package/ts/classes.ticketstore.ts +201 -75
  108. package/ts/classes.workercallerbindings.ts +147 -0
  109. package/ts/classes.workercallers.ts +410 -59
  110. package/ts/driver/classes.drivereventrelay.ts +89 -4
  111. package/ts/driver/functions.driverinstructions.ts +1 -1
  112. package/ts/driver/functions.drivertools.ts +22 -8
  113. package/ts/fleet/classes.boardpump.ts +51 -19
  114. package/ts/fleet/classes.ticketeffects.ts +25 -11
  115. package/ts/fleet/classes.workerlaunches.ts +23 -15
  116. package/ts/fleet/classes.workers.ts +79 -17
  117. package/ts/fleet/functions.workervalidation.ts +1 -1
  118. package/ts/functions.flexprivatesnapshot.ts +601 -0
  119. package/ts/functions.inferencecli.ts +61 -7
  120. package/ts/functions.inferencecliarguments.ts +32 -1
  121. package/ts/functions.inferencelaunch.ts +49 -2
  122. package/ts/functions.mcptickettools.ts +1 -1
  123. package/ts/functions.proxycontract.ts +12 -0
  124. package/ts/functions.proxysocket.ts +39 -0
  125. package/ts/functions.ticketcli.ts +7 -3
  126. package/ts/functions.ticketvalidation.ts +7 -3
  127. package/ts/functions.workerprocessproof.ts +27 -4
  128. package/ts/interfaces.flexipc.ts +50 -21
  129. package/ts_interfaces/fleetworkers.ts +6 -0
  130. package/ts_interfaces/interfaces.ts +1 -1
  131. package/ts_interfaces/requests.tickets.ts +9 -6
  132. package/ts_interfaces/tickets.ts +32 -1
  133. package/ts_interfaces/workercallers.ts +32 -4
  134. package/ts_web/00_commitinfo_data.ts +1 -1
  135. package/ts_web/elements.harnesscontrollerapp.ts +19 -8
  136. package/ts_web/elements.ticketboard.ts +16 -4
  137. package/ts_web/settings.general.ts +10 -4
package/changelog.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-10-26 - 41.0.0
4
+
5
+ ### Breaking Changes
6
+
7
+ - `ticket_get` returns one page of a ticket's history instead of all of it. A ticket with a long history could not be read through the driver's tools at all: the answer passed the 2 MiB tool result limit, and the refusal said to narrow a request that had no way to be narrowed. `ticket_get` (MCP, the driver's tool, `agl.mcp.ticket.get`, `controller.ticket.get` and `agl ticket get`) now returns the ticket, all its questions and one page of history, oldest first: the newest `limit` entries (default 50, at most 500), cut earlier so that the entries and the comments they name stay within 256 KiB (always at least one entry; the size limit wins over `limit`), and the comments those entries name. `historyBefore` is present while older entries exist; passing it as `before` (`agl ticket get AGL-<n> --before <id> --limit <n>`) reads the next older page. `commentId` (`agl ticket get AGL-<n> --comment <id>`) reads the one comment an activity entry or a fleet event names, however old: the answer holds the ticket, its questions and that comment alone; it excludes `before` and `limit`, and an id that is not a comment of that ticket is refused with the new error `ticket_comment_not_found`. Controller protocol 46.
8
+ - The keys stay `ticket`, `comments`, `activity` and `questions`, but their meaning changed: `activity` and `comments` are one page, not the complete log, so a script that counts comments or searches the history in one answer is now silently wrong unless it pages back with `historyBefore` until it is absent. The `comments` operation (`agl.mcp.ticket.comments`) still returns every comment.
9
+ - A `commented` activity entry in the answer names its comment by id instead of repeating it: `changes.comment.after` is now `{ id }`, so `changes.comment.after.body` is undefined; read the body from `comments` (or with `commentId`). Stored activity is unchanged, so nothing is migrated.
10
+ - The board in the browser reads every page and shows the whole history as before.
11
+
12
+ ### Fixes
13
+
14
+ - The driver now reads the end of a long fleet report, where its `result:` or `needs input:` sits (AGL-814). An event text longer than 3 KiB used to reach the driver as its first 3 KiB; it is now a digest within the same 3 KiB: every line the fleet reads as a report marker (`result:`, `needs input:`, `owner question:` and the others), then the text's end, in order, with `[… N lines …]` where lines were left out. Each event's header names its event id and, where it has them, its report id, the comment that holds its whole text and its turn id (`- [event 42] <time> worker.report.mid_turn (ticket AGL-12, worker lane-a, report msg_…, comment …, turn …, status …)`). The note on a digest names the call that returns the whole text -- `ticket_get` with the event's ticket and that comment's id -- instead of `fleet_worker_status`, which observes a job and never returned a report; a text no comment holds says it is not kept, and a report the fleet cut at 32 KiB says so.
15
+ - A fleet event whose whole text is a ticket comment now names that comment (`commentId`, AGL-814), so the driver reads it with one `ticket_get` by `commentId` however long the ticket's history is; since `ticket_get` returns one page of history, "read it with `ticket_get`" could land on a page without the report (AGL-227 has 1,055 comments). The fleet now comments a ticketed worker's report before it publishes the report's event, which carries the id the board returned (a repeated report names the comment the first one wrote), and then its `ticket.applied`, `ticket.failed` or `ticket.unknown` as before: `worker.report.mid_turn` (also the fresh report after a failed observation) and `worker.turn.ended` when its report is commented. The board pump's `ticket.stalled` and `ticket.notified` name the notice comment, and a `ticket.changed` for a comment names that comment. A report whose comment was not written, or a worker without a ticket, names none. The id is not stored with the fleet's ticket effects. `agl fleet watch` shows `commentId` in its JSON; an earlier AGL's CLI refuses it, which controller protocol 46 already fences.
16
+ - The driver on a Claude model asks Anthropic for one-hour cache breakpoints (AGL-814). While the board changed within the hour the driver's cache stays warm, and FlexHarness times its warm-up turns by the cache's lifetime: an idle hour now costs one warm-up turn instead of fourteen. An hour's breakpoint costs 2× the input price to write instead of 1.25×. Other sessions, and the driver on a ChatGPT account, are unchanged.
17
+ - Streaming a Flex reply no longer costs work per delta beyond the delta itself (AGL-813). The Flex child sends each delta as one IPC frame, without a session change beside it, so the controller no longer announces `session.changed` for every delta: the Driver's status, the session feed and the browsers' conversation lists are read again at a part's start and end and at the run's lifecycle, not up to four times a second while a reply streams. The controller tracks a live snapshot's exact JSON and UTF-8 size as deltas arrive (escapes and surrogate pairs split across deltas included) and serializes the growing text only when a snapshot is served, so a part costs work in its own size rather than its size times its delta count; the limits and their results are unchanged.
18
+ - One slow browser no longer slows controller events for everyone (AGL-813). The Driver and the session feed see every event first, in order; each browser then gets it through its own ordered queue with one event in flight, so a tab that does not acknowledge within its two seconds delays only itself. A browser whose queue passes 512 events or 16 MiB is resynchronized alone: its queue keeps the newest event of each state, drops live text, reasoning and tool content, and ends with `sessions.changed` for each harness whose live content it dropped.
19
+ - Save a Flex conversation's checkpoints at the cost of what changed, not of its whole history. Every projection and Agent event save used to read the stored snapshot back (always for an Agent event log, and for a projection over 16 MiB), check and copy it whole, serialize it again, hash and base64-encode every chunk and hash the joined whole once more, while the public transcript hashed every message it lists again: at 32 MiB of history one save hashed about 67 MB, base64-coded about 112 MB and read 45 MB back. A save now applies its change to the snapshot the Flex child holds while it holds the conversation's storage lease, serializes only the new entries, hashes and encodes only the chunks the change touches, keeps every other chunk as stored, and takes the snapshot's SHA-256 in one pass over the kept chunk bytes; the public transcript keeps the record id of each message it listed before. At 32 MiB a save now hashes and encodes about 60 KB of a projection's chunks and about 530 KB of an Agent event log's (its first and last 384 KiB slices), the same as at 1 MiB. The stored documents are byte for byte those 40.5.0 writes, so an earlier or later AGL reads them. A projection save validates what its change carries and reads the entries it keeps for their identities only (FlexHarness's `createChangedProjectionSnapshot`, AGL-811): a turn's save onto 2,492 stored messages validates its two new messages in depth, where it validated all of them; loading a stored projection still validates it whole. That one hash pass still grows with the history: about 22 ms at 32 MiB of projection. After a conflict, a lost lease, a write whose outcome is unknown or a failed check, the next save of that conversation reads and rewrites it whole, as before.
20
+ - The Flex child's snapshot cache now holds Agent event logs too and takes a snapshot over 16 MiB: it holds 512 MiB as counted (a snapshot's kept chunk bytes once and its parsed form at twice its serialized size, as measured on Node 25), the least recently used leaving first, so about 170 MiB of serialized snapshots. A snapshot larger than all of it is saved whole each time, and the Flex child logs that once for it. Kept bytes are zeroed when they leave the cache.
21
+ - Deleting the chunks a save replaced examined every chunk of the project in the database (hundreds at 32 MiB, for both lists); it now examines only the chunks that go.
22
+ - Read one Flex session without reading every session of its project. Every Flex conversation's detail and every delegated transcript read loaded, checked and sorted all of the project's session records to find one (`FlexProjectionReader.getSession`). It now looks the session up through a new index of the public session records (`flex_public_session_lookup`: controller, project, session id) among the records the publication lists, and examines that session's stored versions only: one document with 100 or 2,000 sessions in the project. The returned record is checked against the publication as before; a session whose published record is missing is now reported as not found rather than invalid. The index is created at startup, outside any transaction; an earlier AGL starts with it in place and leaves it there.
23
+ - Ticket operations no longer read the whole board. Every ticket request read every ticket and every open question inside its transaction, a single `get` included, so the board pump's pass (a `get` for each ticket not released, every five minutes) read about the square of the board: some 430,000 ticket documents on a board of 800. Each operation now reads what it decides on: `get` one ticket, its questions and its history page; `comments` one ticket and all its comments; `comment`, `link`, `ask` and `answer` one ticket; `update` the ticket, its parent, and its children only when the project changes; `move` the two columns involved; `create` the parent and the size of its column; the listing operations (`list`, `board`, `search`) the board and its open questions, which they show. A history page reads its entries 16 at a time and stops where it is cut, so the browser, which reads a ticket's history 500 entries per page, no longer reads 500 entries for a page that the 256 KiB size limit cuts after a few long reports. The board revision every change moves, and every ticket revision check, are as before.
24
+ - The board pump reads a ticket's history only when the ticket changed. It keeps what it decided from each ticket's history by the ticket's revision, which every comment, question, answer and other change moves, and reads the ticket again only when the board list shows a new revision; a pass over an unchanged board reads the board list and nothing else.
25
+ - Settings → General shows each harness's default model as one folded button (AGL-902). The button says the model and the effort (`openai/gpt-5.6-sol · max`) and opens both in a speech bubble (`mp-model-picker` `fold="always"`, on `@modelprofile.com/catalog` 1.1.0 and `@design.estate/dees-catalog` 23.4.0), so every row is one line of the same height, where the model and the effort used to stack in some rows and sit side by side in others, and at phone width no longer squeeze the row's text into a column of single letters. Only the model gives way on a tight button; "Model default" is never cut, and the tooltip and the button's name keep the whole text. A saved default the harness no longer offers gives the button the warning tone and says so in its description.
26
+ - The default-model rows name a model without the harness the row already names: "openai/gpt-5.6-sol" in the Flex row instead of "Flex · openai/gpt-5.6-sol", in the choices and in the note on a saved default that is no longer offered (AGL-902).
27
+ - "New browser views show" no longer ends with "Paint is available." while Paint works; it still says why Paint cannot be used, or that no browser runtime runs (AGL-902).
28
+ - The driver's notes no longer sit in its system prompt (AGL-814). Every `driver_notes_update` changed the system prompt, which opens every request, so the provider wrote the driver's whole cached prompt again on the next turn. The system prompt now holds the driver's instructions only, and the notes reach the model as FlexHarness's pinned context `driver-notes`, named by the scratchpad's revision: a turn whose context does not show the current revision gets it appended right before its prompt, a compaction ends its summary with it, and everything in front of it stays byte for byte the previous request. The driver therefore sees its notes when they change and after a compaction rather than at the top of every turn; the packaged instructions and the notes tools' descriptions say so. Empty notes are pinned too (a note that they are empty), so clearing them replaces the text saved before.
29
+ - Proving the delivery of a held Flex message reads each transcript message's identity and state only (AGL-814). The check pages through the whole transcript, undone turns included, for the message's exact id; it used to read every page with each message's full text, reasoning and tool output, so one check of a long session moved its whole transcript between the Flex process and the controller. It now asks for metadata pages (FlexHarness's `listMessageMetadataPage`, the new Flex IPC request `message.metadata.page`): 80 messages cost 17 KB in two pages whether their bodies are 1 KiB or 64 KiB, where the full pages cost 106 KB and 5.3 MB in 2 and 12 pages. What proves delivery, and every rule around it, is unchanged.
30
+
31
+ ### Maintenance
32
+
33
+ - `@design.estate/dees-catalog` ^23.4.0 and `@modelprofile.com/catalog` ^1.1.0 (AGL-902). The composer's account, model and effort pickers fold through the catalog's new `dees-picker-fold`, as they folded before: the same widths, button, speech bubble and events. Its dropdowns now sit in that control's shadow root, which `test.flexaccountpicker` and `e2e.flexaccountswitch` reach through `[data-key="account"]`.
34
+ - FlexHarness 16.4.0 (`@modelprofile.com/flexharness`, `-agent`, `-models`, `-providers`). In Flex sessions a cache-warm turn leaves the model's context once it ends, so later turns no longer see its `[cache-warm]` prompt or answer (its transcript messages stay hidden as before); the `task`, `goal` and `scratchpad` tools return the project revision with only the field they read or changed instead of the whole project state; a context overflow that compaction cannot relieve fails at once instead of calling the model again with the same context; a streamed delta no longer searches the whole transcript, and a message page encodes each message once. Flex IPC protocol 39: `driver.resolve` names the notes' revision (`notesRevision`) and `message.metadata.page` is new; the controller and its Flex process always come from one install.
35
+
36
+ ## 2026-10-25 - 40.6.0
37
+
38
+ ### Features
39
+
40
+ - Serve Claude Code in containers through a confined route of the inference proxy (AGL-882). The proxy also listens on a Unix socket, alone in a private directory of its own (`agl-proxy-confined/proxy.sock` beside its control socket, 0700 and 0600, the proxy user's alone), which serves the Claude pool's three endpoints Claude Code uses -- `GET /anthropic/v1/models`, `POST /anthropic/v1/messages` and `POST /anthropic/v1/messages/count_tokens` -- exactly as the loopback listener serves them, and refuses every other path, method and pool with 404 before anything is read or routed. It accepts confined runs' credentials alone (any other credential, the loopback clients' and leases' included, is unknown there: 401), and a confined run's credential is unknown on the loopback listener. A confined run's credential is issued for one container run on the control socket (`agl.proxy.confined`): a lease of the Claude pool, Claude accounts first and then the Anthropic API keys, whose sessions are the client `confined`'s, so its requests are placed, moved and counted like any other Claude client's. It lives as long as its holder's control connection, survives a proxy restart like a lease (the proxy keeps only its SHA-256 digest, with the new lease field `route: 'confined'`, and its holder takes it back), and `agl.proxy.confined.end` ends it at once; the proxy then closes the holder's connection with one last line saying why (`{"ended": …}`), which the holder reports instead of taking the credential back. `agl proxy confined run -- docker run …` takes a run's credential, adds the listener's directory as a read-only mount at `/run/agl-proxy` and Claude Code's settings right after `docker run` (`ANTHROPIC_UNIX_SOCKET=/run/agl-proxy/proxy.sock`, `ANTHROPIC_BASE_URL=http://localhost/anthropic`, `ANTHROPIC_AUTH_TOKEN`, model discovery on and nonessential traffic off), each passed by name, drops every variable that would give Claude Code another login or route from the environment `docker` runs with, prints the run's id, exits with the container's status and ends the credential when the container exits; a credential the operator ended (`agl proxy confined end <run id>`) or the proxy no longer hands back stops the container and ends the run with the reason. Claude Code sends its API requests through the socket itself (`ANTHROPIC_UNIX_SOCKET`, verified with 2.1.288), so no relay runs in the container. The socket is the proxy user's (0600): the container runs as that uid, or as root under rootless Docker; root of a rootful daemon also connects while it keeps Docker's default capabilities. `agl proxy status` names the confined listener and lists the runs (`confinedSocketPath`, `confinedRuns`). `test/e2e/e2e.proxyconfined.node.ts` runs Claude Code in a container without a network through the socket; it skips without Docker or the `ubuntu:24.04` image. Downgrade: an earlier proxy refuses to start while its store keeps a confined run's credential; let every confined run end first, or start this release once with none going and wait out the 60-second reclaim window.
41
+
42
+ ### Fixes
43
+
44
+ - A fleet Claude worker keeps its verified MCP ticket identity when Claude Code continues its job in a new process and across controller restarts (AGL-840). Its caller launch was proved against one process of its background job and held only in the controller's memory: once Claude Code retired the idle process and started a new one for the same job (when someone wrote to the job in Claude Code), or the controller restarted, every MCP ticket write was refused with `TICKET_IDENTITY_REQUIRED` until AGL itself woke the worker again, and the controller logged nothing. A launch now belongs to its job: the controller keeps its binding in the store (new collection `agl_worker_caller_bindings`, one record per worker with digests of the launch id and generation, the job and session ids, the revision, the proved process and the approved bridge command; never a credential), and a bridge under another process, or one that outlived a restart, is proved again at its next call from a fresh Claude inventory, one read at a time: only the worker's session as the same job, in exactly the bridge's parent process, running the approved Claude Code executable, with the bridge its direct child on the recorded command. Any other process stays refused, and a refused process image is not proved again at every call. A job that settled before the fleet bound it keeps its launch instead of losing it. The launch is revoked for good when the worker is stopped or archived, launched again, or the inventory shows its session as another job or the fleet no longer gives the job to the worker. An upgrade moves each bridge in place onto the new build (same PID, a new image from the new install's path); it keeps the worker's identity when it runs the command recorded with the launch or the one the restarted controller resolves itself from its configured `agl` MCP entry (never one the bridge names), and the new command is kept with the binding. A controller that stops now closes fleet admission first and lets running worker jobs settle (at most ten seconds, then they are aborted) before it removes the caller hooks, so a stop or archive during shutdown is refused by the fleet as closing instead of failing on missing hooks. Every reason an enrollment stays unverified is written once to the controller log, with the worker and its session but never the launch id or a credential. Codex workers are unchanged: they are bound again before each dispatch. Downgrade: 40.5.1 starts with the new collection present and leaves it alone; a worker archived or launched again under the older release leaves its record behind, which this release refuses at the first enrollment that presents it (the fleet no longer gives that job to the worker) or replaces at the worker's next launch. Controller protocol stays 45.
45
+
3
46
  ## 2026-10-25 - 40.5.1
4
47
 
5
48
  ### Fixes