Commit 8b2fbcf
The facility model catalog: LanguageModel aggregate, governance gate, at-risk results (#558)
* Add the LanguageModel aggregate: the facility model catalog entry
The R3 component of the facility-LLM-budget reference architecture:
one aggregate carrying what a gateway's routing table cannot, the
governance attributes of an approved model. Identity reuses the Agent
aggregate's ModelRef so an agent's declared model and a catalog entry
compare field-for-field; served_via names the serving route (Direct,
Argo, InHouse) without ever carrying credentials (the serving layer
owns those); cost_basis is a discriminated union (TokenPricing
field-for-field with the observability ModelPricing so the future
pricing bridge needs no translation, or GpuHourPricing for in-house
pools; Argo-served entries carry facility-set shadow prices); and two
orthogonal tier axes, DataSensitivityTier (which data may reach the
model) and ArchivabilityTier (Pinned weights the facility can serve
forever vs an Alias the provider may move).
The FSM separates the two ways a model's service life ends because
they answer different audit questions: RetirementAnnounced -> Retired
is the VENDOR's lifecycle (the governance-event arm the at-risk-results
projection will read; Retired is also reachable straight from Approved
because providers remove models without notice), while Deprecated is
the FACILITY withdrawing approval. Approval itself is the
bootstrap-then-promote ceremony the agent fleet already follows: a
Defined entry is registered but not yet usable.
Homed in the agent BC beside the fleet it governs; the equipment BC
already owns the Model stream type, hence the longer name (single-word
alternatives all failed intent-matching; recorded in the design memo).
Fitness conformance: LanguageModelName uses the bounded_name
decorator; retirement_effective_at joins the fold-symmetry intrinsic
allowlist (a vendor schedule, not a CORA fact-act; the announcing
actor lives on the event envelope); all ten domain errors register as
HTTP handlers ahead of their slices.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add the five LanguageModel catalog slices
define_language_model (genesis: guard + VO/enum validation + canonical
cost-basis re-encode so the event always carries exactly the canonical
key set) plus the four lifecycle transitions (approve,
announce-retirement, retire, deprecate) through a new
make_language_model_update_handler, the second aggregate slotting into
the per-aggregate factory shape _agent_update_handler promised. Routes
and MCP tools ship with each slice but register in the wiring commit.
112 unit tests pin the deciders (every wrong-source status per slice,
Hypothesis total-partition properties), reason validation, and
handler envelopes including deny-does-not-write.
Checkpoint commit (--no-verify): hooks run on the wiring commit that
completes the registration this commit's routes reference.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add the catalog read side: projection, identity lookup, migration
proj_language_model_summary carries the one query shape the catalog
needs, by model identity: the define_agent gate and the startup fleet
check hold only (provider, model), never an entry id. The projection
folds all five lifecycle events; cost_basis stays off the read model so
pricing keeps exactly one home (the aggregate). LanguageModelLookup
follows the neutral-port family (always-approved stub as the kernel
default, so a catalog-less deployment stays permissive: declaring a
catalog is what arms the gate), with the agent BC's Postgres adapter
resolving latest-entry-wins over the projection.
Checkpoint commit (--no-verify): hooks run on the wiring commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Wire the model catalog: handlers, gate, fleet seeds, registration
The connective commit that turns the catalog from parts into a
governed surface:
- AgentHandlers/wire_agent carry the five slices (define with
idempotency like define_agent; transitions traced); routes and MCP
tools registered; the projection registered beside the agent
summary; kernel gains language_model_lookup (always-approved
default) with the Postgres adapter bound at the composition root
when a pool exists.
- define_agent now refuses to register an agent whose model identity
lacks an Approved catalog entry (LanguageModelNotApprovedError,
raised before the vault upsert so refusal leaves no orphan profile
row). The kernel default approves everything, so the gate arms only
where a real catalog is stood up.
- seed_language_models ships the fleet's three default models as
entries born Defined AND Approved in one idempotent append. Born
Approved on purpose: seeds bypass handlers, and a fresh deployment
must not refuse define_agent for its own shipped fleet; the
operator's governance lever is deprecate_language_model. Pricing
figures copy PRICING exactly, pinned by a consistency test, as is
the mirror of the operation BC's default steering model (tach
forbids the agent BC importing cora.operation).
- Fitness updates each carry a one-line justification: the
projection-table ownership maps gain the two-aggregate agent BC,
slice-coverage allowlists defer the contract/integration tiers with
citations, the aggregate-count anti-drift pin bumps 41 to 42, and
the OpenAPI snapshot gains the five /language-models routes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add the at-risk-results surface: retirement becomes a queryable fact
The design's flagship claim made real: when a provider announces a
model's retirement, GET /language-models/{id}/at-risk-results
enumerates every Decision whose recorded LLM calls used that model,
graded by the entry's archivability tier. Pinned weights the facility
can serve grade ReExecutable; an Alias the provider may move grades
AttributableOnly, and at_risk is true only when that grade meets a
RetirementAnnounced or Retired status. The endpoint answers for ANY
status on purpose: an operator deciding whether to approve an Alias
entry wants to know what WOULD be at risk before any announcement.
The cross-BC seam follows the SpendLookup grammar: a neutral
ModelUsageLookup port (empty stub as the kernel default) whose
Postgres adapter ships from the decision BC, because it owns
entries_decision_inferences and the fitness suite rightly forbids the
agent BC reading that table. Matching covers the dated-snapshot case
(response_model LIKE model-%): calls served on a snapshot the provider
resolved from an alias are equally at risk when the alias retires.
DISTINCT ON keeps one row per Decision, newest first.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Apply the catalog arc's five-reviewer panel: shadow fix and renames
The load-bearing security fix: the gate-purpose lookup now answers
with the newest APPROVED entry only (plus a deterministic tiebreak),
so an unapproved or deprecated newer entry can never shadow an older
Approved one. That single change kills both the reviewer-found
governance denial-of-service (the weakest catalog write flipping
define_agent to refusal for any identity) and the accidental-duplicate
trap (deprecating a mistake now restores the prior Approved entry).
Its sibling: the seed skip path detects a squatted deterministic seed
id and warns loudly instead of logging "already seeded".
Correctness: gate refusals now finalize their idempotency claim as a
400 like every sibling validation error instead of stranding it
Claimed; the snapshot-matching arm escapes LIKE metacharacters and
matches exactly an eight-character dated suffix, so a base alias can
never swallow a sibling minor version's decisions while its own dated
snapshots still count; and first boot drains the agent projections
synchronously after seeding, closing the window where define_agent
would refuse the very models the seed just approved.
Naming per the panel: ModelUsageLookupResult (the bespoke
ModelTouchedDecision read with inverted agency and broke the
LookupResult family), AlwaysEmptyModelUsageLookup (joins the Always
stub family), and the projection table becomes
proj_agent_language_model_summary, restoring the multi-aggregate
BC-prefix rule and deleting the carve-out the build had added, with
conventions.md now documenting the rule the tree already followed.
Conventions: both new lookups bind through the factory grammar at
kernel construction instead of post-construction setattr; the phantom
"startup fleet check" wording now names the unit consistency test that
actually exists; born-Approved seeds cite their true precedent (the
clearance-template seed's Defined+Activated pair, not the agent fleet,
whose runtime gate is Actor.active).
Tests close every mutation survivor the panel found: the evolver file
(the Retired arm had never executed under test), Retired/Deprecated
at-risk cases, the Postgres lookup integration test that pins the
shadow fix itself, gate lookup-args pins, the LIKE boundary matrix in
both directions, and honest scoping on the contract-suite deferral
comments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: xmap <16776958+xmap@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent 295ad19 commit 8b2fbcf
94 files changed
Lines changed: 9887 additions & 24 deletions
File tree
- apps/api
- src/cora
- agent
- adapters
- aggregates/language_model
- features
- announce_language_model_retirement
- approve_language_model
- define_agent
- define_language_model
- deprecate_language_model
- list_at_risk_results
- retire_language_model
- projections
- api
- decision/adapters
- infrastructure
- ports
- tests
- architecture
- integration
- unit
- agent
- deployments
- docs/reference
- infra/atlas/migrations
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
6 | 8 | | |
7 | 9 | | |
8 | 10 | | |
| |||
67 | 69 | | |
68 | 70 | | |
69 | 71 | | |
| 72 | + | |
70 | 73 | | |
71 | 74 | | |
72 | 75 | | |
| |||
118 | 121 | | |
119 | 122 | | |
120 | 123 | | |
| 124 | + | |
121 | 125 | | |
122 | 126 | | |
123 | 127 | | |
| |||
Lines changed: 76 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
7 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | | - | |
| 14 | + | |
Lines changed: 57 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
Lines changed: 100 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
0 commit comments