fix(eval): make the harness runnable on Windows and price runs correctly - #159
Open
akumrazor wants to merge 1 commit into
Open
fix(eval): make the harness runnable on Windows and price runs correctly#159akumrazor wants to merge 1 commit into
akumrazor wants to merge 1 commit into
Conversation
The L1 harness could not run on Windows at all, and the cost preflight was wrong twice over on any model outside the two in the pricing table. Portability: * render-bridge.mjs passed a filesystem path to dynamic import(). On POSIX a bare absolute path happens to work; on Windows `E:\...` parses as the scheme `e:` and is rejected outright. Use pathToFileURL(). * anthropic-client.mjs hardcoded ~/.claude/local/claude and never passed it to cci.py, which reads its own CCI_CLAUDE_BIN. npm/global installs land elsewhere, so the harness failed with a confusing "exited 1" rather than a missing-binary error. Resolve env -> legacy path -> PATH, and pass it down. * cci.py drives the interactive TUI through a pty, which pexpect only provides on POSIX -- pexpect.spawn does not exist on win32, so the shim can never run there. Added a headless `claude -p` transport, automatic on win32 and forcable anywhere with CCI_HEADLESS=1. It also returns a real server usage block the TUI panels do not, so accounting improves. Cost estimator: * No entry for claude-opus-5 / claude-fable-5, and the lookup silently fell back to another model's rates behind a "$?/Mtok" label -- a confidently wrong dollar figure. Added both, plus derived cache read/write rates, and made the unknown-model path say so instead of guessing. * printCostEstimate assumed 2 calls per block while L1 runs one per variant, understating the bill 5.5x at the current 11. It now takes the real count. eval-l1-ocr.mjs was scaling externally to compensate; that is removed so the two do not double-apply. * The variant names moved to eval/lib/variant-names.mjs so the estimator can count them without importing (and thereby running) the eval. eval-l1-ocr.mjs asserts its VARIANTS array matches at startup, so a variant added in one place and not the other fails loudly instead of drifting back into the bug this fixes. run-eval.mjs: the combined report read baselineAgg/reflowAgg, fields that disappeared when L1 became an N-variant sweep, so step 3 crashed even on a dry run. Rebuilt over perVariant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The L1 harness could not run on Windows at all, and the cost preflight was wrong twice over for any model outside the two in the pricing table. Found while pointing the harness at
claude-opus-5.Portability
render-bridge.mjspassed a filesystem path to dynamicimport(). On POSIX a bare absolute path happens to work; on Windows an absolute path likeE:\source\...parses as the schemee:and is rejected outright:Fixed with
pathToFileURL().anthropic-client.mjshardcoded~/.claude/local/claudeand never passed it down —cci.pyreads its ownCCI_CLAUDE_BIN, which nothing set. npm/global installs land elsewhere (e.g.~/.local/bin/claude), so the harness failed with a confusingexited 1rather than a missing-binary error. Now resolves env → legacy path →PATH, and passes it to the shim.cci.pydrives the interactive TUI through a pty, which pexpect only provides on POSIX —pexpect.spawndoes not exist on win32, so the shim can never run there. Added a headlessclaude -ptransport, automatic on win32 and forcable anywhere withCCI_HEADLESS=1. Bonus:-preturns a real serverusageblock that the TUI panels do not, so accounting improves on that path.Cost estimator
No entry for
claude-opus-5/claude-fable-5, andMODELS[model] ?? MODELS[DEFAULT_MODEL]silently fell back to another model's rates behind a$?/Mtoklabel — a confidently wrong dollar figure. Added both, plus derived cache read/write rates, and the unknown-model path now says so instead of guessing.printCostEstimateassumed 2 calls per block while L1 runs one per variant, understating the bill 5.5x at the current 11. It now takes the real count.eval-l1-ocr.mjswas scaling externally to compensate, so that is removed — otherwise the two would double-apply.Before / after for a 20-block L1 sweep on
claude-opus-5:The variant names moved to
eval/lib/variant-names.mjsso the estimator can count them without importing (and thereby running) the eval.eval-l1-ocr.mjsasserts itsVARIANTSarray matches at startup, so a variant added in one place and not the other fails loudly instead of drifting back into exactly the bug this fixes.run-eval.mjscombined reportStep 3 read
baselineAgg/reflowAgg, fields that disappeared when L1 became an N-variant sweep — so the orchestrator crashed withCannot read properties of undefinedeven on a dry run. Rebuilt overperVariant, now emitting a row per variant with deltas againstbaseline.Verification
Full pipeline runs end to end on Windows (dry run and live). Drift guard verified by injecting a bogus variant name — it fails with a diff of both lists. Estimator cross-checked between the orchestrator and the L1 spend gate for both the full sweep and a
--variantssubset; the two agree, confirming no double-scaling.🤖 Generated with Claude Code