Skip to content

Test-suite executions consume 40% of a cloud implement run's wall clock, and some re-derive output the run already had #1923

Description

@The01Geek

Problem Statement

Test-suite executions are the largest single line item in a cloud implement run's wall clock, and some of them buy nothing. Across the five most recent cloud implement runs (measured 2026-08-24 from their Actions transcripts: runs 32774995051, 32775237213, 32777884173, 32781679682, 32781839046), 13 suite executions consumed 94.5 minutes — 40.6% of all agent wall clock.

Three of those 13 (18.3 min) ran on a tree with zero changes since the previous execution. They were launched purely to see output the previous execution had already produced and then discarded through a pipe. The agents' own rationales, quoted from the transcripts: "Let me get explicit PASS evidence for the #1911 assertions." (6.1 min), "Let me get the actual FAIL lines to diagnose." (6.2 min), "Let me re-run monolith capturing the full recap to a file" (6.0 min). Two further executions (12.8 min) were spent characterizing assertions the agents concluded were environmental. Two of the five runs died at ~71 minutes on an expired credential; one of those had spent 12.3 minutes on the zero-change re-runs.

This issue covers six separable defects that each produce or permit an avoidable suite execution, or misprice one. They are independent and may ship as separate PRs.

Current Behavior

Environment fact: items 1–4 and 6 happen regardless of environment. Item 5's failures are environment-dependent and that dependence is the defect.

Item 1 — the shard runner is the only one of the three that never names its retained log

This is a consistency gap, not a missing convention. Two of the three runners already announce where their output was retained; the third does not, so an agent that pipes its output away has no way to get it back except by re-executing.

  • Verified: lib/test/run-parallel.sh prints its retained-log root and, on failure, directs the reader away from re-running: it contains "run-parallel: retained logs: %s" and "aggregate FAILED — read the retained logs above rather than re-running".
  • Verified: lib/test/run-module.sh names its own retained log in its summary block: it contains "printf 'Log: %s\n'".
    Observed live on 2026-08-24: running that module runner on phase2-durability-checkpoint printed its pass/fail summary followed by a Log: line pointing under .prflow/tmp/test-module-logs/.
  • Verified: lib/test/run-shard.sh retains its full output at .prflow/tmp/shard-tally//log.txt and echoes it, but prints no path line; the echo is the file's only use of it, introduced by the comment "# Echo the captured log so the shard job's own log carries the detail too."
  • Verified: CLAUDE.md tells the cloud tier to consume that echo through a tail pipe — "rather than taking its whole echoed log into context" — which discards everything above the tail window with no stated way to recover it.

Nothing under skills/ or agents/ mentions the retained log at all, so a consumer repository inherits none of this. Re-derive: grep -rn "shard-tally|retained log|run-shard" skills/ agents/ .prflow/prompt-extensions/ returns nothing (checked 2026-08-24).

Item 2 — the single flight does not cover a shard run

  • Verified: CLAUDE.md scopes the consult obligation to a full-suite relaunch and points only at the coordinator's logs: "before any full-suite relaunch" and "and the retained shard logs instead of relaunching".

A mid-iteration shard run is therefore outside the obligation, and the flight suppressed none of the three zero-change re-runs above. scripts/verification-flight.py already implements lease expiry, checkout-drift-to-stale, and checkout_verified, and it correctly does not suppress a post-edit relaunch — the gap is the scope of the prose, not the helper.

Coupled mirror — the single-flight coordination paragraph exists in FOUR places and all four must move together: skills/review-and-fix/references/fixing.md (Step 3, item 4), skills/implement/phases/phase-3-ac-gate.md (§3.4), skills/implement/phases/phase-4-documentation.md (§4.3), and CLAUDE.md.

Item 3 — the fix loop's per-iteration test run has no narrowing clause

  • Verified: skills/review-and-fix/references/fixing.md item 4 opens "Run tests after all fixes. Check CLAUDE.md, README, or project configuration for the project's test and lint commands." — with no instruction to narrow.
  • Verified: skills/implement/phases/phase-2-sweeps-quality.md already carries the clause item 4 lacks: "Run the narrowest covering test before the broadest."

The fix loop runs that step once per iteration, up to max_iterations (default 5 in .prflow/config.schema.json), plus the Step 2.6 shadow and the fix-delta gate's inner attempts, which skills/review-and-fix/references/fix-delta-gate.md states are "not counted toward the $MAX_ITERS cap". .prflow/prompt-extensions/review-and-fix.md patches this repository-locally, but a prompt extension ships to no consumer, so every consumer gets the unnarrowed rule. Measured 2026-08-24: across the five runs, lib/test/run-module.sh was invoked zero times — every one of the 13 executions was a monolith shard or the whole-suite coordinator.

Item 4 — two loop-exit whole-suite triggers are not caller-scoped

  • Verified: skills/review-and-fix/references/loop-exit.md carries a base-merge trigger — "Loop-exit suite rule. Re-run the project test suite at Loop Exit whenever a Checkpoint-3 merge landed after the loop's last suite run" — which fires on any recorded base_checkpoint.token equal to UPDATED and fails closed on an absent comparand.
  • Verified: skills/review-and-fix/references/loop-exit.md carries a second, independent trigger: "Identity-keyed refresh (recovery arm)." — one suite re-run whenever claim-time candidate identity differs from the verification record's.
  • Verified: .prflow/prompt-extensions/review-and-fix.md scopes only the loop's terminal gate by caller — "Whose terminal the loop's gate is depends on the caller." — and states "the obligation is owned exactly once by Phase 4.3."

The two triggers above are not the terminal gate, so they fire regardless of caller. Inside the implement command they can therefore double-pay against Phase 4.3's exactly-once whole-suite obligation.

Item 5 — flaky refresher assertions mandate an expensive characterization loop

The credential-refresher liveness arms (#487 arm13, #491 arm20b, #1882 arm1882k, all resident in lib/test/run.sh) go RED only after repeated heavy monolith runs in one sandbox. Measured 2026-08-24: two executions totalling 12.8 minutes were spent characterizing them, and both agents concluded the failures were environmental.

  • Verified: CLAUDE.md forbids treating such a red as known-flake: "There is no known-flake set — every FAIL is a real failure to diagnose."
  • Verified: CLAUDE.md already names the remedy: "A red assertion that reproduces only under pool saturation is a defect in that assertion's slack budget: fix the assertion, do not re-run the suite hoping for green."

The rule is correct and should not be weakened; the assertions are what must change. A separate credential-refresher investigation is in flight — no open issue for it was found on 2026-08-24 (searches: refresher, credential expired token run died) — so check for one before assuming these fixes are independent.

Item 6 — CLAUDE.md prices the suite with measurements that have already rotted

The routing rule that sends a run.sh-resident surface to the monolith shard is justified by a dated pair of runtimes. Both are now wrong, and the rule they support does not depend on their exact values.

  • Verified: CLAUDE.md justifies that routing rule with a dated measurement: "measured on the cloud implement tier at ~10.5 min against ~3.9 min (2026-08-04)".
  • Verified: CLAUDE.md already states the convention such a figure violates: "Prefer generated evidence over exact checked-in numbers".

Measured 2026-08-24 on the same tier, from the transcripts of the five runs above: the coordinator took 16.0 minutes and the monolith shard 5.9–12.6 minutes. Both checked-in figures are low by roughly 1.6x after twenty days, while the qualitative claim they support — that the coordinator meaningfully exceeds one shard on that tier — still holds and needs no number. The same rot applies to any other measured duration CLAUDE.md states for a suite command. A duration a run must literally pass as a command operand is not a measurement and is not in scope here.

Desired Behavior

Every test-suite runner names the log it retained, and an agent that needs more of a run's output re-reads that log instead of re-executing. The single-flight consult obligation covers every suite execution and every retained log, not only a whole-suite relaunch. The fix loop narrows its per-iteration test run the way the implement phase already does, in the shipped body a consumer receives. The two loop-exit whole-suite triggers are caller-scoped on the axis the run already has. The three refresher assertions pass under sandbox contention. CLAUDE.md prices the suite with claims that stay true as the suite grows, rather than with runtimes that rot.

User Impact

A consumer running the implement command pays for suite executions that produce no new information, on the tier where a run can also die on an expired credential mid-way. Recovering an already-produced result costs a re-execution rather than a file read.

Technical Context

Scope note: The files and details below are the known starting points, not the full list. Before implementing, trace the change through the codebase to find every affected call site, consumer, and layer — this issue maps the work, it does not bound it.

  • Relevant Classes/Files — lib/test/run-shard.sh, lib/test/run-parallel.sh, lib/test/run-module.sh, scripts/verification-flight.py, skills/review-and-fix/references/fixing.md, skills/review-and-fix/references/loop-exit.md, skills/implement/phases/phase-3-ac-gate.md, skills/implement/phases/phase-4-documentation.md, .prflow/prompt-extensions/review-and-fix.md, CLAUDE.md, lib/test/run.sh.
  • Architecture Alignment — items 1–4 are prose and helper-output changes on existing surfaces; the caller axis item 4 needs already exists (the focused-selection sink routes on the issue workpad versus iter-N.json).
  • Cross-layer Impact — shell test runners, shipped skill bodies, repository memory, and one repo-local prompt extension. Item 6 touches CLAUDE.md only.

Out of scope, stated as context only. lib/test/modules/coverage-map.json records 469 entries under run_sh_blocks — assertion blocks resident in lib/test/run.sh with no covering focused module — so for those surfaces the narrowest covering test is the roughly six-minute monolith shard. That is a cost-per-execution problem, not an execution-count problem, and belongs in its own issue.

Acceptance Criteria

  • lib/test/run-shard.sh prints a line naming the absolute path of the log it retained, on both its passing and failing exits.
  • CLAUDE.md's tail-pipe bullet states that the tail read is the first read, that every later slice of that run's output comes from the retained log, and that re-executing a suite to obtain output already retained is forbidden.
  • A shipped body under skills/ tells the agent that a suite runner retains its output and that further output is re-read from the retained log rather than obtained by re-executing.
  • The single-flight consult obligation in all four copies — skills/review-and-fix/references/fixing.md, skills/implement/phases/phase-3-ac-gate.md, skills/implement/phases/phase-4-documentation.md, and CLAUDE.md — is scoped to any suite execution and any retained log, not only a full-suite relaunch, and the four copies remain consistent with each other after the change.
  • skills/review-and-fix/references/fixing.md item 4 instructs the run to execute the narrowest covering test before the broadest, in the shipped body rather than in a prompt extension.
  • The loop-exit base-merge trigger and the identity-keyed refresh trigger in skills/review-and-fix/references/loop-exit.md each state that they do not fire when the loop's caller is the implement command, and each still fires when the caller cannot be established.
  • Item 4's caller scoping introduces no new flag, field, or counter, and reads the same caller axis the focused-selection sink already routes on.
  • The Keep writer-job push and gh credentials fresh past the App token's 60-minute lifetime #487 arm13, Keep writer-job push and gh credentials fresh past the App token's 60-minute lifetime #491 arm20b and Sign the credential refresher's JWT without openssl process substitution so long cloud runs keep GitHub access on non-Linux runners #1882 arm1882k assertions in lib/test/run.sh pass when the suite is run repeatedly in one sandbox, and each change is to the assertion's own slack budget rather than to CLAUDE.md's no-known-flake rule.
  • CLAUDE.md's no-known-flake rule and its slack-budget remedy are both present and unweakened after the change.
  • CLAUDE.md states no measured wall-clock duration for a test-suite command, the monolith-shard-versus-coordinator comparison included; each is either dropped in favour of the qualitative claim it supported, or replaced by a pointer to where the figure can be measured.
  • Every duration CLAUDE.md retains is one a run passes verbatim as a command operand, or one that names a configuration setting owned by another file; a configuration duration is referred to by its setting name rather than restated as a literal, so the setting's own file stays the single source.
  • The full test suite passes and shellcheck reports no warning on every changed shell file.

Implementation Notes

  • Approach — mirror lib/test/run-parallel.sh's and lib/test/run-module.sh's existing retained-log announcement into lib/test/run-shard.sh, then widen the three prose scopes (tail-pipe consumption, single-flight coverage, per-iteration narrowing) and caller-scope the two loop-exit triggers. Item 5 is separate work on three assertions.
  • Relevant files — likely lib/test/run-shard.sh, CLAUDE.md, skills/review-and-fix/references/fixing.md, skills/review-and-fix/references/loop-exit.md, skills/implement/phases/phase-3-ac-gate.md, skills/implement/phases/phase-4-documentation.md, and plausibly .prflow/prompt-extensions/review-and-fix.md (whose repo-local patch item 3 supersedes) and lib/test/run.sh plus its refresher fixtures.
  • Code Patterns — lib/test/run-parallel.sh's terminal printf block is the pattern for item 1; the focused-selection sink's existing caller axis is the pattern for item 4.
  • Testing Strategy — a module-level assertion that lib/test/run-shard.sh's output names its retained log on both a passing and a failing shard; assertions that each of the four single-flight copies carries the widened scope; for item 5, run the three arms repeatedly in one sandbox and prove they stay green, and prove each amended assertion still goes RED against a mutated copy of the behaviour it pins.
  • Documentation Needed — CLAUDE.md is edited by items 1, 2 and 5 as part of the change itself; no separate documentation deliverable. none.
  • Potential Gotchas — the five items are separable and may ship as separate PRs, but items 1 and 2 both edit CLAUDE.md and item 2 edits four coupled copies, so a partial edit leaves the copies disagreeing. Item 5 must not be "fixed" by adding a known-flake exemption.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions