@staix/agent-hub 0.27.0 → 0.29.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 +11 -3
- package/docs/agent-notes/adapters.md +4 -2
- package/docs/agent-notes/bus.md +4 -4
- package/docs/agent-notes/daemon.md +9 -3
- package/docs/agent-notes/local-worker.md +3 -1
- package/docs/agent-notes/tasks.md +7 -0
- package/docs/agent-notes/tests.md +7 -5
- package/docs/design/adapters.md +76 -0
- package/docs/design/agent-hub-architecture.md +67 -0
- package/docs/design/agent-hub.md +52 -0
- package/docs/design/bus.md +48 -0
- package/docs/design/task-board.md +86 -0
- package/docs/dogfood.md +21 -3
- package/docs/operations.md +370 -12
- package/docs/profiles.md +1 -0
- package/docs/quickstart.md +19 -3
- package/docs/sdlc.md +2 -2
- package/docs/security.md +24 -4
- package/docs/smoke.md +2 -0
- package/docs/specs/2026-09-19-agent-hub-design.md +2 -0
- package/docs/verification/2026-10-31-codex-0166-reviewer-isolation.md +2 -0
- package/docs/verification/2026-11-02-0.28.0.md +54 -0
- package/docs/verification/2026-11-02-autonomy-t4.md +39 -0
- package/docs/verification/2026-11-02-codex-0166-reviewer-tool-call.md +53 -0
- package/docs/verification/2026-11-02-control-write-after.json +139 -0
- package/docs/verification/2026-11-02-control-write-baseline.json +127 -0
- package/docs/verification/2026-11-02-control-write-guarded.json +127 -0
- package/docs/verification/2026-11-02-control-write-outcomes.md +65 -0
- package/docs/verification/2026-11-02-orca-1.4.245-cli-contract.md +51 -0
- package/docs/verification/2026-11-03-0.29.0.md +59 -0
- package/docs/verification/2026-11-03-control-write-stall-windows.json +241 -0
- package/docs/verification/2026-11-03-control-write-stall-windows.md +20 -0
- package/docs/verification/2026-11-03-live-board-latency.json +556 -0
- package/docs/verification/2026-11-03-live-board-latency.md +64 -0
- package/docs/verified.json +14 -14
- package/package.json +2 -2
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +857 -125
- package/src/adapters/claude-channel.ts +12 -2
- package/src/adapters/compat.ts +1 -1
- package/src/adapters/definitions/native-cli-claude-setup.ts +31 -9
- package/src/adapters/definitions/native-cli-entry-jcode.ts +33 -0
- package/src/adapters/definitions/native-cli-entry-qwen.ts +2 -2
- package/src/adapters/jcode.ts +37 -4
- package/src/adapters/qwen-dual.ts +3 -2
- package/src/cli/agents.ts +4 -2
- package/src/cli/bench.ts +4 -2
- package/src/cli/board-read.ts +25 -0
- package/src/cli/claude-homes.ts +2 -2
- package/src/cli/console-state.ts +8 -3
- package/src/cli/help.ts +6 -5
- package/src/cli/identity.ts +9 -1
- package/src/cli/init-prompt.ts +179 -0
- package/src/cli/init-settings.ts +229 -0
- package/src/cli/init.ts +102 -9
- package/src/cli/launch.ts +3 -1
- package/src/cli/main.ts +106 -35
- package/src/cli/output.ts +19 -0
- package/src/cli/recovery-package.ts +9 -0
- package/src/cli/setup-homes.ts +18 -3
- package/src/cli/specs.ts +150 -0
- package/src/cli/terminal-recovery.ts +35 -11
- package/src/hub/board.ts +59 -5
- package/src/hub/bus.ts +54 -7
- package/src/hub/child-process.ts +6 -4
- package/src/hub/config-apply.ts +4 -1
- package/src/hub/config-edit.ts +1 -1
- package/src/hub/config-tier.ts +1 -0
- package/src/hub/control-client.ts +43 -4
- package/src/hub/control-write-trace.ts +409 -0
- package/src/hub/cost-governance.ts +22 -6
- package/src/hub/crash.ts +20 -0
- package/src/hub/daemon.ts +470 -98
- package/src/hub/delivery-hints.ts +6 -3
- package/src/hub/delivery-journal.ts +14 -3
- package/src/hub/hub-tools.ts +10 -6
- package/src/hub/peers.ts +1 -1
- package/src/hub/review-brief.ts +18 -0
- package/src/hub/routing.ts +14 -3
- package/src/hub/runtime-capture-prune.ts +4 -1
- package/src/hub/sdlc-release-authorization.ts +13 -4
- package/src/hub/sdlc-release.ts +23 -10
- package/src/hub/sdlc.ts +15 -2
- package/src/hub/settings.ts +2 -0
- package/src/hub/specs-config.ts +43 -0
- package/src/hub/specs-task.ts +108 -0
- package/src/hub/specs.ts +1008 -0
- package/src/hub/task-list-page.ts +75 -0
- package/src/hub/task-sweep.ts +10 -1
- package/src/hub/task-worktree.ts +331 -0
- package/src/hub/tasks.ts +606 -53
- package/src/hub/terminal-open.ts +10 -5
- package/src/hub/tool-request.ts +131 -0
- package/src/local/deny.ts +49 -0
- package/src/local/tools.ts +4 -2
- package/src/memory/brief.ts +5 -0
- package/src/memory/client.ts +5 -2
- package/src/ui/office-model.ts +17 -1
- package/src/ui/office-space.ts +1 -1
- package/templates/config.json +1 -0
- package/templates/profiles/dev.json +1 -0
- package/templates/profiles/general.json +1 -0
- package/templates/profiles/research.json +1 -0
- package/templates/profiles/writing.json +1 -0
- package/templates/specs.block.md +5 -0
package/docs/sdlc.md
CHANGED
|
@@ -17,7 +17,7 @@ The built-in lifecycle follows the [AI-Native SDLC Playbook](https://claude.com/
|
|
|
17
17
|
| plan | Build | planner/owner | plan, branch, existing predecessor gates | current planner review required at build admission; literal-path conformance gates approval in enforce | agent-executable |
|
|
18
18
|
| build | Build | owner | PR identity/current head and local check on that head | entering review, when enabled | agent-executable |
|
|
19
19
|
| test | Test | verifier/reviewer | required checks and local gate on the reviewed head | approval, when enabled; bug test integrity and the configuration-PR eval gate below | agent-executable |
|
|
20
|
-
| review | Deploy | assigned reviewer | current head-bound verdict, no pending change request/open thread; AC checklist under Compliance | approval, when enabled; open Important findings block in enforce | agent-executable |
|
|
20
|
+
| review | Deploy | assigned reviewer | current head-bound verdict, no pending change request/open thread; AC checklist under Compliance; each new or changed error, refusal or failure message names its cause and next step (Bugs pass, #1095) | approval, when enabled; open Important findings block in enforce | agent-executable |
|
|
21
21
|
| merge | Deploy | person | current-head readiness, ordered touching PRs | shown; the guarded merge below runs only when `auto_merge` is `on` (default off) | agent-executable where the project's AGENTS.md delegates it to the approving reviewer (this repository does, #784); the hub still shows the person as actor |
|
|
22
22
|
| release | Deploy | person | merged commit, version/tag, docs freshness/live receipt checklist | person authorization and optional tag hook below | agent-evidence / person-verdict (consent) |
|
|
23
23
|
| maintain | Maintain | person/planner | follow-up intent and operational evidence | shown; metrics and control bands from S7 (`ahub sdlc metrics`) | agent-executable |
|
|
@@ -403,7 +403,7 @@ Tracked npm cleanliness compares the cached index to HEAD and raw tracked blob b
|
|
|
403
403
|
|
|
404
404
|
## Release preparation and the guarded tag (#787 P3b)
|
|
405
405
|
|
|
406
|
-
Release preparation is an agent task; the release decision remains the person's. Consent may be recorded by the person or by the configured conductor on the explicit version-naming instruction above; preparation alone grants no consent.
|
|
406
|
+
Release preparation is an agent task; the release decision remains the person's. Consent may be recorded by the person or by the configured conductor on the explicit version-naming instruction above; preparation alone grants no consent. A hub captured before #1120 has no `scripts/check-docs.mjs` in its runtime copy, so `ahub sdlc authorize-release` there refuses with "documentation checker ... is missing from the running hub" (not "stale documentation"): record consent from a hub that carries the checker, either `ahub upgrade` to a release that includes #1120 or a hub started from the candidate checkout with `bun src/cli/main.js`, and never restamp documents to get past it.
|
|
407
407
|
|
|
408
408
|
`bun scripts/release-prepare.ts [--version X.Y.Z] [--dry-run]` is the mechanical half of AGENTS.md "Releasing" steps 1 and 2. On a `release/<version>` branch (it refuses `main`, a detached HEAD, a dirty tree and any other branch name) it reads the commits since the last `v*` tag, applies the rule (any `feat` subject bumps the minor, otherwise the patch; a version below the rule or not newer than the last tag is refused, so is a missing or empty `## Unreleased`), and writes `package.json`, the README `Status:` line, the CHANGELOG section (the Unreleased entries move under the version, Unreleased stays empty), the bundle (`bun run build`) and a verification report skeleton `docs/verification/<date>-<version>.md`. The skeleton lists the pull requests the commits name and the native acceptance receipts, which it reads from `docs/verification/` files added since the tag, never from what an agent writes. It leaves `TODO(agent)` markers for what only a review can state: each PR's review and CI, the document review, the checks and the known gaps.
|
|
409
409
|
|
package/docs/security.md
CHANGED
|
@@ -6,6 +6,8 @@ agent-hub connects agents that can each run commands. This page says what the hu
|
|
|
6
6
|
|
|
7
7
|
- **Other agents' text is untrusted.** Every message that crosses from one peer to another is framed as untrusted input: a channel tag with `meta.source` for Claude started with `ahub claude`; otherwise a fixed header line (`frame()`, `[agent-hub message from ...]`) with an instruction that says it is untrusted, the plugin's server instructions for a tools-only Claude reading `hub_inbox` and a standing instruction for the others. A message body cannot forge the hub's own headers: such lines are quoted (`sanitize`). Replies inherit a hop count capped at 3, so agents cannot ping-pong forever; neither a digest nor a steer can reset it.
|
|
8
8
|
- **The control link is loopback plus a secret.** The daemon and the Codex proxy bind 127.0.0.1 only. The control WebSocket requires a per-run token (`.agenthub/state/control-token`, mode 600), and both servers refuse any request that carries an `Origin` header: any web page can open a WebSocket to localhost, and browsers always send `Origin`. The bearer header a Codex TUI sends to the proxy carries only the terminal launch id (#586): it binds terminal ownership and is not a credential. External clients cannot claim the console user's id or a hub-managed peer's id.
|
|
9
|
+
- **Write retry keys grant no authority (#1078).** The `tool_write_idempotency` feature binds top-level control `requestId` keys to authenticated actor/role/launch/generation/execution scope and canonical business arguments. For task proposals and reviews, MCP `request_id` is an explicit retry argument, independent of JSON-RPC correlation; it is removed before dispatch. A timeout or connection loss remains `outcome: unknown`, with a settling read, while a pre-admission refusal says this attempt did not run. Reusing another scope's key, changed arguments, expired or old-instance IDs never starts a new write. Current authority and privacy are rechecked before a cached result is returned, including the PII status of overlap references. Request payloads are hashed rather than retained; result records are bounded and remain in daemon memory. Limits are per authenticated actor (512 entries/15 minutes), not one shared admission budget. Delivery acknowledgement uses the journal's existing idempotence and socket/generation ownership checks without consuming that cache, so another actor's filled window cannot prevent settlement. Legacy clients without keys keep their path; current clients refuse explicit replay to an older daemon that would ignore it. See [safe retry and refusal semantics](operations.md#control-write-outcomes-and-safe-retries-1078).
|
|
10
|
+
- **Control-write diagnostics carry metadata only (#1126).** The daemon's write spans and event-loop probe record a closed set of operation kinds, phases, task numbers and durations, never task text, paths, ids of transports, actors or sessions, credentials, error text or external output, and nothing for a PII task or a private turn. A frame from a client that has not authenticated is never inspected for them. Retention is capped (128 requests, 256 spans, 512 recent intervals, five-minute expiry) and a record in `hub.log` is at most 2,048 bytes; client timing on stderr is off unless `AHUB_CONTROL_WRITE_TIMING=1`.
|
|
9
11
|
- **Permission prompts stay on unless an operator selects a permission mode.** `ask` leaves native decisions unchanged. `ask-when-needed` grants scoped Claude file tools or Pi/local writes and edits, and a headless Claude implementer's proven shell commands through the host wrapper (#845, below); Kimi and Codex use their own native policies. `never-ask` requires explicit runtime confirmation, a person's console `y` for a config default at hub start, or retained autonomy consent bound to that peer's exact never-ask value in the untracked `config.local.json` (#999, below). Without one of these the peer runs in `ask`. Kimi's and `local`'s permission requests are relayed to the console and cancelled after `approvals.timeout_s` (default 120 s) of silence; the macOS notification for a waiting request carries the peer and the tool name only. The one exception is the hub's own tools (`hub_send` and the task tools, matched by exact name): Kimi's requests for them are approved once without a prompt and logged by name, the same trust Codex gets through `approval_mode` in the hub's config. They invoke hub-owned operations rather than arbitrary file or shell tools, and every call passes the hub's own checks. A call the always-ask policy classes (below) is never approved this way, whatever its title. Identity comes from the exact permission title, or from the earlier tool-call title bound to the same call id and resolved against the configured MCP servers when the permission title contains argument JSON (Qwen). Payload text and unrelated display titles never establish identity. Configured ACP kinds (#451) never get this exception: a request whose title spells a hub tool exactly still goes to the person approval path, and only a mapped native mode changes what the agent itself asks. For ACP agents, a payload longer than the console shows is marked as cut and never offers a session-wide grant. Pi's write, edit, shell and git write requests are relayed the same way and can be answered `Always allow <tool> until Pi restarts`: later calls of that tool by the same Pi start skip the prompt but stay inside the path guard and sandbox. The grant covers every later call of that tool whatever its payload, is kept in memory only, cannot be given from the dashboard, and each call it allows is logged by tool name. A Pi or `local` request whose call was cancelled or whose turn ended is withdrawn at once: a later answer is refused and grants nothing, an `Always allow` included. One shell command runs without a hub approval: the `!command` a person types in the managed Pi TUI. It stays inside the same sandbox and denylist, and the hub takes it only from the verified owner process of a Pi in TUI mode, while Pi is idle, on a reservation that is used once; a model's own bash call never takes that path (issue #253). `--unattended` turns prompts off, says so loudly, and is never the default; a classed call from a hub-owned ACP peer, the local worker or Pi still waits for a person under it.
|
|
10
12
|
- **A committed config cannot choose launch commands, credential files, data endpoints, permission modes or a wider sandbox.** The machine-local fields (`kimi_cmd`, `permission_modes`, `codex_bin`, `pi.cmd`, `checks`, `mlx.bin`, `mlx.runtimeDir`, `mlx.modelPath`, `omniroute.urls`, `omniroute.access_hosts`, the `omniroute` key files, `memory.worker_url` (still accepted, ignored since 0.16.0), `local.read_allow`, `local.bash_network`, `local.network_allow`, `local.doc_read`, `local.web_fetch`, `terminal.open`, `tasks.auto_pull`, `tasks.queue_backpressure`, `context.max_assignment_used`, `schedules` (the `every`, `cron` and `tz` forms alike), `folder_triggers`, `corpus.paths`, `invocation`, `start.agents`, `instances`, `action_policy`, `rooms`) apply only from a config file git confirms nobody committed (`instances`, `action_policy` and `rooms` are read only from an untracked `.agenthub/config.local.json`; in `config.json` they are ignored even when untracked): `.agenthub/config.json` or `.agenthub/config.local.json`, matched by file identity so no other spelling the file system accepts slips past, and `.agenthub` itself not a committed symlink or submodule. Without a repository, or when git fails, they keep their defaults; an empty value always means the default. "Untracked" is answered by the repository that contains the project: a checkout copied or extracted into an unrelated repository, or into an ignored directory of one, is trusted like your own files. So a cloned repository cannot choose a launch command, a completion check, a gateway to send a key file to, a memory endpoint, a permission mode, the command that opens a terminal, which agents `ahub up` opens terminals for, a folder the hub reads, work proposed on a timer, a host a model may fetch from, which of your agents' skills other peers may call, or a wider sandbox. A command in `checks` runs as you, outside the local worker's sandbox, like a git hook. So do the `setup` and `verify` commands of a benchmark suite (issue #251): `ahub bench run <suite.json>` is a person's command, refused from an agent session, and it resets the work tree for each attempt, so it runs only with `bench.enabled`, at the root of a clean repository that tracks nothing under `.agenthub/`. Nothing in `routing.toml` or in task text is ever run. `routing.toml` and the other shared fields still come from the checkout, and they matter: `routing.toml` picks the models the local worker and the hub's inference use at your gateway and can turn the PII constraint off, and roles and budget shape who does what. Review them in a repository you do not trust. The hub's own git calls outside the sandbox (snapshots, facts, config trust, project discovery, memory recall, the bench runner) all use the single hardened implementation in the exact-pinned first-party `@staix/agent-mem/platform` package, re-exported by `src/hub/git.ts`, which disables the programs a repository's configuration can name — the file-system monitor, hooks, external diff, the pager, and the credential and askpass helpers, with prompts failing closed — so a config that ever does get written cannot run code with the hub's rights. Of those, the monitor, hooks and external diff are reachable by commands the hub issues (the planted-program test exercises all three; a `diff --no-index` reads the repo's config, so that call also passes `--no-ext-diff` and `--no-textconv`); the pager is not (every call pipes stdout). Credential and askpass helpers are disabled for project repositories; memory sync alone may use credentials for its own memory repository, without prompts. The cost: `core.fsmonitor=false` also turns off a person's enabled built-in monitor for the hub's own calls, so the per-turn snapshot's `add -A` scans the whole tree (the snapshot Git calls of one burst share a 250 ms budget, each call at most 10 s; a boundary that runs out is recorded as unknown, never as a stale baseline) (#576). git has no global switch for filter drivers, and of the hub's commands only the snapshot's `add`/`restore` would run one (its driver command lives in the protected `.git/config`).
|
|
11
13
|
- **Telemetry holds no bodies.** `.agenthub/state/events.jsonl` (issue #40) records envelope ids, routing and sizes, task ids and states, overlapping paths and token counts, and the task id (with a PII flag) that each usage and token record is attributed to. It never records a message body, a task title or detail, and marks private (PII) envelopes and tasks as such. Budget pauses, resumes and quota resets carry the peer, window, times and the hub's own reason text, and a person's release authorization its commit, version and docs digest. The usage roll-up (#683) folds the usage, token and limit records into `hub.db` and joins issue, PR and release from the board when read; `ahub usage` and the console's Usage panel answer only the console and a configured planner, and a planner not during a private turn. Kimi's token records (#285) are counted from its own session wire log under its home: only the four token integers, the model label and the row time are copied, and the record id is an opaque hash, never a path, session id or text. The log stays on the machine; `ahub export` only prints it. Two opt-in stores copy numbers from it into your home directory, shared by every project on the machine (directories mode 700, files 600): research records (issue #247, `research.enabled`) in `~/.agenthub/research/` hold per approved task the ids, states, counts, tokens, times and PII flag the events hold, a person's label from a closed list, and a hash in place of the project id; benchmark runs (issue #251) in `~/.agenthub/bench/` hold suite name and hash, arm label, the attached peers' ids, models and permission modes, task ids, outcomes, exit codes, counts, tokens and times, never suite text or a command's output.
|
|
@@ -13,7 +15,7 @@ agent-hub connects agents that can each run commands. This page says what the hu
|
|
|
13
15
|
- **The edit hook reads, never decides.** `ahub check-path --hook` (issue #32) reads hub.db and returns context for Claude and a line for you; it sets no permission decision, so your permission rules stay in charge. It names other owners' task ids, titles and states, which then reach Claude's model; PII tasks are left out.
|
|
14
16
|
- **The session record holds identities only.** `.agenthub/state/sessions.json` (issue #37, mode 600) keeps each attached peer's recovery metadata: launch options, session and thread ids, Pi's session file path. No message or task text; loss notices name deliveries by id, sender and public task title. The Pi continuity bookmark that recovery keeps across stop and archive (`.agenthub/state/recovery-continuity.json`, mode 600, at most 16 KiB) holds identities only too: operation and project ids, the project root, and Pi's session id, session file, backend and model name; a bookmark that is not a private regular file, is larger than that or names another project or operation reads as invalid, which is kept distinct from no bookmark.
|
|
15
17
|
- **Context checkpoints have a separate text record.** Native occupancy readings carry numeric metadata only. An optional context checkpoint persists its summary in `.agenthub/state/context-checkpoint-<peer>.json` with mode 0600 and, when memory is enabled, proposes it as a machine-local memory candidate that only a person can accept. Completion requires the outstanding request id, current peer/native session and transport generation; new connection claims invalidate old requests. Private turns, every open PII task associated with the peer as owner or reviewer (including pending review), and PII-pattern summaries are refused before persistence or memory. Its text is never broadcast, and context pressure does not pause, reassign or replace the session.
|
|
16
|
-
- **The local worker is boxed in.** Paths are resolved through symlinks and must stay inside the project, and name-based refusals (the denylist, `.git`, `.agenthub`) judge both the resolved name and the name typed inside the project, because Bun's realpath can name another hardlink of the same file (#541; facts, deliverables and `ahub source add` too, #552); a secrets denylist (`.env*`, keys, credential files, the hub's own state and the state archives `ahub reset --all` leaves) applies to its file tools, its git arguments and its memory capture alike; `.git` and `.agenthub` are not writable. Writes, edits, shell commands and mutating git wait for approval unless the operator's permission mode grants them (writes and edits inside the grant filter in `ask-when-needed`, all four in `never-ask`; see below), and the approver sees what will be written or run, with control characters escaped. Everything it executes runs under the macOS sandbox, attended or not. Since 0.10 the profile starts from deny default (issue #39): commands run and read only the system, toolchain and project directories (and the project's git dir and the selected developer dir; with network on, the public CA bundles); no writes outside the project, its git dir and a temp dir of its own (`TMPDIR`, made for each command and removed when it ends; issue #63); no `.git` name at any depth, closing the creation, rename, symlink and gitfile routes to a planted repository, no `config`, `config.worktree` or `hooks` directly under one, nor in any submodule git directory (every modules tree the project can reach is covered: the common dir's, each linked worktree's own under `<common>/worktrees/<wt>/modules/`, matched by pattern so a tree or worktree that does not exist yet is covered too, and each discovered submodule git directory's own `modules/`, nested submodules and a submodule's own linked worktrees included; under a modules tree every write that is not inside a discovered submodule git directory is refused, whatever its name, so a fake git directory cannot be planted for a later unsandboxed `git submodule update --init` to reuse; inside each discovered one its own `config`, `config.worktree` and `hooks` and its linked worktrees' `config.worktree` are refused, while
|
|
18
|
+
- **The local worker is boxed in.** Paths are resolved through symlinks and must stay inside the project, and name-based refusals (the denylist, `.git`, `.agenthub`) judge both the resolved name and the name typed inside the project, because Bun's realpath can name another hardlink of the same file (#541; facts, deliverables and `ahub source add` too, #552); a secrets denylist (`.env*`, keys, credential files, the hub's own state and the state archives `ahub reset --all` leaves) applies to its file tools, its git arguments and its memory capture alike; `.git` and `.agenthub` are not writable. Writes, edits, shell commands and mutating git wait for approval unless the operator's permission mode grants them (writes and edits inside the grant filter in `ask-when-needed`, all four in `never-ask`; see below), and the approver sees what will be written or run, with control characters escaped. Everything it executes runs under the macOS sandbox, attended or not. Since 0.10 the profile starts from deny default (issue #39): commands run and read only the system, toolchain and project directories (and the project's git dir and the selected developer dir; with network on, the public CA bundles); no writes outside the project, its git dir and a temp dir of its own (`TMPDIR`, made for each command and removed when it ends; issue #63); no `.git` name at any depth, closing the creation, rename, symlink and gitfile routes to a planted repository, no `config`, `config.worktree` or `hooks` directly under one, nor in any submodule git directory (every modules tree the project can reach is covered: the common dir's, each linked worktree's own under `<common>/worktrees/<wt>/modules/`, matched by pattern so a tree or worktree that does not exist yet is covered too, and each discovered submodule git directory's own `modules/`, nested submodules and a submodule's own linked worktrees included; under a modules tree every write that is not inside a discovered submodule git directory is refused, whatever its name, so a fake git directory cannot be planted for a later unsandboxed `git submodule update --init` to reuse; inside each discovered one its own `config`, `config.worktree` and `hooks` and its linked worktrees' `config.worktree` are refused, while the index, logs and objects stay writable and, since #1123, its `refs`, `packed-refs`, `HEAD` and `worktrees` are refused like the project's own, so commit, branch, tag and rebase fail there too; a linked worktree's git directory under `<common>/worktrees/` gets the same `config`, `config.worktree` and `hooks` refusal; every term is anchored at the discovered path, `hooks` by depth, so a directory named `config` or `hooks` above the project neither disables the rule nor trips it; the discovered git directories, the modules roots, the worktrees container, each worktree git directory and every component in between are also refused as targets, closing the rename, replace and symlink routes to the same files), no `commondir` at any depth below one, with every such name matched folded against the code points HFS+ ignores (the fold covers the security-relevant names; on a volume that folds names, folded spellings of the components between `.git` and a submodule's git directory are not matched — the 1024-byte SBPL literal cannot hold a folded path — the same residual the external git dir rules carry since #270), and no `.agenthub` anywhere in the project (in an external git dir the `config`/`config.worktree`/`hooks` rules cover only its own children and the hooks directory's contents, so refs named `config` or `hooks` still work); a nested repository in bare layout stays open — the directory is the git dir, with no `.git` name to anchor a rule on, and the hub never runs git there, whatever the project root is: its calls are all `-C <project root>` or `--no-index` on temp files, and none descends into a nested directory's git layout, so a planted hook fires only if a person or another tool runs git in that directory themselves; the rules are probed on HFS+, which folds the 16 code points the patterns tolerate, and on a case-sensitive APFS image, which folds nothing (a folded spelling is an inert new file there and the real names stay refused); the shared object store takes only new loose objects (#864): `objects/info` (alternates, http-alternates, commit-graph) and `objects/pack` are refused, and so are the `objects`, `objects/info` and `objects/pack` entries, moving a fan-out directory, and changing, removing or replacing an existing loose object, because git reads packs first and never rehashes what it reads, so a planted pack or alternate would change what every checkout and the implementer's host add, commit and push (#845) see; a hardlink to an existing object is refused as well; an object id that does not exist yet can still be planted before git writes it (its exact content must be predicted), which a local checkout then shows, while a push of it is rejected by the receiving side's rehash; the cost is that `git init`, `git clone` and `git worktree add` do not run inside the sandbox (`git add`, `restore`, `checkout -- <file>` and the read commands still do; since #1123 `commit`, `stash`, `branch`, `tag`, `switch`, `merge`, `rebase` and every other command that moves a ref or HEAD do not, see "Refs, HEAD and worktree admin writes" below; `git gc`, `repack`, `fetch` and `maintenance` run outside it, #864), `git submodule update --init` does not either (its git directory's `config` write is refused), and neither do `git worktree remove`, `git worktree prune` of a stale record, `git clean -ffd` in a project with a nested repository, or `rm -rf` of a directory that holds a `.git` (refusing the unlink is what stops the rename-out route); no network, loopback included, unless `local.bash_network`; with it, only through the hub's egress proxy to the hosts in `local.network_allow` (issue #65), which refuses names that resolve to internal addresses (behind NAT64 with the well-known prefix, by the IPv4 address the answer carries; a network-specific prefix is not recognised), so claude-mem and the Codex app-server stay out of reach (`"direct"` opens everything, until 0.13.0). One channel stays open: `trustd`, which TLS clients need, can fetch a certificate's AIA or OCSP URL on a command's behalf, outside the proxy. The allow-default profile of 0.9 and earlier was removed in 0.12.0 (issue #83); a `local.sandbox` setting is ignored with a note. The shared temp dirs (the user's and `/private/tmp`) are closed. Without the sandbox there is no `bash` tool. Two opt-in tools, both machine-local and off by default, work outside the command sandbox: `doc_read` (`local.doc_read`) reads a PDF, DOCX or HWPX file through the path guard and the `pii.paths` screen, converts it with the person's `text_projection` and screens the text before the model sees it; `web_fetch` (`local.web_fetch.allow`) sends a bare https GET only to the listed hosts, through its own egress proxy (never the shell's), re-checking every redirect, and is refused for the whole turn of a PII task. Neither result is captured to memory.
|
|
17
19
|
- **Capabilities are enforced, not suggested.** `capabilities` (issue #39) is checked by the daemon where task operations and messages arrive, so a peer cannot get round it by phrasing. A peer can never answer a permission request: the control link takes `permit` from the console role only, and a message that quotes a permit command is just text. Both bind the hub's own tool paths: a vendor agent with its own shell in the project (Codex, Claude, Kimi) can read `.agenthub/state/control-token` and connect as the console, which only the local worker's and Pi's sandbox prevents.
|
|
18
20
|
- **PII has an enforced path.** A task matching `signals.pii_patterns` goes to `local` or to nobody; its text is absent from other peers' envelopes, the console stream, the log and the board listing; the console user reviews it; `local` answers such a turn to the console only, keeps it out of its history, refuses it when the only gateway is off campus, and may not save notes or spin off tasks during it. Nothing about it enters hub-managed memory; local storage does not relax this privacy fence.
|
|
19
21
|
- **A model screen can add to the patterns (issue #198).** With `signals.pii_screen = "local"` in `routing.toml` (default `off`; it applies while `constraints.pii = "local_only"`), a newly proposed task is read by a model before the hub does anything else with it: until the verdict it is on no board, in no envelope, before no triage model, and the hub makes no brief or note call for it. The local worker's amem capture leaves its hub tool calls out (issue #230), so a proposal it makes in an ordinary turn cannot reach shared memory ahead of the verdict that way. The screen runs on the model on this machine (MLX or Ollama, loopback only) or, without one, on the gateway only while `onCampus()` holds, and the gateway call is refused once more right before transport if the gateway is behind Access; task text never goes off campus to be screened. When the on-device generation slot is taken (Pi generating, another screen), the screen goes to the campus gateway instead of waiting, and on campus a device that fails or is still loading after 60% of the deadline hands over to the gateway too; off campus it waits for the slot and the device within the deadline. With the legacy MLX provider the screen may start an `mlx_lm.server`, as Pi's relay does, and it stays running until `ahub models stop`. Its answer is `pii` or `clear` plus a category from a closed list (name, student id, phone, address, grade, health, other). Anything else, a timeout (8 s, one call and one generation slot per item), a missing or off-campus model, or text longer than 6000 UTF-8 bytes (about 2000 Hangul syllables) is `unknown`, and an unknown task is a PII task: this is the hub's one model call that fails closed, so with the screener down every new task waits for `local`. An unknown verdict has the costs of any PII task, even when a second look clears it later: opening it lifts every silent turn-free cohort for good and turns facts off while it is open, and off campus a proposal without a class is refused (triage is not asked for a PII task there), with an error that says so. Off campus with the on-device slot taken, a task stays `unknown` until it is screened again: while it is still proposed and no peer ever owned it, the hub's release timer (every 60 s, one task at a time, the least tried first, at most `tasks.rescreen_max` (default 10) times per task in a hub run; never text too long to read) asks again, and `clear` lifts its `pii` signal and routes it through the class peers (a named owner is not remembered; a reserved one is offered first, as always). A task `local` took keeps its PII path, also once it is declined back to nobody. A pattern match is PII without a call. The task's history records the source of its `pii` signal (`regex`, `screen` with the category, or `unknown` with the reason), an unknown verdict is a console line naming the task id only, and `events.jsonl` gets a `pii_screen` record with the item kind, label, source, category, reason and latency, never the text. A routing explanation of a draft does not call the screen and says so.
|
|
@@ -385,7 +387,7 @@ and flag. The current daemon emits `agent_cli` with `delegated: true` and
|
|
|
385
387
|
`refused: false` for the negotiated outcome. Allowed-class commands retain the peer identity and capability checks, including
|
|
386
388
|
messages, proposals and reviews. Peer starts, pause and resume may delegate
|
|
387
389
|
operational console authority; task assign/escalate under the flag refuse. `--as-user`, person task labels,
|
|
388
|
-
person-authored planning/release/memory/goal writes, SDLC record, spec and plan-departure acceptance, release authorization, agent version trust, benchmark run,
|
|
390
|
+
person-authored planning/release/memory/goal writes, SDLC record, spec and plan-departure acceptance, release authorization, design-spec stamps (`ahub specs stamp`), agent version trust, benchmark run,
|
|
389
391
|
`ahub recovery reattach`, a `--fresh-session` dispose that would replace a repaired
|
|
390
392
|
session's conversation (or whose scope cannot be read), and the pet
|
|
391
393
|
composer are refused; presentation flags such as `--color` or `--verbose` before
|
|
@@ -793,9 +795,9 @@ The `planner` setting is person-controlled: one peer id or a list of up to eight
|
|
|
793
795
|
|
|
794
796
|
Current daemons advertise `task_cancel` in hello and status metadata. A current CLI refuses cancellation against a daemon without that feature. Controlled upgrade/restart refuses an unsupported target while cancelled task ids exist; source prepare and commit recheck compatibility, and the rows are never rewritten as approved. In the same way it refuses a target without `task_planners` once a planner list or an instance planner is configured or any task or release planner binding or plan-review authorship is stored, even after that configuration is removed. A manually started older binary is outside this compatibility guarantee: it can display cancelled rows as open or fail to move them.
|
|
795
797
|
|
|
796
|
-
Stall causes are persisted and deduplicated by cause and replanning revision. Planner advice joins its next delivery as bounded ids-only context; it does not manufacture an ordinary task turn. Pull-only offer attention clears only after acceptance, decline, supersession or durable positive evidence for that exact offer and recipient. Operator
|
|
798
|
+
Stall causes are persisted and deduplicated by cause and replanning revision. Planner advice joins its next delivery as bounded ids-only context; it does not manufacture an ordinary task turn. Pull-only offer attention clears only after acceptance, decline, supersession or durable positive evidence for that exact offer and recipient. Operator, hub or owner completion of an uncertain delivery is not evidence that the offer was read.
|
|
797
799
|
|
|
798
|
-
`hub_delivery_retry` grants an eligible recipient one retry of its own `needs_review` work, never
|
|
800
|
+
`hub_delivery_retry` grants an eligible recipient one retry of its own `needs_review` work, never pause removal. `hub_delivery_resolve` (#1112) lets a local agent mark only its own `needs_review` row `completed` or `discard`, at the revision `hub_inbox` showed, with a public, screened reason recorded under its actor. It never replays the originals or changes task state. An unknown id, another peer's row and a row that is not `needs_review` share one refusal, so the answer never confirms another peer's row. The person, the hub, a remote peer, a paused or held peer, and recovery, shutdown or storage holds are refused. A row that carries an invocation stays person-only, because its outcome is uncertain. An explicit `hub_inbox` read may return newly queued messages behind such a hold, never the held originals, and only when no recovery, pause, lifecycle or storage fence applies. Durable per-original evidence survives journal pruning; unknown retry history or a used retry requires the person. Hub presence prefaces are excluded from attempted-work identity, so a shared context preface does not consume an unrelated message's retry. Delivery-only local and ACP peers (including Jcode) cannot invoke recipient retry; tool exposure hints do not replace the daemon's actual-adapter guard. Their held work requires person resolution. Before transport handoff, storage failure preserves the queue and preface; after handoff an uncertain effect is never automatically replayed.
|
|
799
801
|
|
|
800
802
|
A declared instance whose only role is reviewer gets review requests, task messages addressed to it and the person's messages; agent chat, digests and presence are discarded and journaled, and it gets no memory recall (task 223). The headless Claude reviewer runs one new `claude -p` per review with `--setting-sources ""`, `--strict-mcp-config`, `--no-session-persistence`, tools limited to Read, Grep, Glob, `hub_review` and `hub_task_show`, and `dontAsk`. Its prompt holds hub facts and a bounded diff, never the builder's summary, and its `hub_task_show` drops the builder's notes. Changes touching `local.deny` or `pii.paths` are withheld and passed as `Read` deny rules, which Claude enforces, not the hub. Private tasks are never given to it. Its `hub_review` counts only while the child started for that task still runs; a stop or exit revokes it first, and surviving processes hold the delivery as `needs_review` and keep the reviewer busy.
|
|
801
803
|
|
|
@@ -823,6 +825,24 @@ Person-directed release authorization (#481 S6, #1063). `ahub sdlc authorize-rel
|
|
|
823
825
|
|
|
824
826
|
SDLC metrics and control bands (#481 S7). `ahub sdlc metrics` and `hub_sdlc_metrics` are planner or person only, read-only, and refused during a private or PII turn. A private task is counted as withheld and read for nothing else; the report calls no model and makes no GitHub read. Band breaches are written only by the daemon's evaluator through Tasks, never while it is stopping, recovering or has a storage error. A `diagnose` or `propose` card is a backlog task (`triage` or `plan`) whose text is fixed words, numbers and task ids, never task text; it passes the PII signal check and the candidate-text screen before it is written, and no GitHub issue is created. A `log` breach is one hub notice, remembered in the board's `band_notices` table as a marker (`<metric>:#<task>:log`, checked against a fixed pattern) and a time, nothing else.
|
|
825
827
|
|
|
828
|
+
Design specs (#1097, #1102, #1107). `hub_specs` is read-only and refused during a private or PII turn. PII tasks and private turns publish no spec paths through task notices. `spec_ack` on `hub_task_done` is refused for private work and while specs review is off. Each id and reason must be public metadata, a withheld reason is refused, and the acknowledgements are recorded at the exact head. `ahub specs stamp` is person-only: refused for an agent identity and under `--live-test`, and refused without a terminal even with `--yes`. After the person answers, it rechecks HEAD, the state of each covered path and every target file's bytes, and any change refuses the whole run.
|
|
829
|
+
|
|
830
|
+
Declared task needs (#1081). A task's `needs_network` or `needs_worktree` is set only by an explicit true, never inferred from its text. Routing, assignment and accept keep such work from a peer whose capability the hub knows is missing (a hub-sandboxed Pi or local worker without `local.bash_network`, or one that cannot run `git worktree add` inside its sandbox, #270), and the accept refusal comes before any write, so no branch ref is left. An unknown capability is never a refusal, so this is advice for routing, not a sandbox boundary; the sandbox profile itself is unchanged.
|
|
831
|
+
|
|
832
|
+
Hub-made task worktree (#1115, #1129, `src/hub/task-worktree.ts`). For write-class work (`implement`, `bulk_edit`) and for any work that declares `needs_worktree`, the hub makes the worktree of a hub-sandboxed owner (Pi, the local worker) at the fixed root `.worktrees/<peer>-<task>` on a new branch `task/<task>-<peer>`, before the accept write, through the hardened git helper (`hubGitSync`, no hook, no helper, no prompt, `repositoryIsolation`). The base is `origin/HEAD` when the repository has one, else the main checkout's HEAD, with no fetch, and it is recorded in the hub's state dir (`task-worktrees.json`), which no sandbox root contains. A refused accept (not a git repository, the branch or path is taken, the repository's own configuration names a filter, include, textconv, ssh command or remote override) creates nothing and leaves no ref. That guard reads only what a repository or a peer can plant: the shared `.git/config` (`git config --local`, which a linked worktree reads too) and, where `extensions.worktreeConfig` is on, the worktree's `config.worktree`. The person's global and system git config is theirs and is not read by it, because git-lfs alone puts `filter.lfs.*` there on most machines and refusing it would switch the feature off for them; the hardened git helper's isolation still applies to that config. The sandbox profile is not rebuilt per task and not widened: `test/task-worktree-sandbox.test.ts` compares `profile()` before and after the hub makes a worktree.
|
|
833
|
+
|
|
834
|
+
What the sandbox can and cannot write is stated here so nobody relies on more. A sandboxed command CAN write files in the worktree and it can add NEW loose objects (#864). It CANNOT write a `.git` gitfile, `config`, `config.worktree`, `hooks`, `commondir`, packs or `objects/info`, and since #1123 it cannot write `refs/**`, `packed-refs`, `HEAD` or a worktree's admin dir (`.git/worktrees/<name>/`), so its own `git commit` or `git branch` fails (see "Refs, HEAD and worktree admin writes" below). The peer is also told not to run git. The hub does not rely on either: it never trusts what is under `.git` for this flow, whatever the profile of the day allows (the profile of #1115 alone did not refuse ref writes, and a rule can be loosened later). At `hub_task_done` it commits only when the worktree is still registered at its fixed path, HEAD is still the task branch, and the branch tip still equals the base the hub recorded (or the hub's own previous commit); a peer that moved the branch to another existing commit is refused with the cause and the next step, and nothing is committed or pushed. It then rebuilds the index from the recorded tip (the peer can write the worktree index), stages the working tree, and refuses the whole commit when any changed path is on the denylist or is a `.git`, `.agenthub`, agent-configuration or protected instruction name, or is a submodule, or when more than 512 paths changed. The commit is the hub's, in the peer's name, with `--no-verify` and no signing, and its message is the task's title. The push is one explicit refspec `refs/heads/<branch>:refs/heads/<branch>`, only after every `origin` URL names this project's GitHub repository, with followTags, mirror and submodule recursion off. Fetch and push stay with the hub. A retry after a failed push pushes the commit the hub already made and never makes a second one.
|
|
835
|
+
|
|
836
|
+
On decline or cancel the hub removes the worktree and deletes the branch while it is still the empty base. A worktree with uncommitted changes, or that cannot be checked, is never force-removed: it is kept with its branch and reported as a console notice. A branch the hub committed to is kept, because its commit may be pushed and under review. A peer that makes its own worktree (Claude, Codex, Kimi) is untouched, and a PII task never gets a hub worktree. Residual: a same-user process outside the sandbox can still plant a ref under `.git/refs/heads`; the sandbox no longer lets a sandboxed command do it (#1123), and the hub refuses to commit or push on top of a moved ref either way.
|
|
837
|
+
|
|
838
|
+
Refs, HEAD and worktree admin writes (#1123). A hub-sandboxed peer (Pi, the local worker) cannot move what a branch, `HEAD` or a linked worktree points at. The profile (`gitRefRules` in `src/local/deny.ts`, built into `hubWriteRegexes`) refuses every write to `refs/**` (branches, tags, `refs/stash`, remote refs), `packed-refs` (and its lock and new files), `HEAD` (and `HEAD.lock`) and `worktrees/**` (a linked worktree's admin dir: its `HEAD`, `index`, `logs`, anything new, and a new admin dir). The rules sit directly under the git dir, so a project below a directory that happens to be named `refs`, `worktrees`, `HEAD` or `packed-refs` keeps working. They cover a plain `.git`, and each external git dir (the common dir and a linked worktree's own, whether the worktree is inside the project or beside it, and a bare repository's common dir that is not named `.git`). Every name is folded for the code points HFS+ ignores like the other git names, and each regex literal stays under seatbelt's 1024-byte limit at any project depth (`test/sandbox-git-refs.test.ts`, run with the real sandbox-exec in the main checkout, in a hub-made worktree, in a worktree outside its project and in a bare repository's worktree). The hub's own git is hardened and runs outside the sandbox, so #1115's hub commit and push are unaffected.
|
|
839
|
+
|
|
840
|
+
What a sandboxed command can still write under `.git`, each with its reason, probed with the real profile: the main checkout's `index` and `index.lock` (`git add` and `git restore` stage there), `logs/HEAD`, `ORIG_HEAD`, `FETCH_HEAD`, `MERGE_HEAD`, `COMMIT_EDITMSG`, `info/exclude` and `description` (none can run a program or move a branch), and NEW loose objects under `objects/` (a staged blob, #864; existing objects, `objects/info` and `objects/pack` stay refused). Still refused as before: a gitfile, `config`, `config.worktree`, `hooks`, `commondir` (#270). Inside a linked worktree the sandbox cannot write the worktree's own admin dir, so `git add` there fails on its `index.lock`; the working tree itself is writable and `git status`, `diff`, `log`, `show`, `blame`, `ls-files`, `rev-parse`, `for-each-ref` and `cat-file` all still work.
|
|
841
|
+
|
|
842
|
+
What stops working in the sandbox, stated so nobody is surprised: `git commit`, `branch`, `tag`, `stash`, `switch`, `checkout -b`, `merge`, `rebase`, `cherry-pick`, `revert`, `reset` and `update-ref`, anywhere, and `git add` inside a linked worktree. A sandboxed peer's work is therefore committed by the hub: for every write-class task (`implement`, `bulk_edit`) it owns, and for any task that declares `needs_worktree`, the hub stages, commits and pushes the hub-made worktree at `hub_task_done` (#1115, #1129), whether or not the task was flagged. Read-only classes (`test`, `summarize`, `triage`, `review`, `plan`) and PII tasks get no worktree and no hub commit, because they commit nothing; a hub-sandboxed peer on a project where the hub cannot make a worktree is not offered write-class work at all, and the refusal names the cause (`no worktree: ...`). The local `git` tool says so in its result when a command is refused this way, and its pointer to `hub_task_done` is true for the work that can reach it.
|
|
843
|
+
|
|
844
|
+
Submodules (#1123, the person's ruling of 2026-11-03: deny `.git` writes, submodule git dirs included). Every DISCOVERED submodule git dir gets the same four refusals as the project's own: `.git/modules/<name>`, nested ones (`.git/modules/<a>/modules/<b>`) and a linked worktree's own (`.git/worktrees/<wt>/modules/<name>`, nested too) refuse `refs/**`, `packed-refs*`, `HEAD*` and `worktrees/**`, so a sandboxed `git commit`, `branch`, `tag`, `stash` or `switch` inside a submodule fails with no ref moved (`test/sandbox-git-refs.test.ts` runs commit, branch and tag in a submodule, a nested one and a linked worktree's, with the real sandbox-exec). A submodule git dir that is not discovered is refused whole by #518 and #520, so nothing is left open by not being found. What stays writable there is what a read needs and nothing that moves a ref or runs code: `index` and `index.lock` (`git status` refreshes it), `logs/HEAD`, `ORIG_HEAD`, `MERGE_HEAD`, `COMMIT_EDITMSG` and `info/exclude` (a test writes each in a submodule git dir), and new loose objects as for the project (#864; not separately tested for a submodule). The working tree of a submodule stays writable and its `status`, `diff`, `log` and `show` work. The `.git` writes that stay open (the main checkout's `index`, `logs`, `ORIG_HEAD`, `MERGE_HEAD`) can be used to corrupt local state the person later reads, not to run code or to move a ref. Consequence for work inside a submodule: the sandbox cannot commit there, and the hub's commit (#1115) is a commit of the project's own repository, which records a submodule only as a commit id. So edits made inside a submodule's working tree are not part of the hub's commit and stay uncommitted in that submodule, while a changed submodule pointer (a gitlink) makes the hub refuse the whole commit, naming the path. A task that edits inside a submodule therefore needs a person or a vendor agent (Claude, Codex, Kimi) to commit that part.
|
|
845
|
+
|
|
826
846
|
## Research campaigns and study tools (#930, #932)
|
|
827
847
|
|
|
828
848
|
Campaign authority is the person's. `ahub study draft|revise|approve|approve-protocol|close`
|
package/docs/smoke.md
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
## Open live legs by class
|
|
11
11
|
|
|
12
|
+
Autonomy T4 (#999 AC8): [2026-11-02 live inventory](verification/2026-11-02-autonomy-t4.md). Hub and both CLI paths are 0.27.0 and machine opt-in is present; the running project's action policy is disabled. The standard task, person-prompt count and both disposable-repository floor probes remain unverified.
|
|
13
|
+
|
|
12
14
|
| Leg | Section | Class | Person verdict or blocker |
|
|
13
15
|
| --- | --- | --- | --- |
|
|
14
16
|
| Off-campus Cloudflare Access headers (#1) | Issue #7 verification ledger | external-blocked | Access credential files; then agent-executable |
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# agent-hub design spec
|
|
2
2
|
|
|
3
|
+
Successor drafts: [goal](../design/agent-hub.md), [architecture](../design/agent-hub-architecture.md), [bus](../design/bus.md), [task board](../design/task-board.md) and [adapters](../design/adapters.md); this file retains the historical change log, and new design amendments belong in the owning spec.
|
|
4
|
+
|
|
3
5
|
Date: 2026-09-19. Status: M1 to M5 merged; M6 implemented on `feat/m6-packaging-inference` (phase spec: issue #2 of the first public repository, archived). Version 0.1.0.
|
|
4
6
|
Owner: Young Joon Lee. Repo: STAIxBWLB/agent-hub.
|
|
5
7
|
|
|
@@ -4,6 +4,8 @@ Date: 2026-10-31. Platform: macOS arm64, Bun 1.4.2. Scope: issue #888, task 576.
|
|
|
4
4
|
|
|
5
5
|
Result: all four model-free legs returned the expected outcome. The subsequent [one-run model-backed receipt](2026-10-31-codex-0166-reviewer-tool-call.md) persisted an approved native verdict but failed its required synthetic-marker readback. The proposed 0.166.0 verified bump was therefore reverted. Both 0.165.0 and 0.166.0 remain unverified; this positive model-free inventory alone does not qualify a version.
|
|
6
6
|
|
|
7
|
+
Update 2026-11-02: the separately authorized [corrected single-run receipt](2026-11-02-codex-0166-reviewer-tool-call.md) passed marker, head, verdict and cleanup readback after a committed model-free envelope regression. It qualifies 0.166.0 for the verified reviewer set. The results and failed admission below describe the 2026-10-31 attempt; 0.165.0 remains unverified.
|
|
8
|
+
|
|
7
9
|
## Source identity and re-read regions
|
|
8
10
|
|
|
9
11
|
`git ls-remote https://github.com/openai/codex.git 'refs/tags/rust-v0.166.0' 'refs/tags/rust-v0.166.0^{}'` returned annotated tag object `593389380740f7b4762771573c447ccfdc59742f` and peeled commit `6ff1e1ca3b30fc8b914720681fcf5fe62e95f856`. The same readback retained the earlier 0.164.0 tag object `fe3b29455488c2e189e43ad5526a107900c5e1b7` and peeled commit `6aaac694803004a63c6f393d153c96d22521a6b9`, matching its receipt.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 0.28.0 release verification
|
|
2
|
+
|
|
3
|
+
This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.28.0 and no live TUI launch.
|
|
4
|
+
|
|
5
|
+
## Candidate
|
|
6
|
+
|
|
7
|
+
Version 0.28.0, prepared from main a23ce85a and updated with main 61972e87 (31 commits since v0.27.0, 7 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.27.0: #1119, #1117, #1081, #1116, #1083, #1114, #1080, #1113, #1079, #1112, #1111, #1110, #1106, #1109, #1107, #1105, #1108, #1104, #1103, #1100, #1102, #1099, #1093, #1101, #1097, #1098, #1094, #1092, #1091, #1074, #1072, #1075, #1073, #1071, #1070.
|
|
12
|
+
|
|
13
|
+
Each merged with `gh pr merge --squash --match-head-commit <head>` after a claude `hub_review` approval, with exact-head CI green on ubuntu and macOS (seeded guards included), no unresolved review thread and no pending change request. The conductor matched every merged PR head against the `sdlc.reviewedHead` of its board task:
|
|
14
|
+
|
|
15
|
+
- Bound at the merged head: #1070 (task 584), #1071 (625), #1072 (621), #1073 (626), #1074 (627), #1075 (628), #1091 (637), #1092 (629), #1093 (638), #1094 (630), #1097 (647), #1098 (646), #1099 (639), #1100 (648), #1101 (640), #1102 (649), #1103 (654), #1104 (641), #1105 (642), #1106 (631), #1107 (650), #1108 (643), #1109 (655), #1110 (651), #1111 (658), #1112 (632), #1114 (663), #1116 (664).
|
|
16
|
+
- One exception, #1113 (task 662, #1080): the merged head f59da348 was reviewed and approved in the verdict note, but the hub bound the approval to the earlier reviewed head 0e5cebf3. The owner's re-file carried the new head only in its summary text, so `hub_review` refused the new head ("supplied review head differs from the task resolved head"), and the approval was recorded without a head. The delta from 0e5cebf3 to f59da348 is the reviewer's own requested fix (clear a planner-pulled offer's reservation, a post-displacement WIP check) plus one wording nit. Later re-files carry `refs.commit`; a hub change that names this cause in the refusal is a follow-up.
|
|
17
|
+
- #1117 (task 665, #1064 T4): approved at its merged head 67491729 after the daemon-fixture isolation fix; its first CI `decision` step refused reuse evidence and passed on rerun.
|
|
18
|
+
- #1119 (task 666, #1064 T5): approved at f4122f49; after #1117's squash GitHub retargeted it to main, and the conductor's update-branch merge cd3bf5cf (no T5 change; the diff against main is exactly T5's six files) is the merged head. The hub kept the approval bound to f4122f49, because the owner had not re-filed; a macOS shard 2/4 timeout in CodeFacts and projection tests passed on rerun.
|
|
19
|
+
- Conductor-made merge commits, no code change: #1111 (8ac08898 to run CI on daemon.ts combined with #1106, then 055e425e for a docs/dogfood.md row conflict after #1110), approved again at 055e425e.
|
|
20
|
+
- Runner flakes retried, not code: #1114 seeded guards shard 1/4 timed out at 20 minutes (passes in about 6) and passed on rerun; #1116 failed `manager forwards scoped delivery evidence reads ... (#257)` at 250e239f, untouched by that PR, and passed at the merged head e29d72a5 (and three times alone on dgx02).
|
|
21
|
+
|
|
22
|
+
## Native acceptance receipts
|
|
23
|
+
|
|
24
|
+
Receipts added under `docs/verification/` since v0.27.0: `docs/verification/2026-11-02-autonomy-t4.md`, `docs/verification/2026-11-02-codex-0166-reviewer-tool-call.md`, `docs/verification/2026-11-02-control-write-after.json`, `docs/verification/2026-11-02-control-write-baseline.json`, `docs/verification/2026-11-02-control-write-guarded.json`, `docs/verification/2026-11-02-control-write-outcomes.md`, `docs/verification/2026-11-02-orca-1.4.245-cli-contract.md`.
|
|
25
|
+
|
|
26
|
+
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.28.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.
|
|
27
|
+
|
|
28
|
+
## Document review
|
|
29
|
+
|
|
30
|
+
Stale at preparation: README.md, docs/agent-notes/{README,adapters,benchmarks,budget,bus,daemon,tasks,tests}.md, docs/operations.md, docs/quickstart.md, docs/security.md and src/cli/help.ts. Three read-only reviews compared each against the diff of its covered sources since v0.27.0 (main c2f392c4); the conductor applied the edits and re-checked the delta of #1113, #1114 and #1116 (each of which edited operations.md, tasks.md and dogfood.md itself).
|
|
31
|
+
|
|
32
|
+
- src/cli/help.ts: `ahub specs stamp` says `--yes` still needs a terminal (#1107), `ahub status` names its specs line (#1102), and `ahub init` says a third wrong answer ends init with nothing written (#1110). Every command and flag still matches src/cli/main.ts, launch.ts and the native entries; #1116 already added `--needs-network`/`--needs-worktree`.
|
|
33
|
+
- README.md: the guided `ahub init` sentence (#1100, #1110), a Design specs bullet (#1097, #1102, #1107), and the report link moved to this file.
|
|
34
|
+
- docs/quickstart.md: the v0.28.0 install tag, an "Upgrading to 0.28.0" section covering every user-visible change since 0.27.0, the guided-init paragraph under First session, and the agent-mem pin 0.18.0 -> 0.19.0 in two places (#1072).
|
|
35
|
+
- docs/operations.md: guide header and protocol-window row (0.26.0 through 0.28.0; window unchanged at 16 through 17), the init settings flags (#1100), Orca start-terminal worktree rule (#1105), Jcode refusal causes and the headless hint (#1093), planned start (#1092), setup plugin rows (#1073, #1074), settled failed rows (#1098), `hub_delivery_resolve` refusals including invocation rows (#1112), in-process `request_id` refusal (#1106), and a corrected sentence: a plain `ahub init` follows `specs.enabled` (on by default), so it adds the specs block to a project with no `specs` key (src/cli/init.ts `specsEnabled`).
|
|
36
|
+
- docs/security.md: `ahub specs stamp` among person-only commands (#1107), `hub_delivery_resolve` authority (#1112), a Design specs privacy paragraph (#1097, #1102, #1107), and a Declared task needs paragraph stating it is routing advice, not a sandbox boundary (#1081, #1115).
|
|
37
|
+
- docs/agent-notes: bus.md (failed-row discard and `resolveOwnDelivery`, #1098, #1103, #1112), adapters.md (`ORCA_*` scrub, Jcode refusal codes, `hub_delivery_resolve` on every list; #1094, #1093, #1112), daemon.md (control write outcomes, crash-recovery lines, console discard states, `native_tui_launch` cause codes, setup scopes, init settings, `ahub specs`; #1106, #1111, #1103, #1093, #1073, #1100, #1110, #1107), tasks.md (planned start, spec coverage on done; #1092, #1102), tests.md (`check.sh --changed` never runs the seeds; a one-line anchor check). docs/agent-notes/README.md, benchmarks.md and budget.md were stale only through covered paths whose changes they do not describe.
|
|
38
|
+
|
|
39
|
+
All thirteen were restamped with `--reviewed` at 3efa678d, the branch commit holding these edits. After main was merged in with #1117 and #1119, docs/agent-notes/tests.md went stale through test/daemon.test.ts and test/repository-specs-block.test.ts; it gained a rule that a repository-root daemon fixture must not depend on the repository's own design specs, and was restamped at 36455498. docs/operations.md was restamped again at b26fcd12 after one sentence was restored: the confirmation matrix (`tui-open.orca.dual`) cites "Orca, when the hub runs in an Orca worktree" as evidence, and the first release CI run failed on its removal.
|
|
40
|
+
|
|
41
|
+
## Checks
|
|
42
|
+
|
|
43
|
+
- `node scripts/check-docs.mjs --require-fresh`: `docs: OK (0 stale documents)` on the release branch.
|
|
44
|
+
- `node scripts/check-package.mjs`: `package: OK (741 files, @staix/agent-hub@0.28.0)`.
|
|
45
|
+
- The seeds.json anchor check added to tests.md: every anchor matches exactly once after the help.ts edits.
|
|
46
|
+
- `bun x tsc --noEmit`, `bun scripts/build.mjs --check` (bundle built by `release-prepare` through the pinned Bun 1.4.2) and the full suite on ubuntu and macOS with the seeded guards: run by the release PR's exact-head CI (heavy checks run only on CI or dgx02 on this machine). The run id is recorded in the release PR.
|
|
47
|
+
|
|
48
|
+
## Known gaps, not blocking
|
|
49
|
+
|
|
50
|
+
- No installation and no running-hub upgrade to 0.28.0 is claimed. The running hub on this machine is 0.27.0; it still shows the codex 0.166.0 reviewer refusal and a codex crash notice that this release fixes (#1071, #1111).
|
|
51
|
+
- No live receipt for the guided `ahub init` prompt, `hub_delivery_resolve`, the paged `hub_task_list` on the live board, the declared-needs routing with a real Pi or local worker, or an urgent accept for a busy owner; each is covered by daemon-level or CLI fixture tests only.
|
|
52
|
+
- #1078: retries are now safe, but the live 35-45 s write stall it reported was not reproduced; whether it needs its own issue is decided after this release is running.
|
|
53
|
+
- #1081: declared needs are set by a planner; an unflagged task can still reach a peer that cannot do it. The hub-made writable worktree is #1115.
|
|
54
|
+
- The five design specs (#1117, #1119) are drafts: none is stamped or active until the person reviews them, and `specs.stamps_file` (`docs/verified.json`) is a local one-key step for the person in the ignored `.agenthub/config.json`, written in #1119's description.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Autonomy T4 live inventory
|
|
2
|
+
|
|
3
|
+
- Issue: #999, phase T4 / AC8; hub task #584.
|
|
4
|
+
- Date: 2026-11-02, Asia/Seoul.
|
|
5
|
+
- Result: unverified. The inventory reached Orca's actual native Codex session, but the running project's action policy was disabled. No standard task or floor probe was started.
|
|
6
|
+
|
|
7
|
+
## Observed prerequisites
|
|
8
|
+
|
|
9
|
+
- Installed `ahub --version`: `0.27.0` at `/Users/yj.lee/.bun/bin/ahub`.
|
|
10
|
+
- Source `bun src/cli/main.ts --version`: `0.27.0`.
|
|
11
|
+
- `ahub status --json`: running hub `0.27.0`, protocol 16, features include `project_autonomy` and `action_policy_floor`.
|
|
12
|
+
- Machine defaults readback: `schema: 1`, `autonomy: true`; owner `yj.lee`, mode `0600`, modification time `2026-11-02 08:19:08 +0900`. This verifies the file state, not the originating person's command transcript or successful application to every registered project.
|
|
13
|
+
- `orca worktree current --json`: project `github:staixbwlb/agent-hub`, local execution host, main checkout at `1d0557d6ee7f6e1b48416e5905865704b35c9dbe`.
|
|
14
|
+
- Orca's worktree process inventory and terminal list identify a live Codex pane with tab `4af7f28a-1d54-4d3a-adf8-ace6998fb9a4`, leaf `3ff021de-d160-44a4-af39-a777249715dd`, handle `term_a087d308-363f-4021-b325-4fa150a4b22e`. Its output preview contains this inventory's commands. These handles are observations for this Orca runtime only.
|
|
15
|
+
|
|
16
|
+
## Effective policy and bounded refusal
|
|
17
|
+
|
|
18
|
+
- Project `.agenthub/config.local.json`: `action_policy.enabled: false`, `action_policy.floor: true`; task auto-pull and sweep auto-reassign are true.
|
|
19
|
+
- Running hub `actionPolicyInfo`: policy disabled for Claude, Codex and Pi; all report `enabled: false`, `floor: true`. Codex also reports `enforceable: false` because native never-ask calls can bypass the approval RPC.
|
|
20
|
+
- `src/hub/action-policy.ts` computes the active floor as `config.enabled && config.floor === true`. A true floor flag alone does not establish active enforcement.
|
|
21
|
+
- The status note's generic phrase `no retained startup confirmation` is generated from weakened policy settings. It does not establish that a consent record is absent; no private consent key or record was read.
|
|
22
|
+
- Read-only `ahub autonomy status --json` exited 1 with this refusal:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
ahub: codex cannot run ahub unknown; the person runs it in ahub console or a terminal. Refused because inherited agent markers (AGENTHUB_PEER_ID, CODEX_THREAD_ID) identify this shell as an agent. A ! command in an agent session runs as that agent; use a separate terminal outside the agent session
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Live acceptance disposition
|
|
29
|
+
|
|
30
|
+
- Standard task (plan, implement, PR, review, merge): not started; person-prompt count unmeasured. Zero prompts during read-only inventory is not the required standard-task receipt.
|
|
31
|
+
- Force-push floor probe: not started, unverified.
|
|
32
|
+
- `gh release create` floor probe: not started, unverified.
|
|
33
|
+
- No disposable probe repository, remote write, release, autonomy mutation, identity-marker removal, trust approval, new native session or restart was performed.
|
|
34
|
+
- AC8 remains unverified. The next live run needs the person to inspect effective project autonomy and restore or confirm the intended floor policy in their own terminal, then a fresh readback before the standard task and disposable-repository probes. The agent must not perform the person-only autonomy command on their behalf.
|
|
35
|
+
|
|
36
|
+
## Validation scope
|
|
37
|
+
|
|
38
|
+
- Evidence above is live read-only inventory; source inspection explains the active-floor calculation only.
|
|
39
|
+
- No fixture, remote Linux test, API approval setting or static classification result substitutes for the native standard-task and floor receipts.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Codex 0.166.0 corrected reviewer tool-call receipt
|
|
2
|
+
|
|
3
|
+
Result: passed. One newly authorized native review persisted one approved verdict with the required private synthetic marker and exact fixture head. Date: 2026-11-02, macOS arm64, Bun 1.4.2. Scope: issue #888, hub task #625. This supplements the [model-free isolation receipt](2026-10-31-codex-0166-reviewer-isolation.md) and preserves the [failed 2026-10-31 marker receipt](2026-10-31-codex-0166-reviewer-tool-call.md). No native model retry was made.
|
|
4
|
+
|
|
5
|
+
## Fixture correction and model-free proof
|
|
6
|
+
|
|
7
|
+
The earlier fixture put its marker in task detail, which the production review request omits when an accepted plan exists. A review-only reviewer also receives a withheld done summary. The corrected fixture places its instruction and marker in one accepted `plan.risks` item under the 512-character item limit. Product behavior is unchanged; `Tasks` was not edited.
|
|
8
|
+
|
|
9
|
+
The committed `test/review-scope.test.ts` regression observes the actual `Tasks` review envelope through the bus. It asserts that accepted plan text reaches a code-scope, review-only reviewer while detail and the done summary remain withheld. Before the native run, exact-head dgx02 verification at `d3d926237eedaca59231e913628d98885dc05fef` returned 20 pass, 0 fail, 105 assertions and `check: OK (changed)`.
|
|
10
|
+
|
|
11
|
+
The native harness also inspected the production review envelope immediately before entering the original `ReviewerPrintPeer.review`: marker present, review-only summary withheld. Only after this assertion did it consume its persistent exclusive one-attempt fence. The observed envelope itself and marker value were not retained in the repository.
|
|
12
|
+
|
|
13
|
+
## One production review
|
|
14
|
+
|
|
15
|
+
The fixture used production `startDaemon`, `ReviewerPrintPeer`, `codexReviewerBackend`, the stdio plugin and `Tasks`. A temporary builder proposed and accepted a synthetic arithmetic task; a temporary console assigned its reviewer; builder completion triggered the native review. The harness neither called `hub_review` on the model's behalf nor substituted its verdict.
|
|
16
|
+
|
|
17
|
+
| Evidence | Observed |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| Tested source head | `d3d926237eedaca59231e913628d98885dc05fef` |
|
|
20
|
+
| Native version / binary identity | 0.166.0 / `sha256:77c2eae1013cec5acaa8a2d980bb760a7ca7657ebb9cb3033550cad787ab2fdd` |
|
|
21
|
+
| Backend source SHA-256 | `8e6ce4e64c6787a81e48a97172d25bbf1876ae5bc24a54934e7a107075a72214` |
|
|
22
|
+
| Stdio plugin SHA-256 at native run | `dda1558792bd2daae85d562ab3953cb3d253dd1fb7e5cee8ae7edd203d8e8a65` |
|
|
23
|
+
| Startup isolation profile SHA-256 | `d9da3aedb1361596675b2d692d1c2d6b61d535054a14c9a0574b8daca9fb1019` |
|
|
24
|
+
| Actual review profile SHA-256 | `4a20862407a5b604a8126cf59a3d1b8edaaf6aa631f58a0fbc09c36b92451f8e` |
|
|
25
|
+
| Fixture task / reviewer | 1 / `codex-review` |
|
|
26
|
+
| Fixture head | `27ed7ec3a56c1caf8c8b0a1b280019b149e96372` |
|
|
27
|
+
| Persisted state / verdict count | `approved` / 1 |
|
|
28
|
+
| Stored refs and running review head matched | true |
|
|
29
|
+
| Required marker matched | true |
|
|
30
|
+
| Marker SHA-256 | `b173f3b2d6d5177ab83637e2aaea40a2c2ef4931a0f7f0ec4e474001ff4dc8de` |
|
|
31
|
+
| History SHA-256 | `5ceab0bbe4bde8595dd30118d56f10b7e55c8facbabddb5fdc927490c04ce6f3` |
|
|
32
|
+
| Review attempts / delivery states / final peer state | 1 / accepted, completed / idle |
|
|
33
|
+
| Fixture start / verdict readback, UTC | 2026-11-01 23:36:58.064 / 23:37:11.189 |
|
|
34
|
+
|
|
35
|
+
The production trace observed successful `hub_task_show` and `hub_review` calls bound to the fixture head. Host and native tracing each observed them, so the two observations per tool are not claimed as distinct model calls. Read-only SQLite readback found exactly one persisted reviewer verdict.
|
|
36
|
+
|
|
37
|
+
## Isolation and cleanup
|
|
38
|
+
|
|
39
|
+
`dot admit` admitted the Mac preparation and native run. The controller held the repository lock before creating fresh HOME, CODEX_HOME and TMPDIR. One `auth.json` symlink referenced the configured account; no credential value or personal configuration was read or copied by the harness. The source worktree had a frozen dependency installation. The fixture used exact-version admission only in its fresh temporary hub home; it changed no real machine trust record. Eighteen bounded private roots covered the original configured account and the original HOME's credential locations, alongside production's private-state and canary denies.
|
|
40
|
+
|
|
41
|
+
The actual isolation receipt retained `readOnly`, `strictMcp` and `ephemeral`, all true, and all 14 model-free evidence markers. Apps, plugins, hooks and legacy notify were disabled; configured tools were exactly the two hub review tools with per-tool approval. Public-read, exact/glob/symlink private-denial, portable-core, credential-root and write-denial canaries passed. Effective network isolation and web-search behavior in the model turn were not separately measured.
|
|
42
|
+
|
|
43
|
+
The setup-only rehearsal returned zero native preparations and zero model requests, without creating an auth symlink or consuming the model fence. The actual run used that fence once, with the existing 110-second fixture and 120-second controller deadlines. No product source or immutable backend object was modified.
|
|
44
|
+
|
|
45
|
+
Before cleanup, `score.ts` was read back and still contained the expected synthetic source. Account auth metadata was unchanged, with before/after SHA-256 `d96bfccc2a92e15d7e437ba24bb7b0669703c5e5bb7daceef01be05c5c94a4fd`; this fingerprint covers filesystem metadata, without reading credential contents. Production whole-process-group teardown was awaited; the driver group was absent and the bounded fixture-root argv scan found zero remaining processes. The controller released only its own inode/owner-bound lock. The auth symlink, temporary homes, source project and task state were removed.
|
|
46
|
+
|
|
47
|
+
Private proof metadata: 4398 bytes, SHA-256 `c5fc7859b2bf81727f57c0558230c569ccea1e36b0799747b9436a986cae2ca0`; harness log length 0 bytes. Account paths, token values, marker value and model prose remain outside the repository.
|
|
48
|
+
|
|
49
|
+
## Admission and limits
|
|
50
|
+
|
|
51
|
+
This complete receipt qualifies 0.166.0 for `COMPAT["codex-review"].verified` alongside 0.146.0, 0.163.0 and 0.164.0. It changes neither attached-Codex compatibility nor the exact-version trust path, runtime proofs or isolation boundaries. The model-free inventory alone remains insufficient for admission.
|
|
52
|
+
|
|
53
|
+
This is one synthetic production-boundary receipt on macOS. It does not establish deployment, native Linux behavior, every review workflow or universal orphan detection. The pinned-Bun generated bundle and changed-source/hosted CI gates at the final PR head are separate evidence from this model run.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "agent-hub.control-write-latency/v1",
|
|
3
|
+
"ok": true,
|
|
4
|
+
"mode": "full",
|
|
5
|
+
"host": {
|
|
6
|
+
"platform": "linux",
|
|
7
|
+
"arch": "x64",
|
|
8
|
+
"bun": "1.4.2"
|
|
9
|
+
},
|
|
10
|
+
"fixture": {
|
|
11
|
+
"tasksSeeded": 600,
|
|
12
|
+
"taskHistoryNotes": 12,
|
|
13
|
+
"noteBytes": 4096,
|
|
14
|
+
"boardAfterSeed": {
|
|
15
|
+
"hubDb": 30617600,
|
|
16
|
+
"hubDbWal": 0
|
|
17
|
+
},
|
|
18
|
+
"boardAfterRun": {
|
|
19
|
+
"hubDb": 30859264,
|
|
20
|
+
"hubDbWal": 4136512
|
|
21
|
+
},
|
|
22
|
+
"events": {
|
|
23
|
+
"bytes": 110100480,
|
|
24
|
+
"rows": 215040,
|
|
25
|
+
"bytesAtEndOfSamples": 110322624
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"startup": {
|
|
29
|
+
"totalMs": 1289.06,
|
|
30
|
+
"includesStartupEventLogReads": true
|
|
31
|
+
},
|
|
32
|
+
"timing": "p50/p95 are ControlClient request round trips; Board method timings are nested synchronous observations and not additive",
|
|
33
|
+
"scope": {
|
|
34
|
+
"taskWrites": "ControlClient task RPCs",
|
|
35
|
+
"deliveryComplete": "real accepted delivery journal path using a synthetic peer ControlClient",
|
|
36
|
+
"channelMcpWrapper": "not measured",
|
|
37
|
+
"nativeModelsAndAccounts": "not used"
|
|
38
|
+
},
|
|
39
|
+
"iterationsPerPhase": 20,
|
|
40
|
+
"phases": [
|
|
41
|
+
{
|
|
42
|
+
"name": "review_approved",
|
|
43
|
+
"count": 20,
|
|
44
|
+
"p50Ms": 247.64,
|
|
45
|
+
"p95Ms": 301.97,
|
|
46
|
+
"outcomes": {
|
|
47
|
+
"ok": 20
|
|
48
|
+
},
|
|
49
|
+
"states": {
|
|
50
|
+
"approved": 20
|
|
51
|
+
},
|
|
52
|
+
"board": {
|
|
53
|
+
"listCalls": 140,
|
|
54
|
+
"listRows": 68300,
|
|
55
|
+
"listMs": 4229.38,
|
|
56
|
+
"privacyProjectionCalls": 40,
|
|
57
|
+
"privacyProjectionRows": 6600,
|
|
58
|
+
"privacyProjectionMs": 7.28,
|
|
59
|
+
"taskWriteCalls": 20,
|
|
60
|
+
"taskWriteMs": 2951.22,
|
|
61
|
+
"deliveryCompleteCalls": 0,
|
|
62
|
+
"deliveryCompleteMs": 0
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "proposal_backlog",
|
|
67
|
+
"count": 20,
|
|
68
|
+
"p50Ms": 60.86,
|
|
69
|
+
"p95Ms": 75.6,
|
|
70
|
+
"outcomes": {
|
|
71
|
+
"ok": 20
|
|
72
|
+
},
|
|
73
|
+
"states": {
|
|
74
|
+
"backlog": 20
|
|
75
|
+
},
|
|
76
|
+
"board": {
|
|
77
|
+
"listCalls": 40,
|
|
78
|
+
"listRows": 21100,
|
|
79
|
+
"listMs": 1085.81,
|
|
80
|
+
"privacyProjectionCalls": 0,
|
|
81
|
+
"privacyProjectionRows": 0,
|
|
82
|
+
"privacyProjectionMs": 0,
|
|
83
|
+
"taskWriteCalls": 20,
|
|
84
|
+
"taskWriteMs": 1218.1,
|
|
85
|
+
"deliveryCompleteCalls": 0,
|
|
86
|
+
"deliveryCompleteMs": 0
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "proposal_claim",
|
|
91
|
+
"count": 20,
|
|
92
|
+
"p50Ms": 473.43,
|
|
93
|
+
"p95Ms": 529.83,
|
|
94
|
+
"outcomes": {
|
|
95
|
+
"ok": 20
|
|
96
|
+
},
|
|
97
|
+
"states": {
|
|
98
|
+
"in_progress": 20
|
|
99
|
+
},
|
|
100
|
+
"board": {
|
|
101
|
+
"listCalls": 260,
|
|
102
|
+
"listRows": 150340,
|
|
103
|
+
"listMs": 7893.86,
|
|
104
|
+
"privacyProjectionCalls": 60,
|
|
105
|
+
"privacyProjectionRows": 1790,
|
|
106
|
+
"privacyProjectionMs": 9.21,
|
|
107
|
+
"taskWriteCalls": 60,
|
|
108
|
+
"taskWriteMs": 4949.73,
|
|
109
|
+
"deliveryCompleteCalls": 0,
|
|
110
|
+
"deliveryCompleteMs": 0
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "delivery_complete",
|
|
115
|
+
"count": 20,
|
|
116
|
+
"p50Ms": 8.89,
|
|
117
|
+
"p95Ms": 26.97,
|
|
118
|
+
"outcomes": {
|
|
119
|
+
"completed": 20
|
|
120
|
+
},
|
|
121
|
+
"states": {
|
|
122
|
+
"completed": 20
|
|
123
|
+
},
|
|
124
|
+
"board": {
|
|
125
|
+
"listCalls": 0,
|
|
126
|
+
"listRows": 0,
|
|
127
|
+
"listMs": 0,
|
|
128
|
+
"privacyProjectionCalls": 0,
|
|
129
|
+
"privacyProjectionRows": 0,
|
|
130
|
+
"privacyProjectionMs": 0,
|
|
131
|
+
"taskWriteCalls": 0,
|
|
132
|
+
"taskWriteMs": 0,
|
|
133
|
+
"deliveryCompleteCalls": 20,
|
|
134
|
+
"deliveryCompleteMs": 141.43
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"sourceCommit": "2adfd6bd0e108baec09b9c75e937b162ff6e316c"
|
|
139
|
+
}
|