Repository navigation
fix(engine): keep the token ledger out of test suites and out of the model CLI's environment - #2311
Conversation
The dev-lead and pr-review jobs export TOKEN_LOG_FILE for the whole job. The agent session inherited it and ran this repository's bats suites, whose fixture calls, rejections and cooldowns were appended to the run's real ledger and uploaded with it. Two independent fixes: - scripts/engine.sh starts every model CLI (claude, gemini, gh copilot; five launch sites) through _engine_child, which removes TOKEN_LOG_FILE, GEMINI_LEDGER_FILE and _ENGINE_USAGE_OUT from the child's environment. The parent shell still records each call around the CLI. - tests/dev-lead/unit/setup_suite.bash unsets the same three variables before any test file starts. tests/ and tests/dev-lead/integration/ gain a setup_suite.bash that loads it: bats reads one such file per run, the one beside the first path it is given, and never looks in subdirectories. Measured with TOKEN_LOG_FILE exported and every bats file run on its own: 16 files wrote 221 records (plus usage sidecars and locks) before, none after. Tests: test_engine_child_env.bats (each launch site, and the parent's record) and test_token_ledger_isolation.bats (suite hooks in every directory of bats files, and nested runs of the suites that wrote). Refs #2304 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, not seven The isolation is suite-wide, so six more suites added about two minutes to the unit job and no coverage. Refs #2304 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 24 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
dev-lead is withholding action on this item. It is labeled To re-enable automated pickup: remove the |
|
Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-10-11T21:54:03Z. |
There was a problem hiding this comment.
Code Review
This pull request implements token ledger isolation by introducing an _engine_child wrapper in scripts/engine.sh that unsets ledger-related environment variables before invoking model CLIs, preventing child processes from polluting the real token ledger. It also unsets these variables in BATS suite-level hooks and adds comprehensive unit tests to verify the isolation. The review feedback suggests optimizing a find command in the tests to avoid spawning multiple dirname processes, and replacing a non-idiomatic return 1 assertion in BATS with false.
QA Lead — test-risk advisoryRisk tier: LOW. The production change is one What I'd shore up (highest leverage first):
Escalate? no Advisory only — I comment, I do not change code. Ground: BMAD Test Architecture |
CodeAnt PR Risk: Low Risk
Assessed commit: |
From the QA advisory: nothing stopped a sixth launch site from being added without _engine_child, and it would have leaked with every behavioural test still green. A static test now fails on any model CLI started in engine.sh outside the wrapper. Also the two small points from review of the isolation test (no per-file dirname fork; fail with false, not return). Refs #2304 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review round 1, head
|
|
|
Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-10-11T22:30:33Z. |



Problem
The org-wide Gemini usage ledger is almost entirely test fixture data: about 8 of 1,819 request-counting Gemini records over four days were real calls. The cause is not a test job. The
dispatchjob ofdev-lead-reusable.ymlsetsTOKEN_LOG_FILEfor the whole job; the agent session inherits it; when the agent runs this repository's tests as part of its work, suites that do not isolate the variable append their fixture calls, rejections and cooldowns to the run's real ledger; the run then uploads it.Measured for this change, by running every bats file on its own with the variable exported: 16 of 247 files wrote 221 records (the largest,
test_fix_reviews, 122). That is more than the seven suites the issue names, and includes three files outsidetests/dev-lead/unit/and two that mention the variable.Design
Two independent halves; either alone stops the leak, and they fail in different ways.
1. Tests never see an inherited ledger.
setup_suite()intests/dev-lead/unit/setup_suite.bashunsetsTOKEN_LOG_FILE,GEMINI_LEDGER_FILE(the Gemini library's override for the same file) and_ENGINE_USAGE_OUT(a per-call usage sidecar). A test that needs a ledger sets its own.setup_suitein the shell that starts every test file, so anunsetthere reaches the tests (verified with a probe suite on bats 1.13).setup_suite.bashper run, the one beside the first path it is given, and never looks in subdirectories. Sotests/andtests/dev-lead/integration/each gain a one-linesetup_suite.bashthat sources the unit one. Every directory holding bats files now has the same hooks.tests/now also gets the git-identity guard the unit directory already had. All 157 top-level files give the same counts with it.2. The model CLI is started without the ledger. New
_engine_childinscripts/engine.shruns its command underenv -ufor the same three variables, and all five CLI starts go through it (Copilot, Gemini's two paths, Claude's two paths). The parent shell keeps the variable and still records every call; the child never needed it. This stops whatever the session runs from writing to the ledger, tests or not.No workflow file changes.
Risk
engine.shhalf reaches production only when the dev-lead channel moves. This repository pinsdev-lead/v139-ring0for both the workflow and its scripts. The suite-hook half needs no tag: the agent runs tests from the branch it is working on, so any branch containing this commit stops leaking; branches cut earlier keep leaking until they pick it up.model-ab.ymlalso sets the variable and starts twoclaude --printprobes directly, not throughengine.sh. They grant no tools and are left as they are.unitjob (measured on macOS). The guard file is not inlint.yml's list, so the time-limitedbatsjob is unaffected. A change that touches only top-leveltests/does not trigger the workflow that runs the guard; it fires on the next change that does.Test plan
tests/dev-lead/unit/test_token_ledger_isolation.bats(new, 3 tests): every directory with bats files has suite hooks, and a probe run through each sees no ledger variable; one real engine suite and three top-level suites, run nested with the variables exported, leave the ledger directory empty.tests/dev-lead/unit/test_engine_child_env.bats(new, 6 tests): for each launch site a stub CLI dumps its environment and finds none of the three variables, while the parent's ledger still gets the call's record; in one, the stub itself calls the token writers and the ledger still holds only the parent's record.test_engine_writertest 15, which failed only when a ledger was inherited, now passes in that case too.shellcheck --severity=warning -xclean; the fixed-path check exits 0; no negated assertion that cannot fail.Rollback
Revert the squash commit. Tests and agent sessions go back to inheriting the ledger path.
Monitoring
gemini-same,gemini-test,gemini-u1, …).dev-lead/v139-ring0moves: the "Gemini ledger provenance" section added by fix(gemini-ledger): hand the tier report only records traceable to trusted runs #2305 should report zero records for models or keys with no caps row. Until both land, the warning there is expected.Closes #2304
🤖 Generated with Claude Code