# schemas — the ServiceDefinition contract This directory holds the **ServiceDefinition** interface — the highest-traffic contract in the platform (spec `agents/coordination-protocol.md` §2). Onboarding a service is adding/editing one ServiceDefinition under [`../catalog/`](../catalog/); the platform compiles it into concrete resources. Operators declare **what**; the platform provides the **how**. **Source of truth:** the read-only spec [`docs/13-service-catalog.md`](../../home-network-k3s/docs/13-service-catalog.md). This schema matches docs/13 exactly. Do not diverge from it here — escalate spec problems, don't fork the contract. ## Files | File | Purpose | |---|---| | `servicedefinition.schema.json` | Formal JSON Schema (draft 2020-12) for a ServiceDefinition. Enforces enums, required fields, patterns, and cross-field invariants. | | `renderer-contract.md` | Authoritative field → rendered-resource mapping, with requirement IDs. The contract other workstreams consume. | **Schema version:** 1.0.0 (in the schema `description`). Treat any change as an interface change: propose on the task board, update dependent renderers/tests in the same change, never silently break a consumer (coordination-protocol §2). ## Required vs. defaulted fields - **Required:** `name`, `source` (with `source.image` for `kind: container`, `source.vmTemplate` for `kind: vm`). - **Everything else is optional and carries a default** matching docs/13's "default posture" (`kind: container`, `exposure: internal`, `egress: internet`, `auth.mode: forward-auth`, `update.channel: stable`, `update.autoRollbackOnFailedHealth: true`, `observability.metrics: true`, `dependencies: []` ⇒ DNS-only). A renderer MUST materialize defaults before rendering — see `renderer-contract.md` §"Default posture". ## Cross-field rules the schema enforces - `kind: vm` ⇒ `source.vmTemplate` required; otherwise `source.image` required. - `auth.mode: oidc | forward-auth` ⇒ `auth.groups` present and non-empty (R-IDP-06 — access is "in an authorized group," not merely authenticated). - `ingressRoutes[].host` must match `