|
| 1 | +--- |
| 2 | +status: accepted |
| 3 | +summary: Keep the SERVICE_KEYS registry + STRUCTURAL_KEYS name-set split; reject a uniform structural-key registry as a false seam, and keep each structural key's behavior in the module that owns its concern. |
| 4 | +supersedes: null |
| 5 | +superseded_by: null |
| 6 | +--- |
| 7 | + |
| 8 | +# Reject a structural-key registry; keep behavior in the owning modules |
| 9 | + |
| 10 | +**Decision:** Do not introduce a uniform structural-key registry (a table of |
| 11 | +`emit(value, ctx)` callbacks covering `image`/`command`/`depends_on`/`dns`/ |
| 12 | +`secrets`/`deploy`/...). Keep the split as it is: the `SERVICE_KEYS` registry |
| 13 | +holds the keys that share one `emit(value) -> list[Token]` interface, and each |
| 14 | +*structural* key's behavior stays in the module that owns its concern |
| 15 | +(`emit.py`, `graph.py`, `pod.py`, `stores.py`, `resources.py`, |
| 16 | +`healthcheck.py`), with `keys.STRUCTURAL_KEYS` as the gate's accept-list. |
| 17 | + |
| 18 | +## Context |
| 19 | + |
| 20 | +Architecture-review candidate 3 flagged a "split-brain": `SERVICE_KEYS` |
| 21 | +single-sources validate+emit per key, but the 20 `STRUCTURAL_KEYS` are a bare |
| 22 | +name set whose behavior lives across six modules, and the supported-key name |
| 23 | +list is echoed again in `parsing.SUPPORTED_SERVICE_KEYS` and the 49-name |
| 24 | +`test_keys.py` snapshot. Two fixes were on the table: (1) a uniform structural |
| 25 | +registry with an `emit(value, ctx)` interface; (2) a narrow single-sourcing of |
| 26 | +the key-*name* list from each owning module. |
| 27 | + |
| 28 | +## Decision & rationale |
| 29 | + |
| 30 | +- **Structural keys are heterogeneous — at least six distinct emit shapes**, so |
| 31 | + they share no single interface: |
| 32 | + - *slot-occupiers* — `image`/`build` (image token), `command`/`entrypoint` |
| 33 | + (argv tokens): they don't produce `--flags` at all; |
| 34 | + - *project_dir flag-producers* — `environment`/`env_file`, `volumes`/`tmpfs`; |
| 35 | + - *healthcheck* — a sub-mapping → `--health-*`, also driving `wait_healthy`; |
| 36 | + - *graph keys* — `depends_on`/`networks`/`hostname`/`container_name`: drive |
| 37 | + ordering and pod-wide `--add-host`, not per-service flags; |
| 38 | + - *pod-level aggregated* — `dns`/`dns_search`/`dns_opt`/`sysctls`: unioned |
| 39 | + across all services onto `podman pod create`; |
| 40 | + - *document-scoped* — `secrets`/`configs`/`deploy`: need compose defs + |
| 41 | + closure order + `project_dir`, and emit create/teardown lines too. |
| 42 | +- `SERVICE_KEYS` is a real registry precisely because its ~29 keys all fit one |
| 43 | + shape ("two adapters = a real seam"). A structural registry spanning the six |
| 44 | + shapes above would need `Any`-typed / variadic callbacks — **a false seam**. |
| 45 | +- It would also **scatter cohesive logic** away from its concern: `depends_on` |
| 46 | + belongs with the graph, `dns` with the pod, `secrets` with stores, `deploy` |
| 47 | + with resources. Centralizing them behind a dispatcher trades locality for a |
| 48 | + lookup table — the opposite of a deep module. |
| 49 | +- `STRUCTURAL_KEYS` holds **no behavior** (deletion test): delete it and only |
| 50 | + the gate's accept-list and the snapshot test break, never an emit path. The |
| 51 | + sole duplicated knowledge is the key-*name* list. |
| 52 | +- **The narrow single-sourcing (option 2) was also weighed and declined now.** |
| 53 | + Deriving the accept-list from per-module declared key sets would distribute |
| 54 | + six small sets plus import edges to remove a minor duplication that the |
| 55 | + snapshot + disjoint tests already guard loudly (no silent-bug risk). Not worth |
| 56 | + it at this size and stage. |
| 57 | + |
| 58 | +## Revisit trigger |
| 59 | + |
| 60 | +Reopen — and when reopening, reach for the **narrow name single-sourcing**, not |
| 61 | +a registry — if either holds: |
| 62 | + |
| 63 | +- a **third reader** of the supported-key name set appears beyond the parsing |
| 64 | + gate and the owning-module handlers (e.g. a `--list-supported-keys` feature, |
| 65 | + or docs generated from the key set), so single-sourcing the list pays back |
| 66 | + across more than the gate; or |
| 67 | +- **several new structural keys arrive that share one new uniform shape** (e.g. |
| 68 | + a cluster of new pod-level aggregated keys), at which point a **narrow |
| 69 | + sub-registry for that one shape** — a `SERVICE_KEYS`-analog for the new emit |
| 70 | + signature — is warranted, never a universal structural registry spanning all |
| 71 | + shapes. |
0 commit comments