informed-decision/INTENT.md
tegwick f6376ddff5 Declare the layer per GH-DEC-2026-012; close T02
Gate House ruled all three questions within a day, attributing the speed to the
request being filed before the architecture with candidate answers and their
costs.

R1 PEP-shaped, confirmed as proposed. The ruling settles the shape; the layer
stays ours to declare, so layer.yaml is written in this repository's voice
rather than transcribed from the reply.

R2 yes to a presentation claim, no second catalog row, under three limits now
declared in layer.yaml and tested. Limit 2 — the claim must never be an input to
the decision it presents for — is load-bearing: our self-dealing argument was
accepted because it holds, not despite it. Limit 3 drives architecture, since
here the actor being audited and the evidence source are the same component.

R3 (b) with the authority rule: binding digest authoritative for what the
request is, view_hash only for what was shown, neither substitutable, and a
disagreement between them is a finding against the presenting surface rather
than a fact about the request. Linkage is co-reference; nesting was refused
because it reproduces the GH-DEC-2026-008 hash cycle.

Built to v0.8 obligation 3 rather than migrating later: axis enumerated, unknown
resolves to fail_closed, absent distinguishable from unknown in the record, and
published-equals-shipped asserted by test rather than claimed. Every stance is
fail_closed, which is a conclusion not a shortcut — ops-warden can justify
fail_open on a continuity argument that does not exist here.

GH-DEC-2026-010 inherited as a declared gap in four documents: a decision cannot
today be proven to have come from access-engine. The decision path must not be
described as validated while FLEX-WP-0024 is open.

46 tests pass. T05 and T07 unblocked.

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 22:25:35 +02:00

298 lines
15 KiB
Markdown

---
project: informed-decision
product: Informed Decision
status: draft
intent_version: 0.1.0
date: "2026-09-09"
domain: infotech
topic_slug: netkingdom
layer: surface
role: pep-shaped # confirmed by GH-DEC-2026-012; see layer.yaml
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
companion: 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 decision** — `access-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 object** — `approval-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 authentication** — `key-cape`. Identity is *imported*
(OIDC, passkeys, eID, EUDI Wallet, QTSP), never invented here;
- **the evidence archive** — `audit-core`. This repository emits and exports;
the trail is held there;
- **credentials materialized after a decision** — `secrets-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 — Ruled
**PEP-shaped**, confirmed by `GH-DEC-2026-012` (answering `INFD-IN-0001`).
Not an Engine: this repository holds no state another layer reads at runtime for
a verdict, and renders no decision. Companion §5 is owed and statute §6.4
applies in full. The declaration is `layer.yaml`, in this repository's own voice
— a layer someone else states about you is not a declaration.
The ruling also confirmed that emitting a **presentation claim** does not
require a second catalog row: PEP and PIP are shapes a repository has, and §4
records the layers it occupies. That permission carries three limits, and they
are the substance of it rather than caveats on it:
1. **The claim carries presentation and nothing else.** It must never carry,
restate, summarise or imply the decision, the verdict, or whether the act was
permitted. A consumer learns from it only what was *shown*, never what was
*decided*.
2. **The claim must not be an input to the decision it presents for.** A policy
reading `view_hash` to decide whether an act is permitted would let the
presenting surface contribute to its own authorization.
3. **The evidence copy reaches `audit-core` independently of this repository.**
The claim endpoint and the evidence path are different things and neither
substitutes for the other.
Limit 2 is load-bearing. `GH-DEC-2026-012` accepted this repository's argument
that a renderer attesting its own rendering is not the self-dealing that kept
the approval object out of `access-engine` — *but only because that limit
holds*. Without it, the two collapse into the same failure.
Limit 3 is the one that most shapes the architecture: audit evidence is
protected from the actor being audited, and here the actor and the source are
the same component.
### `view_hash` and the binding digest
Ruled as option (b): they are **distinct attestations with an authority rule**.
- `approval-engine`'s binding digest is authoritative for **what the request
is**.
- `view_hash` is authoritative for **what was shown**, and nothing else.
- Neither may be substituted for the other.
- **A disagreement between them is a finding against the presenting surface,
never a fact about the request.**
They link by **co-reference**, not nesting: the presentation record carries the
approval or binding identifier explicitly, and both attestations are read
against that one reference. This repository must never recompute or restate
`approval-engine`'s binding digest in its own vocabulary — it references the
digest that layer computed and recorded.
Nesting was refused for a reason worth carrying: it reproduces the hash cycle
that made `GH-DEC-2026-008` unimplementable, where a claim had to name the
digest of a request that would come to contain it, and a fail-closed consumer
obeying it would deny permanently.
### An inherited gap, stated rather than glossed
`GH-DEC-2026-010` requires a decision be **attributable** to `access-engine`.
No consumer can satisfy that today: the decision envelope is unsigned, a
declared §13 gap tracked as `FLEX-WP-0024`. This repository's record can show
that a decision was obtained and what it said; it cannot yet show that
`access-engine` said it. The decision path must not be described as validated
while that is open.
## 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.