Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

feat(coderd): org-scope chat model config schema - #27547

#27547
Draft
mafredri wants to merge 1 commit into
maincoder/coder:mainfrom
mathias/codagt-709-model-config-org-schemacoder/coder:mathias/codagt-709-model-config-org-schemaCopy head branch name to clipboard
Draft

feat(coderd): org-scope chat model config schema#27547
mafredri wants to merge 1 commit into
maincoder/coder:mainfrom
mathias/codagt-709-model-config-org-schemacoder/coder:mathias/codagt-709-model-config-org-schemaCopy head branch name to clipboard

Conversation

@mafredri

@mafredri mafredri commented Jul 27, 2026

Copy link
Copy Markdown
Member

Stack

  1. This PR (M1: org-scope chat model config schema)
  2. feat: add chat model config RBAC resource #27595 (M2: chat model config RBAC resource)

(#27582, fix(coderd/util/syncmap): LoadOrStore, merged into main and is no longer in the live chain.)

Stage 1 of CODAGT-709: chat_model_configs becomes 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, inert group_acl/user_acl jsonb columns seeded with the everyone-in-org read entry (the Everyone group shares the org ID), and moves the single-default partial unique index from ON ((1)) to ON (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

  • Fallback semantics: the per-org default lookup is strict in SQL; every chat-facing resolution path falls back to the default org until the M3 cutover (marked with TODOs referencing the M3 branch): chatConfigCache.DefaultModelConfig for default resolution, resolveFallbackModelConfigID for admission/edit fallback, and listSpawnableModelConfigs/resolveManualTitleModel for 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.
  • Index predicate: the single-default partial unique index keeps WHERE is_default AND NOT deleted verbatim 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.
  • Seed shape: group_acl is 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.
  • Down-migration constraint (accepted self-review finding F3): the down recreates 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)

  • Migration A: 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); replace idx_chat_model_configs_single_default (ON ((1))) with ON (organization_id) WHERE is_default AND NOT deleted; org index; add group_acl/user_acl jsonb NOT NULL DEFAULT '{}' with jsonb_typeof CHECKs; seed each existing row's group_acl with {"<default-org-id>": {"permissions": ["read"]}} (everyone-in-org read, evaluated later).
  • Queries (queries/chatmodelconfigs.sql): InsertChatModelConfig gains org + ACL columns; GetDefaultChatModelConfig and UnsetDefaultChatModelConfigs gain an org param; new GetEnabledChatModelConfigsByOrg; the unfiltered GetChatModelConfigs/GetEnabledChatModelConfigs remain for the old handlers/availability (deleted in M3).
  • Runtime: configcache.go default-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 pass chat.OrganizationID: resolveModelConfig, resolveFallbackModelConfigID, manual-title selection (chatd.go), listSpawnableModelConfigs (subagent.go), defaultCreateChatModelConfigID/ensureDefaultChatModelConfig (exp_chats.go, default org for now).
  • Old API handlers: create assigns the default org. Everything else behaviorally unchanged.
  • dbgen.ChatModelConfig seeds org (default org takeFirst). dbauthz signatures updated (checks still ResourceDeploymentConfig), MethodTestSuite arg updates.
  • Tests: migration fixture + Stepper backfill test (agents-access test pattern) proving default-org backfill and index swap; configcache per-org keying + fallback tests (unique org IDs, no time.Sleep).
  • Review focus: fallback semantics; index predicate; seed shape.

🤖 This PR was created with the help of Coder Agents, and will be reviewed by a human. 🏂🏻

@linear-code

linear-code Bot commented Jul 27, 2026

Copy link
Copy Markdown

CODAGT-709

@mafredri mafredri changed the title feat(coderd/database): org-scope chat model config schema feat: org-scope chat model config schema Jul 27, 2026
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from e33c123 to 950b82c Compare July 27, 2026 21:48
@mafredri mafredri changed the title feat: org-scope chat model config schema feat(coderd): org-scope chat model config schema Jul 27, 2026
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch 2 times, most recently from 41e7b05 to b52ec0d Compare July 27, 2026 23:02
Comment thread coderd/database/queries/chatmodelconfigs.sql Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/configcache_internal_test.go Outdated
Comment thread coderd/x/chatd/subagent.go Outdated
Comment thread coderd/x/chatd/quickgen.go
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch 2 times, most recently from 44678dc to 56b62a3 Compare July 28, 2026 10:56
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch 4 times, most recently from 6544c4a to da336e7 Compare July 28, 2026 13:10
@mafredri
mafredri changed the base branch from main to mathias/codagt-869-syncmap-loadorstore July 28, 2026 13:17
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from da336e7 to 962cb76 Compare July 28, 2026 13:20
@coder coder deleted a comment from github-actions Bot Jul 28, 2026
@mafredri
mafredri requested review from Copilot and removed request for Copilot July 28, 2026 14:47
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from 962cb76 to 8198ae7 Compare July 28, 2026 14:49
@mafredri

Copy link
Copy Markdown
Member Author

@codex review

This comment was marked as off-topic.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment on lines +8 to +10
CREATE UNIQUE INDEX idx_chat_model_configs_single_default
ON chat_model_configs ((1))
WHERE is_default = true AND deleted = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

  • enabledModelConfigFields claims 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) {

@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from 8198ae7 to 5e74a38 Compare July 28, 2026 15:50
Base automatically changed from mathias/codagt-869-syncmap-loadorstore to main July 28, 2026 16:06
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from 5e74a38 to 0d98dec Compare July 28, 2026 18:10
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from 0d98dec to d933256 Compare July 28, 2026 21:43
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
@mafredri
mafredri force-pushed the mathias/codagt-709-model-config-org-schema branch from d933256 to 50e5c39 Compare July 29, 2026 06:35
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

Morty Proxy This is a proxified and sanitized view of the page, visit original site.