@staix/agent-hub 0.31.0 → 0.32.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 +13 -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 +41 -2
- package/docs/dogfood.md +1 -0
- package/docs/operations.md +54 -6
- package/docs/quickstart.md +6 -0
- package/docs/security.md +24 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +44 -1
- 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/verified.json +11 -11
- package/package.json +1 -1
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +1 -1
- package/src/cli/console-state.ts +1 -1
- package/src/cli/room.ts +20 -10
- package/src/hub/bus.ts +18 -0
- package/src/hub/daemon.ts +7 -5
- package/src/rooms/commands.ts +61 -16
- package/src/rooms/link.ts +136 -22
- package/src/rooms/liveness.ts +11 -0
- package/src/rooms/service.ts +142 -18
- package/src/rooms/status.ts +8 -1
- package/src/rooms/store.ts +10 -0
- package/src/ui/index.html +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ 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.32.0
|
|
8
|
+
|
|
9
|
+
- 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.
|
|
10
|
+
- 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.
|
|
11
|
+
|
|
12
|
+
- 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.
|
|
13
|
+
- 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.
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
- 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.
|
|
17
|
+
- 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.
|
|
18
|
+
- 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.
|
|
19
|
+
|
|
7
20
|
## 0.31.0
|
|
8
21
|
|
|
9
22
|
- 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.32.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.32.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
|
@@ -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
|
|
package/docs/dogfood.md
CHANGED
|
@@ -24,6 +24,7 @@ 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 |
|
|
27
28
|
| 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
29
|
| Message bus, digests, priorities | on | `ahub report`: messages, digests, overflow, undeliverable; delivery latency from events |
|
|
29
30
|
| 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/operations.md
CHANGED
|
@@ -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.32.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,11 @@ 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. A change that cannot retain it needs a new minor release.
|
|
3584
|
-
|
|
3580
|
+
(#1164, family contract entelecheia/ai-workspace#70). For 0.32.x, N-1 is 0.31.0,
|
|
3581
|
+
the latest published patch of 0.31.x (exact `@staix/agent-mem` 0.21.0, control
|
|
3582
|
+
protocol 17 with descriptor floor 16). Every patch on 0.32.x keeps that release
|
|
3583
|
+
baseline. A change that cannot retain it needs a new minor release. The 0.31.x
|
|
3584
|
+
baseline remains 0.30.0 (agent-mem 0.20.1); for 0.30.x it was 0.29.0.
|
|
3585
3585
|
|
|
3586
3586
|
In the minor release PR, together with its `package.json` version bump, query
|
|
3587
3587
|
the published versions of `@staix/agent-hub`,
|
|
@@ -5976,6 +5976,54 @@ chat stays usable; upgrade the broker to avoid offline presence retention.
|
|
|
5976
5976
|
The supporting broker withholds ephemeral frames from older member hubs; they
|
|
5977
5977
|
must upgrade to see upgraded hubs' presence. Chat wire shapes remain unchanged. See [wire compatibility](design/bus.md#room-wire-compatibility-1204-t1).
|
|
5978
5978
|
|
|
5979
|
+
### Room liveness and graceful stop (#1204 T3)
|
|
5980
|
+
|
|
5981
|
+
On an ephemeral-capable broker, idle hubs request fresh signed presence every
|
|
5982
|
+
30 seconds. After three missed periods (90 seconds), room presence becomes
|
|
5983
|
+
`unknown` in exposed-peer status. This expiry is advisory only and never blocks
|
|
5984
|
+
outbound transport: current signed roster, exposure, link and Bus proofs still
|
|
5985
|
+
control sending, including broker queueing for members that are not live. An
|
|
5986
|
+
explicit signed offline presence keeps its existing handling. Saved presence after
|
|
5987
|
+
restart is not a fresh liveness observation.
|
|
5988
|
+
The optional room advisory presence is separate from native peer state; neither
|
|
5989
|
+
an offline observation nor expiry stops the other person's agent process.
|
|
5990
|
+
|
|
5991
|
+
With a legacy broker, status says `liveness not tracked (broker without ephemeral)`.
|
|
5992
|
+
Upgrade the broker to enable periodic refresh and aging. Legacy connections keep
|
|
5993
|
+
identical-snapshot dedupe and ordinary state-change publication, with no
|
|
5994
|
+
periodic refresh or freshness expiry. Older clients may ignore the new advisory
|
|
5995
|
+
status fields. Full capability advertisement remains #1204 T4.
|
|
5996
|
+
|
|
5997
|
+
A graceful room stop immediately fences new publications and attempts one signed
|
|
5998
|
+
offline snapshot behind an already attempted FIFO frame, bounded to two seconds
|
|
5999
|
+
before disconnect. Durable sends and receipts remain for recovery. If that
|
|
6000
|
+
attempt fails or the broker is blocked, supporting recipients expire their last
|
|
6001
|
+
observation through aging. A crash has the same aging fallback. A legacy broker
|
|
6002
|
+
has no such expiry guarantee.
|
|
6003
|
+
|
|
6004
|
+
### Inspect outstanding work before rotating an epoch (#1204 T3)
|
|
6005
|
+
|
|
6006
|
+
Before an epoch-changing owner `expose`, `invite --accept`, `revoke` or an
|
|
6007
|
+
existing-room `join --roster`, the person preview prints sorted outstanding
|
|
6008
|
+
sealed delivery ids, without message text. It excludes work still queued only
|
|
6009
|
+
in the local Bus. The operation rechecks the exact id set and roster digest
|
|
6010
|
+
with link application publication quiesced; if either changed, obtain a fresh
|
|
6011
|
+
preview rather than reuse the old confirmation.
|
|
6012
|
+
|
|
6013
|
+
The epoch commit quarantines old active sealed intents and removes their
|
|
6014
|
+
sendable ciphertext. Their local delivery becomes `needs_review` with reason
|
|
6015
|
+
`room epoch rotated; inspect ahub queue show <id>`; `ahub room status team` labels
|
|
6016
|
+
its `holdReason` as `epoch rotated`. Inspect each id with
|
|
6017
|
+
`ahub queue show <delivery-id>` and choose a person disposition. Rotation does
|
|
6018
|
+
not assert completion, cancel a native turn or replay old ciphertext. Existing
|
|
6019
|
+
terminal results and person dispositions remain unchanged. T2 already fences
|
|
6020
|
+
the crash gap between the Store commit and local journal update.
|
|
6021
|
+
|
|
6022
|
+
If the command says `epoch rotated but delivery journal holds are unavailable`,
|
|
6023
|
+
the epoch has committed and old ciphertext is fenced. Inspect `ahub room status`
|
|
6024
|
+
and the affected queue ids before taking further action; do not assume the
|
|
6025
|
+
command rolled the roster back.
|
|
6026
|
+
|
|
5979
6027
|
## Screened room chat (#446 X4)
|
|
5980
6028
|
|
|
5981
6029
|
After joining and confirming fingerprints, expose each receiving native peer with
|
package/docs/quickstart.md
CHANGED
|
@@ -32,6 +32,12 @@ 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.32.0
|
|
36
|
+
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
`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.
|
|
40
|
+
|
|
35
41
|
## Upgrading to 0.31.0
|
|
36
42
|
|
|
37
43
|
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.
|
package/docs/security.md
CHANGED
|
@@ -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.
|
|
@@ -1171,7 +1171,7 @@ at most 8 pending packets/2 MiB per link, 1 MiB packet/backpressure limits and a
|
|
|
1171
1171
|
minutes and do not block local work. Stop, leave, replacement and rotation fence
|
|
1172
1172
|
all awaited work by link generation.
|
|
1173
1173
|
|
|
1174
|
-
With latest-per-sender coalescing, A awaiting C can have its queued request replaced by A's broadcast reply to B
|
|
1174
|
+
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
1175
|
|
|
1176
1176
|
Presence is an encrypted, signed frame containing only exposed peer ids and closed
|
|
1177
1177
|
idle/busy/paused/offline states. It is sent on connection and coalesced peer-state
|
|
@@ -6522,3 +6522,46 @@ permanent refusal remains inspectable. A signed late receipt may settle an
|
|
|
6522
6522
|
unresolved ordinary remote hold once without overriding a person disposition.
|
|
6523
6523
|
Invocation uncertainty retains its person-only ledger hold. Receiver application
|
|
6524
6524
|
deduplication, current identity/privacy fences and all caps remain.
|
|
6525
|
+
|
|
6526
|
+
|
|
6527
|
+
### Room liveness and person-visible rotation (#1204 T3)
|
|
6528
|
+
|
|
6529
|
+
The T3 contract is [room liveness and epoch changes](../design/bus.md#room-liveness-and-epoch-changes-1204-t3).
|
|
6530
|
+
The broker's existing negotiated ephemeral bit alone enables 30-second periodic
|
|
6531
|
+
`requestReply` publication and three-period (90-second) local observation aging.
|
|
6532
|
+
It adds no wire payload kind, codec advertisement or native `PeerState` value.
|
|
6533
|
+
Legacy brokers have no periodic refresh or aging and explicitly report liveness
|
|
6534
|
+
untracked, with a broker upgrade step. The existing state-change dedupe,
|
|
6535
|
+
request/reply fencing, caps, privacy and T2 receipt/dedupe ceilings remain.
|
|
6536
|
+
|
|
6537
|
+
An asynchronous, idempotent stop fences publication synchronously, attempts one
|
|
6538
|
+
signed offline snapshot in FIFO order behind an attempted head, and disconnects
|
|
6539
|
+
within two seconds while retaining durable intents and receipt outbox rows.
|
|
6540
|
+
Failure leaves supporting recipients to age the observation; it grants no
|
|
6541
|
+
remote process-stop or execution authority. Refresh period and observation clock
|
|
6542
|
+
are fixture seams. Restored observations cannot establish freshness; clock
|
|
6543
|
+
rollback makes displayed liveness unknown and status reads mutate neither time
|
|
6544
|
+
nor delivery state. Aging is advisory only and never changes outbound admissibility;
|
|
6545
|
+
signed roster, exposure, link and Bus proofs remain authoritative. Explicit signed
|
|
6546
|
+
offline presence keeps its existing handling, and the broker can queue for members
|
|
6547
|
+
that are not live.
|
|
6548
|
+
|
|
6549
|
+
Person previews for epoch-changing owner exposure, invite acceptance, revocation
|
|
6550
|
+
and existing-room `join --roster` adoption bind the current roster digest and the
|
|
6551
|
+
sorted, exact set of already sealed unresolved Store delivery ids. Link
|
|
6552
|
+
application publication is quiesced before the final recheck and commit; a new or
|
|
6553
|
+
settled id invalidates the preview. Bus-only unsealed work is excluded.
|
|
6554
|
+
RoomStore uses its existing schema and `boundary_refused` reason to quarantine
|
|
6555
|
+
old active intents atomically with the epoch and remove sendable ciphertext.
|
|
6556
|
+
T2's crash-gap quarantine remains the recovery fence, not a new T3 repair.
|
|
6557
|
+
T3 gives matching local Bus deliveries `needs_review` with fixed journal reason
|
|
6558
|
+
`room epoch rotated; inspect ahub queue show <id>` and room-status
|
|
6559
|
+
`holdReason: "epoch rotated"`. Terminal rows and person
|
|
6560
|
+
dispositions remain authoritative; rotation is not completion, replay or
|
|
6561
|
+
cancellation. A committed rotation whose local journal hold cannot be written
|
|
6562
|
+
returns `epoch_rotated_hold_unavailable` with an inspection step, without
|
|
6563
|
+
restoring old sendability.
|
|
6564
|
+
|
|
6565
|
+
Source and isolated fixture coverage are listed in [dogfood](../dogfood.md).
|
|
6566
|
+
Those fixtures do not establish installed or two-machine liveness. #1204 remains
|
|
6567
|
+
open for T4's full capability advertisement and compatibility work.
|
|
@@ -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.
|