Enforce declared human controls at approval binding

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-10 19:26:12 +02:00
parent a3c94fb241
commit be1a388a84
17 changed files with 441 additions and 40 deletions

View file

@ -53,22 +53,21 @@ the deployed issuer's `/jwks` (RS256) and carry:
The **access** token is what we validate. `id_token` appears nowhere in this
codebase; the ID token belongs to the login client and is never evidence here.
**Correction to our 2026-09-09 message.** We said an agent token cannot hold
`approval:approve` under the requested registrations. That is wrong twice: the
`approval-engine-operator` service client holds `approval:approve`, and this
engine does not restrict `/entries` by principal type at all — only `/consume`
is restricted, to `service`/`agent`. So a non-human principal can supply
approver evidence today.
**GH-DEC-2026-016 is now implemented in the source candidate.** An approval
explicitly declared with `human_control: true` refuses service/agent binds at
`/entries`, irrespective of what the caller submits in the body. The verified
human identity supplies the entry. The UI retains its own humans-bind-agents-draft
rule and must require the declared human-control object for that workflow; an
undeclared historical approval must not be relabelled from its human entries.
Request a new declared object when needed. The requester may be a service; it
creates an unapproved request and cannot supply human judgment.
Whether it *should* be able to is approval doctrine and belongs to
`gate-house`, not to us and not to you. What we have done instead is make it
visible: schema v4 records the verified `principal_type` on every entry
(`tests/test_auth.py::test_entry_records_the_verified_principal_type`,
`::test_non_human_approver_is_recorded_as_such`). Your design principle 10
("humans bind, agents draft") is therefore enforceable in the evidence chain
rather than assumed — read `entries[].principal_type` and do not infer the
answer from the shape of `subject_id`. Entries written before v4 are `null` and
must not be read as `human`.
The engine still admits service-to-service approvals when no human control was
declared. The flag neither grants a scope nor identifies which acts require a
human; those remain owner doctrine. See [caller-authentication.md](caller-authentication.md)
for the issuer's human-type provenance and remaining native acceptance. The
source candidate requires schema v5 and a new image; the current production
manifest is not evidence that this enforcement is deployed.
## 3. Open question A — the human client cannot read the approval it renders