Skip to content

fix: full budget-checkpoint coverage across review + adversarial (Codex #2) - #9

Merged
telivity-otaip merged 1 commit into
mainfrom
feat/budget-coverage
Jun 17, 2026
Merged

fix: full budget-checkpoint coverage across review + adversarial (Codex #2)#9
telivity-otaip merged 1 commit into
mainfrom
feat/budget-coverage

Conversation

@telivity-otaip

Copy link
Copy Markdown
Collaborator

Closes critical finding #2 from the Codex review. Also lands the design doc for both criticals (#1 + #2); #1 (sandbox hardening, Level 1) follows as a separate PR.

The bug

The cost-controller created one checkpoint per task but recorded only the executor's tokens. Everything downstream was invisible to both the budget cap and the reported total:

  • Self-review (3 persona calls) — never recorded.
  • Adversarial gate — untracked at the source: CodexCaller.call() returned only { content }, no token fields at all.
  • System B (papa) — recorded an aggregate only after the thinker fan-out, with no pre-flight check.

Net: System A could spend ~3× what the checkpoint saw; the kill switch couldn't fire between the executor and the PR.

The fix

  • CodexCaller gains a token surface (optional fields → existing mocks still compile). createCodexCaller parses OpenAI's usage; createOpenAICompatibleCodexCaller estimates chars/4 when the local server omits usage.
  • SelfReviewResult + AdversarialReviewResult carry tokenUsage. selfReview aggregates the three persona calls; adversarialReview surfaces the codex call's tokens.
  • loop.ts accounts every stage: forceCheck() before the self-review fan-out; recordAndCheck() after self-review and after adversarial; any over-budget result → budget-exceeded + break. The reported totalTokenUsage now sums executor + review + adversarial on all outcome paths (success and failure) — previously even the report undercounted.
  • papa.ts forceChecks before the thinker fan-out so a request already at the ceiling never launches N parallel calls.

On codex pricing

The codex model id is free-form (gpt-4o, codex-mini), not a ModelTier. calculateCallCost returns $0 for ids absent from the pricing table (landed in PR #7), so adversarial tokens are tracked even though the codex wire-cost line reads $0. Adding a real codex pricing row is a clean follow-on.

Tests

  • Before: 380. After: 384. No skips.
  • New: cloud createCodexCaller surfaces usage tokens (+ zero-when-absent); local createOpenAICompatibleCodexCaller token surfacing + chars/4 estimate; loop-level test asserting the reported total exceeds the executor-only tokens (proving review+adversarial are accounted).
  • Three existing review-fixture tests updated for the new tokenUsage field.
  • Build + typecheck clean across all 5 packages.

Validated on a local-disk copy — node_modules on the working tree's Google Drive mount is intermittently corrupting (placeholder files in cac/tsup). Source + git unaffected.

Design doc

docs/design/2026-06-17-criticals-sandbox-and-budget.md — covers this fix and critical #1 (execution sandbox). #1's chosen depth is Level 1 (process hardening: --ignore-scripts, env allowlist so API keys/GH token never enter the pnpm/git child env, credential separation for PR creation). Ships next as its own PR.

🤖 Generated with Claude Code

#2)

The cost-controller only recorded executor token spend; self-review
(3 persona calls) and the adversarial gate were invisible to both the
budget cap and the reported total — System A could spend ~3x what the
checkpoint saw, and the kill switch couldn't fire mid-task. System B
(papa) recorded an aggregate only AFTER the thinker fan-out, with no
pre-flight check.

Changes:
- CodexCaller contract gains optional token fields; createCodexCaller
  parses OpenAI's usage block, createOpenAICompatibleCodexCaller
  estimates chars/4 when the server omits usage. The adversarial gate's
  spend was previously untracked AT THE SOURCE (the interface returned
  only { content }).
- SelfReviewResult + AdversarialReviewResult carry tokenUsage.
  selfReview aggregates the three persona calls; adversarialReview
  surfaces the codex call's tokens.
- loop.ts records every stage against the checkpoint: forceCheck before
  the self-review fan-out, recordAndCheck after self-review and after
  adversarial, kill→budget-exceeded on any over-budget result. The
  reported totalTokenUsage now sums executor + review + adversarial on
  ALL outcome paths (success and failure).
- papa.ts forceChecks before the thinker fan-out so a request already at
  the ceiling never launches N parallel calls.

The codex model id is free-form (not a ModelTier); cost-estimator
returns $0 for ids absent from the pricing table (PR #7), so tokens are
tracked even though the codex wire-cost line is $0. Adding codex pricing
is a follow-on.

Also adds docs/design/2026-06-17-criticals-sandbox-and-budget.md — the
design for this fix (#2) AND critical #1 (sandbox hardening, Level 1
chosen). #1 ships as a separate follow-on PR.

Tests: 380 → 384. New: cloud + local codex token surfacing, loop
total-token accounting includes review+adversarial. No skips.

Refs CODEX_REVIEW.md (#2).
@telivity-otaip
telivity-otaip merged commit 6eef546 into main Jun 17, 2026
@telivity-otaip
telivity-otaip deleted the feat/budget-coverage branch June 17, 2026 20:28
telivity-otaip added a commit that referenced this pull request Jun 17, 2026
…) (#11)

#7 — DomainAnswerStore keyed answers by question TEXT only, so two
different files asking the same question (e.g. "What is the grace
period?") collapsed to one answer; answering it in file A silently
unblocked file B with A's answer. hashQuestion now takes (filePath,
text) and hashes the composite. Same wording in a different file is a
distinct question again.

#9 — Captured transcripts wrote full prompts/responses to disk
unredacted; they can carry pulled-in source and secrets. New
redactSecrets() masks known token shapes (sk-ant-, sk-/sk-proj-,
ghp_/gho_/…, github_pat_, AKIA/ASIA, AIza, xox*, Bearer values, and
SECRET_NAME=value assignments). instrumentLLMCaller/CodexCaller redact
by default (opt out with { redact: false }); the events file is created
mode 0600.

Tests: 387 → 400. New: hashQuestion file-scoping + path-normalization;
redactSecrets per token shape + non-secret passthrough; instrumented
callers redact by default and honor redact:false. No skips.

Refs Codex review #7, #9 (private KB).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant