Detailed description
Score does not aim to support every option of the underlying service specs, rather a common subset. Patch templates are expected to fill in the gaps of what cannot be expressed in Score. However, Score's workload schema is closed (additionalProperties: false) on every object except metadata. So the only place to attach platform-specific extension data is metadata — either annotations (stringly-typed) or a nested map. That forces extension data far from the thing it describes: "give this container a longer startup budget" (Score has no probe-timing fields at all), or "this container runs as uid 101", has to live in a top-level metadata map keyed by container name, instead of inline on the container it applies to. It's awkward to author, awkward to read, and the link between the extension and its target survives only by convention (matching names).
Context
This would allow consumers to supply additional rich information within Score without resorting to distant metadata or annotations.
Possible implementation
Adopt OpenAPI-style specification extensions (x- prefixed fields), allowed at any object level within the service and containers schemas, and preserved through to consumers. Three parts:
- Schema (spec): permit
x- keys anywhere in the service/container subtrees while keeping the core closed — i.e. add patternProperties: { "^x-": {} } alongside the existing additionalProperties: false. Non-x- unknown keys are still rejected, so the portability guarantee is intact and extension data is clearly marked as extension rather than mistaken for core spec.
- Preservation (score-go): keep
x- fields through parsing instead of dropping them, so they re-emit inline where the author placed them.
- Exposure (consumers, e.g. score-k8s): surface them in the patch-template context (
.Workloads) so a patch can read an inline x- field and act on it.
How they're used in patch templates
Probe timing is a good motivating case: Score's container probes carry only host/scheme/path/port/httpHeaders — there is no initialDelaySeconds, periodSeconds, failureThreshold, or startupProbe. A platform that needs those today has to hardcode one budget for every workload in a patch, with no way for an author to tune it. An x- extension lets the author set it inline, right on the container:
apiVersion: score.dev/v1b1
metadata:
name: web
containers:
main:
image: myapp:latest
livenessProbe:
httpGet:
path: /healthz
port: 8080
x-initial-delay-seconds: 30 # Score has no probe-timing fields
A patch template is capable of reading this field, either through a new top level .Extensions or some other mechanism in the template.
The extension lives where it belongs, is clearly namespaced as an extension, and the patch reads it inline — instead of the current pattern where a platform patch hardcodes one probe budget for every workload with no author control. (Note the x- keys are read with dig/index, not dot access, since a hyphen isn't a valid Go-template field selector.)
Additional information
x- is the OpenAPI Specification Extensions convention (older name: "vendor extensions"); Docker Compose calls the same thing extension fields. It's widely understood and signals "clearly-marked extension data", not "arbitrary unknown keys".
Alternatives:
metadata annotations / a nested metadata map (the status quo) — works, but decouples extension data from its target, is stringly-typed, and reads awkwardly.
- Forking score-go / score-k8s — would let us preserve fields today, but means carrying a fork of actively developed projects and re-syncing every release.
Detailed description
Score does not aim to support every option of the underlying service specs, rather a common subset. Patch templates are expected to fill in the gaps of what cannot be expressed in Score. However, Score's workload schema is closed (
additionalProperties: false) on every object exceptmetadata. So the only place to attach platform-specific extension data ismetadata— either annotations (stringly-typed) or a nested map. That forces extension data far from the thing it describes: "give this container a longer startup budget" (Score has no probe-timing fields at all), or "this container runs as uid 101", has to live in a top-levelmetadatamap keyed by container name, instead of inline on the container it applies to. It's awkward to author, awkward to read, and the link between the extension and its target survives only by convention (matching names).Context
This would allow consumers to supply additional rich information within Score without resorting to distant metadata or annotations.
Possible implementation
Adopt OpenAPI-style specification extensions (
x-prefixed fields), allowed at any object level within theserviceandcontainersschemas, and preserved through to consumers. Three parts:x-keys anywhere in the service/container subtrees while keeping the core closed — i.e. addpatternProperties: { "^x-": {} }alongside the existingadditionalProperties: false. Non-x-unknown keys are still rejected, so the portability guarantee is intact and extension data is clearly marked as extension rather than mistaken for core spec.x-fields through parsing instead of dropping them, so they re-emit inline where the author placed them..Workloads) so a patch can read an inlinex-field and act on it.How they're used in patch templates
Probe timing is a good motivating case: Score's container probes carry only
host/scheme/path/port/httpHeaders— there is noinitialDelaySeconds,periodSeconds,failureThreshold, orstartupProbe. A platform that needs those today has to hardcode one budget for every workload in a patch, with no way for an author to tune it. Anx-extension lets the author set it inline, right on the container:A patch template is capable of reading this field, either through a new top level
.Extensionsor some other mechanism in the template.The extension lives where it belongs, is clearly namespaced as an extension, and the patch reads it inline — instead of the current pattern where a platform patch hardcodes one probe budget for every workload with no author control. (Note the
x-keys are read withdig/index, not dot access, since a hyphen isn't a valid Go-template field selector.)Additional information
x-is the OpenAPI Specification Extensions convention (older name: "vendor extensions"); Docker Compose calls the same thing extension fields. It's widely understood and signals "clearly-marked extension data", not "arbitrary unknown keys".Alternatives:
metadataannotations / a nestedmetadatamap (the status quo) — works, but decouples extension data from its target, is stringly-typed, and reads awkwardly.