# Round-2 verification of v9 against round-1 Sonnet panel (coverage/architecture/adversarial/security)

Spec: docs/architecture/specs/task-workflow-format-unification.md, v9 (ec5d062), branch
claude/akm-markdown-tasks-history-75l6du. Baseline for code claims: same checkout.

Method: for every critical/major in the four r1 reports, located the v9 text via §11's
cross-reference table, read the cited section in full, and where the fix leans on a
factual code claim, re-verified the claim by reading the cited file. Then checked the
new text against the rest of v9 for reintroduced contradictions, with extra scrutiny on
the five areas called out (§5.6 ceiling, persona-snapshot hash, `with:` merge, tombstone
+ crash-window ordering, shim vs resolve-akm-bin.ts).

## Criticals — all four verified fixed, no reintroduced contradiction

- **coverage C5** (§5.6 grant contradicts activation-policy's no-new-trust decision):
  v9 deletes the `bundles.<name>.allowScriptExecution` grant entirely and replaces it
  with exact inheritance of the existing `tools:` provenance ceiling (primary-stash-only,
  no override, fail-closed) — verified `show.ts:433-445` really has no override
  (`if (response.toolPolicy !== undefined && !isPrimaryStash) delete ...`), matching v9's
  description exactly. `activation-policy.ts`'s "no new trust machinery" decision (header
  comment, 2026-07-14) is respected: zero new config, zero persisted state. Fixed.
- **security "grant mechanism doesn't exist" / "ceiling philosophy unverified"**: moot —
  v8's grant is withdrawn. The second half of this finding (reviewer claimed the `tools:`
  ceiling "was not found" in code) is factually wrong — it exists at `show.ts:433-445` —
  and v9 §11 correctly flags this as the one rejected panel claim. Confirmed correct.
- **adversarial "`with:` merge/replace semantics undefined"**: §2.2 now states the rule
  explicitly — per-key shallow merge on a step→task→(command|workflow) composition chain,
  referencing step wins, `with.arguments` replaced whole. Checked against §2.3 ("no
  nesting: a task referencing a task is an error") — the chain is capped at depth 1
  exactly where the merge rule assumes it stops, no gap. Checked against §4 ("`with:` is
  not a value field... merges per-key at its target, outside the cascade") — value-field
  cascade (§4's layer list, which includes `uses: tasks/<ref>` as a layer) and `with:`
  merge are two disjoint mechanisms over two disjoint key sets; no overlap, no
  contradiction. Fixed.
- **adversarial "hashVersion 5 omits persona snapshot"**: §5.3's table now has a
  `persona snapshot hash` row (system prompt, tool policy, value fields). Matches §4.2's
  persona-snapshot shape (`{systemPrompt, toolPolicy, model, …valueFields}`) verbatim —
  same field list on both sides. Fixed, consistent.
- **adversarial "`.yml` tombstone hard-error has no remedy for read-only bundles"**: §8
  now carves out read-only/third-party bundles to a warning instead of a hard error,
  explicitly citing it as matching the existing migrator precedent. Verified against
  `scripts/akm-migrate/migrate/legacy/task-target-ref-migration.ts:246-266` —
  `planTaskTargetRefMigration` really does skip non-writable bundles and warn-and-continue
  for legacy files it can't rewrite, word-for-word the precedent v9 claims. Fixed.
> **Editor's note (archival).** The cosmetic stage-name mismatch this
> report flags in §5.6 was fixed in the same revision that followed this
> panel: v9 now says the ceiling is evaluated in the **resolve stage** for
> both surfaces. The finding is retained as the historical record of what
> the panel saw, not as an open issue.


## Majors — verified fixed unless noted

All of the following were checked and are substantively addressed with no new
contradiction: architecture's five majors (task-path staging named in §5.1 as
"resolve → execute"; `RunnerSpec`-vs-`UnitDispatchRequest` split pushed to the sink
per §5.1; `ShellUnitExecutor` explicitly extracted from the task runner's hardened path,
not rebuilt; monotemporal composition rule pins config-snapshot timing for `uses:
tasks/<ref>`; persona resolver extraction named and costed in §9); adversarial's
`extra_params` deep-merge preservation (§4 merge-classes, matches `freeze.ts:211-216`
`mergedLlmOverrides`/`deepMergeConfig` exactly), shell `timeoutMs` slot (§5.2), shell
crash/lease semantics (§5.2), persona-toolPolicy-vs-engine-capability reconciliation
(§4.2's "unconsumed-field notice" line folds it into §4 item 4's capability-notice
mechanism); security's composition-chain bypass (§5.6 bullet 3, "inherit from the
defining asset's own source"), grant-granularity/bundle-update bypass (moot — grant
removed), sync-vs-fire-time gap (§5.6 bullet 2, evaluated at resolution not at
sync/enable time), `env:` literal-secret-heuristic reuse (§5.5, points at
`param-secrets.ts`'s `detectSecretShapedParams` directly), `AKM_ITEM` shell-injection
story (§5.5 pins it to the `exec-utils` env-object pattern, never shell-text splice),
and the two-file migration atomicity gap (§8 states journal-then-verify-then-delete
ordering explicitly as new work, costed in §9, rather than claiming the existing
4-artifact `migration-backup.ts` model already covers it — checked, that model really
is scoped to `config.json`/`state.db`/`workflow.db`/`index.db` only, so v9's honesty
about this being an extension is accurate, not a claim contradicted by code).

- **coverage M13 (improve-exclusion mechanism)**: §3 now removes the `type:"task"`
  pure-YAML special-case (markdown base checks fire) and separately declares tasks
  improve-ineligible via a per-type adapter capability. The capability-declaration
  *pattern* genuinely exists today (`bundle-adapter.ts:9`, "one interface, optional
  capability methods"), so naming that seam is not fabricated — but the concrete
  eligibility check in `src/commands/improve/eligibility.ts` is currently a hardcoded
  `indexed.entry.type === "..."` string comparison, not adapter-capability-driven; v9
  doesn't say eligibility.ts itself gets refactored to consult the new capability
  rather than its own type-string list. Not a contradiction, but thinner than "names a
  mechanism" suggests — residual gap, not blocking.
- **coverage M9 / adversarial-adjacent (akm-bin shim)**: §5.7's synthesized-shim design
  (write a temp-dir `sh`/`.cmd` shim invoking the exact resolved multi-element
  invocation, PATH-prepend the shim's directory) matches `resolve-akm-bin.ts`'s actual
  return shape (`argv: string[]`, up to two elements for the npm/checkout launcher
  cases) — the shim approach correctly generalizes to the multi-element case a bare PATH
  prepend cannot. Fixed.

## Special-attention items — findings

1. **§5.6 ceiling enforceability at both resolve points**: the mechanism itself
   (primary-stash-only, checked at the point the target asset is resolved, no override)
   is sound and symmetric for workflows and tasks. However, v9 states the enforcement
   point as "freeze for workflows, dispatch for tasks" — but §5.1 (this same v9 revision)
   explicitly renames task staging to **"resolve → execute"** (no stage named "dispatch"),
   and §5.4 explicitly splits workflow freeze into **compile → resolve → freeze**, with
   asset loading (the thing the ceiling needs to inspect) happening in **resolve**, not
   in the now-narrower **freeze** ("snapshot + hash" only). So §5.6's own enforcement-point
   language doesn't line up with the stage names v9 itself just introduced elsewhere
   (§5.1, §5.4) to fix the architecture panel's "staging is unstated" finding. This is
   cosmetic (both "resolve" and "freeze"/"dispatch" as used here occur before any
   shell/agent actually spawns, so no execution-order security gap results), but it is a
   real terminology inconsistency introduced by the v9 redesign, not present as such
   before the two staging fixes existed to be inconsistent with. Not blocking; a
   copy-edit item.
2. **"scope: non-AI exec surface only" loophole for third-party `run:` tasks scheduled
   via sync review**: no loophole found. §5.6's own definition of "shell-class work"
   explicitly includes "the `run:` text of a task," so a third-party task whose target is
   `run:` is covered by the ceiling and refuses regardless of whether the operator
   reviewed and enabled it via `sync` (activation-policy rule 3 is a separate, orthogonal
   gate that only concerns *whether the task fires at all*, not *whether its shell target
   is trusted*). The "agent-dispatched third-party tasks... unchanged" carve-out only
   exempts prose/agent-dispatch tasks (which have no direct shell surface here), not
   `run:`/script tasks. No new hole.
3. **Persona-snapshot hash vs §4.2 resolver extraction**: consistent — §5.3's new row
   lists exactly the fields §4.2's snapshot shape defines (systemPrompt, toolPolicy,
   value fields), and both are attributed to the same extracted resolver.
4. **`with:` merge rule vs §4 cascade and §2.3's override bullet**: consistent — verified
   above, disjoint mechanisms, no double-counting.
5. **Tombstone carve-out + crash-window ordering vs §8's journal claims and the real
   migrator**: consistent — the read-only carve-out matches
   `task-target-ref-migration.ts`'s existing warn-and-skip behavior; the create-verify-
   delete ordering is honestly presented as new work extending (not already covered by)
   `migration-backup.ts`'s 4-artifact model, and it's costed in §9's "Named refactors" row.
6. **Shim design vs `resolve-akm-bin.ts`**: consistent — the shim generalizes correctly
   to the multi-element launcher case `resolveAkmInvocation()` can return.

## Verdict

ALL FIXES HOLD.

Residual (non-blocking) notes:
- §5.6's "freeze for workflows, dispatch for tasks" enforcement-point language uses stage
  names that don't match the stage vocabulary §5.1/§5.4 just introduced in this same
  revision ("resolve → execute" for tasks; compile→resolve→freeze for workflows, with
  asset resolution living in "resolve" not "freeze"). Suggest wording as "resolve for
  workflows, resolve for tasks" (or just "at resolve, for both") to align with §5.1/§5.4.
- §3's improve-ineligibility fix correctly names an existing capability-declaration
  *pattern* in the adapter interface, but doesn't state that
  `src/commands/improve/eligibility.ts`'s current hardcoded `entry.type === "..."` checks
  need to be rewired to consult that capability — worth a one-line addition if precision
  matters, but doesn't reopen the original finding (a mechanism is now named, whereas
  before none was).
