@staix/agent-hub 0.17.0 → 0.18.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 (68) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -2
  3. package/docs/agent-notes/README.md +5 -0
  4. package/docs/agent-notes/adapters.md +2 -0
  5. package/docs/agent-notes/benchmarks.md +1 -0
  6. package/docs/agent-notes/daemon.md +1 -0
  7. package/docs/agent-notes/local-worker.md +1 -0
  8. package/docs/agent-notes/tasks.md +7 -1
  9. package/docs/agent-notes/tests.md +1 -0
  10. package/docs/dogfood.md +15 -1
  11. package/docs/memory.md +1 -1
  12. package/docs/operations.md +105 -16
  13. package/docs/profiles.md +36 -0
  14. package/docs/quickstart.md +9 -3
  15. package/docs/sdlc.md +29 -3
  16. package/docs/security.md +26 -4
  17. package/docs/specs/2026-09-19-agent-hub-design.md +16 -6
  18. package/docs/verification/2026-10-25-0.18.0.md +76 -0
  19. package/docs/verification/2026-10-25-codex-review-live-verdict.md +35 -0
  20. package/docs/verification/2026-10-25-remote-docker-transport.md +46 -0
  21. package/docs/verification/profiles/YYYY-MM-DD-general.md +46 -0
  22. package/docs/verification/profiles/YYYY-MM-DD-research.md +61 -0
  23. package/docs/verification/profiles/YYYY-MM-DD-writing.md +46 -0
  24. package/docs/verified.json +24 -18
  25. package/package.json +2 -2
  26. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  27. package/plugins/agent-hub/server.js +94 -33
  28. package/src/adapters/definitions/builtin-metadata.ts +1 -1
  29. package/src/adapters/local-worker.ts +5 -3
  30. package/src/cli/console-state.ts +9 -2
  31. package/src/cli/help.ts +29 -28
  32. package/src/cli/identity.ts +87 -6
  33. package/src/cli/main.ts +190 -69
  34. package/src/cli/output.ts +7 -2
  35. package/src/cli/sdlc-output.ts +242 -0
  36. package/src/cli/task-output.ts +212 -0
  37. package/src/cli/upgrade-output.ts +57 -0
  38. package/src/hub/board.ts +17 -0
  39. package/src/hub/check-runner.ts +252 -22
  40. package/src/hub/conductor.ts +5 -0
  41. package/src/hub/config-apply.ts +16 -7
  42. package/src/hub/config-edit-host.ts +1 -1
  43. package/src/hub/config-tier.ts +1 -1
  44. package/src/hub/daemon.ts +353 -72
  45. package/src/hub/dogfood-profile.ts +248 -0
  46. package/src/hub/dogfood-read.ts +77 -14
  47. package/src/hub/dogfood.ts +5 -1
  48. package/src/hub/events.ts +1 -1
  49. package/src/hub/host-executable.ts +2 -1
  50. package/src/hub/hub-tools.ts +2 -2
  51. package/src/hub/operational-authority.ts +60 -0
  52. package/src/hub/operational-view.ts +141 -0
  53. package/src/hub/orphan-process.ts +69 -0
  54. package/src/hub/permission-mode.ts +1 -1
  55. package/src/hub/read-only-shell-proof.ts +80 -0
  56. package/src/hub/read-only-shell.ts +162 -0
  57. package/src/hub/reviewer-pool-config.ts +3 -2
  58. package/src/hub/reviewer-pool.ts +3 -0
  59. package/src/hub/routing.ts +23 -6
  60. package/src/hub/sdlc-merge.ts +299 -0
  61. package/src/hub/sdlc-mirror.ts +129 -0
  62. package/src/hub/sdlc.ts +58 -12
  63. package/src/hub/settings.ts +11 -5
  64. package/src/hub/snapshots.ts +60 -0
  65. package/src/hub/task-repository.ts +31 -5
  66. package/src/hub/tasks.ts +241 -16
  67. package/src/local/tools.ts +17 -4
  68. package/src/ui/index.html +2 -1
package/docs/profiles.md CHANGED
@@ -56,3 +56,39 @@
56
56
  - `role_text` is bounded guidance for existing flow roles (2000 characters each); it grants no authority. `catalog_roles` supplies bounded compatible guidance ids; the existing explicit catalog selections take precedence. Actual flow maps remain in `roles` and retain their existing validation.
57
57
  - `agents` replaces only the managed AGENTS block (16000 characters maximum); surrounding instructions remain. Init previews contain paths/actions only. `example_checks` is at most 16 display strings of 2000 characters, shown as advisory examples by init and never selected as executable checks. `review_checklist` is at most 16 non-empty strings of 500 characters, customizing the checklist items in review requests with `{target}` and `{check}` interpolations. Existing `checks` trust remains authoritative.
58
58
  - No override mutates shipped profile data or another project. Unknown fields, base remapping and invalid/oversized data are refused. Headers are quoted. Daemon/MCP restart is required for config changes; no native model consumption or research measurement is claimed.
59
+
60
+ # Profile scorecard (#799)
61
+
62
+ The existing ahub report --dogfood command adds a profile section when the selected profile is non-dev, or bound non-dev tasks have evidence in the requested window. Dev-only JSON and readable output retain their prior bytes. Existing flow, quality, cost and other fields keep their meanings; the profile section does not require merged PRs.
63
+
64
+ Rows include profile totals and class-alias groups with the stored base class. A task keeps its recorded profile across later configuration changes. Public custom aliases remain bounded identifiers; private custom aliases are withheld. Task titles, paths, notes, checklist prose and model text are not exported. Private pii/pii_path tasks are counted by id and number.
65
+
66
+ A missing, incomplete or unsupported source produces JSON null, rendered as unknown in the readable report. A complete source can prove zero recorded events; it cannot prove zero events for a category that has no recorder. Source completeness and flow scope distinguish history-backed totals from recorded-window observations. Profile bindings, including event-only fallback, are capped at 500; a capped window reports incomplete/unknown totals rather than extrapolating. Automatic approvals are flow transitions, not reviewer rounds or first-pass review samples.
67
+
68
+ | Row group | Existing evidence | Unmeasured ceiling |
69
+ | --- | --- | --- |
70
+ | Flow | Bound task history and complete task-event windows; observed automatic approvals | Undated approvals, incomplete history and first-pass review without history remain unknown |
71
+ | Review | Explicit verdicts and structured public unmet-criteria ids | Profile checklist prose has no item-id recorder; private criterion ids are withheld |
72
+ | Overlap | Recorded path/section notices and later matching pair/path edit facts | Observed path-edit pairs imply no authorship or causation; section edit confirmation remains unknown |
73
+ | Deliverables | Deduplicated ids in recorded deliverable histories | No new file reads; changed-since-approval and current unknown states remain unknown |
74
+ | Privacy | Private task flags and generic attributed PII note-screen records | Screen records do not identify the operation; memory drops, refusals and capture totals remain unknown without operation-specific counters |
75
+ | Undo | No additional recorder introduced | Request, completion and guard-refusal totals remain unknown |
76
+ | Snapshots | Already-recorded, attributed snapshot durations | No new recording; budget exhaustion and absent durations remain unknown |
77
+ | Profile errors | No additional recorder introduced | Unknown/foreign alias-refusal totals remain unknown |
78
+ | Cost | Existing task-attributed token/usage summaries | Missing usage and attribution remain unknown; no provider/model prose is exported |
79
+
80
+ Research rows also expose bounded current-plan source and claim counts per task. Claim slots are anonymous ordinal numbers; declaration text and identifiers are never exported. In a stored board plan a key the plan omits counts as zero declarations, as an explicit empty list does; a cut or malformed plan leaves that one task's declarations unknown without affecting the rest of the board. These are current-plan counts, not a reconstruction of past plans.
81
+
82
+ Each research class alias retains its own recorded task-check pass/fail counts under `observedCheckOutcomes`. Those history events do not record which check key ran. Consequently `factCheck` pass/fail, check selection and missing-key counts per run remain unknown until that provenance is recorded. No new telemetry is collected. Model labels, person verdicts, claims reaching a person verdict and per-label agreement also remain unknown because no claim-level verdict source exists. Task approval never supplies a claim verdict. Research uses the same recorded section-overlap rows as writing.
83
+
84
+ The weekly writing, general and research receipt templates are in the verification/profiles directory. Copy only the emitted profile subsection, preserve null values, and include no project/person names or paths. A template is not a completed measurement or a live acceptance claim.
85
+
86
+ The following verification claim ids collect the still-unverified statements above. A weekly receipt gives each a verdict of supported, partly supported or not supported, tied to recorded ids and remaining unknowns. Profile counts alone do not prove native ingestion, context retention or account acceptance; those verdicts need corresponding native/account receipt ids and independent judgment. None becomes verified merely because this reporting section exists:
87
+
88
+ - writing-live-example: an observed writing workflow.
89
+ - general-live-example: an observed general workflow.
90
+ - research-live-example: the live three-source/two-agent research example.
91
+ - native-model-ingestion: native peers consuming profile guidance and tasks.
92
+ - context-retention: profile/task context retained through the relevant native turns.
93
+ - native-account-research: a real native/model/account research workflow.
94
+ - research-measurement: observed research-profile measurements.
@@ -17,7 +17,7 @@ ahub setup # installs the Claude Code channel plu
17
17
  Or use the matching GitHub release:
18
18
 
19
19
  ```bash
20
- bun add -g github:STAIxBWLB/agent-hub#v0.17.0
20
+ bun add -g github:STAIxBWLB/agent-hub#v0.18.0
21
21
  ahub setup
22
22
  ```
23
23
 
@@ -30,6 +30,12 @@ and upgrade or crash recovery, see the [operations guide](operations.md). To
30
30
  move running projects to a newer release later, run `ahub upgrade` in a
31
31
  terminal: it reviews the plan with you, applies it and follows it.
32
32
 
33
+ ## Upgrading to 0.18.0
34
+
35
+ The `ahub sdlc` read commands (`status`, `explain`, `queue`, `release`, `metrics`, `costs`, `authorize-release`) now print readable output by default, no longer a JSON document (#814). A script that parses their output must pass `--json`: it prints exactly what the command printed before. `sdlc export` stays JSON. `restart` and `upgrade` off a terminal (a pipe or `--dry-run`), `recovery status` and its results, `models setup|start`, `queue resolve` and `budget execution configure|disable` follow (#814): pass `--json` for the old document. `task show|cancel`, `backlog groom|return|plan|pin|split|undo|pull-ready` and `release list|show|new|plan|activate|freeze|ship|drop` follow (#814): pass `--json` for the hub tool's text. More commands follow in later releases.
36
+
37
+ Agents can now run the read-only `ahub` forms themselves (`doctor`, `projects`, `models status`, `recovery status`, `queue list`, `roster`, `settings` reads, `sdlc status|explain|queue|release`, `release show` and the `--dry-run` previews of `upgrade` and `restart`), and the configured conductor can run `stop`, `queue show|resolve|discard`, `task cancel`, `roster add|remove`, `logs`, `export`, `doctor --orphans --kill` and `settings set` on twelve live keys (#812). Nothing changes for a person's terminal. `sdlc.toml` gains `auto_merge` (`off` by default): set `dry-run` to see what the guarded merge and the one-per-verdict GitHub COMMENT review would do before setting `on` (#786). `review.same_family = "never"` keeps a same-family reviewer from being assigned (#820). In `ask-when-needed`, Pi and the local worker run proven bounded read-only shell commands without asking (#816). The isolated remote Docker check runner is opt-in through `checks.runner = "remote"` in the person's untracked `config.local.json` (#793). `@staix/agent-mem` is pinned at 0.8.0.
38
+
33
39
  ## Upgrading to 0.17.0
34
40
 
35
41
  `ahub qwen --mode tui` runs Qwen Code's own TUI in your terminal, driven by the hub through its dual-output files (#286). It is opt-in: the hub never opens it by itself, `roster.qwen` stays off by default, and headless Qwen works as before. It needs Qwen Code 0.26.1 (a new `qwen-dual` compat entry; the headless entry is not widened), refuses an extra instance (`--as`) and refuses while a headless Qwen runs (`ahub stop qwen` first). It has two limits: a hub deny ends the turn without an answer (the delivery completes, so later messages still reach Qwen), and a stalled turn is never cancelled; the hub reports it and you press Esc in the Qwen terminal. `ahub stop qwen` does not end the TUI, and `ahub upgrade` and recovery do not restore it: end it in its terminal before you upgrade, then run `ahub qwen --mode tui` again, which resumes its session. The `codex-review` reviewer now approves exactly `hub_review` and `hub_task_show`, per tool: on Codex 0.164.0 `exec` refused every MCP tool call, so its reviews ended without a verdict (#783). A reviewer turn that still ends without a verdict leaves one screened `hub.log` line (exit code and the hub tools it called) and is offered on, or to you when you named that reviewer (#453). A stale review request that the hub refuses at admission no longer marks the reviewer unavailable: a request whose binding changed is skipped, and one whose policy changed is rerouted as no verdict (#781). An unavailable reviewer slot no longer stops the agy TUI from reading its own task (#794). An `ahub recovery dispose --stop-and-archive` audit entry now keeps the error that blocked the upgrade as `cause` (#776). A task counts toward a recurring finding only where that finding was recorded open or accepted, so a fix-only record no longer files a "Review policy amendment" card (#328), and a missing generation sync remote no longer logs a failure every sync interval (#401). Upgrade running hubs with `ahub upgrade` and restart Claude sessions so they load the 0.17.0 plugin. Coming from 0.15.0 or older, the notes below apply too.
@@ -106,7 +112,7 @@ The restarted Claude planner gets the release-train tools (`hub_release_new`, `h
106
112
 
107
113
  Jcode must be 0.98.0 or later, below 1.0.0; 0.94.0 is no longer accepted, so `ahub doctor` fails its Jcode row for an older install and the peer does not start (#529). Every owned jcode process runs with `JCODE_NO_TELEMETRY=1`.
108
114
 
109
- Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.7.0. Before anyone runs `amem migrate --shards` on a memory home, every hub using that home must run 0.12.37 or later: an older hub does not see the split and keeps writing the old layout. `ahub memory profile-check` is split-aware and compares each hub with its own project's shard (#536). See [memory profiles and rollout](memory.md#selected-memory-profile).
115
+ Since 0.12.37 the hub opens a split memory home through its shards (#534); the current exact `@staix/agent-mem` pin is 0.8.0. Before anyone runs `amem migrate --shards` on a memory home, every hub using that home must run 0.12.37 or later: an older hub does not see the split and keeps writing the old layout. `ahub memory profile-check` is split-aware and compares each hub with its own project's shard (#536). See [memory profiles and rollout](memory.md#selected-memory-profile).
110
116
 
111
117
  From 0.12.30 or earlier, existing Jcode project MCP entries need one refresh before conductor or dashboard starts. Once per project, the person runs:
112
118
 
@@ -173,7 +179,7 @@ More: `ahub help`. How it is built and why: [`docs/specs/2026-09-19-agent-hub-de
173
179
 
174
180
  ## Shared memory
175
181
 
176
- The hub exact-pins the first-party `@staix/agent-mem` 0.7.0 core, including deterministic capture; no claude-mem worker is needed. Existing shared-v1 memory remains the default; upgrading does not migrate it. Managed agents use screened `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools, or propose a correction with `hub_memory_correct`; only a person accepts candidates through the supported `amem review` path. Since agent-mem 0.7.0, `amem review` also accepts candidates on a selected generation.
182
+ The hub exact-pins the first-party `@staix/agent-mem` 0.8.0 core, including deterministic capture; no claude-mem worker is needed. Existing shared-v1 memory remains the default; upgrading does not migrate it. Managed agents use screened `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` tools, or propose a correction with `hub_memory_correct`; only a person accepts candidates through the supported `amem review` path. Since agent-mem 0.7.0, `amem review` also accepts candidates on a selected generation.
177
183
 
178
184
  Before any real generation migration, upgrade every hub sharing that memory home to 0.12.30 or later and check its authenticated binding with `ahub memory profile-check` in each custom registry. Ready bindings prove compatibility, not an atomic live cutover: quiesce consumers and close their handles before migrating, then reopen through the supported session-preserving lifecycle. Invalid or changed profiles disable native memory without falling back to legacy writes; the bus and board continue. See [memory operations](operations.md#hub-memory) for the remaining rollout gates.
179
185
 
package/docs/sdlc.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Authority and evidence
4
4
 
5
- The issue remains the specification, Tasks remains the sole task mutation boundary, and GitHub remains authoritative for PR heads, required checks, merge commits and releases. The hub stores artifact identities and bounded structured readbacks, never issue/PR bodies. Off is the default. Advise exposes blockers without changing task transitions. Enforce blocks only the review/approval transitions listed below; it never merges, releases, edits GitHub or gives a peer additional capabilities.
5
+ The issue remains the specification, Tasks remains the sole task mutation boundary, and GitHub remains authoritative for PR heads, required checks, merge commits and releases. The hub stores artifact identities and bounded structured readbacks, never issue/PR bodies. Off is the default. Advise exposes blockers without changing task transitions. Enforce blocks only the review/approval transitions listed below; it never releases, edits GitHub or gives a peer additional capabilities. The one GitHub write is the guarded merge of an approved task (#786, below), off by default.
6
6
 
7
7
  A reviewed head is a full lowercase 40-character SHA observed through a successful readback, not an implementer-supplied statement. A check is evidence only for that same head. Unknown/missing required checks, unavailable GitHub, pending reviews or unresolved threads remain blockers in enforce and visible unknowns in advise. A newer head invalidates the derived review and approval readiness. Historical task approval is retained as history, not presented as approval of the new commit. Revalidate after asynchronous readbacks immediately before any board write.
8
8
 
@@ -18,7 +18,7 @@ The built-in lifecycle follows the [AI-Native SDLC Playbook](https://claude.com/
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 below, evals pending S5 | agent-executable |
20
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 |
21
- | merge | Deploy | person | current-head readiness, ordered touching PRs | shown; no mutation | 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 |
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 |
24
24
 
@@ -54,7 +54,7 @@ A reviewer records the head it actually reviewed. If GitHub no longer reports th
54
54
 
55
55
  ## Readbacks and presentation
56
56
 
57
- Use structured gh JSON/GraphQL read-only calls with validated repository and numeric artifact identities. No shell interpolation, PR/issue body fetching, token logging or unbounded comment storage. Failure yields unknown. Required checks come from repository rules or explicitly configured names; an empty/unknown set is not silently green. Review-thread status is counted, not copied. Cancellation and task-owner generation fencing prevent a late read from approving reassigned work.
57
+ Use structured gh JSON/GraphQL read-only calls (the guarded merge below is the one exception) with validated repository and numeric artifact identities. No shell interpolation, PR/issue body fetching, token logging or unbounded comment storage. Failure yields unknown. Required checks come from repository rules or explicitly configured names; an empty/unknown set is not silently green. Review-thread status is counted, not copied. Cancellation and task-owner generation fencing prevent a late read from approving reassigned work.
58
58
 
59
59
  ahub sdlc status and explain expose mode, stage, gate, observed/reviewed/local-check heads, next actor and next action. Console/dashboard derive the same result. Merge ordering compares exact PR path sets, reports intersections and never guesses an automatic landing order where dependencies are unknown. Release readiness lists merged work since the tag, stale/nonancestor documentation stamps and open native/live receipts; each unknown remains visible.
60
60
 
@@ -164,6 +164,30 @@ The package-owned scripts/check-docs.mjs accepts --json with the same normal/--r
164
164
 
165
165
  The release reader additionally requests --committed: manifest, README and package metadata come from the captured HEAD, and dirty documentation/evidence files block freshness. A working-tree restamp cannot certify a commit that still contains stale stamps. The ordinary checker continues to support working-tree review before those stamps are committed.
166
166
 
167
+ # Guarded merge (#786)
168
+
169
+ `.agenthub/sdlc.toml` takes `auto_merge = "off" | "dry-run" | "on"` (default `off`) and optional `[repos."owner/name"]` tables with `required_checks` and `auto_merge`. A table's mode overrides the top-level one for that repository; its `required_checks` come first, then the top-level list, so a repository without branch protection is gated by what this file names (an empty set refuses: `required checks unknown`). Unknown keys are refused with a field path. The file is read once at start.
170
+
171
+ Two triggers, neither blocking: an approving `hub_review` at the PR's current head (the check runs after the verdict is saved and reports through a notice; a failing or throwing check never changes the verdict), and `ahub sdlc merge <task> [--dry-run]` (the person or the one configured conductor; a daemon control op that always replies). Right before acting the hub re-reads the PR (`readSdlcPr`) and the queue (`readMergeQueue`) and refuses, naming every failing gate: task not approved, head changed since the approved head, a required check failing, pending or missing, a pending change request, pending or unknown review requests, an unresolved or unknown thread, an open Important finding, a draft, a PR not first among its touching PRs or a dependency that is not approved, a release PR (`release PR: person consent required`), a private task, or unreadable evidence. Unknown is never a pass. The decision judges every gate on three readings (the PR, the queue's own read, then the PR once more, last) and refuses what any of them fails, so a check, review request, thread or draft that changes between reads at the same head is caught; `--match-head-commit` pins only the head. The board-side inputs are read again, synchronously, in the same stretch as the `gh pr merge` call (nothing is awaited between the read and the call) and compared with what the decision judged: the task's state, repo, PR and reviewed head, its privacy, every dependency's state and the dependency edges, open Important findings on the head, the release stage, the merge mode and required checks in force, and the asker's authority and the hub's availability. Any difference refuses and runs nothing. The complete local queue inputs (all task links, dependency edges, receipts, plans, findings, privacy and SDLC configuration) must also match their pre-read fingerprint in a synchronous check after the fresh gates and argv validation, immediately before dispatch. The caller must still be the person, the hub approval trigger or the currently configured conductor at that final check. Any changed projection refuses, conservatively including an unrelated task projection change; a new invocation reads the queue again.
172
+
173
+ `on` runs exactly `gh pr merge <pr> --repo <repo> --squash --match-head-commit <head>` (a closed argv shape checked right before the call) and reads the PR back: only GitHub reporting `MERGED` is a merge, whatever the exit code. Never `--admin`, never a ref update used to perform the merge, and no `--auto` while the repository does not allow auto-merge (a person's repository setting). `dry-run` reports the same decision and the argv it would run and runs nothing; `off` reads nothing. Logs and notices name the task number and gates only. The verdict mirror is described in the next section.
174
+
175
+ ## Merge result and cleanup (#786 T2)
176
+
177
+ Post-run reads make at most three attempts within a shared six-second budget. Only a GitHub MERGED observation with its merge commit permits cleanup; the CLI exit is recorded separately, including a nonzero exit when GitHub confirms the merge. Non-merged, missing or unreadable evidence records the bounded result and leaves branches alone. Off and dry-run create no merge record or cleanup effects.
178
+
179
+ Tasks stores host-only `sdlc.merge` evidence bound to the repository, PR and head. Lifecycle tools cannot submit this field, and artifact changes invalidate it. A change during an awaited operation leaves the previous attempt in history without overwriting the replacement artifact. Durable cleanup and owner-notice claims precede those effects. Merged or uncertain attempts are not automatically repeated after restart; a positively observed not-merged result can be retried by an explicit command. A crash before the first post-run record remains an untracked attempt requiring inspection.
180
+
181
+ Remote cleanup reads the merged PR head, repository default, legacy protection and active rulesets. It skips missing, fork, default, protected, moved or unsupported refs. Its only ref write is a single GraphQL compare-and-swap deletion: `beforeOid` is the merged PR head and `afterOid` is zero. A moved head refuses deletion; unknown outcomes stay explicit. The hub sends the owner a public-view notice to remove only its task worktree and local branch when safe. The hub runs no local branch or worktree deletion.
182
+
183
+ ## Verdict mirror (#786)
184
+
185
+ Each `hub_review` verdict is mirrored as ONE `COMMENT` review on the head it was given for, so a person reading the PR sees the hub's verdict. One GitHub account authors and merges every PR and GitHub refuses `APPROVE` and `REQUEST_CHANGES` on your own PR, so a comment is the only review the hub can leave; it is a record, never a gate, and nothing reads it back as approval. The call is exactly `gh api repos/<repo>/pulls/<pr>/reviews -f event=COMMENT -f commit_id=<head> -f body=<text>`, a closed shape checked right before it runs; the hub makes no other review write. The first line of the body is `agent-hub verdict: approved|changes_requested (task #N, reviewer <peer>)`.
186
+
187
+ It follows the same `auto_merge` setting as the guarded merge, per repository: `off` posts and reads nothing, `dry-run` reports the call it would make in a notice, `on` posts. It runs after the verdict is saved, is never awaited by the verdict and never fails it (a failure is a notice naming the task number). A verdict at a head the PR is no longer at posts nothing, a closed PR gets nothing (the head and state are read once more after the review list, last, so a push or a close during that read is caught; GitHub offers no compare-and-set on a review, so a push landing between that read and the post is not, and the comment still names its commit), and unknown evidence (an unreadable PR or review list, or a full page of 100 reviews) posts nothing. At most one mirror exists per (task, head, verdict): the hub reads the PR's reviews for its own headline at that head before posting, so a retried verdict or a restart does not post twice. For an approval the comment is posted before the guarded merge starts reading.
188
+
189
+ The body after the headline is the note's public view: a private task, a note the review screen withheld, a note given in a private turn and a note matching a private pattern are mirrored as the headline alone. The note is bounded, control characters are stripped, and a line that looks like a verdict headline or an agent-hub message header is neutralised so a note cannot forge a second mirror.
190
+
167
191
  # Read-only merge queue contract (#257)
168
192
 
169
193
  Queue reads fetch PR numbers and bounded head/check/review/thread/file-count metadata, never remote titles or bodies. Up to16 open PRs and8 external dependency reads share a20second budget. Every linked local receipt must satisfy the existing approval floor on that current head; draft/unknown status, missing file coverage and unlinked/private work remain blocked. Same-target path intersections return counts without names. Task after edges provide the only dependency order; open predecessor PRs block current readiness, unresolved touching order asks the person, cycles/truncation remain incomplete. A board approval never substitutes for a merged-commit receipt. No queue operation changes dependencies, owns work, merges or writes GitHub.
@@ -251,6 +275,8 @@ The planner can provide scope with `hub_plan_review`; the person can run `ahub s
251
275
 
252
276
  A review request is premature if its task head does not match the PR head, configured required checks are not green, or a pending bot thread is unanswered. A resolved thread is settled; an unresolved one needs a user reply after its last bot comment. The hub reads identity, timestamps, authorship type and resolution only, never comment bodies. Without explicit required checks the native floor is both OS checks plus `seeded guards`. Advise reports the gap; enforce refuses before the requesting done/cohort writes. If only quiet task-history events arrive during an advise readback, the evidence is discarded and review continues with unknown readiness, without another external read. A reviewer change is allowed because the reviewer is re-derived before the write; it is not an authority or readiness receipt. Mode, owner, privacy, receipt, authority and other history drift still refuse; enforce remains unchanged. A private turn may finish its own PII task in advise with a generic unknown-readiness notice and no remote metadata read; the private-turn refusal for ordinary work remains. Delayed checks revalidate before completing; a refused completion sends a private-aware notice to call `hub_task_done` again only while the task is still in progress with the owner that started the check. Otherwise only the console notice is recorded. Background roster/quota role changes remain fact, but enforce holds a new review envelope without an admission readback; refresh it through a manual reviewer assignment after CI and replies are ready. The brief and verdict coverage belong to #520, separate from this admission.
253
277
 
278
+ **Evidence in the review request (#824).** A fresh reviewer cannot run tests or read `gh`, so the request carries the hub's own reading of the admission it already made, for every reviewer: `Hub-verified at <head>: required checks <names> passed at this exact head; no bot review thread is waiting for a reply` (plus `via identical-tree run <n>` when the hub reused one), or in advise mode `Hub-verified at <head>: not ready: <blockers>`. No admission (lifecycle off) and a PII task get no block, and no new `gh` call is made for it: it renders what `reviewRequestAdmission` read. `ReviewReadiness.checks` names the required checks that were judged. When the admission is ready and the hub ran no check of its own, the checklist's check line says CI passed at this exact head and that test execution or CI evidence is not an unmet item (name a specific missing test or behaviour instead); otherwise the old wording stays. The text comes only from the hub's reads and recorded `check passed` events, never from the builder's summary or a `hub_sdlc_record` claim, and a review-only reviewer still gets no builder summary (#223 R2).
279
+
254
280
  CI controllers are serialized per pull request (`check-pr-<number>`) and for main pushes and ordinary dispatches (`check-main`), for the entire workflow and without canceling an admitted controller (#609); macOS timing dispatches use their own macos-timing group. Within a PR `queue: single` lets a newer pending run replace the older pending one; main keeps `queue: max`, which preserves up to 100 waiting controllers ([GitHub concurrency documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency)). Different PRs run side by side: a repository-wide lock serialized every PR (17-18 min alone, 40-54 min with 4-5 PRs in flight on 2026-10-20). Two groups admitting the same tree at the same instant can run it twice; that duplicate costs one run and never a false green. Required job names and read-only token permissions are unchanged. Before PR or push gates, `scripts/ci-reuse.mjs` reuses successful full proof for the identical Git tree, including its workflow. On reuse the two OS matrix jobs still expand and report their exact required names, while the seeded aggregate reports its exact name. They run only a `Reuse verified identical-tree full gate` marker step naming the original proof; full setup and gates are skipped. Skipped jobs and successful reuse-reporting jobs never count as fresh full proof. A running identical-tree gate refuses duplicate admission; unknown active coverage refuses safely. Only a 404, a timeout on the individual read limit, or malformed successful proof is dropped: a failed successful-run list drops that proof phase, while a failed commit or jobs read drops only that candidate and continues the bounded search. Other failures (5xx, 403, 429, response size bounds, authentication and unclassified errors) remain unknown. Exhausting the overall deadline or request budget stays unknown even when a request reports a timeout. Without verified proof, a complete empty active scan requires a fresh gate. An unreadable, truncated or unidentifiable active inventory, or exhaustion of the shared request budget or deadline, stays unknown and refuses admission. The release reader (`--require`) still refuses without verified identical-tree full proof. Metadata reads are bounded to 100 recent successes/active runs and 240 calls within 60 seconds. Pending serialized controllers are not admitted gates. Run focused tests and `scripts/check.sh --changed` locally; CI carries the full-suite gate; a known flake warrants only one rerun of its failed job with recorded evidence.
255
281
 
256
282
  `hub_sdlc_costs` and the person's `ahub sdlc costs [owner/repo]` report linked merged PRs without changing the board. A review round is a board done-to-verdict handoff, not each reviewer in a multi-reviewer round. An observed handoff still counts when its declared scope was none. The report counts distinct check-workflow run ids, extra attempts (`run_attempt - 1`), full re-reviews, delta rounds and summed review intervals, with GitHub review counts alongside them. Unspecified scope and unavailable evidence stay unknown/incomplete. Only current public links are projected; a private counterpart withholds the whole PR. Up to 16 linked PR reads share 20 seconds; each PR covers at most 100 commits, reviews and recent check-workflow runs, and the pure aggregator bounds 500 tasks, 200 PRs and 10,000 history entries. Truncation is explicit. S10 exposes pure band-breach proposal data; S7 owns rolling baselines, band configuration, automatic scheduling and board-card creation.
package/docs/security.md CHANGED
@@ -23,7 +23,7 @@ agent-hub connects agents that can each run commands. This page says what the hu
23
23
 
24
24
  ## Native memory authority and profile selection
25
25
 
26
- The portable core is the exact-pinned first-party `@staix/agent-mem` 0.7.0 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
26
+ The portable core is the exact-pinned first-party `@staix/agent-mem` 0.8.0 package; it does not replace the hub's caller identity, PII policy or task-write authority. Deny, hardened git, real paths and process identity are single-sourced in its Node-safe platform entry. Current project privacy is applied by the hub before promotion and again before model-facing reads. Standalone person reads are unscreened, and the standalone `--policy-free` acknowledgement grants no hub or peer authority.
27
27
 
28
28
  `hub_memory_search`, `hub_memory_show` and `hub_memory_graph` take the project from the daemon, require `memory_read`, refuse private turns and validate UTF-8 input before logs or storage work. Complete records and graph metadata are screened before counts and truncation. Search is at most 20 lines/4 KiB (default 8); show accepts at most 8 ids and returns at most 8 KiB; graph is at most 120 nodes/240 edges/6 KiB (default 60 nodes), with no edge lacking an endpoint. Unknown, ambiguous and withheld ids share one neutral refusal. Arguments and results are excluded from hub-managed capture; this does not govern a vendor's independent transcript or memory hooks.
29
29
 
@@ -235,9 +235,23 @@ move other than the hub's own was not made from the console (to another peer
235
235
  only with `assign` when its capabilities are listed).
236
236
  A conductor may inspect public state, assign or escalate work, start a peer in
237
237
  the start mode a person set (it cannot choose the mode) and place its own
238
- delivery holds. It cannot answer approvals,
239
- resolve durable deliveries, override budget pauses, release a human hold or stop
240
- a peer: `peer_stop` is taken from the console role only, and no hub tool sends it.
238
+ delivery holds. Through the `ahub` CLI under its own peer identity it may also
239
+ run the closed operational family of #812: `roster add|remove`, `stop <peer>`,
240
+ `queue show|resolve|discard`, `task cancel`, `doctor --orphans --kill`, `logs`,
241
+ `export` and `settings set` on twelve named live keys. Each is admitted by the
242
+ daemon after a recheck of the conductor role, audited as a closed label with no
243
+ argument text, and bounded: logs and export are public projections of the last
244
+ 100 lines and 1000 events, orphan cleanup signals only a positively identified
245
+ hub-owned process of the selected project, and a stop keeps the existing
246
+ ownership and recovery guards (`peer_stop` from a non-console connection is
247
+ admitted only through this conductor check; no hub tool sends it). It still cannot answer
248
+ approvals, override budget pauses, release a human hold, trust an agent version,
249
+ authorize a release or run recovery resume, abort and reattach: those stay with
250
+ the person. Other agents may run only the read-only forms of #812 (`doctor`,
251
+ `projects`, `models status`, `recovery status`, `queue list`, `roster`,
252
+ `settings` reads, `sdlc status|explain|queue|release`, `release show` and the
253
+ `--dry-run` upgrade and restart previews) through the public views, never the
254
+ console identity.
241
255
  Pending approval summaries exclude titles; PII tasks remain public stubs.
242
256
  Conduct events contain ids only. Supervision feeds use structured reasons and
243
257
  never carry check output or approval bodies.
@@ -485,6 +499,14 @@ SDLC metrics and control bands (#481 S7). `ahub sdlc metrics` and `hub_sdlc_metr
485
499
 
486
500
  The runner uses Apple `container`, pinned Bun 1.4.2 and a verified `hostOnly` internal network with DNS disabled, two CPUs and 4 GiB. It starts a named, labeled VM with a bounded idle process, copies a hub-owned snapshot into the running VM, then invokes a fixed `container exec` check. This run/copy/exec sequence is required because Apple `container copy` rejects a stopped container. No host directory, home, credential directory, hub state or socket is mounted. Source blobs are read from the exact Git commit; symlinks and gitlinks anywhere in the source refuse the run before exclusions. Directory prefixes and filenames are checked for NFC/Unicode case-fold collisions before staging writes, including denied entries; folding must reach a fixed point within a bounded number of passes or the run refuses. This is a conservative collision screen, not a claim of exact parity with every host filesystem. Denied and PII paths are excluded and counted. Dependency files require an equal lockfile, bounded regular files/directories and internal relative symlinks. No dependency installation or Internet access occurs in the VM.
487
501
 
502
+ The optional remote backend (#793) selects `checks.runner = "remote"` and a strict `checks.remote` object containing `host`, digest-pinned `image` and absolute `root`. Both the grant and destination must come from an untracked `config.local.json`; a tracked or shared-file grant is refused. The destination is host-owned configuration, never a peer argument. OpenSSH uses BatchMode, disables TTY allocation (`-T`), agent/X11 forwarding (`-a`, `-x`), configured forwardings and local SSH commands, and retains only the hub-owned agent socket for local SSH authentication. It uses fixed Docker operations, and every remote argument is shell-quoted because OpenSSH joins the command before the remote shell interprets it. SSH diagnostics are discarded. Only actual check execution merges remote command stderr into screened output; readiness JSON keeps stdout separate from withheld diagnostics. Exit 255 discards stdout too; retained container stdout is screened and destination/root strings are replaced before receipt/output persistence. Public image identity is digest-only. Platform comes from inspected Linux image metadata and the actual fixed Bun probe architecture, with only a numeric Docker version prefix. No host, account or remote root is included in those projections.
503
+
504
+ Remote checks reuse the same request validation, exact Git snapshot, queue, authority fences, repository heavy lease, receipt retention and cleanup lifecycle. They stream a trusted host tar producer into `docker exec -i --user 65532:65532 ... tar -xf - -C /work`; no working-tree sync or Mac `node_modules` copy occurs. Darwin pins the system /usr/bin/tar regardless of PATH; Linux keeps the hub-owned executable resolver. The archive excludes extended attributes, macOS metadata and ACLs, and normalizes owner/group identifiers and names instead of carrying host identity. The staging parent remains mode 0700; snapshot directories are explicitly 0755 and files 0644 or Git-executable 0755 even under umask 077, so non-root execution can traverse and read the copy. Extraction does not restore archive ownership: the copied files belong to the container uid and may be changed only in its throwaway work tmpfs. No privileged chown or root extraction is used. Only the throwaway work tmpfs and home/temp tmpfs can be writable, never the host source. The tar producer is cancelled and reaped on failure or cancellation.
505
+
506
+ Docker checks use a non-root numeric uid, `--network none`, read-only root filesystem, home/temp/work tmpfs, all capabilities dropped, no-new-privileges and fixed pids, CPU (4) and memory (4 GiB) caps. No host path, socket, home or credential mount is allowed. A uniquely named/labeled run uses only a locally present image (`--pull never`). Removal is confirmed through project/name-filtered Docker inventory before the existing heavy lease is released. Inventory projects individual hub label fields instead of parsing Docker's comma-joined label display, and does not enumerate unrelated projects' containers. Readiness checks Docker reachability/version, the exact image digest and architecture, and a fixed hardened network-none probe that uses the same archive transfer and non-root readback as a run; any failed proof is `remote runner unavailable`, with no local fallback. Probe cleanup remains bounded and runs even after its admission signal is cancelled. Exact project/probe-UUID/name rows without a task run id are left to their fixed 600-second expiry and excluded from task-run orphan warnings. Malformed probe rows and unknown task-run owners still produce warnings; labels alone never authorize killing a probe.
507
+
508
+ The remote backend's `root` is reserved, validated metadata until the separate #793 dependency-preparation slice needs it; no current Docker command uses a host path. The current read-only named dependency volume is a project-key-scoped, explicitly unprepared placeholder. Even after a successful transport probe, tests capability stays unavailable with `remote dependencies unprepared` until a preparation contract lands. This slice neither installs dependencies nor prepares a shared writable cache; lockfile/Bun-keyed preparation (AC3), actual machine opt-in and a live remote receipt (AC6) remain separate work. Fake transport/argv tests establish the source contract. A bounded [local Docker transport receipt](verification/2026-10-25-remote-docker-transport.md) verifies transfer and cleanup under its disclosed CPU adjustment; remote SSH, dependency readiness and pi's live tools remain unverified.
509
+
488
510
  Dependency copies detect observed inode, size and timestamp changes and refuse final-component symlinks using `O_NOFOLLOW`. A same-user writer can still exchange and restore a parent directory between observations; this is not an atomic immutable-dependency guarantee. Source commits remain immutable. Do not treat a dependency copy as protection against a hostile process running as the same host user.
489
511
 
490
512
  Checks serialize through the repository's existing `ahub-heavy.lock`, with one active and at most two queued runs, a ten-minute execution ceiling after heavy-slot admission and a bounded heavy-slot wait. Container startup has a 120-second cap for cold VM boot, and copy has a 180-second cap for the bounded 512 MiB source plus 1 GiB dependency corpus. Each stage is clamped to the remaining ten-minute budget and uses the same cancellation signal; exec receives only the remaining budget. Network/probe commands retain a 15-second cap, also clamped and cancellable during an admitted run. Named-container cleanup has its separate bounded teardown commands and must still be confirmed before releasing the heavy slot. Queued cancellation settles its receipt and releases queue capacity immediately; active cancellation, timeout and shutdown stop only the named check container. Cleanup is confirmed through inventory before releasing the heavy slot; unknown cleanup keeps the slot and reports an error. Startup removes only this project's labeled containers whose signed recorded hub owner is confirmed gone. Unknown owners are reported for the person, never killed.
@@ -2070,7 +2070,8 @@ reviewer may also call it for that task. They get exactly the conductor's
2070
2070
  view: `publicConductorTask` over `Tasks.publicView(task, true)`, so the whole
2071
2071
  history with its done summary and check line, notes that match a PII pattern
2072
2072
  withheld, and a PII task as a stub with no history. Any other peer is refused
2073
- with the conductor-role error, whatever the task. That refusal is about the
2073
+ with the conductor-role error, whatever the task, except the configured planner,
2074
+ which reads any task through the same view (#812, below). That refusal is about the
2074
2075
  tool, not a secret: the view holds nothing private beyond the PII stub, and the
2075
2076
  control op `task_show` (`ahub task show` from an agent shell) already returns
2076
2077
  the same public view to any peer. These reads write no conduct audit event, as
@@ -2461,7 +2462,7 @@ acts on the stopped state directory.
2461
2462
  - A console-role `{ t: "peer_stop", peer }` request stops a hub-owned headless ACP, Pi or local runtime through its adapter's owned-runtime teardown. Success is `{ ok: true, state: "offline" }`; refusal or incomplete stop is `{ ok: false, error }` naming the reason and next action. New requests already receive an unknown-request reply on older hubs, so `PROTOCOL` stays unchanged.
2462
2463
  - Refuse agent/tools-role callers, unknown or offline peers, Claude/Codex and Pi TUI owners, and recovery/shutdown-held mutations. Starts, requested stops and permission changes are fenced per peer; recovery preparation waits until requested stops finish. A TUI is ended in its terminal, or by the upgrade plan's verified terminal binding.
2463
2464
  - A requested stop marks each in-flight delivery `needs_review` with a fixed ids-only stop reason, cancels pending approvals, and fences stale native completion/failure callbacks. It never completes or implicitly redelivers interrupted work, invokes failure escalation, or triggers Pi's idle auto-restart. The operator inspects effects and explicitly resolves the delivery before replay. Queued unattempted work remains for the next manual start under existing holds/pauses.
2464
- - `ahub stop <peer>` is human-only in `classifyPeerCommand`, prints the returned state, and reports an older hub's unknown request as requiring an upgrade, with a nonzero exit. The upgrade plan's headless `endPlannedPeer` uses the same console request; the daemon does not close a native terminal.
2465
+ - `ahub stop <peer>` is available to the person or the selected project's configured conductor in `classifyPeerCommand` (#812). The conductor retains its authenticated peer identity and audit; other agents receive the person guidance promptly, including when the hub is unreachable. It prints the returned state and reports an older hub's unknown request as requiring an upgrade, with a nonzero exit. The upgrade plan's headless `endPlannedPeer` uses the same console request; the daemon does not close a native terminal.
2465
2466
 
2466
2467
  - Requested stop admission also holds per-peer drain, pull and steering before any teardown await, without changing operator/budget pauses. Arriving work remains queued for explicit restart. Idle Pi captures live empty-session proof before stopping; a first accepted prompt with unpersisted history is not silently recreated as empty.
2467
2468
 
@@ -3284,7 +3285,7 @@ PII authority, complete-row host screening, capture exclusion, byte budgets and
3284
3285
 
3285
3286
  ### Bounded sandboxed-peer capabilities (#418)
3286
3287
 
3287
- The frozen issue #418 contract supplies task-bound `hub_task_spec` and the finite `hub_check_start/result/cancel` tools; memory reads reuse #412 P2. `checks.runner = "container"` remains an untracked, person-owned opt-in. Specs include validated canonical GitHub intake identity as well as bounded textual references and remain complete-or-refused; checks run immutable Git source in a credential-free, internal-network Linux VM with fixed commands and binding-scoped receipts. Default sandbox permissions remain unchanged.
3288
+ The frozen issue #418 contract supplies task-bound `hub_task_spec` and the finite `hub_check_start/result/cancel` tools; memory reads reuse #412 P2. `checks.runner = "container"` or `"remote"` remains an untracked, person-owned opt-in; the remote grant and destination require `config.local.json`. Specs include validated canonical GitHub intake identity as well as bounded textual references and remain complete-or-refused; checks run immutable Git source in a credential-free, isolated Linux VM/container with fixed commands and binding-scoped receipts. Default sandbox permissions remain unchanged. The remote backend (#793) streams a metadata-stripped, owner-normalized archive to non-root `docker exec -i ... tar` extraction in its work tmpfs, rather than Docker cp into a read-only-root container. Readiness proves that same transfer and readback path plus network isolation; project/name-filtered inventory reads individual hub labels and confirms cleanup. Until the separate dependency-preparation slice supplies prepared dependencies, remote tests capability remains unavailable even after transport readiness succeeds.
3288
3289
 
3289
3290
  Apple container 1.5.0 requires a running VM for `copy`. The implementation therefore uses `run --detach --rm` with the fixed bounded idle process, copies the validated source/dependencies, executes only the selected finite check argv and confirms cleanup. A create/copy/start probe failed on the stopped-container copy and left no container; the run/copy/exec probe passed. `--internal` is verified as network configuration `mode: hostOnly`, not an inferred network name. Inactive sandboxed peers establish the cached spec authentication probe at first start/use rather than making unrelated host-embedding fixtures contact real accounts. Source and dependency staging ceilings are 100,000 entries each, 512 MiB source and 1 GiB dependencies; exceeding one refuses the check.
3290
3291
 
@@ -3302,7 +3303,7 @@ Evidence: `docs/verification/2026-10-17-418-probes.md`. The feasibility probe is
3302
3303
  - Ready ownerless tasks retain the ordinary routing decision and reservation guards. A persisted cause/replanning signature admits one ids-only console and supervision notice for an ineligible reserved peer, no eligible peer or a cancelled dependency. Repeated release passes with the same cause add neither history nor notices; a changed cause or explicit replanning admits one new notice. The designated planner (the settled configured planner roles) receives bounded ids-only advice in its next preface, while the configured supervision stream receives the structured item under its existing scope. Advice does not manufacture an ordinary task turn beside a stale backlog batch. Without a planner, the console attention list remains the recipient. Existing owner/reviewer ladders remain unchanged.
3303
3304
  - A current proposed offer to a pull-only peer remains console attention until acceptance, decline, supersession or positive delivery evidence for that exact offer envelope and recipient. Tasks records the original envelope id, assignment revision and offer-time pull-only classification before publication. This classification survives detach and restart; current attachment is not evidence that an unread offer disappeared. Actual adapter completion, a correlated reply or a completed pull records positive evidence atomically with journal completion, surviving terminal pruning and reopening. Accepted-only receipts, unrelated inbox activity and operator/hub completion are not read evidence. Advisory queries never dequeue, steer or settle work. Decoded offer/stall candidates are cached by board revision and live eligibility inputs; positive journal read evidence is checked afresh. The derived revision advances atomically with task and stall writes, independently of unrelated delivery-journal writes.
3304
3305
  - The disabled-by-default sweep adds `ready-unassigned` with `ready_min: 60`. A ready proposed ownerless task follows the existing deterministic, restart-safe ladder, without treating quiet stall/offer bookkeeping as activity. A person-unassigned task stays suppressed until explicit person assignment or reservation. Planner-pulled work retains reserved-only/WIP admission, and a saved-but-undelivered reassignment does not stop the remaining sweep. Cancellation does not satisfy a dependency. This change does not enable any project's live sweep configuration.
3305
- - `cancelled` is terminal and retained. The person may cancel backlog, proposed, in-progress, in-review or changes-requested work, never approved work. A configured planner tool may cancel only its own backlog/proposed task with no historical acceptance. `Tasks.cancel` validates the optional flow revision, screens the reason/reference and rechecks authority, revision and recovery/shutdown exclusion after asynchronous screening before the sole board mutation. History retains actor, reason and optional supersession reference. After the cancellation write commits, advisory cleanup and notices cannot change its successful result. No outcome memory, native cancellation, branch deletion or dependent release occurs.
3306
+ - `cancelled` is terminal and retained. The person may cancel backlog, proposed, in-progress, in-review or changes-requested work, never approved work. A configured planner tool may cancel only its own backlog/proposed task with no execution evidence: never started, or accepted and then declined or returned untouched (#812, which replaces the earlier rule of no historical acceptance). `Tasks.cancel` validates the optional flow revision, screens the reason/reference and rechecks authority, revision and recovery/shutdown exclusion after asynchronous screening before the sole board mutation. History retains actor, reason and optional supersession reference. After the cancellation write commits, advisory cleanup and notices cannot change its successful result. No outcome memory, native cancellation, branch deletion or dependent release occurs.
3306
3307
  - Cancellation releases overlap/reservation participation and sends each distinct former owner/reviewer one stop notice. Its trusted cancellation revision marker keeps that stop notice relevant; earlier notices for the cancelled task become moot under #434. The classifier never uses timestamps alone to identify the stop notice. Dependents keep waiting and receive the cancelled-dependency cause. List, show, explain, dashboard and release projections treat cancellation as closed, retaining the current privacy screen and distinguishing cancellation from successful approval.
3307
3308
  - The daemon advertises `task_cancel` in hello and status features. Current clients refuse cancellation without that feature. Upgrade and restart persist the verified target's exported features with its immutable root/digest before prepare, including cached targets, and reuse that receipt on resume after verifying the same bytes. A legacy staged receipt without feature evidence is probed only while a project is not yet past commit; fully committed projects do not require another probe. This preserves #215: a transient probe failure cannot refuse a target that was already staged with verified evidence. Preflight checks only uncommitted sources and refuses a target lacking `task_cancel` while cancelled rows exist. Source prepare/commit recheck before holds/snapshots and around asynchronous work; cancellation cannot write through recovery preparation. Refusals name task ids and never rewrite rows. An older binary started manually can misclassify cancelled rows as open or fail to move them; this is the explicit unsupported compatibility ceiling. Never map cancellation to approval.
3308
3309
  - The post-release live step remains separate: do not cancel the historical task or enable the project's sweep from implementation tests. AC7 needs installed-runtime receipts.
@@ -3868,7 +3869,9 @@ Owner decision 2026-10-18 (#450 comment 6248184754), R1-R5. R3's mechanism, chos
3868
3869
  - **R1/R5, routing.** `assign()` prefers a dedicated reviewer (holds `reviewer`, not `planner`) among the eligible peers, busy or not; family independence and the PII rule (the person reviews) are unchanged. When a dedicated reviewer is declared but not eligible (offline, not started, paused) the planner reviews as before and the assignment note says `reviewer=planner (fallback)`. With no dedicated reviewer declared nothing changes. The reviewer is chosen at assignment, as before (ponytail: a task assigned during a fallback keeps the planner; re-pick at done if that matters).
3869
3870
  - **Budget.** The reviewer shares the `claude` account and its pauses; usage from each child's `result` event is added to the peer's tokens. No quota is classified from its text.
3870
3871
  - **Privacy.** The diff lists changed paths first, with rename and copy detection, and leaves out every change touching a path that `local.deny` or `pii.paths` covers (a move or copy whole, when either side is private), noting only how many were withheld (ponytail: git's 50% similarity decides what counts as a move); a diff that matches a private-data pattern is withheld whole. Those entries are also passed to the child as Claude `Read` deny rules (Claude evaluates them, not the hub's path policy). A private review is never given to it.
3871
- - **Narrative on the read tool.** `hub_task_show` from a review-only instance returns the task with history notes kept only on `approved` and `changes_requested` entries; the done summary and other notes are dropped.
3872
+ - **Narrative on the read tool.** `hub_task_show` from a review-only instance keeps history notes on `approved` and `changes_requested` entries and the bounded planner-ruling exception below; the done summary and all other notes are dropped.
3873
+
3874
+ - **Planner-ruling exception (#835).** Review requests and review-only task views also carry `plan reviewed` notes after the current ownership boundary, the latest `accepted` or `claimed` event (none without either). The author must be the current effective `taskPlanner(task)`, including its legacy role-holder fallback, and still hold the planner role. Keep the oldest five rulings, screen and sanitize each full note before cutting its displayed text to 1000 characters, and retain the withheld marker. PII tasks show none. Each ruling names its author and timestamp; these rulings inform the reviewer and amend review context only. They do not accept a plan departure: departure acceptance stays the person's and `accepted: false` remains unchanged.
3872
3875
  - **Verdict authority.** A headless reviewer's `hub_review` is accepted only while the child that started for that task still runs (a per-child token, so a replacement child for the same task is a new authority). It is captured when the call starts and rechecked before every write, after each await. The leader's exit, a watchdog or a stop revokes it first. A review ends only when the child's whole process group is confirmed gone; survivors hold the delivery as `needs_review` and keep the peer busy with its handle: a stop fails and leaves it busy (never offline), and a start is refused, until they exit.
3873
3876
  - **Settlement.** A start failure before any review in a delivery ran is `failed_safe`; after one ran, the delivery is held as `needs_review`. A failing facts or verdict-check callback is logged, and the review counts as without a recorded verdict.
3874
3877
  - **Never an owner.** The reviewer variant carries `routing.reviewOnly`; assignment refuses it as an owner for every task class and when named.
@@ -4028,7 +4031,7 @@ pure decision and name the chosen instance. Reviewer independence compares
4028
4031
  families (the kind); an eligible other family takes precedence even when busy.
4029
4032
  Only when no other family is eligible may an assignment use its own family,
4030
4033
  recording `sameFamilyFallback=true` in assignment history. This independence rule
4031
- also applies to an explicit same-family reviewer nomination. A declared owner of
4034
+ also applies to an explicit same-family reviewer nomination. `review.same_family = "never"` (#820, default `"fallback"`) removes that last resort in the pool and the legacy path: the planner reviews when it holds the reviewer role, is not the owner, is of another family and is not blocked, else the person, and a same-family nomination is refused with `same family as <owner>; review.same_family is never`. A declared owner of
4032
4035
  implement, bulk-edit or test work requires the current implementer role and positive
4033
4036
  host evidence tied to the actual adapter generation started in a verified noncanonical
4034
4037
  worktree; a role-only reload cannot promote a canonical reviewer process. External
@@ -5153,3 +5156,10 @@ Ceiling: a scan lists the board once per status revision (at most one per flush)
5153
5156
  - Default CodeFacts review/completion queries have priority over optional neighbours. Interrupt an active optional CLI, await all existing owned cleanup and then admit priority work; do not run native tree preparations concurrently. Optional unknowns have a bounded five-second TTL and never poison priority cache lookups.
5154
5157
  - Dashboard code work requires the Memory view to be open and visible. Derive starts share a five-second floor; known topology lives at most thirty seconds, with current note rows refreshed before publication. A single hardened native HEAD probe establishes a bounded HEAD/ref proof; cache checks do not launch Git.
5155
5158
  - Console task counts use cache-only optional context and return unknown on a miss within the existing task-detail deadline. Snapshot the native brief cap before awaits. Preserve stored nodes when adding derived edges and apply tier/kind/peer filters to neighbour notes; a non-symbol selection resets the toggle.
5159
+
5160
+ ## Amendment: the planner reads any task and cancels its untouched declined task (#812 AC5)
5161
+
5162
+ - **Supersedes** the #208 sentence that refuses every peer but the conductor, a task's owner and its reviewer, and the #438 sentence that limits a planner's cancellation to work with no historical acceptance.
5163
+ - `hub_task_show` also admits the configured planner (a peer holding the `planner` role, `Tasks.isConfiguredPlanner`, `ConductorHooks.isPlanner`) for any task outside the backlog (a staged backlog row stays hidden from agent task tools, #263, and is read through the planner tools; a peer that is also the conductor takes the audited conductor path). It gets exactly the conductor's view (`publicConductorTask` over `Tasks.publicView(task, true)`), so a PII task is still a stub with no history. The read writes no conduct audit event and grants nothing else: the planner cannot assign, escalate, hold or start through the conductor tools, and every other peer is refused with the conductor-role error as before.
5164
+ - `hub_task_cancel` by the planner keeps every check it had (its own proposal, `backlog` or `proposed` state, planner authority, no private turn on ordinary work, the flow revision, recovery and shutdown exclusion) and replaces only the acceptance test with the evidence test `hub_backlog_return_untouched` uses (`taskHasWorkEvidence`): a branch, commit, PR, recorded local check, done, verdict or reopen refuses with the unchanged text `planner may cancel only its own historically unaccepted backlog or proposed work`. An accepted-then-declined task with none of them (the observed case, #454) is cancellable; the history keeps the acceptance and the decline.
5165
+ - Reason: the planner could not read a task it had proposed once an owner took it, and could not clear the board of a task its owner declined untouched. The person's cancellation is unchanged.
@@ -0,0 +1,76 @@
1
+ # 0.18.0 release verification
2
+
3
+ This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.18.0 and no live TUI launch.
4
+
5
+ ## Candidate
6
+
7
+ Version 0.18.0, built from merged main f0e9589a (26 commits since v0.17.0, 19 of them `feat`). The release commit carries the version, the CHANGELOG section, the bundle (plugin 0.18.0, built with the pinned Bun 1.4.2 and the worktree's own frozen `node_modules`) and the document corrections, and every document stamp names it. Control protocol stays 16. `@staix/agent-mem` stays exact-pinned at 0.8.0. The task asked for a release once the in-progress work finished; the release PR is merged with a merge commit by the conductor, then tagged `v0.18.0`.
8
+
9
+ What changed (see `CHANGELOG.md` for the full list):
10
+ - Readable CLI output by default for the `sdlc` read commands, the task, backlog and release commands, and restart, upgrade, recovery, models, `queue resolve` and `budget execution` (#814: #831, #833, #834), with `--json` byte-identical and two guard scans (#837).
11
+ - Guarded merge, merge records and post-merge cleanup guards, and one GitHub COMMENT review per hub verdict (#786: #815, #823, #825).
12
+ - Exact-head CI evidence and current planner rulings in the review request (#824, #826; #835, #836); `review.same_family = "never"` (#820, #828).
13
+ - Agent shell authority: read-only `ahub` forms for every agent and a closed operational family for the conductor (#812: #818, #827, #832); planner task reads and untouched cancel (#822); proven read-only shell grants for Pi and the local worker (#816, #829).
14
+ - Planner WIP split (#784, #819), the isolated remote Docker check runner (#793: #806, #807), dirty-submodule turn facts (#798, #808), and dogfood profile metrics (#799: #810, #817, #830).
15
+
16
+ ## Reviews
17
+
18
+ Every PR below merged after hub reviews and bot review threads were answered, with exact-head CI green at merge (the conductor read it). The review counts are the GitHub COMMENT reviews each PR carries.
19
+
20
+ | PR | Merge | GitHub reviews |
21
+ | --- | --- | --- |
22
+ | #806 (#793) | 170199d6 | 4 |
23
+ | #807 (#793) | fd94621a | 2 |
24
+ | #808 (#798) | 79b33c0d | 2 |
25
+ | #810 (#799) | 860b0c66 | 4 |
26
+ | #811 | edcc059d | 2 |
27
+ | #813 (#525) | 577668de | 2 |
28
+ | #815 (#786) | f236aa59 | 4 |
29
+ | #817 (#799) | b23ad7b7 | 2 |
30
+ | #818 (#812) | 61e2fd3f | 4 |
31
+ | #819 (#784) | b454e527 | 2 |
32
+ | #821 | 7d539061 | 2 |
33
+ | #822 | 97473e85 | 4 |
34
+ | #823 (#786) | be35c0c8 | 2 |
35
+ | #825 (#786) | 10a784f9 | 4 |
36
+ | #826 (#824) | 85559fc8 | 2 |
37
+ | #827 (#812) | 2e77055f | 5 |
38
+ | #828 (#820) | abb3aa93 | 5 |
39
+ | #829 (#816) | 0ee33764 | 4 |
40
+ | #830 (#799) | 3d9a42b3 | 2 |
41
+ | #831 (#814) | 2e56ed37 | 4 |
42
+ | #832 (#812) | 7ae412f9 | 2 |
43
+ | #833 (#814) | e95e052a | 2 |
44
+ | #834 (#814) | 486d47a6 | 5 |
45
+ | #836 (#835) | 5f2fd0c6 | 4 |
46
+ | #837 (#814) | f0e9589a | 2 |
47
+
48
+ ## Document review
49
+
50
+ Fourteen documents were stale against the 0.17.0 stamps (66db7605), 28 commits earlier. Each was rechecked against `git log 66db7605..HEAD` over its paths, the merged PRs above and the source itself, by this implementer. Most features were already documented by the PR that introduced them (operations.md carries 12 of those commits, tasks.md 7, daemon.md 3); the recheck looked for what no PR had updated.
51
+
52
+ | Document | Result | Checked claims and correction |
53
+ | --- | --- | --- |
54
+ | `src/cli/help.ts` | corrected | Every usage string in `main.ts`, `launch.ts`, `identity.ts` and `upgrade*.ts` was cross-checked against the help rows for its command and flags; the top-level command words of help and of the `commands` table match both ways (`pause\|resume` documented as one row). Corrections: `--full` added to `projects`, `queue list` and `task show` (accepted by their usage and by `operations.md`); the authority wording now matches `classifyPeerCommand` and the operations tables (`sdlc status\|explain\|queue\|release`, `queue list` and `release show` open to any agent as public views; `task cancel` and `export` also the conductor's; `task show` gives an agent the public view). `test/help.test.ts` and `test/identity.test.ts` pass unchanged. |
55
+ | `docs/security.md` | corrected | The conductor paragraph said a conductor cannot resolve deliveries or stop a peer; #818 and #827 grant both through the closed operational family, each admitted by `admitOperational` (role recheck, closed audit label), so the paragraph now lists the family, its bounds and what stays with the person, and the read-only forms any agent may run. The agent-mem pin sentence said 0.7.0; it is 0.8.0. |
56
+ | `docs/operations.md` | corrected | The header said 0.13.0; it describes 0.18.0 (protocol 16). The upgrade compatibility sentence and row said protocol 16 ended at 0.12.43; every tag from 0.12.20 through 0.17.0 carries `PROTOCOL = 16` (checked with `git show <tag>:src/hub/control-client.ts`), so both now read 0.18.0. The #812, #816, #820, #784, #793, #786 and #799 sections were already current. |
57
+ | `docs/quickstart.md` | corrected | Install pin `v0.18.0`; "Upgrading to the next release" is now "Upgrading to 0.18.0" and gains the agent and conductor authority, `auto_merge` (off by default), `review.same_family`, the Pi and local read-only shell grants, the opt-in remote runner and the 0.8.0 pin. |
58
+ | `README.md` | corrected | Status 0.18.0, control protocol 16, and the verification link points to this report. Feature bullets unaffected. |
59
+ | `docs/agent-notes/adapters.md` | corrected | New rules for the proven read-only shell grant and its synchronous recheck (#816) and for agent shell authority tables (#812). Scope gains `src/hub/read-only-shell.ts`, `read-only-shell-proof.ts`, `operational-authority.ts` (AGENTS.md and the manifest together). |
60
+ | `docs/agent-notes/local-worker.md` | corrected | The `bash` tool's permit, host recheck and one `forceAsk` retry (#816), and the turn-generation binding. |
61
+ | `docs/agent-notes/benchmarks.md` | corrected | The one covered file that changed, `src/local/tools.ts` (bash permit path), needs no benchmark driver change; stated. |
62
+ | `docs/agent-notes/tests.md` | corrected | The two CLI print scans and the per-command output tests (#814). Scope gains `test/cli-json-guard.test.ts`. |
63
+ | `docs/agent-notes/tasks.md` | no change | Already records the planner WIP breakdown, hub-verified CI block, verdict mirror, guarded merge and `review.same_family`. Scope gains `src/hub/sdlc-merge.ts` and `sdlc-mirror.ts`, which it already names. |
64
+ | `docs/agent-notes/daemon.md` | no change | Already records the CLI output default, `upgrade-output.ts` and the generic print guard (merged with #833 and #834). |
65
+ | `docs/agent-notes/bus.md` | no change | `daemon.ts` changed in operational admission, review and tool handling; the bus, digest and reply paths this note covers were not touched (no `bus.ts` change since the stamp). |
66
+ | `docs/agent-notes/budget.md` | no change | Same: no `budget.ts`, `usage-rollup.ts` or pause-persistence change since the stamp. |
67
+ | `docs/agent-notes/README.md` | corrected | Background for the CLI print guards and agent shell authority; `console-state.ts` changed only to show the planner WIP split in the Peers detail. |
68
+
69
+ Also corrected, outside the stamped set: `docs/memory.md` named agent-mem pin 0.7.0 and now says 0.8.0.
70
+
71
+ ## Known gaps, not blocking
72
+
73
+ - The recheck was by one implementer reading source and PRs, not three independent reviewers; the reviewer of this PR is the independent check on it.
74
+ - No running hub has been upgraded to 0.18.0 here. `auto_merge`, the verdict mirror and the conductor operational family are source and fixture tested; their live receipts follow the upgrade (see `docs/dogfood.md` rows #786, #812, #835).
75
+ - `docs/operations.md` has hand-written statements about older releases (for example "removed in 0.13.0") that were not touched.
76
+ - Flaky tests seen on main: `test/memory-code-head-684.test.ts` "#367 cached HEAD proof" (hub fail note d13a75e3). If the full gate hits it, the run is repeated and both results are reported in the task.
@@ -0,0 +1,35 @@
1
+ # Live codex-review verdict receipt (0.17.0)
2
+
3
+ Date: 2026-10-25, macOS arm64. Refs #783 AC3. Result: the production hub's `codex-review` instance reviewed one real pull request and recorded an approved verdict through `hub_review`. This is the first verdict recorded by `codex-review` on a running hub since the no-verdict failure of #783; the [model-backed fixture receipt](2026-10-25-codex-0164-reviewer-tool-call.md) covered the same path in a temporary fixture only.
4
+
5
+ ## Setup
6
+
7
+ | Item | Value |
8
+ |---|---|
9
+ | Hub | 0.17.0 release runtime, the project's own daemon (not a fixture) |
10
+ | Native reviewer | `codex-cli 0.164.0` (`ahub agents`: verified) |
11
+ | Declaration | `codex-review`, kind `codex`, roles `["reviewer"]`, `start_mode: "headless"`, `review_mode: "fresh"` (untracked `config.local.json`) |
12
+ | Enabled with | `ahub --live-test roster add codex-review`, then `ahub --live-test codex --as codex-review` (user-authorized live test) |
13
+ | Status after start | `codex-review idle attached`, no `reviewer isolation unavailable` line |
14
+
15
+ ## The review
16
+
17
+ | Item | Value |
18
+ |---|---|
19
+ | Hub task / PR | #476 / #809 (docs only, `docs/operations.md`, +9 lines) |
20
+ | Owner / reviewer | `claude` / `codex-review` (assigned by routing) |
21
+ | Reviewed head | `ce16b44be52161a950b66f9220e3cb565ae4781f` |
22
+ | Review request sent | 09:12:17 UTC |
23
+ | Reviewer busy | 09:12:17 UTC |
24
+ | Verdict recorded | 09:13:03 UTC, `approved` (46 s after the request) |
25
+ | Reviewer idle | 09:13:08 UTC |
26
+ | Board state after | `approved`, reviewer `codex-review` |
27
+
28
+ The verdict note cited the two code locations the doc change describes (`validateInstances`, `resolveInstanceExecutionCwd`), reported a read-only `check-docs` run and `git diff --check`, and listed one unmet item: it could not run `scripts/check.sh --changed` because the read-only sandbox refuses the gate's lock, install and build writes. The hub logged `premature review: exact-head full CI is not green` at the request; the review ran anyway, and the merge waited for CI separately.
29
+
30
+ ## Limits
31
+
32
+ - One review of one small docs-only change. A code review with findings and a `changes_requested` verdict were not exercised.
33
+ - Token use for this single review is unknown: `ahub usage` reports a cumulative counted total for `codex-review`, not per review.
34
+ - The reviewer cannot run the repository gate; its approvals rely on CI and the owner's reported gate for that.
35
+ - macOS only; native Linux behavior is not covered.
@@ -0,0 +1,46 @@
1
+ # Remote Docker extraction and cleanup receipt
2
+
3
+ Date: 2026-10-25. Refs #793, transport slice AC1/AC2/AC4/AC5. This is a local Docker transport-component proof, not an SSH or pi tool-call receipt. No machine opt-in, dependency preparation, account or model call occurred.
4
+
5
+ ## Versions and proof boundary
6
+
7
+ - Docker daemon 29.5.2, Linux arm64, through an existing Colima VM.
8
+ - Preinstalled image: oven/bun@sha256:9114c058aeae42162ee16dd5084b95fe9473970bb6bcb5b232ab1630f0546895. The fixture asserted the actual container Bun version was 1.4.2. No image pull occurred.
9
+ - Host Bun 1.4.3; macOS bsdtar 3.5.3, libarchive 3.7.4.
10
+ - Tested src/hub/check-runner.ts SHA-256: 58f6a9f2a86acbf4fb9165ca2315c8df2aaca27b871e6ed3eaef79a28d94f3ad.
11
+ - Private driver SHA-256: 07000fd8aadf00625255784f5ac7b27f6ec6f56166c1e6118031bf963545f091.
12
+
13
+ The existing VM exposes only two CPUs. Two initial attempts with the unchanged production four-CPU argument failed before transfer, and both cleaned their owned resources. The final component driver therefore lowered only the CPU cap from four to two. This is a stricter native-test limit; the product still requests four CPUs. The VM was not reconfigured or restarted. The exact four-CPU launch on the eventual remote host remains unverified.
14
+
15
+ The driver used the production remoteRunnerTransport with ContainerRunner's shared lifecycle and a direct Docker command port. It supplied no always-true dependency-ready predicate. A separate actual RemoteRunner.available() call returned remote dependencies unprepared, so this proof grants no sandboxed-peer tests capability.
16
+
17
+ ## Transfer and negative controls
18
+
19
+ A private synthetic Git fixture contained a nested canary, a lockfile and a bare bun:test file. The working-tree canary was changed after commit. The component returned the committed content, not the dirty working-tree version:
20
+
21
+ - Source commit: abac005b3a543eb3f7d10c74222009e027055776.
22
+ - Tree: 7cb96483df51495ff14e3ae2ad58b1f1398e2385.
23
+ - Lockfile SHA-256: 87b7aa7d4cc3d62bbabeb5971dac92dcf6f0a52815d11afb027fbed4b769c946.
24
+
25
+ Before extraction, the driver attached a benign macOS extended attribute to the staged canary. A baseline host archive retained that attribute, and the former docker cp - ...:/work path failed against the same running, read-only-root/tmpfs container. The production normalized archive omitted the custom attribute, macOS provenance metadata and host username. Its headers used uid/gid 65532 and static check owner/group names.
26
+
27
+ The unchanged production copy function streamed that archive through non-root docker exec -i ... tar --no-same-owner -xf - -C /work. Readback asserted exact committed content and source ownership uid 65532. The real Bun test exited zero; its process reported uid 65532 and six threads under the 64-pid limit. This is one small workload, not a capacity proof for every permitted check.
28
+
29
+ Docker documents the tmpfs copy limitation and recommends an in-container tar stream for this boundary: [Docker cp corner cases](https://docs.docker.com/reference/cli/docker/container/cp/#corner-cases).
30
+
31
+ ## Readiness, labels and teardown
32
+
33
+ The production readiness probe started a detached, project-labeled container, transferred its own tiny source using that same copy function, then checked non-root content readback and network isolation. The driver also inspected its run container and confirmed:
34
+
35
+ - Read-only root; network none; uid/gid 65532:65532.
36
+ - Capabilities dropped with ALL; no-new-privileges.
37
+ - 64 pids, 4 GiB memory and the disclosed two-CPU native-test cap.
38
+ - Source-only transfer; no host path, home, socket or credential mount.
39
+
40
+ The image and an added fixture label contained commas. The production inventory still found the owned container using project/name filters and individual JSON-encoded .Label fields. It never parsed the comma-joined .Labels display.
41
+
42
+ The shared lifecycle persisted a finished remote-shaped receipt, exit zero and linux/arm64 (remote docker 29.5.2). That is the library's platform string; this run used local Docker and no SSH connection. Production cleanup confirmed container absence and released the fixture repository heavy lease. Final project-scoped inventory was empty. The driver removed its own placeholder volume and fixture source, then released its separate native-verification reservation. No other project containers were stopped.
43
+
44
+ ## Remaining work
45
+
46
+ The production runner remains unavailable until the separate admitted, lockfile/Bun-keyed dependency preparation exists (AC3). A real remote SSH leg, the unchanged four-CPU launch there, person opt-in and pi's live hub_check_start receipt (AC6) remain separate work. The fake transport/config regressions and final packaging gate are recorded with the PR's exact head.
@@ -0,0 +1,46 @@
1
+ # General profile weekly verification receipt
2
+
3
+ Template only. No pilot result or verdict has been recorded.
4
+
5
+ - Week ending: YYYY-MM-DD
6
+ - Profile id: general
7
+ - Window bounds: unknown
8
+
9
+ ## Recorded profile JSON
10
+
11
+ Run ahub report --dogfood --since 7d --json once at the review boundary. Replace the null below with only the emitted profile subsection. Preserve numbers and null values. Include no project/person name, task title, path, raw log or model text; use anonymous identifiers where necessary.
12
+
13
+ null
14
+
15
+ ## Verification verdicts
16
+
17
+ Choose exactly one listed verdict for each claim after inspecting recorded evidence. Unknown data alone cannot establish support. These placeholders are not verdicts.
18
+
19
+ - writing-live-example
20
+ - Verdict: [supported | partly supported | not supported]
21
+ - Evidence task/event/receipt ids: []
22
+ - Remaining unknowns: unknown
23
+ - general-live-example
24
+ - Verdict: [supported | partly supported | not supported]
25
+ - Evidence task/event/receipt ids: []
26
+ - Remaining unknowns: unknown
27
+ - research-live-example
28
+ - Verdict: [supported | partly supported | not supported]
29
+ - Evidence task/event/receipt ids: []
30
+ - Remaining unknowns: unknown
31
+ - native-model-ingestion
32
+ - Verdict: [supported | partly supported | not supported]
33
+ - Evidence task/event/receipt ids: []
34
+ - Remaining unknowns: unknown
35
+ - context-retention
36
+ - Verdict: [supported | partly supported | not supported]
37
+ - Evidence task/event/receipt ids: []
38
+ - Remaining unknowns: unknown
39
+ - native-account-research
40
+ - Verdict: [supported | partly supported | not supported]
41
+ - Evidence task/event/receipt ids: []
42
+ - Remaining unknowns: unknown
43
+ - research-measurement
44
+ - Verdict: [supported | partly supported | not supported]
45
+ - Evidence task/event/receipt ids: []
46
+ - Remaining unknowns: unknown