The login case forced it and it now applies everywhere. Defaulting a role to
last-used is **required** for situational awareness — an operator who cannot see
which hat they are about to wear is less safe, not more — and is **forbidden**
from silently entering the signed payload. A person must not be bound to
orientation material they did not commit to.
Promotion is the only bridge: moving a field from awareness into binding creates
a new memo version, invalidates outstanding presentations, and copies the named
fields into `awareness_promoted` where `view_hash` covers them (guard
`G_PROMOTE`).
## 4. The four isolation properties
These are the model. Each is a test in `tests/test_canonicalize.py` and each
must stay green; a failure means `view_hash` no longer means what §1 claims.
| # | Property | Protects | Test |
| --- | --- | --- | --- |
| 1 | Shuffling object keys does not change either hash | Any verifier, in any language, agrees with us | `test_key_order_does_not_change_*` |
| 2 | Editing an awareness field does not change `view_hash` | The person is bound only to what they committed to | `test_editing_awareness_does_not_change_view_hash` |
| 3 | Changing `binding.target`**does** change `view_hash` | Positive control — without it, 2 could pass vacuously | `test_changing_binding_target_changes_view_hash` |
| 4 | Selecting a hat after login does not rewrite `view_hash` | Post-bind session state is a different object | `test_post_bind_hat_selection_does_not_change_view_hash` |
Property 3 is not decorative. Properties 1, 2 and 4 are all *negative* — they
assert that things do **not** change the hash. A canonicalizer that returned a
constant would pass all three. Property 3, plus the per-field variants over
`question`, `requested_act`, `binding_level` and `packet`, is what makes the
suite meaningful.
**Published vectors** reproduce byte for byte and are asserted in CI:
```
login view_hash 492d9d31…1b06b8
login awareness_hash 2be77429…4fe05d1
ADR-0042 view_hash 1c89ec07…e91f202
```
**Provenance is tested.** `history/20260909-initial-exploration/` is never
edited. `test_governed_vectors_match_the_preserved_history_copy` asserts the
governed fixtures have not drifted from the founding copies, so a silent edit to
a vector to make a failing test pass is itself a test failure.
## 5. The presentation record
Every render creates one. It carries:
-`memo_id`, `memo_version`
-`principal` — who it was shown to
-`locale`, `ui_release` — both inside `view_hash`
-`rendered_at`
-`acked_highlight_ids`
-`view_hash`, `awareness_hash`
-`phase` — `pre_bind` | `bind` | `post_bind`
A disposition references exactly one presentation, of the same memo version
(guard `G_PRES`). A presentation taken at version *n* cannot bind after the memo
advances to *n+1* — no silent upgrade (`NC-07`).
Because `locale` is inside `view_hash`, the same memo read in German and in
English produces two different presentations of one binding. Intended, and
documented rather than smoothed over (`PR-61`).
## 6. The evidence bundle
An **export**, not a screenshot (`INTENT.md` principle 7). Contains the memo and
all its versions, every presentation with both hashes, every disposition, the
thread, the route as executed, and the append-only hash chain.
Requirements:
- **Verifies offline.** No network, no access to this service. A verifier
recomputes `view_hash` from the bundle's own binding document and compares.
- **Detects mutation.** Altering any covered field breaks verification.
- **States its own bound.** The residuals in §2 travel with the bundle as
metadata. An auditor must not have to read this document to learn that E-03
exists.
- **Marks unverified assertions as such** — see E-06.
## 7. Relationship to `audit-core`
`audit-core` holds the archive; this repository holds the operative record and
produces the export. This surface emits its transitions there and does not
duplicate the archive's role.
Its guarantee is bounded and the bound is inherited, not re-litigated:
`audit-core` is not WORM or object-locked, its tamper evidence is conditional on
live preconditions, and stronger custody was **decided against** in statute §16.
This repository must not plan around a stronger archive, and must not imply the
bundle is more durable than the archive it reconciles against.
## 8. Open — `view_hash` versus the approval binding digest
**Unresolved.** Filed as `INFD-IN-0001` R3 with `gate-house`.
`approval-engine`'s claim carries *"a digest over the same canonical binding the
decision point already computes."* `view_hash` is also a digest over "the
binding". They cover different material: the approval digest exists with no
human in the loop; `view_hash` additionally covers brief, packet, highlights,
locale and UI release.
Until ruled, this repository computes `view_hash` and **asserts no relationship**
between the two. Three candidate outcomes and their costs are set out in
`docs/gate-house-decision-request-layer-placement.md` §2 R3. The outcome to be
avoided is both digests shipping with no stated authority rule, leaving the