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
Verified the three published hashes reproduce byte for byte before promoting
anything, then moved the schema, canonicalizer and vectors into governed assets.
history/20260909-initial-exploration/ is untouched and stays the provenance
record.
- schemas/, informed_decision/, tests/vectors/ populated; the reference
canonicalizer's ad-hoc __main__ block replaced by a real
`python -m informed_decision` entry point.
- tests/test_canonicalize.py — 20 tests, all green. Published vectors, all four
isolation properties, canonical-form round-trip, key sorting, and a provenance
test asserting the governed fixtures have not drifted from history/.
- docs/specs/EvidenceModel.md — the two hashes, the split and why it exists, the
four isolation properties, the presentation record, the bundle, and the
relationship to audit-core.
- pyproject.toml, Makefile.
One test of mine was wrong on first run: it scanned for ", " to assert no
insignificant whitespace, which fires on prose inside a brief. Replaced with a
canonical round-trip comparison, which is the property actually meant. The
canonicalizer was correct.
EvidenceModel leads with what the model does NOT claim — no proof of
comprehension, no proof of reading (deliberately, since the alternative is
surveillance), no survival of a compromised surface, and audit-core's inherited
bound that a hash chain cannot prove a record was never sent.
T06 stays progress: the SCOPE.md rewrite is gated on the T02 ruling.
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