Skip to content

feat(ai-overage): Claude Team per-seat overage → class_ai_overage → cc_overage bullet - #1371

Merged
mozhaev-dev merged 9 commits into
mainfrom
feat/ai-overage-silver
Jun 19, 2026
Merged

feat(ai-overage): Claude Team per-seat overage → class_ai_overage → cc_overage bullet#1371
mozhaev-dev merged 9 commits into
mainfrom
feat/ai-overage-silver

Conversation

@mozhaev-dev

@mozhaev-dev mozhaev-dev commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What

Introduces AI overage end-to-end for Anthropic / Claude Team: a new unified Silver class class_ai_overage (per-person-per-month spend over the monthly credit limit) surfaced all the way to a Gold AI bullet cc_overage.

Designed homogeneous so OpenAI/ChatGPT can join later by emitting the same contract (deferred by PM for now).

Layers

  • Silver — new class class_ai_overage (19-col positional contract) + first contributor claude_team__ai_overage from the existing claude_team_overage_spend stream (now unblocked: the proxy sessionKey has Owner/billing:view, so /overage_spend_limits returns all 149 seats).
    • Bronze stream gains scalar fields currency / out_of_credits / used_credits_basis / limit_type; promoted to RMT.
    • Units: used_credits / monthly_credit_limit are already cents (USD) → mapped straight to *_cents, no ×100 (unlike cost_cents). overage_cents = max(0, used − limit), honest-NULL when no limit.
    • Grain: latest snapshot per (seat, billing month); month in unique_key preserves history.
  • Goldai_bullet_rows Branch 6 → cc_overage; classified sum in both rollups (query_ref Path A and ai_person_period Path B — the AI bullet metrics: ai_person_period rolls up Codex/cc counters as daily-avg (and PRs as fake zeros) — wrong period aggregation #1286 defect class).
  • analytics-apiquery_ref extended (22→23 keys, honest-NULL guarded, averaged per person like cc_cost) + metric_catalog seed (label "Claude Overage", unit ¢, lower-is-better, good ≤ 0¢ / warn ≤ 5000¢). Guard test updated to cover the new key.
  • Docs/specsclass_ai_overage added to the AI coverage matrix; claude-team PRD/DESIGN/FEATURE reconciled (were Bronze-only); descriptor 1.2.0 → 1.3.0.

Validation

  • cargo test migration86 passed, 0 failed.
  • Local e2e on kind-insight with real data (149 seats): bronze 149 → silver 149 (formula invariant 0 violations, 33 dbt tests) → gold 148 cc_overage (honest-NULL) → ai_person_period sum-classification functionally proven (314 vs avg-bug 157) → analytics-api migrate on MariaDB clean (probes green) → exact stored query_ref vs ClickHouse returns cc_overage = 2.317¢, 23 keys, no regression.

Paired FE

Renders the cc_overage bullet (catalog-driven): constructorfabric/insight-front feat/ai-overage-frontend.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added AI overage spending tracking at per-person, per-month granularity above credit limits
    • Claude Team connector now ingests overage spend and publishes the cc_overage metric (USD, cents)
    • Seeded metric catalog metadata and thresholds for cc_overage to enable it in analytics views
  • Bug Fixes
    • Updated period rollups so cc_overage aggregates as a summing counter (not average)
  • Documentation
    • Refreshed Silver-layer specs and clarified Claude Team Bronze MVP scope for overage
  • Tests
    • Added/updated validations to ensure cc_overage is mapped end-to-end and classified correctly

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fea206e5-ea80-4550-a4bb-900ade5e291d

📥 Commits

Reviewing files that changed from the base of the PR and between 7fc849e7e0eba768da9d00fa9b3dc5513d2aabad and 18f8eae.

📒 Files selected for processing (17)
  • docs/components/connectors/ai/README.md
  • docs/components/connectors/ai/claude-team/specs/DESIGN.md
  • docs/components/connectors/ai/claude-team/specs/FEATURE.md
  • docs/components/connectors/ai/claude-team/specs/PRD.md
  • src/backend/services/analytics-api/src/migration/m20260610_000001_fix_ai_label_drift.rs
  • src/backend/services/analytics-api/src/migration/m20260618_000001_ai_claude_team_overage_metric.rs
  • src/backend/services/analytics-api/src/migration/m20260618_000002_seed_claude_team_overage_catalog.rs
  • src/backend/services/analytics-api/src/migration/mod.rs
  • src/ingestion/connectors/ai/claude-team/connector.yaml
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__bronze_promoted.sql
  • src/ingestion/connectors/ai/claude-team/dbt/schema.yml
  • src/ingestion/connectors/ai/claude-team/descriptor.yaml
  • src/ingestion/scripts/create-bronze-placeholders.sh
  • src/ingestion/scripts/migrations/20260618000000_ai-claude-team-overage-gold.sql
  • src/ingestion/silver/ai/class_ai_overage.sql
  • src/ingestion/silver/ai/schema.yml
✅ Files skipped from review due to trivial changes (5)
  • docs/components/connectors/ai/claude-team/specs/FEATURE.md
  • docs/components/connectors/ai/claude-team/specs/DESIGN.md
  • src/ingestion/connectors/ai/claude-team/descriptor.yaml
  • docs/components/connectors/ai/claude-team/specs/PRD.md
  • docs/components/connectors/ai/README.md
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/ingestion/connectors/ai/claude-team/connector.yaml
  • src/ingestion/scripts/create-bronze-placeholders.sh
  • src/backend/services/analytics-api/src/migration/mod.rs
  • src/ingestion/silver/ai/class_ai_overage.sql
  • src/ingestion/scripts/migrations/20260618000000_ai-claude-team-overage-gold.sql
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__bronze_promoted.sql
  • src/backend/services/analytics-api/src/migration/m20260610_000001_fix_ai_label_drift.rs
  • src/ingestion/silver/ai/schema.yml
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql
  • src/ingestion/connectors/ai/claude-team/dbt/schema.yml
  • src/backend/services/analytics-api/src/migration/m20260618_000002_seed_claude_team_overage_catalog.rs
  • src/backend/services/analytics-api/src/migration/m20260618_000001_ai_claude_team_overage_metric.rs

📝 Walkthrough

Walkthrough

Adds end-to-end support for a new cc_overage (Claude Team per-seat monthly credit overage) metric. Changes span Bronze stream schema extension, a new Silver class_ai_overage dbt model, Gold ClickHouse view updates (ai_bullet_rows, ai_person_period), two new SeaORM analytics-api migrations (query_ref update and metric catalog seed), and corresponding architecture documentation.

Changes

Claude Team cc_overage metric pipeline

Layer / File(s) Summary
Silver class_ai_overage contract, schema, and placeholder setup
src/ingestion/silver/ai/class_ai_overage.sql, src/ingestion/silver/ai/schema.yml, src/ingestion/scripts/create-bronze-placeholders.sh
New incremental dbt model that unions all upstream models tagged silver:class_ai_overage into a ReplacingMergeTree table; schema.yml defines the full 19-column contract (identity, monetary, and flag fields) with column-level tests; placeholder table created early to satisfy ClickHouse view dependencies.
Bronze stream schema extension and claude_team__ai_overage dbt model
src/ingestion/connectors/ai/claude-team/connector.yaml, src/ingestion/connectors/ai/claude-team/dbt/schema.yml, src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql
Extends claude_team_overage_spend stream schema with nullable fields (currency, out_of_credits, used_credits_basis, limit_type); registers the stream as a dbt source; adds the claude_team__ai_overage incremental model (dedup CTE + overage/flag computation with per-month idempotency).
Bronze RMT promotion and connector versioning
src/ingestion/connectors/ai/claude-team/dbt/claude_team__bronze_promoted.sql, src/ingestion/connectors/ai/claude-team/descriptor.yaml
Promotes claude_team_overage_spend Bronze table to ReplacingMergeTree via the promotion bootstrap; bumps connector descriptor from v1.2.0 to v1.3.0 and documents the new overage data feed and its mapping to Silver class_ai_overage.
Gold ClickHouse view migration
src/ingestion/scripts/migrations/20260618000000_ai-claude-team-overage-gold.sql
Recreates insight.ai_bullet_rows with a new UNION branch emitting metric_key='cc_overage' from silver.class_ai_overage (filtered to Claude Team source and non-NULL overage); recreates insight.ai_person_period updating the multiIf classifier to add cc_overage to the sum(metric_value) aggregation branch.
analytics-api query_ref migration
src/backend/services/analytics-api/src/migration/m20260618_000001_ai_claude_team_overage_metric.rs
New SeaORM migration updating metrics.query_ref for Team and IC bullet views: adds cc_overage_v with honest-NULL guard to wide-aggregate SQL, appends cc_overage to the ARRAY JOIN unpivot (23 keys total), and wires it as a counter metric. Includes tests for key cardinality, ACTIVE_LIST exclusion, NULL-guard pattern, and regressions.
analytics-api catalog seed, test updates, and migration registry
src/backend/services/analytics-api/src/migration/m20260618_000002_seed_claude_team_overage_catalog.rs, src/backend/services/analytics-api/src/migration/m20260610_000001_fix_ai_label_drift.rs, src/backend/services/analytics-api/src/migration/mod.rs
New SeaORM migration seeds metric_catalog and metric_threshold rows for cc_overage (unit ¢, higher_is_better=false, source_tags=["claude_team"]). Updates existing migration test constants to add cc_overage to SUM_KEYS and BULLET_ROWS_KEYS with a dedicated test. Registers both new migrations in mod.rs.
Architecture docs and connector specifications
docs/components/connectors/ai/README.md, docs/components/connectors/ai/claude-team/specs/DESIGN.md, docs/components/connectors/ai/claude-team/specs/FEATURE.md, docs/components/connectors/ai/claude-team/specs/PRD.md
Updates AI connector README to list class_ai_overage as a 6th core Silver class with a comprehensive spec block; revises claude-team DESIGN.md, FEATURE.md, and PRD.md to reflect that Silver/Gold transformations have landed with explicit model-to-class mappings and computation semantics.

Sequence Diagram(s)

sequenceDiagram
  participant Airbyte
  participant Bronze as bronze_claude_team.claude_team_overage_spend
  participant StagingModel as claude_team__ai_overage
  participant Silver as silver.class_ai_overage
  participant Gold as insight.ai_bullet_rows / ai_person_period
  participant API as analytics-api metrics.query_ref

  Airbyte->>Bronze: ingest overage_spend rows
  Bronze->>StagingModel: dedup to latest snapshot per (account_uuid, month)
  StagingModel->>StagingModel: compute overage_cents, is_over_limit, overage_metrics_json
  StagingModel->>Silver: union_by_tag insert (tagged silver:class_ai_overage)
  Silver->>Gold: ai_bullet_rows UNION branch emits metric_key=cc_overage
  Gold->>Gold: ai_person_period classifies cc_overage as sum(metric_value)
  Gold->>API: query_ref ARRAY JOIN includes (cc_overage, cc_overage_v)
  API->>API: metric_catalog seeded with cc_overage thresholds
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • constructorfabric/insight#1286: The multiIf classifier in insight.ai_person_period is updated to include cc_overage in the sum(metric_value) branch, directly addressing the stale metric-key classification problem documented in that issue.

Suggested reviewers

  • mitasovr

Poem

🐰 A new metric hops into the warren today,
cc_overage tracks what the credits say!
From Bronze to Silver the data flows neat,
Gold views and catalog rows — oh what a feat!
The rabbit stamps ¢ on every spent cent,
And sums it up monthly with clear intent. 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: introducing Claude Team per-seat overage tracking through a new class_ai_overage data model and cc_overage metric bullet.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/ai-overage-silver

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.

@mozhaev-dev

Copy link
Copy Markdown
Contributor Author

Paired FE PR: constructorfabric/insight-front#167 (renders the cc_overage bullet).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/components/connectors/ai/README.md (1)

201-213: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language tags to fenced code blocks (Line 201 and Line 333).

These new fences are missing a language identifier and trigger MD040.

Proposed fix
-```
+```text
 silver/
 ├── ai/
 │   ├── class_ai_dev_usage         (per-person-day code activity)
 │   ├── class_ai_assistant_usage   (per-person-day chat/cowork/office/web)
 │   ├── class_ai_api_usage         (per-key-or-project-day tokens + multi-modal API)
 │   ├── class_ai_cost              (per-line-item-day financial — org/project total)
 │   ├── class_ai_overage           (per-person-month spend-over-limit — BUILT: Claude Team)
 │   └── class_ai_audit_log         (event-stream — admin actions, compliance)
 └── _shared/
     ├── class_people               (existing) — identity unification
     └── class_ai_directories?      (optional — skills, connectors, projects metadata)

```diff
-```
+```text
 insight_tenant_id, source_id, unique_key, email, account_id
 period_month, tool, seat_tier, currency
 credit_limit_cents, used_amount_cents, overage_cents   -- minor units (cents); overage = max(0, used − limit), honest-NULL if no limit
 is_over_limit, is_enabled, overage_metrics_json
 source, data_source, collected_at, _version
</details>


Also applies to: 333-339

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/components/connectors/ai/README.md around lines 201 - 213, Add the
language identifier text to the two fenced code blocks that are missing
language tags. The first block contains the directory tree structure starting
with "silver/" and includes class definitions like class_ai_dev_usage and
class_ai_assistant_usage. The second block (also mentioned at line 333) contains
field names like insight_tenant_id, source_id, and period_month. Change both
opening fences from triple backticks with no language to triple backticks
followed by text to resolve the MD040 linting error.


</details>

<!-- cr-comment:v1:d83b6511e9223367f898d08e -->

_Source: Linters/SAST tools_

</blockquote></details>

</blockquote></details>
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/backend/services/analytics-api/src/migration/m20260618_000002_seed_claude_team_overage_catalog.rs`:
- Around line 175-177: The assert_eq! macro call within the seed_count_is_one()
test function violates rustfmt formatting standards due to line length. Reformat
the assert_eq! macro invocation to comply with Rust's standard formatting
guidelines by breaking it into multiple lines with proper indentation, or run
cargo fmt --all to automatically apply the correct formatting to the entire
file.

In `@src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql`:
- Around line 42-53: The deduplication in the latest_per_seat_month CTE uses
only account_uuid and the month from _airbyte_extracted_at in the LIMIT 1 BY
clause, but this does not match the model's full grain which also includes
tenant_id and source_id. This causes records to be incorrectly dropped when the
same account_uuid appears across different tenants or sources within the same
month. Modify the LIMIT 1 BY clause to include tenant_id and source_id alongside
account_uuid and toStartOfMonth(_airbyte_extracted_at) to ensure deduplication
respects the complete model grain and prevents cross-source row loss.

---

Outside diff comments:
In `@docs/components/connectors/ai/README.md`:
- Around line 201-213: Add the language identifier `text` to the two fenced code
blocks that are missing language tags. The first block contains the directory
tree structure starting with "silver/" and includes class definitions like
class_ai_dev_usage and class_ai_assistant_usage. The second block (also
mentioned at line 333) contains field names like insight_tenant_id, source_id,
and period_month. Change both opening fences from triple backticks with no
language to triple backticks followed by `text` to resolve the MD040 linting
error.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cf155300-c004-4199-b724-3147300dad74

📥 Commits

Reviewing files that changed from the base of the PR and between c32821d and 6bb2c83e74df9459571d50c6974d2b637687812c.

📒 Files selected for processing (16)
  • docs/components/connectors/ai/README.md
  • docs/components/connectors/ai/claude-team/specs/DESIGN.md
  • docs/components/connectors/ai/claude-team/specs/FEATURE.md
  • docs/components/connectors/ai/claude-team/specs/PRD.md
  • src/backend/services/analytics-api/src/migration/m20260610_000001_fix_ai_label_drift.rs
  • src/backend/services/analytics-api/src/migration/m20260618_000001_ai_claude_team_overage_metric.rs
  • src/backend/services/analytics-api/src/migration/m20260618_000002_seed_claude_team_overage_catalog.rs
  • src/backend/services/analytics-api/src/migration/mod.rs
  • src/ingestion/connectors/ai/claude-team/connector.yaml
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql
  • src/ingestion/connectors/ai/claude-team/dbt/claude_team__bronze_promoted.sql
  • src/ingestion/connectors/ai/claude-team/dbt/schema.yml
  • src/ingestion/connectors/ai/claude-team/descriptor.yaml
  • src/ingestion/scripts/migrations/20260618000000_ai-claude-team-overage-gold.sql
  • src/ingestion/silver/ai/class_ai_overage.sql
  • src/ingestion/silver/ai/schema.yml

Comment thread src/ingestion/connectors/ai/claude-team/dbt/claude_team__ai_overage.sql Outdated
@mozhaev-dev

Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit review in df12eeb5:

  • dbt dedup grain (claude_team__ai_overage.sql) — LIMIT 1 BY now keys on the full grain tenant_id, source_id, account_uuid, toStartOfMonth(...) so a multi-tenant / multi-instance bronze_claude_team no longer drops same-account_uuid rows across tenants/sources. No behaviour change for single-tenant (local e2e: 149 → 149 silver rows).
  • MD040 — added text language to the two bare code fences in docs/.../ai/README.md.
  • rustfmtcargo fmt on the two touched migration files; cargo fmt --check clean.

Re-validated: cargo test migration → 86 passed, 0 failed.

mozhaev-dev and others added 8 commits June 18, 2026 17:51
Introduce class_ai_overage — a unified per-person per-month AI
spend-vs-limit (overage) Silver class — and wire Claude Team as its
first contributor. Designed homogeneous so OpenAI/ChatGPT seats can
join later by emitting the same 19-column positional contract under
tag silver:class_ai_overage (vendor extras → overage_metrics_json,
never new columns).

Claude Team (now unblocked: the proxy sessionKey has Owner role, so
/overage_spend_limits returns 200 with all 149 per-seat rows):
- bronze claude_team_overage_spend gains scalar fields currency /
  out_of_credits / used_credits_basis / limit_type (confirmed live)
- promote claude_team_overage_spend to RMT (ADR-0002)
- claude_team__ai_overage.sql: bronze → Silver contributor. Grain =
  latest snapshot per (seat, billing month); unique_key carries the
  month so a new month never overwrites a prior month's closing value.
  UNITS: used_credits / monthly_credit_limit are already cents (USD) —
  mapped straight to *_cents with NO ×100 (unlike cost_cents in
  claude_team__ai_dev_usage). overage_cents = max(0, used - limit),
  honest-NULL when no limit is known.
- class_ai_overage.sql: union_by_tag('silver:class_ai_overage')
- schema.yml docs/tests for both layers
- descriptor 1.2.0 → 1.3.0 (additive; populates only with billing:view/Owner)

Validated: dbt parse + ls green; tag:claude-team+ now builds the
overage chain; tag:silver:class_ai_overage resolves to the contributor.
Will populate on the next claude-team sync (Bronze table created with
0 rows when the session lacked billing:view).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
Address non-blocker review notes on the class_ai_overage introduction:

- docs: add class_ai_overage to the AI coverage matrix
  (docs/components/connectors/ai/README.md) — coverage-by-class row,
  silver-layer split tree, and a dedicated subsection next to
  class_ai_cost explaining the distinction (cost = org/project total
  financial; overage = per-person spend above their own monthly limit),
  the 19-col contract, units, month grain, and per-provider feeding
  (Claude Team BUILT; OpenAI/Windsurf future). Notes Claude Team is the
  first live source despite predating the matrix's column set.
- tests: currency gains accepted_values ['USD'] on both staging and
  silver (extend when a non-USD billing tenant appears).
- tests: used_amount_cents gains not_null on silver (always populated;
  mirrors staging). email stays nullable on silver by design — future
  OpenAI seats attribute via account_id without email (same precedent as
  class_ai_dev_usage silver email).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
Take Claude Team overage from Silver up to the metric API so the
frontend can render it. Adds metric_key `cc_overage` (per-seat spend
above the monthly credit limit, in cents).

- Gold: 20260618000000_ai-claude-team-overage-gold.sql — DROP+CREATE
  insight.ai_bullet_rows with a new Branch 6 reading
  silver.class_ai_overage (source='claude_team'): emits cc_overage =
  overage_cents, dated at toDate(collected_at) so the current month's
  snapshot lands inside the dashboard's rolling window (period_month's
  1st would miss short windows). Branches 1–5 unchanged. honest-NULL:
  only rows with a computable overage (overage_cents NOT NULL) are
  emitted; within-limit seats emit a real 0.
- analytics-api m20260618_000001: extend Team/IC Bullet AI query_ref
  with cc_overage_v — countIf-guarded sumIf (honest-NULL like prs),
  NOT in ACTIVE_LIST → averaged per person over the period like cc_cost.
  22 → 23 metric_keys. Shape tests added.
- analytics-api m20260618_000002: seed metric_catalog + product-default
  threshold for cc_overage — label "Claude Overage", unit ¢,
  higher_is_better=false, good ≤ 0¢ / warn ≤ 5000¢. Tests added.
- Register both migrations in migration/mod.rs.

Validated: cargo test migration → 85 passed, 0 failed.
FE (cyber-insight-front bullet-layout-groups) is the paired change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
Review gap: cc_overage was added to the query_ref rollup (Path A) but
not to the parallel ai_person_period period-rollup (Path B), so it
silently defaulted to avg() — the exact issue #1286 defect class. For a
monthly overage snapshot, avg divides by each person's active-day count
(understated), while a per-period spend counter must sum.

- Gold migration 20260618000000 now also DROP+CREATEs
  insight.ai_person_period with cc_overage added to the sum branch
  (twin of cc_cost). Counters→sum, active→max, ratios→avg preserved.
- Guard test m20260610_000001: add cc_overage to SUM_KEYS and to the
  emitted-key list BULLET_ROWS_KEYS (branch 6) so
  every_bullet_key_is_classified_not_defaulting_to_avg actually covers
  it; add a focused cc_overage_sums_like_cc_cost spot-check. Documented
  that the emitted-key list is hand-maintained (false-green risk for any
  future gold branch key not added here).

cargo test migration → 86 passed, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
The PRD/DESIGN/FEATURE described claude-team as Bronze-only
(`dbt_select: ''`, "No Silver, no Gold") but Silver has since landed:
`claude_team__ai_dev_usage` → class_ai_dev_usage (INSIGHT-458) and now
`claude_team__ai_overage` → class_ai_overage (Gold bullet `cc_overage`,
descriptor 1.3.0). Update DESIGN §4.4, PRD §3.2 non-goals, and FEATURE
§1 to state Silver landed and point to the cross-connector contract.

Verified end-to-end locally on kind-insight with real overage data
(149 seats from the dev proxy, Owner role): bronze 149 → silver 149
(formula invariant 0 violations, 33 dbt tests) → gold 148 cc_overage
(honest-NULL) → ai_person_period sum-classified (proven 314 vs avg 157)
→ analytics-api migrations applied to MariaDB (probes green) → stored
query_ref run against CH returns cc_overage=2.317¢, 23 keys, no regression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
- claude_team__ai_overage: LIMIT 1 BY now includes tenant_id + source_id
  (was account_uuid + month only) so a multi-tenant / multi-instance
  bronze_claude_team doesn't drop same-account_uuid rows across tenants
  /sources as false duplicates — matches the model's full grain. No
  behaviour change for single-tenant (local e2e: 149 → 149).
- docs README: add `text` language to two bare code fences (MD040).
- cargo fmt the two touched migration files.

Re-validated: cargo test migration 86 passed; fmt --check clean;
dbt re-run on local CH still 149 silver rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
…d view

The ai_bullet_rows cc_overage branch (20260618000000_ai-claude-team-overage-gold.sql)
does CREATE VIEW ... FROM silver.class_ai_overage. CH 24.x validates a view's
source tables at CREATE time, so in any env where migrations run before dbt
builds the silver model (E2E, fresh deploy) the view creation fails with
Code 60 UNKNOWN_TABLE and aborts the whole migration step.

Mirrors the existing class_ai_dev_usage / class_support_activity placeholders:
an empty ReplacingMergeTree(_version) table tagged INSIGHT_PLACEHOLDER_v1 (dropped
and rebuilt by dbt via drop_silver_placeholders_at_start). Columns match the
claude_team__ai_overage staging output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
Backtick the bare identifiers (claude_team, ComingSoon, cc_overage, cc_cost,
silver.class_ai_overage) in the m20260618_* overage migration doc comments and
the m20260610_000001 entries touched by this PR. `cargo clippy --all-targets`
runs with -D warnings, so these tripped doc_markdown and failed Lint & Test.
Doc-comment-only change (clippy --fix); 97 migration tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Mozhaev <mozhaev.dev@gmail.com>
@mozhaev-dev
mozhaev-dev force-pushed the feat/ai-overage-silver branch from 7fc849e to e104962 Compare June 18, 2026 14:53
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.

2 participants