Thanks to visit codestin.com
Credit goes to github.com

Skip to content

test(cli): pin machine-readable output contracts - #533

Merged
ndycode merged 2 commits into
mainfrom
claude/audit-11-cli-output-contracts
Jun 10, 2026
Merged

ndycode merged 2 commits into
mainfrom
claude/audit-11-cli-output-contracts

Conversation

@ndycode

@ndycode ndycode commented Jun 10, 2026

Copy link
Copy Markdown
Owner

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

Surface Contract pinned
--help / bare / -h exit 0, identical output, all 29 documented command lines + 6 section headers (explicit assertions — repo has no inline-snapshot convention)
status --json exact top-level key set + per-account row keys and types
report --json exact key set incl. nested modelSelection/liveProbeBudget/forecast shapes; generatedAt equals the frozen instant; 1-based activeIndex
doctor --json key set, summary {error,ok,warn}, per-check shape + severity enum, and summary.error > 0 → exit 1
forecast --json key set; explanation only with --explain; per-account allowed keys; cached-mode absence of liveQuota/refreshFailure
why-selected --json populated key set + the documented empty-pool contract: exit 1, ok:false, selected:null

Leak assertions on every surface: stdout/stderr never contain the fixture token secrets and never match an email pattern (fixtures deliberately omit emails since status echoes 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.ts mock harness, fixed two-account V3 fixture, Date frozen via fake timers, refresh/probe mocks reject and are asserted un-called (no network possible).

Deliberately skipped (already covered)

status/list --json plumbing, why-selected field 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=0
  • 8/8 passing across 3 consecutive runs (determinism)
  • test/codex-manager-cli.test.ts still 201/201 (shared harness unbroken)
  • Independently re-verified: 8/8

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), and why-selected --json. this closes the audit roadmap §4.4.3 gap and also addresses two gaps flagged in the previous review round (missing forecast --explain coverage and missing key-set guards on why-selected candidate/selected records).

  • frozen clock, rejected-network mocks, and distinctive token secrets ensure the suite is deterministic and any accidental network call or token leak fails loudly.
  • the --explain considered rows use an exact key-set check (sortedKeys(row).toEqual([...])) that excludes primaryReason, while the regular forecast --json account loop uses an allowed-keys whitelist that includes primaryReason as optional — this inconsistency could cause a misleading failure if any considered row ever carries a primaryReason.
  • no windows filesystem operations are performed (everything is mocked), so no ebusy/eperm risk here.

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 --explain considered rows is a test-design nuance, not a runtime defect.

test/cli-output-contracts.test.ts — specifically the forecast --explain considered rows key-set assertion (lines 650-661).

Important Files Changed

Filename Overview
test/cli-output-contracts.test.ts New 768-line contract test file pinning JSON key sets, types, exit codes, and leak guards for 6 CLI surfaces; well-structured with frozen clock, rejected-network mocks, and per-surface assertions. Minor inconsistency: --explain considered rows use exact-key-set matching while regular forecast accounts use a whitelist — could produce misleading failures if primaryReason is 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]
Loading

Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
test/cli-output-contracts.test.ts:650-662
`--explain` considered rows use exact key-set matching, but regular `forecast` accounts use a whitelist that allows the optional `primaryReason` field. If `buildForecastExplanation` (or its shared builder) ever populates `primaryReason` for any account — e.g. when an account has a cooldown or rate-limit reason — this assertion fails with a key-set mismatch rather than a meaningful contract regression. Either switch to the same allowed-keys whitelist used for forecast accounts (and add `"primaryReason"` to it), or add a comment stating that `considered` rows intentionally omit `primaryReason` and the implementation enforces that invariant.

Reviews (2): Last reviewed commit: "test(cli): pin why-selected record keys ..." | Re-trigger Greptile

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
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e94a5a23-87f2-411b-a1a2-c76d46ade5db

📥 Commits

Reviewing files that changed from the base of the PR and between 98d9819 and 7d3f288.

📒 Files selected for processing (1)
  • test/cli-output-contracts.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-11-cli-output-contracts
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-11-cli-output-contracts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread test/cli-output-contracts.test.ts
Comment thread test/cli-output-contracts.test.ts
…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
@ndycode
ndycode merged commit 28bcc39 into main Jun 10, 2026
2 checks passed
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.

2 participants