informed-decision/INTENT.md
tegwick 08b190928f Revise specs against approval-engine's approver-surface requirements
approval-engine replied to INFD-IN-0001 with docs/approver-surface-requirements.md
(31da1af, 5203f46) and two corrections. Several of my requirements were wrong or
incomplete; revised rather than appended to.

Corrected:
- PR-02 listed only approval:approve. Wrong — the surface also needs
  approval:read to fetch what it renders. As drafted it would have shipped a
  client able to submit an entry it could never display. That changes a
  registration key-cape has already implemented, so it is their call (open
  question A).
- NC-03 implied approval-engine refuses non-human approver entries. It does not;
  only /consume is principal-restricted, and the operator service client holds
  approval:approve. Enforcement of "humans bind, agents draft" is therefore ours
  alone, and is auditable via schema v4's entries[].principal_type — never from
  the shape of subject_id.

Added:
- PR-04 assurance shape. approval-engine persists it verbatim and accepts an
  empty object, so it is the only place MFA survives into the approval record.
  Needs auth method, acr/amr, auth_time, agreed with key-cape.
- PR-05 entitlement. A 200 from the engine is not permission to view; we owe
  access-engine a check before rendering. Consuming a decision, not making one.
- PR-06 response mapping, including 409 duplicate_approver rendered as SUCCESS
  (a browser double-submit is routine and the first entry stands) and 503 as
  fail-closed.
- PR-07 and a matching INTENT wrongness condition: never render `approved` as
  permission to act. That is a PDP in the browser wearing UI copy.
- L-05, L-06 and EvidenceModel 8b: view_hash cannot ride into the entry — the
  POST discards its body by design — so Stage 1 correlates by (approval_id,
  subject, approved_at). DoD-3 is satisfied by the triple, not by a stored hash.

PRD open question 1 is answered by construction: there is no inbox endpoint and
there will not be one, so the approvals-inbox shape is foreclosed upstream.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3W1dQG7GFFM9d94jFx7iR

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1565372@bnt-lap001
Assistant-Session: 16bb2f25-b34c-49ef-8e94-5fec3567a568
2026-09-09 14:20:13 +02:00

12 KiB

project product status intent_version date domain topic_slug layer role standard companion
informed-decision Informed Decision draft 0.1.0 2026-09-09 infotech netkingdom surface pep-shaped net-kingdom/canon/standards/security-layer-model_v0.7.md net-kingdom/SECURITY-COMPANION.md

INTENT

This file captures why this repository exists and the kind of system it is meant to become. It is aspirational and stable, not a description of current implementation. Implemented boundary belongs in SCOPE.md; the current stage belongs in GOAL.md; current work belongs in workplans/.

Purpose

informed-decision owns the surface on which a human is shown a decision and binds their identity to it — and owns the evidence that the presentation actually happened.

It answers one question, totally and decidably:

What was this person shown, in what role, at the moment they bound themselves to this act — and can that be proven afterwards?

Nothing else. It does not decide whether the act is permitted (access-engine), does not own the approval object (approval-engine), does not author the doctrine that requires an approval (gate-house), does not authenticate the person (key-cape), and does not archive the trail (audit-core).

Why This Exists

Every layer of the NetKingdom estate has an owner except the one a human actually touches.

approval-engine's INTENT.md names it under Non-Goals, twice and deliberately: "Not a workflow or ticketing system", "Not an approvals inbox or notification surface." That exclusion is correct — an engine that renders its own object is self-dealing — but it leaves a hole, and the hole is now load-bearing:

  • approval-engine is a bearer-token resource server with no Ingress, no redirect endpoint and no browser client (deploy/approval-engine.yaml: Namespace + ClusterIP + StatefulSet).
  • key-cape (KEY-WP-0013-T02) asked approval-engine for the human approver client's client_id and callback URI on 2026-09-08.
  • approval-engine correctly refused to invent them, recording in docs/keycape-service-registrations.md: "The human approver flow therefore belongs to whichever browser-facing approver UI presents approval:approve tokens to this engine. That component is not in this repo."

So the approver UI is not merely missing. It is a named, unassigned dependency that currently blocks an OIDC client registration in another repository. This repository claims it.

The claim is not opportunistic. The founding exploration (history/20260909-initial-exploration/) arrived at the same object from the opposite direction — the German Umlaufmappe / Zeichnungsbuch, a portable decision object that carries a question, the context needed to answer it, the requested act, and a cryptographic binding between identity, what was shown, and what was bound. That is exactly the artifact the estate is missing, and it generalizes past approvals without ever becoming a decision point.

The Concept — the Decision Memo

A Decision Memo is a portable object presented to one human who holds a mandate. It carries:

  • a question that must be answered, and a requested act;
  • the brief and consequences a reasonable decision-maker needs;
  • a packet of hashed documents and highlights pointing into it;
  • a binding slice — the identity and scope being committed, which is signed;
  • an awareness slice — orientation (proposed role, other roles, other tenants, last session), which is shown and hashed but not signed;
  • a route (Zeichnungsleiste), a thread, and a record of every presentation and disposition;
  • an append-only evidence chain.

Two hashes are computed over every presentation:

Hash Over Signed?
view_hash the binding document yes, from organizational level up
awareness_hash the awareness document no, unless a field was promoted

view_hash is the mechanism. It is what turns "the file was signed" into "this person, in this role, was shown this view, and bound this act."

Scale Invariance Is the Thesis

One object model, one evidence model, one UX grammar, from a ten-second login to a multi-party instrument:

Level Act Typical binding
L0 Informed login / session acknowledgment / organizational
L1 Privileged authorization (JIT elevation) organizational
L2 Formal ADR / decision-record accept organizational / AES
L3 Management approval organizational / AES
L4 Contract / instrument AES / QES
L5 Multi-party international instrument QES per party (horizon, not v1)

If L0 and L3 share the schema, the transitions, and the two hashes, the thesis holds. If they fork, it does not — and the estate has bought a bespoke approvals inbox instead of a decision surface.

The approval approver UI is L3. It is the first stage precisely because it is a real consumer with a real blocking dependency, not a demo.

The Disposition Vocabulary

The differentiator is not another workflow engine. It is that approve/reject is the wrong vocabulary for judgment. The verbs are:

comment · discuss (Rücksprache) · return for improvement (Rückgabe) · forward · escalate · acknowledge (Kenntnisnahme) · accept (Mitzeichnung / Schlusszeichnung) · decline · withdraw · configure

accept on a Kenntnisnahme step is illegal on purpose. Return is success, not failure — a memo sent back for improvement is the surface working.

What informed-decision Owns

  • the Decision Memo object, its versions, and its lifecycle;
  • the presentation record — what was rendered, to whom, when, in which locale and UI release;
  • canonicalization of the binding and awareness documents, and the computation of view_hash / awareness_hash;
  • highlight acknowledgment — required highlights acked before a bind is permitted;
  • the disposition vocabulary and its legality tables;
  • the evidence bundle as an export — the reconstructable answer to who decided what, having seen what;
  • the browser-facing OIDC client for human principals, including the client_id and callback URI that key-cape is waiting for;
  • the pre-sign / post-sign split: identity and bind-scope are committed; hats, last-used role, and other-tenant orientation are awareness unless explicitly promoted.

What informed-decision Does Not Own

  • the decisionaccess-engine, always and only (statute §6). This repository renders a question and records an answer; it never evaluates whether an actor may do a thing;
  • the approval objectapproval-engine. This surface calls that engine's mutations with an approval:approve-scoped token; it never holds approval current-state and never answers "is this approval valid";
  • approval doctrine — which acts need approval, how many approvers, which separations of duty — gate-house;
  • identity and authenticationkey-cape. Identity is imported (OIDC, passkeys, eID, EUDI Wallet, QTSP), never invented here;
  • the evidence archiveaudit-core. This repository emits and exports; the trail is held there;
  • credentials materialized after a decisionsecrets-engine;
  • notification transport — a memo may be announced by other means; the dialogue stays on the object.

Design Principles

  1. One object, many depths. Login and instrument share a schema.
  2. Presentation is part of the signed payload. Dynamic linking, not a signature over a file nobody read.
  3. Competence before convenience. Routing follows mandate.
  4. Return is success.
  5. Dialogue stays on the object. Side-channel email is an anti-pattern.
  6. Binding level is explicit. Kenntnisnahme ≠ Mitzeichnung ≠ QES.
  7. Evidence is an export, not a screenshot.
  8. Least privilege of attention. Highlights first, full packet available, no dark patterns — and the UI must make unmistakable that the whole instrument is bound, not only the highlights.
  9. Identity is imported.
  10. Humans bind, agents draft. An agent may assemble a memo. It may never complete the binding act on the principal's surface.
  11. Awareness is not consent. Defaulting a role to last-used is required for situational awareness and forbidden from silently entering view_hash.
  12. Informedness without surveillance. Evidence is the hash of the presented view plus explicit highlight acknowledgment — never keystroke analytics, dwell timers, or attention theater.

Layer Placement — Provisional

Under security layer model v0.7 this repository is not an Engine. It is browser-facing and it causes a protected side effect on the far side of a decision, which is the shape statute §6.4 and companion §5 call PEP-shaped. approval-engine's own INTENT names this expectation: "Callers that do are PEP-shaped and owe companion §5 / statute §6.4."

This is declared provisional because the catalog row does not exist yet and inventing one is the drift §17 exists to prevent. INFD-WP-0001-T02 takes the question to gate-house and writes layer.yaml from the answer, not from this paragraph. The framing this repository will argue: informed-decision is a presentation and binding surface — a PEP for the acts it fronts, and a PIP for exactly one fact, what was presented, which it supplies as a claim and never evaluates.

What Would Make This Repository Wrong

  • It starts deciding. Any surface that answers "may this actor do X" rather than "here is the question, and here is what you were shown" is the failure statute §6 names.
  • It becomes an approvals inbox and nothing else. If the object that ships cannot also carry an L0 login banner and an L2 ADR accept, the scale-invariance thesis is dead and the estate bought a queue.
  • It forks the schema per level. Three levels, three object models, one broken promise.
  • Awareness leaks into the signature. If a last-used role or a tenant orientation hint enters view_hash, the surface signs something the person did not commit to.
  • Highlights shrink the legal object. If acking three highlights is presented as binding only those three sections, the UI has produced a lie.
  • An agent binds. If any automation can complete a disposition on a principal's behalf, the identity half is fiction.
  • It renders approved as permission to act. approved is a state of an object, not authorization. approval-engine actively refuses to serialize a decision. A surface that presents approval status as "you may now do the thing" has re-implemented a PDP in the browser — the same failure as an authorization endpoint, wearing UI copy instead of an API.
  • It reimplements approval-engine. Caching approval validity, inferring consumption from a decision record, or holding approval current-state here breaks GH-DEC-2026-003 and the atomicity contract.
  • It invents identity. A local password, a local session token that is not derived from key-cape, or a self-issued assurance level.
  • Nobody uses it. If approval-engine never receives an approval:approve token from this component's client, the surface is decorative and the gap it claimed to close is still open.

Success Criteria

  1. key-cape holds a registered browser client whose client_id and callback URI this repository owns and published, and KEY-WP-0013-T02 is unblocked.
  2. A human approver completes an approval entry against approval-engine entirely through this surface, with an access token carrying aud=approval-engine, principal_type: human, and scope approval:approve.
  3. The approval entry is reconstructable from a view_hash — the estate can show what the approver was looking at.
  4. Required highlights cannot be bypassed: a bind attempt without acks fails.
  5. return, discuss, and escalate are exercisable on a real approval and are not modelled as decline.
  6. The same schema renders an L0 login banner and an L2 ADR accept, with the binding/awareness split intact and the isolation vectors green.
  7. An evidence bundle exports and verifies offline against audit-core's record of the same transitions.
  8. No endpoint in this repository answers an authorization question.