test(cli): pin machine-readable output contracts - #533
Conversation
Adds test/cli-output-contracts.test.ts, a regression net for the CLI's
stable output surfaces (audit roadmap §4.4.3), driven end-to-end through
runCodexMultiAuthCli with the codex-manager-cli.test.ts mocking pattern
(storage/refresh-queue/quota-probe/quota-cache/runtime/codex-cli mocks,
console.log spy capture), a fixed two-account V3 fixture, and Date frozen
via vi.useFakeTimers({ toFake: ["Date"] }). No network, no real ~/.codex.
Surfaces pinned:
- --help / bare invocation / -h: exit 0, identical usage text, explicit
toContain assertions on all 29 documented command lines and section
headers (explicit assertions over snapshots, matching repo style).
- status --json: exact top-level key set (accountCount, accounts,
activeIndex, pinnedAccountIndex, recommendationReason, recommendedIndex,
runtimeInUseIndex, storageHealth, storagePath), exact per-account row
key set, value types.
- report --json: exact envelope (accounts, activeIndex, command, forecast,
generatedAt, liveProbe, liveProbeBudget, model, modelSelection, runtime,
runtimeOverlay, runtimeSnapshotLoadError, storageHealth, storagePath),
nested key sets for modelSelection/liveProbeBudget/accounts/forecast,
frozen generatedAt, 1-based activeIndex.
- doctor --json: exact envelope (checks, command, fix, storagePath,
summary), summary/fix key sets, per-check shape and severity enum, and
the summary.error > 0 -> exit 1 mapping.
- forecast --json: exact envelope (accounts, command, liveProbe, model,
probeErrors, recommendation, runtimeOverlay, summary; explanation only
with --explain), nested summary/recommendation key sets, per-account
allowed-key contract with liveQuota/refreshFailure absent in cached mode.
- why-selected --json: exact populated key set (availableCount, candidates,
command, config, mode, ok, selected, totalCount) plus the empty-pool
contract (exit 1, ok:false, selected:null, error message).
Leak assertions on every surface: stdout/stderr never contain the fixture
refresh/access token secrets or any email-shaped string, and refresh/probe
mocks reject so a network attempt fails loudly.
Skipped as already covered elsewhere: status/list -j/--json plumbing and
auth-prefixed forms (codex-manager-status-command.test.ts), why-selected
payload field semantics (codex-manager-why-selected-command.test.ts,
codex-manager-cli.test.ts), fix/verify-flagged --json
(repair-commands.test.ts), config explain --json (codex-manager-cli.test.ts),
rotation reset-runtime --json (codex-manager-rotation-command.test.ts).
Validation: typecheck + eslint clean; suite passes 3 consecutive runs
(8 tests); codex-manager-cli.test.ts still passes (201 tests).
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Warning Review limit reached
More reviews will be available in 11 minutes and 46 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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 |
…velope Review follow-ups: candidate/selected records now get the same allowed-key whitelist treatment as every other surface (16 candidate keys + selectionReason), and a new test pins the explanation envelope that --explain adds (key set, considered-row shape, recommendedIndex). https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Summary
Pins the CLI's machine-readable output contracts in
test/cli-output-contracts.test.ts— a cheap regression net so JSON key sets, help text, and exit codes can't drift silently. Audit roadmap §4.4.3 (docs/audits/AUDIT_2026-06-10.md, PR #522). Test-only; 686 lines, 8 tests.Surfaces pinned
--help/ bare /-hstatus --jsonreport --jsonmodelSelection/liveProbeBudget/forecastshapes;generatedAtequals the frozen instant; 1-basedactiveIndexdoctor --jsonsummary {error,ok,warn}, per-check shape + severity enum, andsummary.error > 0 → exit 1forecast --jsonexplanationonly with--explain; per-account allowed keys; cached-mode absence ofliveQuota/refreshFailurewhy-selected --jsonok:false,selected:nullLeak assertions on every surface: stdout/stderr never contain the fixture token secrets and never match an email pattern (fixtures deliberately omit emails since
statusechoes stored emails by design; the invariant pinned is no token material and no email fabricated from token claims).Deterministic by construction: reuses the
codex-manager-cli.test.tsmock harness, fixed two-account V3 fixture,Datefrozen via fake timers, refresh/probe mocks reject and are asserted un-called (no network possible).Deliberately skipped (already covered)
status/list --jsonplumbing,why-selectedfield semantics,fix/verify-flagged --json,config explain --json,rotation reset-runtime --json— each has a dedicated suite; this pass pins the envelope contracts that had none.Validation
npm run typecheck; eslint clean at--max-warnings=0test/codex-manager-cli.test.tsstill 201/201 (shared harness unbroken)Risk / Rollback
Pure test addition; revert the commit. If a future PR intentionally changes a JSON contract, the failing assertion names the exact key delta to update.
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Generated by Claude Code
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
adds
test/cli-output-contracts.test.ts— a pure test addition (no production code changed) that pins machine-readable output contracts for six cli surfaces:--help,status --json,report --json,doctor --json,forecast --json(with and without--explain), andwhy-selected --json. this closes the audit roadmap §4.4.3 gap and also addresses two gaps flagged in the previous review round (missingforecast --explaincoverage and missing key-set guards onwhy-selectedcandidate/selected records).--explainconsideredrows use an exact key-set check (sortedKeys(row).toEqual([...])) that excludesprimaryReason, while the regularforecast --jsonaccount loop uses an allowed-keys whitelist that includesprimaryReasonas optional — this inconsistency could cause a misleading failure if any considered row ever carries aprimaryReason.Confidence Score: 5/5
pure test addition with no production code changes; all mocks reject network calls and token values never reach output.
the change adds only a new test file. no production logic is modified, mocks are scoped tightly to the test, and the frozen clock + rejected-network mocks prevent non-determinism or accidental outbound calls. the one asymmetry in key-set checking style for
--explainconsidered rows is a test-design nuance, not a runtime defect.test/cli-output-contracts.test.ts — specifically the
forecast --explainconsidered rows key-set assertion (lines 650-661).Important Files Changed
--explainconsidered rows use exact-key-set matching while regular forecast accounts use a whitelist — could produce misleading failures ifprimaryReasonis ever populated.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[runCli args] --> B[spy console.log / console.error] B --> C[import codex-manager.js fresh via resetModules] C --> D[runCodexMultiAuthCli] D --> E{command} E -->|--help / bare / -h| F[usage text assertions] E -->|status --json| G[exact 9-key top-level] E -->|report --json| H[exact 14-key envelope] E -->|doctor --json| I[exact 5-key envelope] E -->|forecast --json| J[exact 8-key envelope] E -->|forecast --json --explain| K[explanation.considered exact 9-key row set] E -->|why-selected --json populated| L[exact 8-key envelope] E -->|why-selected --json null pool| M[exit 1 ok=false selected=null] F & G & H & I & J & K & L & M --> N[expectNoSecretOrEmailLeak]Prompt To Fix All With AI
Reviews (2): Last reviewed commit: "test(cli): pin why-selected record keys ..." | Re-trigger Greptile