informed-decision/docs/specs/ArchitectureBlueprint.md

304 lines
15 KiB
Markdown
Raw Normal View History

Architecture Blueprint and rewritten SCOPE; close T05 and T06 T05 written after the ruling rather than before it, which was the point of gating it. GH-DEC-2026-012 limit 3 did most of the shaping: the evidence copy must reach audit-core independently of this component, because here the actor being audited and the evidence source are the same. Booked as four binding implementation consequences plus O-02, which must be resolved before T08 ships — "we will add the independent path later" is how limit 3 becomes limit-3-in-principle. Other constraints fixed in the blueprint: presentation/ is the only writer of view_hash; the approval-engine client exposes no validity cache; a fail-closed outcome is never recorded as an approver's decline, since the human made none; the assurance shape is cited from key-cape's contract rather than restated so it cannot drift; and no polling loop may synthesise the inbox approval-engine refuses to provide. T06 closed with the SCOPE.md rewrite the ruling unblocked. It carries a "What this repository does not claim" section, because a scope file listing only capabilities overstates them: the decision path is not validated while GH-DEC-2026-010 is open, the residual is not closed, view_hash is not inside the approval entry, and nothing is deployed. Two open items block the remainder. O-01, the human token tenant, blocks T07 and is not ours alone to decide. O-02, the independent evidence path, blocks T08. 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:29:06 +02:00
# Architecture Blueprint — Stage 1
**Repo:** informed-decision
**Workplan task:** `INFD-WP-0001-T05`
**Status:** draft, pending review
**Governing ruling:** `GH-DEC-2026-012` (answered `INFD-IN-0001`)
**Declarations:** `layer.yaml`, `pep-stance.yaml`
**Companions:** `ProductRequirementsDocument.md`, `UseCaseCatalog.md`,
`EvidenceModel.md`
---
## 1. What this component is
**PEP-shaped**, ruled by `GH-DEC-2026-012`. Browser-facing; causes a protected
side effect on the far side of a decision (an approver entry recorded against an
approval object). Companion §5 owed, statute §6.4 in full. Not an Engine: it
holds no state another layer reads at runtime for a verdict.
It also emits a **presentation claim** — one fact, *what was shown* — under the
three limits in `layer.yaml`. No second catalog row.
**Nothing in this component renders an authorization decision.** No route
answers "may this actor do X".
---
## 2. Call graph
```
browser (approver)
┌───────────┴────────────┐
│ informed-decision │ PEP-shaped
│ (this repository) │
└──┬────┬────┬────────┬──┘
auth-code + PKCE │ │ │ │ presentation records,
│ │ │ │ dispositions, stance
▼ │ │ ▼ applications
key-cape │ │ audit-core ◄──── independent
(identity)│ │ evidence path
│ │ (limit L3)
▼ ▼
access-engine approval-engine
(decision — (read + entry;
consumed, never /consume)
never made)
```
### 2.1 `key-cape` — identity
Authorization-code + **S256 PKCE**, public client, exact registered redirect.
Access token only; `id_token` is never evidence. Scopes
`[openid, approval:read, approval:approve]`. **Never `approval:consume`.**
Token must carry `aud=approval-engine`, `principal_type: human`, non-empty `sub`
and `scope`, and an `assurance` object.
**`assurance` shape is `key-cape`'s**, adopted as published in their
`docs/approval-engine-auth-contract.md``level` (`aal1|aal2`), `methods`,
`mfa`, `source`, `at`. This blueprint **cites** that document rather than
restating the shape, so it cannot drift. `at` is authentication time, not token
mint time; consumers needing freshness compare `at` rather than assuming it.
Apply GH-DEC-2026-013 and GH-DEC-2026-014; close INFD-IN-0002 Two rulings landed and both corrected something. GH-DEC-2026-013 accepted our binding-versus-awareness argument, wrote it into the record as its §6, and did not change the outcome — it sharpened the defect. Two different facts share one field named tenant: the act-scope, a property of the act that our binding slice commits, and the principal's membership, a property of the person that approval-engine exact-matches. Gate House's correction stands: a binding slice that must commit the scope being entered should commit that scope, not borrow a membership claim to stand in for it. Our schema already does — binding.target IS the act-scope and is inside view_hash — so no field was added, only a statement (PR-08) and a provenance record (PR-09), since key-cape emits tenant as a bare string. key-cape had already implemented registration-bound tenancy on 2026-09-09, correct under both candidate rulings, so the fail-closed-at-first-use risk that made us withhold the client strings was already retired. IN-0002 closed. The one remaining input to T07 is the deployed origin. GH-DEC-2026-014 granted commitment-only evidence and bounded it. It satisfies non-alteration and NOT reconstructability, and must not be described otherwise anywhere. It also corrected our wording of the gap: we wrote that it leaves us able to erase the content, which understates it. Commitment-only moves integrity out of our control and leaves availability entirely inside it — the party that can withhold the content is the party the evidence is about. Limit 3's condition reduced, not removed. The grant carries a condition we did not propose and would not have thought of: the path must assert that committed content exists and where custody sits, so non-production is a finding attributable to the custodian rather than an unremarkable blank. A commitment with no assertion that something is being committed to is indistinguishable from a commitment to nothing. Booked as PR-53, and marked not-a-reversal-candidate. Recorded the meta-rule Gate House named, now in its third setting here: unknown versus absent in the stance map, directory-asserted versus registration-supplied in the tenant claim, erased versus never held in the evidence path. Wherever a system reaches one appearance by two routes, the record must say which route. 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-10 07:57:57 +02:00
**Resolved.** `key-cape` implemented registration-bound tenancy on 2026-09-09
(`329e48f`), deliberately correct under both candidate rulings: a declared zone
applies where the directory places the user nowhere, agreement passes, and a
declared zone **conflicting** with a directory assignment refuses issuance with
`403 tenant_binding` rather than relabelling. `GH-DEC-2026-013` then ruled
directory-sourced the terminal state and granted the registration-bound shape as
a **declared bounded gap** — admissible precisely because its distinguishing
case fails closed.
**Build to it knowing it is transitional.** Two obligations land here:
- **Do not declare a tenant the directory record does not carry** unless
prepared to say so in the record. Declaring one asserts a fact about a person
on this registration's authority, which the ruling permits only as a gap.
- **Record the tenant claim's provenance.** `key-cape` emits `tenant` as a bare
string, so a consumer cannot distinguish a directory-asserted tenant from a
registration-supplied one. `GH-DEC-2026-013` §5 requires the claim to carry
provenance; until it does, this surface records which route the value arrived
by rather than storing an undifferentiated string.
**And do not use the `tenant` claim as the act-scope.** `binding.target` is the
act-scope and is committed in `view_hash`. See `EvidenceModel.md` §8c.
Architecture Blueprint and rewritten SCOPE; close T05 and T06 T05 written after the ruling rather than before it, which was the point of gating it. GH-DEC-2026-012 limit 3 did most of the shaping: the evidence copy must reach audit-core independently of this component, because here the actor being audited and the evidence source are the same. Booked as four binding implementation consequences plus O-02, which must be resolved before T08 ships — "we will add the independent path later" is how limit 3 becomes limit-3-in-principle. Other constraints fixed in the blueprint: presentation/ is the only writer of view_hash; the approval-engine client exposes no validity cache; a fail-closed outcome is never recorded as an approver's decline, since the human made none; the assurance shape is cited from key-cape's contract rather than restated so it cannot drift; and no polling loop may synthesise the inbox approval-engine refuses to provide. T06 closed with the SCOPE.md rewrite the ruling unblocked. It carries a "What this repository does not claim" section, because a scope file listing only capabilities overstates them: the decision path is not validated while GH-DEC-2026-010 is open, the residual is not closed, view_hash is not inside the approval entry, and nothing is deployed. Two open items block the remainder. O-01, the human token tenant, blocks T07 and is not ours alone to decide. O-02, the independent evidence path, blocks T08. 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:29:06 +02:00
### 2.2 `access-engine` — the decision, consumed
A decision is obtained **before an approval is rendered to a person**. A `200`
from `approval-engine` is not entitlement; that engine never answers "may this
actor do X".
Consuming a decision is not rendering one. There is no local fallback: if
`access-engine` is unreachable, the stance applies (§5).
**Declared gap, `GH-DEC-2026-010`.** Obligation 1 requires the decision be
*attributable* to `access-engine`. No consumer can satisfy that today — the
envelope is unsigned (`FLEX-WP-0024`). This surface records
`decision_attributable: false`. **The decision path is not validated and must
not be described as such** while that is open.
### 2.3 `approval-engine` — the object and the entry
| Route | Method | Scope |
| --- | --- | --- |
| `/v1/approvals/{id}` | GET | `approval:read` |
| `/v1/approvals/{id}/claim` | GET | `approval:read` |
| `/v1/approvals/{id}/entries` | POST | `approval:approve` |
| `/v1/approvals/{id}/consume` | POST | **never called** |
Paths containing `check` or ending in `/authorize` return 404 by design; there
is nothing there to call.
`POST /entries` **discards its request body** — approver identity, `assurance`
and `evidence_ref` come only from the verified token. So `view_hash` does not
ride into the entry. Correlation is `(approval_id, subject, approved_at)`.
**No inbox.** Get-by-id only; no list, no search, no "awaiting me". Approval ids
arrive from whatever requested the approval. This component must never poll.
Only `accept` becomes a `POST …/entries`. `return`, `discuss`, `escalate` and
the rest are memo-level and are not represented in that engine at all.
### 2.4 `audit-core` — evidence, on an independent path
**Limit L3 is the architectural constraint of this design.** The evidence copy
must reach `audit-core` independently of this repository, because here the actor
being audited and the evidence source are the same component. The copy that is
evidence must not be reachable only through the party it is evidence about.
Consequences, binding on implementation:
1. **The claim endpoint and the evidence path are separate.** Serving a
presentation record over this component's API does not discharge the evidence
obligation, and emitting evidence does not remove the need for a claim.
2. **A reader must be able to obtain the evidence copy without this component's
cooperation.** If the only route to a presentation record is an API this
component controls, an adversary who controls it controls the evidence about
it.
3. **Emission is not best-effort.** A presentation or disposition that can be
recorded here while its evidence is lost is a state change that never
happened as far as an auditor can tell. `approval-engine`'s local-outbox
reasoning applies unchanged and is adopted rather than rediscovered: the
queue is local, in the same transaction as the state change, with no
synchronous `audit-core` dependency inside it.
4. **Atomicity covers accident, not compromise.** It does not close the residual
in `layer.yaml`, and must never be described as doing so.
Close INFD-IN-0001; design the independent evidence path; track both blockers Housekeeping the ruling left behind, plus the one piece of blocked work that was substantially ours to move. INFD-IN-0001 closed with its resolution recorded, matching approval-engine's IN-0002 form. It was still open after GH-DEC-2026-012 answered it. INFD-IN-0003 and docs/evidence-path-design.md take up O-02, which was sitting in the blueprint as "mechanism unchosen". Read independence and the local transactional outbox are settled and not in question. The real question is what travels, and it is sharper for us than for approval-engine because a presentation record carries the brief and packet material actually shown to a human. Three candidates with costs; proposal is commitment-only for Stage 1 — hashes, principal, timestamps, acks, co-referenced approval id — which discharges limit 3 and removes our ability to alter the record, while leaving us able to erase the content. That residual is declared alongside the existing compromised-surface one rather than papered over. Deliberately not proposing the full binding document unilaterally: it would put commercial and personal material into the audit fabric under retention and export entitlements designed for audit events. That is a meaningful change in what audit-core holds and is its owner's to accept, not ours to assume. The third option, a separate evidence store, is refused here because that store has no owner and inventing one routes around the §16 decision against stronger archival custody. Cadence declared and its form argued rather than copied: approval-engine's heartbeat answer suits genuinely low-volume classes, but ours are mixed — presentations are one per render, while dispositions and stance applications are low-volume and are the security-relevant ones. Reconciliation per class as primary, heartbeat for the low-volume classes. Depends on AUDIT-WP-0009 T04/T06; declared, not claimed operating. INFD-IN-0002 files the tenant blocker as a tracked record rather than leaving it in message threads and a blueprint footnote. T07 and T08 now name their blocking intakes. 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 23:19:27 +02:00
**Cadence is owed**, because `layer.yaml` declares presentation evidence
load-bearing (§9.6). The form differs from `approval-engine`'s: their classes are
genuinely low-volume, so a heartbeat is the answer. Ours are mixed —
presentations are high-volume (one per render), while dispositions and stance
applications are low-volume and are the security-relevant ones. Proposed:
reconciliation per class as the primary form, plus a heartbeat for the
low-volume classes, since a quiet month of dispositions is indistinguishable
from suppression by rate alone. Depends on `AUDIT-WP-0009` T04/T06; declared,
not claimed operating.
What travels is the open question — see `docs/evidence-path-design.md` and O-02.
**T08 must not ship without it chosen**, because "we will add the independent
path later" is how limit 3 quietly becomes limit 3-in-principle.
Architecture Blueprint and rewritten SCOPE; close T05 and T06 T05 written after the ruling rather than before it, which was the point of gating it. GH-DEC-2026-012 limit 3 did most of the shaping: the evidence copy must reach audit-core independently of this component, because here the actor being audited and the evidence source are the same. Booked as four binding implementation consequences plus O-02, which must be resolved before T08 ships — "we will add the independent path later" is how limit 3 becomes limit-3-in-principle. Other constraints fixed in the blueprint: presentation/ is the only writer of view_hash; the approval-engine client exposes no validity cache; a fail-closed outcome is never recorded as an approver's decline, since the human made none; the assurance shape is cited from key-cape's contract rather than restated so it cannot drift; and no polling loop may synthesise the inbox approval-engine refuses to provide. T06 closed with the SCOPE.md rewrite the ruling unblocked. It carries a "What this repository does not claim" section, because a scope file listing only capabilities overstates them: the decision path is not validated while GH-DEC-2026-010 is open, the residual is not closed, view_hash is not inside the approval entry, and nothing is deployed. Two open items block the remainder. O-01, the human token tenant, blocks T07 and is not ours alone to decide. O-02, the independent evidence path, blocks T08. 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:29:06 +02:00
---
## 3. Internal shape
```
informed_decision/
├── canonicalize.py view_hash / awareness_hash (governed, tested)
├── stance.py the shipped unreachable-engine map (tested == published)
├── memo/ Decision Memo object, versions, lifecycle
├── presentation/ presentation records; the only writer of view_hash
├── disposition/ verb legality, guards G_*, thread
├── evidence/ local outbox, bundle export
└── clients/ key-cape, access-engine, approval-engine, audit-core
```
**`presentation/` is the only writer of `view_hash`.** One writer, one
canonicalizer, one place to audit. A second path that computes a hash is a
defect, not an optimisation.
**`clients/approval_engine` must not expose a validity cache.** No memoisation
of "is this approval valid". The engine is asked.
---
## 4. Storage
Stage 1 holds: memos and their versions; presentations with both hashes and
acked highlight ids; dispositions with their coded reasons; thread entries;
the local outbox; stance applications.
Properties required:
- **Presentations are append-only.** A presentation is a record of an event that
happened. Editing one is falsifying evidence.
- **Memo versions are immutable once presented.** A change creates version *n+1*
and invalidates outstanding presentations (guard `G_PRES`).
- **The outbox is in the same transactional store**, written in the same
transaction as the state change it evidences.
- **No approval state.** Not cached, not mirrored, not derived.
Engine choice is deferred to implementation; the constraint is that it be a
single transactional store, so the outbox cannot separate from the mutation.
---
## 5. Failure modes — stance per dependency
Default is **fail closed**. Every stance in `pep-stance.yaml` is `fail_closed`,
and that is a conclusion: refusing to bind delays a decision, it does not remove
a capability anyone needs to keep a system running. There is no continuity
argument here of the kind that justifies `fail_open` elsewhere.
| Dependency | Unavailable | Surface behaviour |
| --- | --- | --- |
| `key-cape` | no authentication | No session. Nothing rendered. |
| `access-engine` | no decision | **Stance applies: `fail_closed`.** Not rendered, not bound. Recorded as a stance application, never as a decline. |
| `approval-engine` 5xx / `503` | no object, or store down | Fail closed. Never present success. |
| `audit-core` | evidence destination down | Rendering and binding continue; evidence queues in the **local** outbox. An `audit-core` outage must not block a binding act — the same reasoning that keeps it from blocking a revocation upstream. |
**A fail-closed outcome is never rendered as a decline by the approver.** No
disposition is recorded, because the human did not make one. Conflating the two
would put a refusal in the record that no person authored.
Engine response mapping — `409 duplicate_approver` is **success**, `409
conflict` is terminal, `503` is fail-closed — is specified in `PR-06` and is not
restated here.
---
## 6. Deployment
`approval-engine` has no Ingress and no external origin, which is why it could
not own the browser client. **This component has both, and that is the point.**
- Public HTTPS origin, TLS terminated at ingress.
- Exact registered redirect URI, scheme and path included. Redirects match
exactly at `/authorize`, so a near-miss fails closed.
- **`client_id` and the callback URI are deployment inputs, not implementation
details.** Once chosen they are stable; changing one silently breaks login
rather than degrading it.
- Outbound to `approval-engine` and `access-engine` on cluster-internal
addresses; no public exposure of either is implied by this component's.
The concrete origin is fixed in `T07` alongside the client registration, and is
gated on the tenant question in §7.
---
## 7. Open and blocking
Apply GH-DEC-2026-013 and GH-DEC-2026-014; close INFD-IN-0002 Two rulings landed and both corrected something. GH-DEC-2026-013 accepted our binding-versus-awareness argument, wrote it into the record as its §6, and did not change the outcome — it sharpened the defect. Two different facts share one field named tenant: the act-scope, a property of the act that our binding slice commits, and the principal's membership, a property of the person that approval-engine exact-matches. Gate House's correction stands: a binding slice that must commit the scope being entered should commit that scope, not borrow a membership claim to stand in for it. Our schema already does — binding.target IS the act-scope and is inside view_hash — so no field was added, only a statement (PR-08) and a provenance record (PR-09), since key-cape emits tenant as a bare string. key-cape had already implemented registration-bound tenancy on 2026-09-09, correct under both candidate rulings, so the fail-closed-at-first-use risk that made us withhold the client strings was already retired. IN-0002 closed. The one remaining input to T07 is the deployed origin. GH-DEC-2026-014 granted commitment-only evidence and bounded it. It satisfies non-alteration and NOT reconstructability, and must not be described otherwise anywhere. It also corrected our wording of the gap: we wrote that it leaves us able to erase the content, which understates it. Commitment-only moves integrity out of our control and leaves availability entirely inside it — the party that can withhold the content is the party the evidence is about. Limit 3's condition reduced, not removed. The grant carries a condition we did not propose and would not have thought of: the path must assert that committed content exists and where custody sits, so non-production is a finding attributable to the custodian rather than an unremarkable blank. A commitment with no assertion that something is being committed to is indistinguishable from a commitment to nothing. Booked as PR-53, and marked not-a-reversal-candidate. Recorded the meta-rule Gate House named, now in its third setting here: unknown versus absent in the stance map, directory-asserted versus registration-supplied in the tenant claim, erased versus never held in the evidence path. Wherever a system reaches one appearance by two routes, the record must say which route. 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-10 07:57:57 +02:00
**~~O-01 — Human token tenant.~~ Closed 2026-09-10** by `GH-DEC-2026-013` and
`key-cape` `329e48f`. Our binding-versus-awareness argument was accepted and
written into the ruling as its §6 — and it did not change the outcome, it
sharpened the defect: two different facts (act-scope, and the principal's
membership) were sharing one field. The condition we asked for is now in
`key-cape`'s `docs/tenant-claim-contract.md`, strengthened from "must be
revisited" to **void** if the dynamic-registration exclusion is lifted, and
enforced by a test asserting the capability and the exclusion together. See
§2.1 for the two obligations that land on us.
**O-02 — The independent evidence path.** *Payload ruled: commitment-only
granted for Stage 1 by `GH-DEC-2026-014`, on the condition that the record carry
an assertion that content exists and where custody sits, so non-production is a
finding attributable to us rather than an unremarkable blank. It satisfies
non-alteration, not reconstructability, and must not be described otherwise. The
registration and cadence remain with `audit-core`.* Design and decision request
written:
Close INFD-IN-0001; design the independent evidence path; track both blockers Housekeeping the ruling left behind, plus the one piece of blocked work that was substantially ours to move. INFD-IN-0001 closed with its resolution recorded, matching approval-engine's IN-0002 form. It was still open after GH-DEC-2026-012 answered it. INFD-IN-0003 and docs/evidence-path-design.md take up O-02, which was sitting in the blueprint as "mechanism unchosen". Read independence and the local transactional outbox are settled and not in question. The real question is what travels, and it is sharper for us than for approval-engine because a presentation record carries the brief and packet material actually shown to a human. Three candidates with costs; proposal is commitment-only for Stage 1 — hashes, principal, timestamps, acks, co-referenced approval id — which discharges limit 3 and removes our ability to alter the record, while leaving us able to erase the content. That residual is declared alongside the existing compromised-surface one rather than papered over. Deliberately not proposing the full binding document unilaterally: it would put commercial and personal material into the audit fabric under retention and export entitlements designed for audit events. That is a meaningful change in what audit-core holds and is its owner's to accept, not ours to assume. The third option, a separate evidence store, is refused here because that store has no owner and inventing one routes around the §16 decision against stronger archival custody. Cadence declared and its form argued rather than copied: approval-engine's heartbeat answer suits genuinely low-volume classes, but ours are mixed — presentations are one per render, while dispositions and stance applications are low-volume and are the security-relevant ones. Reconciliation per class as primary, heartbeat for the low-volume classes. Depends on AUDIT-WP-0009 T04/T06; declared, not claimed operating. INFD-IN-0002 files the tenant blocker as a tracked record rather than leaving it in message threads and a blueprint footnote. T07 and T08 now name their blocking intakes. 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 23:19:27 +02:00
`docs/evidence-path-design.md`, filed as `INFD-IN-0003`. Read independence and
the local transactional outbox are settled; the open question is **what
travels**, because a presentation record carries the brief and packet material
actually shown to a human. Proposal is commitment-only (hashes, principal,
timestamps, acks, co-referenced approval id) for Stage 1, with the erasure
residual declared rather than papered over. Awaiting `audit-core` on the payload
and the sender registration, and `gate-house` only if the content question is
doctrine. Must be resolved before T08 ships.
Architecture Blueprint and rewritten SCOPE; close T05 and T06 T05 written after the ruling rather than before it, which was the point of gating it. GH-DEC-2026-012 limit 3 did most of the shaping: the evidence copy must reach audit-core independently of this component, because here the actor being audited and the evidence source are the same. Booked as four binding implementation consequences plus O-02, which must be resolved before T08 ships — "we will add the independent path later" is how limit 3 becomes limit-3-in-principle. Other constraints fixed in the blueprint: presentation/ is the only writer of view_hash; the approval-engine client exposes no validity cache; a fail-closed outcome is never recorded as an approver's decline, since the human made none; the assurance shape is cited from key-cape's contract rather than restated so it cannot drift; and no polling loop may synthesise the inbox approval-engine refuses to provide. T06 closed with the SCOPE.md rewrite the ruling unblocked. It carries a "What this repository does not claim" section, because a scope file listing only capabilities overstates them: the decision path is not validated while GH-DEC-2026-010 is open, the residual is not closed, view_hash is not inside the approval entry, and nothing is deployed. Two open items block the remainder. O-01, the human token tenant, blocks T07 and is not ours alone to decide. O-02, the independent evidence path, blocks T08. 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:29:06 +02:00
**O-03 — Requester identity for an engine-originated memo.** `approval-engine`
does not model a requester. Likely the approval's `principal`; needs confirming
against the object.
**O-04 — `abstain`.** In the state tables and real in Mitzeichnung practice, but
with no obvious `approval-engine` counterpart. Stage 1 scope undecided.
---
## 8. What would make this architecture wrong
- A route that answers whether an act is permitted.
- A validity cache for approvals.
- A second writer of `view_hash`.
- An evidence path reachable only through this component.
- `view_hash` nested inside, or recomputed from, `approval-engine`'s binding
digest — co-reference only (`GH-DEC-2026-012` R3).
- A polling loop against `approval-engine` synthesising an inbox.
- A fail-closed outcome recorded as an approver's decline.
- Describing the decision path as validated while `GH-DEC-2026-010` is open.
Apply GH-DEC-2026-013 and GH-DEC-2026-014; close INFD-IN-0002 Two rulings landed and both corrected something. GH-DEC-2026-013 accepted our binding-versus-awareness argument, wrote it into the record as its §6, and did not change the outcome — it sharpened the defect. Two different facts share one field named tenant: the act-scope, a property of the act that our binding slice commits, and the principal's membership, a property of the person that approval-engine exact-matches. Gate House's correction stands: a binding slice that must commit the scope being entered should commit that scope, not borrow a membership claim to stand in for it. Our schema already does — binding.target IS the act-scope and is inside view_hash — so no field was added, only a statement (PR-08) and a provenance record (PR-09), since key-cape emits tenant as a bare string. key-cape had already implemented registration-bound tenancy on 2026-09-09, correct under both candidate rulings, so the fail-closed-at-first-use risk that made us withhold the client strings was already retired. IN-0002 closed. The one remaining input to T07 is the deployed origin. GH-DEC-2026-014 granted commitment-only evidence and bounded it. It satisfies non-alteration and NOT reconstructability, and must not be described otherwise anywhere. It also corrected our wording of the gap: we wrote that it leaves us able to erase the content, which understates it. Commitment-only moves integrity out of our control and leaves availability entirely inside it — the party that can withhold the content is the party the evidence is about. Limit 3's condition reduced, not removed. The grant carries a condition we did not propose and would not have thought of: the path must assert that committed content exists and where custody sits, so non-production is a finding attributable to the custodian rather than an unremarkable blank. A commitment with no assertion that something is being committed to is indistinguishable from a commitment to nothing. Booked as PR-53, and marked not-a-reversal-candidate. Recorded the meta-rule Gate House named, now in its third setting here: unknown versus absent in the stance map, directory-asserted versus registration-supplied in the tenant claim, erased versus never held in the evidence path. Wherever a system reaches one appearance by two routes, the record must say which route. 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-10 07:57:57 +02:00
- Describing commitment-only evidence as reconstructability
(`GH-DEC-2026-014`).
- Using the token's `tenant` claim as the act-scope, or storing it without its
provenance (`GH-DEC-2026-013` §5).