# Use Case Catalog **Repo:** informed-decision **Workplan task:** `INFD-WP-0001-T04` **Status:** draft, pending review **Companion specs:** `ProductRequirementsDocument.md` (Stage 1 scope), `ArchitectureBlueprint.md`, `EvidenceModel.md` --- ## Why this catalog exists Scale invariance is the thesis of this repository: one object model from a ten-second login to a multi-party instrument. A thesis stated in a vision document is decoration. This catalog exists to make it **testable** — every case below must map onto the single Decision Memo schema with **no level-specific object**. Only UC-30 is in Stage 1 build scope. The rest are here to constrain the schema now, so it cannot fork later when they arrive. **The test this catalog applies to every case:** can it be expressed with the fields in `decision-memo.schema.json` plus values, or does it need a new field? A new field is permitted only if it is also expressible for UC-00 — the login banner, the shallowest case. A field that only makes sense at L4 is a fork. --- ## Depth spectrum overview | Case | L | Act | Binding | Counterparty | Stage | | --- | --- | --- | --- | --- | --- | | UC-00 | L0 | Informed login | acknowledgment / organizational | `key-cape` | 2 | | UC-10 | L1 | JIT privilege elevation | organizational | `key-cape`, `secrets-engine` | 2 | | UC-20 | L2 | Formal ADR accept | organizational / AES | estate decision records | 2 | | **UC-30** | **L3** | **Approval entry** | **organizational** | **`approval-engine`** | **1** | | UC-40 | L4 | Contract / instrument | AES / QES | external counterparty | horizon | | UC-50 | L5 | Multi-party instrument | QES per party | multiple | horizon | --- ## UC-00 — Informed login (L0) **Actor:** any principal signing in. **Trigger:** authentication at a system boundary. **Question:** *"Sign in to Payroll-Prod as Bernd Worsch?"* **Requested act:** `login`. **Binding slice (signed):** which identity (ordinary vs break-glass), which scope/tenant/system, privileges granted at the gate, monitoring and consent terms. **Awareness slice (shown, hashed, not signed):** the role you will wear after login and where that default came from (`last_used` | `system_default` | `policy` | `explicit`); other roles available inside the bound scope; other tenants you support; last session summary. **Verbs:** `acknowledge` (completes), `decline`, `discuss`. **Not** `accept` — this is Kenntnisnahme. **Post-bind:** `configure(hat)` for non-elevating roles only, while `session.status = active`. Switching to a tenant with `requires_new_bind` opens a **child memo**, never a silent scope change. **Evidence:** presentation with both hashes; `session.hat_selected` events that do not rewrite `view_hash`. **Why it constrains the schema:** UC-00 is the shallowest case and therefore the strictest constraint. It forced the pre-sign/post-sign split that now applies at every level — see `INTENT.md` principle 11. Any field proposed for a deeper case must be expressible here or be justified as genuinely level-specific. --- ## UC-10 — JIT privilege elevation (L1) **Actor:** an operator needing elevated privilege for a bounded task. **Question:** *"Elevate to Payroll Admin on ACME/Payroll-Prod for 60 minutes?"* **Requested act:** `elevate`. **Binding slice:** the privilege, the scope, the validity window, the stated justification, the monitoring terms. **Awareness slice:** current role, what the elevation adds, prior elevations. **Verbs:** `acknowledge` or `accept` depending on whether the elevation is self-service-with-record or requires a co-signer; `decline`; `escalate` where the operator's own mandate is insufficient. **Counterparty:** `key-cape` for identity; `secrets-engine` if the elevation materialises credentials — which this repository never does itself. **Constraint contributed:** an **elevating** role can never be reached by `configure`. It requires either promotion into the binding slice with a new memo version, or its own elevation memo. Guard `G_HAT`. --- ## UC-20 — Formal ADR accept (L2) **Actor:** an architect or owner with the mandate to accept a decision record. **Question:** *"Accept ADR-0042 — Adopt the local outbox pattern?"* **Requested act:** `accept_adr`. **Binding slice:** the ADR id and version, the decision statement, consequences, the accepting role. **Packet:** the ADR document, plus any superseded record. **Highlights:** the consequences section, typically `required_ack: true`. **Verbs:** the full set. `return` with coded reasons is the common path and is the point — an ADR sent back for a clearer consequences section is the surface working. **Constraint contributed:** *"accepted" must stop being a Git status and become an identity act.* The evidence must answer who accepted it, in what role, having seen which version. This is the case that most directly tests whether `view_hash` carries enough to be useful. **Note:** the estate's own decision records (`GH-DEC-*`, `FLEX-DEC-*`, `APPROVAL-*`) are the natural first real consumer of UC-20. Stage 2. --- ## UC-30 — Approval entry (L3) — **Stage 1** **Actor:** a human approver holding the mandate, authenticated by `key-cape`. **Trigger:** an approval exists in `approval-engine` in state `requested`, awaiting an authenticated approval entry. **Question:** *"Approve rotation of the production database credential for task T-1183?"* **Requested act:** `approve`. **Binding slice:** the approval id; the action and target it authorizes; the actor who may use it and the principal on whose behalf; the purpose; the validity window; the approving identity and tenant. **Awareness slice:** the approver's current role; other approvals pending for them (orientation only — see PRD open question 1); prior related approvals. **Packet:** the change or task the approval is for, and any policy citation supplied by the requester. **Highlights:** the target and the validity window, typically `required_ack: true` — these are the two fields whose misreading is most costly. **Verbs:** `accept` (submits the approval entry), `decline`, `return` with coded reasons, `discuss`, `forward`, `escalate`, `comment`. **Only `accept` reaches the engine.** `approval-engine` models entries against an approval object and knows nothing of memo dispositions. `accept` becomes a `POST /v1/approvals/{id}/entries`; `return`, `discuss`, `escalate` and the rest are memo-level and must not be represented in that engine at all. This is the correct separation, and it means the approval object alone does not show that a human sent the question back — see `EvidenceModel.md` §8 and PRD L-06. **Routes used:** `GET /v1/approvals/{id}` and `GET /v1/approvals/{id}/claim` (scope `approval:read`), `POST /v1/approvals/{id}/entries` (scope `approval:approve`). Never `/consume`. Any path containing `check` or ending in `/authorize` returns 404 by design — there is no "may this person approve" surface to call. **Entitlement:** a `200` from the engine is not a statement that this human may see the approval. `access-engine` is asked before rendering (PR-05). **No inbox.** The engine exposes get-by-id only — no list, no search, no "awaiting me". Approval ids arrive from whatever requested the approval. **Boundary — the part that must not drift:** - The surface calls `approval-engine`'s approval-entry mutation with a token carrying scope `approval:approve`. It never mutates approval state itself. - It never requests or performs `approval:consume`. Consumption is the PEP's, at the moment of use, per `GH-DEC-2026-003`. - It never caches or serves approval validity. - It never answers whether the underlying action is permitted. That is `access-engine`. **Evidence:** presentation record with `view_hash`, the disposition, and the approval entry id returned by `approval-engine`, so the entry is reconstructable back to what the approver saw. **Why this is Stage 1:** it is the only case currently costing another repository progress. `key-cape`'s `KEY-WP-0013-T02` is blocked on a browser client for exactly this flow. --- ## UC-40 — Contract or instrument (L4) — horizon **Actor:** a signatory with commercial authority. **Binding:** AES or QES. Identity imported from a QTSP or EUDI Wallet, never issued here. **Constraint contributed:** the signed attributes carry `memo_id`, `memo_version`, `disposition.verb` and `presentation.view_hash` — and **not** `awareness_hash` unless promotion ran. This is dynamic linking: the human-readable content actually presented is bound into the signature. **Open, not scoped:** retention and qualified archive (exploration open question 6). --- ## UC-50 — Multi-party international instrument (L5) — horizon **Actors:** several parties, each with their own QTSP and jurisdiction. **Constraint contributed:** parallel Mitzeichnung, per-party signature levels, and per-party presentations of the same memo version. The schema must already tolerate `parties[]` and multiple presentations per version — which it does. Explicitly not v1, and named here only so nothing shipped earlier forecloses it. --- ## Negative cases These are as load-bearing as the positive ones. Each protects a named invariant and each must be a test. ### NC-01 — `accept` on a Kenntnisnahme step **Attempt:** the approver presses accept on an `inform`/`review`/`acknowledge` step. **Required behaviour:** the verb is **absent from the UI**, not present and disabled; an API call attempting it is refused. **Invariant protected:** Kenntnisnahme is not approval. Collapsing them is how "I saw it" silently becomes "I approved it". `state-transitions.md §B2 · PR-31` ### NC-02 — Bind with unacknowledged required highlights **Attempt:** `accept` while a `required_ack` highlight is unacked. **Required behaviour:** fail closed; no disposition created; error names the outstanding highlight ids. **Invariant protected:** the acknowledgment gate is the only positive evidence of informedness the model has. `guard G_ACK · DoD-4 · PR-20` ### NC-03 — Agent attempts a disposition **Attempt:** a principal with `actor.kind = agent` submits any binding verb. **Required behaviour:** refused at *this repository's* API, not merely hidden in the UI. **Invariant protected:** humans bind, agents draft. `guard G_NOAGENT · P-10 · W-"An agent binds"` **Corrected 2026-09-09.** The first draft implied the refusal was also `approval-engine`'s. It is not: that engine restricts only `/consume` by principal type, and its `approval-engine-operator` service client holds `approval:approve`, so a non-human principal can supply approver evidence there today. Whether it should is `gate-house` doctrine, not ours. Two consequences. First, enforcement of P-10 is **this surface's own obligation** — there is no upstream backstop. Second, it is *auditable*: schema v4 records the verified `entries[].principal_type` from the token. Read that field. **Never** infer the answer from the shape of `subject_id`, which is a naming convention, not a verified claim; entries predating v4 are `null` and must not be read as `human`. ### NC-04 — Tenant switch requiring a new bind **Attempt:** after an L0/L1 bind, the subject selects a tenant marked `requires_new_bind`. **Required behaviour:** `scope.rebind_required` is set and a **child memo** is opened. The current session's `view_hash` is not rewritten. **Invariant protected:** scope is committed, not configured. `guard G_HAT · isolation vector 4` ### NC-05 — Awareness field edited after presentation **Attempt:** the proposed role or last-session summary changes between render and bind. **Required behaviour:** `awareness_hash` changes; `view_hash` does **not**; the bind remains valid. **Invariant protected:** the person is bound to what they committed to, not to orientation material. `isolation vector 2 · PR-40` ### NC-06 — Binding target changed **Attempt:** `binding.target` is altered from ACME to Beta. **Required behaviour:** `view_hash` changes, invalidating any outstanding presentation. **Invariant protected:** the binding slice is genuinely covered by the hash — the positive control for NC-05's negative one. `isolation vector 3` ### NC-07 — Bind against a stale memo version **Attempt:** a presentation taken at version *n* is used to bind after the memo advanced to *n+1*. **Required behaviour:** version conflict; no silent upgrade. **Invariant protected:** binding acts reference a presentation of the same version. `guard G_PRES · PR-14` ### NC-08 — `return` with no coded reason **Attempt:** return with free text only. **Required behaviour:** refused. **Invariant protected:** return is structured feedback, not a shrug. `guard G_REASONS · PR-32` ### NC-09 — `escalate` to an equal or lower mandate **Attempt:** escalate to a target whose mandate is not strictly higher. **Required behaviour:** refused as an escalation; offered as `forward`. **Stage 1 caveat:** without the mandate graph this guard cannot be fully evaluated. Stage 1 records the asserted intent and marks it **unverified** rather than pretending the guard passed. `guard G_ESC · limitation L-01` ### NC-10 — Key shuffling **Attempt:** serialise the same binding document with object keys in a different order. **Required behaviour:** identical `view_hash`. **Invariant protected:** canonicalization is real; otherwise every hash is an artifact of serialisation order. `isolation vector 1` --- ## Schema pressure — cases that would fork the object Recorded so a future contributor recognises them as forks rather than features: - **A level-specific status.** e.g. `awaiting_notarisation` for L4. Belongs as a step kind or a route step, never a new memo status. - **Multiple questions per memo.** An approval bundling three unrelated acts is three memos. The single-question invariant is what makes `view_hash` mean something. - **A per-level packet model.** L4 attachments are packet items, hashed exactly like an L0 consent text. - **An approvals-inbox object.** A list of memos is a query result, not a schema entity. If it acquires state, the product has become a queue.