@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.
- package/CHANGELOG.md +33 -0
- package/README.md +2 -2
- package/docs/agent-notes/bus.md +3 -1
- package/docs/agent-notes/daemon.md +1 -0
- package/docs/agent-notes/tests.md +2 -2
- package/docs/design/bus.md +109 -4
- package/docs/dogfood.md +2 -0
- package/docs/memory.md +9 -3
- package/docs/operations.md +98 -17
- package/docs/quickstart.md +18 -2
- package/docs/security.md +52 -9
- package/docs/specs/2026-09-19-agent-hub-design.md +75 -5
- package/docs/specs/2026-09-20-upgrade-recovery-design.md +7 -3
- package/docs/verification/2026-11-05-hardcoded-values-classification-rules.md +55 -1
- package/docs/verification/2026-11-06-0.32.0.md +149 -0
- package/docs/verification/2026-11-06-0.33.0.md +222 -0
- package/docs/verification/2026-11-06-claude-implementer-2.1.319.md +57 -0
- package/docs/verification/2026-11-06-codex-0167-reviewer-isolation.md +56 -0
- package/docs/verification/2026-11-06-codex-0167-reviewer-tool-call.md +66 -0
- package/docs/verification/2026-11-06-kimi-251-reviewer-compat.md +88 -0
- package/docs/verification/2026-11-06-orca-1.4.250-cli-contract.md +50 -0
- package/docs/verification/2026-11-06-qwen-0268-acp.md +75 -0
- package/docs/verification/2026-11-06-qwen-0268-dual-output.md +44 -0
- package/docs/verification/claude-shell-wrapper-native.py +1 -1
- package/docs/verified.json +11 -11
- package/package.json +2 -2
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +528 -206
- package/src/adapters/compat.ts +11 -11
- package/src/broker/protocol.ts +5 -0
- package/src/broker/server.ts +54 -4
- package/src/broker/store.ts +6 -3
- package/src/cli/console-state.ts +1 -1
- package/src/cli/output.ts +5 -1
- package/src/cli/room.ts +34 -12
- package/src/cli/status-lines.ts +8 -1
- package/src/cli/terminal-recovery.ts +37 -15
- package/src/hub/bus.ts +25 -0
- package/src/hub/daemon.ts +20 -9
- package/src/rooms/application.ts +15 -0
- package/src/rooms/commands.ts +135 -30
- package/src/rooms/health.ts +32 -0
- package/src/rooms/link.ts +394 -56
- package/src/rooms/liveness.ts +11 -0
- package/src/rooms/remote-peer.ts +18 -3
- package/src/rooms/service.ts +167 -28
- package/src/rooms/status.ts +65 -2
- package/src/rooms/store.ts +30 -1
- package/src/rooms/wire.ts +10 -8
- package/src/ui/index.html +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ Issue and pull request numbers in the entries for 0.7.7 and earlier refer to the
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.33.0
|
|
8
|
+
|
|
9
|
+
- Exact-pin the first-party agent-mem core to 0.22.1 (PR #1243, task 754). It includes the upstream strict-host TOML serialization fix and adds no runtime dependency. Placement activation and writer renewal remain opt-in person commands; a pin upgrade does not activate a home or add the hub's missing fresh placement-attestation integration.
|
|
10
|
+
- Correct inactive-placement CLI/dashboard guidance and memory documentation (PR #1244, task 755): the native person-only `amem migrate --sync-placement --dry-run` preview exists and requires every writer through `--writer-root`. The hub still does not supply fresh `placementAttestation` for active-placement sync (#1173); `ahub memory declined` remains the safe inspection step. No activation or API adoption is performed.
|
|
11
|
+
- Rooms expose retained refusal counts, outbox depth/ages, last receipt age and closed link causes with recovery steps (#1204 T4, PR #1237, task 737). Store opening failures retry with bounded backoff, verified journal recovery wakes deferred inbound work, and selective three-member traffic raises no false sequence-gap notice. Codec support is signed current-session compatibility evidence; pending observations keep the original queue expiry and known unsupported feature sends refuse before effects. Plain chat and existing permission, privacy, replay and person-disposition fences remain unchanged. PR #1241 (task 753) documents the rolling-upgrade order and simplifies status projections without behavior changes.
|
|
12
|
+
- Orca terminal recovery recognizes `terminal_exited`, `terminal_gone` and `no_connected_pty` alongside the existing stale-handle code, and preserves Orca's structured error code in failures (#1233, PR #1235, task 746). A missing terminal still follows the existing launcher ownership and reopen checks.
|
|
13
|
+
- Record the single authorized Codex 0.167.0 reviewer tool-call attempt (Refs #888, task 751): startup isolation and the rendered marker precondition passed, but the harness readiness/readback leg did not produce a complete verdict result. No retry; 0.167.0 remains unverified (`docs/verification/2026-11-06-codex-0167-reviewer-tool-call.md`).
|
|
14
|
+
- Verify exactly Qwen ACP 0.26.8 with model-free native macOS arm64 initialization, session, mode and published permission-handler receipts, plus Linux x86_64 evidence (#888, task 749). Qwen dual-output 0.26.8 stays unqualified: required queued-submit Q2 fails identically on the matched 0.26.1 control; its verified entry stays at 0.26.1. Real account/model behavior remains unverified.
|
|
15
|
+
- Kimi Code 2.5.1 is an exact receipt-verified fresh-reviewer version (#888, task 748): the official macOS arm64 artifact passes the production preparation and native two-tool/Write controls in fixture-trust and verified/no-trust runs (`docs/verification/2026-11-06-kimi-251-reviewer-compat.md`). Runtime preparation remains required; real account, model and quota behavior remain unverified.
|
|
16
|
+
- Claude Code 2.1.319 is a receipt-verified headless implementer version (#888, task 750): the model-free permission-transport and host shell-wrapper producers pass on it with 2.1.318 as the control (`docs/verification/2026-11-06-claude-implementer-2.1.319.md`).
|
|
17
|
+
- Codex 0.167.0 passed the model-free reviewer isolation procedure (#888, task 747): all four legs passed with 0.166.0 as the control (`docs/verification/2026-11-06-codex-0167-reviewer-isolation.md`). This is model-free evidence only; the single authorized tool-call attempt above ended with an unknown outcome, so 0.167.0 stays unverified and any new attempt needs fresh person authorization. The person can explicitly trust that version, but every runtime proof still runs. Verified stays 0.146.0, 0.163.0, 0.164.0 and 0.166.0.
|
|
18
|
+
|
|
19
|
+
- 0.33.0 N-1: published 0.32.0, the latest 0.32.x patch, pins agent-mem 0.21.0; this hub pins agent-mem 0.22.1. Control remains protocol 17 (descriptor floor 16). The release N-1 fixture and matrix retain published 0.32.0/core 0.21.0; the separate protocol-16 fixture stays 0.25.0.
|
|
20
|
+
- Room wire: 0.33.0 keeps `x-agent-hub-ephemeral: 1` and adds a separate `x-agent-hub-codecs: 1` upgrade header. A released 0.32.0 broker ignores the latter and retains ephemeral presence/liveness. A 0.32.0 member on a 0.33.0 broker receives its unchanged legacy ready/presence grammar, never codec advertisements or inventories. Plain v1 chat works in both directions.
|
|
21
|
+
- Rolling upgrade: a 0.33.0 person-inbox (`user@label`) or invocation send to a 0.32.0 member, or between upgraded hubs through a 0.32.0 broker, is refused before any effect with the upgrade step. Upgrade the broker, then every member to a codec-capable release, then reconnect. A merely pending observation waits under the original queue expiry; no timer grants support. Codec evidence grants no native, exposure, privacy or task authority.
|
|
22
|
+
- CLI/status: the 0.32.0 `ahub room status` command drops additive health, closed cause and generated action fields, including in its JSON output; its generic `ahub status --json` instead passes raw daemon fields through unchanged. A 0.33.0 room-status client accepts missing diagnostics from an older daemon as unknown. The sequence-gap operator notice is removed; the signed room-wide sequence and permanent replay floors are unchanged.
|
|
23
|
+
- Shared memory home: agent-mem 0.22.x's own N-1 statement keeps curated, capture, hook-spool, candidates, work-list and setup-receipt formats, `INDEX_VERSION` and the index file name unchanged from 0.21.0. Shared-v1, generation and v1/v2 shard sync are unchanged; inactive homes behave as before. Placement activation and writer renewal are opt-in person commands. If renewal history is present, the 0.21.0 closed journal reader refuses that history and placement publication before effects. The person coordinates shared-home operations separately after release; this preparation performs none of them.
|
|
24
|
+
- Local compatibility: hub.db remains schema 2 and RoomStore remains schema 5. The current core is 0.22.1 while N-1's is 0.21.0, with the shared-home limits above. The Orca recovery correction and exact compat additions change neither the control protocol nor native authorization; Codex reviewer 0.167.0 and Qwen dual-output 0.26.8 remain unqualified.
|
|
25
|
+
- Evidence ceiling: the N-1 fixture uses the unmodified published 0.32.0 package for control/plugin and isolated broker/member tests. These source/fixture claims do not establish real-account inference, live TLS/proxy behavior, installation or two-machine operation; the release verification report records execution results separately.
|
|
26
|
+
|
|
27
|
+
## 0.32.0
|
|
28
|
+
|
|
29
|
+
- Rooms gain advisory liveness and person-visible epoch changes (T3 of #1204, task 736). An ephemeral-capable broker enables 30-second presence refresh and unknown status after three missed periods; aging never changes sending authority. Graceful stop fences new work and attempts a signed offline snapshot within two seconds without overtaking an attempted FIFO head. Legacy brokers report liveness untracked with an upgrade step. Epoch-changing commands preview sealed outstanding delivery IDs, recheck the exact set and roster, and immediately hold old-epoch work as needs_review with the cause "epoch rotated". Bus-only work and person/terminal dispositions are preserved; T4 remains open.
|
|
30
|
+
- Classify 149 more baseline keys of the hard-coded values inventory, the `src/hub` length bounds (#741 batch 1, refs #1180): 25 operational, 77 safety floor, 47 contract. A fresh blind sample first scored 70%, six rulings (docs/verification/2026-11-05-hardcoded-values-classification-rules.md, lines 8 to 13) and 17 relabels followed, and a second sample scored 85%. The baseline shrinks from 1155 to 1006 keys; `--check` passes.
|
|
31
|
+
|
|
32
|
+
- 0.32.0 N-1: published 0.31.0, the latest 0.31.x patch, with agent-mem 0.21.0 and protocol 17. The release N-1 fixture and matrix now pin it; the separate protocol-16 fixture stays 0.25.0.
|
|
33
|
+
- Wire/protocol: control remains 16 through 17 and room presence stays v1. A 0.31.0 hub already opts into advertised ephemeral support and understands requestReply and signed offline. With a supporting broker, 0.32.0 requests a signed observation every 30 seconds and 0.31.0 can answer it. A delivered 0.32.0 graceful-stop snapshot is understood by 0.31.0. A 0.31.0 stop has no final offline snapshot, so 0.32.0 relies on its three-period advisory aging; 0.31.0 adds no aging of its own and retains its state-only view. A broker without ephemeral advertisement disables periodic refresh and aging on 0.32.0 and is shown as liveness untracked, with an upgrade step.
|
|
34
|
+
- Local semantics: only 0.32.0 adds advisory unknown display, pending-ID previews and immediate epoch-rotated holds. Aging never changes native PeerState, outbound admissibility or authority. Existing signed roster, exposure, link, Bus proofs, person dispositions and codec checks remain. An epoch hold is local metadata, not a new remote control, cancellation, completion or receipt reason; a 0.31.0 member retains its own epoch-settlement behavior.
|
|
35
|
+
- Files and floors: hub.db remains schema version 2, RoomStore remains schema 5 and the exact agent-mem pin stays 0.21.0. Epoch adoption uses existing needs_review/boundary_refused storage states and does not raise a format floor. The new hold label is a local status projection, not a new room receipt reason.
|
|
36
|
+
- CLI/status: a 0.31.0 client talking to a 0.32.0 daemon drops additive presence/liveness/holdReason fields, including in JSON, and does not display outstanding preview IDs. A 0.32.0 client accepts their absence from a 0.31.0 daemon and keeps its state-only view and existing fingerprint confirmation. New liveness and pending-ID displays require the matching 0.32.0 CLI; existing server ticket checks remain in effect.
|
|
37
|
+
- MCP tools: schemas and capability checks are unchanged from 0.31.0; no new peer tool or native authority follows from T3 liveness or epoch metadata. Full room codec-feature negotiation remains T4.
|
|
38
|
+
- Evidence ceiling: room directions above follow source comparison and isolated current-version broker fixtures. They do not claim a mixed published-version room execution, guaranteed offline-frame delivery under backpressure, live TLS/proxy behavior or two-machine acceptance. Published-package common-control interoperability is recorded separately by the retargeted fixture gate.
|
|
39
|
+
|
|
7
40
|
## 0.31.0
|
|
8
41
|
|
|
9
42
|
- Delivery failures carry one bounded diagnostic cause: peer offline, adapter refused, push error, turn aborted or timeout (#1178, PR #1224, task 714). `ahub queue show` and JSON listings expose it without message text; legacy rows say when no cause was recorded. Status shows each peer's unresolved failed count and the discard next step, excluding explicitly resolved rows; inspect the causes with `ahub queue list` or `show`. Causes do not authorize replay or alter settlement.
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Code, Codex, Kimi Code, Pi and a hub-owned local worker (plus Qwen Code, Jcode a
|
|
|
5
5
|
Antigravity if you want them) share a message bus, a task board and a memory, each
|
|
6
6
|
connected through its own native interface.
|
|
7
7
|
|
|
8
|
-
Status: 0.
|
|
8
|
+
Status: 0.33.0, control protocol 17 (accepts 16). Bun + TypeScript, one loopback daemon per
|
|
9
9
|
project. Site: [agent-hub.staix.net](https://agent-hub.staix.net).
|
|
10
10
|
|
|
11
11
|
## Quick start
|
|
@@ -143,7 +143,7 @@ uses the home must run a version that understands the new layout.
|
|
|
143
143
|
[#258](https://github.com/STAIxBWLB/agent-hub/issues/258)).
|
|
144
144
|
|
|
145
145
|
Live checks that still need a real account or a person are listed in the
|
|
146
|
-
[release verification report](docs/verification/2026-11-
|
|
146
|
+
[release verification report](docs/verification/2026-11-06-0.33.0.md) and the
|
|
147
147
|
[smoke checklist](docs/smoke.md).
|
|
148
148
|
|
|
149
149
|
## Documentation
|
package/docs/agent-notes/bus.md
CHANGED
|
@@ -48,5 +48,7 @@ Scope: delivery, digests and condensation, reply addressing, priority and limits
|
|
|
48
48
|
- `resolveDelivery` (#713): a `queued` delivery was never handed to the peer, and a `failed` one was refused before it ran (#1103), so a busy peer blocks discarding neither; `dispatching` stays refused as `active delivery`, and so does `accepted` except for its own explicit channel's completed/discard (#1172, below); unrelated resolutions keep the busy fence. Only the recipient may explicitly complete/discard its own `needs_review` row, or for a peer with `acceptedSettlement: "explicit"` its own `accepted` row, through `resolveOwnDelivery` with an observed revision and reason (#1079), recording the peer actor through the existing journal audit. Another peer, remote-room disposition and active dispatching/accepted row refuse; this never replays the originals. Every other operator resolution stays fenced while busy. `resolveOwnDelivery` refuses with its own `PreEffectToolRefusal`, which names the cause and the next step, never through `resolutionRefusal`. A row that carries an invocation stays person-only (#1112). The daemon names the refusal from a closed list (`resolutionRefusal`), never from free error text. `queue discard --peer` goes through `resolveDelivery` row by row, reading each row's current revision just before its discard, never the revision listed at the start. Without `--state` it takes the peer's `queued` rows and its unsettled `failed` rows (wire `states`, sent only to a hub whose `features` list `queue_discard_states`; `needs_review` still needs an explicit `--state`). A row a resolution already settled (`settledIds()`) is history: `queue list` hides it unless `all`, and resolving it again is refused as `already resolved by <action>`, never `stale revision` (#1098, #1103).
|
|
49
49
|
- Accepted channel deliveries (#1172): an `accepted` receipt means the channel transport took the notification, never that the session handled it. `expireAcceptedDeliveries`, run from the daemon's 5 s invocation sweep with the host-only `DaemonOptions.acceptedSettlementNow` clock, moves an explicit channel's `accepted` row older than `bus.accepted_settle_ms` (`acceptedSettleMs`, default 10 min) to `needs_review` with `ACCEPTED_SETTLE_TIMEOUT_REASON` under a revision fence. It holds the peer, routes an invocation through `onInvocationUncertain` and never replays. A repeated `accepted` receipt never renews the deadline. `settleSupersededDeliveries` and supervision skip timeout rows; an important, task or review timeout gets one ids-only conductor status notice unless `conductor.feed` is `off`. The explicit channel's `inbox` reply, a refused one included, carries `held` metadata for its own accepted and `needs_review` rows (`heldDeliveryHints(peer, true)`), or `{ unavailable: true }`, never an empty claim.
|
|
50
50
|
- Review provenance (#1056): `reviewResponse` runs on every publish (`publishResult` and the daemon's channel `send`). It strips a caller's `refs.reviewPackage`/`refs.reviewResponse` and stamps a host-derived `reviewResponse` only on a chat or status that answers a review-scoped parent (`lastDelivery`, `lastPulled`, the bounded `reviewParents`, or `reviewObserverScope`, whose failure counts as scoped); never trust a peer's marker or match content. `beforeReviewInputHandoff` runs before every native handoff (steer, drain, pull); a throw leaves the work queued as `ReviewInputHandoffError` and is never a storage error. `publishReviewEnvelope` republishes a saved package only when `reviewEnvelopeStatus` is `absent`, refuses `failed`, `discarded` and `unknown`, and never replays a published one. Terminal pruning keeps hub review-package rows (`refs.reviewPackage` `review-*`). The bus constructor restores from `transportSnapshot()`; only recovery uses the strict `snapshot()`, which refuses malformed review provenance.
|
|
51
|
-
- Room delivery rows (#1204): a remote (`remoteId`) `needs_review` row holds its peer only when it carries an invocation; an ordinary room chat uncertainty never blocks later queued work. Settle, requeue, hold or resume a remote row only through the room adapter's host ports (`settleRemoteReceipt`, `requeueRemoteNotSent`, `holdRemoteMissingIntent`, `holdInvalidatedRemoteOutcome`, `resumeRemotePending`). Each is bound to the current adapter, room and member, revision-fenced and refused after a person disposition. `deliveryReceipt` never calls `completeDelivered` or `deliveryFailed` for a remote peer, and an uncertain invocation stays person-only. At journal open, `recoverInterrupted` keeps an active single-envelope, non-invocation remote row active only while the bus snapshot still holds its room, member and an unexpired queue deadline; every other `dispatching`/`accepted` row becomes `needs_review`.
|
|
51
|
+
- Room delivery rows (#1204): a remote (`remoteId`) `needs_review` row holds its peer only when it carries an invocation; an ordinary room chat uncertainty never blocks later queued work. Settle, requeue, hold or resume a remote row only through the room adapter's host ports (`settleRemoteReceipt`, `requeueRemoteNotSent`, `holdRemoteMissingIntent`, `holdInvalidatedRemoteOutcome`, `holdRemoteEpochRotated`, `resumeRemotePending`). Each is bound to the current adapter, room and member, revision-fenced and refused after a person disposition. `deliveryReceipt` never calls `completeDelivered` or `deliveryFailed` for a remote peer, and an uncertain invocation stays person-only. At journal open, `recoverInterrupted` keeps an active single-envelope, non-invocation remote row active only while the bus snapshot still holds its room, member and an unexpired queue deadline; every other `dispatching`/`accepted` row becomes `needs_review`.
|
|
52
52
|
- Closed publication (#1222): once the `Bus` is closed, `publish` returns `{ targets: [] }` before touching the journal or observers, so a late room or presence publication after shutdown writes nothing; a live storage error still propagates. Keep the closed check first when you touch the publish path.
|
|
53
|
+
|
|
54
|
+
- Room liveness (#1204 T3): keep expired or unavailable observation time as advisory `presence: "unknown"` only; never use aging to change native `PeerState`, outbound admissibility or authority. Keep status reads free of clock and delivery mutations. An epoch change uses `holdRemoteEpochRotated` only for the captured sealed intents under current room/member proof; preserve person dispositions and never interpret the hold as completion, cancellation or replay. Read `docs/design/bus.md` "Room liveness and epoch changes" before changing these paths.
|
|
@@ -141,6 +141,7 @@ Scope: the operator console, control WS and its protocol, state files, the dashb
|
|
|
141
141
|
|
|
142
142
|
- Channel tool-result hints (#493, #221): `withPendingHint` (`src/adapters/claude-channel.ts`) appends fresh `delivery_holds` counts, and drops the "call hub_inbox" advice whenever the same reply carries a held-delivery hint, because `bus.pull` refuses under that hold and the advice would send the session into a refused read. A `hub_inbox` result that already says how many messages remain unread adds only the important count, never a second queued count. A `hub_inbox` result that renders its own held or accepted metadata (`HELD_HINT_INCLUDED`) gets no second held hint and no polling advice, and unavailable metadata adds the inspect step instead of "Nothing is waiting" (#1172). Do not add a Claude client-version gate on steer without a probe of the older client and an optional hello field that carries the version (background: README).
|
|
143
143
|
- Memory sync (#438): stop an in-flight `syncMemory` only through `syncStop` (`src/hub/daemon.ts`), and await `syncRun` before the memory store closes, as `stopOnce` does. agent-mem runs the sync's git in its own process group, so a process that ends without `daemon.stop()` leaves that git and its transport child holding the memory repository. A signal the hub exits on goes through lifecycle stop (`STOP_SIGNALS` in `src/hub/lifecycle.ts`: SIGINT, SIGTERM, SIGHUP, SIGQUIT), never the default action; SIGQUIT in particular must not reach its default core dump (Bun honours it: agent-mem #435 measured a 5.9 GB core file and a delayed exit). The forced exit after the shutdown deadline stays `process.exit`. A sync result is logged as a failure only when `quietSyncError` is false: a missing remote in either agent-mem wording (`no sync remote`, `no generation sync remote configured`) and a stop are not failures (#401); a new agent-mem wording for them extends that one predicate. Every pass gets the host screen and policy version (`currentMemorySyncPolicy`, `memorySyncPolicyVersion`, #1173); a version change during the pass records `binding`, never success. Record outcomes only through `reduceMemorySync` and publish them only as `memorySyncView` (`sync` in memory status: closed cause, counts, next step). The log line names the closed cause (`classifyMemorySyncFailure`), never the raw error text. `DaemonOptions.memorySyncTrigger` is a host-only fixture seam.
|
|
144
|
+
- Room shutdown (#1204 T3): `RoomCommands.stop()` fences new room work synchronously and returns a promise. Await it in `stopOnce` before closing shared storage: it waits for pending room work and each link's bounded offline-presence attempt before closing RoomStore. Preserve an attempted FIFO head and consume shutdown storage controls without admitting new presence or application work.
|
|
144
145
|
- Schedules timer (#512a): `schedulesTimer` in `startDaemon` is its own interval, apart from the task sweep's, armed whenever `config.schedules` or `config.folder_triggers` is non-empty and re-armed in `reloadConfig` on a change to either; never gate it on `task_sweep.enabled`. `schedules` is machine-local (`MACHINE_LOCAL`) and never editable from settings (`NEVER_EDITABLE`): a committed file or a settings write must not be able to make the hub create tasks. The daemon status carries `schedules` (`scheduleViews`) only when some are configured.
|
|
145
146
|
- Anything the daemon starts on a timer and registers only with `startupCleanup` is not stopped by a normal `stop()`: `startupCleanup` runs on a failed startup only. Clear the timer and close the store in `stopOnce`, and wait for a pass in flight before the board closes (`schedulesPass`, #512a). A console op that runs the same writer on demand (`schedule_run`, #335) joins that wait through `manualSchedulePasses`; add any new on-demand entry to it, or `stopOnce` closes the board and the store under it.
|
|
146
147
|
- Corpus (#510a, `src/hub/corpus.ts`, `corpus-config.ts`): `corpus.paths` is machine-local and `corpus` is never editable from settings. Keep `corpus-config.ts` free of file-system imports, because the config schema (`config-apply.ts`) reaches the Claude channel bundle. A refusal of a root is a reason string, never a thrown error and never a partial read: evidence the check cannot read refuses, and only a completed read certifies a folder. The vault check is `.obsidian` at the real root, in every ancestor and anywhere below (any entry of that name), always on the `realPath`. A folder the pii, deny or local.deny rules protect is never listed, so it cannot be shown vault-free: the root that holds it is refused, never certified with that subtree skipped (a protected file is only skipped).
|
|
@@ -12,7 +12,7 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
|
|
|
12
12
|
- A test timeout that fires while `Bun.spawnSync` runs can start the next test inside spawnSync's own event loop (Bun 1.3.14 and 1.4.2; background: README). `scripts/check.sh` runs tests with a 20 s timeout and under `scripts/hang-watch.sh`; a test that spawns and reads the process table gets a timeout of its own, never above 20 s: an explicit larger timeout overrides the gate's `--timeout 20000`, so shorten the scenario instead.
|
|
13
13
|
- Sandboxed commands and the MLX server get a fixed environment (`PATH`, `HOME` and their own keys), so test knobs for their fakes travel in a wrapper script or argv, not in `process.env`. Daemon-owned peer children use `peerChildEnv`, which drops `ORCA_*` and replaces agent identity markers; a person-owned native launch preserves only its own pane's `ORCA_*` context while dropping inherited agent identity.
|
|
14
14
|
- Bind agent identity markers explicitly in native/CLI fixture children. The full gate starts the test runner without inherited agent markers (including `AGENTHUB_DELIVERY_ONLY`) and without an `ahub claude` session's hub variables (`AGENTHUB_PROJECT_DIR`, `AGENTHUB_STATE_DIR`, `AGENTHUB_INSTANCE_ID`, `AGENTHUB_LAUNCH_ID`); a new variable a native session exports and a fixture child reads joins that `env -u` list in `scripts/check.sh`. Never weaken production marker detection to make them pass.
|
|
15
|
-
- A fixture that spawns the real channel plugin (`src/adapters/claude-channel.ts` or `plugins/agent-hub/server.js`) to act as a peer runs it with `cwd` at the hub's project root, made with `realPath` (the macOS temp dir is a symlink). The plugin chooses its hub through `channelProject` (rule: `daemon.md`), so from another cwd it joins the wrong hub, joins as a distinct session or connects nowhere. Only tools mode with both `AGENTHUB_STATE_DIR` and `AGENTHUB_PROJECT_DIR` set skips that check. A fixture whose plugin must push as a channel (not fall back to tools mode) injects the parent row with `syntheticClaudeParentEvidenceSetup()` (`test/fakes/claude-channel-parent.ts`, #1171), which replaces only `claudeParentCommandPort.read`; the production marker and classifier still run, so never stub `classifyClaudeParentCommand` or skip the evidence check. A second opted-in session attached while a fixture owner holds the peer stays a standby (#1174): close the owner and wait for offline before attaching the session under test (`test/channel-inbox-daemon.test.ts`).
|
|
15
|
+
- A fixture that spawns the real channel plugin (`src/adapters/claude-channel.ts` or `plugins/agent-hub/server.js`) to act as a peer runs it with `cwd` at the hub's project root, made with `realPath` (the macOS temp dir is a symlink). The plugin chooses its hub through `channelProject` (rule: `daemon.md`), so from another cwd it joins the wrong hub, joins as a distinct session or connects nowhere. Only tools mode with both `AGENTHUB_STATE_DIR` and `AGENTHUB_PROJECT_DIR` set skips that check. A fixture whose plugin must push as a channel (not fall back to tools mode) injects the parent row with `syntheticClaudeParentEvidenceSetup()` (`test/fakes/claude-channel-parent.ts`, #1171), which replaces only `claudeParentCommandPort.read`; the production marker and classifier still run, so never stub `classifyClaudeParentCommand` or skip the evidence check. For an unchanged published bundle with an inlined observer port, use the published-leg raw port-fact injection in `test/published-protocol-compat.test.ts`: bootstrap its import with Bun's built-in `mock.module` only for `child_process` and `node:child_process`, export the real functions and replace only `spawnSync` for `/bin/ps -ww -p <direct-parent-pid> -o command=`. Return `SYNTHETIC_CLAUDE_PARENT_COMMAND` from the same fixture helper and delegate every other call. Preserve the bundle bytes, classifier, inherited marker, parent-identity check, assertions and timeouts. This synthetic host observation is not native-launch acceptance. A second opted-in session attached while a fixture owner holds the peer stays a standby (#1174): close the owner and wait for offline before attaching the session under test (`test/channel-inbox-daemon.test.ts`).
|
|
16
16
|
- Orca environment (#613, #1048): the `test/hub-home.ts` preload also deletes every inherited `ORCA_*` variable, and `scripts/check.sh` unsets them before `bun test`. A run from an Orca pane otherwise reaches the person's Orca through `ORCA_WORKTREE_ID`, `ORCA_TERMINAL_HANDLE` and `ORCA_CLI_COMMAND` (the launcher's four names are `ORCA_LAUNCHER_ENV` in `src/hub/orca-env.ts`, the one list; `personEnv` drops the whole prefix) and opens real tabs and agents there. A test that needs one sets it itself after the preload and restores it; a test of the launcher uses a stub `ORCA_CLI_COMMAND` and never the real one. `test/orca-env-guard.test.ts` runs a real `ahub up` with fake values and a recording stub and must see zero calls.
|
|
17
17
|
- `bunfig.toml` preloads `test/hub-home.ts`, which first clears inherited `AMEM_HOME`, gives every test run (the gate and `bun test <file>` alike) a temp `AGENTHUB_HOME` unless one is set, and always replaces `KIMI_CODE_HOME` with a temp dir, an inherited value included (#285); scoped tests may set their own `AMEM_HOME` or `KIMI_CODE_HOME` after preload. Hub memory (#258) is on with any project config, and no test may write the person's `~/.agenthub`. Do not remove it; a test that needs its own home sets and restores the variable. The preload keeps an inherited `AGENTHUB_HOME`, which an agent shell exports as the person's hub home and `scripts/check.sh` does not unset: run `bun test` and the gate with `env -u AGENTHUB_HOME`.
|
|
18
18
|
- `test/registry-guard.test.ts` statically scans `src/` against the committed `test/registry-guard.baseline.json` (#451); a test never writes, regenerates or repairs that baseline, and a failing guard is fixed in the source by moving the policy into a definition (rule: `docs/agent-notes/adapters.md`); the baseline stays `[]`. Scanner behavior is pinned on inline sources in `test/registry-guard-fixtures.test.ts`, never on edits to real files. A new table, hint or flag list in generic code that names a peer (`"pi"`, `isJcodePeer`) is a new group: derive it from the definitions instead (`ADAPTERS.filter(...)`, a port such as `statusNotice`). Missed twice on 2026-11-02 (PR #1093 `jcodeTuiHint`, PR #1100 `INIT_SETTINGS`), both found only by CI's shard 3; run `scripts/check.sh --changed` or `bun test --timeout 20000 test/registry-guard.test.ts` before pushing a new peer-shaped table (a bare `bun test` times out at 5 s on this file).
|
|
@@ -58,4 +58,4 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
|
|
|
58
58
|
- A test of `scripts/release-prepare.ts` or `scripts/release-tag.ts` runs the script with its root in a scratch repository whose only remote is a local bare directory: set `AHUB_RELEASE_ROOT` to it, or copy the script into it as `test/release-tag-daemon.test.ts` does. Without that the script takes its root from its own location and fetches and runs `ls-remote` against this checkout's real origin. Consent comes from a fake port, a stand-in `AHUB_CLI` or a scratch daemon, never the person's hub.
|
|
59
59
|
- Production `MemoryClient` (`src/memory/client.ts`) is the in-process amem store and never opens `memory.worker_url` (#752). A test that needs the legacy worker shape injects `FakeMemoryClient` (`test/fakes/mem-worker.ts`) as `DaemonOptions.memoryClient` or in place of the client; never add an HTTP path to the production client for a test. An amem-backed test sets its own temp `AMEM_HOME` and reads only its own fixture memory directory.
|
|
60
60
|
- CLI print guards (#814, `test/cli-json-guard.test.ts`): two scans over every file in `src/cli`. One finds `console.log(JSON.stringify(...))` and passes only behind a `--json` branch (`selectsJson`) or a named `DATA_FORMAT` entry (`NOT_YET_CONVERTED` is empty since #899; keep it empty). The other finds a print of a hub tool's text (`console.log(await taskOp(<op>))`, or a variable bound from one) and passes only behind `--json`, for a named `SENTENCE_OPS` op (checked against the daemon's case), or named debt (`TEXT_DEBT`, `CONDUCTOR_DEBT`, `REFUSAL_FALLBACK`). A list entry with no matching site fails, so the lists only shrink. Add a command's `--json` branch or renderer; never add a list entry to make a new print pass. Per-command output tests (`test/task-output.test.ts`, `test/sdlc-output.test.ts`) run the real CLI against a fake control server and assert default not JSON, `--json` byte equality, 80 and 200 columns and `--color=never`.
|
|
61
|
-
- Hard-coded values inventory (#719, #1180, `scripts/inventory-hardcoded-values.ts --check`, a once-only step of `scripts/check.sh`): a constant or inline literal you add to `src/` or `scripts/` is an inventory entry, and the gate fails until it is classified in `scripts/inventory-hardcoded-values.classifications.json` (`operational`, `safety floor`, `contract` or `test seam`, by the reasons of `docs/verification/2026-10-30-operational-settings-closure.md`). Never add a key to `scripts/inventory-hardcoded-values.baseline.json`: it is the list of keys that were unclassified when the check began and it only shrinks. Classify a baseline key by adding it to the classifications file and deleting it from the baseline in the same commit; the check refuses either half alone.
|
|
61
|
+
- Hard-coded values inventory (#719, #1180, `scripts/inventory-hardcoded-values.ts --check`, a once-only step of `scripts/check.sh`): a constant or inline literal you add to `src/` or `scripts/` is an inventory entry, and the gate fails until it is classified in `scripts/inventory-hardcoded-values.classifications.json` (`operational`, `safety floor`, `contract` or `test seam`, by the reasons of `docs/verification/2026-10-30-operational-settings-closure.md`). Never add a key to `scripts/inventory-hardcoded-values.baseline.json`: it is the list of keys that were unclassified when the check began and it only shrinks. Classify a baseline key by adding it to the classifications file and deleting it from the baseline in the same commit; the check refuses either half alone. For `src/hub` bounds and truncations, apply the committed conventions and rulings in `docs/verification/2026-11-05-hardcoded-values-classification-rules.md` (#739/#741). Before each batch, run a fresh blind sample of 80 already-decided entries and proceed only at 85% agreement or more. Outside that settled slice, a baseline key needs a calibrated mechanical rule that the committed file agrees with on at least 94% of its decided keys; leave an undecided shape in the baseline pending a ruling, never guess its label. Do not classify keys in bulk from reading the code: a blind pass agreed with the committed file on 58% of a sample, because the file counts hub-internal caps, injected `opts.x ?? N` defaults and script deadlines as operational (`docs/verification/2026-11-05-hardcoded-values-ratchet.md`). A line moved inside a file changes no key; a changed value or name does.
|
package/docs/design/bus.md
CHANGED
|
@@ -119,7 +119,7 @@ persistence, which belong to T2. Existing layer caps remain authoritative.
|
|
|
119
119
|
|
|
120
120
|
### Room wire compatibility (#1204 T1)
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Version 1 requests only the ephemeral feature with the WebSocket upgrade header
|
|
123
123
|
`x-agent-hub-ephemeral: 1`. A supporting broker includes `ephemeral: true` in its
|
|
124
124
|
ready response only to an opted-in client, preserving the exact legacy ready
|
|
125
125
|
shape for older hubs. Each new connection starts with the feature disabled.
|
|
@@ -130,7 +130,7 @@ members under its old queue rules. Upgrade the broker for ephemeral retention.
|
|
|
130
130
|
A supporting broker forwards ephemeral presence only to ready members that
|
|
131
131
|
opted in. Older members do not see upgraded members' presence until they upgrade. Application
|
|
132
132
|
chat frames keep the legacy shape. This is the one-bit compatibility bridge;
|
|
133
|
-
|
|
133
|
+
current links keep this header unchanged and add the codec opt-in described below.
|
|
134
134
|
|
|
135
135
|
Ephemeral replacement preserves a recipient's outstanding one-packet transport
|
|
136
136
|
slot until its matching ACK or the original TTL/grace bound expires. Only the
|
|
@@ -140,8 +140,47 @@ packet's deadline. Unsupported recipients never receive the new frame shape.
|
|
|
140
140
|
A refresh request
|
|
141
141
|
remains on non-reply snapshots until all asked members supply validated presence;
|
|
142
142
|
replies never request a reply. The bounded round resets on reconnect or roster
|
|
143
|
-
change.
|
|
144
|
-
|
|
143
|
+
change. Periodic idle refresh in T3 repairs a crossed request even without a peer-state
|
|
144
|
+
change; latest-per-sender coalescing and the existing dedupe ceiling remain.
|
|
145
|
+
|
|
146
|
+
## Room liveness and epoch changes (#1204 T3)
|
|
147
|
+
|
|
148
|
+
Only a connection whose broker negotiated ephemeral presence publishes periodic
|
|
149
|
+
`requestReply` snapshots, every 30 seconds by default. Replies never request
|
|
150
|
+
replies. Three missed local refresh periods (90 seconds) make that member's room
|
|
151
|
+
presence `unknown` in its exposed-peer status. Aging is advisory only: it changes
|
|
152
|
+
no outbound admissibility, native peer state or authority. Sending remains governed
|
|
153
|
+
by the signed roster, exposure, link and Bus proofs; the broker can queue for a
|
|
154
|
+
member that is not live. An explicit signed offline presence keeps its existing
|
|
155
|
+
handling. Freshness uses local observation time, never a saved snapshot or a sender
|
|
156
|
+
clock; restart needs a fresh observation for its displayed liveness. Invalid time
|
|
157
|
+
or clock rollback makes that advisory view unknown without changing transport gates.
|
|
158
|
+
Status computes the advisory view without mutating the clock or delivery state.
|
|
159
|
+
The refresh period and clock are injectable for fixtures.
|
|
160
|
+
|
|
161
|
+
A legacy broker gets no periodic refresh or aging. Identical-snapshot dedupe and
|
|
162
|
+
state-change publication remain, with at most one final offline observation at
|
|
163
|
+
stop. Its view says `liveness not tracked (broker without ephemeral)` and asks
|
|
164
|
+
the person to upgrade the broker. Optional room-only `presence` and `liveness`
|
|
165
|
+
metadata keep the closed native `PeerState` type unchanged; older readers ignore
|
|
166
|
+
the added fields. No new codec or full capability handshake is introduced; T4
|
|
167
|
+
remains separate.
|
|
168
|
+
|
|
169
|
+
Stop is asynchronous and idempotent, with a synchronous publication fence. It
|
|
170
|
+
attempts one signed final offline observation behind an already attempted FIFO
|
|
171
|
+
head, then disconnects within two seconds. Durable application intents and
|
|
172
|
+
receipts survive. A blocked or failed final observation falls back to aging at
|
|
173
|
+
supporting brokers; it does not stop a remote process or grant native authority.
|
|
174
|
+
|
|
175
|
+
Before an actual epoch change, the person preview lists only already sealed,
|
|
176
|
+
unresolved RoomStore delivery ids. The commit quiesces link application
|
|
177
|
+
publication and rechecks that exact id set and the current roster digest.
|
|
178
|
+
RoomStore atomically quarantines old active intents as `needs_review` with the
|
|
179
|
+
existing `boundary_refused` reason and drops their sendable ciphertext. The local
|
|
180
|
+
Bus holds use `room epoch rotated; inspect ahub queue show <id>`; current room status exposes `holdReason: "epoch rotated"`.
|
|
181
|
+
Bus-only unsealed work stays queued. This is no completion, replay or cancellation;
|
|
182
|
+
terminal rows and person dispositions remain unchanged. T2 already supplied the
|
|
183
|
+
crash-gap quarantine; T3 adds the person preview and named local hold.
|
|
145
184
|
|
|
146
185
|
## Room application retry and settlement (#1204 T2)
|
|
147
186
|
|
|
@@ -192,3 +231,69 @@ ACK after durable local commit of either the receipt or the inbox entry.
|
|
|
192
231
|
Deferred application admission may ACK its durable crypto inbox entry so it does
|
|
193
232
|
not pin broker capacity; later admission commits and replays the same durable
|
|
194
233
|
receipt path before retiring its local work.
|
|
234
|
+
|
|
235
|
+
## Room codec visibility and sequence diagnostics (#1204 T4)
|
|
236
|
+
|
|
237
|
+
The room-wide signed sequence counter and durable replay floors stay unchanged.
|
|
238
|
+
A chat addresses one recipient, so another member can legitimately observe a
|
|
239
|
+
numeric gap. The host no longer turns that number into an operator loss notice;
|
|
240
|
+
three-member selective traffic therefore produces no false sequence-gap alarm.
|
|
241
|
+
The low-level replay result remains available to transport tests and does not
|
|
242
|
+
relax authentication, permanent sequence floors or exactly-once application admission.
|
|
243
|
+
|
|
244
|
+
Codec support is compatibility evidence from fresh authenticated presence, never
|
|
245
|
+
a permission or privacy grant. Every link retains the released
|
|
246
|
+
`x-agent-hub-ephemeral: 1` upgrade header byte for byte and adds
|
|
247
|
+
`x-agent-hub-codecs: 1` in the same WebSocket upgrade. Released brokers ignore
|
|
248
|
+
the codec header and retain ephemeral presence and liveness. A supporting
|
|
249
|
+
broker adds `codecFeatures: true` and the connection's `codecSession` token
|
|
250
|
+
only to an opted-in client's ready response. Legacy ready and presence shapes
|
|
251
|
+
remain unchanged.
|
|
252
|
+
|
|
253
|
+
Upgraded links keep the existing signed presence payload byte shape and send a
|
|
254
|
+
separate presence snapshot carrying a bounded, sorted `features` list. That
|
|
255
|
+
snapshot has signed `ephemeral: true` and `codecFeatures: true` headers. The
|
|
256
|
+
broker routes it only to clients that opted into codec support; legacy clients
|
|
257
|
+
receive only their original presence grammar. Legacy and codec snapshots have
|
|
258
|
+
separate coalescing groups so neither can replace the other's pending state.
|
|
259
|
+
The signed feature snapshot echoes its connection's `codecSession`; it does not
|
|
260
|
+
request a reply or renew peer-state observations. Ordinary presence does not
|
|
261
|
+
revoke support for that same connection.
|
|
262
|
+
|
|
263
|
+
Before ciphertext delivery, the broker gives codec-aware recipients a bounded
|
|
264
|
+
`codec_peers` inventory scoped to the current roster digest. A row names an
|
|
265
|
+
authenticated member's current connection token and whether it opted into codec
|
|
266
|
+
advertisements; a null token means the observation is pending or disconnected.
|
|
267
|
+
Replacement, disconnect and roster change invalidate prior connection evidence.
|
|
268
|
+
Only a fresh signed advertisement echoing the current token establishes support;
|
|
269
|
+
a delayed advertisement from another session cannot establish it. New current
|
|
270
|
+
peer-session evidence also triggers a coalesced feature-only advertisement from
|
|
271
|
+
this hub, independently of legacy replies and snapshot dedupe; missed bootstrap
|
|
272
|
+
advertisements therefore do not require unrelated application traffic to recover.
|
|
273
|
+
|
|
274
|
+
An early ordinary live-state observation from a codec-capable session waits as
|
|
275
|
+
bounded metadata until that session supplies signed codec evidence. Releasing
|
|
276
|
+
it preserves its original local receive time; the signed advertisement does not
|
|
277
|
+
renew liveness. Empty or offline snapshots and known legacy sessions remain
|
|
278
|
+
immediate. The receive-time annotation is host-only and is never accepted from
|
|
279
|
+
the room wire.
|
|
280
|
+
|
|
281
|
+
The advertised codecs are `chat_v1`, `person_inbox_v1` and `read_invocation_v1`.
|
|
282
|
+
Plain chat and status retain their legacy shape. Person-inbox sends require
|
|
283
|
+
`person_inbox_v1`; invocation kinds require `read_invocation_v1`. Compatibility
|
|
284
|
+
has three states: pending, supported and unsupported. Pending observations defer
|
|
285
|
+
the original Bus queue entry without application, sequence or socket effects;
|
|
286
|
+
the original queue lifetime still bounds this wait. A signed advertisement wakes
|
|
287
|
+
that member's queued feature-required sends as well as retained durable intents.
|
|
288
|
+
The pending path rechecks observations after requeue so an advertisement arriving
|
|
289
|
+
during asynchronous refusal cannot be lost. No timer or grace period grants support.
|
|
290
|
+
The private low-level link API has no Bus queue: it returns a typed not-sent
|
|
291
|
+
pending outcome and the caller retries after signed evidence; it never waits
|
|
292
|
+
inside the serialized receive lane. Codec-aware publication puts signed codec
|
|
293
|
+
evidence before its ordinary peer-state observation on the outbound FIFO.
|
|
294
|
+
Only a known legacy transport, an authenticated legacy member, or a signed
|
|
295
|
+
advertisement missing the required feature refuses with the upgrade-and-reconnect
|
|
296
|
+
step. Support is rechecked across awaited admission and at actual publication.
|
|
297
|
+
Live signed observations are scoped to the current connection and roster; saved,
|
|
298
|
+
stale or replayed presence never grants codec support. Existing native, exposure,
|
|
299
|
+
privacy and invocation authorization checks still decide whether a send is allowed.
|
package/docs/dogfood.md
CHANGED
|
@@ -24,6 +24,8 @@ agent-hub is developed with agent-hub. This page lists every feature, whether it
|
|
|
24
24
|
| Room membership and presence (#446 X3) | off; no person room enrollment or exposure configured here | isolated fake-hub/broker tests for OOB enrollment, MITM refusal, durable sequence/replay/grace, explicit fingerprint confirmation/abort, refused-frame retirement, exposure revocation and ids-only presence; room list/status for ids and link state; #1204 T1 fixtures cover unchanged-presence dedupe, 1,000 flips with an offline member, latest-only ephemeral broker retention, old-broker wire fallback and same-frame queue_full backoff; CI task 742 adds counter-bounded deferred-presence reuse, concurrent chat ciphertext/Store FIFO and post-close publication regressions (test/rooms-presence-coalescing-742.test.ts, test/bus-closed-publication-742.test.ts); Linux diagnostic counts and targeted hosted macOS acceptance (unchanged AC1 787.72 ms; controlled idle-entry 783.51 ms) are in docs/verification/2026-11-06-rooms-presence-cost.md; no live rooms receipt; X4 chat and X7 two-machine live receipt remain separate and unverified |
|
|
25
25
|
| Presence publication cost (#1204, #740) | source and isolated broker coverage; installed rooms remain off here | unchanged 1,000-flip AC1 test under its 20 s guard; transient pause/resume journal-write count, explicit manual-pause persistence, requestReply and exposure fences; hosted macOS is the acceptance gate |
|
|
26
26
|
| Room automatic resend and late settlement (#1204 T2) | off here; source and isolated in-process broker coverage after validation; release and person enrollment/exposure required; live two-machine behavior remains unverified | AC2-AC4: receiver offline for 15 minutes then each application admitted once; pre-enqueue refusal retries without uncertainty; ACK deadline resends within the original TTL; signed late receipt settles once; local receipt commit survives restart before broker storage; no person-disposition override or native/task-read evidence |
|
|
27
|
+
| Room liveness and epoch-change preview (#1204 T3, #736) | source and isolated fixtures, validation pending; rooms remain off here and installed/two-machine behavior is unverified | `rooms-liveness-link-736.test.ts`: signed offline within five seconds, idle crossed-request convergence and no reply loop, synchronous stop fence/FIFO preservation; `rooms-presence-aging-736.test.ts`: three local periods to advisory unknown without changing outbound admissibility, legacy untracked behavior, restart and clock rollback; `rooms-rotation-736.test.ts`: sorted ids-only preview, changed id-set/digest refusal, sealed hold versus Bus-only queue, unchanged person/terminal disposition; `rooms-liveness-status-736.test.ts`: native state preserved, broker upgrade guidance and named epoch-rotated cause; defaults 30 s refresh, 90 s aging, 2 s stop bound; exact-head gate and live proof remain separate |
|
|
28
|
+
| Room health and codec compatibility (#1204 T4, #737) | source and isolated fixtures; installed rooms remain off here | metadata-only refused counts, outbox depth/ages, closed causes, store-open retry/stop and clock rollback; Bus recovery edge wakes receive-only admission; selective three-member traffic emits no false gap; broker opt-in preserves released-broker ephemeral/liveness and legacy presence; immediate-online and forced-refresh feature sends defer pending observations under the original TTL, known unsupported codecs refuse before wire effects; dgx02 and hosted evidence recorded in the PR, native/account and two-machine receipts remain unverified |
|
|
27
29
|
| Worktree shelf (#1057): `ahub worktrees`, `tidy`, `tidy --confirm <fingerprint>`, the Agents panel section, Park/Pin, the explicit PR refresh and the inbox alert | fixture-only until a person uses it, and only after release and upgrade: this repository keeps every task in `.worktrees/<name>`, so it is the first real use, but nothing here has run `tidy --confirm` yet, and `worktrees.quiet_days` stays 7 until the owner has used it for a week | `ahub worktrees` live and settled counts over a week, and how many settled rows a person then Pins (a Pin means a rule was wrong); `tidy` preview refusals by reason (`task not approved or cancelled`, `unpushed commits`, `branch changed since preview`); after a confirm, `git worktree list` against the preview; test/worktree-shelf.test.ts, test/worktree-tidy.test.ts and test/worktree-panel.test.ts (a PII row stays live and redacted, a branch switch refuses, no GitHub call on a read, the daemon removes nothing) |
|
|
28
30
|
| Message bus, digests, priorities | on | `ahub report`: messages, digests, overflow, undeliverable; delivery latency from events |
|
|
29
31
|
| Control-send recipient normalization (#963) | active after release and hub upgrade; this PR does not change the running hub | string recipients reach only the named peer, invalid shapes publish nothing, omitted/empty arrays preserve broadcast; real native recipient behavior remains unverified |
|
package/docs/memory.md
CHANGED
|
@@ -271,8 +271,14 @@ An unchanged failure emits one safe log line per episode. A complete bounded pol
|
|
|
271
271
|
|
|
272
272
|
`ahub memory declined [--json]` is a person-only, read-only inspection. It reports physical outbound row IDs and safe policy categories, never title, body, path nodes or literal private patterns. Reads defer promotions and recheck the profile binding. Forgotten originals still matter: `forget` changes materialized visibility but leaves the source row in append-only history. Do not use it as a promise to clear a sync refusal.
|
|
273
273
|
|
|
274
|
-
The exact-pinned agent-mem 0.
|
|
274
|
+
The exact-pinned agent-mem 0.22.1 supplies bounded `inspectSyncPolicy` inspection for shared-v1 and generation profiles. A complete result lists the declined IDs and safe rule categories for the inspected physical outbound history, including originals hidden by a later forget. An unavailable, stale or bounded-out inspection remains explicitly incomplete; it never proves that no declined rows exist. The hub uses the public SDK rather than private helpers, snapshots of full history or its own portable log reader.
|
|
275
275
|
|
|
276
|
-
The package also owns per-row local placement. The hub adopts only the projection of a successful trusted SDK placement result: `ok` with its verified withheld/exported counts. This is tested through an injected SDK-result seam, not an activated store. Agent-mem 0.
|
|
276
|
+
The package also owns per-row local placement. The hub adopts only the projection of a successful trusted SDK placement result: `ok` with its verified withheld/exported counts. This is tested through an injected SDK-result seam, not an activated store. Agent-mem 0.22.1 requires a fresh `placementAttestation` for each v3 sync; the default hub does not supply one, so its active-v3 sync remains unsupported until legitimate host-attestation integration is added. Activation alone does not enable this hub's automatic sync, and the hub never fabricates that proof. Count projection does not delete or rewrite notes, change policy or promote a declined row; transport failures remain failures.
|
|
277
277
|
|
|
278
|
-
Legacy stores without active per-row placement still refuse a sync containing declined rows.
|
|
278
|
+
Legacy stores without active per-row placement still refuse a sync containing declined rows. The native amem CLI has person-only activation from 0.22.0 ([activation documentation](https://github.com/STAIxBWLB/agent-mem/blob/v0.22.1/README.md#initial-sync-placement-activation)). A person using the 0.22.1 CLI can preview it with every local writer installation declared, including the CLI and hub library installs:
|
|
279
|
+
|
|
280
|
+
```sh
|
|
281
|
+
amem migrate --sync-placement --dry-run --writer-root '<cli-install-root>' --writer-root '<host-amem-install-root>' --json
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Declare any other local writers too, and review the package's layout and version prerequisites before a separately authorized apply. The preview writes nothing; activation does not migrate layouts, change privacy policy or automatically raise a format floor. This hub neither invokes activation nor supplies a local fallback or fabricated attestation. Complete bounded diagnostics address #1173 AC4; AC5 has result projection only. #1173 remains open for legitimate fresh host-attestation integration. Source adoption and isolated fixtures do not establish activation, deployed behavior or a successful sync of the person's memory home.
|
package/docs/operations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Operations guide
|
|
2
2
|
|
|
3
|
-
This guide describes ahub 0.
|
|
3
|
+
This guide describes ahub 0.33.0 and control protocols 16 through 17. Live verification
|
|
4
4
|
results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
|
|
5
5
|
|
|
6
6
|
## Agent-operated live verification
|
|
@@ -1824,7 +1824,7 @@ ahub memory forget 1a2b3c4d # a person's; also promote, demote, sup
|
|
|
1824
1824
|
|
|
1825
1825
|
`"memory": { "native": false }` in `.agenthub/config.json` turns it off for a project.
|
|
1826
1826
|
|
|
1827
|
-
The exact-pinned `@staix/agent-mem` 0.
|
|
1827
|
+
The exact-pinned `@staix/agent-mem` 0.22.1 resolves `AMEM_HOME`, then `$AGENTHUB_HOME/memory`, then `~/.agenthub/memory`. An absent `M/profile.json` selects shared v1; an explicit generation selects `M/generations/G` with the package's readonly legacy bridge. All daemon memory consumers and the hub memory/goal CLI use that selected profile. Invalid metadata or a missing selected generation makes native memory unavailable while the bus and board continue; there is no fallback to legacy writes. Inspect the daemon's memory binding/availability before interpreting missing memory as an empty store.
|
|
1828
1828
|
|
|
1829
1829
|
The daemon checks its selector at hub operation entry and before candidate/counter writes. It does not hot-switch handles or provide an atomic fence against selection changes during an in-flight core call. Quiesce consumers and close their handles before migration or selection changes; reopen through the supported session-preserving lifecycle afterward. Candidate/counter storage remains `M/candidates.db`, independent of `G`; since agent-mem 0.7.0 `amem review` also lists and accepts candidates on a selected generation. Every running hub using this home needs an authenticated receipt: a matching ready binding, or a generation-capable unbound receipt (`disabled` when native memory is off, `unavailable` when opening failed) proving it holds no memory handle. An unbound daemon and zero running hubs are quiesced for memory; a stale bound handle, unreadable registry or unknown runtime is not ready. Existing JSON memory/goal results remain unchanged; the additive binding receipt belongs to daemon status, profile-check and the decay object. This source integration does not authorize installing a new runtime, migrating real memory, restarting sessions or claiming real-machine sync/capture receipts. Migration/deactivation and their limits belong to [agent-mem](https://github.com/STAIxBWLB/agent-mem); see [the hub profile contract](memory.md#selected-memory-profile).
|
|
1830
1830
|
|
|
@@ -3569,7 +3569,7 @@ or the plugin is older than the daemon it installed (#1179). It prints nothing w
|
|
|
3569
3569
|
| Runtime | Control protocol window | Legacy status field |
|
|
3570
3570
|
| --- | --- | --- |
|
|
3571
3571
|
| 0.12.20 through 0.25.0 | 16 only | `protocol: 16` |
|
|
3572
|
-
| 0.26.0 through 0.
|
|
3572
|
+
| 0.26.0 through 0.33.0 | 16 through 17 | `protocol: 16`, `protocolMin: 16`, `protocolMax: 17` |
|
|
3573
3573
|
|
|
3574
3574
|
New clients choose the highest common protocol. The protocol window remains 16
|
|
3575
3575
|
through 17, so the published protocol-16 client and channel plugin remain usable; unrelated feature
|
|
@@ -3577,11 +3577,14 @@ capabilities still require their own labels. A disjoint window refuses with 4426
|
|
|
3577
3577
|
The compatibility-floor `protocol` field remains readable by old clients.
|
|
3578
3578
|
|
|
3579
3579
|
Release N-1 is counted in minor versions, separately from this protocol window
|
|
3580
|
-
(#1164, family contract entelecheia/ai-workspace#70). For 0.
|
|
3581
|
-
the latest published patch of 0.
|
|
3582
|
-
protocol 17 with descriptor floor 16). Every patch on 0.
|
|
3583
|
-
baseline.
|
|
3584
|
-
the
|
|
3580
|
+
(#1164, family contract entelecheia/ai-workspace#70). For 0.33.x, N-1 is 0.32.0,
|
|
3581
|
+
the latest published patch of 0.32.x (exact `@staix/agent-mem` 0.21.0, control
|
|
3582
|
+
protocol 17 with descriptor floor 16). Every patch on 0.33.x keeps that release
|
|
3583
|
+
baseline. For 0.32.x, N-1 is 0.31.0,
|
|
3584
|
+
the latest published patch of 0.31.x (exact `@staix/agent-mem` 0.21.0, control
|
|
3585
|
+
protocol 17 with descriptor floor 16). Every patch on 0.32.x keeps that release
|
|
3586
|
+
baseline. A change that cannot retain it needs a new minor release. The 0.31.x
|
|
3587
|
+
baseline remains 0.30.0 (agent-mem 0.20.1); for 0.30.x it was 0.29.0.
|
|
3585
3588
|
|
|
3586
3589
|
In the minor release PR, together with its `package.json` version bump, query
|
|
3587
3590
|
the published versions of `@staix/agent-hub`,
|
|
@@ -4876,7 +4879,7 @@ selected roster and existing capabilities; the TUI is always a person's start.
|
|
|
4876
4879
|
- If the hub cannot read the event file the peer is `detached`, shown as offline with a notice, never idle: Qwen itself keeps working, and the hub reattaches when the file is readable again.
|
|
4877
4880
|
- Restart: if the hub restarts while your Qwen keeps running, it reads on from its saved offset (no event twice, no launch). If Qwen is gone, `ahub qwen --mode tui` starts `qwen -r <session id>` on the same two files; the earlier submits are not replayed and the recorded answers are not shared again. Recovery never restores this terminal as a headless worker, and `ahub stop qwen` refuses: end Qwen in its own terminal.
|
|
4878
4881
|
|
|
4879
|
-
Receipt-verified native ACP identities are qwen-code 0.25.0 and 0.26.0 ([dated receipt](verification/2026-10-22-kimi-qwen-compat.md)), 0.26.1 ([0.26.1 receipt](verification/2026-10-26-qwen-0261-acp.md)) 0.26.4 ([0.26.4 ACP receipt](verification/2026-10-31-qwen-0264-acp.md))
|
|
4882
|
+
Receipt-verified native ACP identities are qwen-code 0.25.0 and 0.26.0 ([dated receipt](verification/2026-10-22-kimi-qwen-compat.md)), 0.26.1 ([0.26.1 receipt](verification/2026-10-26-qwen-0261-acp.md)), 0.26.4 ([0.26.4 ACP receipt](verification/2026-10-31-qwen-0264-acp.md)), 0.26.5 ([0.26.5 ACP receipt](verification/2026-11-03-qwen-0265-acp.md)) and 0.26.8 ([0.26.8 ACP receipt](verification/2026-11-06-qwen-0268-acp.md)). The separate [0.26.4](verification/2026-10-31-qwen-0264-dual-output.md), [0.26.5](verification/2026-11-03-qwen-0265-dual-output.md), and [0.26.8](verification/2026-11-06-qwen-0268-dual-output.md) dual-output attempts did not establish their queued-turn criterion, so `qwen-dual` stays at 0.26.1. A CLI version label alone
|
|
4880
4883
|
is insufficient: startup verifies its native identity/version and advertised mode
|
|
4881
4884
|
ids before any prompt. The earlier local installation reported CLI 0.25.0 while
|
|
4882
4885
|
its package/ACP source said 0.24.1; that was not a ready identity. The 0.26.0 receipt
|
|
@@ -5558,7 +5561,7 @@ Default-branch capture runs only at daemon startup when a Claude implementer is
|
|
|
5558
5561
|
|
|
5559
5562
|
Project Git retains the core policy that clears credential.helper and core.askpass; an HTTPS push needing those helpers may fail, rather than importing credentials or relaxing that policy. Task branch/config proof reads are bounded synchronous reads (1.5 seconds per reader); slow or unknown evidence asks. The existing sandbox profile discovery is also synchronous; moving it to an asynchronous inventory proof with a shared deadline remains a follow-up. The nonce is visible in a permission response, so it proves a bounded grant rather than native-dispatch provenance.
|
|
5560
5563
|
|
|
5561
|
-
The [native permission receipt](verification/2026-10-23-headless-claude-permissions.md) covers Claude Code 2.1.309, and the [2.1.310 receipt](verification/2026-10-26-claude-implementer-2.1.310.md) repeats it on 2.1.310 (with 2.1.309 as a control), and the [2.1.314 receipt](verification/2026-10-31-claude-implementer-2.1.314.md) repeats it and the host-wrapper procedure on 2.1.314 (with 2.1.310 as a control), and the [2.1.316 receipt](verification/2026-10-31-claude-implementer-2.1.316.md) repeats both on 2.1.316 (with 2.1.314 as a control), and the [2.1.318 receipt](verification/2026-11-05-claude-implementer-2.1.318.md) repeats both on 2.1.318 (with 2.1.316 as a control), each with a deterministic loopback fixture and no real account/model call. It is not sandbox proof or a runtime receipt gate. The real account/model/person interaction remains a separate live leg.
|
|
5564
|
+
The [native permission receipt](verification/2026-10-23-headless-claude-permissions.md) covers Claude Code 2.1.309, and the [2.1.310 receipt](verification/2026-10-26-claude-implementer-2.1.310.md) repeats it on 2.1.310 (with 2.1.309 as a control), and the [2.1.314 receipt](verification/2026-10-31-claude-implementer-2.1.314.md) repeats it and the host-wrapper procedure on 2.1.314 (with 2.1.310 as a control), and the [2.1.316 receipt](verification/2026-10-31-claude-implementer-2.1.316.md) repeats both on 2.1.316 (with 2.1.314 as a control), and the [2.1.318 receipt](verification/2026-11-05-claude-implementer-2.1.318.md) repeats both on 2.1.318 (with 2.1.316 as a control), and the [2.1.319 receipt](verification/2026-11-06-claude-implementer-2.1.319.md) repeats both on 2.1.319 (with 2.1.318 as a control), each with a deterministic loopback fixture and no real account/model call. It is not sandbox proof or a runtime receipt gate. The real account/model/person interaction remains a separate live leg.
|
|
5562
5565
|
|
|
5563
5566
|
A headless Claude reviewer is run by the hub instead (task 223): declare
|
|
5564
5567
|
`"claude-review": { "kind": "claude", "roles": ["reviewer"], "start_mode": "headless" }`
|
|
@@ -5596,9 +5599,9 @@ A reviewer has a review scope (#852): `full` (reads the code, runs the affected
|
|
|
5596
5599
|
|
|
5597
5600
|
Start them with `ahub claude --as claude-review`, `ahub codex --as codex-review` and `ahub kimi --as kimi-review`; stop with `ahub stop <id>`. For the Claude and Codex reviewers the command asks the running hub to start the reviewer and returns: nothing runs in that terminal, it takes no launch arguments, and `--print-command` or `--dry-run` prints a hub-start note instead of a launch (#720). Fresh Claude and Codex variants share the project checkout; the Kimi variant runs in a clean temporary working directory and reviews only the screened brief and host facts. All fresh variants refuse a custom worktree or permission mode. Codex and Kimi require `review_mode: "fresh"`; without it, an existing headless instance with the reviewer role keeps its native app-server/ACP behavior, worktree and permission options and does not join this pool. Claude retains its task 223 automatic headless-reviewer declaration. The agy reviewer slot remains automatically unavailable (`agy is an implementer peer (#485)`). A failed or unsupported fresh start never downgrades to a native continuing session. Ordinary implementer instances retain their own adapters. The default logical pool order is Claude, Codex, Kimi. Only configured kinds with at least one declared reviewer count as slots, including declared ones that are offline, paused, quota-limited or failing, so availability never renumbers them; configured kinds with no declaration are listed after the walk as `no declared reviewer`. `review.rerotate` defaults to false. Pool selection starts at PR number modulo the number of declared kind slots, or task id when there is no PR, then skips the implementer's family and unavailable candidates. Delta review prefers the preceding eligible independent family in a fresh child. A preceding same-family fallback does not outrank a newly available independent family. `ahub route explain` shows the same pure walk.
|
|
5598
5601
|
|
|
5599
|
-
Codex requires a verified `codex-cli` (0.146.0, 0.163.0, 0.164.0 or 0.166.0) or one the person trusts on this machine, and a passing bounded runtime receipt before its model child starts. 0.146.0 and 0.163.0 passed the [2026-10-22 model-free production admission](verification/2026-10-22-codex-reviewer-isolation.md) and 0.164.0 the [2026-10-24 one](verification/2026-10-24-codex-0164-reviewer-isolation.md); 0.166.0 passed the [2026-10-31 model-free procedure](verification/2026-10-31-codex-0166-reviewer-isolation.md). Its [first authorized model review](verification/2026-10-31-codex-0166-reviewer-tool-call.md) missed a marker hidden by the fixture's accepted plan, so that admission was reverted. After a committed model-free envelope regression and a fixture correction, the separately authorized [2026-11-02 single model review](verification/2026-11-02-codex-0166-reviewer-tool-call.md) persisted one approved verdict with the required marker and exact head; 0.166.0 is now verified. A refusal names the installed and verified versions. Either set `codex_bin` to a verified executable, or run `ahub agents trust codex-review <version>`: trust lifts only the version pin, and every proof below still runs before each child (#691). Each launch approves exactly `hub_review` and `hub_task_show` per tool (`approval_mode = "approve"`), never through a server-wide default: without it Codex 0.164.0 listed the tools but refused the call, so reviews ended with no verdict (#783). A model-free receipt proves the inventory, not that a verdict reaches the hub; a [model-backed 0.164.0 run](verification/2026-10-25-codex-0164-reviewer-tool-call.md) recorded one verdict through that path. The producer checks native binary/config stability, configured MCP inventory with only the two hub tools, effective Apps/plugins/hooks disablement, an explicit empty legacy `notify` command and a named filesystem profile. Apps needs separate feature readback because configured inventory omits runtime connectors. Web search is requested disabled; its effective turn mode is not read back and managed requirements can select Cached (see the verification ceiling). Each launch proves public-read, exact/glob/symlink private-denial, standard host credential denial and write-denial in temporary fixtures. Standard credential and configured tool-home/XDG subtrees are denied independently of project `local.deny`. Its sandboxed shell is filesystem read-only with private paths denied and network configured disabled; it is not Claude's Read/Grep/Glob-only tool whitelist. No credential home is copied.
|
|
5602
|
+
Codex requires a verified `codex-cli` (0.146.0, 0.163.0, 0.164.0 or 0.166.0) or one the person trusts on this machine, and a passing bounded runtime receipt before its model child starts. 0.146.0 and 0.163.0 passed the [2026-10-22 model-free production admission](verification/2026-10-22-codex-reviewer-isolation.md) and 0.164.0 the [2026-10-24 one](verification/2026-10-24-codex-0164-reviewer-isolation.md); 0.166.0 passed the [2026-10-31 model-free procedure](verification/2026-10-31-codex-0166-reviewer-isolation.md). Its [first authorized model review](verification/2026-10-31-codex-0166-reviewer-tool-call.md) missed a marker hidden by the fixture's accepted plan, so that admission was reverted. After a committed model-free envelope regression and a fixture correction, the separately authorized [2026-11-02 single model review](verification/2026-11-02-codex-0166-reviewer-tool-call.md) persisted one approved verdict with the required marker and exact head; 0.166.0 is now verified. 0.167.0 passed the [2026-11-06 model-free procedure](verification/2026-11-06-codex-0167-reviewer-isolation.md) with 0.166.0 as control. The separately authorized [single model-backed attempt](verification/2026-11-06-codex-0167-reviewer-tool-call.md) failed a harness readiness/readback check after startup and marker preconditions; a complete persisted verdict/head/marker result was not recorded, so the model/tool outcome is unknown and 0.167.0 remains unverified. No retry was made. It joins the verified set only after a separately authorized model-backed tool-call run succeeds; until then it is refused unless the person runs `ahub agents trust codex-review 0.167.0`, and every runtime proof still runs. A refusal names the installed and verified versions. Either set `codex_bin` to a verified executable, or run `ahub agents trust codex-review <version>`: trust lifts only the version pin, and every proof below still runs before each child (#691). Each launch approves exactly `hub_review` and `hub_task_show` per tool (`approval_mode = "approve"`), never through a server-wide default: without it Codex 0.164.0 listed the tools but refused the call, so reviews ended with no verdict (#783). A model-free receipt proves the inventory, not that a verdict reaches the hub; a [model-backed 0.164.0 run](verification/2026-10-25-codex-0164-reviewer-tool-call.md) recorded one verdict through that path. The producer checks native binary/config stability, configured MCP inventory with only the two hub tools, effective Apps/plugins/hooks disablement, an explicit empty legacy `notify` command and a named filesystem profile. Apps needs separate feature readback because configured inventory omits runtime connectors. Web search is requested disabled; its effective turn mode is not read back and managed requirements can select Cached (see the verification ceiling). Each launch proves public-read, exact/glob/symlink private-denial, standard host credential denial and write-denial in temporary fixtures. Standard credential and configured tool-home/XDG subtrees are denied independently of project `local.deny`. Its sandboxed shell is filesystem read-only with private paths denied and network configured disabled; it is not Claude's Read/Grep/Glob-only tool whitelist. No credential home is copied.
|
|
5600
5603
|
|
|
5601
|
-
Kimi requires a compat-admitted Kimi Code on the hub's PATH (receipt-verified 2.2.0, 2.3.0, 2.3.1, 2.3.2 and 2.
|
|
5604
|
+
Kimi requires a compat-admitted Kimi Code on the hub's PATH (receipt-verified 2.2.0, 2.3.0, 2.3.1, 2.3.2, 2.4.1 and 2.5.1), signed in through its managed OAuth provider, and a passing runtime preparation before each child; an unverified/untrusted version or a failed preparation is unavailable with its reason. The [2.3.0](verification/2026-10-22-kimi-qwen-compat.md), [2.3.1](verification/2026-10-25-kimi-231-reviewer-compat.md), [2.3.2](verification/2026-10-26-kimi-232-reviewer-compat.md), [2.4.1](verification/2026-10-31-kimi-241-reviewer-compat.md) and [2.5.1](verification/2026-11-06-kimi-251-reviewer-compat.md) receipts are model-free and do not verify real login/provider readiness. Each review runs a new `kimi -p` child without Seatbelt, in a private `KIMI_CODE_HOME` with managed-provider-only config, a clean temporary working directory and an empty skills directory. Its agent may call only `hub_review` and `hub_task_show`, through a task-bound loopback MCP session that never carries the hub's control token, and has no native read, file or shell tool: it reviews the screened brief and host facts only. Its `credentials/`, `oauth/` and `device_id` link to the person's native Kimi files, so it shares the native login, refresh lock and the Kimi account's budget; no token is copied. A stop revokes its verdict authority first, then waits briefly while an OAuth refresh holds the lock; a forced stop mid-refresh may require a native re-login. The Kimi backend records no measured token counts here, so its usage stays unknown; the 2.3.0 receipt makes no usage claim. This is a native tool-authority boundary, not filesystem or network isolation.
|
|
5602
5605
|
|
|
5603
5606
|
A dangling or unreadable standard/configured credential root makes the Codex reviewer unavailable with only its path class in the reason (for example `~/.docker` or `$DOCKER_CONFIG`, never an expanded path or contents); repair the root and start the reviewer again.
|
|
5604
5607
|
|
|
@@ -5696,7 +5699,7 @@ Native launcher connections retry transport timeouts/unclean closes with bounded
|
|
|
5696
5699
|
|
|
5697
5700
|
## amem runtime (agent-mem#13 P4)
|
|
5698
5701
|
|
|
5699
|
-
The hub exact-pins @staix/agent-mem 0.
|
|
5702
|
+
The hub exact-pins @staix/agent-mem 0.22.1 for recall, curated evidence and local deterministic capture. No runtime call reaches a claude-mem worker; `memory.worker_url` is ignored. The person's `ahub memory import claude-mem` remains explicit and off by default. Existing profile, alias, PII and private-turn fences still apply. `ask --remember` and context checkpoints propose machine-local candidates, never automatic curated evidence. See [memory integration](memory.md#in-process-recall-and-capture-agent-mem13-p4) for changed behavior and bounded-view ceilings.
|
|
5700
5703
|
|
|
5701
5704
|
## Person-run backlog legs (#1176)
|
|
5702
5705
|
|
|
@@ -5976,6 +5979,54 @@ chat stays usable; upgrade the broker to avoid offline presence retention.
|
|
|
5976
5979
|
The supporting broker withholds ephemeral frames from older member hubs; they
|
|
5977
5980
|
must upgrade to see upgraded hubs' presence. Chat wire shapes remain unchanged. See [wire compatibility](design/bus.md#room-wire-compatibility-1204-t1).
|
|
5978
5981
|
|
|
5982
|
+
### Room liveness and graceful stop (#1204 T3)
|
|
5983
|
+
|
|
5984
|
+
On an ephemeral-capable broker, idle hubs request fresh signed presence every
|
|
5985
|
+
30 seconds. After three missed periods (90 seconds), room presence becomes
|
|
5986
|
+
`unknown` in exposed-peer status. This expiry is advisory only and never blocks
|
|
5987
|
+
outbound transport: current signed roster, exposure, link and Bus proofs still
|
|
5988
|
+
control sending, including broker queueing for members that are not live. An
|
|
5989
|
+
explicit signed offline presence keeps its existing handling. Saved presence after
|
|
5990
|
+
restart is not a fresh liveness observation.
|
|
5991
|
+
The optional room advisory presence is separate from native peer state; neither
|
|
5992
|
+
an offline observation nor expiry stops the other person's agent process.
|
|
5993
|
+
|
|
5994
|
+
With a legacy broker, status says `liveness not tracked (broker without ephemeral)`.
|
|
5995
|
+
Upgrade the broker to enable periodic refresh and aging. Legacy connections keep
|
|
5996
|
+
identical-snapshot dedupe and ordinary state-change publication, with no
|
|
5997
|
+
periodic refresh or freshness expiry. Older clients may ignore the new advisory
|
|
5998
|
+
status fields. Codec negotiation is described under Room health diagnostics below.
|
|
5999
|
+
|
|
6000
|
+
A graceful room stop immediately fences new publications and attempts one signed
|
|
6001
|
+
offline snapshot behind an already attempted FIFO frame, bounded to two seconds
|
|
6002
|
+
before disconnect. Durable sends and receipts remain for recovery. If that
|
|
6003
|
+
attempt fails or the broker is blocked, supporting recipients expire their last
|
|
6004
|
+
observation through aging. A crash has the same aging fallback. A legacy broker
|
|
6005
|
+
has no such expiry guarantee.
|
|
6006
|
+
|
|
6007
|
+
### Inspect outstanding work before rotating an epoch (#1204 T3)
|
|
6008
|
+
|
|
6009
|
+
Before an epoch-changing owner `expose`, `invite --accept`, `revoke` or an
|
|
6010
|
+
existing-room `join --roster`, the person preview prints sorted outstanding
|
|
6011
|
+
sealed delivery ids, without message text. It excludes work still queued only
|
|
6012
|
+
in the local Bus. The operation rechecks the exact id set and roster digest
|
|
6013
|
+
with link application publication quiesced; if either changed, obtain a fresh
|
|
6014
|
+
preview rather than reuse the old confirmation.
|
|
6015
|
+
|
|
6016
|
+
The epoch commit quarantines old active sealed intents and removes their
|
|
6017
|
+
sendable ciphertext. Their local delivery becomes `needs_review` with reason
|
|
6018
|
+
`room epoch rotated; inspect ahub queue show <id>`; `ahub room status team` labels
|
|
6019
|
+
its `holdReason` as `epoch rotated`. Inspect each id with
|
|
6020
|
+
`ahub queue show <delivery-id>` and choose a person disposition. Rotation does
|
|
6021
|
+
not assert completion, cancel a native turn or replay old ciphertext. Existing
|
|
6022
|
+
terminal results and person dispositions remain unchanged. T2 already fences
|
|
6023
|
+
the crash gap between the Store commit and local journal update.
|
|
6024
|
+
|
|
6025
|
+
If the command says `epoch rotated but delivery journal holds are unavailable`,
|
|
6026
|
+
the epoch has committed and old ciphertext is fenced. Inspect `ahub room status`
|
|
6027
|
+
and the affected queue ids before taking further action; do not assume the
|
|
6028
|
+
command rolled the roster back.
|
|
6029
|
+
|
|
5979
6030
|
## Screened room chat (#446 X4)
|
|
5980
6031
|
|
|
5981
6032
|
After joining and confirming fingerprints, expose each receiving native peer with
|
|
@@ -6283,12 +6334,42 @@ Corrupt or unreadable provenance stays unknown and held. The status next step di
|
|
|
6283
6334
|
|
|
6284
6335
|
A ready memory profile does not prove a successful sync. Read the separate automatic-sync result and timestamp in `ahub status` or Memory. It resets to not run after daemon restart; it is not a machine-global record of manual CLI attempts. Missing remote configuration is the neutral `not-configured` state; an interrupted/stopped attempt is neutral `stopped`. Both keep their safe next step and produce no failure log under `quietSyncError`.
|
|
6285
6336
|
|
|
6286
|
-
For policy-declined rows, a person runs `ahub memory declined --json` to inspect IDs and safe rule categories, never note text. The pinned agent-mem 0.
|
|
6337
|
+
For policy-declined rows, a person runs `ahub memory declined --json` to inspect IDs and safe rule categories, never note text. The pinned agent-mem 0.22.1 public `inspectSyncPolicy` API bounds physical outbound inspection for shared-v1 and generation profiles. A complete result supplies the declined IDs and rules; `complete:false` means the scan is unavailable, stale or over its diagnostic bound, not zero declined rows. The command stays read-only and rechecks its profile binding. No migration or policy edit is performed automatically.
|
|
6287
6338
|
|
|
6288
|
-
The hub projects verified withheld/exported counts when a trusted SDK sync returns a successful placement result. That projection is covered by an injected-result fixture, not an activated-store sync. Agent-mem 0.
|
|
6339
|
+
The hub projects verified withheld/exported counts when a trusted SDK sync returns a successful placement result. That projection is covered by an injected-result fixture, not an activated-store sync. Agent-mem 0.22.1 requires a fresh `placementAttestation` even for an already active v3 store; the default hub supplies no such integration and therefore cannot perform that sync yet. Activation alone does not enable the hub's automatic sync, and no attestation is fabricated. A nonzero withheld count in a successful result is not a transport failure and does not mean those rows were deleted, rewritten or published. Inspect the IDs and rules before deliberately changing any source or approved policy; a forget operation does not remove its original text from physical history.
|
|
6289
6340
|
|
|
6290
|
-
A legacy store without active per-row placement still blocks a sync containing declined rows. Status
|
|
6341
|
+
A legacy store without active per-row placement still blocks a sync containing declined rows. Status names inactive placement and the person-only `amem migrate --sync-placement --dry-run` preview, which requires every local writer installation through repeatable `--writer-root` flags. It also names the missing host `placementAttestation` and keeps `ahub memory declined` as the safe inspection step. The native CLI supports activation from 0.22.0; the pinned core is 0.22.1. See the [activation preview and prerequisites](memory.md#automatic-sync-health-1173) before any separately authorized apply. Preview writes nothing, and activation does not migrate layouts, change policy or automatically raise a format floor. The hub does not invoke it or fabricate its proof.
|
|
6291
6342
|
|
|
6292
|
-
The bounded diagnostic addresses #1173 AC4; AC5 has result projection only
|
|
6343
|
+
The bounded diagnostic addresses #1173 AC4; AC5 has result projection only. The core activation command is available, while legitimate fresh host-attestation integration remains necessary for default-host v3 sync. #1173 remains open for that integration.
|
|
6293
6344
|
|
|
6294
6345
|
For a transport or unknown failure, run `ahub memory sync` as a person to see the local diagnostic. Logs keep only the cause class and known declined count, once per unchanged failure episode. Complete declined-ID sets can distinguish a changed failure without placing IDs or bodies in the log; incomplete inspection keeps the set unknown. Existing write-time screening and profile/privacy fences remain. SDK adoption and isolated fixtures do not prove live rollout or a successful sync of the person's memory home.
|
|
6346
|
+
|
|
6347
|
+
### Room health diagnostics (#1204 T4)
|
|
6348
|
+
|
|
6349
|
+
`ahub room status [name]` prints retained refused-frame counts by reason, room
|
|
6350
|
+
outbox depth, oldest age, last signed receipt age and the link cause with a next
|
|
6351
|
+
step. `--json` contains the same allowlisted metadata. Unknown age is not zero;
|
|
6352
|
+
legacy generic outbox rows have no creation timestamp. Refusal counts cover only
|
|
6353
|
+
retained diagnostics, not lifetime failures. No message body, key, broker URL or
|
|
6354
|
+
raw exception appears in these projections.
|
|
6355
|
+
|
|
6356
|
+
`ahub status` names `rooms: unavailable (<code>)` if room storage cannot open.
|
|
6357
|
+
Open retries back off from 1 s to at most 30 s and stop on shutdown. For
|
|
6358
|
+
`clock_rollback`, correct the system clock to at least the last recorded room
|
|
6359
|
+
time; do not edit stored replay or clock records. A receive-only hub retries
|
|
6360
|
+
blocked admission when a successful journal checkpoint clears its storage error.
|
|
6361
|
+
Status reads and idle ticks do not poll blocked plaintext.
|
|
6362
|
+
|
|
6363
|
+
Codec negotiation keeps `x-agent-hub-ephemeral: 1` and adds
|
|
6364
|
+
`x-agent-hub-codecs: 1` on the same WebSocket upgrade. A released broker ignores
|
|
6365
|
+
the latter and retains its ephemeral/liveness behavior. A peer with a pending
|
|
6366
|
+
codec observation waits under the original queue expiry; it does not receive a
|
|
6367
|
+
false upgrade refusal. Known legacy or unsupported peers name the upgrade step.
|
|
6368
|
+
Ordinary presence refreshes preserve same-connection signed codec evidence.
|
|
6369
|
+
During a rolling upgrade, person-inbox (`user@label`) and invocation sends to a
|
|
6370
|
+
released 0.31/0.32 member, or between upgraded hubs on a released broker, are
|
|
6371
|
+
refused before any effect with an upgrade step; plain chat keeps working.
|
|
6372
|
+
Upgrade the broker, then every room member to a codec-capable release, then reconnect.
|
|
6373
|
+
`ahub status` distinguishes local room storage opening from a failed broker
|
|
6374
|
+
connection; direct `ahub room status` failures expose only closed cause/action
|
|
6375
|
+
metadata. A healthy online link needs no broker repair advice.
|