Skip to content

Commit 097bb4f

Browse files
authored
docs: record ADR rejecting a structural-key registry (#39)
Architecture-review candidate 3 proposed folding the 20 structural keys into a uniform registry. The structural keys span six distinct emit shapes and share no interface, so such a registry is a false seam that would scatter cohesive logic (depends_on/graph, dns/pod, secrets/stores) behind Any-typed callbacks. STRUCTURAL_KEYS holds no behavior -- the only duplication is the key-name list, which the snapshot/disjoint tests already guard. The narrow name single-sourcing was also weighed and declined for now; the ADR names it as the designated move should a revisit trigger fire.
1 parent 8d4ebf6 commit 097bb4f

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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

Comments
 (0)