@staix/agent-hub 0.31.0 → 0.33.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 (50) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +2 -2
  3. package/docs/agent-notes/bus.md +3 -1
  4. package/docs/agent-notes/daemon.md +1 -0
  5. package/docs/agent-notes/tests.md +2 -2
  6. package/docs/design/bus.md +109 -4
  7. package/docs/dogfood.md +2 -0
  8. package/docs/memory.md +9 -3
  9. package/docs/operations.md +98 -17
  10. package/docs/quickstart.md +18 -2
  11. package/docs/security.md +52 -9
  12. package/docs/specs/2026-09-19-agent-hub-design.md +75 -5
  13. package/docs/specs/2026-09-20-upgrade-recovery-design.md +7 -3
  14. package/docs/verification/2026-11-05-hardcoded-values-classification-rules.md +55 -1
  15. package/docs/verification/2026-11-06-0.32.0.md +149 -0
  16. package/docs/verification/2026-11-06-0.33.0.md +222 -0
  17. package/docs/verification/2026-11-06-claude-implementer-2.1.319.md +57 -0
  18. package/docs/verification/2026-11-06-codex-0167-reviewer-isolation.md +56 -0
  19. package/docs/verification/2026-11-06-codex-0167-reviewer-tool-call.md +66 -0
  20. package/docs/verification/2026-11-06-kimi-251-reviewer-compat.md +88 -0
  21. package/docs/verification/2026-11-06-orca-1.4.250-cli-contract.md +50 -0
  22. package/docs/verification/2026-11-06-qwen-0268-acp.md +75 -0
  23. package/docs/verification/2026-11-06-qwen-0268-dual-output.md +44 -0
  24. package/docs/verification/claude-shell-wrapper-native.py +1 -1
  25. package/docs/verified.json +11 -11
  26. package/package.json +2 -2
  27. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  28. package/plugins/agent-hub/server.js +528 -206
  29. package/src/adapters/compat.ts +11 -11
  30. package/src/broker/protocol.ts +5 -0
  31. package/src/broker/server.ts +54 -4
  32. package/src/broker/store.ts +6 -3
  33. package/src/cli/console-state.ts +1 -1
  34. package/src/cli/output.ts +5 -1
  35. package/src/cli/room.ts +34 -12
  36. package/src/cli/status-lines.ts +8 -1
  37. package/src/cli/terminal-recovery.ts +37 -15
  38. package/src/hub/bus.ts +25 -0
  39. package/src/hub/daemon.ts +20 -9
  40. package/src/rooms/application.ts +15 -0
  41. package/src/rooms/commands.ts +135 -30
  42. package/src/rooms/health.ts +32 -0
  43. package/src/rooms/link.ts +394 -56
  44. package/src/rooms/liveness.ts +11 -0
  45. package/src/rooms/remote-peer.ts +18 -3
  46. package/src/rooms/service.ts +167 -28
  47. package/src/rooms/status.ts +65 -2
  48. package/src/rooms/store.ts +30 -1
  49. package/src/rooms/wire.ts +10 -8
  50. package/src/ui/index.html +5 -3
@@ -32,6 +32,22 @@ terminal in that project: it reviews the plan with you, applies it and follows
32
32
  it; other projects keep their version. It then names the `bun add -g` and
33
33
  `ahub setup` step when your global CLI or plugin is older than the new daemon.
34
34
 
35
+ ## Upgrading to 0.33.0
36
+
37
+ Rooms now show refused-frame counts, outbox depth/ages and a closed link cause with a recovery step. Store-open failures retry, receive-only work wakes after journal recovery, and selective traffic no longer produces false sequence-gap notices. For a rolling room upgrade, update the broker first, then every member, then reconnect: 0.33.0 person-inbox (`user@label`) and invocation sends to a released 0.32.0 member, or through a released 0.32.0 broker are refused before effects with the upgrade step; plain chat keeps working. Use the matching CLI for the new diagnostics: 0.32.0 `ahub room status` drops the new fields, including in its JSON output, while `ahub status --json` passes raw daemon fields through.
38
+
39
+ Orca recovery now recognizes its gone-terminal codes. The compat policy adds exactly Claude headless implementer 2.1.319, Kimi reviewer 2.5.1 and Qwen ACP 0.26.8 based on their model-free receipts. Codex reviewer 0.167.0 remains unverified after an unknown tool-call outcome, and Qwen dual-output remains at 0.26.1. These entries do not install agent CLIs or prove real-account/model behavior. N-1 is published 0.32.0 and control remains 16 through 17.
40
+
41
+ This hub pins agent-mem 0.22.1 while 0.32.0 pins 0.21.0. Placement is opt-in; inactive homes behave as before, and the common formats and `INDEX_VERSION` are unchanged. The person-only activation preview is available, but activation alone does not enable this hub's automatic v3 sync: fresh host `placementAttestation` integration remains #1173. Shared-home activation and writer renewal are separate person operations; upgrading the hub performs neither. See [memory integration](memory.md#automatic-sync-health-1173).
42
+
43
+ `ahub upgrade` does not update the global CLI or the shared Claude plugin: run `bun add -g @staix/agent-hub@0.33.0` and then `ahub setup` yourself, and `ahub doctor` warns while either is older than a running daemon.
44
+
45
+ ## Upgrading to 0.32.0
46
+
47
+ Rooms on an ephemeral-capable broker now refresh signed presence every 30 seconds; three missed periods display advisory unknown without changing sending authority. A graceful stop attempts a signed offline snapshot within two seconds. Epoch-changing room commands list sealed outstanding delivery IDs before confirmation and immediately hold old-epoch work with the named cause. Upgrade the global CLI and plugin with the step below to see the new previews and advisory status: a 0.31.0 CLI ignores those additive fields, even in JSON. A broker without ephemeral support keeps state-change publication and reports liveness untracked, with no periodic aging. Protocol 16 through 17 and room v1 shapes remain; the N-1 baseline is published 0.31.0, with the same agent-mem 0.21.0 pin.
48
+
49
+ `ahub upgrade` does not update the global CLI or the shared Claude plugin: run `bun add -g @staix/agent-hub@0.32.0` and then `ahub setup` yourself, and `ahub doctor` warns while either is older than a running daemon.
50
+
35
51
  ## Upgrading to 0.31.0
36
52
 
37
53
  The control protocol stays at 16 through 17 and hub.db keeps schema version 2, but this release adds the nullable `deliveries.failure_cause` diagnostic column. N-1 recovery ignores the extra snapshot key, and older rows without it remain unknown. The exact `@staix/agent-mem` pin moves from 0.20.1 to 0.21.0; upgrading does not activate placement or migrate a memory home. `ahub memory declined` now lists complete bounded physical IDs and safe rule categories when inspection succeeds. Automatic v3 sync remains unsupported until agent-mem#281 provides activation and fresh host attestation. The [N-1 statement](../CHANGELOG.md) distinguishes the hub 0.30.0 fixture from agent-mem's own 0.20.3 compatibility proof.
@@ -188,7 +204,7 @@ The restarted Claude planner gets the release-train tools (`hub_release_new`, `h
188
204
 
189
205
  Jcode must be 0.98.0 or later, below 1.0.0; 0.94.0 is no longer accepted, so `ahub doctor` fails its Jcode row for an older install and the peer does not start (#529). Every owned jcode process runs with `JCODE_NO_TELEMETRY=1`.
190
206
 
191
- Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.21.0. Before anyone runs `amem migrate --shards` on a memory home, every hub using that home must run 0.12.37 or later: an older hub does not see the split and keeps writing the old layout. `ahub memory profile-check` is split-aware and compares each hub with its own project's shard (#536). See [memory profiles and rollout](memory.md#selected-memory-profile).
207
+ Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.22.1. Before anyone runs `amem migrate --shards` on a memory home, every hub using that home must run 0.12.37 or later: an older hub does not see the split and keeps writing the old layout. `ahub memory profile-check` is split-aware and compares each hub with its own project's shard (#536). See [memory profiles and rollout](memory.md#selected-memory-profile).
192
208
 
193
209
  From 0.12.30 or earlier, existing Jcode project MCP entries need one refresh before conductor or dashboard starts. Once per project, the person runs:
194
210
 
@@ -266,7 +282,7 @@ More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-de
266
282
 
267
283
  ## Shared memory
268
284
 
269
- The hub exact-pins the first-party `@staix/agent-mem` 0.21.0 core, including deterministic capture; no claude-mem worker is needed. Existing shared-v1 memory remains the default; upgrading does not migrate it. Managed agents use screened `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools, or propose a correction with `hub_memory_correct`; only a person accepts candidates through the supported `amem review` path. Since agent-mem 0.7.0, `amem review` also accepts candidates on a selected generation.
285
+ The hub exact-pins the first-party `@staix/agent-mem` 0.22.1 core, including deterministic capture; no claude-mem worker is needed. Existing shared-v1 memory remains the default; upgrading does not migrate it. Managed agents use screened `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools, or propose a correction with `hub_memory_correct`; only a person accepts candidates through the supported `amem review` path. Since agent-mem 0.7.0, `amem review` also accepts candidates on a selected generation.
270
286
 
271
287
  Before any real generation migration, upgrade every hub sharing that memory home to 0.12.30 or later and check its authenticated binding with `ahub memory profile-check` in each custom registry. Ready bindings prove compatibility, not an atomic live cutover: quiesce consumers and close their handles before migrating, then reopen through the supported session-preserving lifecycle. Invalid or changed profiles disable native memory without falling back to legacy writes; the bus and board continue. See [memory operations](operations.md#hub-memory) for the remaining rollout gates.
272
288
 
package/docs/security.md CHANGED
@@ -26,7 +26,7 @@ agent-hub connects agents that can each run commands. This page says what the hu
26
26
 
27
27
  ## Native memory authority and profile selection
28
28
 
29
- The portable core is the exact-pinned first-party `@staix/agent-mem` 0.21.0 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
29
+ The portable core is the exact-pinned first-party `@staix/agent-mem` 0.22.1 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
30
30
 
31
31
  `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` take the project from the daemon, require `memory_read`, refuse private turns and validate UTF-8 input before logs or storage work. Complete records and graph metadata are screened before counts and truncation. Search is at most 20 lines/4 KiB (default 8); show accepts at most 8 ids and returns at most 8 KiB; graph is at most 120 nodes/240 edges/6 KiB (default 60 nodes), with no edge lacking an endpoint. Unknown, ambiguous and withheld ids share one neutral refusal. Arguments and results are excluded from hub-managed capture; this does not govern a vendor's independent transcript or memory hooks.
32
32
 
@@ -179,6 +179,30 @@ completion authority. Old brokers receive the legacy frame shape. The broker wit
179
179
  hubs until they upgrade; chat
180
180
  frames remain compatible. See [room wire compatibility](design/bus.md#room-wire-compatibility-1204-t1).
181
181
 
182
+ Room liveness (#1204 T3) is advisory availability, never native execution or
183
+ process ownership proof. Periodic refresh and three-period expiry run only after
184
+ broker ephemeral negotiation. A legacy broker reports liveness untracked, with
185
+ no periodic refresh or aging. Unknown room presence adds no native `PeerState`
186
+ value or authority. Aging neither grants nor removes outbound admissibility;
187
+ signed roster, exposure, link and Bus proofs still govern sending. Explicit signed
188
+ offline presence keeps its existing handling. Freshness uses validated local
189
+ observations only; restored presence and rolled-back clocks cannot renew the
190
+ advisory liveness view, and status remains read-only.
191
+ Graceful stop fences publications synchronously and attempts one signed offline
192
+ frame in FIFO order within two seconds; durable intents/receipts remain, and
193
+ failure relies on supporting recipients' aging rather than remote process stop.
194
+
195
+ Before a person changes a room epoch, an ids-only preview binds already sealed
196
+ unresolved Store intents and the roster digest. The final commit rechecks both
197
+ with link publication quiesced. Old active intents are quarantined atomically
198
+ using the existing `boundary_refused` reason and schema, with sendable ciphertext
199
+ removed. T3's local Bus `needs_review` journal reason is the fixed
200
+ `room epoch rotated; inspect ahub queue show <id>` text; room status labels its
201
+ `holdReason` as `epoch rotated`. No body enters either reason. Bus-only queued work, terminal results and person
202
+ dispositions are unchanged. T2's existing crash-gap quarantine remains the
203
+ recovery boundary. No completion, replay, cancellation, new wire codec or new
204
+ native authority follows from the preview, rotation or liveness metadata.
205
+
182
206
  ## What is not defended
183
207
 
184
208
  - **A malicious local process running as you.** It can read the control token, `hub.db`, the project and your home directory without the hub's help. The token keeps web pages and other users out, not your own processes.
@@ -705,7 +729,7 @@ withholds the scoped mode on these writes so an older hook grants nothing too.
705
729
 
706
730
  Agent CLI versions (#691). One policy gates the Codex and Kimi fresh reviewers, the headless Claude implementer, Jcode, agy, Qwen (ACP and the dual-output TUI) and Pi (#843): a receipt-verified version passes, Jcode and agy also start an untested version inside their compatible line with a note, and any other version is refused unless the person trusts that exact version on this machine with `ahub agents trust <id> <version>`. The record is `agent-compat.json` in the hub home (`~/.agenthub`), written atomically with mode 600 and at most 64 entries; an unreadable, linked, oversized or invalid record trusts nothing. Agent shells and `--live-test` may read `ahub agents` but cannot trust or revoke. Trust lifts only the version pin: the fresh reviewers' runtime proofs still run before every child, and an untested version's native contract stays unverified.
707
731
 
708
- Qwen Code's optional production ACP peer requires the qwen-code native identity, a compat-admitted version (receipt-verified 0.25.0, 0.26.0, 0.26.1, 0.26.4 and 0.26.5)
732
+ Qwen Code's optional production ACP peer requires the qwen-code native identity, a compat-admitted version (receipt-verified 0.25.0, 0.26.0, 0.26.1, 0.26.4, 0.26.5 and 0.26.8)
709
733
  and advertised mode ids before setting a policy or starting work. Its own tools
710
734
  have no hub sandbox; auto-edit approves file edits, yolo every tool. Configured
711
735
  never-ask still requires the person's confirmation. qwen_cmd is machine-local and
@@ -800,8 +824,10 @@ result. Failure logs retain only the closed cause and known declined count.
800
824
  and uses bounded physical-row inspection to show IDs and rule categories, never
801
825
  note text or literal patterns; incomplete inspection is not a zero count.
802
826
  Default-host v3 sync remains unsupported because the hub supplies no fresh
803
- placement attestation. No activation proof is fabricated; the supported activation
804
- and attestation path remains agent-mem#281. Suggested graph edges are off by default
827
+ placement attestation. No activation proof is fabricated. The native amem CLI
828
+ provides person-only activation from 0.22.0; the hub does not invoke it, and
829
+ default-host v3 sync still requires legitimate fresh host-attestation integration
830
+ (#1173). Suggested graph edges are off by default
805
831
  and are not evidence until a person confirms them. Operational details and limits: [hub memory](memory.md).
806
832
 
807
833
  ## Floating pet retirement (#1012)
@@ -849,7 +875,7 @@ Task branch authority uses recorded `refs.branch`, otherwise a host-observed non
849
875
 
850
876
  The fresh Codex reviewer (#519) needs `review_mode: "fresh"` and a compat-admitted Codex (receipt-verified 0.146.0, 0.163.0 and 0.164.0; `ahub agents` shows the current policy); an unverified/untrusted version is unavailable. Before each review it requires a model-free isolation receipt: binary and config unchanged, only the two hub tools in the configured MCP inventory (each approved by its own name, never by a server-wide default, #783), plugins, hooks and Apps disabled (Apps by a separate feature readback), and a named filesystem profile whose fixtures prove public reads, private-path denial (exact, glob and symlink), standard host credential denial and write denial. Credential and tool-home roots are denied even with an empty `local.deny`; that list does not cover every personal file. A dangling or unreadable credential root refuses the reviewer, and the reason names only its path class (`~/.docker`, `$DOCKER_CONFIG`), never the path or its contents. A failed per-review start names one class from a closed list (`version`, `binary`, `mcp_inventory`, `plugins_hooks_apps`, `sandbox_proof`, `credential_root`, `timeout`, `unknown`) with a fixed sentence in the unavailable reason, `hub.log` and the `reviewer` line of `ahub status`; it never carries a path, native CLI text or a token (#722). Its shell is sandboxed read-only, not Claude's Read/Grep/Glob whitelist. Network and web search are configured disabled but not observed: managed requirements can still select cached web search, and no run has shown the review selecting the profile through `default_permissions`. A failed receipt or start never falls back to a continuing native session, and a child that ends without a saved verdict is never approval. The agy reviewer slot is an unavailable placeholder and never runs; it binds nothing, so agy's own `hub_task_show` reads are not fenced as a review (#792).
851
877
 
852
- The fresh Kimi reviewer (#533) needs `review_mode: "fresh"` and a compat-admitted Kimi Code (receipt-verified 2.2.0, 2.3.0, 2.3.1, 2.3.2 and 2.4.1; `ahub agents` shows the current policy) with its native OAuth login; an unverified/untrusted version, or a failed preparation, is unavailable. The [2.3.0](verification/2026-10-22-kimi-qwen-compat.md) and [2.3.1](verification/2026-10-25-kimi-231-reviewer-compat.md) receipts are model-free and do not prove real login or a model review. It is a native tool-authority boundary, not a sandbox: no Seatbelt wraps it, and same-user native code is not isolated from the filesystem or network. Each review starts a new child in a private `KIMI_CODE_HOME` with managed-provider-only config, a clean temporary working directory and an empty skills directory. Its agent may use only `hub_review` and `hub_task_show`, served by a loopback MCP session bound to the task, head and review revision that never carries the hub's control token; it has no native read, file or shell tool and sees only the screened review brief and host facts. Its `credentials/` and `oauth/` directories and `device_id` link to the person's native ones, so refresh keeps Kimi's own lock and atomic rename; no token is copied and `KIMI_DISABLE_OAUTH_LOCK` is never set. A stop revokes its verdict authority before termination; killing it mid-refresh may require a native re-login. Private tasks are never given to it, and a child that ends without a saved verdict is never approval.
878
+ The fresh Kimi reviewer (#533) needs `review_mode: "fresh"` and a compat-admitted Kimi Code (receipt-verified 2.2.0, 2.3.0, 2.3.1, 2.3.2, 2.4.1 and 2.5.1; `ahub agents` shows the current policy) with its native OAuth login; an unverified/untrusted version, or a failed preparation, is unavailable. The [2.3.0](verification/2026-10-22-kimi-qwen-compat.md), [2.3.1](verification/2026-10-25-kimi-231-reviewer-compat.md) and [2.5.1](verification/2026-11-06-kimi-251-reviewer-compat.md) receipts are model-free and do not prove real login or a model review. It is a native tool-authority boundary, not a sandbox: no Seatbelt wraps it, and same-user native code is not isolated from the filesystem or network. Each review starts a new child in a private `KIMI_CODE_HOME` with managed-provider-only config, a clean temporary working directory and an empty skills directory. Its agent may use only `hub_review` and `hub_task_show`, served by a loopback MCP session bound to the task, head and review revision that never carries the hub's control token; it has no native read, file or shell tool and sees only the screened review brief and host facts. Its `credentials/` and `oauth/` directories and `device_id` link to the person's native ones, so refresh keeps Kimi's own lock and atomic rename; no token is copied and `KIMI_DISABLE_OAUTH_LOCK` is never set. A stop revokes its verdict authority before termination; killing it mid-refresh may require a native re-login. Private tasks are never given to it, and a child that ends without a saved verdict is never approval.
853
879
 
854
880
  The review brief (#520) withholds private changes whole (both sides of a move) and counts them; a rule file that fails the private-data screen is named, not shown. Attributes and rules are read at the merge base, so a change cannot loosen its own review. Optional changed symbols (#684) come from ripwire 0.6.7 on the daemon's host PATH, run as an owned process on a disposable snapshot of the task's commit; each path, name and kind passes the hub's public metadata screen before the brief, the console's task detail or the dashboard shows it, a private task stores and shows none, and a failed or missing read is `unknown`, never a gate. Spec acceptance, plan review, plan conformance, premature-review, cost, test-integrity (#481 S4), issue and PR identity linking (#694) and dogfood scorecard (#687) reads fetch GitHub metadata only (edit times, check states, thread authorship and resolution, changed file names, open PR heads, workflow run conclusions), never issue bodies, comments or patches. Issue identity linking at propose and accept (#723) parses the task's title and refs locally, reads nothing from GitHub and skips PII tasks. The CI workflow keeps `contents: read` and `actions: read`.
855
881
 
@@ -1183,10 +1209,11 @@ X5b adds the separate durable inbox boundary below.
1183
1209
 
1184
1210
  The console Rooms panel (`8`) and dashboard Agents > Rooms use only the canonical
1185
1211
  room metadata projection: local name/id, epoch, owner/self fingerprints, member
1186
- count, link state and exposed peer ids/states. No body, title, reason, broker URL,
1187
- key material or delivery history enters this projection. Reading it creates no
1188
- room storage or keys; missing rooms stay hidden and unavailable metadata stays
1189
- explicitly unknown.
1212
+ count, link state and exposed peer ids/states, closed link cause and regenerated
1213
+ next step, retained refusal counts, outbox depth and transport ages. No body,
1214
+ title, arbitrary reason/error prose, broker URL, key material or delivery history
1215
+ enters this projection. Reading it creates no room storage or keys; missing rooms
1216
+ stay hidden and unavailable metadata stays explicitly unknown.
1190
1217
 
1191
1218
  Relay counts are daemon-session observations, reset at restart: successful
1192
1219
  outbound handoffs, confirmed inbound admissions and withheld handoffs as a subset
@@ -1296,3 +1323,19 @@ Person comment writes (`review_comment_put`, `review_comment_delete`, `review_co
1296
1323
  - **Material.** Placement material comes only from guarded immutable Git snapshots at the task's recorded head (declared refs, plan paths, or same-head verified PR paths), bounded per operation to eight files and eight seconds; a sent package is at most 12,000 bytes. `review_blob` refuses a PII task, and periodic snapshots make no comment-material Git or GitHub read. PII tasks and private paths keep comments on the board and count-only in every public view.
1297
1324
  - **Delivery.** A sent package carries the host-only `refs.reviewPackage` marker: the intended owner gets the body, while logs, stream projections, incoming labels, memory capture and observers get an ids-only stub; review markers a peer supplies are discarded. Open sent comments, anchored findings and unsettled review deliveries keep the original recipient's responses out of shared memory and observers until resolution, dismissal, task close or explicit disposition (#1192, #1205). The marker grants no task, console or PII authority.
1298
1325
  - **Retry and recovery.** A send is never retried automatically, and a queued receipt proves publication, not that the owner read it. A restart, upgrade or recovery onto a daemon lacking `review_comments` is refused while anchored comments are stored.
1326
+
1327
+ ### Room health and codec advertisements (#1204 T4)
1328
+
1329
+ Room health projects closed cause codes, retained refusal counts and transport
1330
+ ages only. Raw store errors, broker URLs, bodies, titles and key material never
1331
+ enter status. Codec advertisements are signed compatibility evidence scoped to
1332
+ the current local session, source connection token and roster. Missing observation
1333
+ is pending and permits no wire effect; only positively known legacy or unsupported
1334
+ members receive an upgrade refusal. Pending sends retain their original queue
1335
+ expiry and wake on a current member observation. Peer connection metadata is
1336
+ compatibility evidence only, never an authorization source. The existing ephemeral
1337
+ header remains exactly `1`; an extra ignored codec header preserves released
1338
+ broker behavior. A feature-presence variant reaches opted-in sessions only; legacy members retain
1339
+ the unchanged presence payload. Codec support grants no exposure, role, privacy,
1340
+ invocation or native permission. A storage-recovery wake retries deferred
1341
+ admission under its existing guards and never replays uncertain native work.
@@ -1130,8 +1130,20 @@ The optional ephemeral field is used only after an opted-in connection receives
1130
1130
  clients that do not opt in. Missing advertisement means legacy presence frames,
1131
1131
  with dedupe/backoff still active. The broker withholds ephemeral frames from older member hubs
1132
1132
  until upgraded; application chat stays wire-compatible. See the [compatibility
1133
- ceiling](../design/bus.md#room-wire-compatibility-1204-t1); #1204 T4 owns full codec
1134
- feature negotiation.
1133
+ ceiling](../design/bus.md#room-wire-compatibility-1204-t1). Codec-aware presence
1134
+ keeps `x-agent-hub-ephemeral: 1` and adds `x-agent-hub-codecs: 1` on that same
1135
+ WebSocket upgrade. Released brokers ignore the codec header while preserving
1136
+ ephemeral presence and liveness. Only explicitly opted-in clients receive the
1137
+ bounded current-roster peer connection inventory and signed feature snapshots.
1138
+ Feature evidence is tied to the observed source connection token and roster;
1139
+ ordinary presence never revokes a same-connection claim. Legacy members receive
1140
+ the unchanged legacy presence bytes. A missing observation is pending, grants no
1141
+ support, and defers a send under its original queue expiry. Known legacy members
1142
+ or signed feature lists missing the required codec refuse with an upgrade step.
1143
+ Fresh support and known-legacy observations wake only that member's codec waiters,
1144
+ including sends not yet admitted to the room outbox. Requeue rechecks the observation
1145
+ to avoid losing a wake that arrived during an await. These signals grant no exposure,
1146
+ roles, privacy clearance or native authority. Plain v1 chat stays compatible.
1135
1147
 
1136
1148
  ### Durable state and outbound link
1137
1149
 
@@ -1171,7 +1183,7 @@ at most 8 pending packets/2 MiB per link, 1 MiB packet/backpressure limits and a
1171
1183
  minutes and do not block local work. Stop, leave, replacement and rotation fence
1172
1184
  all awaited work by link generation.
1173
1185
 
1174
- With latest-per-sender coalescing, A awaiting C can have its queued request replaced by A's broadcast reply to B, so C sees the request only on A's next state change or reconnect; task #736 idle refresh or per-(sender,recipient) coalescing is the upgrade path.
1186
+ With latest-per-sender coalescing, A awaiting C can have its queued request replaced by A's broadcast reply to B. T3's periodic idle refresh requests another observation without waiting for a state change or reconnect; per-(sender,recipient) coalescing remains a possible stronger transport design. Legacy brokers retain the state-change/reconnect behavior without periodic refresh.
1175
1187
 
1176
1188
  Presence is an encrypted, signed frame containing only exposed peer ids and closed
1177
1189
  idle/busy/paused/offline states. It is sent on connection and coalesced peer-state
@@ -1402,11 +1414,26 @@ confirmed local admissions. Withheld counts are a subset of outbound handoffs,
1402
1414
  not an additional total. Missing or unreadable values stay `null`/unknown, never
1403
1415
  zero. These counters do not prove application completion or lifetime traffic.
1404
1416
 
1405
- The projection contains no message body/title, reason, broker URL, key material
1406
- or delivery history. This projection never reads a person inbox body; X5b below
1417
+ Room health additionally exposes retained refused-frame counts by closed reason,
1418
+ current outbox depth, oldest outbox age and last retained signed receipt age, and
1419
+ a closed link cause with a locally generated next step (#1204 T4). Unknown ages
1420
+ remain null, including generic legacy outbox rows without creation time. Counts
1421
+ are bounded retained diagnostics, not lifetime totals or delivery authority.
1422
+ The projection contains no message body/title, arbitrary error reason, broker URL,
1423
+ key material or delivery history. This projection never reads a person inbox body; X5b below
1407
1424
  provides that separate person-only CLI. Native/account and X7 two-machine
1408
1425
  receipts remain separate live verification.
1409
1426
 
1427
+ A failed store open is shown as `rooms: unavailable (<code>)` with a next step,
1428
+ and retried with exponential delay from one second to a thirty-second ceiling.
1429
+ Shutdown cancels the owned retry. Clock rollback is explicitly named; status
1430
+ reads never advance the durable clock. A verified Bus journal recovery write
1431
+ wakes deferred inbound room admission once without unrelated traffic or plaintext
1432
+ polling. This wake preserves recovery, PII, exposure and person-disposition fences.
1433
+ The signed sequence remains room-wide. Recipient-selective traffic makes gaps
1434
+ unobservable at a member, so operator gap notices are removed; monotone replay
1435
+ floors, dedupe and receipt evidence remain unchanged.
1436
+
1410
1437
  ## Encrypted rooms: X5b person inbox (#446)
1411
1438
 
1412
1439
  Authenticated eligible chat to local `user` is admitted to a durable person
@@ -6522,3 +6549,46 @@ permanent refusal remains inspectable. A signed late receipt may settle an
6522
6549
  unresolved ordinary remote hold once without overriding a person disposition.
6523
6550
  Invocation uncertainty retains its person-only ledger hold. Receiver application
6524
6551
  deduplication, current identity/privacy fences and all caps remain.
6552
+
6553
+
6554
+ ### Room liveness and person-visible rotation (#1204 T3)
6555
+
6556
+ The T3 contract is [room liveness and epoch changes](../design/bus.md#room-liveness-and-epoch-changes-1204-t3).
6557
+ The broker's existing negotiated ephemeral bit alone enables 30-second periodic
6558
+ `requestReply` publication and three-period (90-second) local observation aging.
6559
+ It adds no wire payload kind, codec advertisement or native `PeerState` value.
6560
+ Legacy brokers have no periodic refresh or aging and explicitly report liveness
6561
+ untracked, with a broker upgrade step. The existing state-change dedupe,
6562
+ request/reply fencing, caps, privacy and T2 receipt/dedupe ceilings remain.
6563
+
6564
+ An asynchronous, idempotent stop fences publication synchronously, attempts one
6565
+ signed offline snapshot in FIFO order behind an attempted head, and disconnects
6566
+ within two seconds while retaining durable intents and receipt outbox rows.
6567
+ Failure leaves supporting recipients to age the observation; it grants no
6568
+ remote process-stop or execution authority. Refresh period and observation clock
6569
+ are fixture seams. Restored observations cannot establish freshness; clock
6570
+ rollback makes displayed liveness unknown and status reads mutate neither time
6571
+ nor delivery state. Aging is advisory only and never changes outbound admissibility;
6572
+ signed roster, exposure, link and Bus proofs remain authoritative. Explicit signed
6573
+ offline presence keeps its existing handling, and the broker can queue for members
6574
+ that are not live.
6575
+
6576
+ Person previews for epoch-changing owner exposure, invite acceptance, revocation
6577
+ and existing-room `join --roster` adoption bind the current roster digest and the
6578
+ sorted, exact set of already sealed unresolved Store delivery ids. Link
6579
+ application publication is quiesced before the final recheck and commit; a new or
6580
+ settled id invalidates the preview. Bus-only unsealed work is excluded.
6581
+ RoomStore uses its existing schema and `boundary_refused` reason to quarantine
6582
+ old active intents atomically with the epoch and remove sendable ciphertext.
6583
+ T2's crash-gap quarantine remains the recovery fence, not a new T3 repair.
6584
+ T3 gives matching local Bus deliveries `needs_review` with fixed journal reason
6585
+ `room epoch rotated; inspect ahub queue show <id>` and room-status
6586
+ `holdReason: "epoch rotated"`. Terminal rows and person
6587
+ dispositions remain authoritative; rotation is not completion, replay or
6588
+ cancellation. A committed rotation whose local journal hold cannot be written
6589
+ returns `epoch_rotated_hold_unavailable` with an inspection step, without
6590
+ restoring old sendability.
6591
+
6592
+ Source and isolated fixture coverage are listed in [dogfood](../dogfood.md).
6593
+ Those fixtures do not establish installed or two-machine liveness. #1204 remains
6594
+ open for T4's full capability advertisement and compatibility work.
@@ -242,9 +242,13 @@ slices, and once the terminal reads idle (an idle terminal may be the shell the
242
242
  launcher returned to), a recorded launcher that is gone means the launch failed,
243
243
  recognized within one slice. A launcher whose identity cannot be read is unknown
244
244
  and is waited for, never taken as gone. A handle Orca reports
245
- `terminal_handle_stale` means the terminal is gone only when no recorded
246
- launcher may still run and Orca no longer lists the terminal's incarnation;
247
- otherwise the create stays uncertain. A launcher that died before recording
245
+ `terminal_handle_stale`, `terminal_exited`, `terminal_gone` or
246
+ `no_connected_pty` (the codes Orca itself groups as gone; 1.4.250 raises
247
+ `terminal_exited` for a wait on a pane whose process ended, #1233) leads to the
248
+ launcher check: the terminal is gone only when no recorded launcher may still
249
+ run and Orca no longer lists the terminal's incarnation; otherwise the create
250
+ stays uncertain. Any other Orca failure is reported with Orca's error code and
251
+ message, and a wait Orca answers as blocked names its `blockedReason`. A launcher that died before recording
248
252
  itself is not distinguished from a slow one, and whether Orca reports the bare
249
253
  login shell as TUI-idle is not verified: if it does, the create stops at once as
250
254
  not mappable to the session; if not, after the 10-minute readiness bound. Either
@@ -67,6 +67,15 @@ Truncations (`.slice`, `.substring`) are decided by what is cut:
67
67
  6. The **hub's own list** cut to N (`pending.slice(0, 64)`, `history.slice(-5)`) is **operational**, and so is a **display cap on the hub's own report** (`pool.walk.length > 16`, `paths.length > 20`, a held-rows cap).
68
68
  7. **Text cut for a log line, notice or reply** is a **safety floor** only when the cut text **originates outside the hub process**: a model, a peer, a person, another project, a native hook process, or a subprocess, network, git or file-parse error that can carry external content. The hub's own composed message, or its own internal error text logged locally, is **operational**. Ask where the text comes from, not where it goes.
69
69
 
70
+ Rulings of #741 (the conductor, 2026-11-06), added after a fresh blind sample (seed 741001) agreed on 70% and the misses fell into six shapes. They extend lines 1 to 7; where one differs, the later line decides its shape:
71
+
72
+ 8. A cap on **the hub's own cache, set, map or concurrency limiter** is **operational**, and so is the line 3 reading of lists, batches and reports. Exception: decide by **what one insert is caused by, not by the name**. A set or map that gains one entry per event **another process controls** (a peer's envelope, a remote room frame, a native hook's tool call, a file a person or agent writes, an acknowledgement a caller names) is a **safety floor**: it bounds memory against outside input. A set the hub fills only from its own decisions (a check run, a launch candidate, an approval, a prepared review) is operational.
73
+ 9. A **silent truncation of a tool argument** (the hub cuts it and goes on, with no refusal) is a **contract** when the limit is stated in that tool's schema (`maxLength` in `hub-tools.ts`) or in `docs/operations.md`; otherwise it is a **safety floor**. The same argument in two tools is decided per tool: `hub_backlog_split` states `title` 300 and `detail` 8000, `hub_task_propose` does not, so its cut is a safety floor.
74
+ 10. **Error or stack text** cut for a log, notice or reply is a **safety floor**, unless the text is a **fixed phrase the hub composed**: then the cut is a display cap and **operational**.
75
+ 11. A cap on **what a read tool returns** (edges, lines, bytes of one result) is a **contract**: it is the documented shape of that result.
76
+ 12. A bound on **a field of a documented message or envelope** (a task handoff key's project id, the `refs.paths` of a deferred envelope, a hub task envelope's `refs.backlog`) is a **contract** under line 1, as is a shortened id or hash (`lease.holder.slice(0, 8)`).
77
+ 13. A bound on something **parsed from git, GitHub or a subprocess** (a path inventory, a control line, a config key listing, a documents list, a tail of runner output) is a **safety floor**: it fails closed against content the hub does not write.
78
+
70
79
  A number is never evidence by itself. Many unrelated schema entries share `32`, `64`, `256` or `4096`, so "the same number appears in `hub-tools.ts`" decides nothing: the first measurement of #739 counted 280 of 378 `src/hub` bounds as mirrors of a schema by number, and only a handful really repeat a tool schema's limit once the call sites are read.
71
80
 
72
81
  ### What the committed file did before this change (measured on `8e44babc`)
@@ -254,4 +263,49 @@ Round 2 clears the 85% bar. It is **in-sample in one respect**: lines 5 to 7 and
254
263
 
255
264
  Round 2's nine misses: three are keys the first list left out (`workflow.ts` criteria 32, criterion refs 8 and `claude-launch-proof.ts` launchId 128, relabelled contract above); `check-runner.ts` `lines.slice(-40)` (a cut of a subprocess's output, which line 7 calls safety floor, labelled by me operational) and `version.stdout.trim().slice(0, 80)` (the converse); `daemon.ts` `schedules pass failed: ...message.slice(0, 160)` and `tasks.ts` `task.title.slice(0, 120)` (a memory title from the task's own title, where whether the origin is outside the hub is a judgement); `execution-budget.ts` `input.id.length > 200` and `delivery-hints.ts` `held.rows.length > 32`. The remaining disagreements are about where text originates, and line 7 is the place to sharpen if a later sample falls short.
256
265
 
257
- No baseline key is labelled in this change. That is #741.
266
+ No baseline key is labelled in this change. That is #741 (below).
267
+
268
+ ## Batch 1 of #741: 149 `src/hub` length bounds (#741)
269
+
270
+ Date: 2026-11-06. Refs #1180. The population is the 187 baseline keys in `src/hub` that are a length or size bound and not a truncation. The 38 left in the baseline are the keys no line decides without a ruling or a caller trace: lower bounds that only say "not empty" or "at least N" (`< 1`, `>= 2`, `< 8`, `before.size < 1`), bounds whose message the key does not name (`daemon.ts` `values.length > 256`, `tool-request.ts` scope and bucket 4096, `operational-view.ts` metadata lists, `specs.ts` `base.length > 200`), research-campaign and experiment bounds in `board.ts` (`owners`, `hostEvidence`, runner receipts), and read-side display caps in `publicReadValue`. A key left here is reported for a ruling, not guessed. Truncations (`.slice`, `.substring`) are batch 2.
271
+
272
+ ### Calibration
273
+
274
+ | Round | Seed | File state | Reader | Agreement | Result |
275
+ | --- | --- | --- | --- | ---: | --- |
276
+ | 1 | 741001 | after #739, lines 1 to 7 | blind reader, lines 1 to 7 | 56 of 80 (70.0%) | below the bar: 24 misses in six shapes (below) |
277
+ | 2 | 741002 | after the 17 relabels below, lines 1 to 13 | blind reader, lines 1 to 13 | 68 of 80 (85.0%) | meets the 85% bar |
278
+
279
+ Both samples are drawn from the decided `src/hub` bounds and truncations (`hub-tools.ts` excluded), without replacement across rounds (round 2 excludes round 1's 80 keys). The reader read each key at its call site with the committed label hidden and wrote every label before scoring.
280
+
281
+ Round 1's misses, by shape: 6 bounds on a message or envelope field the file called safety floor or operational (line 12); 5 bounds on content parsed from git, GitHub or a subprocess (line 13); 4 caches, sets and limiters (line 8); 4 cuts of error or stack text (line 10); 3 silent truncations of a tool argument (line 9); 2 caps on a read tool's output (line 11). The conductor ruled each; the rulings are lines 8 to 13 above.
282
+
283
+ Round 2's 12 misses. Five are **relabelled** in this PR (the rule decides and the file contradicted it, so they follow #739's practice of changing a contradicting entry by name): `plan-conformance.ts` `planPaths.length > 1000` (operational to safety floor, rule 13: it is the same check as `completePlanInventory`, on the plan paths compared with a PR's file list read from GitHub), `usage.ts` transcript size 32 MiB (operational to safety floor, rule 13: it bounds a file a Claude process writes), `github-import.ts` 2 MiB read (operational to safety floor, rule 13: GitHub's output), `deferred-hub.ts` `env.to.length > 256` (safety floor to contract, rule 12: a field of the deferred envelope, like its `refs.paths`) and `deliverable-files.ts` `message.replace(path, "the path").slice(0, 160)` (safety floor to operational, rule 10: a guardPath refusal the hub composed). One is **decided and left**: `delivery-journal.ts` `Object.keys(queues).length > 4096` stays safety floor, because `queues` is a field of the journal snapshot the hub writes and reads back, which no document names, so rule 12 does not apply and rule 13 reads a damaged file as outside content. Six **stay open for batch 2**: `settings.ts` `presetValue` 4096, `dogfood-read.ts` `line.slice(0, 24)`, `claude-launch-proof.ts` `executionCwd` 4096, `board.ts` `failure.head.length > 300`, `code-facts.ts` `a.at.length < 9` and `spec-read.ts` `issues.size > 3`: no line decides them without a ruling.
284
+
285
+ ### Existing labels changed by the rulings (17, by key, old to new; the five round 2 relabels are listed in the round 2 paragraph above)
286
+
287
+ | Rule | Key | Old | New |
288
+ | --- | --- | --- | --- |
289
+ | 8 | `check-runner.ts` `this.entries.size >= 3` (in `start`) | safety floor | operational |
290
+ | 8 | `code-facts.ts` `this.cache.size>128` (in `query`) | safety floor | operational |
291
+ | 8 | `memory-observations.ts` `this.pending.size > 2048` (in `delivery`) | safety floor | operational |
292
+ | 8 | `daemon.ts` `injected.size > 512` (in `readTranscript`, one entry per hook line a native process writes) | operational | safety floor |
293
+ | 8 | `limits.ts` `this.recent.size > 1000` (in `admit`, one entry per distinct message a peer sends) | operational | safety floor |
294
+ | 8 | `daemon.ts` `retainedCliAudits.size > 4096` (in `drainCliAuditsNow`, one entry per audit a CLI process sends) | operational | safety floor |
295
+ | 10 | `daemon.ts` `sanitize(error.message).slice=1000` (in `error`, a fixed Pi version refusal) | safety floor | operational |
296
+ | 12 | `deferred-hub.ts` `refs.paths.length > 256` (in `validateDeferredEnvelope`) | safety floor | contract |
297
+ | 12 | `tasks.ts` `projectId.length > 200` (in `handoffStateByKey`) | safety floor | contract |
298
+ | 12 | `bus.ts` `backlog.length > 64` (in `queuedBacklogIds`) | safety floor | contract |
299
+ | 12 | `daemon.ts` `g.lease.holder.slice=8` (in `goalLine`) | operational | contract |
300
+ | 13 | `plan-conformance.ts` `evidence.paths.length > 1000` (in `completePlanInventory`) | operational | safety floor |
301
+ | 13 | `code-facts.ts` `keys.length>128` (in `nativeEnv`) | operational | safety floor |
302
+ | 13 | `code-facts.ts` `control.length>64` (in an anonymous stream handler) | operational | safety floor |
303
+ | 13 | `sdlc-release-authorization.ts` `value.documents.length > 128` (in `docsVerdict`) | contract | safety floor |
304
+ | 13 | `check-runner.ts` `lines.length > 40` (in `cut`) | operational | safety floor |
305
+ | 13 | `check-runner.ts` `Buffer.byteLength(result) > 4096` (in `cut`) | operational | safety floor |
306
+
307
+ (The 17 are the 15 of the first pass and two found when rule 8 was read by cause. `daemon.ts` `error` is the Pi refusal, a fixed phrase, and the other `sanitize(error.message).slice=1000` keeps safety floor.)
308
+
309
+ ### The 149 keys labelled, by label
310
+
311
+ Each key was read at its call site and decided by the rule named. 25 operational (rule 8 for the hub's own caches and display caps, rule 6 for a hub-built report), 77 safety floor (rule 13 for content parsed from git, GitHub or a subprocess, the config or environment values the hub reads and fails closed on, rule 8 for sets one outside event fills, rule 2 for free text no message defines), 47 contract (rule 1 and 12 for a documented message or envelope field, rule 4 for a documented file the person writes, rule 11 for a read tool's result). The keys are in `scripts/inventory-hardcoded-values.classifications.json`; the baseline file lost exactly those 149 and gained none (1155 to 1006).
@@ -0,0 +1,149 @@
1
+ # 0.32.0 release verification
2
+
3
+ This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.32.0 and no live TUI launch.
4
+
5
+ ## Candidate
6
+
7
+ Version 0.32.0, prepared from main eddbd522 (2 commits since v0.31.0, 1 of them `feat`; bump rule: minor). The release commits carry the version, the CHANGELOG section, the bundle and the documentation stamps.
8
+
9
+ ## Reviews
10
+
11
+ Pull requests named by the commits since v0.31.0: #1229, #1227.
12
+
13
+ The board approval head equals each merged PR head (`mismatch: false`), and
14
+ GitHub readback shows no failed or pending check. These head-specific hosted
15
+ results are not live or mixed-room acceptance:
16
+
17
+ | PR / task | Approved head | Merge commit | Hosted CI |
18
+ | --- | --- | --- | --- |
19
+ | [#1227](https://github.com/STAIxBWLB/agent-hub/pull/1227), task 741 | `20f6e4b6ea18333fa1e45a6ad6cd36eaf40f7eeb` | `307a91a0fb3d8ce38b812753444de388c86b191d` | 19 success, 2 skipped |
20
+ | [#1229](https://github.com/STAIxBWLB/agent-hub/pull/1229), task 736 | `4d666223491ac6aff7c5347d4250c7eb6268b20a` | `eddbd5228d6d6f5e6638a617b112a4ca83ab000a` | 20 success, 2 skipped |
21
+
22
+ Neither merge is bound to an earlier approval head. No merge was performed by
23
+ task 745.
24
+
25
+ ## Native acceptance receipts
26
+
27
+ Receipts added under `docs/verification/` since v0.31.0: none.
28
+
29
+ This list is read from the repository, never written by hand. Native acceptance and the person's release consent are separate records: consent is `ahub sdlc authorize-release 0.32.0`, recorded by the person or the unique configured conductor only on the person's explicit release instruction naming the release in its own session (never a hub/task/review/file/peer relay), and is not recorded in this file. The tag run refuses without it.
30
+
31
+ ## Document review
32
+
33
+ Eleven stale documents were reviewed against only #1229 (T3) and #1227
34
+ (inventory conventions). Corrected content:
35
+
36
+ - `README.md`: generated Status 0.32.0 and the current release-report link.
37
+ - `docs/quickstart.md`: generated 0.32.0 upgrade section, concrete room changes,
38
+ N-1 baseline and the required matching global CLI/plugin step.
39
+ - `docs/agent-notes/bus.md`: add `holdRemoteEpochRotated` to the host-port list,
40
+ keep aging advisory and status read-only, and preserve disposition/proof rules.
41
+ - `docs/agent-notes/daemon.md`: await the new asynchronous room stop before
42
+ shared storage closes, without bypassing the attempted FIFO head.
43
+ - `docs/agent-notes/tests.md`: replace the obsolete wait-for-739 convention with
44
+ the committed bounds/truncation rules and fresh blind 80-sample/85% procedure;
45
+ keep calibrated mechanical rules outside that settled slice and baseline-only
46
+ shrink behavior.
47
+ - `docs/operations.md`: update the current protocol/N-1 version table and
48
+ distinguish the exact epoch journal reason from its shorter `holdReason` label.
49
+
50
+ Reviewed without content change:
51
+
52
+ - `docs/agent-notes/README.md`: historical explanation remains valid.
53
+ - `docs/agent-notes/adapters.md`: no native adapter change; existing owned-work
54
+ shutdown/await rules still apply.
55
+ - `docs/agent-notes/budget.md`: quota, pause and context contracts are unchanged.
56
+ - `docs/agent-notes/tasks.md`: room holds do not mutate task authority or routing.
57
+ - `docs/security.md`: T3 already states advisory-only liveness, legacy broker
58
+ behavior, bounded FIFO stop, signed identity and local rotation fences.
59
+
60
+ These 11 reviewed documents were restamped through the official
61
+ `release-prepare restamp ... --reviewed` path after the reviewed content commit
62
+ `2f4c372a6ce48dc01acb4a002f6a46e9557cbd17`. Following the approved fixture
63
+ exception, the tests note was reviewed again and its final stamp points to
64
+ `4ad77748c96383bdef8e55a11ff53808a1359500`; the other ten retain `2f4c372a`.
65
+ Fresh benchmarks, local-worker, models and help stamps were not refreshed.
66
+ All watched path definitions remain unchanged.
67
+
68
+ ## Checks
69
+
70
+ The official generator was dry-run first, then executed on dgx02 from committed
71
+ `eddbd5228d6d6f5e6638a617b112a4ca83ab000a`, on exact branch `release/0.32.0`,
72
+ after fetching the existing published v0.31.0 tag and a frozen root install.
73
+ Bun 1.4.2 generated the bundle/manifest and the separately retargeted fixture
74
+ lock. Approved artifact-return exception `981f5052` returned only the bundle and
75
+ manifest plus task source/generator outputs and fixture lock; no node_modules,
76
+ target or other build output returned. Producer hashes:
77
+
78
+ - `server.js`: `6f48c2f68e062798eab50b00b14c3319f03f06465f194d8b133f5641607e4bce`.
79
+ - Plugin manifest: `a8c5f3b2295ac58c935eb6df65617dfc887f1fd357cc989ee0400752d8232606`.
80
+ - N-1 `bun.lock`: `de66be194ed847153324d9715422355e0984d49fa7c903ac15451a49db171a91`.
81
+
82
+ npm readback confirms 0.31.0 is the only published 0.31.x patch and pins agent-mem
83
+ 0.21.0. The fixture manifest/matrix now match; protocol floor 0.25.0 is unchanged.
84
+ The initial full run at `a182b06b` exposed a fixture-only positive-host gap:
85
+ the now-retargeted published 0.31.0 plugin already requires native parent-row
86
+ evidence, while the fixture injected it only for current source. The unchanged
87
+ published bundle correctly attached tools-only under the test runner parent.
88
+ Approved exception `67147dad` bootstraps that published import with one exact
89
+ `/bin/ps` raw parent-row observation and delegates every other subprocess call.
90
+ Pinned-runtime inspection showed Bun 1.4.2 does not rebind static builtin named
91
+ exports after a default-export mutation and syncBuiltinESMExports. Approved
92
+ amendment `06f31614` therefore uses Bun's built-in `mock.module` only inside the
93
+ published-leg child for `child_process` and `node:child_process`. Every real
94
+ function is exported; only `spawnSync` gets the same exact ps predicate and
95
+ other calls delegate. It adds no runtime dependency or product change.
96
+ Both fixture forms use the shared synthetic row constant; published bytes,
97
+ classifier, marker, parent check and every assertion/timeout remain unchanged.
98
+ This is synthetic host setup, not real native-launch acceptance. The original
99
+ red run was intentionally stopped after the known setup failure (697 seconds,
100
+ exit 143); it is not a completed full-suite result. Pinned Bun 1.4.2 validation
101
+ of the corrected setup passed as recorded below.
102
+
103
+ At committed `b9c5e1ffb13f0991bfe66b1dd5bcd8621f8538b9`, dgx02 used frozen
104
+ root and published-fixture installs, Bun 1.4.2 and typecheck. The focused actual
105
+ published 0.31.0 client/unchanged plugin and protocol-floor 0.25.0 legs passed
106
+ in both directions, followed by production evidence-classifier tests: 7 pass,
107
+ 0 fail, 79 assertions across two files in 2.09 seconds. These are common-control
108
+ and MCP interoperability results under synthetic native-host observations;
109
+ they are not mixed-room or real-Claude acceptance.
110
+
111
+ The same committed-head run then executed
112
+ `node scripts/check-docs.mjs --require-fresh && scripts/check.sh --changed`.
113
+ The changed gate selected the full suite and passed:
114
+
115
+ ```text
116
+ 12014 pass
117
+ 101 skip
118
+ 0 fail
119
+ 311749 expect() calls
120
+ Ran 12115 tests across 934 files. [2010.22s]
121
+ check: no current-invocation agent-hub daemon leaks
122
+ check: OK
123
+ remote_dev: verify dev/agent-hub/.worktrees/release-0.32.0 b9c5e1ffb13f exit 0 in 2067s
124
+ ```
125
+
126
+ Documentation was fresh with 0 stale documents; roles, inventory (3281 entries,
127
+ 2276 classified, 1005 baseline), bundle freshness and package contents (795 files,
128
+ 0.32.0) passed. The run's total wall time includes the focused leg above.
129
+ This following report-only commit records that completed result; it does not
130
+ inherit a new full-suite claim for itself. Final-head documentation/delta checks
131
+ and hosted CI are recorded in the PR, and exact-head CI remains the merge gate.
132
+
133
+ ## Known gaps, not blocking
134
+
135
+ - No installation, running-hub upgrade, real account, live TLS/proxy or two-machine
136
+ room run is performed by this preparation. No mixed published-version room
137
+ execution is claimed: the N-1 room directions in CHANGELOG follow unchanged
138
+ codecs/source comparison and isolated current-version broker tests.
139
+ - An offline stop snapshot is a bounded attempt behind the existing FIFO head,
140
+ not a guarantee under backpressure. Legacy brokers without ephemeral support
141
+ do not refresh or age; upgrade the broker for that liveness behavior.
142
+ - A 0.31.0 CLI drops additive advisory/hold fields and outstanding preview IDs,
143
+ including in JSON. A 0.32.0 client accepts absent metadata from a 0.31.0 daemon
144
+ and keeps its prior state-only/fingerprint-confirmation behavior. New displays
145
+ require the matching CLI and daemon.
146
+ - #1204 remains open for T4 visibility, deferred-inbound wake and full codec
147
+ features. #1173 still waits for supported activation/fresh host attestation in
148
+ agent-mem#281. Existing live gates for #1053, #1056 and #1196 remain separate.
149
+ - No merge, tag, npm publication or release-consent record is made by this task.