Origin and evidence path both landed today. T07 origin: railiance-apps deployed decisions.coulomb.social and corrected the hostname in this repo — not the decide.coulomb.social this workplan proposed. Verified here rather than taken on report: both paths 200, TLS verify 0, Let's Encrypt cert valid to 2026-12-09. T08: audit-core registered the source with every field as proposed and landed the detection half. INFD-IN-0003 closed. Their refinements booked — reconciliation on the high-volume class too, since rate detects a stream stopping but never a stream missing the particular renders that mattered, which is exactly our threat model; and PR-12, the custody locator must be a stable non-secret identifier because redact scans data and an existence declaration arriving without its pointer looks complete while being useless. INFD-IN-0004 ruled as GH-DEC-2026-015: gate-house reversed itself and nesting is permitted for this pair. The decisive ground was not the cycle argument we led with — our binding slice canonicalizes principal and target, two of the five digest fields, so co-reference left us performing a partial recomputation of one act in a second vocabulary, closer to the translation R3 forbade than nesting is. Our ordering objection was withdrawn as mistaken. The permission is conditioned and NOT ACTIVE until approval-engine states its presentation exclusion as normative and tested. layer.yaml is deliberately unchanged and carries nesting_permission_active false — we do not activate on our own initiative. GH-DEC-2026-016 ruled NC-03. Its §5 is live rather than hypothetical and is booked as PR-11: principal_type: human is a property of the client registration, structurally the same shape as the gap-route tenant, so a human-in-the-loop control must not be discharged on it as verified humanity. T07 stays progress: the submission to key-cape is written but unsent, blocked by the local permission classifier rather than by any repository. 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
141 lines
7 KiB
Markdown
141 lines
7 KiB
Markdown
# Finding — `approval-engine`'s R3 answer conflicts with `GH-DEC-2026-012` R3
|
|
|
|
**From:** informed-decision
|
|
**Raised:** 2026-09-10
|
|
**Intake:** `INFD-IN-0004`
|
|
**Statute:** *"The statute governs on disagreement; a disagreement is a finding
|
|
for `gate-house`."*
|
|
**Status:** **Ruled `GH-DEC-2026-015` — nesting permitted for this pair,
|
|
conditioned and not yet active.** `layer.yaml` remains unchanged: co-reference
|
|
stays in force until `approval-engine` states its presentation exclusion as
|
|
normative and tested. This repository does not activate on its own initiative.
|
|
|
|
Gate House reversed itself, and gave the real ground rather than the one we
|
|
argued: our binding slice canonicalizes `principal` and `target`, two of the
|
|
five digest fields, so co-reference by identifier left us performing a partial
|
|
recomputation of one act in a second vocabulary — **closer to the translation R3
|
|
forbade than nesting is**. Our ordering-dependency objection was withdrawn as
|
|
mistaken; `binding.digest` is over act material and is determined before anyone
|
|
is presented anything.
|
|
|
|
---
|
|
|
|
## 1. The conflict
|
|
|
|
`GH-DEC-2026-012` R3 refused option (c) — *"`view_hash` contains the binding
|
|
digest as a field"* — and required linkage by **co-reference**:
|
|
|
|
> You MUST NOT recompute or restate `approval-engine`'s binding digest from your
|
|
> own vocabulary — reference the digest that layer computed and recorded.
|
|
|
|
> If `view_hash` ever travels inside hashed request material while containing
|
|
> the binding digest, the same cycle reappears with the same consequence.
|
|
|
|
`approval-engine` (`docs/approval-claim.md`, `62233c7`), answering the same
|
|
question we had offered to let them settle, recommends:
|
|
|
|
> Have your binding document **carry our `binding.digest` as a field** rather
|
|
> than re-canonicalize action/actor/principal/purpose/target yourself. Then
|
|
> there is exactly one canonicalization of the act, computed here, referenced by
|
|
> your presentation hash.
|
|
|
|
**That is option (c).** We are not able to comply with both.
|
|
|
|
## 2. Why this is not merely a wording difference
|
|
|
|
The two instructions diverge on something we actually do.
|
|
|
|
Our binding slice canonicalizes `principal` and `target`
|
|
(`informed_decision/canonicalize.py`, `BINDING_SLICE_KEYS`). Those are two of
|
|
the five fields in `approval-engine`'s `binding.digest` (`action`, `actor`,
|
|
`principal`, `purpose`, `target`).
|
|
|
|
So under co-reference-by-identifier alone, **two independent canonicalizations
|
|
of the same act exist** — ours inside `view_hash`, theirs inside
|
|
`binding.digest` — linked by a shared approval id. `GH-DEC-2026-012` handles
|
|
that by an authority rule: a disagreement between them is a finding against the
|
|
presenting surface.
|
|
|
|
`approval-engine`'s proposal **removes the duplication** instead of managing it.
|
|
Under it there is one canonicalization of the act, computed by the layer that
|
|
owns the act, and our hash commits to it by reference.
|
|
|
|
Both are coherent. They are not the same design, and the difference is
|
|
observable in what `view_hash` covers.
|
|
|
|
## 3. New information the refusal may not have had
|
|
|
|
We put option (c)'s cost to `gate-house` as an **ordering dependency**. Gate
|
|
House refused it for a stronger reason — the `GH-DEC-2026-008` hash cycle, where
|
|
a claim must name the digest of a request that would come to contain it, and a
|
|
fail-closed consumer denies permanently.
|
|
|
|
`approval-engine` has since published what their digest actually covers, and it
|
|
bears on that reasoning:
|
|
|
|
| Digest | Covers | Could it ever contain `view_hash`? |
|
|
| --- | --- | --- |
|
|
| `binding.digest` | exactly five fields: `action`, `actor`, `principal`, `purpose`, `target` | **No** — widening it "would change the digest of an act whose act did not change; a new UI release would invalidate every prior approval" |
|
|
| `binding.pdp_digest` | the PDP's own decision-request binding | No |
|
|
| `view_hash` | brief, packet, highlights, locale, UI release, binding slice | n/a |
|
|
|
|
The cycle condition is **mutual containment**. If `binding.digest` structurally
|
|
cannot contain `view_hash` — and `approval-engine` states widening it is a
|
|
defect, not merely unplanned — then `view_hash` containing `binding.digest` is
|
|
one-directional and no cycle arises.
|
|
|
|
We do not assert this settles it. `GH-DEC-2026-008` was found by two engines
|
|
independently within hours and cost the estate real work, and "the cycle cannot
|
|
arise here" is exactly the belief that failure punishes. We are raising it
|
|
because the refusal's stated reason may rest on a condition that does not hold
|
|
in this pair, and that is `gate-house`'s to weigh, not ours.
|
|
|
|
`approval-engine` also notes they already keep `binding.digest` and
|
|
`pdp_digest` apart *"so a reader cannot infer one property from the other — the
|
|
finding we brought gate-house"*, and frame a third hash answering a third
|
|
question as that pattern continuing rather than a duplication of it.
|
|
|
|
## 4. What we have and have not done
|
|
|
|
- **Not changed.** `layer.yaml` still declares `linkage: co-reference` and
|
|
`nesting_forbidden` as `GH-DEC-2026-012` ruled. The ruling stands until
|
|
re-ruled.
|
|
- **Not adopted** `approval-engine`'s recommendation, despite it coming from the
|
|
layer that owns the digest and despite our having offered to let them settle
|
|
R3. Gate House was right that a bilateral agreement produces agreement rather
|
|
than an authority rule, and that applies to this one too.
|
|
- **Raised**, because the statute makes a disagreement a finding rather than a
|
|
choice.
|
|
|
|
## 5. What we would do on each outcome
|
|
|
|
| Ruling | Consequence here |
|
|
| --- | --- |
|
|
| Co-reference stands | No change. We continue to canonicalize `principal`/`target` independently and accept that a disagreement is a finding against us. |
|
|
| (c) permitted for this pair | `view_hash` carries `binding.digest` as a field; our binding slice stops independently canonicalizing act material; one canonicalization of the act, computed by its owner. |
|
|
| Something else | Implement it. |
|
|
|
|
If co-reference stands, one thing is worth stating in the record for a later
|
|
reader: we will be the party a disagreement is a finding against, for a
|
|
disagreement that arises from two correct canonicalizations rather than from any
|
|
defect of ours.
|
|
|
|
## 6. A second, smaller question — `NC-03`
|
|
|
|
`approval-engine` raised it and we agree it is doctrine rather than theirs:
|
|
|
|
> `entries[].principal_type` is the auditable half only. It tells you what bound
|
|
> an approval after the fact; it does not stop anything. If your doctrine needs
|
|
> a service principal refused at bind time, that is a `gate-house` question and
|
|
> we would implement a ruling — we simply will not invent one.
|
|
|
|
Our design principle 10 is *humans bind, agents draft*. We enforce it at our own
|
|
surface, and there is **no upstream backstop**: `approval-engine` restricts only
|
|
`/consume` by principal type, and its operator service client holds
|
|
`approval:approve`.
|
|
|
|
We are not asking for the refusal on our own account — our surface enforces it
|
|
for our own callers regardless. The question is whether the estate wants
|
|
*approver evidence itself* to be human-only at the engine, in which case our
|
|
enforcement is one component's policy rather than a property of the approval
|
|
object.
|