diff --git a/spec/v1/10-project-intent.md b/spec/v1/10-project-intent.md index 29b0cf1..4f50bb3 100644 --- a/spec/v1/10-project-intent.md +++ b/spec/v1/10-project-intent.md @@ -55,6 +55,20 @@ repository holding three Applications rather than three repositories with three publish workflows) and a project never spans repositories, so composition unions fragments and never has to union a project (chapter 40). +**A composition fixture that stands in for an already-published fragment does +not carry `.project.yml`.** `spec/v1/examples/negative/*/intent*/` holds +documents fed directly to composition to exercise an invariant at the union +(chapter 40), never rendered and never read out of a `platform/` tree. The +suffix above names a file a publish step reads from a project's own +repository; putting it on a fixture that is published by nothing and has no +`platform/` tree to sit in would claim a layout that does not exist. The +difference is deliberate: a directory under `spec/v1/examples//` is a +worked project meant to render, and one under `spec/v1/examples/negative/` is +meant to make composition fail, at least one of them +(`duplicate-process-name`) before a union of two fragments ever runs. A test +that discovers project files by the `.project.yml` suffix is meant to find +only the former, and must keep finding only the former. + The split that matters is not file-level but concern-level. A secret's **access** is declared in the project file, beside the `dependsOn` edge that motivates it; the **environment variable** that carries it is a placeholder in the env file. Each @@ -254,7 +268,7 @@ the others. `name` and `instance` are both the Process name rather than one naming the Application, because the selector must match exactly one controller's pods. A `name` of the Application and an `instance` of the Process would read better and -would make every Process of a multi-Process Service selector-ambiguous the +would make every Process of a multi-Process Application selector-ambiguous the moment anything selected on `name` alone. No `app.kubernetes.io/version`. A version label would have to come from the diff --git a/spec/v1/examples/data/rendered/README.md b/spec/v1/examples/data/rendered/README.md index 3637c0d..ca01b4e 100644 --- a/spec/v1/examples/data/rendered/README.md +++ b/spec/v1/examples/data/rendered/README.md @@ -114,7 +114,7 @@ contributes routes and exposures to both; it owns neither object. | `hpa.yaml` | The registered `kubernetes` adapter can emit one; nothing in layer 1 declares autoscaling | | `vso.yaml` for rabbitmq and valkey | Neither declares `secrets` at either level. Their clients hold the credentials, which is what a provider looks like | | `configmap.yaml` for rabbitmq and valkey | No `assets`, and their env files are not in this example set ([G-28](#g-28)) | -| `servicemonitor.yaml` for valkey | No `scrape`. No exporter runs beside it, so there is no metrics surface and none is invented, which is why the Application declares `alertClass: none` rather than a class it could not signal | +| `servicemonitor.yaml` for valkey | No `scrape`. No exporter runs beside it, so there is no metrics surface and none is invented, which is why the Application declares no `observability` block at all rather than a class it could not signal | | a backup job for `valkey-data` | `durability: reconstructible` derives none. **The one absence in this project that is a decision rather than a hole** | | `PrometheusRule`, anywhere | Not the model's to render. `alertClass` is published as a resolved fact and the monitoring stack that owns PromQL, severity and receivers reads it from the projection ([chapter 10](../../../10-project-intent.md#observability)) | | `Role` / `RoleBinding` | No `rbac` adapter ([G-35](#g-35)) | diff --git a/spec/v1/examples/platform/README.md b/spec/v1/examples/platform/README.md index ebea3fd..ae84153 100644 --- a/spec/v1/examples/platform/README.md +++ b/spec/v1/examples/platform/README.md @@ -16,10 +16,11 @@ nothing in it names a Kubernetes field, a Traefik key, a k3s flag or a command |---|---|---| | `substrate` | cluster facts that decide other decisions, named for what they are | [0057](../../../../docs/adr/model/0057-datastore-and-restore.md), [0028](../../../../docs/adr/model/0028-secrets-at-rest-gate.md) | | `bootstrap` | what must exist before the first rendered object can apply | [0099](../../../../docs/adr/model/0099-bootstrap-set-is-recorded.md) | -| `tiers` | the shared edge is finite; four edge facts, and the Traefik Application each tier is | [0076](../../../../docs/adr/model/0076-middleware-has-one-producer.md), [0097](../../../../docs/adr/model/0097-authored-values-name-model-concepts.md) | +| `tiers` | the shared edge is finite; four edge facts, and the Traefik Service each tier is | [0076](../../../../docs/adr/model/0076-middleware-has-one-producer.md), [0097](../../../../docs/adr/model/0097-authored-values-name-model-concepts.md) | | `durability` | a backup window is one node's IO, a destination one remote target | [0077](../../../../docs/adr/model/0077-durability-derives-a-backup.md) | | `engines` | the method is an image; nothing authored is executable | [0097](../../../../docs/adr/model/0097-authored-values-name-model-concepts.md) | | `monitors` | one scrape cadence for the estate, because ingest is shared and no Application knows better. It is the whole observability surface of this document: no receiver map, no severity mapping, no rule catalog ([chapter 14](../../14-platform-intent.md#monitor-cadence)) | [0021](../../../../docs/adr/model/0021-observability-scrape-and-alert-class.md), [0079](../../../../docs/adr/model/0079-alert-class-derives-from-a-rule-catalog.md) | +| `hardening` | one posture for every container the estate renders: thirty declarations of the only legal value are thirty copies of one decision. A Process authors no hardening at all, and there is no per-control exception surface to author, because a relaxation carried with a reason is an override under another name ([chapter 14](../../14-platform-intent.md#hardening-policy)) | [0016](../../../../docs/adr/model/0016-pod-hardening.md) | | `probes`, `ephemeral` | one cadence and one size for the estate | [0088](../../../../docs/adr/model/0088-startup-probe-targets-liveness.md), [0092](../../../../docs/adr/model/0092-writable-paths-are-declared.md) | | `providers` | something the estate reaches and does not deploy: a fact, not a hole | [0090](../../../../docs/adr/model/0090-edges-resolve-against-the-register.md), [0095](../../../../docs/adr/model/0095-platform-intent-is-the-second-authored-document.md) |