RS4A-PATCH1-02 — Stable Effect Identity and Uniqueness Axes — 2026-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_idand undefined approval-binding identity." RS4A-07's samplereplay_key = H(protocol_version, logical_request_key, canonical_operation, canonical_target, deployed_artifact_hash, owner_or_approval_binding, run_id)is unstable:run_idis execution context (a new run changes the digest), andowner_or_approval_bindingdid 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 axisas sufficient for DB uniqueness design." RS4A requiredUNIQUE on identity axisbut never decided whether identity iscode, canonical path, artifact hash, a composite, or multiple independent constraints. T-P3-1 assumed duplicatecodewhile 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_approvalsrow re-approving the sameregister_dotpolicy for the same artifact/owner scope):canonical_owner_scopeandcanonical_authority_policy_refare unchanged ⇒effect_identityis unchanged ⇒ this is a duplicate effect →REPLAY_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_refis 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 | absent — dot_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 | absent — dot_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)
- 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
codeis the effect identity. - 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. - U3 and U4 are POLICY axes, decided by the Owner; they must not be merged into U1.
codeuniqueness 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. canonical_path/artifact_hashare 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.- Current DB carries none of U1–U4 (only
PRIMARY KEY (id), a surrogate). Therefore the contract isUNIQUENESS_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 undergovernance_object_ownership, selected by the accountable headuq_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_scopeis unresolvable today ⇒OWNER_ABSENTfail-closed.)canonical_authority_policy_ref— the policy version that authorizesregister_dotfor this scope (a governedregister_dotaction type + its quorum policy), not theapproval_requests/apr_approvalsinstance id. A re-approval under the same policy version is the same authority for identity purposes. (LIVE:apr_action_typeshas 14 codes, noregister_dot; the register-shaped codes are allhandler_ref='unimplemented'⇒ there is no policy version to canonicalize ⇒APR_NOT_BOUND_TO_ARTIFACTfail-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_dotpolicy version, or owner-scope reassignment viaassign_governance_owner) changescanonical_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, noregister_dotpolicy ⇒ the authority terms are unresolvable ⇒ the wholeeffect_identityis 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 withattempt_no—(key,1),(key,2)… all insert ⇒ the sameidempotency_keyrecurs across attempts. This is the opposite of U1 (it makes attempt-number a keying field, which §1.1 forbids) and isREPLAY_ATTEMPT_NO_BYPASS.- Wrong domain (IU message routing,
route_kindinbound/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 canonicaleffect_identity = logical_request_key, run_id/attempt/nonce/timestamp/approval-instance excluded, authority canonicalized to scope+policy with a fail-closedAUTHORITY_BINDING_IDENTITY_UNSTABLErule. - Uniqueness axes: U1/U2 mandatory, U3/U4 policy — all
REQUIRED_NOT_PRESENTon live surfaces ⇒UNIQUENESS_AXES_DEFINED_FAIL_CLOSED. - No schema, no column, no constraint, no surface created. Gate
REGISTRATION_HOLD·CAN_PROCEED = NO.