Short-Name Addressing for Platform-Bucket Config Entities
Type: EPIC / Design
Issue tracker
| Child issue |
Status |
#1782 — Slice A — Materialize config-managed applications/toolsets in the platform bucket |
[ ] |
#1783 — Slice B+C — Short-name resolution via derivation + schema $id index |
[ ] |
#1784 — Slice D — Config-file migration endpoint POST /v1/admin/config/file/migrate |
[ ] |
Problem
We are migrating configuration entities (models, applications, toolsets,
interceptors, roles, application-type schemas, catalog schemas, keys, routes,
settings) out of the JSON config files and into blob storage, so every entity
becomes API-managed. In blob these live in the platform bucket keyed by a
canonical id (models/platform/gpt-4), whereas clients address config entities
by short name (gpt-4). The migration must not change what clients send or see.
Requirement:
| Surface |
Behavior |
| Inbound (client → Core) |
short name gpt-4 resolves to the entity; canonical id keeps working as a harmless superset |
| Outbound (Core → client) |
listings/responses emit the short name gpt-4, never models/platform/gpt-4 |
Concretely, all of the following must keep working after migration with no client
change:
POST /openai/deployments/gpt-4/chat/completions (path addressing)
GET /openai/models returning id: "gpt-4" (not models/platform/gpt-4)
- a stored conversation/prompt/custom app that embeds the bare name
gpt-4
- a buried reference such as
applicationProperties.orchestrator.deployment.name = "gpt-4o"
- a
Role.limits block keyed by a deployment's short name
- a role name matched against an IdP claim (
admin, not roles/platform/admin)
Key facts that shape the design
- Config entities are never fetched from blob/Redis on the request path — they
live in the in-memory Config snapshot, rebuilt by MergedConfigStore as the
union of the file-derived config and the blob-stored entities. Resolution is an
in-memory map lookup, centered on Config.selectDeployment (deployments), plus
role/interceptor/schema lookups.
- The canonical id is a pure function of
(type, bucket, name); since the bucket is
always platform and the blob name is always the short name, the canonical id is
deterministically derivable from the short name:
shortName → "{type-segment}/platform/{shortName}".
Design decisions
- The
platform bucket is the short-name signal — every materialized
platform-bucket config entity is short-name addressed, inbound and outbound. No
per-entity flag. public/user-bucket apps/toolsets are unaffected.
- Inbound: deterministic derivation, no stored index. Resolution tries the id
verbatim (canonical callers / file entries), then the derived canonical id. No
parallel short→canonical map to build/clone/maintain. Canonical addressing keeps
working as a superset.
- Outbound:
name = last path segment of the map key, uniformly (a file key has
no slash → identity; a canonical key → short name). Listing sites need no change.
- Coexistence: blob shadows file. When a blob entity is added at rebuild, the
same-short-named file entry is removed, so .values() yields one entry per logical
entity and short-name lookups resolve to blob.
- Schemas use a separate
$id index (app-type + catalog): referenced by the
body-internal $id/catalogSchemaId URI, not derivable — an always-on
$id → canonical index, independent of the bucket signal.
- Config-managed applications/toolsets move to the
platform bucket (not
public) and are materialized like models. Reasons: (a) public cannot
disambiguate a migrated config app from a user app in listings; (b) migrating into
public would overwrite a same-named user-published app (applications/public/{name}
collision → data loss); (c) config apps declare access via userRoles
(Deployment.hasAccess, same path as models), whereas public apps use folder
rules (AccessService→RuleService) — materializing into platform preserves the
userRoles semantics, public would force a lossy translation.
Rejected alternatives
- Per-entity
exposeAsShortName flag. Was designed to let migrated entities be
short-addressed while native-API entities stayed canonical. The team decided all
clients want short names for platform entities, so the distinction is unnecessary
and the flag is dropped — the bucket is the signal, and derivation replaces the
flag's alias index.
- Short-name-keyed
Config maps. Would avoid derivation but create a
canonical-vs-short impedance mismatch with the deeply canonical CRUD / pub-sub /
partial-update machinery. Rejected in favor of canonical-keyed maps + derivation.
public bucket for config apps/toolsets. Rejected for the three reasons in
decision 6 (ambiguity, write collision, access-model mismatch).
Compatibility note
For any entity already blob-stored in platform today, the outbound name flips
from canonical (models/platform/gpt-4) to short (gpt-4); inbound canonical
addressing still works via derivation. This is intended per the "all clients want
short names" decision.
Work breakdown (slices)
Dependency chain — not peers:
- Slice A — apps/toolsets →
platform (materialized, canonically addressed). No
dependency.
- Slice B+C — short-name resolution via derivation (+ outbound naming, blob-shadows-file,
call-site sweep) and the schema $id index. B splits internally into
models/interceptors/roles (independent of A) and apps/toolsets (needs A); C is
independent.
- Slice D — the config-file migration endpoint. Depends on A + B.
Recommended order: A, B(models/interceptors/roles), C in parallel →
B(apps/toolsets) → D. Land the apps/toolsets part of B before migrating any
app/toolset so they surface under short names.
Short-Name Addressing for Platform-Bucket Config Entities
Issue tracker
platformbucket$idindexPOST /v1/admin/config/file/migrateProblem
We are migrating configuration entities (models, applications, toolsets,
interceptors, roles, application-type schemas, catalog schemas, keys, routes,
settings) out of the JSON config files and into blob storage, so every entity
becomes API-managed. In blob these live in the
platformbucket keyed by acanonical id (
models/platform/gpt-4), whereas clients address config entitiesby short name (
gpt-4). The migration must not change what clients send or see.Requirement:
gpt-4resolves to the entity; canonical id keeps working as a harmless supersetgpt-4, nevermodels/platform/gpt-4Concretely, all of the following must keep working after migration with no client
change:
POST /openai/deployments/gpt-4/chat/completions(path addressing)GET /openai/modelsreturningid: "gpt-4"(notmodels/platform/gpt-4)gpt-4applicationProperties.orchestrator.deployment.name = "gpt-4o"Role.limitsblock keyed by a deployment's short nameadmin, notroles/platform/admin)Key facts that shape the design
live in the in-memory
Configsnapshot, rebuilt byMergedConfigStoreas theunion of the file-derived config and the blob-stored entities. Resolution is an
in-memory map lookup, centered on
Config.selectDeployment(deployments), plusrole/interceptor/schema lookups.
(type, bucket, name); since the bucket isalways
platformand the blob name is always the short name, the canonical id isdeterministically derivable from the short name:
shortName → "{type-segment}/platform/{shortName}".Design decisions
platformbucket is the short-name signal — every materializedplatform-bucket config entity is short-name addressed, inbound and outbound. No
per-entity flag.
public/user-bucket apps/toolsets are unaffected.verbatim (canonical callers / file entries), then the derived canonical id. No
parallel
short→canonicalmap to build/clone/maintain. Canonical addressing keepsworking as a superset.
name= last path segment of the map key, uniformly (a file key hasno slash → identity; a canonical key → short name). Listing sites need no change.
same-short-named file entry is removed, so
.values()yields one entry per logicalentity and short-name lookups resolve to blob.
$idindex (app-type + catalog): referenced by thebody-internal
$id/catalogSchemaIdURI, not derivable — an always-on$id → canonicalindex, independent of the bucket signal.platformbucket (notpublic) and are materialized like models. Reasons: (a)publiccannotdisambiguate a migrated config app from a user app in listings; (b) migrating into
publicwould overwrite a same-named user-published app (applications/public/{name}collision → data loss); (c) config apps declare access via
userRoles(
Deployment.hasAccess, same path as models), whereaspublicapps use folderrules (
AccessService→RuleService) — materializing intoplatformpreserves theuserRolessemantics,publicwould force a lossy translation.Rejected alternatives
exposeAsShortNameflag. Was designed to let migrated entities beshort-addressed while native-API entities stayed canonical. The team decided all
clients want short names for platform entities, so the distinction is unnecessary
and the flag is dropped — the bucket is the signal, and derivation replaces the
flag's alias index.
Configmaps. Would avoid derivation but create acanonical-vs-short impedance mismatch with the deeply canonical CRUD / pub-sub /
partial-update machinery. Rejected in favor of canonical-keyed maps + derivation.
publicbucket for config apps/toolsets. Rejected for the three reasons indecision 6 (ambiguity, write collision, access-model mismatch).
Compatibility note
For any entity already blob-stored in
platformtoday, the outboundnameflipsfrom canonical (
models/platform/gpt-4) to short (gpt-4); inbound canonicaladdressing still works via derivation. This is intended per the "all clients want
short names" decision.
Work breakdown (slices)
Dependency chain — not peers:
platform(materialized, canonically addressed). Nodependency.
call-site sweep) and the schema
$idindex. B splits internally intomodels/interceptors/roles (independent of A) and apps/toolsets (needs A); C is
independent.
Recommended order: A, B(models/interceptors/roles), C in parallel →
B(apps/toolsets) → D. Land the apps/toolsets part of B before migrating any
app/toolset so they surface under short names.