feat(store,server): model registry store + operator write RPC + fail-closed config lint (RIG-3122) - #853
Open
rigel-mintaka wants to merge 1 commit into
Open
Conversation
…closed config lint (RIG-3122) Adds the P2 model registry: a singleton, versioned map of stable model names to ordered provider/model candidate chains, written by an admin-only operator RPC and read back by the same door. This is the routing substrate agent config bundles pin against — a profile references a model by its stable name, and the registry is what resolves that name to a concrete provider candidate at gateway time. ## Store - New `model_registry` table (`0001_init.sql`): singleton `BOOLEAN PRIMARY KEY DEFAULT TRUE CHECK (singleton)` one-row pin (same shape as `agent_config_bundle`), monotonic `version BIGINT`, `registry JSONB`. New in this PR — no legacy rows. - `PutModelRegistry` is compare-and-swap on `version`: `expectedVersion 0` seeds via `INSERT ... ON CONFLICT DO NOTHING` (a lost racing seed maps to `ErrVersionConflict`, never a silent success); `expectedVersion N>0` updates gated on the row still holding `N`. Negative versions rejected up front. - `ValidateModelRegistry` is the pure, DB-free door check the write path runs before any row write (fail-closed): a stable-name key grammar (non-empty, within the per-field byte cap, and free of `/`, `:`, and whitespace — the guard that makes the reverse-lint's `/` escape-hatch and split-on-last-colon tier discriminators *total* over stored keys, design.md §P2 L530-532, L583-585), per-field and aggregate byte caps, entry/candidate count caps, and a reverse orphan lint that fails closed when `PutAgentConfig` publishes a bundle whose profile pins a stable name the registry does not carry (including the unconfigured nil-map case). ## Server - `PutModelRegistry` / `DeleteModelRegistry` / `GetModelRegistry` on the CompassService door. Put/Delete are admin-gated; Get is `authenticatedOpen` (the registry names providers/models, never credentials — same posture as `GetAgentConfigInfo`). The admin-gate classifier fails closed to `adminOnly` for any unclassified procedure, and `classify_exhaustive` reddens CI until a new RPC is classified. - `mapModelRegistryErr` maps `ErrInvalidArgument`→`CodeInvalidArgument`, `ErrVersionConflict`→`CodeAborted` (the CAS-contention convention: re-read and retry), else `CodeInternal`. - Read caps: `CompassService` keeps its 128 MiB `connect.WithReadMaxBytes` (it carries `PutAgentConfig`'s 64 MiB decompressed bundle); the sibling `CommsService` and `SecretsService` mounts on the same network door now carry a 16 MiB cap (`CommsService` is `authenticatedOpen`, so an uncapped mount was strictly more exposed than the admin-gated capped one). Follow-up RIG-3221 tracks the still-uncapped internal RunnerService mount (Kind-gated, narrower exposure). ## Tests pgtest (store + server) and default-gate unit suites: CAS discipline (seed/replace/stale/negative), admin gating (non-admin `PermissionDenied` on both writes, admission on Get), wire error mapping, metadata round-trip with distinct per-field values, malformed-registry rejection (slash/colon/whitespace/newline in the key, oversized fields), stable-name grammar accept/reject, reverse-lint orphan rejection and fail-closed-on-unconfigured, and delete-clear + orphaning-clear at the wire. Spec-impact: none. Refs RIG-3122 Co-authored-by: Matt Wilkinson <matt@rigel.build>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
|
Compass engineering docs preview: https://compass-server-rig-3122-mode.compass-eng-docs.pages.dev Deployed from |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the P2 model registry: a singleton, versioned map of stable model names to ordered provider/model candidate chains, written by an admin-only operator RPC and read back by the same door. This is the routing substrate agent config bundles pin against — a profile references a model by its stable name, and the registry is what resolves that name to a concrete provider candidate at gateway time.
Store
model_registrytable (0001_init.sql): singletonBOOLEAN PRIMARY KEY DEFAULT TRUE CHECK (singleton)one-row pin (same shape asagent_config_bundle), monotonicversion BIGINT,registry JSONB. New in this PR — no legacy rows.PutModelRegistryis compare-and-swap onversion:expectedVersion 0seeds viaINSERT ... ON CONFLICT DO NOTHING(a lost racing seed maps toErrVersionConflict, never a silent success);expectedVersion N>0updates gated on the row still holdingN. Negative versions rejected up front.ValidateModelRegistryis the pure, DB-free door check the write path runs before any row write (fail-closed): a stable-name key grammar (non-empty, within the per-field byte cap, and free of/,:, and whitespace — the guard that makes the reverse-lint's/escape-hatch and split-on-last-colon tier discriminators total over stored keys, design.md §P2 L530-532, L583-585), per-field and aggregate byte caps, entry/candidate count caps, and a reverse orphan lint that fails closed whenPutAgentConfigpublishes a bundle whose profile pins a stable name the registry does not carry (including the unconfigured nil-map case).Server
PutModelRegistry/DeleteModelRegistry/GetModelRegistryon the CompassService door. Put/Delete are admin-gated; Get isauthenticatedOpen(the registry names providers/models, never credentials — same posture asGetAgentConfigInfo). The admin-gate classifier fails closed toadminOnlyfor any unclassified procedure, andclassify_exhaustivereddens CI until a new RPC is classified.mapModelRegistryErrmapsErrInvalidArgument→CodeInvalidArgument,ErrVersionConflict→CodeAborted(the CAS-contention convention: re-read and retry), elseCodeInternal.CompassServicekeeps its 128 MiBconnect.WithReadMaxBytes(it carriesPutAgentConfig's 64 MiB decompressed bundle); the siblingCommsServiceandSecretsServicemounts on the same network door now carry a 16 MiB cap (CommsServiceisauthenticatedOpen, so an uncapped mount was strictly more exposed than the admin-gated capped one). Follow-up RIG-3221 tracks the still-uncapped internal RunnerService mount (Kind-gated, narrower exposure).Tests
pgtest (store + server) and default-gate unit suites: CAS discipline (seed/replace/stale/negative), admin gating (non-admin
PermissionDeniedon both writes, admission on Get), wire error mapping, metadata round-trip with distinct per-field values, malformed-registry rejection (slash/colon/whitespace/newline in the key, oversized fields), stable-name grammar accept/reject, reverse-lint orphan rejection and fail-closed-on-unconfigured, and delete-clear + orphaning-clear at the wire.Spec-impact: none. Refs RIG-3122
Co-authored-by: Matt Wilkinson matt@rigel.build