INPUT: ceo 2937ab4ea148f3a53969c36337bdca53476892d5f7e8d8b1556bfa8763df6845 Reviewed from the native prompt file (202 lines, 41937 bytes, read in full). Receipts below are from the live checkout at origin/main `91bbd9e` (v1.91.69.0), the plan's stated base. ## Step 0 Mode: SELECTIVE EXPANSION. Expand where the plan under-builds the contract a parent agent depends on (artifact schema, adoption measurement, a session kind that does not collide with the eval harness); hold or defer where it builds breadth no incident in the feedback paid for. ### Premise table | # | Premise (from the plan) | Receipt | Verdict | |---|---|---|---| | 1 | Capy user-scope installer `--check` is a bare `test -x` chain that prints nothing on failure | `~/.capy/drive/user-garry-tan/skills/gstack/scripts/install.sh:7-16` (`test -x ... \|\| return 1` chain), `:32-35` (`--check` calls `check_install; exit 0` with no output on the failure path) | VALID | | 2 | `bin/gstack-doctor` has one `check_*` row per component, fix lines, exits 1 on `fail` | `bin/gstack-doctor:8-12` (contract), `:441-456` (row calls and `[ "$N_FAIL" -eq 0 ]`) | VALID | | 3 | Doctor has no `--check`, `--json`, `--require` or Node row | grep of `bin/gstack-doctor` for those tokens: only an unrelated `server-node.mjs` hit at `:296` | VALID | | 4 | `gstack-session-kind` classifies `spawned \| headless \| interactive`; only `spawned` is honored as an explicit `GSTACK_SESSION_KIND` override | `bin/gstack-session-kind:33-36` (spawned override), `:47-50` (`GSTACK_HEADLESS` → headless), `:59-62` (`CI`/`GITHUB_ACTIONS` → headless) | VALID | | 5 | `headless` means BLOCK on any question; only `spawned` auto-continues | `scripts/resolvers/preamble/generate-ask-user-format.ts:15` (spawned auto-chooses), `:28` (`headless` → `BLOCKED — AskUserQuestion unavailable`) | VALID | | 6 | Upgrade/telemetry/lake/proactive prompts are suppressed for `spawned` only | `bin/gstack-skill-start:96` (`if [ "$_SESSION_KIND" != "spawned" ]` around update-check), `:394` (same guard around the emission block) | VALID | | 7 | Snapshot `init` wraps a raw plan in `## Implementation plan` | `bin/gstack-autoplan-snapshot.ts:413-417` | VALID | | 8 | Review-log `status`/`unresolved` are model-written; nothing derives them from findings | `bin/gstack-review-log:88-93` (passes the record straight to `bindReview`), `lib/review-evidence.ts:178-186` (binds commit/tree only) | VALID, with a nuance the plan omits: `reviewFreshness` already downgrades `status: clean` with `issues_found > 0` to `UNVERIFIED` at read time (`lib/review-evidence.ts:238-240`). The gap is write-time derivation, not detection. | | 9 | `gstack-version-bump write` stamps VERSION/package.json/locks with one hard-coded post-write hook | `bin/gstack-version-bump:373-402` (`regenAgentsDigest`, opt-in via `--regen-digest`, hard-coded path) | VALID | | 10 | `bin/gstack-next-version` already reads the live PR queue and sibling worktrees | `bin/gstack-next-version:78-106` (`claimed`, `siblings`, `active_siblings`, `pickNextSlot`) | VALID | | 11 | `gstack-evidence` records tree fingerprints | `bin/gstack-evidence:10-13`, `:388-396` (`tree`, `dirty`, wtree TOCTOU guard) | VALID | | 12 | `ship/sections/measure.md.tmpl:3-16` holds a never-loosen rerun discipline | `ship/sections/measure.md.tmpl:3-7` | VALID | | 13 | `codex_reviews` defaults to `enabled` | `bin/gstack-config:251` | VALID | | 14 | Paid evals (Step 6) run before Step 16's cheap generation checks | `ship/sections/tests.md.tmpl:54` (Step 6 evals), `ship/SKILL.md.tmpl:371-389` (Step 16 stage 1 runs declared generation/build commands) | VALID | | 15 | `/investigate` has no flake, polluter, race or backlog content | grep of `investigate/SKILL.md.tmpl`: one table row `Race condition` at `:165`, no recipe; no flake/polluter/backlog hits | VALID (one-line mention of race, no recipe) | | 16 | Preregistration/panels/budgets are gstack-internal | `scripts/ship-measure.ts:22-28` (admission budget), `scripts/judge-calibration.ts:42` (`split: 'dev' \| 'heldout'`), `test/helpers/periodic-exclude-data.ts:79-92` (`EVAL_POLICY`) | VALID | | 17 | Doctor's codex fix line does not name the `OPENAI_API_KEY` login path | `bin/gstack-doctor:186` (`codex login, or export CODEX_API_KEY`), `TODOS.md:1639-1641` (CI-only use of `codex login --with-api-key`) | VALID | | 18 | `./setup --status` always exits 0 | `setup:146` (`exit 0` unconditionally after status lines) | VALID | | 19 | `--no-browser` is undocumented; only `GSTACK_SKIP_PLAYWRIGHT=1` exists | grep for `--no-browser` in `setup`: none; `setup:2071-2072` (`GSTACK_SKIP_PLAYWRIGHT`), `setup:1505-1512` (`GSTACK_SKIP_FONTS`) | VALID | | 20 | `GSTACK_CODEX_MODEL` is honored by `select-model` | `bin/gstack-codex-probe:143-147`, `:456`, `:497` | VALID | | 21 | No resolver reads `capabilities.questions` (basis for "no capy host") | only `scripts/host-config.ts:178` validates the value; no reader under `scripts/resolvers/` | VALID | | 22 | Module-size ratchet is 800 lines / 150 per function; `gstack-next-version` 822, snapshot 865, `setup` 4662 must not grow | `test/module-size-ratchet.test.ts:2`; `wc -l`: 822 / 865 / 4662 | VALID | | 23 | `nativeDispatchPrompt` already exists in `snapshot.json` | `bin/gstack-autoplan-snapshot.ts:661-669` | VALID | | 24 | Running Bun 1.3.14 vs repo requirement 1.4.2 | `bun --version` → 1.3.14; `package.json:80-81` (`engines.bun: ">=1.4.2"`), `.github/workflows/arm-setup-smoke.yml:33` | VALID (note: `engines` is a range `>=`, not a pin) | | 25 | "13 of 27 threads ran no gstack workflow beyond the installer" and the causal reading that tooling gaps (not low perceived value) explain it | No artifact in the repo or the prompt file; the plan offers no per-thread reason | UNVERIFIED (the load-bearing premise of the wave) | | 26 | Effort: A 1.5 d, B 1.5 d, C 1 d, D 1.5 d CC+gstack | No basis given; PR B alone names 5 new binaries, 4 lib modules, 11 pre-gate checks each with a fixture | UNVERIFIED (see Section 3) | | 27 | `bin/gstack-hermetic-run` can be "reused" by the `hermetic` check | no such file in `bin/`; `buildHermeticEnv()` exists at `test/helpers/hermetic-env.ts` | FALSE as worded (the bin is new; the helper is reusable) | ### What already exists (relevant to scope) | Capability | Where | Plan's use | |---|---|---| | Readiness rows with fix lines and exit 1 on fail | `bin/gstack-doctor:441-456` | A1 adds a mode, not a tool. Correct. | | Session kind classification and preamble branching | `bin/gstack-session-kind`, `generate-ask-user-format.ts:15-28` | A3 reuses; see Section 6 for the collision. | | Raw plan wrapping | `bin/gstack-autoplan-snapshot.ts:413-417` | A4 documents it. Correct. | | Native dispatch prompt in snapshot | `bin/gstack-autoplan-snapshot.ts:661` | A6 exposes it. Correct. | | Queue-aware next version | `bin/gstack-next-version:78-106` | B2 `--next` wraps it. Correct. | | Tree/wtree fingerprints | `bin/gstack-evidence:388-396`, `gstack-wtree` | B3 composes them. Correct. | | Read-time inconsistency guard on review rows | `lib/review-evidence.ts:238-240` | A7 should cite it and add only the write-time derivation. | | Opt-in code execution posture for repo-declared regen | `bin/gstack-version-bump:373-385` | B4/B8 should inherit it; they currently do not (Section 6). | | Admission budget, calibration splits, EVAL_POLICY | `scripts/ship-measure.ts:22-28`, `scripts/judge-calibration.ts:42`, `periodic-exclude-data.ts:79-92` | D1 generalizes all three at once. | | Hermetic env builder | `test/helpers/hermetic-env.ts` | B8 `hermetic` check; the bin wrapper is new. | ### Dream state A parent agent on any machine runs one install line, greps one `gstack: ok` line, then runs `/autoplan` or `/ship` unattended and receives versioned, schema-checked JSONL it can act on without reading prose, while the owner receives a one-page numbered gate list. The plan's PR A reaches most of that for autoplan. PR B reaches it for ship if the receipt and restamp land together. PRs C and D are breadth that the dream state does not need in this wave. ### Alternatives considered against the plan 1. **Ship PR A alone as the wave, then B trimmed, then measure adoption before C/D.** Rejected by the plan implicitly (four stacked PRs, D1). This review recommends it (Section 1, 3). 2. **A fourth session kind (`unattended`) instead of redefining `headless`.** Not considered by the plan; required (Section 6). 3. **One artifact-schema module with a version field instead of six independently described files.** Not considered; required (Section 2). 4. **Chromium always lazy, dropping `--light` as a user-facing mode.** Not considered; optional simplification (Section 4). 5. **Premise table + three rows instead of 17 reality rows in plan reviews.** Not considered; recommended (Section 4). ## Sections 1-11 ### 1. Is this the right problem? Could a reframing yield 10x? **Finding 1.1 (High): the wave treats "13 of 27 threads ran nothing" as a supply failure and never measures whether PR A changes it.** Premise 25 is unverified; an equally plausible reading is that in a coordinator-driven serial queue, an agent with a working harness still prefers the repo's own tooling because the gstack workflows cost context and time they cannot see the return on. If that is the cause, PR A fixes the install lie and nobody runs autoplan anyway, and PRs B-D build on an unmeasured assumption. Fix: make adoption a release promise. A10 already writes `analytics/autoplan-timing.jsonl`; add a `session_kind` and `consumer` field there and to the ship receipt, and define P7: "of the next 10 Capy threads that install gstack, at least 6 run one headless workflow whose artifacts the parent consumed (grep/jq in the parent transcript)". Gate PR C and D on that number, not on the queue. The thesis itself (machine-readable first) is right and is the 10x lever: a parent agent that can `jq` a decision list is the product. The reframing that follows is that the artifact contract is the product, and the tools are implementations of it. The plan has it backwards: 17 new binaries, zero schema. ### 2. Are the premises stated or assumed? Which could be wrong? The repo-level premises are stated and almost all hold (table above; 23 VALID, 1 FALSE as worded, 3 UNVERIFIED). The ones that could be wrong and matter: **Finding 2.1 (High): six output files, five JSONL shapes, no schema owner, no version field.** `tasks.jsonl` is said to reuse today's per-phase schema; `decisions.jsonl` and `findings.jsonl` list fields inline; the ship receipt is a fenced block; `pregate.json` and `timing.json` are described by example. In six months a parent agent written against PR A's `findings.jsonl` breaks when PR C adds `incident` and PR D adds `contributor`. Fix: one `lib/headless-artifacts.ts` that owns every schema with `schema_version`, exports the TypeScript types, and backs a `bin/gstack-artifact validate ` that `phase-close`, `gstack-ship-receipt` and `gstack-pregate` call before writing. Align `findings.jsonl` rows with the review-log row shape so A7's derivation is one function over one type. **Finding 2.2 (Medium): A7's "becomes impossible" overstates.** `reviewFreshness` already returns UNVERIFIED for `clean` with open issues (`lib/review-evidence.ts:238-240`); the real gap is that the inconsistent row is still written and the log reader trusts the model's `unresolved` count. Fix: scope A7 to "bindReview rejects at write time when `--findings` is given; interactive rows without `--findings` are tagged `status_source: claimed`", and cite the existing read-time guard so a reviewer does not believe detection is new. **Finding 2.3 (Medium): runtime-pin semantics are underdefined for the machine the promise is made on.** `engines.bun` is `>=1.4.2`, a range (package.json:80-81); the plan's message prints `pinned 1.4.2`. More important, the Capy cloud image ships Bun 1.3.14, so on the default image `--check` can never end `gstack: ok` unless the installer upgrades Bun, and A2 does not say it does. P1 ("on a healthy machine it ends with `gstack: ok`") is then unmeetable on the primary target. Fix: A2 runs `bun upgrade --version ` (or `mise`) when the row fails and the pin is satisfiable, and A1 distinguishes `range` from `exact` pins in the message. ### 3. 6-month regret scenario **Finding 3.1 (High): the effort table is not credible and the delivery shape depends on it.** PR B is five new binaries (`restamp`, `tree-receipt`, `regen`, `ship-receipt`, `pregate`), four lib modules, a queue-replay test with three PRs, a mirror repo and a CHANGELOG re-header, plus eleven pre-gate checks each with its own fixture, in 1.5 CC-days. PR D is a new skill with thirteen sections and three lib extractions in 1.5 days. If the real multiplier is 3-4x, PRs C and D sit behind A and B for weeks, the stacked base drifts, and the plan's own queue incident (restamp after reorder) hits this wave first, before B2 exists to fix it. Fix: re-estimate per binary with a fixture count; cut PR B to B1, B2 (`--version`, `--next` only; `--after` and `mirror` in a follow-up), B3, B5 and the four pre-gate checks whose incidents the plan actually names fixtures for (`regen`, `strays`, `literals`, `lanes`+pipefail). Ship `guards`, `patches`, `integrator`, `hermetic`, `links`, `lint`, `ratchets` as a second pre-gate PR after one repo has run the first four for a week. **Finding 3.2 (Medium): the pre-gate becomes a second CI that drifts from the repo's real CI.** `lanes`, `guards`, `platform`, `integrator` re-derive what `.github/workflows/*.yml` already encode. Six months out, a repo changes its CI matrix and the pre-gate still reports `Tiers ran: unit serial` from a stale mapping. Fix: `lanes` and `platform` read the workflow files for the lane list (A1's `runtime pins` already parses them); the pre-gate never carries its own lane taxonomy. **Finding 3.3 (Medium): seventeen reality rows make plan reviews longer at the moment context budget is the binding constraint.** The plan notes every template edit must clear `test/parity-suite.test.ts` and the budget ratchets but adds 17 conditional rows plus incident notes to four templates. The regret is a plan review that spends its budget on rows whose scope detector misfires (`Transaction semantics`, `Recall`, `Units` need a scope signal that does not exist today). Fix: ship the four rows that this review itself demonstrates value for and that need no scope detection (premise table with receipts, already-done git check, surface check, binding decisions); defer the other 13 to a follow-up gated on scope-detection evidence from `detectDxScope`. ### 4. Alternatives dismissed without sufficient analysis **Finding 4.1 (Medium): D1 (four stacked PRs) is argued on reviewability, not on the queue cost the plan itself calls an incident.** Stacked PRs in a repo whose `/ship` cannot yet gate ahead (B2 `--after` is in PR B) means PR B restamps by hand after A merges, PR C after B, PR D after C: exactly the "manual stamp edits" P3 promises to eliminate. Fix: land A; land a minimal B (B1+B2 `--next`+B3+B5) next; dogfood on C and D so the queue tool is proven by the wave that ships it. **Finding 4.2 (Low): `--light` as a user mode versus Chromium always lazy.** D9 picks flag plus lazy install. If `gstack-browser-ensure` exists, the flag is redundant: default installs skip Chromium and the first browser skill installs it. One less mode in the installer, one less `SKIP browser (light mode)` state, and A2 shrinks. Fix: make lazy the default; keep `--with-browser` for machines that want the 86 s up front. **Finding 4.3 (Low): A9's free-text owner reply grammar (`all except 3=b 7=no`, `d10 yes`, `1a 2a`).** The plan correctly refuses to guess, but five accepted dialects is a parser that grows with every owner. Fix: one grammar (`