Skip to content

fix(claude-team): read seat spend before the billing month closes - #2526

Merged
Gregory91G merged 7 commits into
mainfrom
fix-seat-spend-month-tail
Aug 18, 2026
Merged

fix(claude-team): read seat spend before the billing month closes#2526
Gregory91G merged 7 commits into
mainfrom
fix-seat-spend-month-tail

Conversation

@Gregory91G

Copy link
Copy Markdown
Contributor

Closes #2525. Part of #2479.

/api/organizations/{org}/overage_spend_limits reports the billing month in progress and carries no history. A month's spend is therefore frozen at the last read that happened inside it, and everything after that read is lost for good — the next sync answers for the new month and cannot go back.

Reading at 04:00 UTC dropped the last twenty hours of every month by construction. A failed or missing run on the last day dropped a day more.

Measured against the reference implementation

July, 145 seats, compared per address:

Our total $12,780.60
Reference $13,415.12
Short by $634.52 — 4.7%
Non-zero seats agreeing to the cent 44 of 57
Disagreeing 13, every one of them short, never over

Our final read of July landed 2026-07-30 04:02 UTC — 44 hours unread. June's landed 2026-06-24, leaving 164 hours.

The transformation is exact: joining bronze to silver over the same month gives zero mismatches on both the amount and the ceiling. Nothing is miscomputed; the rows simply stop before the month does.

What lands

  • descriptor.yaml50 23 * * * instead of 0 4 * * *, leaving ten minutes of a month unread instead of twenty hours. Still off-peak: the other connectors occupy 02:00-06:00 and 11:00, and the customer's proxy runs a single browser instance. Both streams tolerate the move — the code-metrics stream walks a trailing window and re-reads it, so it is unaffected by the hour.
  • assert_ai_overage_read_before_the_month_closed — a warning when the month that just closed was last read more than six hours before it ended. The schedule puts the final read ten minutes before the boundary; one failed run there makes it a day. Only the just-closed month is judged: an open month is still being read, and an older one can be neither re-read nor acted on.

No descriptor version bump: the reconciler applies the CronWorkflow unconditionally (kubectl apply, no-op when unchanged — lib/reconcile.sh), and ADR-0015's semver governs the connector's spec and data shape, neither of which moves here.

Test plan

  • dbt parse — clean; the new test is in the manifest as test.ingestion.assert_ai_overage_read_before_the_month_closed.
  • The check's SQL run against a populated instance: returns exactly one row — July, last read 2026-07-30 04:02, hours_unread = 44. It catches the defect that prompted it.
  • The same SQL after the current month closes returns nothing once a read lands near the boundary, which is what the six-hour line is for.
  • pre-commit run --files on both paths — yamlfmt and the file-hygiene hooks pass.

An earlier draft of the check aliased the closed month to period_month in its SELECT; the alias shadowed the column, the WHERE compared the alias with itself, and every month collapsed into one group whose latest read belonged to the open month — inverting the result to a silent pass. The comment in the file records it so the shape is not reintroduced.

The seat endpoint reports the month in progress and carries no history, so a
month's spend freezes at the last read inside it and everything after that read
is lost permanently — a later sync answers for the new month and cannot go back.

Reading at 04:00 UTC therefore dropped the last twenty hours of every month by
construction, and a failed run on the last day dropped a day more. Measured on a
populated instance: July's final read landed 2026-07-30 04:02 UTC, leaving 44
hours unread, and the month came out $634.52 short of the reference
implementation's $13,415.12 — 13 of the 57 seats with a non-zero amount, every
one of them short rather than over. June's final read was 2026-06-24, leaving
164 hours.

23:50 leaves ten minutes instead of twenty hours, and stays off-peak: the other
connectors occupy 02:00 to 06:00 and 11:00, and the customer's proxy runs a
single browser instance. Both of this connector's streams tolerate the move —
the code-metrics stream walks a trailing window and re-reads it.

The check names the same failure as a warning on the month that just closed,
because losing the tail is silent otherwise: nothing else notices that a figure
is short, and no re-sync can fix it once the month is over.

Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
@Gregory91G
Gregory91G requested a review from a team as a code owner August 14, 2026 02:55
@Gregory91G Gregory91G self-assigned this Aug 14, 2026
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1a90ae18-cc0f-41a3-ad2f-646f1658882e


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.

@Gregory91G

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Gregory91G

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@hello1101n

Copy link
Copy Markdown
Contributor

failed checks

…LECT

The comment explaining why `closed_month` is not aliased sat between two SQL
tokens and used trimming Jinja delimiters. `{#-` eats the whitespace before the
tag and `-#}` the whitespace after, so the rendered SQL read
`closed_monthSELECT` and ClickHouse rejected the check with SYNTAX_ERROR.

An erroring data test fails the whole dbt build, so the ai shard lost the
ai_cost and seat-history fixtures with it — three red tests, one cause. The
source file looks correct; only the compiled SQL shows the defect.

Untrimmed delimiters keep the newline. The comment stays where it is: it
explains the line below it, and moving it would cost the reader the reason.

Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
…h-tail

Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>

# Conflicts:
#	src/ingestion/connectors/ai/claude-team/descriptor.yaml
@Gregory91G
Gregory91G added this pull request to the merge queue Aug 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 17, 2026
@hello1101n
hello1101n enabled auto-merge August 17, 2026 16:43
@hello1101n
hello1101n added this pull request to the merge queue Aug 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 17, 2026
…h-tail

Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>

# Conflicts:
#	src/ingestion/connectors/ai/claude-team/descriptor.yaml
…h-tail

Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
@Gregory91G
Gregory91G added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 2d1872a Aug 18, 2026
61 checks passed
@Gregory91G
Gregory91G deleted the fix-seat-spend-month-tail branch August 18, 2026 17:49
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.

Claude Team seat spend loses the tail of every billing month

2 participants