@staix/agent-hub 0.12.24 → 0.12.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,23 @@
2
2
 
3
3
  Issue and pull request numbers in the entries for 0.7.7 and earlier refer to the previous repository, archived on 2026-09-30 when this repository's history was rewritten; the one exception is the open smoke-check issue, formerly #12, which moved here as #1. Numbers in newer entries refer to this repository.
4
4
 
5
- ## Unreleased
5
+ ## 0.12.26
6
+
7
+ - Import claude-mem observations under a checkout-independent identity, so the same observation is one entry on every machine after sync however the checkouts differ; scan the source database project-aware with a persisted machine-local cursor (`--restart` re-scans), so unrelated projects cannot starve the requested one; reconcile legacy duplicate imports with `ahub memory dedupe` through append-only supersede operations (#380).
8
+ - Protect the targets of direct-child symlinks of a protected directory under every data-policy form (exact entry, `data/*`, `data/**`), with case-compatible on-disk root discovery and a streaming scan inside the shared 4096-entry bound: a dangling link covers its lexical target, an unresolvable link loop aliases nothing, a root whose discovery budget is exhausted contributes no aliases, and an unreadable protected root still fails closed (#385).
9
+ - State the document converter's project-scoped read guarantee and the bounded, cleared-when-full failure record precisely in code comments and docs (#386).
10
+
11
+ ## 0.12.25
12
+
13
+ - Preserve person-owned reservations through planner grooming, including same-value changes (#378).
14
+ - Refuse stale Pi roster-return snapshots when native activity changes in flight (#378).
15
+ - Refresh deferred memory indexes for goal and suggestion reads (#378).
16
+ - Update overdue board badges when deadlines pass without rebuilding unchanged cards on every poll (#378).
17
+ - Match glob data policies against NFD, compatibility and long-s spellings, so a read-only or private subtree with a decomposed Hangul or accented name is protected (#382).
18
+ - Keep document converters from reading project files other than their input snapshot and program files, and stop retrying a failed conversion of unchanged bytes on every facts read (#382).
19
+ - Let `ahub watch kimi` follow a running headless Kimi under the default TUI start mode, and keep a newer Kimi TUI admission when an older socket closes (#382).
20
+ - Keep a disabled Codex plugin off when its hook trust entry remains, and read project Claude settings without blocking on a FIFO or device (#382).
21
+ - Gate `hub_task_done` once, refuse an overlapping done in advise mode, and let the owner relink a PR after a reviewed head was recorded (#382).
6
22
 
7
23
  ## 0.12.24
8
24
 
package/README.md CHANGED
@@ -4,7 +4,7 @@ Native multi-agent hub for one developer's machine: Claude Code, Codex, Kimi Cod
4
4
  hub-owned local-LLM worker, with optional Qwen Code and Jcode support, collaborate as peers in independent project directories, with
5
5
  task-aware model routing (Switchyard) in front of a self-hosted gateway (OmniRoute).
6
6
 
7
- Status: 0.12.24, control protocol 16. Durable delivery records distinguish queued
7
+ Status: 0.12.26, control protocol 16. Durable delivery records distinguish queued
8
8
  work from uncertain execution. The [smoke checklist](docs/smoke.md) records
9
9
  verified paths and remaining prerequisites.
10
10
 
@@ -33,7 +33,7 @@ cd <your project> && ahub init && ahub up
33
33
  Or install the same version from GitHub:
34
34
 
35
35
  ```bash
36
- bun add -g github:STAIxBWLB/agent-hub#v0.12.24 && ahub setup
36
+ bun add -g github:STAIxBWLB/agent-hub#v0.12.26 && ahub setup
37
37
  ```
38
38
 
39
39
  The installed commands remain `ahub` and `agent-hub`.
@@ -41,3 +41,5 @@ Scope: the Codex, ACP and Pi adapters and the Pi extension (turn `generation` an
41
41
  - Apply QWEN_MODE_IDS only to a production qwen025 adapter with verified qwen-code 0.25.0 native identity and advertised ids; legacy benchmark ACP stays unmanaged. Await the native acknowledgement before bus admission, preserve existing approval fences, and never map auto or plan. No Qwen quota classification exists until a pinned native refusal is observed.
42
42
 
43
43
  - ACP `onActivity` is a closed, transient person-only projection. Never publish it through the bus, log/event writers, UI, tools or memory. Emit only for an active turn; latch private envelopes and associated PII work, including unreadable privacy state, and discard pending chunks on turn teardown. Native terminal references do not authorize filesystem/terminal RPC reads.
44
+
45
+ - Pi TUI hub prompts (#379; an idle snapshot ACK arriving before a personal start inserted a hub prompt into the person's turn): attribute a start, end or settle to a hub turn only by the command's `promptId`, which lasts until the logical `agent_settled`; treat any other start while a hub prompt is pending or running as personal activity that detaches Pi. Settle `failed_safe` only on a `prompt_not_started` refusal bound to the verified owner, session, command id and generation; everything else stays `needs_review`. Refuse roster return without `fencedPrompt`.
@@ -15,3 +15,7 @@ Scope: the task flow, assignment, the state machine and the hub's MCP tools. Rea
15
15
  - Pass off-roster ids as data into `assign()` so its trace and every owner/reviewer choice share the membership filter. Refuse a manual off-roster assignment before a board write, including a reservation. Use `reassignForRoster` through the existing assignment delivery path on removal, including in-review ownership while keeping its review state; keep the old owner or reviewer when no eligible replacement exists and emit the guarded public-title notice. Preserve budget-relay behavior when sharing that implementation.
16
16
 
17
17
  - Phase checklists are written only through Tasks.recordLifecycle by that task's reviewer/person. Validate exact current Tasks.after edges and privacy before saving; never change dependencies, accepted owners or reservations from an import. Keep verified checklist claims separate from externally read CI, and bind them to the current reviewed head. Export only derived sanitized board/config projections.
18
+
19
+ - A planner patch that names `reserved` at all, the same value included, is refused while `hasPersonReservation` holds; planner pull and grooming both ask it (#378: a same-value write laundered a person's reservation).
20
+ - `done()` gates the SDLC transition once: pass `gated` to `complete()` when nothing was awaited since, and after any awaited gate readback refuse if another done already moved the task, in every mode (#382: advise recorded overlapping dones).
21
+ - A changed `reviewedHead`, or one supplied with a changed repo or PR, needs the reviewer or a person; a head dropped because the owner relinked the PR does not (#382: the owner could not relink, and could carry a head to a new PR).
@@ -13,3 +13,6 @@ Scope: tests, fakes and the test gate. Read before adding or changing a test or
13
13
  - A bounded polling wait must assert its condition after the last attempt, or document why giving up is intentional. Append-only event histories wait for a correlated closing event, not removal of the opening event. Before changing a slow wait, identify the unreached state and repair its cause (#296).
14
14
  - A request that a test expects a stop or shutdown to cut gets its rejection handler where the request is created, never after the awaited teardown: a late `catch` races the reset and the run fails on an unhandled rejection.
15
15
  - Run `bun scripts/seeded-check.ts` before reporting the seeded-guard gate complete. Keep the `scripts/seeds.json` cases sequential; require the same named test green before its seeded assertion fails. Seed rot, survivors, setup/compiler failures, timeout/watchdog termination and process leaks fail the gate. Never run the full seed runner from a unit test or mutate the source checkout; inspect preserved failed fixtures before removing them. CI runs this in the required Linux `seeded guards` job after the ordinary check, separately from `scripts/check.sh`.
16
+
17
+ - The whole-suite watchdog is `AHUB_CHECK_HANG_S` (default in `scripts/check.sh`, hosted macOS value in `.github/workflows/check.yml`; #378, macOS CI hit it while tests still passed): raise it only when the suite was still progressing at the cutoff, never for a hung test, and keep the per-test 20 s timeout.
18
+ - A seed's named test must run on Linux, where the seeded job runs: a darwin-only test reports no result there and fails the job (#382). Cover a macOS-only protection with its regression test instead.
@@ -2,7 +2,7 @@
2
2
 
3
3
  - Optional shared or machine-local config declares `pii.paths` and `data.readonly`, each at most 64 project-relative paths/patterns of at most 200 characters. Entries name exact paths/subtrees or bounded globs, with no command execution. Empty or absent lists preserve existing behavior. These initial policies apply at daemon start; edit config deliberately and restart to refresh them.
4
4
  - Example: `{ "pii": { "paths": ["data/private"] }, "data": { "readonly": ["data/raw"] } }`.
5
- - Matching compares declared spellings and real targets, including symlink aliases and case variants. Unknown resolution conservatively matches an active policy. Paths outside the project cannot be selected as policy entries; managed tools retain their existing project boundary.
5
+ - Matching compares declared spellings and real targets, including symlink aliases, case variants and NFC/NFD spellings, which a case-insensitive disk treats as the same name; entries also match compatibility forms and the long s, a deliberate over-match (#382). Unknown resolution conservatively matches an active policy. Paths outside the project cannot be selected as policy entries; managed tools retain their existing project boundary.
6
6
 
7
7
  # Private task flow
8
8
 
@@ -28,7 +28,8 @@
28
28
 
29
29
  - `*` matches any characters within one path segment, `?` matches one character, and a whole-segment `**` matches zero or more segments. Matching includes dot names and folds case consistently with the existing exact policy. A matched directory protects its subtree. Directory task scopes are private if they can contain a future matching descendant, even before a file exists.
30
30
  - Examples: `pii.paths = ["data/**/*.csv"]` and `data.readonly = ["data/raw-*/**"]`. Up to 16 wildcard characters per pattern. Absolute paths, parent traversal, bracket classes, braces, negation and mixed `**suffix` forms are refused. Backslashes remain literal in exact entries but are refused in glob entries; no escape syntax is interpreted.
31
- - Match both declared spelling and real target. Wildcard directory/file aliases are discovered from compatible prefixes, including symlink aliases to future targets. Discovery is refreshed per decision, with no stale cached expansion. It reads at most 4096 directory entries and traverses at most 32 levels. An unreadable/dangling/cyclic/out-of-project alias or an exhausted discovery bound conservatively protects rather than declaring a path public/writable. No discovered name or policy body is logged.
31
+ - An exact directory entry (`data`), a single-segment glob (`data/*`) and a subtree glob (`data/**`) all protect targets of symlinks directly inside `data`, including file targets. Only this one level is aliased: `data/sub/link` does not protect its outside target under any of these forms, while paths through the protected tree remain protected lexically. Exact entries and trailing `**` matches scan immediate children once, without descending; `*` retains its existing matched-link resolution. Retargeted links are evaluated afresh on the next decision. A self-link such as `data/loop -> .` adds only the directory itself and does not trigger a recursive walk.
32
+ - Match both declared spelling and real target. Wildcard directory/file aliases are discovered from compatible prefixes, including symlink aliases to future targets. Discovery is refreshed per decision, with no stale cached expansion. Wildcard discovery and immediate alias scans share one per-call budget of 4096 directory entries; wildcard traversal is limited to depth 32. Existing wildcard discovery runs before the new direct-child scans, so these scans cannot consume its budget first. Immediate scans stream directory entry types and resolve only symlink children, with no descent. For exact entries and trailing-`**` roots, a dangling direct child protects its lexical target (including a future target), an ELOOP child is skipped, and a root whose scan cannot complete within the remaining shared budget contributes no child aliases, even if an earlier child matched. Unreadable matched roots still fail closed, including when earlier roots used up the budget. Lexical protection of the tree stays in force; tree depth and cycles below that one level are never traversed. `data/*` retains its existing matched-link failure behavior, and descending glob discovery (`data/**/*.csv`, `**/ß`) retains its existing fail-closed handling of unreadable/dangling/cyclic/out-of-project aliases and exhausted bounds. No discovered name or policy body is logged.
32
33
  - Managed local/Pi write/edit and private Tasks/facts use this same matcher. Existing hardlink refusal, post-approval recheck and filesystem-read-only command profile remain unchanged.
33
34
  - Claude's managed `ask-when-needed` hook receives `ask` for a write matching data.readonly. Reads and ordinary project writes retain their existing scoped decisions. The daemon evaluates policy locally only for the current managed PreToolUse ask-when-needed write grant and sends no pattern list to the hook. PostToolUse, unavailable/ask/never-ask modes and non-write tools perform no grant-policy discovery. Explicit native approval and `never-ask` remain the person's native authority; this is scoped auto-grant filtering, not a new Claude sandbox or containment claim.
34
35
  - The previous malformed-config fixture that refused every wildcard now refuses an unsupported bracket class; its rejection assertion is retained. New tests establish the deliberately added glob grammar, future paths, wildcard aliases/retargeting, private scopes, discovery failures and actual daemon hook replies. Native account/model consumption is unverified.
package/docs/memory.md CHANGED
@@ -196,21 +196,58 @@ ahub memory demote 1a2b3c4d # a long-term entry becomes short-term
196
196
  ahub memory forget 1a2b3c4d # gone from the index here, and on other machines once synced
197
197
  ahub memory supersede <old> <new> # the old one is dropped from briefs and recall
198
198
  ahub memory rebuild
199
+ ahub memory dedupe # inspect legacy claude-mem duplicate groups
200
+ ahub memory dedupe --apply # append supersede relations, never rewrite log bytes
199
201
  ```
200
202
 
201
203
  A forgotten long-term entry stays in the log file and in the sync remote's git history; removing it from there is a
202
- person's rewrite of that history.
204
+ person's rewrite of that history. Forgetting a claude-mem import forgets every known non-forgotten member of its tuple group (source, project, source timestamp and text), including hidden duplicates, so they cannot reappear when their replacement is forgotten.
203
205
 
204
206
  ## Importing from claude-mem
205
207
 
206
- `ahub memory import claude-mem [--db <path>] [--limit N]` (a person's) copies the hub's own notes from claude-mem
208
+ `ahub memory import claude-mem [--db <path>] [--limit N] [--restart]` (a person's) copies the hub's own notes from claude-mem
207
209
  (observations whose metadata names a `peer`: `hub_remember` and the hub's task notes) into long-term hub memory as
208
- `source: claude-mem`, for this project only (claude-mem files them under the repository's own name; a superproject's
209
- notes stay out, and two unrelated repositories with one name share it). Model answers from `ahub ask --remember`, text
210
- matching a PII pattern, text about a path the project's `pii.paths` makes private and secret-looking text are skipped. An
211
- imported note is placed in the graph by the paths and symbols in its text (claude-mem keeps no task proposal time).
212
- claude-mem's database is opened read-only and never changed; an observation always maps to the same entry, on any
213
- machine, so importing again adds nothing.
210
+ `source: claude-mem`, for this project only. The SQL filters by the repository's basename before applying the limit;
211
+ a superproject's notes stay out, while two unrelated repositories with one basename still share claude-mem's namespace.
212
+ Model answers from `ahub ask --remember`, PII-pattern text, text about a path made private by the project's `pii.paths`
213
+ and secret-looking text are skipped. The source database is opened read-only and never changed.
214
+
215
+ - Import graph nodes are derived from text only: no checkout existence check and no machine-local `local.deny`.
216
+ Built-in denylisted names, relative-path normalization, absolute/parent exclusion, sorting and the 64-node cap still apply.
217
+ The source's timestamp and the existing content hash stay unchanged. Matching observations on different checkouts now
218
+ produce the same id; old ids, references and content validation remain valid. The local tuple fallback keeps re-import
219
+ idempotent even for legacy ids (its known ceiling is that the tuple excludes title).
220
+ - A machine-local `memory/import-state.json` records the last fully handled row, including all skips. The cursor key
221
+ combines the source DB's real path, claude-mem project name and hub project key. The file uses mode 0600 and atomic
222
+ replacement; it never syncs. Unreadable or malformed state replays from zero, write failure logs a warning and preserves
223
+ the import result, and a source whose maximum candidate id for this project is below the cursor resets it (unrelated projects cannot mask a recreated source). Completed progress is saved even if a later
224
+ row throws. `--restart` starts from zero; use it after changing a PII policy to revisit rows skipped under the old policy.
225
+ - The default limit is 10000. JSON reports `read` (project-matched, peer-tagged SQL rows this run), `added`,
226
+ `skipped.model`, `skipped.pii`, `skipped.secret`, `cursor` (last handled id), and `more` (`read === limit`). Malformed
227
+ metadata, non-string peers and empty text count only in `read`; already imported rows add nothing. `more` asks for
228
+ another run, which can return zero rows when the last batch exactly filled the limit. There is no project-skip counter.
229
+ - Repository identity still depends on the local real path without an origin remote, and non-GitHub remotes spelled
230
+ differently can yield different project keys. These affect all hub memory and remain outside this import fix.
231
+
232
+ ### Legacy duplicate imports
233
+
234
+ `ahub memory dedupe [--apply] [--json]` is console-only, including the listing, because it shows unscreened note text.
235
+ It groups this project's non-forgotten claude-mem entries by `(source, project, at, text)`. Listing reports only actionable
236
+ groups, their members, heads and chosen target; `--apply` appends ordinary supersede operations in this machine's log.
237
+ Historical log bytes are never rewritten. Forget operates on the whole known tuple group.
238
+
239
+ - Heads have no current replacement. Existing replacement relations, including a person's distinct outside notes, stay
240
+ intact. If every head can reach a valid synced outside terminal (shared when any head is shared), the newest qualifying
241
+ terminal by `(at, id)` replaces all heads, even a single head. Otherwise multiple heads converge onto the smallest id
242
+ among the heads; zero heads or one head without a qualifying outside terminal require no writes. A refused supersede
243
+ is reported as an error. Re-running after convergence writes nothing.
244
+ - When `A -> B` already exists inside a group, dedupe connects another head `C -> B`, without trying the cyclic `B -> A`.
245
+ When `B -> X` and `C -> Y` name outside user replacements, `X` and `Y` both remain visible; a remaining head moves to
246
+ the newer qualifying terminal. A later outside replacement can make a previously settled group actionable again.
247
+ - Old or mixed extractor versions can still introduce duplicate ids. Run dedupe after syncing them. Two machines acting
248
+ on divergent prior relations can choose different targets; sync folds relations deterministically using the existing
249
+ latest-relation and cycle guards. If several group members remain visible, one more dedupe run converges them. New
250
+ same-version imports with stable project keys converge automatically in either sync order.
214
251
 
215
252
  ## Measuring it
216
253
 
@@ -1,6 +1,6 @@
1
1
  # Operations guide
2
2
 
3
- This guide describes ahub 0.12.24 and control protocol 16. Live verification
3
+ This guide describes ahub 0.12.26 and control protocol 16. Live verification
4
4
  results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
5
5
 
6
6
  ## Command output
@@ -1129,7 +1129,12 @@ result and return) or `ahub codex resume` to select its previous native session.
1129
1129
  the terminal window itself. The Claude channel retries and reconnects on return.
1130
1130
  Pi return retains the verified owner's monotonic generation even after refused
1131
1131
  native activity while detached; it shares no personal output and invalidates any
1132
- cached empty-session resume proof after that activity.
1132
+ cached empty-session resume proof after that activity. Return also needs the
1133
+ current hub extension, which fences prompt admission: a TUI still running an
1134
+ older extension is refused (restart its retained terminal), and a return whose
1135
+ snapshot raced native activity is refused until retried. When personal TUI
1136
+ activity overtakes a hub prompt, Pi is detached: a prompt the extension proves it
1137
+ never inserted returns to the queue, anything else is held as `needs_review`.
1133
1138
  It leaves queued and held deliveries, and existing manual or budget pauses,
1134
1139
  untouched. The queue listing names `off roster` as the membership hold. Returning
1135
1140
  and starting the peer makes retained queued messages available again; held
@@ -1614,21 +1619,21 @@ section is what they run.
1614
1619
 
1615
1620
  Upgrade running projects with the target release's own coordinator. It accepts
1616
1621
  a running source on control protocol 9 (0.6.x), 10 (0.7.0 through 0.12.0),
1617
- 11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.24), and only
1622
+ 11 (0.12.1 and 0.12.2), 12 (0.12.3), 13 (0.12.4 through 0.12.15), 14 (0.12.16), 15 (0.12.17 through 0.12.19) or 16 (0.12.20 through 0.12.26), and only
1618
1623
  a target on its own protocol, so the target's coordinator fits every supported
1619
1624
  source and carries every recovery fix released up to it. Protocol 8 and older
1620
1625
  (0.5.x and earlier) are refused as `manual-bootstrap-required`. Run from the
1621
1626
  project directory, without replacing the global CLI first:
1622
1627
 
1623
1628
  ```bash
1624
- bunx --package @staix/agent-hub@0.12.24 ahub upgrade --to 0.12.24 --dry-run
1625
- bunx --package @staix/agent-hub@0.12.24 ahub upgrade --to 0.12.24 --yes
1629
+ bunx --package @staix/agent-hub@0.12.26 ahub upgrade --to 0.12.26 --dry-run
1630
+ bunx --package @staix/agent-hub@0.12.26 ahub upgrade --to 0.12.26 --yes
1626
1631
  ```
1627
1632
 
1628
1633
  | Running now | Coordinator to use |
1629
1634
  | --- | --- |
1630
1635
  | 0.6.x (protocol 9) | the target's, through `bunx` as above |
1631
- | 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.24 (protocol 16) | the target's, through `bunx` as above |
1636
+ | 0.7.0 through 0.12.0 (protocol 10), 0.12.1 and 0.12.2 (protocol 11), 0.12.3 (protocol 12), 0.12.4 through 0.12.15 (protocol 13), 0.12.16 (protocol 14), 0.12.17 through 0.12.19 (protocol 15), 0.12.20 through 0.12.26 (protocol 16) | the target's, through `bunx` as above |
1632
1637
  | any supported source, with the installed CLI already at the target | `ahub upgrade` below, which is the same coordinator |
1633
1638
  | 0.5.x or earlier (protocol 8 and older) | not supported: bootstrap by hand with the matching CLI |
1634
1639
 
@@ -1660,14 +1665,14 @@ projects first:
1660
1665
 
1661
1666
  ```bash
1662
1667
  ahub restart --dry-run
1663
- ahub upgrade --to 0.12.24 --dry-run
1668
+ ahub upgrade --to 0.12.26 --dry-run
1664
1669
  ```
1665
1670
 
1666
1671
  Apply only after reviewing the plan:
1667
1672
 
1668
1673
  ```bash
1669
1674
  ahub restart --yes
1670
- ahub upgrade --to 0.12.24 --yes
1675
+ ahub upgrade --to 0.12.26 --yes
1671
1676
  ahub recovery status [<operation-id>]
1672
1677
  ahub recovery resume [<operation-id>]
1673
1678
  ahub recovery abort [<operation-id>]
@@ -2316,9 +2321,11 @@ ancestor: the manifest-only follow-up commit need not hash or stamp itself.
2316
2321
 
2317
2322
  ## Seeded guard verification
2318
2323
 
2319
- `bun scripts/seeded-check.ts` runs six guard pairs sequentially: header quoting,
2320
- Origin refusal, control-token authentication, the hop cap, PII public views and
2321
- uncertain-delivery receipts. Each named test first passes on current tracked
2324
+ `bun scripts/seeded-check.ts` runs every guard pair in `scripts/seeds.json`
2325
+ sequentially, starting with header quoting, Origin refusal, control-token
2326
+ authentication, the hop cap, PII public views and uncertain-delivery receipts.
2327
+ A guard needs a test that runs on Linux, where the CI job runs; a macOS-only
2328
+ protection (sandbox, text projection) is covered by its regression test. Each named test first passes on current tracked
2322
2329
  checkout bytes, then must fail an assertion with the corresponding guard weakened.
2323
2330
  Seed rot (anything other than one exact replacement), a surviving seed and an
2324
2331
  invalid detection have distinct errors. Compiler, setup, unrelated-test and timeout
@@ -2334,8 +2341,8 @@ fixture location with test and leak evidence for inspection.
2334
2341
 
2335
2342
  The required Linux CI job `seeded guards` follows the ordinary checks; it does not
2336
2343
  repeat on macOS or run recursively inside `bun test`. The runner reports every
2337
- pair's elapsed seconds and the total runtime. Runtime measurement remains pending
2338
- until that gate executes; a green ordinary check alone does not prove these pairs.
2344
+ pair's elapsed seconds and the total runtime. A green ordinary check alone does
2345
+ not prove these pairs.
2339
2346
 
2340
2347
  The full CI gate tests the PR head tree on Linux and macOS, followed by the
2341
2348
  sequential seeded-guard job. Main and release jobs reuse only a successful full
@@ -2344,6 +2351,9 @@ unreadable result runs the main gate again and refuses release. A manual
2344
2351
  `prepare_bundle` dispatch builds reviewable plugin assets without publishing;
2345
2352
  it is never accepted as full-gate evidence. A `timing_runs=20` dispatch runs only the daemon, PII screen and ACP
2346
2353
  test files twenty times on macOS, in its own concurrency group; it does not replace the full gate.
2354
+ `scripts/check.sh` stops a suite still running after `AHUB_CHECK_HANG_S` seconds
2355
+ (600 by default); hosted macOS CI sets 780 inside the unchanged 15-minute job
2356
+ limit (#378).
2347
2357
 
2348
2358
  ## Preview initialization and native launch
2349
2359
 
@@ -2612,7 +2622,7 @@ Native policy is unmanaged and has NO hub sandbox; no permission_modes.jcode or
2612
2622
 
2613
2623
  # Rich-document text projections (#259)
2614
2624
 
2615
- - Configure text_projection only in an untracked machine-local file, with a separate {input} argv argument. Facts uses bounded read-only/no-network conversion and a content/config cache; failure keeps the prior file view and logs a bounded notice.
2625
+ - Configure text_projection only in an untracked machine-local file, with a separate {input} argv argument. Facts uses bounded read-only/no-network conversion from a scratch directory, where the converter reads only its input snapshot and its own program and script files (no other project file, even under `local.read_allow`), and a content/config cache; failure keeps the prior file view and logs a bounded notice, and a conversion that failed with its full deadline is not retried for the same bytes and command while its entry lives in the failure record, which is in memory, bounded at 1024 entries, and cleared when full or at restart (#382).
2616
2626
  - Raw change identity and projected presentation stay separate; private paths never enter conversion. Schema, limits and current surface scope: [text projections](text-projection.md).
2617
2627
 
2618
2628
  # Task catalog guidance (#295)
@@ -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.12.24
20
+ bun add -g github:STAIxBWLB/agent-hub#v0.12.26
21
21
  ahub setup
22
22
  ```
23
23
 
@@ -38,7 +38,7 @@ In your project directory, one terminal each:
38
38
  ahub init # .agenthub/config.json, .agenthub/routing.toml, the marker block in AGENTS.md
39
39
  ahub up # starts the daemon and opens the operator console in a terminal
40
40
  ahub console # use in another terminal if up used --no-console; Tab opens panels
41
- ahub kimi # Kimi, headless
41
+ ahub kimi # Kimi in its own pull-only TUI; --mode headless for the hub-driven peer
42
42
  ahub codex # Codex TUI, attached through the hub
43
43
  ahub claude # Claude Code with the hub channel
44
44
  ```
package/docs/smoke.md CHANGED
@@ -1626,9 +1626,12 @@ Confirm JSON output stays plain under `--color=always`. Record the exact head an
1626
1626
  process in a trusted project. Stop ACP and return to a new TUI, preserving queued
1627
1627
  work and task ownership. Unverified.
1628
1628
 
1629
- ## Initial SDLC gates (#257)
1629
+ ## SDLC gates (#257)
1630
+
1631
+ Source is complete: head-bound gates (#333), gsd-lite checklists (#336), bounded custom stages and gates (#349), and the read-only merge queue and release report in CLI, console and dashboard (#350). Fake-gh and task fixture checks are source/unit evidence only.
1632
+
1633
+ Unverified (tracked in #273): one real issue on this repository taken through merge and release under `sdlc.mode = "advise"`. Record the issue, PR, heads, each gate's blocker readback and `ahub sdlc release` output here. No live cycle or automatic merge is claimed.
1630
1634
 
1631
- Unverified: a live repository cycle through merge/release under advise. Fake-gh and task fixture checks are source/unit evidence only. Custom lifecycle gates and full release-readiness presentation remain pending; no live cycle or automatic merge is claimed.
1632
1635
  ## Qwen Code 0.25.0 production peer (#256)
1633
1636
 
1634
1637
  Unverified: real provider handshake, a native model/tool turn, context occupancy,
@@ -1651,11 +1654,14 @@ Source/fixture proof is recorded in verification/2026-10-11-jcode-peer-contract.
1651
1654
  - Source model and isolated DOM/daemon regressions cover five columns, ready/wait
1652
1655
  reasons, public stubs, owner/reviewer markers, keyboard buttons, assignment and
1653
1656
  staging authority, stale/foreign gesture fences and legacy capability refusal.
1654
- - Current source checks are pending for this draft; browser visual verification
1655
- at desktop/phone widths and real peer permission/state readback are unverified.
1656
- - Native planner grooming into two releases, planned/actual date measurement and
1657
- GitHub import remain unverified or unimplemented in later source slices. No
1658
- release, installation, account experiment or live activation is implied.
1657
+ - Source shipped in #353, #359 and #361 to #367 (v0.12.24); the reservation and
1658
+ overdue fixes in #379. Phone/desktop source captures are in
1659
+ verification/2026-10-13-board-phone.md. A real browser look and real peer
1660
+ permission/state readback are unverified.
1661
+ - Unverified (tracked in #273): a native planner grooms a small backlog into two
1662
+ releases, with planned and actual dates read back. A real GitHub intake
1663
+ (#365) is unverified. No release, installation, account experiment or live
1664
+ activation is implied.
1659
1665
 
1660
1666
 
1661
1667
  ## Planning and release controls (#263)
@@ -1663,9 +1669,9 @@ Source/fixture proof is recorded in verification/2026-10-11-jcode-peer-contract.
1663
1669
  Source/fixture coverage is in planning.test.ts and planning-surfaces.test.ts:
1664
1670
  legacy/restart persistence, revision/role/pin/person order/frozen scope/undo/ship,
1665
1671
  actual task dates, CLI marker authority, public PII and research reset identities.
1666
- All current platform and seeded checks remain pending. Desktop/phone rendering and
1667
- native planner grooming into two releases are unverified; no real account run,
1668
- tag, publish, install or live activation was performed.
1672
+ Platform and seeded checks passed at each merged head. A real browser look and
1673
+ native planner grooming into two releases are unverified (see Project board above);
1674
+ no real account run was performed.
1669
1675
 
1670
1676
  ## Office stack merge review (#355, #357, #358, #360)
1671
1677
 
@@ -2424,7 +2424,7 @@ the queue.
2424
2424
 
2425
2425
  ## Amendment: bounded data policy globs (#259)
2426
2426
 
2427
- pii.paths and data.readonly accept exact paths/subtrees and *, ? and whole-segment ** patterns. Validation keeps 64 entries, 200 characters each and at most 16 wildcard characters. Unsupported bracket/brace/negation/escape syntax, absolute paths and parent traversal refuse. Matching folds case, protects matched subtrees and treats parent task scopes as private when a future matching descendant is possible. Resolve both declared and real paths; wildcard alias discovery is uncached and bounded to 4096 directory entries and 32 levels. Resolution/discovery failure conservatively matches an active policy. Managed local/Pi tools retain hardlink and read-only command protections. Only an authenticated pre-tool ask-when-needed write grant evaluates the daemon-side read-only matcher; other phases/modes perform no grant-policy discovery. Protected grants are withheld without exposing policy paths; explicit approval/never-ask remain native authority, with no new sandbox claim. No account/research pilot is implied.
2427
+ pii.paths and data.readonly accept exact paths/subtrees and *, ? and whole-segment ** patterns. Validation keeps 64 entries, 200 characters each and at most 16 wildcard characters. Unsupported bracket/brace/negation/escape syntax, absolute paths and parent traversal refuse. Matching folds case, protects matched subtrees and treats parent task scopes as private when a future matching descendant is possible. Resolve both declared and real paths; wildcard alias discovery is uncached and bounded to 4096 directory entries per decision and 32 levels. Wildcard resolution/discovery failure conservatively matches an active policy. Exact entries and trailing-** roots also protect the targets of symlinks directly inside the matched directory, one level only (#385): a dangling child protects its lexical target, an ELOOP child is skipped, a root whose scan does not complete within the shared budget contributes no child aliases, and an unreadable root matches; * keeps its matched-link resolution. Managed local/Pi tools retain hardlink and read-only command protections. Only an authenticated pre-tool ask-when-needed write grant evaluates the daemon-side read-only matcher; other phases/modes perform no grant-policy discovery. Protected grants are withheld without exposing policy paths; explicit approval/never-ask remain native authority, with no new sandbox claim. No account/research pilot is implied.
2428
2428
 
2429
2429
  ## Amendment: custom lifecycle data (#257)
2430
2430
 
@@ -2798,3 +2798,35 @@ The per-issue intake failure boundary includes existing-row lookup and profile p
2798
2798
  Release snapshots group scope rows once and read approval dates once per task. Cross-release audit previews contain at most 32 IDs per category plus exact counts, with truncation disclosed in the UI. Sorted date indexes preserve strict after-cut semantics without rescanning every task history for every release. Full audit pagination remains a future extension.
2799
2799
 
2800
2800
  Release-card invalidation includes the task-state snapshot, so approval of a prerequisite outside the release refreshes blocked counts even when the release row and audit preview are unchanged.
2801
+
2802
+
2803
+ ## v0.12.24 audit corrections (#378)
2804
+
2805
+ Planner grooming cannot clear, replace or reassert a person-owned reservation;
2806
+ only a person may change that decision. Pull and grooming share the same
2807
+ reservation provenance, including a return to Backlog after a planner pull.
2808
+
2809
+ A personal Pi roster return rejects its snapshot if authenticated, current
2810
+ native lifecycle activity was observed while the snapshot was in flight. The
2811
+ session remains detached, and a fresh snapshot retry is required before hub
2812
+ admission. The owner process and queued deliveries are retained.
2813
+
2814
+ Goal and suggestion reads retry deferred segment indexing just as note reads
2815
+ do. This adds no log format change and does not invoke unrelated note promotion
2816
+ for an already fresh goal or suggestion read.
2817
+
2818
+ The board's existing polling notices deadline crossings through derived overdue
2819
+ state in its render cache. Unchanged overdue state preserves the current DOM.
2820
+
2821
+ The current Pi extension negotiates fenced prompt admission at verified session
2822
+ startup. It checks native idle state immediately before synchronous prompt
2823
+ insertion, refuses insertion while its settlement callback is active, and tags
2824
+ hub prompt lifecycle events with the command id. A delayed personal lifecycle
2825
+ must not consume a hub audience or receipt. Only a verified command/session-bound
2826
+ pre-effect refusal permits safe requeue; uncertain delivery stays held. Roster
2827
+ rejoin without this extension capability is refused, requiring a current native
2828
+ session instead of assuming that an older extension provides the fence.
2829
+
2830
+ Prompt lineage lasts until logical `agent_settled`: native retry, compaction or
2831
+ continuation starts inside that run retain the same command id. A later personal
2832
+ run has no hub command lineage.
@@ -2,8 +2,8 @@
2
2
 
3
3
  - Optional machine-local text_projection maps lowercase extensions to argv arrays. Each uses one separate {input} argument. No shell string, automatic converter install or default command.
4
4
  - Example: { "text_projection": { ".docx": ["/usr/bin/textutil", "-convert", "txt", "-stdout", "{input}"] } }. Configure the converter explicitly for the machine. Shared/tracked config cannot choose these programs.
5
- - Facts excludes private paths before conversion. The converter reads an immutable snapshot in an owned temporary directory, with a literal read grant for that file only, uses the existing macOS no-network/read-only sandbox and has a 5-second deadline, 16 MiB input cap and 256 KiB stdout/stderr cap. A trusted helper owns and stops its process group; converter stderr is never published.
6
- - Output caches in state by raw content hash, extension and argv/program/script metadata fingerprint. Invalid/oversized cache or failing/unavailable conversion falls back to the existing raw/binary facts behavior, with one bounded notice per extension.
5
+ - Facts excludes private paths before conversion. The converter reads an immutable snapshot in an owned temporary directory, from its own scratch directory, with literal read grants for that file and for the program and script files its argv names (relative ones are passed as absolute paths, and the directories above an in-project script can be listed) (nothing else in the project is readable, even under a `local.read_allow` entry that encloses it, so a converter that follows an include or loads a sibling helper module fails), uses the existing macOS no-network/read-only sandbox and has a 5-second deadline, 16 MiB input cap and 256 KiB stdout/stderr cap. A trusted helper owns and stops its process group; converter stderr is never published.
6
+ - Output caches in state by raw content hash, extension and argv/program/script metadata fingerprint. Invalid/oversized cache or failing/unavailable conversion falls back to the existing raw/binary facts behavior, with one bounded notice per extension. A conversion that fails with its full deadline is not tried again for the same bytes and command while its entry lives in the failure record, which is in memory, bounded at 1024 entries, and cleared when full or at restart (#382).
7
7
  - Raw hashes and git blob identities remain the change identities. Projected text only supplies presentation diffs. A projected read or patch cannot establish raw-file write attribution. Existing text privacy checks and header sanitization still apply.
8
8
  - Converter programs may require temporary writes/caches; those fail under this read-only policy. Use a converter that emits stdout. The owner and other native same-user processes remain outside this boundary.
9
9
  - Linux retains no-sandbox/no-converter behavior. No native model/account study runs. Shadow repositories and profile override/glob follow-ups remain open in #259.
@@ -0,0 +1,123 @@
1
+ # v0.12.24 implementation audit
2
+
3
+ Baseline: `v0.12.24`, commit `e311b50b7367668ae9b84f37e46886831de67850`.
4
+ Change contract: [#378](https://github.com/STAIxBWLB/agent-hub/issues/378).
5
+
6
+ ## Feature inventory and review scope
7
+
8
+ The release changes 287 files, with 28,958 insertions and 1,008 deletions relative to v0.12.23. This is a risk-focused audit, not an exhaustive certification of every changed line.
9
+
10
+ | Area | Shipped behavior reviewed | Review boundary |
11
+ | --- | --- | --- |
12
+ | Planning and board | Backlog, reservations, WIP pull/return, split, dependency planning, GitHub intake | Tasks transitions, board persistence, related unit and surface tests |
13
+ | Native adapters | ACP cancellation, optional jcode, Pi roster return and recovery | Changed adapter paths and fixtures; no real-account execution |
14
+ | Hub memory | Append-only notes, graph, goals, leases, import and private-remote sync | Store, import, sync, recall, CLI and related tests |
15
+ | Dashboard and attention | Five columns, planning dates, Office projections, attention and pets | Shared models, dashboard rendering/actions, console deltas and DOM fixtures |
16
+ | Document and delivery evidence | Text projection, path policy, release/merge readiness | Selected source paths; no converter or remote delivery trial |
17
+
18
+ Independent read-only reviews covered the first four areas. Additional source inspection covered text projection and path-policy boundaries. OCR preview and file rules were collected for the release range: 120 reviewable files and 167 excluded files. That inventory is not a claim that all 287 files received a full review. Unexamined release paths include portions of benchmarks, research measurement, role/profile integration, CI/package tooling and daemon wiring outside the reported triggers.
19
+
20
+ ## Corrected defects
21
+
22
+ - Person reservation protection: planner grooming could clear or replace a person's reserved peer, or write the same value to change its provenance and then bypass the pull guard. Shared provenance checks now refuse all planner reservation writes while the current reservation belongs to a person. Person overrides and ordinary planner reservations remain supported.
23
+ - Pi roster return: a native start or settlement arriving during a session snapshot request could be overwritten by its stale idle flag. This could admit work during a personal turn or leave queued work permanently busy. Authenticated lifecycle changes now invalidate the snapshot; the verified owner, detached state and queue remain intact for a fresh retry.
24
+ - Deferred memory indexing: goal and unscoped suggestion reads bypassed the freshness check used by note reads. After an append succeeded while SQLite was busy, these readers could retain stale goals, links, leases or suggestion verdicts. All three reader families now share the freshness check without changing log bytes or the index schema.
25
+ - Overdue board rendering: the cached board did not refresh when time alone crossed a task deadline. Its key now includes the derived overdue IDs, with the same values used for card badges. Unchanged overdue state preserves DOM identity.
26
+
27
+ ## Verification
28
+
29
+ Before the source changes, 24 new assertions failed for the reported conditions and one new compatibility case passed. The same regressions were retained unchanged after the fixes. The related four-file suite then passed 94 tests and 542 assertions with no failures in 44.02 seconds.
30
+
31
+ The memory regressions use real SQLite write contention, both the writer and another pre-opened store, and compare the recovered index with a rebuild. Pi regressions interleave authenticated lifecycle events and snapshot acknowledgements, then verify a fresh retry and exactly-once queued delivery. The board regression executes the actual render cache with a controlled clock and checks DOM identity before and after the deadline.
32
+
33
+ Nine mutation guards exercise the new protections. Two existing mutation selectors were retargeted to the refactored code while preserving their original test and mutation intent. All 391 selectors match exactly once. Final full-gate and mutation-run outcomes are recorded on the PR at its exact reviewed head; selector matching alone is not a passing mutation run.
34
+
35
+ ## Remaining limits
36
+
37
+ - Import identity needs a compatibility design: the same claude-mem observation can acquire different content IDs when filesystem-derived graph nodes differ across machines. A safe correction must retain old content-hash validation, append-only logs, graph determinism and existing forget/supersede references. This audit does not silently rewrite those logs.
38
+ - Import scan semantics need clarification: the current limit is applied before project filtering, so older rows from unrelated projects can consume the scan window. A project-aware bounded pagination design should preserve the existing result counters and privacy checks.
39
+ - Existing native/account, physical terminal/font and research-effect obligations remain unverified. Fixture or source success does not close those release obligations.
40
+ - This change does not publish a release, upgrade an installed CLI or restart a live daemon.
41
+
42
+
43
+ ## Additional review: acknowledgment before native activity
44
+
45
+ The first corrective head passed the local full gate (2,667 tests, zero failures,
46
+ 188,881 assertions, `check: OK`, no owned daemon leaks) and both platform checks.
47
+ External review then identified the opposite transport ordering: an idle snapshot
48
+ ACK can arrive before a personal start event, so a daemon-side event counter alone
49
+ cannot prevent native prompt insertion or erroneous personal-output attribution.
50
+ Those earlier passing checks therefore do not certify this additional race.
51
+
52
+ The follow-up extends the verified Pi bridge handshake with native prompt admission
53
+ and command lineage. Native prompt consumption, not receipt of an idle snapshot,
54
+ is the insertion boundary. A legacy extension without this proof cannot rejoin the
55
+ roster. Dedicated extension/adapter regressions cover the additional transport
56
+ ordering; final results belong to the PR's current head.
57
+
58
+
59
+ The extension performs its final idle/generation check and prompt insertion in
60
+ one synchronous JavaScript turn. The pinned native path claims an active run
61
+ before its first await; if the post-insertion idle check does not prove that
62
+ claim (for example, another extension defers it during settlement), the effect
63
+ is classified as uncertain and no hub lineage is lent to a later personal turn.
64
+ The callback barrier supports normal queue draining; it is not treated as an
65
+ atomic reservation across all third-party extension callbacks.
66
+
67
+ The dedicated follow-up regressions cover the actual extension, retained native
68
+ owner, delivery journal, malformed refusal fields, legacy capability refusal,
69
+ capability downgrade, accepted-turn replacement and old-lineage retirement.
70
+
71
+
72
+ The follow-up Pi suite passed 72 tests with 642 assertions and no failures in
73
+ 9.53 seconds, followed by a successful TypeScript check. This includes 11 new
74
+ prompt-admission regressions and the existing Pi, roster, receipt and ceiling
75
+ suites. All existing assertions were retained; the shared fake bridge now sends
76
+ the additive capability and command lineage of the current extension.
77
+
78
+
79
+ Independent review of the native continuation path then identified that one
80
+ logical prompt can emit several `agent_start` events before `agent_settled`.
81
+ A real-extension regression reproduced loss of the command ID on the second
82
+ start. The ID now persists until logical settlement; later personal runs remain
83
+ untagged. The adapter regression also checks one accepted delivery completes
84
+ once across the retry sequence.
85
+
86
+
87
+ ## Hosted macOS whole-suite budget
88
+
89
+ Both hosted macOS attempts at `79d308b0` reached the unchanged 600-second
90
+ whole-suite watchdog while individual tests continued to pass. They recorded
91
+ 2,593 and 2,313 completed pass lines, no named assertion failure, exit 143 and no
92
+ current-invocation daemon leaks. The same-head local gate completed 2,680 tests
93
+ with no failures in 500.85 seconds. This establishes a whole-suite budget cutoff;
94
+ it does not establish an individual hang or a production regression.
95
+
96
+ The new SQLite-contention cases consumed about 63 seconds on each hosted run
97
+ and 37 seconds locally. Workload growth and runner latency contribute to budget
98
+ use, but their separate causal shares are unknown. The CI macOS gate now uses
99
+ the existing `AHUB_CHECK_HANG_S` option at 780 seconds. The job retains its
100
+ 15-minute ceiling, each test retains its 20-second bound, all tests and leak
101
+ checks remain present, and execution remains serial. Linux and local invocation
102
+ defaults remain 600 seconds. No expectation or fixture timing was changed to
103
+ address this cutoff. Current-head CI must still pass before verification is
104
+ reported complete.
105
+
106
+
107
+ ## Second pass (#382)
108
+
109
+ Scope: the areas listed above as unexamined or selected-only: SDLC and delivery evidence, data path policy and document projection, roles/research/tooling, and the jcode, Kimi and ACP adapters with their daemon wiring. Four independent read-only reviews ran against `a8143c96`; every finding was reproduced by a regression test that failed before its fix.
110
+
111
+ Corrected:
112
+
113
+ - Glob data policies lowercased names only. A directory stored in NFD with an NFC pattern, e.g. `data.readonly: ["학생자료/**"]`, was not matched, so a read-only file could be overwritten and a private subtree read as public. Both sides now use `foldSegment`.
114
+ - The converter sandbox was rooted at the project. A converter following an include published a `pii.paths` file's text. It is now rooted at an empty system directory, project file data is denied even under an enclosing `local.read_allow`, and only its snapshot and program files are granted.
115
+ - A failing converter ran again on every facts read, about 5 s on the event loop each time. A full-budget failure is remembered per input, command and extension for the process lifetime.
116
+ - `ahub watch kimi` judged headless Kimi by the configured start mode, and an older Kimi TUI socket's close cleared a newer admission.
117
+ - A disabled Codex plugin was re-added from its `hooks.state` trust entry; project Claude settings were read with a blocking, unbounded read.
118
+ - `hub_task_done` gated the review transition twice (four gh calls, two advice notices), and advise mode recorded overlapping dones. An owner could not relink a PR after a reviewed head was recorded.
119
+
120
+ Examined and kept: the Kimi MCP writer replaces any `agent-hub` entry, as operations.md and the existing test define that key as the hub's own. Converters that load sibling helper modules from the project no longer can; docs/text-projection.md now says so.
121
+
122
+ Gate review then found that folding made `?` stop matching a name whose fold expands (`ß`, `fi`); matching now accepts either the lowercase or the folded spelling. A further review found that denying project data broke converters that call getcwd or load a relative project script; the converter now runs in its scratch directory with absolute program paths and listing grants for the directories above an in-project script. Ten new mutation guards cover the fixes; the projection protections have regression tests only, because those tests run on macOS and the seeded job runs on Linux. Native/account behavior remains unverified as before.
123
+
@@ -0,0 +1,27 @@
1
+ # 0.12.25 release verification
2
+
3
+ This record covers release preparation and source verification. It does not certify tagging, package publication, global installation or a live upgrade; those receipts are recorded separately.
4
+
5
+ ## Candidate
6
+
7
+ 0.12.25 carries the two v0.12.24 audit passes: #379 (issue #378) and #383 (issue #382), plus the docs-only #381. Control protocol remains 16.
8
+
9
+ - #379: person reservations survive planner grooming, Pi roster return and prompt admission are fenced against native activity, deferred memory indexes refresh on goal and suggestion reads, overdue badges update on deadline crossing.
10
+ - #383: glob and exact data policies match NFD, compatibility and long-s spellings without protecting less than before, document converters run in their scratch directory and read no project file other than their snapshot and program files, a failed conversion is not retried for the same bytes and command, Kimi watch and admission follow the live owner, disabled Codex plugins stay off, Claude settings reads are bounded, and SDLC done is gated once with reviewed-head ownership kept.
11
+
12
+ Each #383 fix has a regression test that failed before it. Four independent read-only reviews of #383 found further defects; each was fixed and reviewed again until the final head was approved. The final independent review fuzzed `matchesPolicy` against v0.12.24 over real temporary trees and reported no case where the release protects less.
13
+
14
+ ## Document review
15
+
16
+ Every stale document was rechecked against the covered source changes since its stamp. README, Quickstart and Operations carry the 0.12.25 version and install/upgrade strings. Operations now states Pi return's extension requirement and prompt fencing, the converter scope and failure memo, the seeded-guard scope and the macOS suite watchdog. Quickstart's `ahub kimi` line now names the default pull-only TUI. Area notes gained rules for Pi prompt attribution (adapters), reservation provenance, done gating and reviewed-head ownership (tasks), and the suite watchdog and Linux-only seeds (tests). Security, Benchmarks, Budget, Bus and Daemon were confirmed accurate. `src/hub/path-policy.ts`, `text-projection.ts`, `tooling.ts` and `memory/store.ts` are covered by no area note; their contracts are in docs/data-policy.md and docs/text-projection.md, updated in #383.
17
+
18
+ ## Recorded checks
19
+
20
+ - PR #383 final head 716adaff: local `scripts/check.sh` 2689 pass, 0 fail, 189022 assertions, `check: OK`; CI Linux and macOS checks and the seeded guards passed.
21
+ - PR #381 head 138cdcb6: CI Linux, macOS and seeded guards passed; independent review approved.
22
+ - Release candidate 6e6b35b5: local `scripts/check.sh` 2689 pass, 0 fail, 189022 assertions, `check: OK`, documents fresh. Later commits on this branch change documentation only.
23
+ - Release head: CI, document freshness at the merge commit, and the release workflow are required before tagging is reported complete.
24
+
25
+ ## Not verified
26
+
27
+ Native, account and research legs remain open in #273 and #1. The installed runtime and live hubs are not upgraded by this release.