Skip to content

Short-name addressing for platform-bucket config entities (config-to-blob) #1781

Description

@KirylKurnosenka

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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 (AccessServiceRuleService) — 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.

Metadata

Metadata

Labels

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions