diff --git a/02-DECISIONS/0054-a-consumers-identity-fits-the-tightest-backend.md b/02-DECISIONS/0054-a-consumers-identity-fits-the-tightest-backend.md index e242461..5466f10 100644 --- a/02-DECISIONS/0054-a-consumers-identity-fits-the-tightest-backend.md +++ b/02-DECISIONS/0054-a-consumers-identity-fits-the-tightest-backend.md @@ -70,29 +70,54 @@ keeps meeting — but it directly contradicts 023 and ADR 0053: the identity wou mesh's single derivation the two ends share, it would be a value one side invents and the other must be told. Listed for completeness; not recommended. +**E — A module (and a node) may declare a short slug; the identity is built from it.** The identity +becomes `mesh__`: where a slug is declared it is used, +otherwise the cleaned name. A slug is a deliberately short, operator-chosen identifier — `kc` for +keycloak, `wkstn` for a workstation. It is optional: short names (`anchor`, `redis`) need none. +- *For:* this is the escape hatch B wanted to be, without the opacity. The name stays legible — a + provisioner can read `mesh_wkstn_kc` and know who is asking — because a person chose it, not a + hash function. And it makes an early refusal *palatable*: if even the slug-built identity overflows, + the refusal points at the slug, a field made for exactly this, rather than at the machine's name. + Both ends still derive it from one declared thing, so they agree by construction. +- *Against:* a new optional manifest field, and someone must pick the slug — but only for names that + would otherwise overflow, and picking a short legible identifier is a better job than being handed + a hash. + +## What implementing A revealed + +A was tried first. At `identityLimit = 20`, the readable budget is `mesh_` (5) + node + `_` + module +≤ 20, i.e. **node + module ≤ 14 characters** — far tighter than it looked. The catalogue's own +existing tests use `workstation`+`keycloak` (25), which compacts to `mesh_dbbc02f8dde34d3`; common +mesh names (`home-server`, `the-build-node`, `workstation`) blow the budget with any module. So B's +compact fallback would fire for the *common* case, not the rare overflow — which inverts A+B: most +identities would be opaque hashes. A alone (hard refusal at 20) would refuse most realistic names. +This is what moved the recommendation to E: the problem is not the limit, it is that the *readable +name* is the wrong source when it is long, and a slug is a better source than either a hash or a ban. + ## Recommendation -**A, with B held as the escape hatch.** Fixing the constant is what the code already says it meant -to do ("the shortest limit among the systems these names reach"), and moving the failure to an -honest assignment-time refusal is strictly better than a silent provision loop. Accept the naming -budget first; it is a forcing function toward short node/module names, which the mesh benefits from -elsewhere. If the ≤14 budget proves too tight in real use, add B's compact fallback for the overflow -case only — keeping the legible name for everyone it fits. Reach for C only if per-interface bounds -turn out to matter beyond this one 20-vs-63 gap; it is the right shape but more machinery than the -problem currently demands. +**E, over a per-consumer bound (start with the global minimum, 20).** Build the identity from an +optional slug, keep it when it fits, and refuse at assignment with "declare or shorten ``'s +slug" when it does not — no hash, no lost legibility, and the fix is a first-class field. Set the +bound to the true minimum (20) now; it needs no per-interface machinery to unblock S3, and a module +that consumes S3 simply declares a short slug. Graduate to **C** (per-interface bounds) later if it +turns out that non-S3 consumers are paying for S3's limit often enough to mind — E and C compose: +slugs are the mechanism, per-interface bounds refine where the ceiling sits. **B is dropped**: a +declared slug is a strictly better escape hatch than an opaque hash. **D stays rejected.** -## Consequences (of A) +## Consequences (of E) -- `identityLimit` becomes 20; the comment stops claiming postgres is the shortest and names S3 as - the binding one. `CheckIdentity` refuses over-long names at `module add` / assignment, not at - provision. -- Existing node/module names longer than the budget must be shortened before they can consume a - provision — a migration cost paid once, surfaced as a clear refusal. -- minio (04-ISSUES/010) is unblocked without any provider-specific mapping, and the minio - per-backend e2e (skipped, pending this) can run. -- **How it is checked:** the minio grant e2e — a consumer with a name inside the budget reaches its - bucket with the credential the mesh delivered — and a unit test that `CheckIdentity` refuses a - name whose derived identity exceeds 20. +- A module manifest gains an optional `slug`; a node may carry one too. `ConsumerIdentity` prefers + the slug over the cleaned name for each half. `identityLimit` becomes 20 (the true minimum), and + `CheckIdentity` refuses at `module add` / assignment — now with a message naming the slug to set. +- The common case stays legible; only names that overflow the budget need a slug, and what they get + is a name a person chose, not a hash. +- Existing modules/nodes whose names overflow declare a slug once — a migration cost paid as a clear + refusal with an obvious remedy, not a silent hash or a silent truncation. +- minio (04-ISSUES/010) is unblocked: an S3 consumer declares a short slug and its access key fits. +- **How it is checked:** the minio grant e2e — a consumer whose (slugged) identity fits reaches its + bucket with the credential the mesh delivered — plus unit tests that a slug is preferred, that an + un-sluggable over-long identity is refused (naming the slug), and that two consumers never collide. ## References