Skip to content

fix: normalize new /teams/spend response shape - #23

Merged
ofershap merged 2 commits into
ofershap:mainfrom
alex-pex:fix/teams-spend-shape-19
Oct 6, 2026
Merged

ofershap merged 2 commits into
ofershap:mainfrom
alex-pex:fix/teams-spend-shape-19

Conversation

@alex-pex

Copy link
Copy Markdown
Contributor

Fixes #19.

Changes

1. Normalize the new /teams/spend response shape

Cursor changed /teams/spend: spendCents is now the overage above the plan, the cycle total moved to overallSpendCents, and includedSpendCents is gone. The collector crashed with NOT NULL constraint failed: spending.included_spend_cents, and even past that it would have stored 0 spend for every user within plan.

getSpending now normalizes each member so downstream code keeps its contract:

  • spendCents = overallSpendCents ?? spendCents (cycle total)
  • includedSpendCents = includedSpendCents if present, otherwise max(0, total - overage)

Pre-2026 responses keep working. Tests cover both shapes, and .cursor/rules/cursor-api.mdc documents the new response.

2. Fix the top-model query in getUserCostDrivers

The query filters on ue.timestamp (shared dateFilter) but selected FROM usage_events without the ue alias, so SQLite threw no such column: ue.timestamp. getUserCostDrivers is used by the z-score and trend detectors, so anomaly detection failed. Includes a regression test. This is a separate bug from #19; happy to split it into its own PR if you prefer.

Credits

Commit 1 is based on @mcobery's work in #21 (closed unmerged), reduced to the minimal fix: no .vscode/launch.json, no fetch error wrapping, no extra upsertSpending defaults (the normalization already guarantees the values) and no unused MemberSpend fields. He is credited as co-author.

Checks

npm run typecheck, npm run lint, npm test and npm run build pass on Node 22.

Note: #22 touches some of the same files.

alex-pex and others added 2 commits September 29, 2026 22:20
Cursor's /teams/spend now returns spendCents as the overage above the plan,
exposes the cycle total as overallSpendCents and no longer sends
includedSpendCents. The collector crashed with a NOT NULL violation on
spending.included_spend_cents and would have stored 0 spend for users
within plan.

Normalize each member so spendCents stays the cycle total and
includedSpendCents is derived (total - overage), keeping pre-2026
responses working. Tests cover both shapes.

Fixes ofershap#19.

Based on Marc Cobery's f15dab2 (proposed in ofershap#21, closed unmerged).

Co-authored-by: Marc Cobery <coberym@ae.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The top-model query filtered on `ue.timestamp` (via the shared dateFilter)
but selected FROM usage_events without the `ue` alias, so SQLite failed
with "no such column: ue.timestamp". getUserCostDrivers is used by the
z-score and trend detectors, so anomaly detection broke.

Alias the table and qualify the selected/grouped column, and add a
regression test.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ofershap
ofershap merged commit 768d6a1 into ofershap:main Oct 6, 2026
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.24.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

collect fails on /teams/spend: NOT NULL on included_spend_cents + wrong spend amounts (API shape changed)

2 participants