feat(coderd): org-scope chat model config schema - #27547
#27547feat(coderd): org-scope chat model config schema#27547mafredri wants to merge 1 commit intomaincoder/coder:mainfrom mathias/codagt-709-model-config-org-schemacoder/coder:mathias/codagt-709-model-config-org-schemaCopy head branch name to clipboard
Conversation
e33c123 to
950b82c
Compare
41e7b05 to
b52ec0d
Compare
44678dc to
56b62a3
Compare
6544c4a to
da336e7
Compare
da336e7 to
962cb76
Compare
962cb76 to
8198ae7
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8198ae7613
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| CREATE UNIQUE INDEX idx_chat_model_configs_single_default | ||
| ON chat_model_configs ((1)) | ||
| WHERE is_default = true AND deleted = false; |
There was a problem hiding this comment.
Make the downgrade handle per-org defaults
When more than one organization has a live default, which the new schema explicitly permits, recreating this deployment-wide unique index fails with a duplicate-key error before organization_id can be dropped. This makes migration 556 impossible to roll back after valid per-org data has been created; collapse or unset the extra defaults before creating the old index.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 31 changed files in this pull request and generated no new comments.
Files not reviewed (7)
- coderd/database/check_constraint.go: Generated file
- coderd/database/dbmetrics/querymetrics.go: Generated file
- coderd/database/dbmock/dbmock.go: Generated file
- coderd/database/foreign_key_constraint.go: Generated file
- coderd/database/models.go: Generated file
- coderd/database/querier.go: Generated file
- coderd/database/unique_constraint.go: Generated file
Comments suppressed due to low confidence (2)
coderd/x/chatd/quickgen.go:169
enabledModelConfigFieldsclaims the type switch is unreachable due to a closed union constraint, but the current default path silently returns empty values. If the constraint is ever widened or refactored, this will fail open and can cause incorrect model selection without an obvious error. Prefer a hard failure (panic) to make any unexpected row type immediately visible during tests and runtime.
func enabledModelConfigFields[T enabledModelConfigsRow](row T) (string, database.ChatModelConfig) {
switch row := any(row).(type) {
case database.GetEnabledChatModelConfigsRow:
return row.Provider, row.ChatModelConfig
case database.GetEnabledChatModelConfigsByOrganizationRow:
return row.Provider, row.ChatModelConfig
}
// Unreachable: the constraint is a closed union.
return "", database.ChatModelConfig{}
coderd/x/chatd/subagent_internal_test.go:4783
- The test name says the non-default org "sees" default-org configs, but the assertions verify the opposite (default-org configs must NOT leak when the org has its own config). Renaming will prevent confusion when reading test failures or search results.
func TestListSubagentModels_NonDefaultOrgSeesDefaultOrgConfigs(t *testing.T) {
8198ae7 to
5e74a38
Compare
5e74a38 to
0d98dec
Compare
0d98dec to
d933256
Compare
Stage 1 of CODAGT-709: chat_model_configs gains organization_id (FK organizations, ON DELETE CASCADE) backfilled to the default org, plus inert group_acl/user_acl jsonb columns seeded with the everyone-in-org read entry. The single-default partial unique index moves from ON ((1)) to ON (organization_id) with its predicate unchanged, and an org lookup index is added. Runtime behavior stays deployment-wide: the chatd default-config cache is keyed by org with a default-org fallback (removed at the cutover), old create/update/delete handlers pin every write to the default org, and authorization checks are unchanged. The per-org query variants (GetDefaultChatModelConfig, UnsetDefaultChatModelConfigs, GetEnabledChatModelConfigsByOrg) are consumed by chatd so orgs stop leaking into each other's resolution once rows diverge at the explosion stage. Refs CODAGT-709
d933256 to
50e5c39
Compare
Stack
(#27582,
fix(coderd/util/syncmap): LoadOrStore, merged into main and is no longer in the live chain.)Stage 1 of CODAGT-709:
chat_model_configsbecomes organization-owned at the schema level while every release behavior stays byte-identical.Migration 000557 adds
organization_id(FK organizations,ON DELETE CASCADE) backfilled to the default org, inertgroup_acl/user_acljsonb columns seeded with the everyone-in-org read entry (the Everyone group shares the org ID), and moves the single-default partial unique index fromON ((1))toON (organization_id)with its predicate unchanged. Runtime stays deployment-wide: the chatd default-config cache is keyed by org with a default-org fallback (removed at the M3 cutover), and the old create/update/delete handlers pin every write to the default org, seeding the everyone-read ACL entry at create time so configs created before the cutover remain visible to members once ACLs are enforced.Authorization checks are unchanged (
ResourceDeploymentConfig); only method signatures gain the org parameter. The per-org query variants are consumed by chatd resolution paths (default resolution, fallback resolution, manual-title selection, subagent spawn list) so resolution cannot leak across orgs once rows diverge at the explosion stage.One note for the M3 author: the down migration recreates the deployment-wide single-default index, which can only build while at most one live default exists. That holds at this stage (all configs live in the default org); the cutover's down must account for it.
Review focus
chatConfigCache.DefaultModelConfigfor default resolution,resolveFallbackModelConfigIDfor admission/edit fallback, andlistSpawnableModelConfigs/resolveManualTitleModelfor the enabled catalog (empty org catalog substitutes the default org's). Dedicated tests cover per-org keying, fallback hit, no-recurse on default-org miss, no cross-org leak, and non-default-org resolution.WHERE is_default AND NOT deletedverbatim and only gains the org key; the Stepper test asserts a second live default in the default org is rejected while a second org hosts its own.group_aclis keyed by the org ID itself, relying on the Everyone-group invariant (group id == org id, migration 000058); nested{"permissions": ["read"]}shape matching the chats table ACLs.idx_chat_model_configs_single_default ON ((1)), which fails to build once multiple orgs each hold a live default. Safe at this stage; M3's down must handle it.Refs CODAGT-709
Plan excerpt (CODAGT-74, unit M1)
M1
feat(coderd/database): org-scope chat model config schema(base: main)ALTER TABLE chat_model_configs ADD COLUMN organization_id uuid REFERENCES organizations(id) ON DELETE CASCADE; backfill all rows to the default org (000467 recipe: nullable, UPDATE, SET NOT NULL); replaceidx_chat_model_configs_single_default(ON ((1))) withON (organization_id) WHERE is_default AND NOT deleted; org index; addgroup_acl/user_acl jsonb NOT NULL DEFAULT '{}'withjsonb_typeofCHECKs; seed each existing row'sgroup_aclwith{"<default-org-id>": {"permissions": ["read"]}}(everyone-in-org read, evaluated later).queries/chatmodelconfigs.sql):InsertChatModelConfiggains org + ACL columns;GetDefaultChatModelConfigandUnsetDefaultChatModelConfigsgain an org param; newGetEnabledChatModelConfigsByOrg; the unfilteredGetChatModelConfigs/GetEnabledChatModelConfigsremain for the old handlers/availability (deleted in M3).configcache.godefault-config cache keyed by org (map, coarse invalidation on any model-config event);DefaultModelConfig(orgID)looks up the chat's org, falls back to the default org when empty (fallback removed in M3, marked with a TODO referencing M3's branch). Callers passchat.OrganizationID:resolveModelConfig,resolveFallbackModelConfigID, manual-title selection (chatd.go),listSpawnableModelConfigs(subagent.go),defaultCreateChatModelConfigID/ensureDefaultChatModelConfig(exp_chats.go, default org for now).dbgen.ChatModelConfigseeds org (default org takeFirst). dbauthz signatures updated (checks stillResourceDeploymentConfig), MethodTestSuite arg updates.time.Sleep).