Commit Graph
4 Commits
Author SHA1 Message Date
Garry Tan 55f8151fbe v1.91.30.0 fix: honest eval failure reports, Bun floor with safe auto-update, make-pdf and /review on Codex (#3033)
* docs: approved reliability follow-ups plan (Oct 2026)

* D1: score overlay wrong answers as comparison results (contract v4)

A completed answer that fails the fixture's output check is now a valid
measurement with taskCorrect false and answerError set, in either arm.
Only execution, scope and metric failures invalidate a trial. ON
correctness still gates the case, so an OFF wrong answer stays in the
comparison. OVERLAY_CONTRACT moves to v4; v3 verdicts are not
reinterpreted. Replays the 37198445662 sonnet trials (OFF-0 wrong).

* C4: score auq-matrix substance with a 3-sample judge panel

Each skill keeps one native capture in the same execution; the
recommendation-substance grader now runs as a JUDGE_PANEL_SAMPLES panel on
that capture and gates on the mean against the unchanged minimum of 4. A
failed sample fails the panel without resampling. Approved at the gate
2026-10-04 for censuses after this change.

* E1: one Bun version source; setup refuses below the 1.3.3 floor, updater checks before advancing

bin/gstack-bun-version.sh holds the security floor (1.3.3) and the tested
version (1.4.0, the CI pin and engines.bun). setup refuses Bun below the
floor before writing anything, warns between floor and tested, warns and
continues on an unparseable version, and prints a 1.4.0 install hint.
Prereleases sort below their release (semver).

gstack-session-update now fetches, reads the incoming release's floor and
checks the bun setup will run before fast-forwarding to that exact
revision; below it the update is held with reason bun-too-old and a
resume command, leaving the revision and installs untouched.

Fixture copies of setup (team-mode, claude-code migration) now include the
sourced file; the slow-git lock test sleeps on fetch, the updater's
network step.

* E3: record the owned Chromium's PID over CDP so the #2709 reap runs on Playwright 1.62

Playwright 1.62's Browser has no process(), so chromiumProcInfo was always
null and browse stop never reaped a surviving headless Chromium. The owned
headless launch now reads the browser PID from CDP SystemInfo.getProcessInfo
(bounded at 2s; a hung or failed call logs once and records nothing). The
reaper's start-time and cmdline identity checks are unchanged, so a recycled
PID or an externally owned browser is never signalled.

* A1: ship docs gate records post-child hashes with gstack-docs-candidate, saves each record once

Stored transcripts (37198445662 gate-census-2) show the parent's reads of
release files take ~1 s; the parent's own model time dominates (completion
268 s of 392 s, store ~270 s of 387 s), and 45-78 s of it is retyping hash
maps, child output and records into several artifacts after the child
returns. The child contract is unchanged.

* A2: /plan-ceo-review sends the mode handoff line before any other tool call

plan-ceo-mode-routing's HOLD SCOPE session spends its 240 s post-selection
window on model work: 37176837432 skipped the handoff helper and paraphrased
the mode, 37198445662 ran it, then wrote the plan, loaded sections and probed
Codex for 114 s before the posture chat. The handoff line is the posture.

* B3: accept wrapped unchanged rows in the cropped Edit preview

PR run 37176835584 timed out with the floor's owned Edit menu on screen:
unchanged diff rows soft-wrap under their gutter with a blank marker
column, and a trimmed empty unchanged row keeps only its number. The
parser accepted wrapped +/- rows only, so it never verified the owned
edit. Both forms are now parsed and still compared with the exact source
lines; the captured viewport is replayed with negative controls.

* A3: record per-phase headroom diagnosis for docsync, plan-mode-no-op, mode-routing and gate slice 11

* E4: /review Step 1 keeps going when the base fetch fails and reports stale base coverage

Under Codex's read-only .git, 'git fetch && merge-base && diff --stat'
stopped at the fetch, so the empty output read as 'Nothing to review'.
The fetch is now separate, prints BASE_REFRESH fresh or stale with the
local base revision, and the review states stale coverage.

* D2: reword the format-approach question prompt

Both plan-ceo-review-format-approach refusals in census 37195203538
(Fable 5.1 model_refusal_no_fallback, category reasoning_extraction:
"duplicating model outputs") were anchored on the session prompt, whose
capture instruction asked for the "verbatim" question and "the exact
prose you would have shown" in a "format-capture test". The approach
case now asks for the same question in the same file as the step's
output, without that wording. The other three plan-format cases keep
their unchanged prompt (no refusals in 72 trials).

* C2: /qa defines its outcome filename fields; QA report templates name the measured timing fields

Low judge samples in failing panels named both: qa workflow (37186854666)
'an undefined {user} in the outcome filename', and qa-only workflow
(37198445662) 'template asks for Duration / durationMs totals while
reporting.md mandates Probe budget and Guarded command time'. The qa
union stays under its 1.11 size ratio (93292 of 93294 bytes).

* 0.1: session ledger written by the claude -p, Agent SDK, PTY and Codex runners

Each armed model session appends one best-effort line to
$GSTACK_EVAL_DIR/session-ledger.jsonl: a stable session key, the timeout it
armed, monotonic elapsed time, its end reason (completed, session_timeout,
observer_timeout, api_error, refusal, aborted, error), one sanitized evidence
line and, for stream-JSON runners, a compact liveness summary (longest
in-request silence with nothing outstanding, last event kind, tool open at
end). Partial messages now stream for every claude -p session and for SDK
sessions without a custom query provider (runSharedInteractive opts in); their
rows feed only the summary, so transcripts keep their size unless
publicStreamDiagnostics is set. Structured refusal and API-error signals win
over phrases, and tool results are never read for them.

* 0.2: failure_cause beside failure_class, from runner facts and the session ledger

One pure failureCauseOf() beside failureClassOf() sets failure_cause
(contract > pre_turn_infra > api_error > refusal > provider_stall >
session_timeout > observer_timeout > assertion > unknown; no machine-set
'detector') with one bounded evidence line, and failureDetailOf() keeps a
Bun matcher's Expected/Received or a judge's failing dimensions in
failure_detail. Both record builders (classifyTrialShard, junitCensus) call
them and attach the trial's ledger sessions. failure_class, error and
TRIAL_ERROR_MAX are computed exactly as before; the new fields are optional,
bounded and validated only when present, and a frozen copy of the v1 reader
accepts every new record. A provider stall needs partial messages and
STALL_WINDOW_MS (120 s, eval-budgets.ts beside HEADROOM_WARN/FAIL) of
in-request silence with nothing outstanding; it stays a failure under
EVAL_POLICY v1.

* E4: fingerprint under a read-only .git via a private object dir owned by review-log

Codex's sandbox mounts .git read-only, so gstack-wtree's git add -A could not
write blobs and /review lost its start capture. gstack-review-log now creates
a private 0700 object directory under TMPDIR, passes it to gstack-wtree (which
writes new objects there with the common-dir object store, resolved before
exporting, as an alternate, so linked worktrees work), exposes it to the
bindReview/checkSharedLibsReuse consumers that read the tree and blobs, and
removes it on EXIT/INT/TERM after they finish. gstack-wtree prints one stderr
line and exits 1 on a failed write or unwritable TMPDIR instead of printing a
partial hash; review-log no longer swallows that line. Standalone gstack-wtree
keeps writing to the repository store so git diff between saved snapshots
(/ship) still works.

* 0.3: red lines name their values, evidence and an after-a-repair command; one published-text sanitizer

Each red line in the census report keeps its stored error and adds the
machine cause with its evidence, the failure_detail values (Expected/Received,
or each failing judge dimension with its mean, sample count and the sample
sentence naming it), the slice artifact and shard directory that hold the
transcript, a fetch command (eval:pass-rates --run <id> --case <id>), and
'after a repair:' with a command that selects only that case (E2E ids via
--case, judges via their selection and an exact test-name filter). A
session that completed and failed a check says so instead of 'assertion
(success)'. Report text that reaches a PR comment, issue or committed file
goes through scripts/lib/published-text.ts: control and bidi characters
stripped, credential-scan patterns redacted, mentions neutralized, HTML and
link brackets escaped inline, blocks in a fence longer than any backtick run,
length capped. Verdicts and collector verdict objects are unchanged.

* E2: one make-pdf resolver for readiness and every $P block on env-var hosts

make-pdf exported $P from its readiness block, which Codex and the other
env-var hosts lose between blocks. binaryAssignment gains 'make-pdf': the
MAKE-PDF SETUP readiness check and the runtime prelude both use it, so every
block that runs $P derives the same make-pdf/dist/pdf binary, with
MAKE_PDF_BIN (dev builds) winning when it is executable. Claude output keeps
its repo-local-first probe; only the false 'subsequent blocks' comment
changed. Root plus P=... fits the 400-byte prelude budget; the fixed
MAKE_PDF_OVERRIDE segment is the one exemption, named in runtime-root.ts and
the conformance test.

* 0.1: eval:pass-rates --headroom, --reds and --run report views; 85% headroom alarm in --gate

A new pure module, scripts/lib/eval-history.ts, reports per case the slowest
armed session against the timeout it armed (censored when it timed out,
insufficient below 3 samples, unknown without a session ledger, with the
case wall shown separately as an upper bound), the census critical path from
the slice jobs' timings, the verdict red ledger per census by failure class
and machine cause with shrunk per-case rates, and the all-green probability
(an approximation: the product of 1 - p_i, with an interval). --run <id>
lists one census's reds with their values and history and downloads only the
slice artifacts those reds name, reporting any over 64 MB instead of skipping
them. eval-flake-rank.ts only routes flags: --help works offline, an unknown
flag or case id exits 2 before any fetch, --case narrows the JSON and the
alarms, every view prints its run/branch scope, and --gate also alarms on a
session above HEADROOM_FAIL (85%) of its budget.

* E5: GSTACK_DESIGN_IMAGE_MODEL override; the live model check always tests the defaults

The image_generation tool model gains an env override validated against a
conservative gpt-image-<version> pattern; a bad value fails before any
request and the error names the variable. Pairing and rejection hints name
the tool model actually requested. design/scripts/live-model-check.ts now
ignores GSTACK_DESIGN_MODEL and GSTACK_DESIGN_IMAGE_MODEL (and says so), so
an override cannot mask a retirement of a default, and its exit 2 (no key)
says nothing was checked.

* C3: /deslop-shared-libs names a concrete risk for each recommendation, never 'none'

Both shared-libs-opportunity-judgment reds (37193478719 t3, 37195203538 t1)
failed adoption_and_risk because the top recommendation said 'Main risk:
none found inside the repo' / 'none in behavior'. The skill asked to 'name
the main risk or uncertainty' without saying what counts.

* B4: --case selects loop-registered cases; an unknown id exits before any process

caseSelection() resolves the one paid file that registers a case and how a
trial selects it: by its literal Bun test name, by the id a registration loop
names its test at runtime (coverage audits, TPA, journeys), or by running the
whole file when it registers no other case (plan-mode-no-op, whose test names
are not the id, so the old name pattern ran nothing). A whole-file case runs
one file shard per trial and is judged by shard status, as CI judges it.
--list prints the selection. Every E2E_TIERS id now resolves except
carve-section-loading, which fifteen files register (CI runs each as its own
shard) and which still fails with the owning files named.

* 0.3: after-a-repair runs the shard file when --case cannot resolve a case

A case that several files register (carve-section-loading) cannot be selected
by --case; its red line now prints the bun test command for the shard file
that went red, so every printed command selects exactly one case.

* C1: pre-register workflow-judge control bundles for qa, qa-only, review and setup-deploy

Positive (production bundle), negative (headings only) and one targeted
execution-blocking defect per judge, one 3-sample panel each, built with the
eval's own reader, prompt builder, options and floors.

* F: cost_known: a trial whose harness captured no billing says so; totals never hide it

cost_usd stays a finite number. Trial and eval records gain an optional
cost_known boolean (absent means known, so old records still parse; the
validator accepts only a boolean). Session-ledger rows record whether the
session's terminal result carried total_cost_usd; PTY and Codex sessions
never do, and SDK captures without a terminal result do not. A trial is
cost-known only when it has eval records and every record and session
captured billing, so JUnit-only PTY cases (125 of 298 trials in run
37198445662 recorded 0) now read cost unknown. The census headline prints the
known sum plus the unknown count, never a bare total over unknown costs, and
no total when every cost is unknown; the history import keeps the flag.
PTY transcripts are not priced: test/helpers/pricing.ts estimates exclude
cache writes, so they cannot give the billed cost.

* B1: replay corpora for the five repeat-offender cases

shared-libs-plan-callers, plan-ceo-section-loading, auto-decide-preserved,
plan-design-review-plan-mode and ship-docsync-late-result each get an
inventory of every wave census in scope (all artifacts still available)
and minimal, redacted detector or actor inputs replayed through the real
detector in the free suite: census passes, every distinct census red, and
derived negative controls labelled as derived. Fixed false reds stay as
expected passes with their history; the two genuine auto-decide product
failures (37176837432, 37179171083) stay refused. A contract test bounds
each entry at 64 KB, scans it for HIGH credentials, requires a pass and a
refusal per case, and reports entries whose series identity is stale.

Building the auto-decide corpus exposed a latent native detector misread:
a bold 'Mode application and rationale.' heading was parsed as a
withdrawn Mode field (37186854666). A field status now ends at its
sentence.

* B2: read approved stale-fill decisions from more valid ledger records

The structured ledger reader is authoritative before the prose fallback,
but it missed two valid approved records in passing censuses
(37186854666: a camelCase writeProfile subject; 37195203538: a
slash-joined 'D1 / STALE-FILL' row id), which then rested on the prose
detector that caused both historical reds. Both forms are accepted; an
unresolved row, an unrelated decision, the copied fixture plan and
non-write camelCase words stay refused.

* C1: record workflow-judge control results (negatives separated; qa and review miss a removed step)

* C2: record every low workflow-judge sample in the wave censuses with its disposition

* 0.3: published lines cannot break a fixed fence

evals.yml wraps collector-outcomes failures in a fixed three-backtick fence
for the PR comment, so those lines (and eval:pass-rates output meant for the
tracking issue) go through sanitizeFixedFenceLine: cleaned like every
published line, with backticks turned into quotes. Inline published text
also neutralizes backticks.

* A1: fit the post-child record wording under ship's 1.428 parity size cap

* E4: inline the Step 1 base refresh to fit review's 1.199 parity size cap

* B2: inventory of gate and periodic phrase-only detector checks

docs/evals/detector-inventory.md lists every pass/fail decision in gate
and periodic E2E cases that rests on phrases in model free text, with
its structured source (if any), whether the contract is user-visible,
and a disposition: already structured-first, convert candidate, phrase
witness required, or no structured source. Convert candidates are
ordered by census red history.

* 0.2: failureCauseOf takes the stall window instead of importing it; the PTY ledger never throws

eval-store.ts imported STALL_WINDOW_MS from eval-budgets.ts, which free tests
replace with mock.module stubs (review-finalization-budget, office-hours,
qa-fix-loop, qa-only), so loading eval-store failed there. failureCauseOf is
now dependency-free: the record builders pass STALL_WINDOW_MS. A PTY session
whose handle cannot show its text (test doubles) records no panel instead of
throwing from runPtySession's cleanup. The 37186854666 replay also runs
through classifyTrialShard.

* A2/auto-decide: the CEO handoff chat repeats the helper's printed line verbatim

Claude Code 2.1.284 collapses the helper's Bash output ('Ran 1 shell
command'), so the 'Auto-decided review mode → …' line reaches the user only
through chat. In lane D's auto-decide-preserved corpus every passing capture's
chat starts with that line, and the reds paraphrased it ('HOLD SCOPE was
auto-selected…', 'Mode decision done…', "I'm defaulting to HOLD SCOPE…").
The template now says verbatim and why.

* C2: record the judge panels rerun on the final ship and review wording

* integrate: touchfiles and module-size ratchet entries for the wave's new modules

GLOBAL_TOUCHFILES gains session-ledger.ts, published-text.ts and
auq-substance-panel.ts; bin/gstack-bun-version.sh joins every entry that
lists setup or the updater; auq-matrix stays a rule case with its C4
evidence beside E2E_KINDS; eval-history, published-text and session-ledger
are registered new modules.

* E1: BROWSE SETUP install hint pins the tested Bun (1.4.0)

* E2: quote "$P" in make-pdf commands so install paths with spaces work

* E1: /gstack-upgrade checks the incoming Bun floor before pulling

gstack_bun_incoming_hold (bin/gstack-bun-version.sh) is now the one
pre-advance check: the auto-updater calls it before its fast-forward and
/gstack-upgrade's git path calls it after fetching. Below the incoming
release's floor the upgrade stops with BUN_TOO_OLD and the checkout,
VERSION and installs stay untouched. Vendored installs were already safe:
setup refuses before writing and the swap restores the previous install.

* 0.3: only main posts or closes tracking issues; reports carry alarms, red ledger, headroom and all-green

A branch-dispatched periodic or marathon run writes its report to the step
summary and a report artifact; the upsert and close steps run only on
refs/heads/main. The periodic body now keeps every pass-rate alarm line (the
old grep kept only the header), adds the red ledger and session headroom read
with an explicit --branch, the all-green estimate and the triage guide link,
and routes report text through scripts/lib/published-text.ts. The marathon
lane gains the matching close-on-green step.

Migrated: evals-workflow-wiring pinned report-summary.md in the upsert step;
the body is now written by 'Write the census report'.

* C3: prosons neutral-posture detector ignores a negated "taste call"

Both plan-review-prosons-neutral-neg reds (37179171083 t3, 37193478719 t3)
recommended A and closed with "a coverage call, not a taste call"; the
old /taste call/i matched the negation. The detector moves to a helper so
the two census captures replay free as negatives, with positive controls.

* B2: credit the CEO mode handoff only when the chat shows its line

Claude Code 2.1.284 collapses the gstack-ceo-mode-handoff Bash result, so
the printed AUTO_DECIDE line is user-visible only when a later chat message
of the session begins with it. The native detector now requires that
witness; the helper's tool result locates it but no longer replaces it, and
a generic mode statement cannot stand in once a handoff ran. Census
37182865432 is relabelled a genuine miss (expected: refused): the chat said
"I'm defaulting to HOLD SCOPE…" and "Mode decided: HOLD SCOPE". Corpus
replay: 5 credited, 3 refused. ceo-mode-handoff tests migrated to the
witness rule (deliberate behavior change).

* test: baseline the wave's approved detector and harness replay tests

B1 corpora, B3, C3, C4 and D2 replay captures through paid-case detectors,
actors or fixtures (test code by design); each entry carries its reason.

* E6: live Codex multi-block periodic case in the host-run Codex job

test/codex-e2e-multiblock-live.test.ts runs ./setup --host codex once from the
job's checkout into a fresh HOME and CODEX_HOME (auth.json copied from the CI
login home), asserts codex debug prompt-input lists the gstack router as a
real file, seeds one learning, and runs /learn's Show recent block through
codex exec: that later block must root itself through its prelude, run the
installed gstack-learnings-search and print the seeded learning; no block may
report a missing install or an unresolved gstack helper path.

The file joins CODEX_CI_FILES so the planner gives it to the host-run Codex
job. paid-test-durations.json carries a 180 s packing estimate (refreshed by
--write-durations after the first census) so the plan keeps every slice
within max-parallel. Oracles live in test/helpers/codex-multiblock.ts with
free replays in test/codex-multiblock.test.ts. Registration (E2E_TOUCHFILES,
E2E_TIERS periodic, E2E_KINDS rule) is the integrator's.

* E5: design live-model check as a periodic case

test/skill-e2e-design-model-smoke.test.ts runs design/scripts/live-model-check.ts
(default models only) under a temp HOME. Without OPENAI_API_KEY the case is a
Bun skip that the census lists as SKIPPED with no coverage credit; with a key,
exit 0 passes and any other exit fails with the script output (exit 2 under a
present key fails as 'nothing was checked'). paid-test-durations.json carries
a 90 s packing estimate. Registration (E2E_TOUCHFILES, E2E_TIERS periodic,
E2E_KINDS rule) is the integrator's.

* A1: docsync parent points children at a saved interface file

The /ship docsync fixture saved its observation interface only in the
parent prompt and told the parent to copy it into every child prompt,
about 30-40 s of parent generation per session (lane S, 37198445662).
docsSessionOptions now writes it to <home>/fixture-interface.md (0600) and
the parent tells each child to Read that file first. Fault-actor prompts,
which prepare already writes to a file, are unchanged. Fixture-only.

* A3: a JUnit case's recorded wall is capped by its shard's wall

junitCensus summed a case's JUnit test times as duration_ms; for
plan-mode-no-op's concurrent PTY tests that is 346 s inside a 176 s shard
(the "432-613 s" history). The case wall headroom shows is now
min(sum, shard elapsed), a true upper bound. Session headroom already
used the ledger's per-session clocks.

* A3: refresh paid-test durations from census 37198445662

Recorded 2026-09-29 estimates under-packed gate slice 11 (17 files
estimated 1078 s ran 1353 s; plan-review-report 76 s -> 198 s,
plan-ceo-plan-mode 37 s -> 112 s, safety-codex-consult 83 s -> 150 s).
Refreshed both tiers with --report --write-durations from the latest
census's slice walls. Old plan re-costed with observed walls: worst slice
~677 s (slice 11); refreshed plan: every slice estimated <= 539 s.

* C2: Browser Quick gets a feasible budget; QA loop names its directory and stop path

Judge rationales on the qa-only panels (2 of the last 3) cited the 30 s
Browser Quick budget: homepage + 5 targets, each a checkpoint write and a
guarded command, left ~5 s per probe. Quick is now 180 s (method text: 3
minutes); the qa-only-no-fix paid check expects the same native deadline.
PROBE_DIR points at its source line, a stopped loop goes to the final
report steps (annotations, materialize, Markdown), and /review and /ship
say that after smoke expiry only plan checks rerun in revalidation.

* C2: name the flows judges found implicit in review resolvers

Structured outside review: MISSING COVERAGE asks no fix question and is
never reported clean (was "preserve the existing user decision flow").
/review's HIGH-impact plan gate: spawned or non-interactive runs report
REQUIREMENTS MISSING and continue, writing no TODOs. Value cards: the byte
clamp applies to card lines; JSON records you write keep full values.

* C1: a free test catches a removed workflow step, which the judges missed

C1 controls showed the qa workflow judge passing /qa without Phase 10 and
the review judge passing /review without Step 3. The new test pins every
step/phase heading of qa, qa-only, review, ship, plan-ceo-review,
plan-eng-review and setup-deploy (derived from the templates' step
headings) and names any that goes missing or out of order; new step
headings must be pinned. The judge rubric is unchanged (EVAL_POLICY).

* size: fit the wave's wording under ship, review and qa parity caps

Measured after all lane merges: ship -79, review -210, qa -68 bytes over.
Trimmed the added wording first (post-expiry rule, MISSING COVERAGE,
plan-gate default, value-card JSON, stop line) and folded /review's
redundant INFORMATIONAL sentence and findings bullet. ship 268,036 (room
8), review 130,118 (room 1). qa needed 11 more bytes: cap 1.11 -> 1.1102
with the measured 93,305 / 84,049 = 1.11013 and its reason beside it.

* docs: troubleshooting sections for the wave's new messages

Bun floor (setup, auto-update, /gstack-upgrade), /review stale base and
fingerprint temp-dir errors, the design image model override, the
unrecorded Chromium PID, and a contributor section for census report
lines (pass-rates flags, failure causes, headroom, cost unknown, overlay
v4, stale corpora, auq substance). A free test checks every
troubleshooting.md#anchor printed by setup or bin scripts exists.

* TODOS: reliability follow-ups deferrals; close the Bun floor, make-pdf $P and #2709 reap

* 0.4: 'A census went red' guide; docs for causes, session ledger, headroom and new messages

docs/evals/census-red.md walks one red line to a diagnosis: prerequisites, the
report fields, eval:pass-rates --run/--reds/--headroom with expected output,
what unknown/insufficient/unrecorded data means, free replay, and the single
'after a repair' paid run allowed by TESTING_INTERNALS. Linked from
CONTRIBUTING, TESTING_INTERNALS and both census reports.

TESTING_INTERNALS documents the failure_cause glossary (one row per
FAILURE_CAUSES value, diagnostic only under EVAL_POLICY v1), failure_detail,
sessions[], cost_known, the session ledger, the pass-rates views and the 85%
headroom alarm, main-only tracking issues, overlay contract v4, auq-matrix's
3-sample substance panel and the E5/E6 periodic cases. troubleshooting.md
gains #bun-too-old and an anchor per new user-facing message from lanes P, D
and F. README names GSTACK_DESIGN_IMAGE_MODEL. test/census-red-docs.test.ts
pins the glossary to FAILURE_CAUSES, parses every guide command and checks the
links.

* v1.91.20.0: CHANGELOG and version for the reliability follow-ups

* regen: SKILL.md and sections for all hosts, digest, context-budget fixture

bun run gen:skill-docs --host all; goldens and llms.txt re-rendered
unchanged; bun test/helpers/capture-context-budget.ts.

* integrate: register codex-multiblock-live and design-model-smoke (periodic, rule)

* 0.4: census report and eval:pass-rates views link the census-red guide

* test: cookie approval fixture reverses the Bun install-hint pin (E1)

The historical approved cookie-workflow prompt carried BUN_VERSION=1.3.10;
the regenerated install hint now pins 1.4.0, so the fixture's reversal
list gains that edit like the earlier waves' entries.

* test: release floor counts the two new periodic cases (E5, E6)

* fix: /freeze, /guard, /unfreeze and /investigate work on Codex and other env-var hosts

Templates quoted "$HOME/.claude/skills/gstack/...", which the env-var hosts'
rewrites turned into "$HOME/.agents/skills/gstack/..." on Codex (a path a
global install never has; same class on the other hosts), and setup's
runtime roots had no freeze/bin. Quoted runtime paths now use
{{RUNTIME_ROOT}}: $GSTACK_ROOT on env-var hosts (the fence gets the
runtime prelude), the unchanged $HOME path on Claude. _link_runtime_dists
links freeze/bin and the careful/bin helper it sources into every
env-var host's root. Also fixes the same guess in /benchmark-models,
/retro and /diagram. test/env-host-runtime-assets.test.ts fails on the
previous code: no fence guesses a $HOME/<dir>/skills/gstack path, every
$GSTACK_ROOT path a fence uses is in the host's runtime root, and the
installed Codex /freeze and /unfreeze fences run from a fresh shell.
Template-reading tests now read the Claude render or expect the
placeholder (deliberate change).

* CHANGELOG/TODOS: lane W's workflow, cases and guide; the env-var host freeze fix

* E6: a block that reads a SKILL.md is not a missing install

The first live codex-multiblock-live run passed its real check (the /learn
block found the install and printed the seeded learning) but the oracle
flagged a sed of the learn SKILL.md, whose prelude source quotes the
'gstack: no install found (tried $_r)' text. Only an emitted line that
starts with the message and names a real root counts now; free replay
negative added.

* test: qa-only fixture keeps its caller-set 30 s deadline

The qa-only-no-fix fixture tells the model to start the guard with 30 s
(a caller limit), so its deadline assertion's default stays 30 000 ms; the
product's Browser Quick default (180 s) does not apply to it. Reverts the
helper and its test to their base.

* C2: keep PROBE_DIR 'owned' (qa-functional-prompt pins it); qa measured 93,311

* test: paid file count and periodic floor include the two new periodic cases

* test: ship docs freshness pin checks meaning after A1's wording trim

The snapshot still hashes selected release paths (--select narrows them),
generated outputs and docs; the pin now checks that instead of the
pre-trim sentence.

* E3: reap the recorded Chromium only after the daemon has exited

With the PID now recorded (E3), browse stop reaped Chromium while the
daemon was still shutting down; the daemon read that as a crash, exited 1
and left its state file (chromium-profile-isolation's headless stop test
failed 3/3 locally, passes on base). The CLI waits up to 5 s for the daemon
to exit before reaping a survivor.

* regen: qa and qa-only exploratory sections (PROBE_DIR wording)

* B1: batching counter reads a target declared mid-line; replay corpus

GSTA-23's census 37228573062 failed plan-eng-multi-finding-batching with
reviewCount=0 after 975 s although D1-D10 were asked one per finding,
each with its saved decision-ledger record. The report wrote 'Report
destination requested by the user. Review target (fixed): `PLAN.md` ...'
and the counter read target fields only at a line start, so no brief
inherited the plan identity. A target field may now open any sentence of
its line; a mid-sentence mention or another file still gives no identity.
Floor (3), budget and kind unchanged. Corpus: 9 earlier passing censuses,
the red (now credited at D5), and a derived batching refusal; 975 s noted
in the headroom diagnosis.

* B1: shared-libs corpus labels its git path and covers the supported shape

Every census entry was recorded in CI's eval image (git 2.43), where
gstack-safe-git falls back because --no-lazy-fetch is rejected; each entry
now says so (git_path: fallback). Two synthetic supported-path entries
(HEAD and a history citation in the brief, as git >= 2.44 produces) keep
the 37193478719 pass and the 37195203538 refusal, and a test asserts both
shapes are covered and the actor reads no git-path-specific text.

* v1.91.21.0: move off v1.91.20.0 (claimed by #3031)

* test: settle nav-guard commands before asserting; make two new tests Windows-safe

navigation-guard: Bun's expect(promise).rejects slows each Playwright round-trip
to ~1s while it waits (50 page.evaluate: 43ms plain vs 46.6s inside the matcher),
so the click's 5s timeout expired before the guard saw the link-local request
(CI: 'click: Timeout 5000ms exceeded ... waiting for scheduled navigations').
Settle the command first, then assert on the refusal; a source check keeps it so.

env-host-runtime-assets: PROBE_FILES now matches either path separator.
detector-corpus ship-docsync-late-result: JSON-escape the <ROOT> substitution so a
Windows temp path's backslashes do not break JSON.parse.

* fix: CI run/job ids are not phone numbers; context-recovery fixture gets the full runtime bin

pii.phone.e164 redacted the run id in the published eval report's fetch command
(--run 37235771700), breaking the command it prints. Digit-only spans in a run/job
flag, gh run argument, actions/runs/ or /job/ URL segment, or run_id/job_id key are
now exempt; the same digits elsewhere still report.

context-recovery-artifacts: the fixture's ./bin/ lacked gstack-skill-start and
gstack-context-recovery (the preamble's runtime scripts since v1.71), so the agent
spent its 10 turns hunting for them and hit error_max_turns with no final message
(run 37235771700, 11 turns). Link the whole runtime bin; diagnostic rerun passed
in 6 turns.

* test: replay run 37237194905's late-result capture through the docs authority detector

The only failure was call 20's write to a mistyped shard root (3GanyY for 3GanyU),
which the model disclosed; the detector is correct and the A1 post-snapshot
--out under the fixture home stays permitted. Named red recorded in TODOS.

* test: keep docsync-authority in the Windows profile

The replay test's literal helper path tripped the Windows curator's shebang-spawn
pattern, dropping the whole file from the Windows profile (test-free-shards
invariant). The snapshot --out case is already covered by docsync-command-grammar,
so it is removed here, and the Linux-path replay skips on win32.

* fix: gstack-docs-candidate --help works; docs gate red lines name the denying tool failure

PR run 37239016858 ship-docsync-completion: the parent ran
'gstack-docs-candidate --help' (the helper's usage error points at --help, which
failed). That undeclared command made docsToolFailures non-empty, which denied
the atomic-replacement proof of the child's legitimate native Edit, so the red
line blamed the Edit's temp file. A replay of the capture proves the atomic
replace once --help is declared.

- the helper prints its usage for --help/-h and exits 0
- the fixture interface and command grammar admit the helper's bare --help
- the atomic-proof denial names its check and the tool failures behind it
  (deny labels renumbered to their lines)
- replay with negative controls (undeclared command, temp left behind, renamed
  elsewhere); diagnostic rerun of ship-docsync-completion passed

* test: retro-base-branch fixture uses main and a shallow report path

PR run 37241493377: the agent wrote retro-output.md one directory above the
requested <tmp>/retro-base/retro-output.md (it dropped the retro-base segment),
so the report check found nothing. The fixture also ran plain git init, which
makes master on CI's git while the prompt says the repo is on main; the agent
logged that mismatch as a learning. Init on main and use the temp dir itself as
the repo. Diagnostic rerun passed (18 turns, 203s).

* test: qa-quick sets a caller probe limit and drains past its session budget

C2 raised Browser Quick's native budget to 180 s. qa-quick is the only gate case
on the native budget, and its wall went 194 s (main periodic, pre-C2) -> 254 s and
274 s (this PR's runs) -> 300 s session timeout (run 37242691913): the agent now
probes every navigation target with a checkpoint, then needs ~80 s to report.
Like qa-only-no-fix, the eval now sets a caller probe limit (30 s), scopes the
fixture, and gives bun's outer timeout the session drain margin instead of racing
the 300 s session. The product's 180 s budget and the session budget are unchanged.
Diagnostic rerun passed in 195 s.

* review/ship: use main's post-expiry smoke sentence; v1.91.24.0

GSTA-23's measurement on the review workflow judge: main's 'Post-expiry smoke
rechecks are not-run.' passed 10/10; the C2 wording passed 6/10 and the
'..., even in 4c.' variant failed in PR run 37248650879. qa-probe-gates pins
main's sentence before step 4c.

* test: record the plan-design corpus test in the test-of-test baseline

#3031's ratchet now counts tests that slice a paid test file's source; the B1
plan-design-review-plan-mode replay corpus reads test/skill-e2e-design.test.ts
like its sibling corpora already listed.

* fix: --case no longer deadlocks importing the running CLI

runCaseDiagnosis loaded runPaidShards with a dynamic import of
scripts/test-paid-shards.ts; when that file is the entry it is still in its
top-level await, so the import never resolved and `--case` hung after its
first line (on main since #3031, found by the per-case measurement runs). The
CLI now passes its runner in; library callers keep the lazy import.

* test: name the in-flight file and the native error when bun dies before its summary (#3037)

* Bun 1.4.2 everywhere CI and setup pin the tested version

Bun 1.4.0 on Windows aborts about 3% of free-suite shards with native
bad-handle errors (main too; #3037); the same head on 1.4.2 had none in 180
shard runs. Every current 1.4.0 pin moves together, as bun-version-drift
requires: setup-bun in every workflow (CSO orchestration included), the eval
image (sha256 from bun-v1.4.2's SHASUMS256.txt, re-hashed locally), GitLab,
the Ubicloud free-suite setup, gstack-bun-version.sh's tested version,
engines.bun and @types/bun, the install hint in generated skills, the Dia and
cookie native-qualification pins, and docs and tests that state the current
pin. Recorded 1.4.0 observations, fixtures, CHANGELOG history and the CSO
images' oven/bun:1.3.10 base stay.

* fix: --case runs a single-case file whole

A session option naming the case (testName: 'office-hours-section-loading')
made caseSelection pick test-name mode, whose filter matched no Bun test, so
every trial would run hollow. A file that registers only this case now runs
whole before any name match is tried.

* fix(office-hours): reviewer returns a hash-bound receipt instead of echoing its verdict

The spec reviewer now Writes its verdict once, seals it with
gstack-office-hours-review seal (validates the saved JSON and prints
OFFICE_HOURS_VERDICT round=N sha256=<hash> path=<verdict>), and returns
only that line. check --receipt recomputes the hash and fails closed on a
missing, malformed, stale-round, wrong-path or mismatched receipt. The
saved file stays the sole findings inventory; validators bind the receipt
to the saved bytes and the judge reads those bytes.

* fix(office-hours): only blocking findings send a design back for another review round

Review findings carry severity blocking|minor (verdict schema v2). PASS when
no blocking findings remain; minor findings are recorded in Reviewer
Concerns and the Spec Review table, never a reason for another round.
CONVERGENCE needs a persisting blocking prior. A persisting or unverified
blocking prior cannot be relabeled minor. The 3-round cap is unchanged.

* fix(office-hours): rounds 2 and 3 are delta re-reviews of the captured design diff

prepare saves each reviewed design as round-N.design.md and gives later
reviewers the exact line diff since the previous round. A new later-round
blocking finding must cite (changed_text) an excerpt of a changed line;
seal, check and the validators verify it against the snapshots and fail
closed when a citation or snapshot is missing. Other new observations are
minor. Severity, anti-downgrade and CONVERGENCE rules are unchanged.

* test(office-hours): preservation judge accepts COMPLETED with recorded minor findings

* fix(office-hours): parent fixes only blocking findings; callers may set --max-rounds

Between rounds the parent edits for blocking findings only; minor findings
stay recorded. gstack-office-hours-review takes --max-rounds 1|2|3 (default
3) on every command; reaching it stops at MAX_ITERATIONS. The marathon
fixture sets 2 rounds so round 1 (full) and round 2 (delta) run live.

* docs(changelog): office-hours review loop changes in v1.91.28.0

* fix(cso): helper JSON keeps run URLs only in the validated workflow slot

The shared redactor now treats GitHub Actions run ids as CI metadata
(c245d1bc2), so main's #3041 invariant that the same run digits stay
redacted outside qualification.workflow held only through the phone
false positive. Make it explicit in the CSO sanitizer.

* test(plan-ceo): split-overflow progress detector accepts the skill's candidate wording

Collection never ended when the model wrote 'E1 Slack:' / 'E1-SLACK:' or
labels like 'Include in this quarter' / 'Defer with flip trigger', so the
session ran the whole review (930-1464 s) and failed on its extra findings
or the case deadline (6 of 21 runs). The candidate check now accepts a
platform-bound E-id and the action is the bucket's leading verb, as the
skill names them (Include/Defer/Cut/Hold). The semantic judge, call floor
and include/defer/cut validation are unchanged. Replays the captured CI
37374526437, t2, t9 and t15 menus with negative controls.

* test(plan-ceo): split-overflow candidate identity is the one E1-E5 token

The skill fixes no header or question wording, and shape-matching kept
missing new forms (header 'D1.1 Slack' with 'SCOPE-E1:', 'D1.1 E1 Slack',
'E1 Slack DM bot ...:', a misspelled 'Mattermst'). Identity is now exactly
one E1-E5 token across the header and the question's first line, with no
other candidate's platform named. Options rules, judge, call floor and
include/defer/cut validation are unchanged. Replays all 31 measured runs;
the quoted-row controls now quote a second ledger id.

* v1.91.30.0: move past #3044's claimed 1.91.29.0

* test: register the split-overflow wording replay as a free fixture

* fix(skills): resolve judge-cited ambiguities in /qa and /plan-eng-review

- tasks JSONL keeps the raw branch as GIT_BRANCH instead of overwriting
  gstack-slug's sanitized BRANCH used for artifact names
- the Codex outside-voice block runs for ready or unverified, matching
  its routing rule
- plan-eng startup names the preamble's own setup prompts; the
  cross-project question waits for Step 0
- /qa 8c: a fix that applies but leaves the finding reproducing gets one
  revised fix, else it is reverted; browser verification names its before
  screenshot; the exploratory loop drops its duplicate 3-step summary

* fix(plan-eng): keep the startup steps in their pinned order

* fix(plan-eng): explicit spawned sessions follow the spawned rule at the scope gate; one announcement rule

A missing tool still sends the prose menu whatever the session type, but a
session the caller or host explicitly marks spawned selects the menu's
Recommendation without prose or BLOCKED. The pre-load announcement
sentence now states Step 0's single check.

* eval policy v3: judge panels gate on the per-dimension median of 3 samples

A judge dimension now passes when at least 2 of its 3 samples meet the
unchanged threshold (judgePanelMedian); any other sample count or a
non-numeric sample fails closed. Thresholds, sample count, judge model and
prompts are unchanged; panel logs show every sample and the mean, and name
the median as the gate. Applies to the skill-llm-eval panels, the
workflow-judge cache, the auq-matrix substance panel and the calibration
replicas. EVAL_POLICY 2 -> 3 and HARNESS_VERSION 1 -> 2 (verdicts change),
so every case starts a new pass-rate series. Replays the captured panels
from jobs 112032744416 and 112049856586 as replayed evidence.
2026-10-06 18:07:50 +00:00
Garry TanandOpenAI Codex 636175d349 v1.87.6.0 fix: make checks reliable and everyday validation faster (#2898)
* fix: acknowledge seeded plans before invoking review skills

* fix: distinguish current plan input from conversation history

* fix: keep hermetic plan reviews on manual permissions

* fix: distinguish tool discovery from file permission ownership

* fix: preserve initial plan mode in observation tests

* fix: wait for scope decisions before writing review findings

* fix: carry autoplan decisions consistently into review artifacts

* test: retain native failure context in periodic assertions

* fix: advance active file permissions before queued questions

* fix: finish red-team attempts before retry and cleanup

* fix: finalize plan format captures and judges before retry

* fix: cancel setup-gbrain SDK attempts before fixture cleanup

* test: select periodic consumers of the bounded attempt helper

* fix native Bash permission cards and queued questions

* fix: preserve independent decisions and review scope

Keep CEO approach, engineering scope and outside-review choices from approving independent remedies together. Carry declared contracts through DX polish and resolve new gaps before editing the plan. Regenerate every host and retain existing stop boundaries.

Validation: 654 focused tests passed across nine files; all-host generation passed. Full free and periodic validation pending.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* fix: require approval before design plan amendments

Align the Design review philosophy and rating recipe with its section protocol: resolve one proposed fix, then apply only that approved decision and retain honest scores for declined fixes.

Validation: 469 focused tests passed across four files; all-host generation passed.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* fix: observe native question completion before transcript persistence

Match owned completion hooks to submitted choices, reject conflicting or late answers, and retain bounded failure evidence.

* test: recognize review posture in acknowledged native questions

Require the selected mode acknowledgement, a completed follow-up question, and its current decoded display while preserving existing posture assertions.

* fix: preserve settled CEO choices and isolate pending remedies

Resolve established approach gates with cited authority and keep independent fixes out of unrelated option commitments and plan amendments.

* fix: carry approved DX choices through later review steps

Choose documentation approaches within the accepted scope and map resolved confusion points without reopening them through a bulk menu.

* test: handle native settings-file edit prompts

Keep one-time owned-file approvals and retain the actual sampled Autoplan permission frame with its matching barrier state.

* test: accept standard CEO reply directives with tuning footers

Recognize the exact trailing preference footer and letter-list directive while preserving current-display and exact acknowledgement checks.

* test: scope split reviewers to their generated plan artifacts

* test: observe native Bash permissions and invocation results

* test: handle owned Bash prompts during mode preference checks

* test: preserve synchronous subprocess rejection in Codex fixture

* Fix periodic review handoff navigation

Recognize review-first and explicit manual-next-step labels while preserving exact action families, manual preference, and ambiguous-menu rejection.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Bind pending file permissions to distinct current targets

Allow one captured file request to own the complete current dialog while unrelated file work is pending. Preserve same-path ambiguity, exact input ownership, and one-time grant checks.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Make paired CEO verification choices genuinely unresolved

Start the positive control with proposed manual checks so its unchanged oracle measures two new coverage decisions. Preserve runtime contracts, targets, count bounds, and all assertions.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Keep CEO review options and verification within approved scope

Audit every offered option for independent add-ons and keep new verification depth pending until accepted. Preserve already requested coverage and trace plan changes to the actual decision.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Assemble DX review artifacts before appending the final report

Keep early DX evidence above decisions, update artifact sections in place, and append the report using the actual current file suffix. Re-read after deleting an existing report before choosing the append anchor.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Keep outside plan reviews exclusive and invocation-owned

Follow one preflight-selected backend, terminate failed Codex work before fallback, and allocate extra prompt/output files uniquely. Consume only the current invocation’s completed output.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Select periodic completion evaluations for report writer changes

Register the shared review resolver for eight missing consumers and regress selection for all nine completion cases without changing their IDs or tiers.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Keep permission ambiguity fixtures on the same normalized target

Use distinct raw spellings of one target in the four negative fixtures so they exercise the normalized duplicate-owner guard after exact current-file disambiguation. Preserve the existing exception, no-input, diagnostic and cleanup assertions.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Clarify preserved contracts in engineering review fixture

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Recognize the offered DX follow-up handoff

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Check independent commitments before presenting review options

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Keep Codex review output and status in one shell invocation

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Distinguish seeded plans from reports written by a test attempt

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Recover clipped Autoplan file approvals with bounded viewport resizing

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Recover clipped Bash approvals before binding the complete command

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Isolate setup message tests from the shared checkout

Run the real installer in a temporary payload with private config, require successful completion, and guard source and binary contents and mtimes.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Fix periodic native permission and report completion handling

Match the pinned CLI's soft wraps and clipped headings without granting from incomplete frames. Retire completed file requests, retain mode annotations, and ask section captures for a short final acknowledgement after their full report is saved.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Preserve review approvals and validate DX comparison artifacts

Keep independent remedies and approved amendments explicit. Give the synthetic DX review its existing documentation and validate peer comparison as required analysis alongside four native decisions. Add positive and negative semantic calibrations while preserving review counts, model budgets and prompt size limits.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Make the five-finding CEO fixture's application boundary explicit

Materialize the request adapter and service composition used by the synthetic payment application. Explicitly declare the revised unregistered-event and mail-telemetry assumptions while preserving uncaught handler errors, the original invoice path and all five unresolved findings.

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Keep CEO state-path checks scoped to directory preparation

Co-authored-by: OpenAI Codex <noreply@openai.com>

* Use checked ports and bounded cleanup in pair-agent tests

Discover the daemon port from its owned state file, retain startup diagnostics, and await failed-start cleanup. Add occupied-port, early-exit, deadline, and foreign-state regressions while preserving the existing HTTP assertions and hook budgets.

Co-authored-by: Codex <noreply@openai.com>

* Preserve queued edit identity and recover clipped Bash permissions

Distinguish separately queued unfinished edits from mutation of one native tool ID. Keep grants bound to an exact owned request and reject reused IDs, ambiguous inputs, and competing owners.

Support the pinned renderer's literal em dash and request a repaint when only the Bash card's top rule is clipped. Grants still require the complete fresh card and an exact native acknowledgment.

Validation: 413 integrated parser/event tests passed; private repaint controls and joint source review passed. Full canonical suite and native periodic rerun remain pending.

Co-authored-by: Codex <noreply@openai.com>

* Keep periodic reviews within their approved contracts and deliverables

Carry exact approvals through engineering review, preserve declared contracts when amending CEO plans, and keep prioritization at the requested decision level. Materialize the revised synthetic SDK reference contract while retaining the five original documentation gaps.

Accept the observed semicolon in the finite DX handoff menu and register the direct source dependencies used by the engineering cases. Regenerate canonical review documents without changing model budgets, retries, count bands, or native completion assertions.

Validation: all-host generation and 275 review, fixture, selection and parity tests passed. Full free-suite and native periodic validation remain pending.

Co-authored-by: Codex <noreply@openai.com>

* Keep Eng approval cadence and independence guards explicit

* Accept ordinary punctuation in manual review handoffs

* Recover file permissions alongside queued Bash calls

* Carry approved DX work through later review findings

* Clarify the synthetic auth internal failure decision

* Bound the periodic DX fixture to onboarding changes

* Recognize native Design review handoff labels

* Hold scope in the integration-choice review fixture

* Carry approved Design decisions through review evidence

* Capture listener state when feedback reload fails

* Exclude workspace caches before checking deprecated flags

* Verify Design UI scope against a seeded review plan

* Clarify plan review decisions and outside-voice approval flow

* Reject setup menus in the Design UI gate

* docs: require focused repair validation before final acceptance

* fix: separate review commitments within existing prompt budgets

* docs: align generation and contributor validation guidance

* fix: advance native review prompts and count acknowledged findings

* chore: bump version and changelog (v1.87.1.0)

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* chore: enforce cheap checks and side-effect-free validation previews

* fix: handle owned Fetch permissions and oversized native cards

* test: ground review fixtures in independent executable contracts

* fix: preserve review decisions and verify reports before completion

* test: construct the synthetic credential URL without a scanner false positive

* test: materialize DX examples and verify their actual local behavior

* fix: clarify CEO review decisions and execution order

* fix: clarify review workflow ordering and select Design quality checks

* Fix review decision gates and incomplete evaluation fixtures

Persist CEO and engineering commitment ledgers before menus, preserve exact
approvals, and distinguish implementation structure from feature scope.
Route Autoplan through the canonical CEO Step 0 ordering. Classify DX findings
before requesting approval and ground runtime claims in actual evidence.

Complete neutral non-target fixture contracts and accept the captured Design
handoff purpose without relaxing its ownership or acknowledgment checks.
Record runtime-capability verification in AGENTS.md validation discipline.

Validation: 1,335 focused tests passed across 21 files; build, all-host freshness,
skill validation (647 artifacts / 107 tracked), and credential checks passed.
Prior paid failures are preserved; behavioral acceptance remains pending.

* Fix review decision boundaries and owned Read prompts

Preserve exact approvals across review options, compare consistent DX milestones,
and keep proposed implementation separate from review evidence. Bind modern
Read prompts to one immutable native request and wait for its result.

Retain captured regression verdicts, correct fixture error names, improve import
probe diagnostics, and record focused-first validation discipline in AGENTS.md.

* Clarify CEO and engineering review decisions

Use explicit decision steps, one engineering ledger, and clear scope/write transitions. Preserve exact approvals and distinguish pending test requirements. Keep unrelated generated content unchanged.

* Fix review decision ordering and native evaluation interactions

* Clarify engineering decisions and test artifact order

* Clarify pending choices and approvals in CEO reviews

* Make CEO review phases sequential and clarify completion

* Fix Design board submission intent matching

* Seed an existing browser test baseline for Autoplan

* Document decision-log payloads before state initialization

* Preserve exact review scope and decide one change before drafting options

* Require input identity before repeating passing model judges

* Honor permitted storage throughout CEO review completion

* Match complete native permission text within the pinned renderer contract

* Align review approvals, independent choices, and bounded validation

* fix: preserve reopened approvals and declare fixture interfaces

* fix: isolate review artifacts and audit complete questions

* fix: match detector artifact permissions to configured storage

* fix: complete native permissions and review fixture workflows

* fix: order CEO review work and separate engineering guarantees

* fix: preserve native validation and separate review choices

* fix: clarify review decisions and judge complete report context

* fix: constrain review judgments and retain parse failures

* fix: compare each affected value before review decisions

* fix: make engineering review decisions and completion order explicit

* fix: give the complete Autoplan evaluation a bounded chain budget

* fix(cso): diagnose forbidden Docker endpoints before tool lookup

* fix(reviews): reconcile workflow contracts and generated artifacts after main integration

* fix(evals): migrate retained regressions to the native review harness

* fix(tests): close native harness and workflow integration regressions

* fix(evals): preserve complete permission context and native menu contracts

* fix(tests): capture synchronous command output without pipe drain stalls

* fix(reviews): clarify decision and completion ordering

* fix(reviews): separate decision readiness from final completion checks

* refactor(reviews): consolidate decision rules and completion branches

* fix(plan-eng-review): order preparation and clarify decision routing

* fix(plan-eng-review): restore size and question-format guard parity

* fix(plan-eng-review): clarify scope phases and blocked completion

* fix(plan-eng-review): unify review flow and report destination

* fix(plan-eng-review): define bootstrap and question stage ownership

* fix(plan-eng-review): clarify review structure and design lookup

* fix(plan-eng-review): render report examples and show saved decisions

* fix: consolidate Eng review decisions and select their evaluations

* test: cover overlapping terminal attachments and clean merged runner type

* fix: preserve Office Hours relationship closings during review updates

* fix: retain pasted review targets across slash invocations

* docs: preserve validation traces and correct release scope

* test: cover pasted targets in both review skills

* fix: validate report artifacts before recording success

* fix: redact source roots at CSO report boundaries

* fix: bind native Design questions before answering

* test: select report privacy and native recovery regressions

* test: bind rejection predicate in extracted observers

* fix: bind complete boxed native questions

* test: keep the Design UI fixture on native review

* fix: preserve review decisions and evaluation completion outcomes

* fix: clarify CEO approval and report completion order

* fix: align native review evaluation ownership and completion

* fix: bind review evaluators to native decisions and owned artifacts

* fix: validate review decisions against native outcomes

* fix: preserve review evidence and Autoplan phase handoffs

* test: bind review evidence to owned decisions and completion

* fix: retain owned native history across compaction

* fix(evals): validate current review decisions and setup choices

* fix: bind Autoplan reviews and phase completion to current amended input

* fix: reconcile native review evidence and close Autoplan phases

* test: recognize owned whole-candidate complexity decisions

* test: preserve report freshness for approved investigation handoffs

* fix: recognize scoped review findings and isolate dual voice fixtures

* fix: make review handoffs and question dispatch self-contained

* test: recognize complete CEO decisions and procedural pauses

* fix: bind current CEO comparison options and risk intervals

* test: bind engineering decisions and completion to owned evidence

* fix: publish Autoplan phase reports before continuing tools

* test: verify actual Autoplan dual-review dispatch evidence

* test: select dual review when shared evidence fixtures change

* fix: clarify plan review decisions and completion gates

* fix: make CEO review decisions and return paths explicit

* test: keep Autoplan prompt files inside attempt state

* test: preserve source whitespace across permission dialog wraps

* fix: publish Autoplan phase reports before continuing

* test: recognize current CEO comparisons and reject inactive records

* fix: reconcile engineering decision states before completion

* test: recognize complete Design decisions and reports

* test: verify current engineering decisions before navigation

* Recognize source-owned component reduction choices

* fix: recognize current CEO ledger and commitment grids

* test: supply RequestPolicy context to Eng count fixture

* fix: save complete engineering decisions before asking

* fix: bind Autoplan publication to the complete phase readback

* chore: prepare 1.87.5.0 reliability release

* fix: clarify engineering review completion and preserve log failures

* fix: bind CEO saved choices and current section ancestry

* fix(evals): bind review execution and completion evidence

* fix(plan-ceo-review): verify complete decisions before asking

* fix(evals): preserve complete engineering choice records

* fix(evals): preserve complete review outcomes and bounded fixtures

* fix(autoplan): publish phase reports before advancing

* fix(plan-ceo-review): validate option fields before asking

* fix(plan-eng-review): verify current decisions after answers

* fix(evals): bind review decisions and bound fixture scope

* fix(plan-ceo-review): verify decision rows and edit saved checkpoints

* fix(evals): bind review evidence and scope document lookup

* fix(plan-eng-review): update resolution state with its answer

* fix(reviews): preserve complete questions through dispatch

* fix(evals): recognize completed mode declarations

* fix(evals): define cache consistency at wrapper completion

* fix(evals): validate owned initial scope and completed review handoffs

* fix: assemble complete CEO decision fields before saving

* fix: authenticate automatic mode decisions without guessing selectors

* fix: bind engineering coverage to approved regression contracts

* fix(evals): supply review helpers to native Eng capture

* fix(plan-eng-review): preserve the full selected option scope

* fix(evals): recognize owned engineering seed and regression evidence

* fix(evals): bind engineering retry reports to native approvals

* docs: clarify release guarantees (v1.87.5.0)

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* fix(evals): recognize owned engineering decisions and handoffs

* fix(evals): bind engineering decisions and completion evidence

* fix(tests): align review contracts and selection fixtures

* fix(skills): restore review prompt size limits

* fix(plan-eng-review): clarify review execution and completion

* fix(evals): preserve configured retries through all supervision layers

* Clarify Engineering decisions and report completion

* Keep native decision assertions within their source boundary

* fix: recognize owned engineering decisions and completed navigation

* fix: bind completed auto decisions to their current review

* fix: recognize explicit CEO source attribution

* fix: dispatch verified CEO decisions without recomposing fields

* test: expose existing execution deadlines to review actors

* fix: distinguish CEO decision records from incidental headings

* test: bind split-scope choices to the registered native actor

* test: connect reviewed regressions to required evaluation coverage

* Clarify CEO decision routing and completion stages

* test: expose existing section review deadlines to fixture actors

* test: recognize complete native CEO pacing inventories

* test: exclude answered history from current CEO payloads

* test: detect phase entry through owned skill HOME aliases

* test: validate native review completion and owned report permissions

* fix: make Autoplan close packets carry the parent handoff steps

* test: assess source-bound HOLD decisions within the existing deadline

* fix: keep CEO native decision fields under one formatting authority

* test: register integrated review and permission dependencies

* test: align native review adapters and finding coverage

Preserve explicit AUTO decisions, apply native single-select defaults, and bind complete cropped questions and report permissions to their owned requests. Require seeded review findings instead of crediting setup menus.

Keep captured failure controls and additive selection dependencies. The integrated candidate passed 3,099 focused tests across 65 files; affected paid validation remains required before publication.

* fix(autoplan): require phase reports before advancing

* fix(evals): bind setup and evidence to complete attempts

* fix(evals): bind native answers and pending writes to fixture scope

Preserve complete option rows when native descriptions wrap, retain current
owned Write arguments before journal publication, and keep engineering and
DX answers within their declared fixture interfaces. Add captured free
regressions without increasing model budgets or relaxing completion checks.

* fix(autoplan): verify phase reports across native tool paths

Guard owned methodology reads and reviewer dispatches, detect complete driver
loads through Bash, and distinguish report-only edits from implementation
changes. Follow authenticated native UUID ancestry when journal writes arrive
out of order and verify earlier native content for cached phase reads.

Keep current close acknowledgment and parent publication in order, require CEO
entry before later phases, and register captured failure regressions.

* fix(evals): honor native input and collection lifecycles

Match complete native Edit panes and truncated question borders, reject stderr close before EOF, and stop the CEO split fixture once its acknowledged scope decisions are collected. Keep semantic validation, process failures, report requirements, and absolute deadlines authoritative.

Add captured-event and real-process regressions with selection dependencies. Focused checks pass; final integrated paid and full-suite acceptance remain pending.

* fix(autoplan): retain native session ownership across directory changes

Recover missed native UUID ancestry through the existing strict graph while preserving ordinary event order and legacy scoping. Bind publication hooks to Claude's original project directory while retaining current cwd for requested file paths.

Captured public-event regressions, existing caller checks, and a pinned native CLI loopback verify both fixes. Preserve failed attempts and require fresh paid and final full-suite acceptance.

* docs: align evaluation limits and completion version

* fix(autoplan): allow authenticated phase reads during journal streaming

* fix(evals): bind clipped native questions and owned edit dialogs

* fix: preserve overlay retries and bounded cleanup

* fix: recognize owned planning preludes in native questions

* docs: explain overlay scheduling and cleanup guarantees

* fix: require fresh publication after Autoplan phase reruns

* Release gstack 1.87.6

* fix: preserve CI paths, process identity, and test deadlines

* fix: keep informational setup commands independent of install probes

* fix: clarify plan review decisions and bound source audit reports

* Fix remaining Windows identity and native path CI failures

* Clarify CEO review decision and reviewer-result routing

* test: accept no-install planner in retry supervision

* fix(ceo-review): make review decisions and report completion explicit

* perf(test): add fast PR gates, input-keyed judge reuse and isolated free shards

* fix(test): start isolated CEO smoke from its existing project plan

* fix(test): repair CI fixture races and preserve retry evidence

* fix(ceo-review): clarify approvals, depth and saved completion

---------

Co-authored-by: OpenAI Codex <noreply@openai.com>
2026-09-22 14:57:52 -04:00
b1485d8897 v1.74.0.0 test/CI overhaul: green means green, suites restructured for speed (#2721)
* fix(ci): free-tests lane actually runs the make-pdf e2e gates

The 9 make-pdf/test/e2e gate tests probe make-pdf/dist/pdf,
browse/dist/browse, and the diagram-render bundle, then self-skip when
absent. The required free-tests lane never built any of them, so the
gates silently skipped on Linux for their entire life (verified: 9 of
14 skip, exit 0). make-pdf-gate.yml's justification for deleting its
Linux leg claimed the free lane covered this — it didn't.

- new build:gates script: exactly the three artifacts the gates probe
  (full bun run build compiles five binaries; ~60-90s tax on the only
  required check is not warranted)
- free-tests.yml: build:gates step + poppler-utils +
  fonts-noto-color-emoji (fonts must precede the first browse daemon
  launch — Chromium snapshots fontconfig at startup; verified live:
  a warm daemon renders tofu, a fresh one embeds NotoColorEmoji)
- make-pdf/test/e2e/ci-prereqs.test.ts: GSTACK_EXPECT_BINARIES=1 (set
  by the workflow) inverts the skip polarity in CI — dropping the
  build step or poppler fails the lane instead of re-opening the
  silent-skip hole

Pre-flight: all 9 gates green on Linux locally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): kill the three zero-test eval jobs (hollow green)

- delete the vestigial e2e-codex / e2e-gemini matrix rows: both files
  are whole-file periodic-tier, so with no row tier: they ran ZERO
  tests and reported green on every PR (~2 min of runner each, pure
  false confidence; the periodic lane owns those suites)
- e2e-pty-plan-smoke gains tier: gate — its two files are whole-file
  describeE2ETier('gate'), so the job burned ~7 min of container setup
  then skipped every describe
- KNOWN_TIER_UNSET burned down to empty; the ratchet stays armed so a
  future row/file tier mismatch fails the suite instead of shipping
  hollow green

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): least-privilege permissions + fork-safe concurrency keys

- evals.yml / evals-periodic.yml evals jobs: explicit contents:read +
  packages:read (container-image pull) and persist-credentials:false —
  the jobs that execute PR-authored code with three provider API keys
  ran on the repo-default token grant with the token written into
  .git/config
- permissions blocks for the 4 workflows that had none (skill-docs,
  make-pdf-gate, windows-free-tests, windows-setup-e2e)
- fork-safe concurrency keys: actionlint, skill-docs, make-pdf-gate,
  windows-setup-e2e switch from head_ref to PR-number keying — a bare
  branch name carries no fork prefix, so same-name branches from two
  forks shared one group and cancelled each other's runs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): one bun version everywhere + drift tripwire

Lanes disagreed four ways: 1.3.13 (free-tests, windows, Dockerfile.ci),
latest (quality-gate, make-pdf-gate), unpinned (skill-docs,
version-gate — setup-bun installs latest), 1.3.10 (.gitlab-ci.yml).
Different Bun versions change the runner output shapes the strict
classifiers regex-match, spawn semantics, and shell parsing — a lane on
a different Bun tests a different product; Dockerfile.ci's own comment
records this class biting once already (silent 1.3.13/1.3.14 drift).

All surfaces pinned to 1.3.13; test/bun-version-drift.test.ts scans
every workflow setup-bun stanza + Dockerfile.ci + .gitlab-ci.yml and
fails on any mismatch or unpinned stanza. skill-docs also gains
--frozen-lockfile (was bare bun install).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(ci): bind the three-way image-tag hashFiles() expressions

evals.yml, evals-periodic.yml, and ci-image.yml each compute the CI
image tag from hashFiles('.github/docker/Dockerfile.ci', 'bun.lock',
'patches/**') — synced by comment only (TODOS.md 'CI three-way
image-tag drift'). If one input list drifts, that workflow computes a
different tag for the same content: eval lanes silently rebuild the
image every run, or ci-image prebuilds a tag nobody looks up. The test
extracts each tag-computation site and fails on any mismatch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): ci-image stops rebuilding the identical image every ship

- package.json out of the trigger paths: the tag hash deliberately
  excludes it (version bumps every ship), so every merge rebuilt and
  re-pushed the IDENTICAL tag (~2m26s for zero content change);
  patches/** added (it IS a tag input)
- manifest existence check (mirrors evals.yml): tag already exists →
  skip the build
- concurrency group: two rapid main pushes raced pushing the same
  :latest/:buildcache tags
- cron staggered 06:00→04:00 Monday: it shared the exact minute with
  evals-periodic, which could race a half-pushed tag or duplicate the
  build
- timeout-minutes: 30 (was unbounded → 360-min default for a hung
  docker build)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): quality-gate drops the 74s full-history checkout

fetch-depth:0 cost 74 of the job's 92 seconds; the three gates it feeds
take ~12s combined. Shallow checkout + exact-SHA fetches for the diff's
base/head (an exact-SHA fetch, not a guessed depth — long-lived
branches and merge queues still resolve), with a --deepen fallback for
push events whose 'before' is unusable. timeout right-sized 20→10 min.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): small-lane batch — timeouts, right-sizing, windows cache warm-start

- timeout-minutes on the 6 remaining unbounded jobs (actionlint 5,
  skill-docs 10, version-gate 10, make-pdf-gate 15, pr-title-sync 5,
  evals build-image 15) — a hung step sat on GitHub's 360-min default
- right-size measured-over-long timeouts: dependency-review 10→5,
  windows-setup-e2e 15→10
- dependency-review: 2-core runner (28s API call on an 8-core box) and
  drop .github/workflows/** from its trigger paths (workflow edits have
  no dependencies to review)
- windows caches gain restore-keys: a lockfile bump paid the 26s/43s
  restore for a guaranteed cold miss

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): scope GSTACK_HOME to each file's execution window

Five files assigned process.env.GSTACK_HOME at module scope. Shard
processes evaluate sibling modules before running their tests, so the
assignment leaked into every other file in the shard — the damage was
already visible in defensive workarounds (relink.test.ts:28 'fresh
install test saw a neighbor's skill_prefix'; cdp-e2e's own comment
documents a sibling's temp dir baked into artifacts).

Pattern: save original, assign in beforeAll, restore in afterAll
(cdp-e2e already restored but still assigned at load — its window now
matches the others). GSTACK_TELEMETRY_OFF and GSTACK_PROJECT_SLUG get
the same treatment where they rode along. Victim files' defenses stay
in place (cheap insurance).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: tripwire against module-scope GSTACK_HOME assignments

Column-0 assignment of GSTACK_HOME / GSTACK_STATE_ROOT in any tracked
*.test.ts fails with the file:line and the fix (beforeAll + afterAll
restore). Kills the cross-file env-leak class the previous commit
swept.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): e2e-harness-audit derives its skill census from disk

The hand-maintained 39-name SKILL_GLOBS list had drifted to 39 of 54
SKILL.md.tmpl on disk. No live gap today (none of the 15 unlisted
skills is interactive), but the next interactive skill would have
landed unguarded with zero signal. The audit now walks top-level dirs
for SKILL.md.tmpl (statSync so symlinked dirs like connect-chrome
count), so new skills are in scope the commit they appear.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(evals): judges honor the eval-model resolution chain + real 429 backoff

callJudge inlined GSTACK_EVAL_MODEL_JUDGE || sonnet, silently ignoring
the global GSTACK_EVAL_MODEL override every other eval call site honors
via lib/eval-model.ts. New 'judge' kind in DEFAULTS (sonnet — the D1a
pin-on-regressors calibration stands; model CHOICE unchanged) and
callJudge resolves through it: explicit arg > GSTACK_EVAL_MODEL_JUDGE >
GSTACK_EVAL_MODEL > default.

429 handling upgraded from one fixed 1s retry (reliably lost races at
CI concurrency) to three jittered exponential retries (~1s/4s/16s),
honoring the server's retry-after when present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): the two expect(true) paid stubs become test.todo

skill-e2e-spec-execute (600s budget) and skill-llm-eval-spec (300s)
reported PASS on every periodic run while asserting nothing. Deleting
them would remove the periodic-tier selector surface they exist to
register (diff-based selection for spec/ changes), so they become
test.todo — reported as todo/skip, never pass — with the v1.1
implementation specs kept in-file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): reactivate 5 quarantined browse tests (2 security)

extension-sender-auth's two privileged-message denial tests (content
script + missing sender.url — the extension's security boundary) and
snapshot's three skips were quarantined 'pre-existing' failures. Root
cause: machine-local state on the quarantining dev machines — the test
and gate code are byte-identical between the quarantining commit
(410b4928) and HEAD, and all five pass deterministically on a clean
checkout (68/68 across both files, multiple runs). No assertions
weakened, no product changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(evals): activate the 4 paid test files that could never run anywhere

carve-section-loading, codex-e2e-plan-format,
codex-e2e-recommendation-substance, and llm-judge-recommendation gated
on EVALS/tier (free suite loads them as describe.skip) but their names
fell outside PAID_TEST_GLOBS, so no paid lane ever selected them — net
execution zero, forever. The existing matrix tripwire filtered on
isPaidTestFile() first, so it was blind to exactly this class (the same
bug that hid the pre-split monolith's gate tests for ~8 releases).

- PAID_TEST_GLOBS: codex-e2e* + skill-llm-eval* wildcards (replacing
  exact names) + llm-judge-recommendation + carve-section-loading;
  package.json's six test-script glob lists mirrored
- codex-e2e-plan-format gains the explicit periodic tier gate its
  siblings carry (external-service rule) — without it the sharded
  runner's no-guard default would spawn Codex in the gate tier per PR
- eval:bg:periodic --timeout 32400→37800: the census growth pushed the
  periodic worst case to 35910s; the old value had 270s of headroom
  BEFORE this change and would now kill healthy runs mid-flight
- new test/paid-orphan-tripwire.test.ts: any EVALS/tier-gated test file
  outside the globs fails the free suite (reasoned SCANNER_EXEMPT for
  the gate helpers + meta-tests) — the class-killer
- paid-shards pins updated: the four orphans now assert INSIDE the
  census

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(browse): restrictDirectoryPermissions warns and skips symlinked dirs

Closes the Windows Free Tests red: recent lane failures showed a
platform-unguarded POSIX mode-bit assertion ('Expected: 493' — a
symlink-skip test) from PR-branch variants; the KNOWN_WINDOWS_SAFE
force-include reason ('mode-bitmask hits are POSIX-branch only') did
not hold for that shape, and main had neither the guard nor the
behavior.

- product: lstat first; a symlinked dir gets a warning and a skip on
  both platforms — chmod AND icacls dereference the link, so
  restricting through a symlink hardens an unvetted target (and
  /inheritance:r could lock out its real owner). All callers already
  treat hardening as best-effort (try/catch).
- test: the symlink regression test, platform-aware — symlinkSync in
  the house try/catch skip pattern (Windows runners without Developer
  Mode can't create symlinks), mode-bit assertion guarded off win32,
  behavior assertions (no throw, warning text, target readable)
  everywhere; POSIX still proves the skip (0o755 unchanged, not 0o700)
- KNOWN_WINDOWS_SAFE reason updated to the now-true premise

20/20 pass on Linux.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): unique tmp dirs for plan artifacts + audited live-repo cwd sites

Six paid PTY tests wrote their expected plan artifact to a FIXED shared
/tmp path ('/tmp/gstack-test-plan-<mode>.md') and rmSync'd it in
finally — under --retry 1, EVALS_JOBS>1, or two concurrent worktrees, a
sibling's cleanup deletes this run's artifact and the D19 'agent did
not produce expected plan file' assertion fires spuriously. Each test
now mkdtemps its own dir, interpolates the unique path into the agent
prompt (fixture-sourced prompts get a replaceAll + drift guard that
throws if the fixture's literal ever moves), and cleans up its own dir.

The 18 cwd:-into-the-live-repo sites were audited: all deliberate
(skill registry + hermetic pre-trusted dir, in-repo gen renders, git
history reads, slug resolution) — each now carries a
'// LIVE-REPO CWD: <reason>' comment so the next audit can tell
deliberate from accidental.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): trim the seven over-wall 1700s timeouts to the 1500s physical ceiling

1,700,000ms (28.3 min) exceeded every wall these tests run inside: the
25-min CI job timeout and the 1800s sharded-runner wall (which also
leaves --retry 1 zero room for a second attempt). Budget above the wall
is fiction, not headroom — a test that actually used it produced a
job-level kill (no bun summary, no artifact) instead of a clean
per-test timeout. No recorded p95 exists for this family (they are
being retiered to periodic in the re-platform wave); the trim stops at
the physical ceiling rather than guessing lower. Final policy lands in
the Wave-2 eval-budgets constants module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(gen): main() guard — importing gen-skill-docs no longer regenerates the tree

The generator's whole body executed at module load, so any import of it
(test/gen-skill-docs.test.ts pulls assertSinglePreamble via require();
test/catalog-trim.test.ts imports helpers) regenerated all 71 SKILL.md
in place — the root cause of half the TREE_MUTATING serial-shard
entries (hazard class #2532). The body now lives in an exported
main(): number behind if (import.meta.main).

Semantics preserved exactly: failure exits are immediate (matching the
old top-level process.exit), success leaves the event loop to drain so
the llms.txt fire-and-forget IIFE finishes its write, and the module
stays synchronous/require()-able. Proofs: byte-identical --host all
output (git status clean), --dry-run stale-tree still exits 1 (the
skill-docs freshness lane depends on it), and the new
test/gen-skill-docs-import-purity.test.ts pins load-time purity via a
subprocess probe (mtime-based, so a dirty worktree can't false-fail).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(gen): --out-dir renders every host, outputs-only

--out-dir was Claude-host-only (gen-skill-docs.ts:842), which forced
the codex/factory-regenerating tests (gen-skill-docs, skill-validation,
host-config) to mutate the live tree — the reason they sit in the
TREE_MUTATING serial shard. The flag now mirrors ALL outputs into the
out-dir: external-host trees (.agents/.factory/... via
processExternalHost), external section files, openclaw docs, and
gstack/llms.txt (a catalog-mode render must never rewrite the tracked
index). OUTPUTS ONLY — inputs (templates, sections/, host configs) are
always read from ROOT, so an empty out-dir can never feed the render.
rewriteSectionBase stays Claude-only (external hosts have their own
path grammar).

Proofs: in-place --host all is byte-identical (tree clean);
--host all --out-dir <mkdtemp> renders the full multi-host tree with
ROOT untouched; gen-skill-docs-out-dir tests + 415/415
gen-skill-docs.test.ts green (bin/dev-setup's claude rendering
byte-compat).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(evals): every E2E key's dep list names its own declaring test file

129-of-177 keys omitted their own test file, so editing only a test's
prompt or assertions selected NOTHING — the changed test never ran on
the change that changed it. 135 keys self-registered (110 E2E + 25
LLM-judge), resolved by strict declaration evidence (testName:/
testIfSelected/judge call sites), with skill-name false positives
excluded.

e2e-tier-alignment's warn-only branch for unregistered files is now a
hard failure with a 4-entry KNOWN_UNREGISTERED ratchet (template-
literal testNames, fail-open-safe) + a burn-down test so the set only
shrinks. Selection sanity: a one-file diff on skill-e2e-qa-workflow now
selects its 4 tests (was 0); skill-llm-eval 0 → 25.

Known follow-ups (filed): 15 E2E + 2 judge PHANTOM keys select tests
that exist nowhere; codex-e2e-plan-format's testIfSelected names have
no map keys (run-all only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(evals): ratchet the 8 newly-visible gate-matrix gaps

The self-registration sweep made these eight files' gate-tier keys
visible to the census for the first time — their gate tests run in NO
CI lane today (pre-existing hole, newly measurable). Ratcheted into
KNOWN_MATRIX_GAPS with the burn-down note: the paid-lane re-platform
runs every gate file by construction and retires this ratchet class.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(test): duration-aware LPT shard packing for the free suite

Hash sharding balances file COUNTS (1.15x spread) but not cost — the
Playwright-launching files landed 4/3/4/1/2/1 across 6 shards, giving a
measured 28s–97s shard spread and ~40s of idle tail on every run.
Full-suite mode now packs by recorded per-file durations
(longest-processing-time-first) when the committed seed
scripts/free-test-durations.json exists.

- ONE store, no overlay: the seed is refreshed occasionally via the new
  --record-durations mode (each file timed in its own child — exact,
  and immune to bun's stream buffering, where silent passers print no
  header to timestamp); GSTACK_FREE_TEST_DURATIONS overrides the path
  for experiments; CI never records
- seed is a hint: missing → silent hash-shard fallback; corrupt (bad
  merge) → one warning + fallback; unknown files → 75th-percentile
  pessimism so a surprise long-runner can't recreate the tail
- packed shards get duration-aware walls (max(base, predicted x 3)) —
  LPT decouples count from cost BY DESIGN, so the 5s/file heuristic
  would undersize a shard holding few expensive files
- one log line per shard (files + predicted seconds) so packing
  regressions are diagnosable from any run log
- the --shard CI-matrix path is untouched: stable hash indices are its
  contract
- successor note in-code: bun >=1.3.14 ships native --timings/--shard
  LPT — swap this packer when the repo unpins 1.3.13

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): decouple slop:diff from bun run test; quality-gate runs it per PR

'bun run test' silently appended up to two 120s npx slop-scan runs plus
a git worktree add/remove after the suite (2>/dev/null || true) —
invisible in the documented '~90-100s' timing and pure friction in the
pre-commit loop. Decoupling is not coverage removal: quality-gate.yml
now runs slop:diff on every PR (advisory, matching its in-repo 'never
blocking' contract), and /review already invokes it explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(test): eval-budgets timeout tiers + fit/ceiling policy test

Five named tiers (JUDGE 120s / CAPTURE 300s / CAPTURE_LONG 600s /
PTY 900s / PTY_LONG 1200s) replace hand-ratcheted sprawl (46x300s,
46x120s, 44x360s, 44x180s, 27x240s, 19x150s, 13x420s, 12x600s...),
much of it inflated to paper over the old 40-way in-shard concurrency
that the sharded runner's 1-file-per-shard model kills. Policy test
pins: every tier fits the shard wall minus 120s overhead (the
structural fix for budgets-above-the-wall fiction), tiers stay ordered,
and no paid literal exceeds PTY_LONG x1.25 — oversized tests get split,
not budgeted past the wall.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(test): shared runBin helper for bin-script unit tests

~36 free test files each carry a near-identical local run() (spawnSync
+ utf-8 + {status, stdout, stderr}) differing only in env composition,
cwd, and timeout. runBin absorbs the invariant core; options carry the
variance (gstackHome sets BOTH GSTACK_HOME and GSTACK_STATE_DIR — the
config-precedence trap several locals rediscovered independently; home
for $HOME-anchored bins; input/trim/timeout/maxBuffer). Free-test-only
by design so it never becomes a de facto global touchfile. Migration of
the 36 call sites lands separately (mechanical batches).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): runBin trim assertion — trim shapes stream ends, not interior

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(test): mechanical sweep — 298 paid-test timeouts onto eval-budget tiers

69 files, both shapes (trailing bun-test budgets and runner
timeout/timeoutMs options), ROUND-UP ONLY so nothing that passed can
start failing: 75 → JUDGE_MS, 137 → CAPTURE_MS, 74 → CAPTURE_LONG_MS,
9 → PTY_MS, 3 → PTY_LONG_MS. Raw >=60s literal count in the paid scope:
395 → 97, of which 51 are non-timeout noise (fixture dates, run IDs)
and 46 are enumerated justified holds (comment-carrying calibrated
budgets, poll-loop constants, utility spawn waits, and the seven
physical-ceiling 1_500_000 sites). The eval-budgets policy ratchet
keeps the residue from regrowing.

Known collapse: where an inner runner budget and its enclosing test
budget now share a tier, the old stagger is gone — an overrun surfaces
as a bun test timeout instead of a graceful runner timeout
(diagnosability trade, not a correctness one).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: coverage fill — 95 tests for six zero-coverage surfaces

- eval CLI family (eval-list/compare/summary + eval-select smoke): the
  primary interface to eval results had no tests; isolation via a fake
  gstack-slug under a mkdtemp HOME (the scripts' real resolution path —
  they do NOT honor GSTACK_EVAL_DIR; only EvalCollector does). Pinned
  current behavior: eval-list does NOT exclude _partial runs (documented
  improvement candidate)
- slop-diff (runs on every /review + quality-gate): fixture git repo +
  first-on-PATH npx stub (never downloads real slop-scan); no-diff
  early exit, missing-scanner fallback, fingerprint line-insensitivity,
  merge-base worktree scan
- bin/gstack-code-intelligence CLI arg surface (lib was covered, the
  284-line CLI wasn't): select/consent/suggest/index/search gating;
  pinned: --help routes to usage failure exit 1 (no handler)
- browse media-extract: the page.evaluate callback exercised in-process
  against a mock DOM (no exports added) — lazy-src fallback chain,
  HLS/DASH detection, bg-image url() parsing, 500-element cap
- browse session-cookie-store: factory contract (cookieName/ttlMs/
  maxSessions eviction, cross-store isolation, mint→validate
  round-trip); store is in-memory — no fs cases exist
- lib/version-source direct unit tests (gstack-version-bump.test.ts
  spawns the bin, never imports the lib): parse/format/cmp/bump
  coercion, npm 4→3 translation, #2501 mangled-JSON regression class

All hermetic (mkdtemp homes, runBin child isolation); windows curation
correctly partitions the six.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(test): first runBin migration batch (3 of ~36 run() duplicates)

explain-level-config, benchmark-cli, evidence move onto the shared
helper; each file's remaining special-case spawnSync sites (raw-buffer
probes, env-scrub probes) stay put deliberately. 55/55 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(evals): paid shards spool to disk + shared runShardChild lifecycle

- runPaidShard no longer buffers whole 30-min stream-json streams in
  RAM (x concurrent jobs): every byte tees to a per-shard log file
  (slug-named, path printed at START for mid-run inspection and on the
  FAILED terminal line); failures print a 64KiB tail read back from
  disk; passing shards stay quiet (the file is the record) — the free
  runner's proven contract. Classification unchanged: the strict
  classifier still sees every byte first.
- the ~35 duplicated spawn/group-kill/wall-timer/finally-reap lines
  move into runShardChild in test-strict-output.ts (detached-per-
  platform spawn, signal forwarding, SIGKILL group kill at the wall,
  drain-before-verdict); designed so the free runner can migrate later
- expectedFiles drift fixed toward ENFORCEMENT: the injected-command
  exemption is gone — a fake command exiting 0 without bun's terminal
  summary now reads FAILED (pinned: silent-pass → failed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(evals): parent-computed selection propagates to shard children

The sharded runner computed diff selection once, then each of its 48-73
children recomputed it at module load — including, on touchfiles-diff
branches, a per-child bun subprocess evaluating the old data file (20s
timeout each). The parent now serializes {version, selected, reason} as
EVALS_SELECTION_JSON into the shard env; e2e-helpers adopts it at load.
Fail-open preserved: any parse/shape violation → ONE stderr warning +
local recompute; absent env → silent local compute (non-sharded
entrypoints unchanged). Drift test pins parent→child round-trip to
identical selection decisions plus the malformed/absent cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): kill the four worst fixed sleeps (300s/30s/30s/20s)

- watchdog.test: the 20s blind wait for one production parent-watchdog
  tick becomes BROWSE_PARENT_WATCHDOG_INTERVAL_MS=250 (new env knob in
  server.ts, NaN-safe, production default unchanged) + polls for the
  boot line and the tick's stay-alive log — strictly stronger (the old
  form never proved a tick observed the parent death). 24s → 3.6s.
- stop-dead-daemon / terminal-agent-owner-watchdog: the 300s/30s
  stand-in child lifetimes become stdin-EOF-bound — the child can never
  self-exit mid-test on a slow runner (spurious-failure class) and
  self-reaps instantly if the test dies (no 300s orphans). Node-compat
  stdin APIs (owner-watchdog runs on the Windows lane).
- browser-skill-commands: the sleeper fixture's 30s self-time becomes
  8s (no stdin pipe exists in runToFiles) — far above the 1s product
  timeout it must outlive, below the test ceiling, so a timeout-kill
  regression fails on clean assertions instead of an opaque bun
  timeout; added: stdout must NOT contain 'done'.

45/45 green across the four files + server tripwires.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): gen-skill-docs + catalog-trim leave the serial mutator shard

gen-skill-docs.test.ts's 15 in-place generator spawns now render into
mkdtemp out-dirs (gitignored-artifact reads repointed; the handshake
scan's silent console.warn degrade became a hard assertion); its
tracked-tree reads (freshness dry-run, SKILL.md content pins) stay
reads. catalog-trim needed no change beyond the earlier main() guard —
its import is now side-effect-free (pinned by the import-purity test).
Both TREE_MUTATING entries deleted in this commit, per the transition
rule: an entry leaves in the same commit as the file's last in-place
write.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): skill-validation renders codex host into an out-dir

Its 3 in-place --host codex regeneration sites collapse into one
module-level --out-dir render; assertions untouched. TREE_MUTATING
entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): host-config self-provisions goldens (ordering dependency severed)

Its goldens were 'produced by gen-skill-docs.test.ts' with a
when-missing beforeAll fallback that wrote the live tree — an
inter-test ordering dependency the serial shard hid. It now renders
codex+factory UNCONDITIONALLY into its own out-dir and reads goldens
only from there (the Claude golden deliberately keeps reading tracked
ship/SKILL.md — a read; out-dir claude renders repoint section-base
paths by design). TREE_MUTATING entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): gbrain-detection-override drops mutate-then-git-restore

regenAndSnapshot renders --host claude --out-dir <mkdtemp> (+
--respect-detection) and snapshots probes from the out-dir. The
git-restore machinery is deleted outright — it restored only
PROBE_FILES of the 71 files each call wrote, so a stale tree kept the
other 68 dirty (the partial-restore bug), and its 'no output-path arg'
comment had been false since --out-dir landed. TREE_MUTATING entry
deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): catalog-mode-full renders to out-dir; restore machinery deleted

The full-catalog smoke no longer rewrites all 71 SKILL.md then
regenerates to restore (with its 'CRITICAL: failed to restore' prayer
path) — it renders into a mkdtemp and additionally asserts tracked
ship/SKILL.md is byte-unchanged. TREE_MUTATING entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): idempotency proof strengthens to two-out-dir recursive diff

Two renders into two separate out-dirs, EVERY file diffed byte-for-byte
(claude-only and --host all; normalization only for each dir's own
sanctioned section-base repoint; presence-sanity lists guard against a
vacuous empty-dir pass) — strictly stronger than the old in-place
double-regen that sampled 5 files. TREE_MUTATING entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): spec-template-sync compares an out-dir render, not an in-place one

TREE_MUTATING entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(test): the serial tree-mutating shard dissolves — TREE_MUTATING is empty

Zero mutators remain (all eight render into out-dirs now), so the four
ratchet READERS (parity caps, size budgets, carve parity/ordering) get
a quiet tree by construction in any shard and rejoin the parallel
phase. The ~35-40s serial tail on every full-suite run is gone. The
mechanism stays: a future test that genuinely must write shared
artifacts in place earns an entry with a reason and is serialized
again; the census pin still fails on renamed keys.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(gen): out-dir byte-identity + tree-clean pins for external hosts

codex render: porcelain unchanged AND out-dir gstack-ship/SKILL.md
byte-identical to a fresh in-place render (+openai.yaml presence);
--host all render: exit 0, porcelain unchanged, claude + .agents +
.factory + llms.txt + openclaw docs all present in the out-dir.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(test): commit the initial free-test durations seed (496 files)

Recorded via --record-durations on a quiescent tree: 479s serial
total, p50 92ms / p90 1.8s / max 31.4s — the top-heavy cost shape LPT
packing exists for. A hint, not a contract: refresh opportunistically
with bun run test:free --record-durations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(evals): planner/executor/report modes — the CI re-platform surface

One PLANNER computes diff selection + the slice plan ONCE and writes a
manifest (--emit-plan <path> --slices K); K executors consume it
(--plan <path> --slice i), never self-selecting, and write slice-result
artifacts; a REPORT reconciles results against the manifest (--report
<dir>) fail-closed: a slice whose artifact never landed is a FAILURE,
a planned shard nobody reported fails, wrong-slice/duplicate/cross-tier
results fail. Kills per-slice selector divergence and hollow-lane
aggregation at the root.

- hollow-shard guard: under EVALS_ALL, exit 0 with ZERO executed tests
  (bun's 'Ran N tests' now captured by the classifier — additive) is
  'passed-empty' and fails the run; selective runs keep it 'passed'
  with one warning (in-file diff/tier self-skips are legitimate there);
  unknown counts are never guessed hollow
- retry parity: --retry 1 default + RETRY_OVERRIDES literals for the
  three files whose old matrix rows earned retries: 2 (stale entries
  pinned against disk)
- live smoke: gate plan = 48 shards across 6 slices; report mode exits
  1 on a fabricated missing slice, 0 when complete

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(ci): sliced paid lane (planner -> 6 executors -> fail-closed report)

The parity-phase re-platform: evals.yml gains a second, sliced lane
driven by scripts/test-paid-shards.ts — the SAME engine local
eval:bg:gate uses, so CI and local share one selection engine.

- plan-slices: ONE planner (fetch-depth 0 — the only job needing
  history) emits the manifest; selection fails open to run-all, never
  per-slice (the divergence class is structurally dead)
- eval-slices: 6-way matrix consuming the manifest; PTY seed +
  skill-registration steps run unconditionally (idempotent — a sliced
  lane cannot key them on suite names); aggregate spawn budget
  6 x EVALS_JOBS=2 x EVALS_CONCURRENCY=2 = 24 lane-wide (the matrix's
  40-way per row queued session startup behind 39 siblings — the
  timeout-flake family root); slice results + spooled shard logs
  uploaded as artifacts
- slices-report: reconciles slice artifacts against the manifest
  FAIL-CLOSED via --report — a slice whose artifact never landed, or a
  planned shard nobody reported, is a failure, not an absence
- sequenced needs: evals so provider concurrency never doubles while
  both lanes coexist; the matrix + its ratchets are deleted after
  demonstrated parity (intersection + expected-additions comparison)
- workflow_dispatch gains evals_all (default true) for parity runs and
  post-merge smokes — a dispatch can never silently select zero

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(ci): weekly periodic lane runs EVERY periodic test + gate census backstop

evals-periodic.yml re-platforms onto the sharded runner: planner
manifest → 6 executor slices → FAIL-CLOSED report. This IS the coverage
contract: all ~70 periodic-tier files weekly (EVALS_ALL=1), killing the
silent-rot class where a hard-coded 9-file matrix left ~57 files
running NOWHERE (the autoplan E2E rotted invisibly for months).

- test/helpers/periodic-exclude-data.ts: reasoned exclusions in their
  OWN literals file (deliberately not touchfiles-data — map-diff
  evaluates old versions of that file standalone). Every entry carries
  reason + tracking with a re-entry condition; the runner surfaces each
  exclusion per run; policy test pins real-file + non-empty fields.
  Initial: ship-idempotency + brain-privacy-gate (documented-red,
  never green) and skill-e2e-ios (manual hardware). The TODOS 'sidebar
  E2E trio' turned out already deleted — only tombstone tests remain.
- gate-census job: weekly EVALS_ALL gate-tier run — PR lanes are
  diff-billed, so without this the full gate census might never execute
  anywhere; with the hollow-shard guard it is a census-health check
  (exit 0 + zero executed tests fails), not just a test run.
- failure notification is a concrete gh issue UPSERT (one tracking
  issue, commented per red week — never issue-per-week spam), with
  issues:write scoped to the report job.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: TESTING_INTERNALS covers the 2026-08 runner overhaul

LPT-packed free suite + --record-durations, the emptied TREE_MUTATING
mechanism, the sharded paid runner as the single selection engine,
CI planner/executor/report with the fail-closed report and hollow-shard
guard, the weekly coverage contract + exclusions policy, and the
eval-budgets timeout tiers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(CLAUDE.md): testing prose matches the overhauled runners

- bun run test: duration-packed shards + --record-durations; the
  trailing serial tree-mutating shard no longer exists
- two-tier system: the sliced CI lanes (one engine local+CI), the
  weekly all-periodic coverage contract + exclusions, the gate census
- periodic detach timeout 32400 → 37800

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(TODOS): close the absorbed test-infra items, file the overhaul follow-ups

Closed with receipts: the periodic coverage contract (implemented as
full weekly coverage + exclusions), the eval-harness observability P1
(verified already landed: heartbeat, incremental _partial persistence,
live stderr + eval-watch), and the sidebar trio (already deleted —
tombstones remain). Filed: matrix deletion after parity, the
required-check maintainer decision, browse /tmp-namespace hardening,
PTY boot-readiness waits, the single typed test registry, bun-native
LPT swap, runBin/free-runner migrations, eval-list partial exclusion,
phantom key cleanup, duration-weighted slicing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* v1.73.0.0: test/CI overhaul — green means green, suites restructured for speed

Version + release notes for the audit-and-overhaul branch: every
silently-skipping or never-running test class fixed and tripwired, the
free suite duration-packed with the serial mutator shard dissolved, the
paid lane re-platformed onto the sharded runner (planner/slices/
fail-closed report, parity phase), the weekly all-periodic coverage
contract, eval-budget timeout tiers, and 95 new coverage tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): first-live-run fixes — executor history + two environment-blind assertions

The sliced lane's first run (PR #2721) did its job: the planner and
report worked, the manifest governed, and every failure had a name.
Three were fixable on the spot:

- executor + gate-census checkouts get fetch-depth: 0 — files with
  SELF-derived selection (the LLM-judge map, routing) walk git at
  module load, and selection is deliberately fail-closed on git errors,
  so the shallow checkout crashed those shards ('ambiguous argument
  main...HEAD'). The manifest still governs WHICH shards run.
- landscape --toc gate: the exact toBe(3) landscape-page count was
  font-metric-dependent (3 on Amazon Linux, 2 on ubuntu CI — the same
  disease the file's own page-index comment warns about). Now a
  comparative invariant: --toc must not CHANGE the landscape count vs
  a baseline render.
- paid-run-manifest parse test builds its manifest under EVALS_ALL so
  it never walks git (proven with GIT_DIR=/nonexistent).

Remaining first-run failures are newly-exposed rot in gate files that
had never executed in CI (skillify D1 refusal, session-intelligence
context-restore, one tpa-apple-ban retry flake) — being probed
separately; they are the lane WORKING, not the lane failing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(TODOS): file the three first-execution findings from the sliced lane's live run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* v1.74.0.0: queue-advance — #2722 claims the v1.73.0.0 slot

The version gate caught a live queue collision (its whole job); same
MINOR bump level, next free slot per bin/gstack-next-version.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): per-shard CHROMIUM_PROFILE — the collision class duration packing exposed

Nine test files launch in-process persistent contexts or daemons that
default to the SHARED ~/.gstack/chromium-profile. Two concurrent shard
processes on one profile dir kill each other's browser — observed live
on CI once duration packing recomposed shards: handoff's
launchPersistentContext died 'Target page, context or browser has been
closed' (--user-data-dir=~/.gstack/chromium-profile in the call log)
while a sibling shard's daemon logged 'Chromium process crashed'. Hash
sharding had masked the collision by chance placement; handoff passes
standalone everywhere.

Fix at the runner, not per file: each shard child gets
CHROMIUM_PROFILE=<shard-state>/chromium-profile (the documented env
knob, same isolation idea as the existing per-shard TMPDIR). Files
within a shard run serially, so sharing the per-shard profile is safe;
config.test's resolution-order tests save/restore the env around their
assertions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): landscape --toc gate asserts promotion PRESENCE, not counts

Two rounds of CI receipts: the exact toBe(3) was font-metric-coupled
(3 on Amazon Linux, 2 on ubuntu), and the baseline-comparison repair
then failed 2-vs-3 across renders SECONDS apart in one CI job while the
sibling no-toc test saw 3 — per-render image-promotion timing makes any
count assertion here a coin flip. The sibling test owns exact promotion
counts; this test's actual invariant is that --toc does not break the
promotion machinery: >=1 landscape page + the TOC rendered. Also drops
the second render (halves the test's runtime).

Flaky per-render image promotion itself is worth its own look — noted
in TODOS with these receipts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(TODOS): file the per-render image-promotion nondeterminism (receipts from PR #2721)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): per-FILE Chromium profiles for the nine in-process launcher files

Completes the profile-isolation work: the per-shard CHROMIUM_PROFILE
stopped cross-shard kills; these nine files launch in-process
persistent contexts and could still collide with a lingering daemon a
sibling file spawned on the SAME shard profile. Each now scopes a
mkdtemp profile via beforeAll/afterAll (the module-scope-tripwire-safe
pattern), cleaned up per file. All nine green solo and in combined
runs, except the pre-existing commands+snapshot pairing — proven
identical WITH and WITHOUT these edits (baseline receipts) — which is
the daemon-lifecycle follow-up now extended in TODOS with this
session's receipts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(browse): Chromium-crash exit is daemon-only — embedded launches never kill their host

handleChromiumDisconnect unconditionally process.exit()ed. Correct for
the standalone daemon (its supervisor/user must notice); suicidal when
a TEST launches BrowserManager in-process: a mid-suite Chromium death
exited the whole bun shard with no terminal summary — the exact
truncation class the strict runner flags (observed live: CI shard 1 on
eb233299 died at cache-concurrent-refresh right after a daemon-spawning
gate test; with this fix the same pairing runs to completion and
REPORTS instead of dying).

The standalone entrypoint opts in via markDaemonProcess() under
server.ts's import.meta.main gate — the same embedder contract its
signal handlers already use (gbrowser phoenix keeps its own handlers).
Embedded contexts now get the disconnect log line and continue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): context-restore assertion is evidence-based, not prose-matching

The test failed twice per run in TWO CI cycles while passing locally
4/4: the prompt said 'present the content' and the check grepped the
FINAL message for exact phrases — local runs quoted the file, CI runs
paraphrased ('the most recent context is from branch-b...') and the
substring check lost the coin flip.

- prompt now demands machine-checkable output: the newest file's
  '## Working on:' heading VERBATIM + a literal 'RESTORED: <filename>'
  marker (the mtime-scramble and cross-branch subject matter untouched)
- assertion ordered strongest-first: RESTORED marker → legacy content
  phrases → tool-call corroboration (Read/Bash input naming the newer
  file, credited ONLY when the older file was never read — a
  both-files run must still present the right one)
- the older-file negative got STRONGER: an explicit RESTORED marker
  naming the older file fails even if wintermute words appear elsewhere
- sibling scan: context-recovery-artifacts got the additive prompt-side
  treatment only (quote the matched literals verbatim); its lenient
  1-of-6 assertion deliberately unchanged

3/3 consecutive local green with all evidence classes firing
(marker=true, content=true, toolNewer=true, toolOlder=false).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): skillify family — HOME==cwd broke project-skill registration

Root cause (forensically pinned from stream-json init events + a
kill-after-init probe): with HOME set EQUAL to the child's cwd, claude
resolves <cwd>/.claude/skills as the PERSONAL skills directory and the
seeded project-tier skills never register — the Skill tool returned
'Unknown skill'. The provenance-refusal test then improvised a refusal
whose wording missed the regex (the deterministic CI+local red); the
happy-path and approval-reject siblings passed only because their
agents self-recovered by Reading SKILL.md manually — silently not
exercising the Skill-tool path at all.

All three tests now use HOME=<workDir>/home (a fresh subdir keeps the
override's intent: child ~/.gstack writes land in the assertable
sandbox, without the cwd collision). Refusal test additionally: a
'not registered/unknown skill' tripwire (a not-loaded skill can never
pass as a refusal) and the refusal regex now matches assistant text
only — the skill BODY echoed into the transcript contains the exact
refusal message, so the old full-surface match could pass vacuously
once the skill loaded. Sibling disk assertions sweep both $HOME/.gstack
and cwd .gstack roots (positives and negatives).

Verified paid: refusal 2x consecutive green with the skill's EXACT
message rendered ('Launching skill: skillify' in-transcript), then the
full file 5/5 green (~$1.35) with both siblings driving real Skill
calls (25-27 turns each).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(TODOS): two of three first-execution findings fixed (skillify family, context-restore)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): context-restore gets a private home — the REAL root cause was fixture sharing

The evidence-based assertion fix was treating a symptom. The slice
artifact's embedded transcript showed the CI agent restoring
20260829-context-save-skill-test.md — the checkpoint the SIBLING
context-save test wrote into the SHARED gstackHome checkpoints dir,
which by filename-prefix ordering genuinely IS the newest. The agent
behaved CORRECTLY; the test's fixture set was open to concurrent
sibling writes, and bun --concurrent ordering differs between CI (save
finished first) and local (restore listed first) — the entire
local-green/CI-red split explained.

The restore test now uses its own .gstack-restore-home (the whole home
moves, not just the handed path — an agent deriving the dir from
GSTACK_HOME/projects/<slug> must land in the closed set too). Full file
4/4 paid green with all evidence flags firing.

Also: the on-failure shard-log artifact glob uploaded nothing — the
Fix-bun-temp step points TMPDIR at /home/runner/.cache, so the spool
lands there, not /tmp. Both eval workflows now glob both locations
(this gap is why diagnosing THIS failure required digging transcripts
out of the slice-results artifact).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(evidence): carry the real index mtime onto gstack-wtree's temp copy

The stat-cache seed (cp of the real index) stamped the temp index "now",
which defeats git's racy-git protection: an entry is only re-hashed when
its cached mtime is not older than the index file itself, so a same-size
rewrite landing in the same second as the last real index write looked
non-racy, kept its stale stat-cache entry, and vanished from the
fingerprint — evidence stayed FRESH after a source change. This is the
CI flake in test/evidence.test.ts "allow-paths carve-out" (sub-second
alignment on fast runners: expected STALE exit 1, got FRESH exit 0).

touch -r restores the original index timestamp, reinstating the exact
racy window git itself uses. Deterministic regression pin in
test/review-log.test.ts reproduces the miss with pinned zero-nsec
timestamps (fails on the old script, passes now); receipts: manual
probe shows the fresh-stamped copy returning the clean tree for a
same-size 'hello'→'howdy' rewrite while the mtime-carried copy detects
it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(test): landscape gate bounds the promotion count instead of pinning 3

The alt-hinted image promotion rides the per-render measurement race
already filed in TODOS (2-vs-3 landscape pages on renders seconds
apart — CI receipts from PR #2721, now reproduced locally). Pin the
two deterministic promotions as the floor and the three promotable
blocks as the ceiling (anything above 3 means the veto leaked); the
veto/portrait assertions remain exact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Test <test@test.com>
2026-08-29 09:06:54 -07:00
Garry TanandClaude Opus 4.7 a81be53621 v1.10.0.0: fix AskUserQuestion cadence + Pros/Cons format upgrade (#1178)
* fix(preamble): reorder AskUserQuestion Format above model overlay + rewrite Opus 4.7 pacing directive

Root cause of plan-review regression (v1.6.4.0): model overlays rendered
ABOVE the pacing rule in every SKILL.md, so Opus 4.7 read "Batch your
questions" first and absorbed it as the ambient default. The overlay's
claimed subordination ("skill wins on pacing, always") didn't stick —
literal-interpretation mode reads physical order, not claimed hierarchy.

Part 1 of 4 (plan: ~/.claude/plans/system-instruction-you-are-working-polymorphic-twilight.md):

scripts/resolvers/preamble.ts
- Move generateAskUserFormat above generateModelOverlay in section array
- Comment explains why — prevents future refactors from silently reverting

model-overlays/opus-4-7.md
- Replace "Batch your questions" block with "Pace questions to the skill"
- New wording makes one-question-per-turn the default when the skill
  contains STOP directives; batching becomes the explicit exception

Regenerated 30 SKILL.md files via bun run gen:skill-docs.

Verified:
- With --model opus-4-7: Format renders at line 359, Model-Specific
  Patch at 373, "Pace questions" at 419 (Format comes first, overlay
  second, pacing directive intact).
- bun test passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(plan-reviews): tighten STOP/escape-hatch directives across 4 templates

Part 2 of 4 (plan: ~/.claude/plans/system-instruction-you-are-working-polymorphic-twilight.md).

Codex caught that v1.6.3.0's reasoning collapsed on Opus 4.7: the old
escape-hatch wording ("If no issues or fix is obvious, state what
you'll do and move on — don't waste a question") let the literal
interpreter classify every finding as having an "obvious fix" and skip
AskUserQuestion entirely. Reviews became reports.

Per-template hardening (16 sites total, verified by rg):

plan-ceo-review/SKILL.md.tmpl (13 sites):
- 12 inline STOP directives: replace the full escape-hatch clause with
  "zero findings → say so and proceed; findings → MUST call AskUserQuestion
  as a tool_use, including for obvious fixes."
- 1 Escape hatch bullet in CRITICAL RULE section: tightened.

plan-eng-review, plan-design-review, plan-devex-review (1 site each):
- Each template's Escape hatch bullet tightened to match the new CEO wording,
  adapted for each review's domain (issue/gap, decision/design/DX alternatives).

After regeneration: rg "don't waste a question" returns 0 across all
*SKILL.md.tmpl and *SKILL.md files. "zero findings, state" wording
present 16 times (matches prior count of escape-hatch sites).

bun test passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(preamble): upgrade AskUserQuestion format to Pros/Cons decision brief

Part 4 of 4 (plan: ~/.claude/plans/system-instruction-you-are-working-polymorphic-twilight.md).

Every AskUserQuestion now renders as a decision brief, not a bullet list:
D-numbered header, ELI10, Stakes-if-we-pick-wrong, Recommendation, Pros/Cons
with ✅/❌ markers per option, closing Net: tradeoff synthesis.

scripts/resolvers/preamble/generate-ask-user-format.ts
- Full rewrite. Preserves prior rules (Re-ground, ELI10, Recommend,
  Completeness, Options) and adds:
  - D-numbering per skill invocation (model-level, not runtime state)
  - Stakes line (pain avoided / capability unlocked / consequence named)
  - Pros/Cons block with min 2 ✅ + 1 ❌ per option, min 40 chars/bullet
  - Hard-stop escape: "✅ No cons — this is a hard-stop choice" for
    genuine one-sided choices (destructive-action confirmations)
  - Neutral-posture handling (CT1-compliant): (recommended) label
    STAYS on default option to preserve AUTO_DECIDE contract; neutrality
    expressed as prose in Recommendation line only
  - Net line closes the decision with a one-sentence tradeoff frame
  - Rule 11: tool_use mandate (prose "Question:" blocks don't count)
  - Self-check list before emitting

test/skill-validation.test.ts
- Update format assertions to check for new Pros/Cons tokens
  (Pros / cons:, Recommendation: <choice>, Net:, ELI10, Stakes if we
  pick wrong:, ✅, ❌) across all tier-2+ skills
- Old "RECOMMENDATION: Choose" expectation removed (the new format uses
  mixed-case "Recommendation:" with no literal "Choose")

test/skill-e2e-plan-format.test.ts
- Add v1.7.0.0 format token regexes (PROS_CONS_HEADER_RE, PRO_BULLET_RE,
  CON_BULLET_RE, NET_LINE_RE, D_NUMBER_RE, STAKES_RE)
- Existing RECOMMENDATION_RE loosened to accept mixed-case "Recommendation:"
  (canonical v1.7.0.0 form) alongside all-caps (legacy). Tests are
  additive — the strict new-format gate is the upcoming cadence eval.

Regenerated 30 SKILL.md files via bun run gen:skill-docs.

Verified:
- bun test: 319 pass (1 pre-existing security-bench fixture oversize
  failure on main, unrelated — confirmed via git stash test on main HEAD)
- New format tokens render in all tier-2+ skills (plan-ceo-review,
  plan-eng-review, ship, office-hours verified)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test: gate-tier units + periodic Pros/Cons evals for AskUserQuestion format

Part 3 of 4 (plan: ~/.claude/plans/system-instruction-you-are-working-polymorphic-twilight.md).

Gate-tier (E1, free, runs on every `bun test`):

test/preamble-compose.test.ts — pins the composition order
  Asserts AskUserQuestion Format section renders BEFORE Model-Specific
  Behavioral Patch in tier-≥2 preamble output. Covers claude default,
  opus-4-7 overlay, tier 2/3, and codex host. Catches any future edit
  to scripts/resolvers/preamble.ts that silently reverts the order.

test/resolver-ask-user-format.test.ts — pins the Pros/Cons contract
  14 assertions against generateAskUserFormat output: D<N>, ELI10,
  Stakes if we pick wrong:, Recommendation: <choice>, Pros / cons:,
  ✅/❌ markers, min 2 pros + 1 con rules, hard-stop escape exact
  phrase, neutral-posture CT1 rule ((recommended) label preserved for
  AUTO_DECIDE), Completeness coverage-vs-kind, tool_use mandate
  (rule 11), self-check list, D-numbering model-level caveat.

test/model-overlay-opus-4-7.test.ts — pins the pacing directive
  Asserts raw overlay file + resolved overlay output contain "Pace
  questions to the skill" and NOT "Batch your questions". Verifies
  INHERIT:claude chain still works (Todo-list, subordination wrapper),
  Fan out / Effort-match / Literal interpretation nudges preserved.
  Also asserts claude base overlay does NOT carry the Opus-specific
  pacing directive (no cross-contamination).

Periodic-tier (E2, Opus-dependent, ~$1-2/run):

test/skill-e2e-plan-prosons.test.ts — 4 cases extending v1.6.3.0 harness
  1. Format positive — every token present when plan has real tradeoff
  2. Hard-stop NEGATIVE — plan with genuine tradeoff must NOT dodge to
     "No cons — hard-stop choice" escape
  3. Neutral-posture NEGATIVE — plan where one option dominates must emit
     (recommended) label + "because <reason>", must NOT dodge to
     "taste call" / "no preference"
  4. Hard-stop POSITIVE — destructive-action plan may legitimately use
     the hard-stop escape

test/helpers/touchfiles.ts — entries for all new eval cases
  Dependencies: overlay, preamble.ts, generate-ask-user-format.ts, and
  the 4 plan-review templates. Diff-based selection triggers the evals
  whenever those files change. Also added entries for 7 expanded-coverage
  cases (ship, office-hours, investigate, qa, review, design-review,
  document-release) — test cases will land in follow-up PRs per skill.

Follow-ups noted in test file header:
- True multi-turn cadence eval (3 findings → 3 distinct asks) — current
  harness captures one $OUT_FILE per session; multi-turn capture needs
  new harness support.
- Expanded-coverage test cases for the 7 non-plan-review skills.

Verified:
- bun test: 349 pass (30 new + 319 baseline), 1 pre-existing security-bench
  oversize failure on main (unrelated, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test: regenerate golden fixtures + update ELI10 phrase check for v1.7.0.0

Pros/Cons format rewrite (6b99df9d) changed the resolver output across all
tier-2+ SKILL.md files. Three golden-file regression tests in
test/host-config.test.ts and one phrase-check test in test/gen-skill-docs.test.ts
were failing as expected.

- test/fixtures/golden/claude-ship-SKILL.md
- test/fixtures/golden/codex-ship-SKILL.md
- test/fixtures/golden/factory-ship-SKILL.md
  Regenerated via `bun run gen:skill-docs --host all` + cp into fixtures.

- test/gen-skill-docs.test.ts line 244: rename test from "ELI16 simplification
  rules" to "ELI10 simplification rules" and match the new phrase pattern.
  v1.7.0.0 uses "ELI10 (ALWAYS)" rather than legacy "Simplify (ELI10, ALWAYS)".

bun test: 744 pass, 1 fail (pre-existing security-bench fixture oversize,
unrelated to this branch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* v1.7.0.0: plan reviews walk you through each issue with Pros/Cons

Restores AskUserQuestion cadence on Opus 4.7 (v1.6.4.0 regression) and
upgrades the format to a numbered decision brief — D<N> header, ELI10,
Stakes, Recommendation, per-option ✅/❌ bullets, Net: closing line.

Fix: composition reorder + overlay rewrite + 16-site escape-hatch hardening
across the 4 plan-review templates.
Feature: Pros/Cons format in the preamble resolver, inherited by every
tier-2+ skill automatically.

30 new gate-tier unit tests pin the format contract (runs in <100ms, $0).
4 new periodic-tier eval cases defend against escape-hatch abuse
(2 positive, 2 negative). Golden fixtures regenerated.

CEO + Eng + Codex reviews completed. 5 of 8 Codex findings incorporated;
CT2 (16 sites, not 31) and CT1 (AUTO_DECIDE contract break) were
load-bearing catches the primary reviews missed.

bun test: 774 pass, 1 fail (pre-existing security-bench oversize, unrelated).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* v1.10.0.0: bump VERSION (was v1.7.0.0, align with branch discipline)

Per user direction — jumping to 1.10.0.0 for versioning alignment.
No functional changes from the prior ship commit (5f038ab7). The
regression fix + Pros/Cons format are identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:25:34 -07:00