Skip to content

docs(health): document field-name drift vs ManagedAccount (AUDIT-M08)#408

Merged
ndycode merged 1 commit intomainfrom
refactor/health-unify
Apr 17, 2026
Merged

docs(health): document field-name drift vs ManagedAccount (AUDIT-M08)#408
ndycode merged 1 commit intomainfrom
refactor/health-unify

Conversation

@ndycode
Copy link
Copy Markdown
Owner

@ndycode ndycode commented Apr 17, 2026

Summary

Documents the field-name drift between lib/health.ts and lib/accounts.ts's ManagedAccount in an explicit in-file comment. This closes the audit's observability gap (AUDIT-M08 / D-04) without a breaking API change.

Problem

Audit (docs/audits/MASTER_AUDIT.md §6 MEDIUM AUDIT-M08 / dim-D-routing.md D-04) identified that getAccountHealth() in lib/health.ts uses parameter field names that do not exactly match ManagedAccount:

getAccountHealth input ManagedAccount field
rateLimitedUntil computed from rateLimitResetTimes per family
cooldownUntil coolingDownUntil
lastUsedAt lastUsed
health computed from getHealthTracker().getScore()

The drift is not a bug — the function is a pure shape-transformation utility and callers are responsible for the flattening. But the mismatch was silent and not discoverable from the code.

Why not Oracle's recommended fix?

Oracle's options were "reads from tracker state directly OR module deleted":

  • Delete — breaks external consumers. The module is exported via lib/index.ts and documented as public API for dashboards / diagnostics / JSON exporters.
  • Change signature to take AccountManager — also breaks public API.
  • Add a parallel getPluginHealthFromManager(manager) — plausible, but no internal consumer today; adding it would duplicate the shape-transformation logic without a live caller.

The pragmatic fix is documentation: make the drift discoverable from the code, and give future implementers explicit guidance on how to add a direct-from-manager bridge safely when an internal consumer eventually needs one.

Change

lib/health.ts gets a multi-line comment block before the exported interfaces that:

  1. States the module is a pure shape-transformation utility by design.
  2. Lists the exact field-name mapping between getAccountHealth input and ManagedAccount.
  3. Tells future contributors what to do if they want a direct-from-manager variant: add getPluginHealthFromManager(manager), do NOT change the existing signature.

No code changes. No behavioral change. No new dependencies.

Verification

  • Full suite: 225/225 test files, 3418/3418 tests pass (docs-only change)
  • npm run typecheck exit 0
  • npm run lint exit 0

Audit reference

  • docs/audits/MASTER_AUDIT.md §6 MEDIUM AUDIT-M08
  • docs/audits/evidence/dim-D-routing.md D-04
  • docs/audits/evidence/oracle-verdicts.md §1.2

Scope guarantees

  • ✅ Documentation-only — zero code / API changes
  • ✅ Field-name drift is now discoverable from the code
  • ✅ Future implementers have explicit guidance for adding a live-manager bridge
  • ✅ Full test suite green

Follow-up

Phase 1 remaining architectural work:

  • PR-L — Zod at storage JSON.parse boundaries (R3)
  • PR-M — settings-hub split (R1, large)
  • PR-N — routing mutex + SelectionRecord (R4, depends on L)
  • PR-P — CLI why-selected + verify --paths features (F1, F2)

Tracked in .sisyphus/plans/phase1-implementation.md.

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

documentation-only change adds a module-level comment block to lib/health.ts that codifies the field-name drift between the getAccountHealth input shape and ManagedAccount (AUDIT-M08 / D-04). the four-row mapping table is accurate against lib/accounts.ts, the export claim matches lib/index.ts, and the guidance for a future getPluginHealthFromManager bridge is sound. no code, no behavior, no api changes.

Confidence Score: 5/5

safe to merge — docs-only, zero behavioral or api change, all field mappings verified correct

no code changes; the four documented field-name mappings are accurate against lib/accounts.ts; the public-api export claim is confirmed via lib/index.ts; existing test suite unaffected; all p2 or lower

no files require special attention

Important Files Changed

Filename Overview
lib/health.ts adds a 27-line audit docstring before the exported interfaces; all four field-name mappings verified accurate against lib/accounts.ts and the public-api export claim matches lib/index.ts

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    MA["ManagedAccount\n(lib/accounts.ts)"]
    ADAPTER["caller adapter\n(flatten to input shape)"]
    GH["getAccountHealth(accounts[])"]
    AH["AccountHealth[]"]

    MA -->|"lastUsed → lastUsedAt"| ADAPTER
    MA -->|"coolingDownUntil → cooldownUntil"| ADAPTER
    MA -->|"rateLimitResetTimes (per-family) → rateLimitedUntil"| ADAPTER
    MA -->|"getHealthTracker().getScore() → health"| ADAPTER
    ADAPTER --> GH
    GH --> AH
Loading

Reviews (1): Last reviewed commit: "docs(health): document field-name drift ..." | Re-trigger Greptile

…/ D-04)

The master audit (dim-D-routing.md D-04, AUDIT-M08) flagged that
lib/health.ts uses field names that do not exactly match
ManagedAccount in lib/accounts.ts — specifically:

  getAccountHealth input   ManagedAccount field
  ----------------------   --------------------
  rateLimitedUntil         <computed from rateLimitResetTimes per family>
  cooldownUntil            coolingDownUntil
  lastUsedAt               lastUsed
  health                   <computed from getHealthTracker().getScore()>

Oracle's recommended fix was either "reads from tracker state directly
OR module deleted". Neither is appropriate here:

- Deleting would break external consumers (the module is exported via
  lib/index.ts and documented as public API).
- Changing the signature would also break public API.
- Adding a parallel `getPluginHealthFromManager(manager)` function is
  plausible but has no internal consumer today and would duplicate the
  shape-transformation logic.

The pragmatic fix is to DOCUMENT the drift explicitly in the module so
the next contributor who reads this code understands the design
choice: this is a PURE SHAPE-TRANSFORMATION UTILITY that deliberately
takes a flattened input so callers can build it from any source. The
comment also calls out the exact field-name mappings and tells future
implementers what to do if they want a direct-from-manager variant
(add a new function, do NOT change the existing signature).

This closes the audit's observability gap (the drift is now
discoverable from the code) without a breaking change. When an
internal consumer eventually needs a direct-from-manager bridge, the
guidance in the comment tells them exactly how to add it safely.

Closes AUDIT-M08 / D-04 (health module field-name drift vs live
AccountManager state) at the documentation level.

Evidence: 225/225 test files, 3418/3418 tests pass (docs-only change).
typecheck + lint exit 0. No new dependencies, no API changes.
@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
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 17, 2026

📝 Walkthrough

Severity: Minor (Documentation-only)

This PR adds a module-level comment to lib/health.ts documenting the deliberate field-name drift between the getAccountHealth() input shape and ManagedAccount, addressing audit finding AUDIT-M08. The change is purely documentary with no code logic, behavioral changes, or API modifications—all 3,418 tests pass and there are no security, data-loss, or test coverage risks.

Summary

Adds a multi-line in-file comment explaining:

  • The module's design as a pure shape-transformation utility
  • The exact field-name mappings between getAccountHealth inputs and ManagedAccount fields
  • A directive for future contributors to add a new getPluginHealthFromManager(manager) function rather than modifying the existing exported signature

Verification

Full test suite: 225/225 files, 3,418/3418 tests passing; npm typecheck and lint both exit cleanly.

Walkthrough

module-level docstring added to lib/health.ts documenting the getAccountHealth function's shape-transformation behavior, expected field mapping, and public api status with deprecation guidance. no executable code modified.

Changes

Cohort / File(s) Summary
Documentation
lib/health.ts
Added 28-line module-level docstring describing getAccountHealth as pure shape-transformation utility, documenting input-to-output field mappings, marking function as public api (via lib/index.ts), and instructing against signature changes without deprecation cycle.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format (docs(scope): summary), is 69 chars, uses lowercase imperative, and accurately summarizes the documentation addition.
Description check ✅ Passed Description includes comprehensive summary, problem statement, rationale, change details, verification results, and scope guarantees. Validation checklist present but unchecked; however, PR author confirms all checks passed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/health-unify
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch refactor/health-unify

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/health.ts`:
- Around line 4-30: The docstring documents field-name mappings between
ManagedAccount and the public getAccountHealth input but offers no compile-time
guarantee; add a type-level regression test that imports type ManagedAccount and
the getAccountHealth function and constructs the getAccountHealth input directly
from a ManagedAccount instance (e.g., a small function like
testFieldMapping(managed: ManagedAccount) { getAccountHealth([ { index:
managed.index, email: managed.email, accountId: managed.accountId, refreshToken:
managed.refreshToken, health: managed.getHealthTracker().getScore(),
rateLimitedUntil: /* map from managed.rateLimitResetTimes */, cooldownUntil:
managed.coolingDownUntil, cooldownReason: managed.cooldownReason, lastUsedAt:
managed.lastUsed } ]) } ) so any rename in ManagedAccount will break compilation
and surface the drift.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 575a893f-8901-44e4-8311-ffe00c886ca2

📥 Commits

Reviewing files that changed from the base of the PR and between 1f6da97 and b47789a.

📒 Files selected for processing (1)
  • lib/health.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/health.ts
🔇 Additional comments (1)
lib/health.ts (1)

4-30: the field mappings in the docstring are accurate and properly tested.

verified against the actual code:

  • lastUsedAtlastUsed confirmed (lib/accounts.ts:245)
  • rateLimitedUntilrateLimitResetTimes confirmed (lib/accounts.ts:253)
  • cooldownUntilcoolingDownUntil confirmed (lib/accounts.ts:254)
  • health input field used throughout (test/health.test.ts validates it across multiple scenarios)

export via lib/index.ts:25 confirmed. no token/email leaks in the docstring. tests in test/health.test.ts cover all field mappings with green results.

Comment thread lib/health.ts
Comment on lines +4 to +30
// AUDIT-M08 / D-04 docstring (master repository audit, Oracle-confirmed):
// --------------------------------------------------------------------------
// This module is a PURE SHAPE-TRANSFORMATION UTILITY. Callers pass an
// already-flattened accounts array with the fields defined in the public
// `getAccountHealth` parameter shape below. It is deliberately decoupled
// from the live AccountManager: that keeps the function easy to test, and
// lets external consumers (dashboards, diagnostics scripts, JSON exporters)
// build the input from any source without taking a hard dependency on the
// manager singleton.
//
// HOWEVER, the parameter shape uses field names that do NOT exactly match
// ManagedAccount in lib/accounts.ts:
//
// getAccountHealth input ManagedAccount field
// ---------------------- --------------------
// rateLimitedUntil <computed from rateLimitResetTimes per family>
// cooldownUntil coolingDownUntil
// lastUsedAt lastUsed
// health <computed from getHealthTracker().getScore()>
//
// Callers are responsible for flattening ManagedAccount → the input shape
// via a small adapter. If a future refactor wants a single call site that
// reads straight from AccountManager, add a `getPluginHealthFromManager(
// manager: AccountManager): PluginHealth` function here and implement the
// flattening inline. Do NOT change the signature of the existing
// `getAccountHealth` function without a deprecation cycle — it is exported
// via lib/index.ts and is considered public API.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

docstring improves observability but doesn't prevent future drift.

the comment correctly documents the current field-name mappings (verified lastUsedAtlastUsed at lib/health.ts:80), but the audit gap will reopen if someone renames fields in ManagedAccount without updating this comment.

consider adding a type-level test or assertion that forces a compile error if the mappings diverge. for example, in your test suite, add a static check that constructs the input shape from a ManagedAccount instance to catch renames.

🔒 example type-level test to prevent drift

add to your test file:

// type-level regression test for AUDIT-M08 field mapping
import type { ManagedAccount } from '../lib/accounts.js';
import { getAccountHealth } from '../lib/health.js';

// this will fail to compile if ManagedAccount renames fields
// without updating the adapter
function testFieldMapping(managed: ManagedAccount) {
  getAccountHealth([{
    index: managed.index,
    email: managed.email,
    accountId: managed.accountId,
    refreshToken: managed.refreshToken,
    health: managed.getHealthTracker().getScore(), // computed
    rateLimitedUntil: managed.rateLimitResetTimes?.['family']?.resetAt, // computed
    cooldownUntil: managed.coolingDownUntil, // renamed field
    cooldownReason: managed.cooldownReason,
    lastUsedAt: managed.lastUsed, // renamed field
  }]);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/health.ts` around lines 4 - 30, The docstring documents field-name
mappings between ManagedAccount and the public getAccountHealth input but offers
no compile-time guarantee; add a type-level regression test that imports type
ManagedAccount and the getAccountHealth function and constructs the
getAccountHealth input directly from a ManagedAccount instance (e.g., a small
function like testFieldMapping(managed: ManagedAccount) { getAccountHealth([ {
index: managed.index, email: managed.email, accountId: managed.accountId,
refreshToken: managed.refreshToken, health:
managed.getHealthTracker().getScore(), rateLimitedUntil: /* map from
managed.rateLimitResetTimes */, cooldownUntil: managed.coolingDownUntil,
cooldownReason: managed.cooldownReason, lastUsedAt: managed.lastUsed } ]) } ) so
any rename in ManagedAccount will break compilation and surface the drift.

@ndycode ndycode merged commit e647545 into main Apr 17, 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.

1 participant