@staix/agent-hub 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +13 -4
  3. package/docs/agent-notes/adapters.md +4 -2
  4. package/docs/agent-notes/bus.md +4 -4
  5. package/docs/agent-notes/daemon.md +8 -4
  6. package/docs/agent-notes/tasks.md +7 -2
  7. package/docs/agent-notes/tests.md +6 -5
  8. package/docs/design/adapters.md +76 -0
  9. package/docs/design/agent-hub-architecture.md +67 -0
  10. package/docs/design/agent-hub.md +52 -0
  11. package/docs/design/bus.md +48 -0
  12. package/docs/design/task-board.md +86 -0
  13. package/docs/dogfood.md +19 -2
  14. package/docs/operations.md +337 -15
  15. package/docs/profiles.md +2 -0
  16. package/docs/quickstart.md +15 -3
  17. package/docs/sdlc.md +4 -4
  18. package/docs/security.md +9 -4
  19. package/docs/smoke.md +2 -0
  20. package/docs/specs/2026-09-19-agent-hub-design.md +3 -1
  21. package/docs/specs/2026-11-01-research-campaigns-design.md +12 -1
  22. package/docs/verification/2026-10-31-codex-0166-reviewer-isolation.md +2 -0
  23. package/docs/verification/2026-11-01-0.27.0.md +49 -0
  24. package/docs/verification/2026-11-02-0.28.0.md +54 -0
  25. package/docs/verification/2026-11-02-autonomy-t4.md +39 -0
  26. package/docs/verification/2026-11-02-codex-0166-reviewer-tool-call.md +53 -0
  27. package/docs/verification/2026-11-02-control-write-after.json +139 -0
  28. package/docs/verification/2026-11-02-control-write-baseline.json +127 -0
  29. package/docs/verification/2026-11-02-control-write-guarded.json +127 -0
  30. package/docs/verification/2026-11-02-control-write-outcomes.md +65 -0
  31. package/docs/verification/2026-11-02-orca-1.4.245-cli-contract.md +51 -0
  32. package/docs/verified.json +13 -13
  33. package/package.json +2 -2
  34. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  35. package/plugins/agent-hub/server.js +344 -116
  36. package/src/adapters/claude-channel.ts +12 -2
  37. package/src/adapters/compat.ts +1 -1
  38. package/src/adapters/definitions/native-cli-claude-setup.ts +31 -9
  39. package/src/adapters/definitions/native-cli-entry-jcode.ts +33 -0
  40. package/src/adapters/definitions/native-cli-entry-qwen.ts +2 -2
  41. package/src/adapters/jcode.ts +37 -4
  42. package/src/adapters/qwen-dual.ts +3 -2
  43. package/src/cli/agents.ts +4 -2
  44. package/src/cli/bench.ts +4 -2
  45. package/src/cli/board-read.ts +25 -0
  46. package/src/cli/claude-homes.ts +2 -2
  47. package/src/cli/console-state.ts +8 -3
  48. package/src/cli/help.ts +8 -6
  49. package/src/cli/identity.ts +14 -6
  50. package/src/cli/init-prompt.ts +179 -0
  51. package/src/cli/init-settings.ts +229 -0
  52. package/src/cli/init.ts +102 -9
  53. package/src/cli/launch.ts +3 -1
  54. package/src/cli/main.ts +112 -36
  55. package/src/cli/output.ts +14 -0
  56. package/src/cli/setup-homes.ts +18 -3
  57. package/src/cli/specs.ts +150 -0
  58. package/src/cli/study-output.ts +56 -0
  59. package/src/cli/study.ts +26 -3
  60. package/src/cli/terminal-recovery.ts +35 -11
  61. package/src/hub/action-policy.ts +5 -3
  62. package/src/hub/board.ts +56 -3
  63. package/src/hub/bus.ts +54 -7
  64. package/src/hub/child-process.ts +6 -4
  65. package/src/hub/config-apply.ts +4 -1
  66. package/src/hub/config-edit.ts +1 -1
  67. package/src/hub/config-tier.ts +1 -0
  68. package/src/hub/control-client.ts +28 -4
  69. package/src/hub/cost-governance.ts +22 -6
  70. package/src/hub/crash.ts +20 -0
  71. package/src/hub/daemon.ts +324 -64
  72. package/src/hub/delivery-hints.ts +6 -3
  73. package/src/hub/delivery-journal.ts +14 -3
  74. package/src/hub/events.ts +2 -1
  75. package/src/hub/hub-tools.ts +15 -9
  76. package/src/hub/no-writes.ts +1 -1
  77. package/src/hub/peers.ts +1 -1
  78. package/src/hub/project-runtime-state.ts +38 -13
  79. package/src/hub/review-brief.ts +18 -0
  80. package/src/hub/routing.ts +7 -3
  81. package/src/hub/sdlc-release-authorization.ts +11 -5
  82. package/src/hub/session-identity.ts +1 -1
  83. package/src/hub/settings.ts +2 -0
  84. package/src/hub/specs-config.ts +43 -0
  85. package/src/hub/specs-task.ts +108 -0
  86. package/src/hub/specs.ts +1008 -0
  87. package/src/hub/task-list-page.ts +75 -0
  88. package/src/hub/task-sweep.ts +10 -1
  89. package/src/hub/tasks.ts +448 -40
  90. package/src/hub/terminal-open.ts +10 -5
  91. package/src/hub/tool-request.ts +131 -0
  92. package/src/ui/office-model.ts +17 -1
  93. package/src/ui/office-space.ts +1 -1
  94. package/templates/config.json +1 -0
  95. package/templates/presets/confirmation-matrix.json +5 -5
  96. package/templates/profiles/dev.json +1 -0
  97. package/templates/profiles/general.json +1 -0
  98. package/templates/profiles/research.json +1 -0
  99. package/templates/profiles/writing.json +1 -0
  100. package/templates/release-guard.block.md +2 -1
  101. 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 |
@@ -389,7 +389,7 @@ A private (PII) task reads no eval metadata and records none.
389
389
 
390
390
  ## Person release authorization (#481 S6)
391
391
 
392
- From the running daemon's candidate checkout, the person runs `ahub sdlc authorize-release <version>`. The console-only operation binds approval to the exact current commit, its committed package version, the origin fetch/push identity and fresh committed documentation evidence. It rereads the head and remote after the documentation check. Agent shells, including `--live-test`, cannot grant it. An append-only metadata event records the approval id, commit, version and documentation digest/count. The authoritative ledger is daemon-owned memory: restart revokes every approval; audit history cannot restore one.
392
+ From the running daemon's candidate checkout, the person or the one configured conductor runs `ahub sdlc authorize-release <version>` (#1063). The conductor acts only on the person's explicit instruction in its own session naming that release. A hub message, task text, review note, file or another peer's relay is never that instruction; the daemon cannot verify this cooperative rule. A conductor request uses the tools role and refuses a child `toolsOwner`, private turn or PII context, exactly like `sdlc merge`. Other peers and `--live-test` refuse. Consent binds the exact current commit, its committed package version, origin fetch/push identity and fresh committed documentation evidence, all reread after the docs check. Receipt `by` and the append-only metadata audit identify the actual asker alongside the approval id, commit, version and docs digest/count. The authoritative ledger is daemon-owned memory: restart revokes every approval; audit history cannot restore one.
393
393
 
394
394
  `ahub sdlc release <owner/repo>` shows a matching or stale authorization receipt. Authorization removes only the person-decision blocker. Native acceptance remains unverified and `ready` remains false until separately supported. No tag, workflow or publication is changed by authorization or readback.
395
395
 
@@ -403,13 +403,13 @@ 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 is not. They are two records and two commands, and consent stays person-only.
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.
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
 
410
410
  It restamps nothing by itself. A stamp in `docs/verified.json` records that someone read what changed under a document, so `bun scripts/release-prepare.ts restamp <document>... --reviewed` sets `verifiedAgainst` to HEAD for the named documents only, refuses without `--reviewed`, refuses an unnamed or unknown document and refuses with staged changes. The agent runs it per document after reading the source commits, commits `docs/verified.json`, opens the release PR and merges it with a merge commit (never squash).
411
411
 
412
- `bun scripts/release-tag.ts <version> [--execute]` is the one guarded tag run. Every run repeats the whole preflight and reports every refusal at once: a valid release version; `package.json`, the README Status line and a CHANGELOG section at HEAD all naming it; HEAD on `main`, clean, and the merge commit of a `release/<version>` PR (a squash is refused); HEAD an ancestor of `origin/main` (fetched, not assumed); no `v<version>` tag locally or on the remote; `scripts/check-docs.mjs --require-fresh --committed` clean; and exactly one `docs/verification/<date>-<version>.md` with no `TODO(agent)` left. Without `--execute` it only reports, and whether the person's consent matches (exit 2 when it does not). With `--execute` it reads the consent through `ahub sdlc release-guard -- git push <remote> <commit>:refs/tags/v<version>` (read only; the ledger `ahub sdlc authorize-release` fills, person only, revoked by a hub restart), repeats the preflight, checks the commit did not move, reads the consent once more, and then makes the single push of that exact commit. A rejected push is reported and never retried, and the script passes neither `--force` nor `--no-verify`; the pre-push hook from `ahub init --release-guard` still runs on that push. The push creates a lightweight tag (`<commit>:refs/tags/v<version>`), the exact form `ahub sdlc release-guard` parses and the consent receipt binds; the repository's tags are mixed (v0.19.0 and v0.18.0 are annotated, v0.17.0 is not) and `.github/workflows/release.yml` accepts either (`v*`, then `--verify-tag`), so this is a convention difference, not a gap. If the project wants annotated release tags, create the tag object first and push the tag ref, which the guard also accepts (its source object is peeled to the commit); that is a later change to this script. `AHUB_RELEASE_ROOT` points both scripts at a checkout other than the one they live in (the tests use it so nothing outside a scratch repository is touched). Nothing here calls `authorize-release`, and no agent shell can: the report only names the command. Publication (npm, the GitHub release) stays with the tag-triggered workflow, which has its own gate (`.github/workflows/release.yml`).
412
+ `bun scripts/release-tag.ts <version> [--execute]` is the one guarded tag run. Every run repeats the whole preflight and reports every refusal at once: a valid release version; `package.json`, the README Status line and a CHANGELOG section at HEAD all naming it; HEAD on `main`, clean, and the merge commit of a `release/<version>` PR (a squash is refused); HEAD an ancestor of `origin/main` (fetched, not assumed); no `v<version>` tag locally or on the remote; `scripts/check-docs.mjs --require-fresh --committed` clean; and exactly one `docs/verification/<date>-<version>.md` with no `TODO(agent)` left. Without `--execute` it only reports, and whether the person's consent matches (exit 2 when it does not). With `--execute` it reads the consent through `ahub sdlc release-guard -- git push <remote> <commit>:refs/tags/v<version>` (read only; the ledger `ahub sdlc authorize-release` fills from the person or the explicitly instructed configured conductor, revoked by a hub restart), repeats the preflight, checks the commit did not move, reads the consent once more, and then makes the single push of that exact commit. A rejected push is reported and never retried, and the script passes neither `--force` nor `--no-verify`; the pre-push hook from `ahub init --release-guard` still runs on that push. The push creates a lightweight tag (`<commit>:refs/tags/v<version>`), the exact form `ahub sdlc release-guard` parses and the consent receipt binds; the repository's tags are mixed (v0.19.0 and v0.18.0 are annotated, v0.17.0 is not) and `.github/workflows/release.yml` accepts either (`v*`, then `--verify-tag`), so this is a convention difference, not a gap. If the project wants annotated release tags, create the tag object first and push the tag ref, which the guard also accepts (its source object is peeled to the commit); that is a later change to this script. `AHUB_RELEASE_ROOT` points both scripts at a checkout other than the one they live in (the tests use it so nothing outside a scratch repository is touched). Neither script calls `authorize-release`: the report only names the command; the person or the explicitly instructed configured conductor records consent separately. Publication (npm, the GitHub release) stays with the tag-triggered workflow, which has its own gate (`.github/workflows/release.yml`).
413
413
 
414
414
  The scripts and their pure helpers live in `scripts/release-prepare.ts`, `scripts/release-tag.ts` and `scripts/lib/release-plan.ts`; they are maintainer tooling and are not part of the published package. The deterministic recovery barriers of #787 AC3 are not needed by either leg and are not part of this change.
415
415
 
package/docs/security.md CHANGED
@@ -6,6 +6,7 @@ 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).
9
10
  - **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
11
  - **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
12
  - **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.
@@ -385,7 +386,7 @@ and flag. The current daemon emits `agent_cli` with `delegated: true` and
385
386
  `refused: false` for the negotiated outcome. Allowed-class commands retain the peer identity and capability checks, including
386
387
  messages, proposals and reviews. Peer starts, pause and resume may delegate
387
388
  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,
389
+ 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
390
  `ahub recovery reattach`, a `--fresh-session` dispose that would replace a repaired
390
391
  session's conversation (or whose scope cannot be read), and the pet
391
392
  composer are refused; presentation flags such as `--color` or `--verbose` before
@@ -793,9 +794,9 @@ The `planner` setting is person-controlled: one peer id or a list of up to eight
793
794
 
794
795
  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
796
 
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/hub completion of an uncertain delivery is not evidence that the offer was read.
797
+ 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
798
 
798
- `hub_delivery_retry` grants an eligible recipient one retry of its own `needs_review` work, never completion/discard authority or pause removal. 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
+ `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
800
 
800
801
  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
802
 
@@ -819,10 +820,14 @@ The review brief (#520) withholds private changes whole (both sides of a move) a
819
820
 
820
821
  Deliverable records (#509a). `hub_task_done` and `hub_sdlc_record` name files as `{path, format, version?}`; the hub hashes them itself and refuses a claimed `sha256`, `hash` or `bytes` and any field it does not own. Paths resolve under the owner's execution root with `realPath` and `guardPath` in read mode: outside the project, the secrets denylist, the hub's own state (`.git`, `.agenthub`), a dangling link, a non-regular file and more than 256 MiB each or 512 MiB together are refused, with the path as given and never a resolved one. The file is opened without following a final link and its device, inode, size and time are compared with what was checked, before and after the read, so a swapped or changing file is refused rather than recorded half-read; a bad call writes nothing. A declared worktree instance whose root is not proven refuses, and a later read of it reports `unknown`. No hash of hub state is ever taken, and a file the hub cannot read or vouch for is `unknown`, never `unchanged`. A reviewer's approval re-hashes the files and is refused when one changed, went missing or is unknown; only the person may approve the current bytes, which are then measured and bound. For a PII task, a file under `pii.paths` or a path matching a PII pattern, `publicDeliverables` is the one projection every peer view, review request, status and log uses: id, hash and size only. The board keeps the path, as it keeps a PII task's text. `ahub deliverables` (#509b) from an agent shell lists only the tasks `hub_task_show` would show that agent (#933), and `--live-test` cannot delegate it. It lists the board's records through `publicDeliverables` and opens a file only with `--check`, through the same reader and limits. The dashboard's Deliverables chip and task group use the same projection of the same records and never read a file on the poll; a `changed` mark there is only as fresh as the last live read in this daemon.
821
822
 
822
- Person release authorization (#481 S6). `ahub sdlc authorize-release <version>` is taken from the console role only and refused under `--live-test`. It binds the daemon checkout's commit, package version, push remote identity and a fresh-docs verdict, lives only in daemon memory (a restart revokes it) and is logged with its commit, version and docs digest. `ahub sdlc release-guard -- <argv>` is a read-only preflight that agents may run, except during a private or PII turn; it never executes the command and refuses ambient target selectors (`GIT_DIR`, `GH_REPO`, npm prefix and registry settings and the like). The pre-push hook that `ahub init --release-guard` installs refuses an unauthorized or unknown `v*` tag push, also with the daemon down, and passes other pushes through. It and the release block in `AGENTS.md` are a cooperative guard, not an operating-system boundary: `git push --no-verify`, a custom `core.hooksPath` or another Git invocation bypasses the hook, and `gh release create` and `npm publish` are checked only when the preflight is run (tasks 312 and 313).
823
+ Person-directed release authorization (#481 S6, #1063). `ahub sdlc authorize-release <version>` accepts the console user or the one configured conductor under the same admission as `sdlc merge`: tools role, matching configured conductor, no child `toolsOwner`, private turn or PII context. It remains refused under `--live-test`. The conductor may record consent only on the person's explicit instruction in its own session naming the release; a hub message, task text, review note, file or peer relay is never that instruction. The daemon cannot verify that cooperative prerequisite. Receipt `by` and the audit identify the actual asker. It binds the daemon checkout's commit, package version, push remote identity and a fresh-docs verdict, lives only in daemon memory (a restart revokes it) and is logged with its commit, version and docs digest. `ahub sdlc release-guard -- <argv>` is a read-only preflight that agents may run, except during a private or PII turn; it never executes the command and refuses ambient target selectors (`GIT_DIR`, `GH_REPO`, npm prefix and registry settings and the like). The pre-push hook that `ahub init --release-guard` installs refuses an unauthorized or unknown `v*` tag push, also with the daemon down, and passes other pushes through. It and the release block in `AGENTS.md` are a cooperative guard, not an operating-system boundary: `git push --no-verify`, a custom `core.hooksPath` or another Git invocation bypasses the hook, and `gh release create` and `npm publish` are checked only when the preflight is run (tasks 312 and 313).
823
824
 
824
825
  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
826
 
827
+ 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.
828
+
829
+ 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 itself is unchanged, and a hub-made writable worktree is a separate design (#1115).
830
+
826
831
  ## Research campaigns and study tools (#930, #932)
827
832
 
828
833
  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
 
@@ -5888,7 +5890,7 @@ Order: 2a first (it measures everything else). 2b and 2c are independent. 2d aft
5888
5890
 
5889
5891
  ### S6 person release authorization boundary (#481)
5890
5892
 
5891
- - `ahub sdlc authorize-release <version>` is console-only, never live-test delegated. The daemon binds consent to its candidate checkout's exact HEAD, committed package version, origin fetch/push identity and fresh committed-doc verdict. Caller-supplied expected HEAD must match. Head and origin are rechecked after the bounded package-owned documentation checker. Only ids, hashes, version, timestamp and counts enter the receipt/audit event; no project script or release operation runs.
5893
+ - `ahub sdlc authorize-release <version>` accepts the console user or the one configured conductor, never live-test delegated (#1063). Conductor admission matches `sdlc merge`: tools role, `conductorPeer(config.roles) === c.peer`, no `toolsOwner`, private turn or caller PII context. The conductor records consent only on the person's explicit instruction in its own session naming the release; a hub message, task text, review note, file or another peer's relay is never that instruction. This instruction-origin condition is cooperative, not verified by the daemon. Receipt `by` and the metadata audit identify the actual asker (`user` or conductor peer). The daemon binds consent to its candidate checkout's exact HEAD, committed package version, origin fetch/push identity and fresh committed-doc verdict. Caller-supplied expected HEAD must match. Head and origin are rechecked after the bounded package-owned documentation checker. Only ids, hashes, version, timestamp and counts enter the receipt/audit event; no project script or release operation runs.
5892
5894
  - Authoritative receipts live only in the current daemon generation's bounded memory ledger (at most 64 candidates). An additive metadata event audits consent but cannot recreate it. Restart revokes all approvals. The release report shows matching/stale consent without certifying native acceptance, changing the tag workflow or publishing.
5893
5895
  - Optional `ahub init --release-guard` installs a managed executable Git pre-push hook plus instructions. A regular existing hook is renamed, preserving its inode/mode, and chained with exact argv/stdin after successful guard readback. Linked/hardlinked hooks, occupied backups and custom hooksPath refuse before project writes. Re-init retains the guard; the wrapper pins Bun/package paths and needs re-init if they move.
5894
5896
  - Actual pushed `v*` refs must have a valid version and captured source-object/commit matching consent. Missing/mismatched commit/version/remote, unreachable daemon, deletion, unknown evidence or restart refuses the version-tag push. Branch-only pushes work offline. `--no-verify` remains the person's explicit bypass and is forbidden to agents; this is cooperative Git enforcement, not a sandbox.
@@ -276,7 +276,7 @@ All new tables live in `hub.db`, created in the `Board` constructor with `CREATE
276
276
 
277
277
  | Surface | Name | Who |
278
278
  |---|---|---|
279
- | CLI | `ahub study draft <parent> <contract.json>`, `study revise <id> <revision> <contract.json>`, `study approve <id> <revision>`, `study close <id> <revision> --reason`, `study show [<id> | --after <id>] [--json]`, `study experiments [--campaign <id>] [--json]`, `study attest <attempt> <field> <value>`, `study receipt <file>` | approve, attest and receipt are person only; draft and revise are person or planner; show is anyone |
279
+ | CLI | `ahub study draft <parent> <contract.json>`, `study revise <id> <revision> <contract.json>`, `study approve <id> <revision>`, `study close <id> <revision> --reason`, `study show [<id> | --after <id>] [--json]`, `study experiments (--campaign <id> [--after <n>] | --attempt <ra-id> | --plan <hash> --baseline <ra-id> --variant <ra-id>) [--json]`, `study attest <attempt> <field> <value>`, `study receipt <file>` | approve, attest and receipt are person only; draft and revise are person or planner; show and experiments are anyone. `experiments` ships in #602 in exactly those three closed forms; `attest` and `receipt` are not built yet (see the #602 row) |
280
280
  | Hub tools | `hub_study_draft` and `hub_study_revise` (configured planner only, through `planningAuthority`; they store drafts and never approve), `hub_study_show` (read-only; no id lists this project's campaigns as receipts, one page of at most 50 as `{ campaigns, next? }`, and `after` continues from the `next` of the previous page), `hub_study_handoff` (bound task owner), `hub_experiment_record` (`kind`: `protocol`, `plan`, `attempt`, `event` or `receipt`; task owner), `hub_experiment_show` (read-only) | none of them approves or attests |
281
281
  | CLI (person only) | `ahub study approve-protocol <hash>` | person |
282
282
  | Control | `study` (console role, CLI only) | person |
@@ -299,6 +299,17 @@ Each slice amends this spec in its own PR if it must differ, and updates `docs/d
299
299
  | #601 | #930 T3, AC5 and AC6 | `ahub study` draft, revise, approve, close and show; `hub_study_draft`, `hub_study_revise`, `hub_study_show` and `hub_study_handoff`; the privacy stubs; role guidance in `templates/`; the three-source, two-peer example |
300
300
  | #602 | #932 T3, AC5 and AC6 | `ahub study experiments`, `attest` and `receipt`; `hub_experiment_show`; the synthetic CPU-only fixture; the rerun checklist in `docs/profiles.md` |
301
301
 
302
+ **As built in the #602 PR (amended here, because the build differs from this row).** Built: `ahub study experiments` in its three closed forms, the read-only `hub_experiment_show` (a read for every local peer, in `STUDY_TOOLS`, the read-only tool lists and `SESSION_READ_OPS`), the synthetic CPU-only fixture `test/research-experiments-fixture.test.ts`, and the person-authored rerun checklist, which lives in `docs/operations.md` ("Experiment readback") with a pointer from `docs/profiles.md`. Not built, and not needed for AC5 or AC6: `ahub study attest`, `ahub study receipt` and the `hub_experiment_record` tool. `Tasks.experimentRecord` and its receipt kind exist and are tested, but no tool, daemon case or CLI calls them yet, so until that slice lands the readback shows only what a test or a later slice recorded. Each of those writers needs its own authority review (person-only attest and receipt, task-owner record) and is a separate change.
303
+
304
+ **Task 615 record relay.** `hub_experiment_record` passes the whole inert envelope to
305
+ `Tasks.experimentRecord` with the authenticated caller identity. Its five existing kinds are `protocol`,
306
+ `plan`, `attempt`, `event` and `receipt`. Ordinary records require the current in-progress owner of a bound
307
+ unit in the current approved campaign; the person may relay a signed runner receipt through the existing
308
+ `USER` branch. This is not a new attestation or approval authority. All PII turns refuse before dispatch,
309
+ read-only callers cannot mutate, and arguments/results are excluded from hub-managed memory capture.
310
+ The relay returns the method's bounded record metadata only and performs no execution, signing or
311
+ verification itself. `ahub study attest` and `ahub study receipt` remain separate, unimplemented forms.
312
+
302
313
  ## Departures from the issues
303
314
 
304
315
  - Runner registration is person only in V1. #1018 proposed "the person or conductor". A public key is a trust root, so the conductor path is deferred until a reviewed change gives it the same confirmation as other trust settings.
@@ -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,49 @@
1
+ # 0.27.0 release verification
2
+
3
+ This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.27.0 and no live TUI launch.
4
+
5
+ ## Candidate
6
+
7
+ Version 0.27.0, prepared from main de08b8e1 (4 commits since v0.26.0, 3 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.26.0: #1066, #1062, #1061, #1059.
12
+
13
+ Each merged after a claude `hub_review` approval with exact-head CI green, no unresolved review thread and no pending change request:
14
+
15
+ - #1059 (task 602, experiment readback): approved at c10a509f, exact-head CI run 41313240639. One nit (the spec's as-built note could name task 615) left open; #1062 then named it.
16
+ - #1061 (task 616, runtime.json read retried only when the file was replaced): approved after exact-head CI run 41318247416 at 636fe45f. The board bound the approval to 6c6dfeff, because hub 0.23.1 refuses an in_review re-file; the verdict note names the one-line CHANGELOG delta to 636fe45f.
17
+ - #1062 (task 615, `hub_experiment_record`): approved at 66b76a8e, run 41322472076.
18
+ - #1066 (task 617, conductor-recorded release consent, #1063): approved at 6f3b2dfc, run 41341091037. The first head 5f12dec3 failed CI on two assertions of wording #1063 changed (run 41339855105); the reviewer ruled that exactly those two be updated to the new text, and the delta to 6f3b2dfc is those two lines.
19
+
20
+ ## Native acceptance receipts
21
+
22
+ Receipts added under `docs/verification/` since v0.26.0: none.
23
+
24
+ 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.27.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.
25
+
26
+ ## Document review
27
+
28
+ Stale at preparation (`node scripts/check-docs.mjs`): README.md, docs/agent-notes/{adapters,budget,bus,daemon,tasks,tests}.md, docs/operations.md, docs/quickstart.md, docs/security.md and src/cli/help.ts; docs/agent-notes/README.md became stale after the daemon.md edit. The conductor read each against the diff of its covered sources since v0.26.0 (#1059, #1061, #1062, #1066) and found:
29
+
30
+ - src/cli/help.ts: `ahub study experiments` (three closed forms) shipped in #1059 without a help row; added. Every other form in `ahub help` still matches `src/cli/main.ts`, `src/cli/study.ts` and `src/cli/launch.ts`; the `sdlc authorize-release` row was already updated by #1066.
31
+ - docs/agent-notes/daemon.md: the `ahub study` note now names `experiments` as an allowed read form beside `show`.
32
+ - docs/quickstart.md: the v0.27.0 install tag and a new "Upgrading to 0.27.0" section (instructed release consent, experiment read and record, the runtime.json race fix, and updating the global CLI and plugin by hand as in 0.26.0).
33
+ - README.md: the report link, and one sentence on experiment record and readback under Research campaigns.
34
+ - docs/operations.md: the guide header (0.27.0) and the protocol-window table row (0.26.0 through 0.27.0, unchanged window 16 through 17). The experiment and release-approval sections were already updated by #1059, #1062 and #1066.
35
+ - docs/security.md, docs/agent-notes/{tasks,tests}.md: already current (#1066 updated the release-authorization paragraphs; tasks.md names both experiment tools). adapters.md, budget.md, bus.md and agent-notes/README.md: stale only through covered daemon.ts or note paths; nothing in them describes the changed behavior.
36
+
37
+ All twelve were restamped with `--reviewed` at the release branch head that holds these edits.
38
+
39
+ ## Checks
40
+
41
+ - `node scripts/check-docs.mjs --require-fresh`: `docs: OK (0 stale documents)` on the release branch.
42
+ - `bun test test/help.test.ts test/completion.test.ts` after the help row: 24 pass, 0 fail.
43
+ - `bun x tsc --noEmit`, `bun scripts/build.mjs --check` and `node scripts/check-package.mjs`: run by the release PR's exact-head CI, together with the full suite on ubuntu and macOS and the seeded guards (heavy checks run only on CI or dgx02 on this machine).
44
+
45
+ ## Known gaps, not blocking
46
+
47
+ - No installation and no running-hub upgrade to 0.27.0 is claimed here. The running hub on this machine is 0.23.1, so the conductor-recorded consent of #1063 is not live yet; this release's consent is the person's own `ahub sdlc authorize-release 0.27.0`.
48
+ - No live receipt for `hub_experiment_record` or the instructed-consent path; both are covered by daemon-level tests only.
49
+ - Issue #418 was closed with its managed-Pi live leg waived (owner decision 2026-11-02); a post-close Pi smoke on hub 0.23.1 (tasks 618, 619) passed spec read, memory read and one remote isolated check, Linux evidence only.
@@ -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
+ }