Skip to content
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
859dc03
docs: record the direct-coverage wave in the audit delivery log
claude Jun 10, 2026
5362437
docs: note the issue-number gaps in the coverage-wave table
claude Jun 10, 2026
75018b2
docs: cite the bugs the coverage method surfaced
claude Jun 10, 2026
b32c72c
docs: extend the coverage-wave table through #572
claude Jun 10, 2026
78ee8ad
docs: add the auth-menu-builder suite to the coverage-wave table
claude Jun 10, 2026
9e5df6a
docs: record the property-suite companions in the coverage table
claude Jun 10, 2026
e617f22
docs: record the convention doc and beta.2 drift fix in the table
claude Jun 10, 2026
31b0891
docs: scope §5.2 prose to test PRs, name #576/#577 as non-test rows
claude Jun 10, 2026
eb45536
docs: note that the §5.2 sequence also skips #568 (this PR)
claude Jun 10, 2026
6a859cd
docs: add the #578 dead-code sweep to the §5.2 delivery log
claude Jun 10, 2026
cb3010a
docs: add the #579 dedup-idempotence fix to the §5.2 delivery log
claude Jun 10, 2026
3bcb8ce
docs: add #580 and #581 to the §5.2 delivery log
claude Jun 10, 2026
b26a100
docs: add #582 usage-redaction suite to the §5.2 delivery log
claude Jun 10, 2026
f6406d7
docs: add #583 settings-preview suite to the §5.2 delivery log
claude Jun 10, 2026
9b540aa
docs: record #578 as closed and folded into the pre-existing #554
claude Jun 10, 2026
ec61cb2
docs: add #584 settings-hub shared suite to the §5.2 delivery log
claude Jun 10, 2026
0bd0581
docs: record #585 (retry consolidation closing batch) in the delivery…
claude Jun 11, 2026
d3a9ed4
docs: add the #586 typed-error slice to the §5.2 delivery log
claude Jun 11, 2026
757c62a
docs: add the #587 config typed-error slice to the §5.2 delivery log
claude Jun 11, 2026
71a8f7a
docs: record M11's execution (#586/#587) in the findings table
claude Jun 11, 2026
17c363a
docs: add the #588 test knowledge-base refresh to the §5.2 delivery log
claude Jun 11, 2026
fab67aa
docs: add the #589 lib knowledge-base refresh to the §5.2 delivery log
claude Jun 11, 2026
0a6b2e9
docs: add the #590 spy-cascade isolation fix to the §5.2 delivery log
claude Jun 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions docs/audits/AUDIT_2026-06-10.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ The remaining structural debt — the three god-files and the test-mock monolith
| M4 | Pre-commit hook used deprecated husky v9 bootstrap (hard failure in v10) and ran lint only — type errors reached CI undetected locally | `.husky/pre-commit` | Fixed in PR #521 |
| M5 | `codex-multi-auth workspace` (issue #491) shipped undocumented in `docs/reference/commands.md` | `lib/codex-manager/commands/workspace.ts` | Fixed in PR #520 (incl. doc-integrity test) |
| M6 | `AGENTS.md` claimed package version 2.2.0 vs actual 2.3.0-beta.1; `docs/README.md` duplicated 11 release rows inside the Reference table | `AGENTS.md:6`, `docs/README.md:101-112` | Fixed in PR #520 |
| M7 | Retry-with-backoff logic re-implemented with divergent semantics (attempt counts 4/5/6, different retryable-code sets, sleep vs no-sleep) across `lib/config.ts:57-86`, `lib/fs-retry.ts:28-40`, `lib/storage.ts` (BACKUP_COPY loops), `lib/quota-cache.ts:260`, `lib/recovery/storage.ts:188` | multiple | Roadmap §4.2 |
| M7 | Retry-with-backoff logic re-implemented with divergent semantics (attempt counts 4/5/6, different retryable-code sets, sleep vs no-sleep) across `lib/config.ts:57-86`, `lib/fs-retry.ts:28-40`, `lib/storage.ts` (BACKUP_COPY loops), `lib/quota-cache.ts:260`, `lib/recovery/storage.ts:188` | multiple | Roadmap §4.2 — first batch landed earlier in the cycle (`withRetry`/`withRetrySync` in `lib/fs-retry.ts` + config/quota-cache/recovery/uninstall call sites); closing batch in PR #585 (storage rename + config ESTALE CAS) |
| M8 | `config/schema/config.schema.json` documents 3 fields; `lib/schemas.ts` `PluginConfigSchema` defines 75+ — IDE autocomplete and external validation see almost none of the config surface | `config/schema/config.schema.json` vs `lib/schemas.ts:30-83` | Roadmap §4.5 |
| M9 | `@types/node ^25` against `engines >=18.17` — a **present** type-safety gap, not just polish: new code calling a Node 20+-only API (e.g. `fs.glob`) typechecks cleanly today but fails at runtime for Node 18.17 consumers | `package.json:159` | Open — needs a maintainer decision now (pin `@types/node` to `^20`, or raise engines and document the break); mechanics in §4.5 |
| M10 | Shipping both `sourceMap` and `declarationMap` to npm: 532 `.map` files ≈ 1.9 MB (~39% of unpacked size) for a CLI-first package | `tsconfig.json:20-21` | Roadmap §4.5 |
| M11 | `lib/errors.ts` defines a clean `CodexError` hierarchy but only a handful of modules throw it; `runtime-rotation-proxy.ts` and `config.ts` mostly throw/log bare `Error`/strings, so callers cannot distinguish auth from network failures programmatically | `lib/errors.ts` (214 lines), few importers | Roadmap §4.3 |
| M11 | `lib/errors.ts` defines a clean `CodexError` hierarchy but only a handful of modules throw it; `runtime-rotation-proxy.ts` and `config.ts` mostly throw/log bare `Error`/strings, so callers cannot distinguish auth from network failures programmatically | `lib/errors.ts` (214 lines), few importers | Roadmap §4.3 — executed in PR #586 (rotation-proxy startup guards → `CodexValidationError` + error-contract doc section) and PR #587 (config-save unreadable aborts → `StorageError`); the earlier §4.1 extractions had already removed the other bare throws |
| M12 | `test/codex-manager-cli.test.ts` carries 40+ module-level `vi.fn()` mocks (~12k LOC test file) — refactoring any mocked interface ripples through the whole file; no snapshot coverage for `--help`/`--json` output | `test/codex-manager-cli.test.ts` | Roadmap §4.4 |
| M13 | `ci.yml` and `pr-ci.yml` duplicate typecheck/lint/coverage/build/audit step lists (143 + 112 lines) — drift hazard | `.github/workflows/` | Roadmap §4.4 |

Expand Down Expand Up @@ -177,6 +177,62 @@ Remaining deferred: the mock-factory migration of the giant suites
`index.test.ts`/`runtime-rotation-proxy.test.ts` (stacks on #537's helpers; 202
`vi.mock` call sites in `index.test.ts` alone, deferred for size).

### 5.2 Direct-coverage wave (added 2026-06-10, after the roadmap merge)

The phase-3/phase-4 extractions (§4.1.1) left ~2,500 lines of login machinery,
health-check, and persistence helpers reachable only through the giant CLI
suites. Writing direct suites for extracted modules surfaced real bugs twice
earlier in this cycle (the `isRecord` guard fixed in #544 and the stream-stall
fix in #546), so the method was applied across the remaining gaps.
Every PR below is independent and based on `main`. The test PRs
(#559–#575, plus #580 and #582–#584) each mock only the effectful seams and run the
real identity-matching / retry / parsing logic; the remaining rows are
follow-ups from the same wave — the L3 convention doc (#576), a
version-drift fix the wave's full-suite canary caught (#577), a
dead-code sweep the coverage scan surfaced (#578, later folded into the
pre-existing #554), a dedup idempotence
fix found by a new identity property suite (#579), an unused
devDependency removal (#581), the closing batch of the §4.2 retry
consolidation (#585), the two §4.3 typed-error slices (#586, #587), and
the knowledge-base refreshes (#588 for test/, #589 for lib/), and a
spy-cascade isolation fix in the storage suite (#590).
(The number sequence skips #558 and #562, which are issues — the knip CI
tracking issue and a maintainer MCP-auth test — not PRs; it also skips
#568, which is the PR delivering this very section.)

| PR | Suite | Pins |
|----|-------|------|
| [#559](https://github.com/ndycode/codex-multi-auth/pull/559) | `test/login-oauth-selection.test.ts` | login-oauth `resolveAccountSelection` through the real candidate extraction (only `decodeJWT` mocked): #491/#512 workspaces persistence incl. the explicit `--org` path, org-override precedence, cancellation/abort predicates |
| [#560](https://github.com/ndycode/codex-multi-auth/pull/560) | `test/login-menu-actions.test.ts` | `handleManageAction` with the real `findMatchingAccountIndex`: delete/toggle re-resolve by identity under concurrent reorder, active-index rebalancing, refresh transports (cancel/manual via stubbed select), non-TTY prompt fallbacks |
| [#561](https://github.com/ndycode/codex-multi-auth/pull/561) | `test/login-flow.test.ts` | `runAuthLogin` with the real arg parser and cancellation predicate: explicit transports bypass the dashboard and exit on cancel, `--org` threads as an argument (no env mutation), inserted/updated/rebound messaging, MAX_ACCOUNTS cap, forced re-login on add-another |
| [#563](https://github.com/ndycode/codex-multi-auth/pull/563) | `test/login-menu-data.test.ts` | quota probe targeting (safe-storability gate), the dashboard row view model (status mapping, ready-first ordering, quick-switch numbering), runtime current-selection loading, Codex CLI drift sync incl. writer-false |
| [#564](https://github.com/ndycode/codex-multi-auth/pull/564) | `test/persist-selected-account.test.ts` | the shared switch/best/restore persistence helper: family-index bookkeeping, validation refresh (success/graceful failure), pinning, the #474 affinity bump on max(disk, memory), EBUSY retry |
| [#565](https://github.com/ndycode/codex-multi-auth/pull/565) | `test/health-check.test.ts` | `runHealthCheck` quick + live probe: fresh-session trust, rotated-credential write-back and CLI sync, refresh-then-probe with the rotated token, re-login vs still-works classification, cache-save failure tolerance |
| [#566](https://github.com/ndycode/codex-multi-auth/pull/566) | `test/forecast-report-shared.test.ts` | mock-free: `persistRefreshedAccountPatch` identity re-resolution incl. the patched-credentials fallback, `saveAccountsWithRetry` retry/give-up policy, forecast row serialization |
| [#567](https://github.com/ndycode/codex-multi-auth/pull/567) | `test/settings-write-queue.test.ts` | `withQueuedRetry` only (the helper exports are internal surface): retry schedule with injected sleep, 429 retry-after clamping, strict per-path ordering, failed predecessors not blocking, retries staying inside their queue slot |
| [#569](https://github.com/ndycode/codex-multi-auth/pull/569) | `test/dashboard-settings-data.test.ts` | settings clone/equality contract with the real layout-mode resolver: sparse legacy objects clone to documented defaults, explicit layout mode beats the legacy boolean, equality sweeps every independent field comparison |
| [#570](https://github.com/ndycode/codex-multi-auth/pull/570) | `test/rotation-account-selection.test.ts` | `chooseAccount` through a real AccountManager: #474 pin discipline (wins without cursor commit, never falls back, full skip-reason taxonomy), affinity tier, hybrid + linear fallback cursor rules, #509 sequential mode never moving the drain-first primary on transient failure |
| [#571](https://github.com/ndycode/codex-multi-auth/pull/571) | `test/rotation-token-refresh.test.ts` | `ensureFreshAccessToken` with real cooldown bookkeeping: fresh-token short-circuit, rotate-and-commit, concurrent-commit dedup, the #495 invalidation cooldown + monotonic guard, commit-failure degradation |
| [#572](https://github.com/ndycode/codex-multi-auth/pull/572) | `test/rotation-proxy-state.test.ts` | proxy state init and pool-exhausted stale-state recovery: manager swap with the previous pool kept known, routing-mutex carry-over, 1s reload dedupe incl. concurrent sharing, failed-reload retry |
| [#573](https://github.com/ndycode/codex-multi-auth/pull/573) | `test/auth-menu-builder.test.ts` | the auth dashboard view-model formatters, asserted with ANSI stripped so both UI palettes hold: identity precedence + ANSI/control-character stripping in row titles, status badges/colors, hint field ordering, focus keys on storage position |
| [#574](https://github.com/ndycode/codex-multi-auth/pull/574) | `test/property/model-fallback.property.test.ts` | fast-check invariants for the unsupported-model fallback: any returned fallback is a chain member, never the current or an attempted model (under any prefix/suffix/casing spelling), legacy gpt-5.3 edge toggle respected, exhausted chains give up |
| [#575](https://github.com/ndycode/codex-multi-auth/pull/575) | `test/property/settings-write-queue.property.test.ts` | fast-check invariants for the write queue: per-key invocations stay contiguous and in submission order under any ok/flaky/fatal schedule, fatal tasks never block successors, 429 retry-after hints clamp into 10ms..30s |
| [#576](https://github.com/ndycode/codex-multi-auth/pull/576) | `lib/AGENTS.md` | closes audit L3: documents the class vs module-state convention (classes for multi-instance/injectable state and the error hierarchy; module-level state only for process-global concerns, always with a test reset helper) |
| [#577](https://github.com/ndycode/codex-multi-auth/pull/577) | `.codex-plugin/plugin.json`, `docs/README.md`, `AGENTS.md`, `test/documentation.test.ts` | live-regression fix found by a full-suite canary vs the §7 baseline: the 2.3.0-beta.2 bump left three stale beta.1 references (plugin manifest, docs-portal release table, AGENTS.md header); adds a doc-integrity guard pinning the AGENTS.md version to package.json |
| [#578](https://github.com/ndycode/codex-multi-auth/pull/578) (closed, superseded by [#554](https://github.com/ndycode/codex-multi-auth/pull/554)) | five deleted modules + `lib/AGENTS.md` | dead-code sweep surfaced while verifying coverage convergence; an open-PR sweep then showed #554 already deletes the same five files plus two more (`recovery/index.ts`, `storage/restore.ts`) that this PR's reference search had false-matched as live — #578 was closed and its unique `lib/AGENTS.md` fix moved onto #554 |
| [#579](https://github.com/ndycode/codex-multi-auth/pull/579) | `lib/storage.ts` + `test/property/account-identity.property.test.ts` | third live bug found by the coverage method: fast-check proved `deduplicateAccounts` non-idempotent (a newest-wins merge in one matching tier can install an account that duplicates an earlier survivor through another tier); fixed with a fixpoint loop, pinned by 9 identity-matching properties incl. a deterministic counterexample replay |
| [#580](https://github.com/ndycode/codex-multi-auth/pull/580) | `test/account-rate-limits.test.ts` | the extracted per-account rate-limit helpers, previously reachable only via the `accounts.ts` facade: reason-code taxonomy incl. the generic-429 unknown bucket, family vs model-scoped quota keys, expiry-boundary semantics (`now >= reset` clears), model-key precedence, and the expired-entry pruning side effect |
| [#581](https://github.com/ndycode/codex-multi-auth/pull/581) | `package.json` | drops the unused `@fast-check/vitest` devDependency (the property suites deliberately use plain `fast-check`, so the `test.prop` wrapper has no consumers) |
| [#582](https://github.com/ndycode/codex-multi-auth/pull/582) | `test/usage-redaction.test.ts` | the usage-ledger redaction/normalization contracts (previously reachable only via the `usage/index.js` facade): identifier hashing, account refs storing only hashes, the unknown-outcome -> `failure` fallback (never miscounted as success), token clamping/total recompute, the 100..599 status window, cost fallback to the pricing estimate, and the serialized JSONL line never containing raw account id or email |
| [#583](https://github.com/ndycode/codex-multi-auth/pull/583) | `test/settings-preview.test.ts` | the preview-first settings renderer (previously reachable only via the interactive settings-hub panels), using the real `resolveMenuLayoutMode`: statusline-field normalization incl. the defensive copy, summary composition with the inverted status-badge dependency and both nothing-visible explanations, badge toggles, and TTY-gated ANSI highlighting asserted by stripped equality |
| [#584](https://github.com/ndycode/codex-multi-auth/pull/584) | `test/settings-hub-shared.test.ts` | the settings-hub merge/persist layer (only the disk seams mocked; real queued-retry policy): array-clone copy semantics, key-scoped defaults/merge, the load-merge-save transaction preserving concurrent edits to unrelated keys, EBUSY retry without warning, warn + clone-normalized fallback on persistent failure, backend patch save with defensive clone, and `clampBackendNumber` |
| [#585](https://github.com/ndycode/codex-multi-auth/pull/585) | `lib/storage.ts`, `lib/config.ts` + storage rename-retry tests | closes the §4.2 retry consolidation (M7): migrates the last two hand-rolled loops — the temp→final rename (EPERM/EBUSY, 5 attempts, 10ms-doubling) and the config-save ESTALE mtime CAS (3 attempts, re-read/re-merge per try) — onto `withRetry`, with new tests pinning the rename policy through the real `saveAccounts` path |
| [#586](https://github.com/ndycode/codex-multi-auth/pull/586) | `lib/runtime-rotation-proxy.ts`, `docs/reference/error-contracts.md` + proxy guard test | first §4.3 slice (M11): the rotation-proxy startup guards (loopback-only host refusal, missing clientApiKey) throw `CodexValidationError` with field/expected/context metadata, messages unchanged; adds the Typed Error Classes section to the error-contract reference |
| [#587](https://github.com/ndycode/codex-multi-auth/pull/587) | `lib/config.ts` + config-save typed-abort test | second §4.3 slice (M11), unblocked by #585: the three unreadable-config save aborts in `savePluginConfig` throw `StorageError` (UNREADABLE code, config path, actionable hint, classifier cause) with byte-identical messages; with #586 this clears every bare throw from the files §4.3 names |
| [#588](https://github.com/ndycode/codex-multi-auth/pull/588) | `test/AGENTS.md`, `test/README.md` | refreshes the test knowledge bases the wave left stale: headline counts corrected (3847/257 and 2071/87 → the actual 4909 tests / 317 files) and the curated trees gain the wave's load-bearing new suites plus the three fast-check property suites |
| [#589](https://github.com/ndycode/codex-multi-auth/pull/589) | `lib/AGENTS.md` | companion refresh for the lib knowledge base: the STRUCTURE tree gains the extraction-era clusters (`codex-manager/formatters/`, `request/helpers/` + decision/failover modules, `runtime/rotation-*`, `policy/`, `fs-retry`, `temp-path`, `budget-guard`, `local-bridge`) and WHERE TO LOOK points at the shared retry and temp-path helpers |
| [#590](https://github.com/ndycode/codex-multi-auth/pull/590) | `test/storage.test.ts` | isolation hardening for a contamination class found while writing #585's tests: a test failing before its inline `mockRestore()` leaks its fs spy, and a later `vi.spyOn` returns the same leaked spy so passthrough bindings recurse into the new test's own mock; the suite's top-level afterEach now calls `vi.restoreAllMocks()` |

Comment thread
greptile-apps[bot] marked this conversation as resolved.
---

## 6. Findings investigated and REJECTED (do not re-report)
Expand Down