You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The chat-cost stack (#27328, #27329, #27330) removed native chat usage limits and native chat cost tracking, leaving AI Gateway data and budgets as the only path. Three physical columns, one table, and one index were deliberately left in place for one release so a replica still running the previous release keeps working during a rolling upgrade.
users.sql and groups.sql use SELECT *, so sqlc bakes every column into explicit column lists in GetUserByID, GetUserByEmailOrUsername, GetUsersByIDs, GetGroupByID, GetGroupByOrgAndName, and GetGroups. Dropping the users and groups columns in the same release would have failed broad authorization, audit, and API-key reads on an old replica, not just the usage-limit admin screens. Dropping chat_messages.total_cost_micros would have broken InsertChatMessages, and therefore every chat message insert.
chat_usage_limit_config and idx_chat_messages_owner_spend were kept for the same reason: an old replica still serves getMyChatUsageLimitStatus, which reads that table through chatd.ResolveUsageLimitStatus and runs GetUserChatSpendInPeriod behind that index. Dropping the table would 500 that handler (it tolerates only sql.ErrNoRows); dropping the index would leave a per-minute-polled path scanning chat_messages.
Nothing in the application reads any of these as of #27330.
Scope
Drop in a single migration:
users.chat_spend_limit_micros and users_chat_spend_limit_micros_check
groups.chat_spend_limit_micros and groups_chat_spend_limit_micros_check
chat_messages.total_cost_micros
chat_usage_limit_config (table, plus its sequence and three check constraints)
idx_chat_messages_owner_spend
Then:
Delete the two "chat_spend_limit_micros": ActionTrack entries in enterprise/audit/table.go (the &database.User{} and &database.AuditableGroup{} maps). They exist only because entry() exits the process at package init for any JSON-tagged field without an action, so they must go with the columns.
Remove the &i.ChatSpendLimitMicros scan from GetAuthorizedUsers in coderd/database/modelqueries.go, which is hand-maintained and must match generated GetUsers.
make gen, then confirm check_constraint.go loses both check constants and the three chat_usage_limit_config ones, unique_constraint.go loses its primary key, and models.go loses both fields and the now-unused ChatUsageLimitConfig struct.
Deleting a migration does not invalidate the mtime-gated dump.sql target, so if the drop is ever reverted, touch a migration that creates the object before regenerating.
Notes
Choose the migration number at authoring time against origin/main, not now. Also note that stacked PRs target their parent branch, so a duplicate migration number passes CI green; compare against origin/main directly before pushing.
Operators who still want their old native caps should read these columns out of the database before this lands. feat: remove native chat usage limits in favor of AI Gateway budgets #27329 did not migrate configured values into group_ai_budgets: period semantics do not map (native supported day/week/month, gateway budgets are month-only), group resolution picks the highest budget where native limits took the minimum, and user_ai_budget_overrides.group_id is NOT NULL so a groupless native user override has no destination.
Context
The chat-cost stack (#27328, #27329, #27330) removed native chat usage limits and native chat cost tracking, leaving AI Gateway data and budgets as the only path. Three physical columns, one table, and one index were deliberately left in place for one release so a replica still running the previous release keeps working during a rolling upgrade.
users.sqlandgroups.sqluseSELECT *, so sqlc bakes every column into explicit column lists inGetUserByID,GetUserByEmailOrUsername,GetUsersByIDs,GetGroupByID,GetGroupByOrgAndName, andGetGroups. Dropping theusersandgroupscolumns in the same release would have failed broad authorization, audit, and API-key reads on an old replica, not just the usage-limit admin screens. Droppingchat_messages.total_cost_microswould have brokenInsertChatMessages, and therefore every chat message insert.chat_usage_limit_configandidx_chat_messages_owner_spendwere kept for the same reason: an old replica still servesgetMyChatUsageLimitStatus, which reads that table throughchatd.ResolveUsageLimitStatusand runsGetUserChatSpendInPeriodbehind that index. Dropping the table would 500 that handler (it tolerates onlysql.ErrNoRows); dropping the index would leave a per-minute-polled path scanningchat_messages.Nothing in the application reads any of these as of #27330.
Scope
Drop in a single migration:
users.chat_spend_limit_microsandusers_chat_spend_limit_micros_checkgroups.chat_spend_limit_microsandgroups_chat_spend_limit_micros_checkchat_messages.total_cost_microschat_usage_limit_config(table, plus its sequence and three check constraints)idx_chat_messages_owner_spendThen:
"chat_spend_limit_micros": ActionTrackentries inenterprise/audit/table.go(the&database.User{}and&database.AuditableGroup{}maps). They exist only becauseentry()exits the process at package init for any JSON-tagged field without an action, so they must go with the columns.&i.ChatSpendLimitMicrosscan fromGetAuthorizedUsersincoderd/database/modelqueries.go, which is hand-maintained and must match generatedGetUsers.make gen, then confirmcheck_constraint.goloses both check constants and the threechat_usage_limit_configones,unique_constraint.goloses its primary key, andmodels.goloses both fields and the now-unusedChatUsageLimitConfigstruct.dump.sqltarget, so if the drop is ever reverted,toucha migration that creates the object before regenerating.Notes
origin/main, not now. Also note that stacked PRs target their parent branch, so a duplicate migration number passes CI green; compare againstorigin/maindirectly before pushing.group_ai_budgets: period semantics do not map (native supported day/week/month, gateway budgets are month-only), group resolution picks the highest budget where native limits took the minimum, anduser_ai_budget_overrides.group_idisNOT NULLso a groupless native user override has no destination.