KB-272F

RS4A-PATCH2-02 — Effect Identity with Authorization Binding Separated — 2026-06-21

14 min read Revision 1
rs4a-patch2effect-identityauthorization-binding-digestu1business-effect-onlyfail-closeddesign-only2026-06-21

RS4A-PATCH2-02 — Effect Identity with Authorization Binding Separated — 2026-06-21

Macro: RS4A-PATCH2 · Mục tiêu A + B (closes Codex re-review residual R1: authority scope/policy still participates in U1 effect identity) Deliverable: 02 of 6 (under rs4a-patch2/) · design-only · scoped correction addendum Corrects: RS4A-PATCH1-02 §1 (effect-identity formula still hashed canonical_owner_scope + canonical_authority_policy_ref) and §3 (authority canonicalized into the identity). Does NOT overwrite PATCH1 or RS4A; does NOT create any schema/column/constraint. Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO Status: EFFECT_IDENTITY_BUSINESS_EFFECT_ONLY + AUTHORIZATION_BINDING_SEPARATED — U1 now keys only the business registry effect; authority evidence is bound to the attempt/decision record but excluded from U1.


0. The residual defect this file closes (Codex re-review §3 / §12.1)

PATCH1 correctly excluded run_id, attempt_id/no, nonce, timestamps, TTL, operator/session, and volatile approval-instance ids. But it still hashed canonical_owner_scope and canonical_authority_policy_ref into effect_identity. Codex:

"A reassigned owner scope or policy-version change therefore creates a new U1 key for the same operation, code, artifact identity, and artifact hash. PATCH1 explicitly calls that a 'different effect.' It is not: authority determines whether an effect is authorized; it does not change the registry effect being requested. … A policy change could bypass U1 and attempt a second registration."

Codex's required correction (mandatory):

  • effect_identity = stable business effect only (operation + canonical target + canonical artifact identity/hash);
  • authorization_binding_digest = owner scope + authority policy + approval/nonce evidence, bound to the attempt/consume record but excluded from U1;
  • policy/owner changes may authorize or deny a new attempt, but must not mint a new registration effect;
  • re-registration under changed lifecycle must use an explicit different operation, not a changed authorization digest.

This file makes exactly that split. No schema, column, or constraint is created.


1. Effect identity v2 (closes R1 — business effect only)

effect_identity = logical_request_key = H(
    protocol_version,                 # versioned hashing/canonicalization contract
    operation = "register_dot",       # fixed canonical operation
    canonical_target_dot_code,        # the one scalar DOT code (canonicalized)
    canonical_artifact_identity,      # canonical_path @ origin (symlink/.. resolved)
    canonical_artifact_hash           # trusted_attested.artifact_hash from Interface F (NEVER request_proposed)
)

H is a governed hash over a canonicalized field tuple under protocol_version. effect_identity and logical_request_key remain the same single key (PATCH1 retired the replay_key alias; PATCH2 keeps one key and removes the two authority terms PATCH1 had left in it).

1.1 Fields EXPLICITLY EXCLUDED from effect identity (Codex re-review mandatory list)

PATCH2 adds the two authority terms PATCH1 missed (★) to the existing exclusion set:

Excluded field Why it is not effect identity
canonical_owner_scope authority/accountability, not the requested effect — a reassigned owner does not change what artifact/code is being registered
canonical_authority_policy_ref authority policy version, not the requested effect — a policy bump does not change the registry effect
★ approval instance id (approval_requests.id) volatile approval-instance row id
★ APR row id (apr_approvals.id) volatile approval-instance row id
★ owner row id (governance_object_ownership.id) volatile authority row id
authorization_nonce single-use grant credential (a state transition, not identity)
attempt_id execution attempt
attempt_no retry ordinal (the iu_route_attempt anti-pattern) — keying on it is REPLAY_ATTEMPT_NO_BYPASS
run_id observability/execution context
timestamps / date_created / last_executed wall-clock
request TTL / freshness window admissibility gate, not identity
operator / session / host / VPS IP actor/infra context

Rule (EFFECT_IDENTITY_BUSINESS_EFFECT_DISCIPLINE): effect_identity is a pure function of what registry effect is requested — operation, target code, artifact identity, artifact hash. Any authority/accountability/credential/execution field is excluded. Authority answers may this effect be admitted; it never answers which effect this is.

1.2 Why removing authority from U1 is the correct (and safer) posture

PATCH1 reasoned: "fresh approval under unchanged policy ⇒ unchanged authority terms ⇒ same key ⇒ REPLAY_DUPLICATE." That was right for the unchanged-policy case but wrong for the changed-policy case: a genuine owner reassignment or policy-version bump changed the authority terms ⇒ changed the U1 key ⇒ the same artifact/code could be registered a second time. PATCH2 closes that hole: because authority is no longer in U1, the same operation/code/artifact/hash yields the same U1 key regardless of any authority change, so the duplicate is caught by U1 every time. (See AUTHORIZATION_CHANGED_SAME_EFFECT_DUPLICATE, §3.)


2. Authorization binding digest (closes R1 — authority evidence bound separately)

Authority evidence is preserved in full — it is simply bound to the attempt/consume/decision record, not to U1.

authorization_binding_digest = H(
    protocol_version,
    effect_identity,                  # binds the authorization TO the effect, without being part of U1
    canonical_owner_scope,            # owner-of-record SCOPE (governance_object_ownership accountable head), not a row id
    canonical_authority_policy_ref,   # the governed register_dot policy VERSION, not an approval-instance id
    approval_evidence_ref,            # reference to the register_dot APR + decision (instance), as evidence not identity
    quorum_evidence_ref,              # reference to the quorum/approvals proof
    authorization_nonce_issuer,       # the authority that minted the single-use grant (not the nonce value as identity)
    authorization_window              # the validity window of the authorization (admissibility, not identity)
)

2.1 Rules (Codex re-review §3 / §12.1)

  1. authorization_binding_digest is REQUIRED for admission, but is NOT U1. A registration cannot be admitted without a resolved authorization binding; the binding is recorded on the Phase-3 attempt/consume record (PATCH1-05 §2) as non-identity evidence.
  2. Authority changes may authorize or deny an attempt, but do not mint a new registration effect. Two attempts with different authorization_binding_digest values but the same effect_identity are two attempts at one effect.
  3. Same operation/code/artifact under changed owner/policy = same U1 effect_identity ⇒ must not create a second registration. It is REPLAY_DUPLICATE at U1; the changed authority is recorded as new authorization evidence on the attempt, not as a new effect.
  4. Intentional re-registration is a different OPERATION, not authority drift. If lifecycle genuinely wants to re-register, it must use an explicit, governed, different operation — e.g. register_dot_revision, supersede_dot_registration, or another governed lifecycle operation — which changes operation (and therefore legitimately changes effect_identity). Authority-digest drift must never be the re-registration mechanism.

2.2 Binding location (no new surface invented)

authorization_binding_digest lives where PATCH1-05 §2 already puts authority consumption: the Phase-3 atomic attempt/consume record, alongside the consumed authorization_nonce (U2) and the consumed effect_identity (U1). It is a bound non-identity attribute of that record. No new table/column is created here; like every other carrier in this package, the binding record is REQUIRED_NOT_PRESENT on live surfaces and therefore fails closed today (no owner-of-record, no register_dot policy — see §4).


3. Required reject set (Codex re-review §3)

Reject code Trigger
AUTHORIZATION_CHANGED_SAME_EFFECT_DUPLICATE a second attempt presents the same effect_identity with a changed authorization_binding_digest (new owner/policy/approval) — U1 already consumed ⇒ duplicate registration refused; the changed authority is logged as evidence, not honored as a new effect
AUTHORITY_BINDING_UNRESOLVED authorization_binding_digest cannot be canonicalized to a stable scope + governed policy version (only volatile instance ids available, or no governed policy exists) ⇒ admission fail-closed
AUTHORIZATION_EVIDENCE_MISSING no approval_evidence_ref / quorum_evidence_ref / bound nonce issuer present ⇒ admission fail-closed
REPLAY_DUPLICATE the same effect_identity is presented after commit (any authority, fresh run/nonce/approval) ⇒ returns the durable prior decision, mints no second effect

3.1 Behavior matrix (against the v2 split)

Scenario effect_identity authorization_binding_digest Outcome
Exact retry, same everything unchanged unchanged return durable prior decision (idempotent)
Same effect, different run_id unchanged unchanged same effect ⇒ prior decision (run_id non-keying)
Same effect, fresh nonce unchanged changed (new nonce issuance) REPLAY_DUPLICATE (nonce non-identity)
Same effect, fresh approval instance, same policy unchanged changed (new approval evidence) REPLAY_DUPLICATE (approval instance non-identity)
Same effect, changed owner scope / policy version unchanged changed AUTHORIZATION_CHANGED_SAME_EFFECT_DUPLICATE — authority revalidated, but no second registration
Genuinely new effect (register_dot_revision/supersede_*) changed (operation differs) changed admissible iff the new operation + authority are governed and lifecycle permits

The decisive PATCH2 fix is the fifth row: under PATCH1 it would have produced a new U1 key (a second registration); under PATCH2 it is a duplicate at U1.


4. Live posture (read-only query_pg, db directus, 2026-06-21) — overall still fail-closed

The separation does not weaken the gate; it relocates the failure attribution:

  • governance_object_ownership = 0 rowscanonical_owner_scope unresolvable ⇒ AUTHORITY_BINDING_UNRESOLVED ⇒ admission fail-closed (G2).
  • apr_action_types = 14 codes, no register_dot; register-shaped codes handler_ref='unimplemented' ⇒ no governed canonical_authority_policy_refAUTHORITY_BINDING_UNRESOLVED (G3).
  • dot_tools constraints (LIVE, re-confirmed): only dot_tools_pkey PRIMARY KEY (id), chk_dot_tier (A/B), chk_dot_coverage, chk_dot_trigger, fk_dot_tools_domainno UNIQUE on any effect/grant axis ⇒ U1/U2 REQUIRED_NOT_PRESENT.

Net change vs PATCH1: previously the whole effect_identity was fail-closed because authority terms were inside it (AUTHORITY_BINDING_IDENTITY_UNSTABLE). Now effect_identity is computable from business fields alone, and the fail-closed condition moves to admission: no admission without a resolved authorization_binding_digest (AUTHORITY_BINDING_UNRESOLVED). The registration outcome is identical — HOLD / fail-closed — but the contract is now correct: a future authority change can never mint a duplicate registration.


5. What this corrects in PATCH1 (precise, no overwrite)

PATCH1 location PATCH1 text PATCH2 correction
PATCH1-02 §1 formula effect_identity = H(…, canonical_owner_scope, canonical_authority_policy_ref) remove both authority terms from effect_identity (§1)
PATCH1-02 §1.2 / §3.1 "changed authority policy ⇒ a different effect" changed authority ⇒ same effectAUTHORIZATION_CHANGED_SAME_EFFECT_DUPLICATE; re-registration needs a different operation (§2.1.4, §3)
PATCH1-02 §3 authority canonicalized into identity; AUTHORITY_BINDING_IDENTITY_UNSTABLE authority canonicalized into a separate authorization_binding_digest bound to the attempt record; fail-closed becomes AUTHORITY_BINDING_UNRESOLVED at admission (§2, §4)

U1 axis (PATCH1-02 §2 UNIQUE(effect_identity)) is unchanged in form; only its input set narrows to business-effect fields. U2/U3/U4 are unaffected by this file (U3 is handled in PATCH2-03).

6. Status

  • EFFECT_IDENTITY_BUSINESS_EFFECT_ONLY — U1 keys operation + target code + artifact identity + artifact hash; all authority/credential/execution fields excluded.
  • AUTHORIZATION_BINDING_SEPARATED — owner scope + policy + approval/quorum/nonce-issuer/window bound to the Phase-3 attempt/consume record as non-identity evidence, required for admission, excluded from U1.
  • Changed-authority/same-effect ⇒ duplicate (never a new registration); intentional re-registration ⇒ explicit different operation.
  • No schema/column/constraint; overall registration fail-closed (now via AUTHORITY_BINDING_UNRESOLVED at admission). Gate REGISTRATION_HOLD · CAN_PROCEED = NO.
Back to Knowledge Hub knowledge/dev/laws-new/reports/rs4a-patch2/02-effect-identity-with-authorization-binding-separated-2026-06-21.md