Skip to content

fix(core): ModelUsage.dayReports loses or corrupts a provider whose id collides with Object.prototype — '__proto__' vanishes, 'constructor' reports NaN #673

Closed

Description

@dezren39

Problem

ModelUsage.dayReports (packages/core/src/model-usage.ts:246-255) accumulates each day's per-provider share in a plain object literal keyed by provider ID:

const providers: Record<string, { requests: number; metered: number; costUsd: number }> = {}
for (const row of dayRows) {
  const current = providers[row.providerID] ?? { requests: 0, metered: 0, costUsd: 0 }
  providers[row.providerID] = { requests: current.requests + row.requests, ... }
}

Provider IDs are user-chosen keys (custom providers are defined by name in config) and reach this function from the recorded route history. Any ID that collides with an Object.prototype member corrupts the report:

  • __proto__ — the read returns the prototype (not the zero record), and the assignment sets the object's prototype instead of an own property: the provider vanishes from the report entirely.
  • constructor, toString, valueOf, hasOwnProperty, … — the read returns the inherited member (a function, not undefined), so current.requests is undefined and the provider's share becomes NaN (serialised as null).

The day totals stay correct (they are summed from the row array, not the record), so the corruption is silent: the per-provider breakdown — the part of the route_usage day report that answers "which provider did this day use" — drops or NaNs one provider's share with no error anywhere.

This is the same collision class the codebase already fixed for config alias resolution in #538, which moved user-keyed copies to Object.fromEntries; this accumulator was not part of that audit.

Evidence (verified this run, main 45e00c8f48)

Laptop bun probe importing the real ModelUsage module (probe at laptop ~/git/fleet/probe-2026-10-27-2335/probe.ts; model-usage.ts md5 cf82532048c7fea28a8257223eb47878, byte-identical on both checkouts):

  • Input rows for one day: anthropic (3 requests), __proto__ (7 requests), constructor (5 requests), each 15 metered tokens / $1.
  • Output providers JSON: {"anthropic":{"requests":3,"metered":15,"costUsd":1},"constructor":{"requests":null,"metered":null,"costUsd":null}} — __proto__ absent (own keys are exactly ["anthropic", "constructor"]), constructor's numbers are NaN.
  • Output day total: requests: 15 — correct, which is why nothing downstream notices.

Existing tests (packages/core/test/model-usage.test.ts, "days group by date and keep each provider's share") cover only openai/anthropic IDs.

Acceptance criteria

  • dayReports reports a correct own entry for provider IDs __proto__, constructor, and toString (requests/metered/cost summed across that provider's rows for the day, including multiple rows with the same colliding ID).
  • Ordinary provider IDs produce exactly the same reports as before, and the returned providers value serialises with JSON.stringify including the colliding IDs.
  • The fix uses a prototype-safe construction (e.g. accumulate in a Map and/or build the record with Object.fromEntries, as fix(core): config alias resolution drops an entry named __proto__ #538 did) rather than blocklisting names.
  • Regression tests in packages/core/test/model-usage.test.ts beside the existing day-grouping test; CI green.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
  3. added
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    app/corePackage: core (pkgs/ or apps/ in this repo)
    effort/xsTrivial: expected under 30 minutes of work
    on Oct 28, 2026
  4. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-opencode)
    • Session / ID: cron new-issue-creator-opencode run 2026-10-28T04:43Z
    • Found via: filed this run
    • Task: Filed this issue after verifying it this run with a laptop bun probe importing the real ModelUsage module: dayReports' plain-object provider accumulator drops a 'proto' provider and NaNs a 'constructor' provider while the day totals stay correct. Enqueued as a small-fix packet for the queue lane; not self-solved.
    • Expectation: effort/xs — done when colliding provider IDs report correct own entries, ordinary IDs are unchanged, and regression tests pass in CI.
    • Links: queue repo-health-opencode-pilot · probe at laptop ~/git/fleet/probe-2026-10-27-2335/probe.ts
  5. added
    work/assignedAn agent holds this item via the queue (claimed task)
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  6. 3 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/claimedA queue worker has claimed the task for this item
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    on Oct 28, 2026
  8. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    🤖 Agent note · merged

  9. removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/corePackage: core (pkgs/ or apps/ in this repo)effort/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobstatus:donetask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions