RS4A-02 — Registrar Hardening Target Contract v0.2 — 2026-06-21
RS4A-02 — Registrar Hardening Target Contract v0.2 — 2026-06-21
Macro: RS4A · Mục tiêu B
Deliverable: 02 of 14 · design-only (no code, no implementation, no patch, no registration)
Builds on: RS3B-03 Single-Artifact Governed Registrar Contract v0.1; promoted to v0.2 by consuming the recovered source (RS3C-02/03) and live reads (this macro).
Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO
Status: CONTRACT_V0_2_DEFINED_SOURCE_AWARE — target contract for a governed replacement registrar; the operational dot-dot-register is NON-COMPLIANT with every material clause (RS4A-01, RS4A-03). This is a contract schema + reject-code table + phase table, not an implementation.
What changed v0.1 → v0.2: v0.1 was CONTRACT_CRITERIA_DEFINED_PENDING_SOURCE. Now the source is read: the contract is reconciled against the actual input shape (no scalar target, mass glob), the actual write (status:"active" REST POST, fail-open), the actual dedup (fragile grep + no DB UNIQUE), and the live activation condition (tier∈watch ∧ status='active'). Each reject code is now anchored to a source defect (D-id) it must categorically prevent.
1. Design intent and anti-mega rules
One invocation registers exactly one admitted artifact into dot_tools — never a scan, never "all untracked bin/dot-*". The registrar registers; it does not activate (activation is a separate Owner-gated phase, RS4A-09). The contract is a pure dict/envelope contract joined to its dependencies only by explicit envelopes (Owner, APR, Interface F, replay surface, audit sink). Per the standing đầu-bài constraints:
- No mega-registry — reuse target surface
dot_tools(309 rows live); no new registry/table/collection. - No mega-graph, no mega-birth pipeline — registration writes one inert row and ends; it triggers no chained automation.
- Each part born / tested / replaced / rolled-back separately, joined by contract. The Owner envelope, the artifact resolver (F), the replay surface, and the audit sink are independent blocks (RS4A-05/06/07/08), each independently fail-closed.
2. Input schema registrar_request v0.2
Caller-side fields are request_proposed.* (untrusted; never self-promoting). A proposed value is honored only after a reread trusted_attested.* row agrees (the request_proposed-vs-trusted_attested hard split, Codex RS3-PATCH2). The single-use authority argument is separate from the dict (so it cannot be replayed as data).
| Field | Tier | Meaning / binding | Reject code if absent/invalid | Closes defect |
|---|---|---|---|---|
dot_code |
proposed | the one DOT code to register (scalar) | MISSING_DOT_CODE |
D03 |
artifact_path |
proposed | canonical path of the one admitted artifact | MISSING_ARTIFACT_PATH |
D03 |
admission_ref |
proposed | KB/registry ref of the birth-admission record | MISSING_ADMISSION_REF / ARTIFACT_NOT_ADMITTED |
D08 |
artifact_hash |
proposed | claimed deployed-artifact hash (resolved/verified by Interface F, RS4A-06) | MISSING_ARTIFACT_HASH |
D09 |
hash_algorithm + canonicalization_version |
proposed | how artifact_hash was computed |
MISSING_HASH_ALGO / UNKNOWN_CANONICALIZATION |
D09 |
artifact_type |
proposed | declared executable type (e.g. bash), reconciled vs admitted artifact |
ARTIFACT_TYPE_MISMATCH |
D21 |
origin |
proposed | deployed origin (path root / commit) | MISSING_ORIGIN |
D09 |
owner_envelope_ref |
proposed | ref into governance_object_ownership head row |
OWNER_ABSENT (live 0 rows → fail-closed) |
D08 |
approval_envelope_ref |
proposed | APR ref + quorum proof binding this artifact_hash | APR_NOT_BOUND_TO_ARTIFACT (live: no register_dot → fail-closed) |
D08 |
logical_request_key |
proposed | stable per intended registration effect (RS4A-07 C1) | MISSING_LOGICAL_KEY |
D11/D12 |
authorization_nonce |
proposed | single-use authority credential, bound to envelope+window | MISSING_NONCE / NONCE_UNBOUND |
D08 |
attempt_id |
proposed | execution/retry identity; never part of the single-use key | MISSING_ATTEMPT_ID |
— |
run_id |
proposed | validated registration run id | BAD_RUN_ID |
— |
closed_config_assertion |
proposed | asserts registration opens no gate and sets no active status | WOULD_OPEN_GATE |
D05/D19 |
pair_cardinality_claim |
proposed | content-derived pair shape (one primary row), not "5", not a copied field | PAIR_GUARD_MISMATCH |
D24 |
owner_real_run_gate_open |
separate authority arg (not in dict) | boolean; registration MUST run with this closed | ACTIVATION_AT_REGISTRATION if used to activate |
D05/D19 |
Hard broad-scan prohibition: the contract accepts a scalar dot_code + artifact_path. Any list / glob / "all untracked" / directory input is a categorical reject MASS_REGISTRATION_ATTEMPTED (closes D01/D02). There is no scan mode in the governed registrar.
3. Output schema registrar_result v0.2
{
decision: "REGISTER_CANDIDATE" | "REJECT" | "HOLD",
dot_code, logical_request_key, attempt_id, run_id,
reject_codes: [ ... ], # non-empty iff decision == REJECT
registered_row_intent: { # write-INTENT data only; no DB call by this design
table: "dot_tools",
columns: { code, name, file_path, tier, domain, artifact_type, paired_dot?,
deployed_artifact_hash, owner_envelope_ref, approval_envelope_ref,
status: "<inert/non-active>" } } | null,
postcondition_verifier_ref, # paired verifier (DOT-HEALTH-DOT family), RS4A-04 Phase 4
audit_envelope: { sink, payload_classification, written: bool }, # RS4A-08
activation: "NOT_PERFORMED" # ALWAYS; activation is separate + Owner-gated
}
status in registered_row_intent is an inert/non-active value (closes D05); the row, once written by a future implementation, must NOT satisfy status='active', so trg_context_pack_dot_register does not emit a notify (closes D19). The success signal is HTTP-2xx + readback (closes D10), never a process-exit check.
4. Reject-code table v0.2 (complete)
| Code | Trigger | Enforcement layer | Closes defect |
|---|---|---|---|
MASS_REGISTRATION_ATTEMPTED |
input is a set / glob / all-untracked / directory | V (validator) | D01/D02 |
NO_SCALAR_TARGET |
no scalar dot_code+artifact_path resolvable |
V | D03 |
ARTIFACT_NOT_ADMITTED |
admission_ref missing/invalid or not candidate-born/engineering-admitted |
V + R | D08 |
SOURCE_NOT_DEPLOYED |
artifact path not proven deployed (Interface F) | F | D09 |
HASH_MISMATCH |
reread trusted_attested.artifact_hash ≠ request_proposed.artifact_hash |
F | D09 |
ARTIFACT_TYPE_MISMATCH |
declared type ≠ admitted artifact type (e.g. .ts vs bash) |
V/F | D21 |
OWNER_ABSENT |
no governance_object_ownership head row (live: 0 rows) |
R/F | D08 |
APR_NOT_BOUND_TO_ARTIFACT |
approval not bound to this artifact_hash (live: no register_dot action) |
R/F | D08 |
REPLAY_DUPLICATE |
logical_request_key already consumed (RS4A-07) |
R | D11/D12 |
ATTEMPT_COLLISION |
concurrent attempt_id on same logical key |
R | — |
REPLAY_ATTEMPT_NO_BYPASS |
attempt identity used to re-admit same logical effect | R | D11 |
DEDUP_NON_CANONICAL |
identity check relies on fragile substring/path compare | V/R | D11/D12 |
IDENTITY_UNIQUE_ABSENT |
no DB UNIQUE backstop on the identity axis | SCHEMA/R | D13 |
DOT_TOOLS_ROW_DRIFT |
existing dot_tools row diverges from admitted artifact |
R | D11 |
CATALOG_SYNC_CONFLICT |
a non-registrar writer raced the same code (future regression guard) |
R | D-boundary |
PAIR_GUARD_MISMATCH |
pair not content-derivable / guard not standalone (RS4A-09) | V/R | D24 |
WOULD_OPEN_GATE / ACTIVATION_AT_REGISTRATION |
registration would set status=active or flip a dot_config gate |
R | D05/D19 |
INSECURE_TRANSPORT |
write path skips TLS verify (-k) |
R | D15 |
PRIVILEGED_PATH_USED |
write/read path uses root SSH / raw psql bypass | R | D14/D16 |
AUDIT_SINK_UNAVAILABLE |
durable failure-audit sink not writable (RS4A-08) | R | D20 |
POST_COMMIT_VERIFY_FAIL |
committed row fails paired readback (RS4A-04 Phase 4) | R | D23 |
REQUEST_PROPOSED_AS_TRUSTED |
a proposed value used without a matching reread trusted row | V/F | all-proposed |
FALSE_SUCCESS_SIGNAL |
success asserted on process-exit, not HTTP-2xx + readback | R | D10 |
5. Invariants (must hold for any compliant registrar)
- No-mass-scan invariant — input is scalar; glob/list ⇒
MASS_REGISTRATION_ATTEMPTED. (D01/D02) - No-activation invariant — registration writes an inert/non-active row; never flips
dot_configgates (process_dot_runtime.real_run_enabled,iu_core.operator_runtime_enabledboth false live), never wiresdot_agent_api_contract, never setsstatus='active'for a watch-tier (so the live notify condition is not met). (D05/D19, RS4A-09) - Authority-before-write invariant — no Owner envelope (live
governance_object_ownership=0) or no APRregister_dotbinding (live absent) ⇒ no write; fail-closed. (D08, RS4A-05) - Trusted-attestation invariant —
request_proposed.artifact_hashis never honored directly; onlytrusted_attested.artifact_hashfrom Interface F (RS4A-06). Hash ≠ signature. (D09) - Single-effect invariant — one committed effect per
logical_request_key, with a DB UNIQUE backstop; exact retry returns the prior decision. (D11/D12/D13, RS4A-07) - Honest-success invariant — success = HTTP-2xx + post-commit readback by the paired verifier; never a curl exit code. (D10/D23)
- Durable-audit invariant — a failed/rolled-back registration writes a durable audit record outside the rolled-back transaction. (D20, RS4A-08)
- No-mega invariant — the registrar does not build, chain, or call any other governed pipeline; it registers one inert row and stops.
6. No-implementation status
This contract is specification only: schemas, reject codes, phase references, invariants. It defines what a governed registrar must satisfy, not how it is coded. No executable, no migration, no Directus mutation payload, no patch to dot-dot-register is produced or authorized here. The phase model and proof obligations are in RS4A-04; the replacement-vs-wrapper decision (the contract cannot be met by wrapping the current real-run path) is in RS4A-10.