KB-7628

RS4A-PATCH1-02 — Stable Effect Identity and Uniqueness Axes — 2026-06-21

14 min read Revision 1
rs4a-patch1effect-identitylogical-request-keyuniqueness-axesreplayfail-closeddesign-only2026-06-21

RS4A-PATCH1-02 — Stable Effect Identity and Uniqueness Axes — 2026-06-21

Macro: RS4A-PATCH1 · Mục tiêu A + B (closes Codex C1 replay/effect identity, C3 DB uniqueness axes) Deliverable: 02 of 10 · design-only · correction addendum (does NOT overwrite RS4A-07; does NOT create any surface/constraint) Builds on / corrects: RS4A-07 Replay/Nonce/Attempt Contract v0.2 (replay_key still included run_id; identity axis left undecided). Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO Status: EFFECT_IDENTITY_STABILIZED + UNIQUENESS_AXES_DEFINED_FAIL_CLOSED — identity is now a closed canonical formula; the axes are decided at the contract level; no DB surface carries them today, so the contract fails closed.


0. The two Codex defects this file closes

  • C1 (Codex §9 / §17): "REJECT the current replay-key formula as a stable effect identity while it includes run_id and undefined approval-binding identity." RS4A-07's sample replay_key = H(protocol_version, logical_request_key, canonical_operation, canonical_target, deployed_artifact_hash, owner_or_approval_binding, run_id) is unstable: run_id is execution context (a new run changes the digest), and owner_or_approval_binding did not say whether volatile APR/approval-instance IDs participate (a fresh approval could change the key and buy a duplicate effect).
  • C3 (Codex §4.2 / §17): "REJECT an unspecified identity axis as sufficient for DB uniqueness design." RS4A required UNIQUE on identity axis but never decided whether identity is code, canonical path, artifact hash, a composite, or multiple independent constraints. T-P3-1 assumed duplicate code while other sections reasoned from path/hash.

Both are closed below without creating any schema, column, or constraint.


1. Canonical effect identity (closes C1)

The registrar has exactly one logical effect: register one admitted artifact under one governed authority. Its identity must be a pure function of the effect, never of how/when/who executed it.

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 (canonicalized, symlink/.. resolved)
    canonical_artifact_hash,          # trusted_attested.artifact_hash from Interface F (NEVER request_proposed)
    canonical_owner_scope,            # the owner-of-record SCOPE, not a row id (see §3)
    canonical_authority_policy_ref    # the authority POLICY version, not an approval-instance id (see §3)
)

H is a governed hash over a canonicalized field tuple under protocol_version. effect_identity and logical_request_key are the same key — PATCH1 retires the separate replay_key name and the replay_key ≟ logical_request_key ambiguity that Codex flagged as unsafe. There is one effect key.

1.1 Fields explicitly EXCLUDED from effect identity (Codex C1 mandatory list)

Excluded field Why it is not effect identity If it leaked into the key
run_id observability/execution context a re-run would mint a new effect → duplicate registration
attempt_id execution attempt a retry would mint a new effect
attempt_no retry ordinal (the iu_route_attempt anti-pattern, §4) incrementing attempt re-admits the same effect (REPLAY_ATTEMPT_NO_BYPASS)
authorization_nonce single-use grant credential (a state transition, not an identity) a fresh grant would buy a duplicate effect
timestamps / date_created / last_executed wall-clock every submission would be unique
request freshness / TTL window admissibility gate, not identity (RS4A-07 §4) a stale-then-fresh resubmission would duplicate
replaceable approval-instance id (approval_requests.id, apr_approvals.id) a volatile row id; the same policy can be re-approved re-approval would buy a duplicate effect
transient APR row id same as above same
operator / session id actor context per-operator duplicates
execution host / VPS IP infra context per-host duplicates

Rule (EFFECT_IDENTITY_FIELD_DISCIPLINE): any field whose value can change while the requested effect is identical MUST be excluded from effect_identity. Execution/observability/credential/approval-instance fields are non-identity. They may be bound as non-identity attributes of the consume record (for audit/forensics), but they never participate in the uniqueness digest.

1.2 Fresh-approval and exact-retry behavior (against this identity)

  • Exact retry (same effect_identity, after commit S2): returns the durable prior decision; creates no second effect. (RS4A-07 S2, idempotent replay.)
  • Fresh approval instance, same effect, unchanged authority policy (a new apr_approvals row re-approving the same register_dot policy for the same artifact/owner scope): canonical_owner_scope and canonical_authority_policy_ref are unchangedeffect_identity is unchanged ⇒ this is a duplicate effectREPLAY_DUPLICATE. A fresh approval does not buy a new registration. (This is the exact failure mode Codex C1 named.)
  • Fresh nonce, same effect: identical outcome — REPLAY_DUPLICATE. The nonce authorizes; it is not identity (RS4A-07 RP-02; PATCH1-05 §1).
  • Authority genuinely changed (supersession / policy version bump): see §3 — a changed canonical_authority_policy_ref is a different effect, admissible only if the authority-versioning rule is satisfied; otherwise fail-closed.

2. Canonical DB uniqueness axes (closes C3)

Identity is decided at the contract level as four named axes, not one vague "identity axis." No schema is created; the current surfaces carry none of these, so each axis fails closed today.

Axis Purpose Required? Field(s) Excluded from this axis Current surface status (LIVE 2026-06-21) Fail-closed condition
U1 one committed effect per logical request MANDATORY UNIQUE(effect_identity) (= logical_request_key) run_id, attempt_id/no, nonce, timestamps, approval-instance id absentdot_tools has only dot_tools_pkey PRIMARY KEY (id); no UNIQUE on any effect axis no U1 backstop ⇒ IDENTITY_UNIQUE_ABSENT → HOLD
U2 one consume per authorization grant MANDATORY UNIQUE(authorization_nonce) on a dedicated consume record logical_request_key, attempt_id absent — no nonce/consume surface exists (REPLAY_SURFACE_REQUIRED_NOT_PRESENT); iu_route_attempt rejected (§4) no U2 backstop ⇒ AUTH_NONCE_NOT_DURABLY_CONSUMED → HOLD
U3 at most one current/active head row per DOT code POLICY (optional) UNIQUE(canonical_target_dot_code) WHERE status='active' (partial), if registration semantics allow one current row per code artifact hash, owner absent — no UNIQUE on code; live data already shows duplicate-prone code space (no constraint) undecided ⇒ governed by Owner; until decided, DOT_TOOLS_ROW_DRIFT guarded by U1, fail-closed
U4 an artifact may not be registered more than once POLICY (optional) UNIQUE(canonical_artifact_identity) (path@origin) and/or UNIQUE(canonical_artifact_hash) code, owner absentdot_tools has no hash column at all (G4) and no UNIQUE on file_path undecided ⇒ Owner policy; until decided, fail-closed

2.1 Axis discipline (the C3 fix)

  1. U1 is the effect backstop and is mandatory. Duplicate-effect prevention is U1, not U3/U4. T-P3-1 ("duplicate code") is re-scoped: a duplicate code is caught by U3 (head policy) and/or by U1 when the whole effect repeats — it is not evidence that code is the effect identity.
  2. U2 is the authorization backstop and is mandatory and SEPARATE from U1. Conflating them is LOGICAL_KEY_AND_NONCE_CONFLATED (carried case 43). One axis for what effect, one axis for which grant.
  3. U3 and U4 are POLICY axes, decided by the Owner; they must not be merged into U1. code uniqueness and artifact uniqueness are registration-policy questions (can the same code be re-registered? can one artifact back two codes?) that are orthogonal to single-effect idempotency.
  4. canonical_path / artifact_hash are inputs to U1 and candidates for U4 — they are not, by themselves, "the identity axis." Codex's complaint that "T-P3-1 assumes duplicate code, while other sections reason from path/hash" is resolved: code→U3, path/hash→U4, whole-effect→U1. No section may say "UNIQUE identity axis" unqualified again.
  5. Current DB carries none of U1–U4 (only PRIMARY KEY (id), a surrogate). Therefore the contract is UNIQUENESS_AXES_DEFINED_FAIL_CLOSED: the replacement registrar may not rely on DB-enforced single-effect/single-grant until U1+U2 exist as governed constraints (a CONTRACT_BACKSTOP, Owner/design-gated). This is the same fail-closed posture as D13.

3. Canonical authority binding (the part of C1 about approval identity)

The unstable term in RS4A-07 was owner_or_approval_binding. PATCH1 splits it into two stable, canonical references and one fail-closed rule:

  • canonical_owner_scope — the owner-of-record scope (object scope under governance_object_ownership, selected by the accountable head uq_gov_obj_accountable), not a row id. Re-recording the same accountable owner for the same scope does not change identity. (LIVE: governance_object_ownership = 0 rows ⇒ canonical_owner_scope is unresolvable today ⇒ OWNER_ABSENT fail-closed.)
  • canonical_authority_policy_ref — the policy version that authorizes register_dot for this scope (a governed register_dot action type + its quorum policy), not the approval_requests/apr_approvals instance id. A re-approval under the same policy version is the same authority for identity purposes. (LIVE: apr_action_types has 14 codes, no register_dot; the register-shaped codes are all handler_ref='unimplemented' ⇒ there is no policy version to canonicalize ⇒ APR_NOT_BOUND_TO_ARTIFACT fail-closed.)

3.1 Authority versioning rule

  • Same scope + same policy version + same artifact ⇒ same effect (fresh approval/nonce ⇒ REPLAY_DUPLICATE).
  • A policy supersession (a new governed register_dot policy version, or owner-scope reassignment via assign_governance_owner) changes canonical_authority_policy_ref/canonical_owner_scope ⇒ a different effect, admissible only if (a) the new policy version is itself governed and quorum-bound, and (b) the prior effect's lifecycle permits re-registration under the new authority.
  • If the authority binding cannot be canonicalized to a stable scope+policy reference (e.g. only volatile instance ids are available, or no governed policy exists) ⇒ AUTHORITY_BINDING_IDENTITY_UNSTABLE → fail-closed; the registrar must not compute an effect identity from volatile approval rows. (This is the live state today: no owner-of-record, no register_dot policy ⇒ the authority terms are unresolvable ⇒ the whole effect_identity is fail-closed, which is the correct posture.)

4. Why no live surface carries the axes — iu_route_attempt re-rejected (LIVE)

Re-read live 2026-06-21 (pg_constraint, db directus):

iu_route_attempt_pkey        PRIMARY KEY (id)
iu_route_attempt_idem_uniq   UNIQUE (idempotency_key, attempt_no)
iu_route_attempt_no_chk      CHECK (attempt_no >= 1)
iu_route_attempt_kind_chk    CHECK (route_kind IN ('inbound','outbound'))
iu_route_attempt_status_chk  CHECK (status IN ('pending','dry_run','sent','skipped','failed','disabled'))
  • UNIQUE(idempotency_key, attempt_no) keys the uniqueness with attempt_no(key,1),(key,2)… all insert ⇒ the same idempotency_key recurs across attempts. This is the opposite of U1 (it makes attempt-number a keying field, which §1.1 forbids) and is REPLAY_ATTEMPT_NO_BYPASS.
  • Wrong domain (IU message routing, route_kind inbound/outbound), binds none of U1/U2's fields, no triggers. Rejected as the registrar replay/authorization store; usable only as retry-ledger precedent.

dot_tools itself (LIVE): only PRIMARY KEY (id) + chk_dot_tier/chk_dot_coverage/chk_dot_trigger + fk_dot_tools_domain. No UNIQUE on code, file_path, or any effect/grant axis. So U1, U2, U3, U4 are all REQUIRED_NOT_PRESENT.


5. Corrected proof obligations (replace RS4A-07 §6 item (a))

The required-but-not-present surface must prove ALL: U1 UNIQUE(effect_identity) with run/attempt/nonce/timestamp/approval-instance non-keying; U2 separate UNIQUE(authorization_nonce) consume record; U3/U4 Owner-decided policy axes (not merged into U1); columns binding operation, canonical_target_dot_code, canonical_artifact_identity, canonical_artifact_hash, canonical_owner_scope, canonical_authority_policy_ref; registration domain (not IU routing); atomic in-Phase-3 consume (ON CONFLICT → reject, return prior); proven registrar writer + append-only; exact-retry returns prior decision; retention/tombstone for the replay horizon. No table created.

6. Status

  • Effect identity: EFFECT_IDENTITY_STABILIZED — one canonical effect_identity = logical_request_key, run_id/attempt/nonce/timestamp/approval-instance excluded, authority canonicalized to scope+policy with a fail-closed AUTHORITY_BINDING_IDENTITY_UNSTABLE rule.
  • Uniqueness axes: U1/U2 mandatory, U3/U4 policy — all REQUIRED_NOT_PRESENT on live surfaces ⇒ UNIQUENESS_AXES_DEFINED_FAIL_CLOSED.
  • No schema, no column, no constraint, no surface created. Gate REGISTRATION_HOLD · CAN_PROCEED = NO.
Back to Knowledge Hub knowledge/dev/laws-new/reports/rs4a-patch1/02-stable-effect-identity-and-uniqueness-axes-2026-06-21.md