KB-41AE

RS4A-PATCH2-03 — U3 Current-Head Uniqueness Policy — 2026-06-21

10 min read Revision 1
rs4a-patch2u3current-headdraftactivelifecycle-roleduplicate-draft-headfail-closeddesign-only2026-06-21

RS4A-PATCH2-03 — U3 Current-Head Uniqueness Policy — 2026-06-21

Macro: RS4A-PATCH2 · Mục tiêu C (closes Codex re-review residual R2: U3 defined only for status='active' while registration writes status='draft') Deliverable: 03 of 6 (under rs4a-patch2/) · design-only · scoped correction addendum Corrects: RS4A-PATCH1-02 §2 (U3 = UNIQUE(canonical_target_dot_code) WHERE status='active'). Does NOT overwrite PATCH1/RS4A; does NOT create any index/constraint. Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO Status: U3_HEAD_CURRENT_UNIQUENESS_DEFINED (Option 1) — one current/head row per canonical DOT code across the non-terminal lifecycle states {draft, active}; the enforcing surface is REQUIRED_NOT_PRESENT ⇒ fail-closed before any draft write.


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

PATCH1's U3 was UNIQUE(canonical_target_dot_code) WHERE status='active'. Codex:

"WHERE status='active' does not protect the state created by registration, because Phase 3 writes status='draft'. Two different artifacts or authority-policy versions can therefore create multiple draft rows for the same code before either becomes active. This also contradicts Phase 4's requirement to read exactly one row for dot_code."

Codex's required correction (choose one):

  • Option 1 — define one current/head row across all non-terminal lifecycle states, including draft and active; or
  • Option 2 — leave the exact U3 formula unresolved for the Owner while explicitly failing closed before any draft write.

PATCH2 adopts Option 1 (preferred), because it is directly consistent with the live, governed Directus status vocabulary.


1. Live evidence supporting Option 1 (read-only query_pg, db directus, 2026-06-21)

Fact Value (LIVE) Bearing on U3
directus_fields.dot_tools.status.options.choices {draft, active, deprecated, retired} (validation=null, required=false) the governed lifecycle vocabulary exists and is exactly four states
field note "Trạng thái: draft/active/deprecated/retired" declares the lifecycle order draft → active → deprecated → retired
dot_tools constraints only PRIMARY KEY (id), chk_dot_tier, chk_dot_coverage, chk_dot_trigger, fk_dot_tools_domain no UNIQUE on code ⇒ no head protection today
dot_tools.status data active 291 · published 16 (out-of-vocab) · null 2 · draft 0 head/code space is currently unconstrained; out-of-vocab rows already exist

The four governed states partition cleanly into current/head (draft, active) and terminal/non-head (deprecated, retired), which is what Option 1 requires. The vocabulary is not invented; it is the field's declared SSOT.


2. U3 v2 — current-head uniqueness (closes R2, Option 1)

2.1 Canonical formula (lifecycle-role form)

U3:  UNIQUE(canonical_target_dot_code) WHERE lifecycle_role = "current_head"

lifecycle_role is a derived classification of status, not a new business column:

lifecycle_role(status) =
    "current_head"  if status IN ('draft', 'active')      -- non-terminal: at most ONE per code
    "terminal"      if status IN ('deprecated', 'retired') -- terminal/non-head: unconstrained count

2.2 Design-level equivalent (since live dot_tools has no lifecycle_role column)

U3 (equivalent partial uniqueness):
    UNIQUE(canonical_target_dot_code) WHERE status IN ('draft','active')
=>  one current head per canonical_target_dot_code across statuses {draft, active}
    terminal/non-head statuses {deprecated, retired} are NOT counted toward the head

Either realization (a derived lifecycle_role generated column + partial unique, or a partial unique index WHERE status IN ('draft','active')) is a future, Owner/design-gated surface. Neither exists today (no UNIQUE on code), so U3 is REQUIRED_NOT_PRESENT ⇒ fail-closed (§4).

2.3 Policy

  • draft and active are current/head states; at most one such row may exist per canonical_target_dot_code.
  • deprecated and retired are terminal/non-head states; any number may exist (history).
  • Registration may create a draft row only if no existing draft or active current head exists for the same canonical code.
  • Activation changes a row draft → active in place; it does not create another head (the head count stays at one).
  • Replacement / supersession must first retire/deprecate the old head (active → deprecated/retired) or use an explicit governed lifecycle operation (cf. PATCH2-02 §2.1: register_dot_revision / supersede_dot_registration). Only then may a new head be created.

2.4 Reject set (Codex re-review §9 / §12.2)

Reject code Trigger
DUPLICATE_CURRENT_HEAD a write would yield two current-head rows (draft/active) for one code
DRAFT_HEAD_ALREADY_EXISTS registration attempts a second draft for a code that already has a draft head
ACTIVE_HEAD_ALREADY_EXISTS registration attempts a draft for a code that already has an active head (must supersede/retire first)
HEAD_POLICY_UNRESOLVED the head-uniqueness surface cannot be resolved/enforced ⇒ fail closed before any draft write (the live state today, §4)

3. U3 is not U1 — axis discipline (carried + sharpened)

Axis Prevents Keyed on This file
U1 duplicate exact effect effect_identity (business-effect only, PATCH2-02) unchanged
U2 duplicate grant consume authorization_nonce unchanged
U3 multiple current heads per code canonical_target_dot_code WHERE current_head redefined here (across draft+active)
U4 duplicate artifact registration canonical_artifact_identity / hash remains Owner policy
  • U3 ≠ U1. U1 stops the same effect from committing twice; U3 stops two different effects (different artifact/authority) from both producing a current head for the same code. The "duplicate draft head" case (two distinct artifacts, same code, both draft) is U3, not U1 — U1 would not catch it because the effects differ.
  • U4 may remain Owner policy, but per Codex it cannot be relied upon to repair an unstable U1 or a draft-head gap. U3 is the head backstop; U4 is a separate artifact-reuse policy.

4. Live posture — surface absent ⇒ fail-closed before draft write

  • dot_tools has no UNIQUE on code (LIVE) ⇒ the U3 partial-unique / lifecycle_role head index is REQUIRED_NOT_PRESENT.
  • Therefore U3 is defined at the contract level (Option 1) but not enforceable on the live surfaceHEAD_POLICY_UNRESOLVED at the DB layer ⇒ the replacement registrar must fail closed before any draft write (it must not write a draft row it cannot prove is the sole current head).
  • This is the same fail-closed class as U1/U2 (REQUIRED_NOT_PRESENT) and D13: the policy is decided; the enforcing constraint is a future Owner/design-gated surface. Until the partial-unique exists, no draft is written.

(Live data shows draft = 0 and 16 out-of-vocab published rows — i.e. the head space is presently unconstrained and even the vocabulary can drift, which is exactly why the surface must be added before any registration draft is written. The status-domain CHECK backstop carried in PATCH1-03 (STATUS_DOMAIN_NOT_DB_ENFORCED) is a prerequisite for the lifecycle_role partition to be trustworthy.)


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

PATCH1 location PATCH1 text PATCH2 correction
PATCH1-02 §2 (U3 row) UNIQUE(canonical_target_dot_code) WHERE status='active' UNIQUE(canonical_target_dot_code) WHERE lifecycle_role='current_head' = across {draft, active} (§2)
PATCH1-02 §2.1.1 "duplicate code is caught by U3 (head policy) and/or U1" retained, but U3 head now spans draft+active so a duplicate draft head is caught (§2.3)
PATCH1-08 §4 (axes table) U3 = UNIQUE(code) WHERE status='active' U3 = current-head across {draft, active}; terminal = {deprecated, retired}

U3 remains a policy axis in the sense that the Owner ratifies the partial-unique surface; PATCH2 fixes the predicate so the decided policy actually protects the registration (draft) state. This is Option 1, so the verdict is not RS4A_PATCH2_HOLD_U3_HEAD_POLICY_UNRESOLVED.

6. Status

  • U3_HEAD_CURRENT_UNIQUENESS_DEFINED (Option 1): one current head per canonical_target_dot_code across {draft, active}; {deprecated, retired} terminal/non-head.
  • Registration writes draft only if no draft/active head exists; activation is in-place draft→active; replacement must retire/deprecate first or use an explicit lifecycle operation.
  • Surface REQUIRED_NOT_PRESENT (no UNIQUE on code live) ⇒ fail closed before any draft write.
  • No index/constraint created; no DDL. Gate REGISTRATION_HOLD · CAN_PROCEED = NO.
Back to Knowledge Hub knowledge/dev/laws-new/reports/rs4a-patch2/03-u3-current-head-uniqueness-policy-2026-06-21.md