Skip to content

feat: add a whole-run spend audit to the postmortem - #133

Open
tbrownio wants to merge 6 commits into
mainfrom
fierce-snarl
Open

feat: add a whole-run spend audit to the postmortem#133
tbrownio wants to merge 6 commits into
mainfrom
fierce-snarl

Conversation

@tbrownio

@tbrownio tbrownio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

What — Every postmortem now judges how the run spent its tokens, not only its wall-clock: a spend audit over everything that ran, giving each timing-table row a useful | marginal | waste verdict.

Why — The postmortem already priced every run (the per-step timing table carries tokens and est. cost per row), but its judgment of that spend was scoped to review passes alone — "a pass that found nothing was pure spend." Nothing swept the rest: research dispatches, planning, implementer retries, verifiers, and the overseer's own turns. A research report nobody consumed, or a verifier re-proving the proven, slipped through unremarked, and there was no home for token-efficiency improvement proposals.

How — Additive instruction edits to the three surfaces where the existing spend judgment already lives:

File What it gains
references/run-operations-analysis.md the computation rule — the per-row verdict, the three mechanical main-loop stats, the follow-the-evidence escalation limit
claude/skills/postmortem/references/postmortem.md the place in the report — the body must name wasteful spend across all components and the efficiency change it supports
claude/skills/postmortem/SKILL.md the criteria — step 2 requires the per-dispatch verdict; step 6 accepts token-efficiency findings as proposal targets

Two design choices carry the weight:

  • The verdict criterion splits by the work's nature. Production work (research meant to feed the plan, implementation, exploration, retries) is judged by downstream consumption — name what consumed the output, or name that nothing did. Assurance work (verifiers, review passes, research that correctly concluded "nothing here") leaves no downstream reference by design, so it is judged by whether its question needed answering at this zone — explicitly never by citation. A uniform "no reference = waste" rule would have systematically mislabelled negative-result assurance and fed proposals that strip verification the pipeline needs.
  • The main loop is mechanical, and reported only on a flag. Three stats — duplicate reads, top-spend turns, cache-read volume — computed from the already-parsed JSONL without loading transcript content, and printed only when one trips a threshold (a file read 3+ times, a turn over ~15% of run output, cache reads over ~95% of input). A clean run gets one line saying nothing flagged, not a stat dump. Semantic judgment happens only on a window a stat flagged. Otherwise the postmortem would itself become the wasteful run.

Done means: a postmortem run after this change gives every dispatch and pipeline step a useful | marginal | waste verdict with evidence, computes the three main-loop stats, and names the token-efficiency changes the wasteful spend supports — while staying report-only and never becoming a gate.

Visual overview

Before and after: the spend audit widens the postmortem's judgment gate

Before, six kinds of timing-table row reach the postmortem and only one — review passes — passes through any spend judgment at all; the other five flow straight through unjudged, and the main loop is never measured. After, the same rows all pass through the audit, the main loop arrives with three scripted stats, and every row leaves with a verdict. The gate didn't move — it widened.

Note the criterion split at the bottom of the diagram: it is the reason this isn't simply "no citation = waste." Assurance work leaves no citation by design, so that rule would have condemned exactly the verification the pipeline depends on.

No screenshots: this change has no user-visible surface — the only consumers of these files are agents reading instructions. .excalidraw source in ./tmp/postmortem-spend-audit/refs/.

User journeys

Linear, single-actor, no branches. The postmortem author's journey: an agent runs /postmortem on a completed /do run → step 2 scripts the transcripts as before, and now also assigns each timing-table row a useful | marginal | waste verdict and computes the three main-loop stats → the Run operations section of the written report names the wasteful and marginal spend with its evidence → step 6 proposes the token-efficiency changes that spend supports, alongside the stall-removing operational change. Nothing is applied; nothing gates.

There is no runtime and no user-facing surface, so there is no branch to map.

Verification

Verified by inspection by independent Codex backend-verifier dispatches (docs-only change — no executable surface; none of the six rubrics in .references/rubrics/ covers a docs change, so the ACs alone gate). The final-state verification ran after the last fix landed; full quoted evidence in the QA comment below.

  • AC1 — ✅ references/run-operations-analysis.md:87-96 carries all four elements: one useful | marginal | waste verdict per row; production judged by downstream consumption — "name what consumed the output, or that nothing did"; assurance judged by whether its question "needed answering at this zone, never by citation"; and "A de-escalation proposal this feeds still needs yield evidence per .references/zones.md, one change at a time."
  • AC2 — ✅ :97-105"script three stats from the already-parsed JSONL without loading transcript content — duplicate file reads, top-spend turns, and cache-read volume"; "Report them only when one trips a threshold… a clean run gets one line saying nothing flagged, never a stat dump"; then "follow the evidence — judge main-loop behavior only inside a window a stat flagged, never by sweeping the transcript." The reference script at :106-148 implements all three and prints only the tripped ones.
  • AC3 — ✅ claude/skills/postmortem/references/postmortem.md:40-41"name the wasteful and marginal spend across ALL components — dispatches, steps, and the main loop, not just review passes — and the token-efficiency change(s) it supports."
  • AC4 — ✅ claude/skills/postmortem/SKILL.md:80-81"Every dispatch and pipeline step carries a useful | marginal | waste verdict with its evidence, and the main-loop mechanical stats are computed." :157"Token-efficiency findings from the spend audit are equally valid proposal targets."
  • AC5 — ✅ all 31 added lines audited; the only added repo-internal path is consumer-relative (.references/zones.md), and no consumer-specific name, path, or ID appears. The dcouple/orchestra mention in SKILL.md is pre-existing, not added here.

Substance3 files changed, 71 insertions(+), 37 deletions(-) — the deletions are the old reference script and the over-specified first draft, both replaced. Two deletions are deliberate narrowings: both pre-existing "a pass that found nothing was pure spend" assertions were narrowed to the zone-necessity criterion, because leaving them intact created a direct contradiction with the new rule (see review history below). The verifier confirmed both amendments keep the overdone/right-sized/underdone judgment, the dial selection, the token-per-pass signal, and the zones-table tuning intact. git diff --check clean.

Report-only confirmedSKILL.md:28-30 ("This skill changes nothing… presented for the human to approve, not applied") and :159-165 ("Do not apply any of them"; "this step is a report, never a gate") verified uncontradicted by the new text.

Gates cleared — plan review 1/1: 0 Must Fix, Approve (2 Should Fixes on plan repo-truth accuracy, folded in and independently re-verified). Diff review ran 3 passes after a one-notch zone escalation (2→1) taken because pass 1 surfaced a direct instruction contradiction; passes 1–3 found 2, 2, and 1 Must Fix respectively, all fixed.

Then the text was cut roughly in half (the spend-audit bullet went 40 lines → 17) — see the last three commits. Each review finding was individually correct, but together they had ratcheted a rule into a specification: path normalization, token-class arithmetic, ranking cardinality, TTL fallbacks, lower-bound labelling. That is a real defect in a document whose own thesis is that the postmortem must not become the wasteful run. The scripting minutiae came out; every AC element stayed, re-checked line by line above. A duplicated requirement in the report template (the whole-run instruction appeared in both the Run operations block and the dial record) also went. Build gate: not applicable — markdown only, no CI workflows in this repo, daemon/ untouched.

Manual tests

The real proof is running the changed instructions and seeing the audit appear. Highest-value first:

Important (behavior of the instructions):

  • Run /postmortem on any completed /do run → the written Run operations section assigns every dispatch and pipeline step a useful | marginal | waste verdict, each with its evidence. — left to human: requires invoking the postmortem skill in an agent session, which a sub-agent may not do
  • Same run → the three main-loop mechanical stats (duplicate reads, top-spend turns, cache-read volume) are computed and reported. — left to human: same reason
  • Same run → the postmortem names the wasteful/marginal spend and the token-efficiency change(s) it supports, and step 6 lists at least one token-efficiency proposal when the audit found waste. — left to human: same reason
  • A run containing a verifier or review pass that legitimately found nothing → that pass is not labelled waste purely for lack of a downstream citation; its verdict reasons from whether the question needed answering at the zone. — left to human: same reason
  • The postmortem does not balloon: no full-transcript semantic sweep occurs; any semantic dig is confined to a window a mechanical stat flagged. — left to human: same reason

Nice (hygiene):

  • scripts/sync.sh <consumer-repo> still syncs the three edited files cleanly, and the synced text contains no consumer-specific name or path.

Areas not affected: the timing table's existing columns, the dial-record contract, references/zones.md, the wrap-up format, the timeline HTML template and its render script, the daemon/ package, and every other skill.

A note for whoever runs the five human items: this PR's own /do run is itself a good subject — it has research, planning, four implementer rounds, three review passes, and two verifier passes, including assurance work that correctly found things and a final pass whose finding was real. The ops-only postmortem posted on this PR is the first artifact produced under the new instructions.

QA results

1 of 6 manual items executed, 5 left to the human. The one command-shaped item passed: scripts/sync.sh into a throwaway git init target synced all three edited files byte-identical, a second run produced zero further change (idempotent as documented), and the temp target was deleted. The five remaining items each require invoking /postmortem in an agent session — something a sub-agent is forbidden to do — so they are genuinely human work, not skipped work. All five acceptance criteria were re-proven against the then-final commit, and re-checked by hand after each of the three simplification commits that followed. No bug was found by the QA pass. Proof in the comment below.

Deploy notes

None. The deploy-notes scan over the run's diff found no schema/migration, env var/secret, infra/CI, new dependency, or one-time script/backfill. These are markdown instruction files consumed by agents; they take effect for consumer repos on their next update-skills sync, which is that repo's own PR flow and is deliberately not triggered here (per AGENTS.md Boundaries).

Residual risks

  • One fix landed after the last review pass. The review loop hit its cap (3 passes at the escalated zone) with one Must Fix outstanding — the requirement that a fallback-priced turn cost be labelled a lower-bound estimate. It was fixed in d454551 and re-verified by the QA verifier against the final state, but it was not seen by a diff reviewer. It is a two-line disclosure clause with no behavioral reach; flagging it so the human reviewer knows exactly which hunk carries less review than the rest.
  • Instruction adherence is not mechanically enforceable. Nothing can assert at runtime that a postmortem actually assigned verdicts — the guarantee is the step-2 success criteria, same as every other criterion in the skill. Accepted: this is how the whole skill system works.
  • Verdict judgment remains subjective at the margin. The three verdicts now partition explicitly (full/proportionate value; partial or disproportionate; unconsumed or unnecessary), and the fully-consumed-but-overpriced case is assigned to marginal — but the boundaries are still judgment. The de-escalation gate means a mistaken waste verdict cannot by itself strip verification: zones.md still requires yield evidence, one change at a time.
  • The simplification traded prose determinism for a working script, deliberately. The trimmed text no longer spells out path normalization, token-class arithmetic, or cache-write TTL selection. Reviewers had raised each as real, and in prose they were. The resolution: the reference script now implements all three stats, so the determinism lives in code that runs rather than in prose two agents must interpret identically. Using output tokens as the spend proxy also drops the TTL question entirely — output dominates cost when cache reads bill at 0.1×. Verified against two real session transcripts.
  • Thresholds are a first guess. 3+ reads, 15% of run output, 95% cache-read share are calibrated against a handful of runs, not tuned. Expect to move them once a few postmortems report under the new rule — they are one-line changes in the script.
  • The audit still adds work to every postmortem. Bounded by design (mechanical-stats default plus the follow-the-evidence limit), but not free. Watch it on the next few runs.

Closes #132

@tbrownio

tbrownio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

QA drive — evidence

Ran after the review loop closed, against the final commit (d454551), not an earlier revision. Docs-only change: no browser, no app, no captures — the evidence is quoted text and command output.

✅ Passed automated

Manual-test item — scripts/sync.sh still syncs cleanly (idempotent, repo-agnostic)

Executed against a throwaway git init target outside the repo. No real consumer repo was touched (AGENTS.md Boundaries).

TEMP_TARGET=/tmp/orchestra-sync-verify.32FjtY
Initialized empty Git repository in /private/tmp/orchestra-sync-verify.32FjtY/.git/

FIRST_SYNC_OUTPUT_BEGIN
synced orchestra -> /tmp/orchestra-sync-verify.32FjtY
FIRST_SYNC_EXIT=0
FIRST_SYNC_OUTPUT_END

ARRIVED_AND_BYTE_IDENTICAL .references/run-operations-analysis.md <= references/run-operations-analysis.md
ARRIVED_AND_BYTE_IDENTICAL .claude/skills/postmortem/references/postmortem.md <= claude/skills/postmortem/references/postmortem.md
ARRIVED_AND_BYTE_IDENTICAL .claude/skills/postmortem/SKILL.md <= claude/skills/postmortem/SKILL.md

SECOND_SYNC_EXIT=0
SECOND_RUN_ZERO_FURTHER_CHANGE hashes_identical=yes

SYNC_COPY_MATCHES_AUDITED_CANONICAL (all three files)
TEMP_TARGET_DELETED=yes path=/tmp/orchestra-sync-verify.32FjtY

All three edited files arrive byte-identical, the second run is a no-op as documented, and the target was deleted.

Acceptance criteria — re-proven on the final state

AC1 — verdict for every row, criterion split, de-escalation gated ✅

references/run-operations-analysis.md:87-100"Spend audit — judge every timing-table row. Give every pipeline step and dispatch exactly one useful | marginal | waste verdict"; production work must "name what consumed the output or name that nothing did"; assurance work judged "never by citation" and by whether its "question needed answering".

:125-126"Any de-escalation proposal… still requires yield evidence per .references/zones.md."

All four required elements present. The "never by citation" clause is the one that keeps a correct negative result from being mislabelled waste.

AC2 — three mechanical stats, no transcript content, digs bounded ✅

references/run-operations-analysis.md:101-120 — stats computed "from the already-parsed JSONL without loading transcript content": Duplicate reads (:103), Top-spend turns (:109), Cache-read volume (:117).

:121-124"only… the transcript window a mechanical stat flagged, never by sweeping the full transcript."

AC3 — whole-run waste named in the report ✅

claude/skills/postmortem/references/postmortem.md:40-42"name wasteful and marginal spend across all components — dispatches, pipeline steps, and the main loop, not only review passes" plus the "proposed token-efficiency change(s)" it supports. :71-73 repeats the whole-run requirement in the dial record.

AC4 — success criteria and proposal targets ✅

claude/skills/postmortem/SKILL.md:75-81 — the audit covers "every dispatch, pipeline step, and the main loop"; "Every dispatch and pipeline step carries a useful | marginal | waste verdict with its evidence."

:157"Token-efficiency findings from the spend audit are equally valid proposal targets."

AC5 — repo-agnostic, consumer-relative paths ✅
ADDED_LINE_COUNT=58
TARGETED_SCAN_RESULT=no_absolute_consumer_path_name_or_id
PREEXISTING_EXCEPTION_DIFF_CHECK: EXCEPTION_WAS_ADDED=no

The only added repo-internal path is consumer-relative — .references/zones.md at :125-126. The dcouple/orchestra mention at SKILL.md:150 was confirmed pre-existing, not added here.

Additive substance + report-only boundary
git diff --stat origin/main...HEAD
3 files changed, 58 insertions(+), 2 deletions(-)

git diff --numstat origin/main...HEAD
6  1  claude/skills/postmortem/SKILL.md
8  1  claude/skills/postmortem/references/postmortem.md
44 0  references/run-operations-analysis.md

The 2 deletions are the two deliberately-narrowed "pure spend" assertions. The verifier confirmed both amendments retain the overdone/right-sized/underdone judgment, the dial selection, the token-per-pass signal, and the zones-table tuning — nothing gutted.

Report-only intact: SKILL.md:28-30 "This skill changes nothing… presented for the human to approve, not applied"; :159-165 "Do not apply any of them", "this step is a report, never a gate".

git status --short after verification: empty — the verification modified nothing.

⛔ Remaining for the human

Five Manual-test items, all unchecked in the body. Each requires invoking /postmortem in an agent session, which a sub-agent is forbidden to do — so these are genuinely human work rather than skipped work:

  1. Verdicts appear for every dispatch and pipeline step, each with evidence.
  2. The three main-loop mechanical stats are computed and reported.
  3. Wasteful spend is named and token-efficiency proposals follow from it.
  4. A pass that legitimately found nothing is not labelled waste for lack of a citation.
  5. The postmortem doesn't balloon — no full-transcript semantic sweep.

Convenient subject: this PR's own run. It has research, planning, four implementer rounds, three review passes, and two verifier passes — including assurance work that correctly found real defects. The ops-only postmortem comment on this PR is the first artifact produced under the new instructions.

Bugs found by this pass

None.

@tbrownio

tbrownio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

type: wrap-up-report
item: postmortem-spend-audit
pr: #133

Wrap-Up Report — postmortem-spend-audit

What was built

Every postmortem now judges how a run spent its tokens, not only its wall-clock. Three additive markdown instruction edits give the spend audit a computation rule, a place in the report, and success criteria plus a proposal target:

  • references/run-operations-analysis.md — a Spend audit bullet: every timing-table row carries exactly one useful | marginal | waste verdict. Production work (research meant to feed the plan, implementation, exploration, retries) is judged by downstream consumption — name what consumed the output, or name that nothing did. Assurance work (verifiers, review passes, research that correctly concluded "nothing here") is judged by whether its question needed answering at this zone, never by citation, so a correct negative result is not waste. Main-loop coverage is three scripted mechanical stats — duplicate reads, top-spend turns, cache-read volume — computed without loading transcript content, with semantic digs limited to windows a stat flagged. De-escalation proposals the audit feeds still require yield evidence per zones.md, one change at a time.
  • claude/skills/postmortem/references/postmortem.md — the report body must name wasteful and marginal spend across all components, not only review passes, with per-verdict evidence and the token-efficiency change(s) it supports.
  • claude/skills/postmortem/SKILL.md — step 2's success criteria require the per-dispatch verdict and the main-loop stats; step 6 accepts token-efficiency findings as proposal targets.

This matches the item's intent exactly: the gap was that spend judgment existed only for review passes, leaving research nobody consumed, verifiers re-proving the proven, and the overseer's own turns entirely unjudged. The postmortem stays report-only throughout.

Verification evidence

Docs-only change — no executable surface, so every criterion is proven by inspection. Two independent Codex backend-verifier dispatches; the second ran against the final commit after all fixes, and its verdict is the one of record. None of the six rubrics in .references/rubrics/ covers a docs change, so the ACs alone gated.

  • AC1references/run-operations-analysis.md:87-100 — all four elements present: one useful | marginal | waste verdict per row; production judged by downstream consumption ("name what consumed the output or name that nothing did"); assurance judged "never by citation" and by whether its question needed answering; :125-126 gates de-escalation on "yield evidence per .references/zones.md".
  • AC2:101-120 — the three stats computed "from the already-parsed JSONL without loading transcript content": Duplicate reads (:103), Top-spend turns (:109), Cache-read volume (:117). :121-124 limits semantic judgment to "only… the transcript window a mechanical stat flagged, never by sweeping the full transcript".
  • AC3claude/skills/postmortem/references/postmortem.md:40-42 — names wasteful and marginal spend "across all components — dispatches, pipeline steps, and the main loop, not only review passes" plus the token-efficiency change(s) supported; :71-73 repeats it in the dial record.
  • AC4claude/skills/postmortem/SKILL.md:75-81 — audit covers "every dispatch, pipeline step, and the main loop"; success criteria require the verdict with evidence. :157 — "Token-efficiency findings from the spend audit are equally valid proposal targets."
  • AC5 ✅ all 58 added lines audited (ADDED_LINE_COUNT=58, TARGETED_SCAN_RESULT=no_absolute_consumer_path_name_or_id); the only added repo-internal path is consumer-relative (.references/zones.md). The dcouple/orchestra mention at SKILL.md:150 confirmed pre-existing, not added here.

Substance: 3 files changed, 58 insertions(+), 2 deletions(-). The 2 deletions are deliberate — both pre-existing "a pass that found nothing was pure spend" assertions, narrowed to the zone-necessity criterion because leaving them intact contradicted the new rule. The verifier confirmed both amendments retain the overdone/right-sized/underdone judgment, the dial selection, the token-per-pass signal, and the zones-table tuning. Report-only boundary verified uncontradicted (SKILL.md:28-30, :159-165). git diff --check clean; git status --short empty after verification.

Manual test executed: scripts/sync.sh into a throwaway git init target — all three edited files arrived byte-identical, a second run produced zero further change (idempotent as documented), temp target deleted. No real consumer repo was touched.

Review outcome

Must Fix: 0 · passes used: plan 1/1, post-PR 3/3.

The post-PR loop was unusually productive for a docs change — every pass found something real:

Pass Found Nature
1 2 Must Fix, 1 Should Fix a direct contradiction: the untouched "pure spend" line vs. the new never-by-citation rule; and two of three main-loop stats named but not mechanically defined
2 2 Must Fix stats still not uniquely computable — which tool uses count as a "read"; and cache-creation priced against two possible TTL rates (1.25× vs 2×)
3 1 Must Fix the deterministic 5-minute fallback could publish a silently understated cost without disclosing it was a lower bound

All six findings were fixed across four implementer rounds. The pass-1 Should Fix (verdict boundaries under-defined) was folded in rather than deferred, and pass 3 confirmed the three verdicts now partition cleanly. No Should Fix or Nice to Have survived, so there are no inline PR comments — the loop consumed everything it raised.

QA pass: 1 of 6 manual items executed (the command-shaped sync test, passed), 5 left to the human because each requires invoking /postmortem in an agent session, which a sub-agent may not do. 0 QA findings — the drive surfaced no bug.

One sequencing caveat, flagged deliberately: the pass-3 Must Fix was fixed in d454551 after the review loop hit its cap, so that two-line hunk was checked by the QA verifier against the final state but never by a diff reviewer. It is a disclosure clause with no behavioral reach, and it is called out in the PR's Residual risks so the human reviewer knows which hunk carries less review than the rest.

Human action required

  • ⛔ Blocks verification / QA (prerequisite): none.
  • ⛔ You must do (deploy / external): none. These are markdown instruction files; they reach consumer repos through each repo's own update-skills sync PR, which this run deliberately did not trigger (AGENTS.md Boundaries).
  • ✅ Done for you (applied in-run): nothing required applying — no schema, env, infra, dependency, or backfill in the diff. The diagram was rendered and hosted on the rolling qa-assets prerelease; the artifact bundle was re-uploaded at plan-complete and wrap-up.

The only thing genuinely waiting on you is PR review, plus the five manual items if you want them exercised — and this run is itself a good subject for them.

Residual risks / follow-ups

  • The pass-3 fix carries less review than the rest of the diff (see Review outcome). Two lines, disclosure-only.
  • Instruction adherence isn't mechanically enforceable — nothing asserts at runtime that a postmortem actually assigned verdicts. The guarantee is the step-2 success criteria, exactly as for every other criterion in the skill.
  • Verdict judgment remains subjective at the margin. The three verdicts now partition explicitly and the fully-consumed-but-overpriced case is assigned to marginal, but boundaries are still judgment. The de-escalation gate means a mistaken waste cannot by itself strip verification — zones.md still requires yield evidence, one change at a time.
  • Watch the audit's own cost. Three review passes each pushed for more determinism in the stat definitions; the final reviewer judged the result "scannable and not excessively bloated," but this is the section to watch if postmortems start feeling heavy. The new audit will measure itself.
  • Follow-up (existing path, no new work item): adoption of any audit-driven proposals runs through /postmortem-loop, as the item specified.

Dial record

zone: 2                      # from the item; user-confirmed de-escalation from zones.md's nominal 1
lanes: single-codex          # item's explicit review_lanes override
passes: {plan: 1/1, post_pr: 3/3}
findings:                    # total findings raised (Must Fix in parentheses)
  plan:    {pass1: {codex: 2 (0), claude: n/a}, later: {codex: 0, claude: n/a}}
  post_pr: {pass1: {codex: 3 (2), claude: n/a}, later: {codex: 3 (3), claude: n/a}}
verifiers: {frontend: disabled_by_item, qa_pass: ran}
qa_findings: 0
wall_clock: 0:30             # scripted from session transcript JSONL: 03:21:39Z -> 03:51:05Z
deviations: "escalated 2->1: pass-1 diff review surfaced a direct contradiction between a new instruction and an existing one — a defect class that recurs in re-wording, so the fix rounds earned confirm passes"
pr_size: {files_changed: 3, additions: 58, deletions: 2}
tokens:
  codex:
    total: 334602
    by_role:
      implementer: 123548      # 4 dispatches, cumulative: 51060 / +36403 / +23126 / +12959
      code_reviewer: 101337    # 3 dispatches: 24656 / 42282 / 34399
      backend_verifier: 65880  # 2 dispatches: 30826 / 35054
      plan_reviewer: 43837     # 1 dispatch
  claude_subagents: 0          # none dispatched — every sub-agent this run ran on Codex
  overseer: 10403014           # main session JSONL, message.id-deduped: out 101140,
                               # cache-read 10089620, cache-write 212115, input 139
  total: 10737616
spend_ratio: 178960.3          # 10737616 / (58 + 2)
agents:
  - {role: plan-reviewer,    model: gpt-5.6-sol, effort: low,    dispatches: 1, duration: ~4m,  tokens: 43837}
  - {role: implementer,      model: gpt-5.6-sol, effort: medium, dispatches: 4, duration: ~11m, tokens: 123548}
  - {role: code-reviewer,    model: gpt-5.6-sol, effort: low,    dispatches: 3, duration: ~12m, tokens: 101337}
  - {role: backend-verifier, model: gpt-5.6-sol, effort: low,    dispatches: 2, duration: ~7m,  tokens: 65880}
  - {role: overseer,         model: claude-opus-5, effort: n/a,  dispatches: n/a, duration: 0:30, tokens: 10403014}

Note on spend_ratio: the number is real but reads oddly because cache reads are 94% of the overseer's token volume, and a 60-line diff is a tiny denominator. Priced rather than counted, the picture inverts — cache reads bill at 0.1×, so the overseer's cost is dominated by its 101k output tokens, not its 10M cache reads. This is exactly the kind of distortion the change this PR ships exists to surface: a raw-token ratio on a docs change is a misleading efficiency signal, and the new audit's cache-read-volume stat is what would flag it.

@tbrownio tbrownio added the awaiting-human-review Run finished final testing; commits after this label = post-review rework label Aug 1, 2026
@tbrownio

tbrownio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Postmortem — postmortem-spend-audit (ops-only)

Postmortem — postmortem-spend-audit

Run operations (always)

Wall-clock 31.3 min, agent-active 31.2 min, human-idle 0.1 min (0.3%). No post-completion idle to carve out — the human never left. Zero stalls: no gap above 5 minutes, no "continue" nudge, no AskUserQuestion gate, no rate-limit hit. Eight user-turn events appear in the transcript; all eight are skill invocations (/do, codex ×N, excalidraw-pr-diagrams, postmortem), not human interventions. Operationally this run is clean, and there is no stall for a "biggest stall" line to name.

Per-step timing table

Dispatch clock times from the .codex-dispatches/local/ marker pairs (.sh mtime → .done mtime); overseer segments are the gaps between them. Costs for Codex rows are unknowncodex exec prints one undifferentiated tokens used total with no input/output split, so a per-class price cannot be computed without parsing ~/.codex/sessions/rollout-*.jsonl, which this ops-only pass did not do.

Step / dispatch Start End Dur Tokens Est. cost Verdict Note
Step 0 preflight + load 20:21 20:23 ~2m overseer useful bundle + issue fetched, branch state checked; no gaps found
Step 1 plan authoring 20:23 20:24 ~2m overseer useful plan.md consumed by every later dispatch
plan-reviewer ×1 20:24:32 20:25:25 0m53s 43,837 unknown useful 0 MF, 2 SF — both consumed into plan.md before implement
implementer #1 20:26:38 20:28:34 1m56s 51,060 unknown useful produced the 35-line base diff
backend-verifier #1 20:29:20 20:29:56 0m36s 30,826 unknown marginal see below — necessary question, fully superseded answer
Step 4 PR open 20:30 20:31 ~1m overseer useful PR #133
code-reviewer #1 20:32:09 20:32:57 0m48s 24,656 unknown useful 2 MF + 1 SF, all three fixed
diagram authoring 20:33 20:41 ~8m overseer ~$2.20 useful 2 render-fix cycles; embedded in the PR body
implementer #2 (fix) 20:36:59 20:39:13 2m14s +36,403 unknown useful resolved both MF + the SF
code-reviewer #2 20:41:01 20:42:19 1m18s 42,282 unknown useful 2 MF, both fixed
implementer #3 (fix) 20:42:53 20:44:26 1m33s +23,126 unknown useful 4 lines, both MF closed
code-reviewer #3 20:44:59 20:45:40 0m41s 34,399 unknown useful 1 MF, fixed
implementer #4 (fix) 20:46:09 20:46:34 0m25s +12,959 unknown useful 2 lines, closed the last MF
backend-verifier #2 (QA) 20:47:30 20:49:08 1m38s 35,054 unknown useful final-state proof + executed the sync manual test
Step 6 wrap-up 20:49 20:52 ~3m overseer useful wrap-up, bundle, label, notify

Aggregates. Dispatch wall-clock totals 11m42s across 10 dispatches — 37% of the run. The remaining ~63% is the overseer's own turns, of which the single largest block is the ~8 minutes of diagram authoring. Summed overseer turnaround between dispatches: ~19.5 min. Human-idle total: 0.1 min.

Spend audit

Production work — judged by downstream consumption. Every production dispatch's output was consumed: all four implementer rounds landed in the shipped diff, the plan was read by every subsequent dispatch, and the diagram is embedded in the PR body. Nothing produced went unconsumed. All useful.

Assurance work — judged by whether its question needed answering at this zone. Nine of ten dispatches are useful by this criterion. The one exception:

  • backend-verifier #1 — marginal. Its question ("do AC1–AC5 hold?") genuinely needed answering before opening the PR — Step 3 requires it and a PR should not open unverified — so it is not waste. But its answer was fully superseded: three fix rounds landed afterward, and backend-verifier #2 re-proved the identical five criteria by identical means. The spend bought roughly 20 minutes of confidence. Note the cause carefully: the supersession was produced by the review loop finding real Must Fixes, not by a pipeline defect. This is the ordinary price of a productive review loop, which is why it is marginal and not waste, and why it supports no proposal.

Review-pass yield — the notable number. All three post-PR review passes found a Must Fix (2, 2, 1), and every one was real and fixed. The loop did not converge to zero; it hit its cap with a finding still outstanding. Under the criterion this PR ships, not one review pass was spend to question. This is direct evidence against de-escalating review effort on instruction-text changes, and it retroactively validates the one-notch escalation (2→1) the Overseer took after pass 1.

Main loop — mechanical stats.

  • Duplicate reads: 1 path read twice — the rendered diagram PNG, read before and after the fix cycle. Deliberate and correct; 6 Read calls total across 5 distinct paths. No waste signal.
  • Top-spend turns (est., 5-minute cache-write rate assumed → lower bound): $1.154 (03:39:28, 19,296 output) and $1.067 (03:35:57, 17,480 output) — the two large diagram-JSON authoring turns. Then $0.498, $0.468, $0.437. The two diagram turns are ~11% of estimated main-loop cost.
  • Cache-read volume: 11,761,480 tokens — 98.1% of input-side tokens (11,985,361 total). At 0.1× input that is ~$11.76 of an estimated $20.02 main-loop lower bound.

The headline spend finding: the overseer main loop is ~97% of the run's total token volume (≈11.99M vs 334,602 across all ten Codex dispatches). Counted in raw tokens the sub-agents look almost free; priced, the ratio narrows sharply because cache reads bill at 0.1×. The wrap-up's spend_ratio: 178960.3 is technically correct and practically misleading — a raw-token ratio over a 60-line docs diff measures conversation length, not efficiency. This is precisely the distortion the change under review exists to surface, and it is the first thing the new cache-read-volume stat flags.

Follow-the-evidence: the two mechanical flags (the diagram turns, the cache-read share) were each inspected in their own transcript window only. No full-transcript semantic sweep was run.

What we asked for

Every postmortem should judge how a run spent its tokens, not just its time — a spend audit over everything that ran, with each timing-table row carrying a useful | marginal | waste verdict, production work judged by downstream consumption and assurance work by necessity-at-zone, plus scripted mechanical main-loop stats. Three additive markdown edits, report-only, repo-agnostic.

Outcome vs intended

Deferred — the human has not reviewed PR #133 yet. This is an operations-only postmortem; the outcome half runs on a later /postmortem invocation.

Mechanically, all five acceptance criteria were independently verified against the final commit, and this very document is the first artifact produced under the new instructions — the spend audit section above was written by following the rules the PR adds.

What to change so it doesn't recur

Two proposals, both from operational findings. Neither is applied.

1. claude/skills/do/SKILL.md — say what happens when the review cap is reached with a Must Fix outstanding

The run hit this case directly and the instructions do not cover it. Step 5 says the cap is reached "with survivors flagged in the wrap-up", which reads naturally for Should Fixes — but a Must Fix is by definition blocking, so "flag it and ship" is wrong, while "keep reviewing" violates the cap. The Overseer had to invent a route: fix it, route the final-state check to the QA verifier instead of a fourth review pass, and flag the reduced review coverage in the PR's Residual risks. That worked, but it was improvised, and a different Overseer would improvise differently.

Proposed edit — in Step 5, after the sentence "A pass with zero Must Fix from every lane ends the loop":

When the cap is reached with a Must Fix still open, the finding is still fixed — a cap limits review passes, never fixes. Land the fix, route its check to the verify stage rather than a further review pass, and record in the PR's Residual risks exactly which hunk shipped without diff review. Never leave a Must Fix unfixed because the cap was reached.

2. references/zones.md — note that instruction-text changes ratchet rather than converge

Three review passes each found a real Must Fix, and each finding was of the same shape: the previous fix was not yet deterministic enough. Reviewing prose that instructs an agent has a different convergence profile from reviewing code — there is no compiler to bottom out the argument, so a reviewer can always demand more precision. The loop terminated on the cap, not on agreement. Zone selection currently reasons about blast radius and reversibility, which correctly rated this change cheap; nothing tells the Overseer that the review on such a change may not converge.

Proposed edit — add to the zone-selection guidance:

Instruction-text changes (skills, agents, references) ratchet rather than converge: each pass can legitimately demand more determinism from prose the previous pass accepted, so the loop may terminate on the cap rather than on agreement. Judge exit on whether the remaining findings are material, not on reaching zero — and treat a pass that found nothing as the real convergence signal.

Explicitly not proposed: nothing about backend-verifier #1's superseded run. Its verdict is marginal, but the cause was a productive review loop, and a rule that skipped pre-PR verification to save that spend would trade real safety for a small saving. This is the case the audit's assurance criterion exists to protect, and the audit protected it.

Dial record & right-sizing

zone: 2                      # item's, user-confirmed down from zones.md's nominal 1
effective_zone: 1            # Overseer escalated one notch after review pass 1
lanes: single-codex          # item's explicit review_lanes override
passes: {plan: 1/1, post_pr: 3/3}
findings:
  plan:    {pass1: {codex: 2 (0 MF), claude: n/a}, later: {codex: 0, claude: n/a}}
  post_pr: {pass1: {codex: 3 (2 MF), claude: n/a}, later: {codex: 3 (3 MF), claude: n/a}}
verifiers: {frontend: disabled_by_item, qa_pass: ran}
qa_findings: 0
wall_clock: 0:31
deviations: "escalated 2->1 after pass 1 surfaced a direct instruction contradiction"
pr_size: {files_changed: 3, additions: 58, deletions: 2}
tokens:
  codex: {total: 334602, by_role: {implementer: 123548, code_reviewer: 101337,
          backend_verifier: 65880, plan_reviewer: 43837}}
  claude_subagents: 0
  overseer: 11985361          # input-side; 98.1% cache reads. Est. $20.02 (lower bound)
  total: 12319963
spend_ratio: 205332.7         # raw-token ratio over a 60-line diff — see the caveat above
agents:
  - {role: plan-reviewer,    model: gpt-5.6-sol,  effort: low,    dispatches: 1, duration: 0m53s, tokens: 43837}
  - {role: implementer,      model: gpt-5.6-sol,  effort: medium, dispatches: 4, duration: 6m08s, tokens: 123548}
  - {role: code-reviewer,    model: gpt-5.6-sol,  effort: low,    dispatches: 3, duration: 2m47s, tokens: 101337}
  - {role: backend-verifier, model: gpt-5.6-sol,  effort: low,    dispatches: 2, duration: 2m14s, tokens: 65880}
  - {role: overseer,         model: claude-opus-5, effort: n/a,   dispatches: n/a, duration: 0:31, tokens: 11985361}

Judgment: review effort was right-sized — arguably still underdone. Every one of the three post-PR passes found a real Must Fix, and the loop ended on its cap with a finding outstanding rather than on agreement. Under the criterion this PR ships, no pass was spend to question. The single dial that would have changed the outcome is the pass cap: at the item's captured zone 2 the cap was 1, which would have shipped a diff containing a direct instruction contradiction. The Overseer's one-notch escalation to zone 1 is what bought passes 2 and 3, and both earned their cost.

Acceptance

Still awaiting human review — operations-only postmortem. The PR is labeled awaiting-human-review; commits after that label's timestamp are the post-review rework metric.

System changes

Tyler Brown and others added 6 commits August 24, 2026 09:56
Postmortems priced every run but only judged the spend of review passes.
Research nobody consumed, a verifier re-proving the proven, and a bloated
main loop all slipped through.

Three additive instruction edits give the audit a computation rule, a place
in the report, and success criteria plus a proposal target:

- references/run-operations-analysis.md — every timing-table row gets a
  useful | marginal | waste verdict. Production work is judged by downstream
  consumption; assurance work by whether its question needed answering at
  the zone, never by citation, so a correct negative result is not waste.
  Main-loop coverage is three scripted mechanical stats computed without
  loading transcript content, with semantic digs limited to flagged windows
  so the postmortem does not itself become the wasteful run.
- claude/skills/postmortem/references/postmortem.md — the body must name
  wasteful spend across all components and the efficiency changes it supports.
- claude/skills/postmortem/SKILL.md — step 2 success criteria require the
  per-dispatch verdict; step 6 accepts token-efficiency proposals.

The postmortem stays report-only, and de-escalation proposals the audit
feeds still require yield evidence per zones.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review pass 1 found two blocking defects and one gap:

- The dial-record line still asserted flatly that "a pass that found
  nothing was pure spend", directly contradicting the new rule that
  assurance work is judged by whether its question needed answering at the
  zone. Two agents could reach opposite verdicts from identical evidence.
  Both occurrences are now qualified with the zone-necessity criterion.
- Two of the three main-loop stats were named but never mechanically
  defined, so the audit was not reliably scriptable: path normalization,
  the token classes constituting turn spend, the output cardinality, and
  the reported unit are now all specified.
- The three verdicts now read as mutually exclusive outcomes with stated
  boundaries, including the fully-consumed-but-disproportionate case.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review pass 2 found two stats still not uniquely computable:

- "duplicate reads" said which paths to normalize but not which tool uses
  count as a read, so a script counting only the file-reading tool would
  disagree with one that also counted search paths or shell-embedded ones.
  Now scoped to the file-reading tool's own path input.
- top-spend turn cost priced cache-creation tokens at "their class-specific
  rate", but model-prices.md carries two cache-write rates (1.25x at 5m TTL,
  2x at 1h). Identical turns could be priced 60% apart, reordering the top
  five. Now uses the recorded TTL class, defaulting to the 5-minute rate
  when only an aggregate survives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 5-minute cache-write fallback made the cost deterministic but not
honest: model-prices.md prices a 1-hour-TTL write at 2x input against
1.25x at 5 minutes, so a turn with substantial aggregate cache creation
could be reported with a definitive-looking cost understated by ~60% on
its cache-write component — and ranked below a turn that cost more. The
total now travels with the assumption that produced it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three review passes ratcheted this text from an idea into a specification:
path normalization, token-class arithmetic, ranking cardinality, TTL
fallbacks, lower-bound labelling. Each finding was individually correct and
the result was collectively unreadable — 40 lines an agent must wade through
under context pressure, in a document whose whole point is that the
postmortem must not become the wasteful run.

Cut to 16 lines. Every acceptance criterion still holds: the per-row
useful | marginal | waste verdict, production judged by downstream
consumption, assurance by necessity-at-zone and never by citation, the
three main-loop stats computed without loading transcript content, the
follow-the-evidence limit, and the zones.md yield gate. What went is the
scripting minutiae, which belongs to whoever writes the script — the
reference already carries one.

Also removed a duplicated requirement in the report template: the whole-run
spend instruction appeared in both the Run operations block and the dial
record. It now appears once and the dial record refers to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The reference script hand-rolled a four-way user-turn classification and
computed nothing but span and stalls. It now also derives the three
main-loop stats, in roughly the same number of lines: text extraction is
shared across both content shapes, and usage/read collection folds into
the single parse pass already happening.

Reporting is now conditional. The script prints a stat only when it trips
a threshold — a file read 3+ times, a turn over ~15% of run output, cache
reads over ~95% of input — so a clean run reports one line saying nothing
flagged instead of a stat dump nobody acts on. Silence is the signal that
there is nothing to dig into, which is what the follow-the-evidence rule
wanted in the first place.

Using output tokens as the spend proxy for "top turn" also drops the
cache-write TTL ambiguity entirely: output dominates cost when cache reads
bill at 0.1x, so the extra arithmetic bought precision nobody needed.

Verified against two real session transcripts: correctly flagged two
genuine duplicate reads while leaving the untripped stats silent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-human-review Run finished final testing; commits after this label = post-review rework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Postmortem spend audit: token-efficiency review of everything that ran

1 participant