RS4A-06 — Interface F Deployed-Artifact Resolver v0.2 — 2026-06-21
RS4A-06 — Interface F Deployed-Artifact Resolver v0.2 — 2026-06-21
Macro: RS4A · Mục tiêu F
Deliverable: 06 of 14 · design-only (does NOT create any carrier/table/column)
Builds on: RS3B-04 Interface F v0.1 (CARRIER_SOURCE_UNPROVEN_FAIL_CLOSED); promoted to v0.2 with live carrier reads (this macro) and a sharpened hash taxonomy.
Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO
Status: INTERFACE_F_FAIL_CLOSED — no live carrier proves a per-artifact, immutable, owner-bound deployed-artifact-hash binding. The resolver is specified; it emits nothing trusted today.
1. Five distinct hashes (the taxonomy that must never collapse)
The defect across prior cycles was treating different hashes as interchangeable. v0.2 pins five:
| Hash | What it is | Trust value | Source |
|---|---|---|---|
| request_proposed.artifact_hash | the caller's claimed hash | none — caller input, never authority | RS4A-02 input |
| source mirror hash | sha256 of the KB source mirror (registrar 31d5cf15…, catalog-sync 7dd84cda…) |
proves the mirror matches a recorded value; fidelity-of-record only (P1) | RS3C-02 |
| snapshot recorded hash | wf_fs_dot_bin_snapshot.hash recorded same-day on the VPS (id 6022/5963) |
integrity record, not a signature, not a Codex-live attestation; mutable, no observer credential | LIVE (this macro) |
| trusted deployed-artifact hash | a hash a PROVEN carrier binds to (canonical_path, origin) under immutability + restricted writer + observer independence |
the only hash that may authorize a registration row | does not exist today |
| trusted_attested.artifact_hash | the resolver's output, emitted only if all R-criteria pass | consumable by registrar/replay | emitted by Interface F (none today) |
Hard rule: hash ≠ signature. A matching hash proves content equality to a recorded value, not authenticity, authority, or freshness. The source mirror hash equalling the snapshot hash (P1) establishes the mirror is faithful to a same-day record — it does not establish a trusted deployed-artifact attestation.
2. Live carrier evidence (my own read-only reads, 2026-06-21)
| Candidate carrier | Live fact | Verdict |
|---|---|---|
dot_tools |
309 rows, 28 cols, no hash/checksum/artifact_hash column (cols verified live) | NOT_FIT (no carrier) |
wf_fs_dot_bin_snapshot |
constraints = PK(id) + UNIQUE(source_key, object_key); no triggers; hash is a plain column (integrity record, mutable, no observer credential) |
SOURCE_UNPROVEN_FAIL_CLOSED — binds identity (source_key,object_key), not hash; no immutability; not a signature |
context_pack_manifest |
131 rows; columns include logical_checksum_sha256, file_checksum_sha256, git_commit, plus per-pack aggregate counts law_count, dot_count, entity_count, species_count, db_count, total_size_bytes, section_count; constraints = PK(id) + CHECKs (publish_status/kb_mirror_status/health_status/section_count>0) + FK trigger_source; no UNIQUE on either checksum; no immutability trigger |
STRONGEST_CANDIDATE_BUT_UNPROVEN_AND_NOT_PER_ARTIFACT — the checksums describe the whole context pack (aggregate), not one deployed DOT artifact; cannot bind one artifact's hash |
dot_tools.extra_metadata (jsonb) |
caller-writable free-text | NOT_FIT_AS_AUTHORITY (proposed tier only) |
v0.2 sharpening vs v0.1: v0.1 named context_pack_manifest the "strongest candidate / lead". Live column inspection now shows its sha256 columns are per-pack aggregates (law_count/dot_count/...), not per-artifact — so even as the lead, it cannot carry a single DOT artifact's deployed hash. This is a stronger fail-closed than v0.1: there is no per-artifact hash carrier at all in live runtime (G4 confirmed live).
3. Deployed Artifact Resolver Contract v0.2 (criteria only)
resolve_deployed_artifact(request_proposed) -> trusted_attested.artifact_hash | FAIL_CLOSED
Inputs (request_proposed, untrusted):
artifact_path, artifact_hash, hash_algorithm, canonicalization_version, artifact_type, origin, admission_ref
Required to emit trusted_attested.artifact_hash (ALL must pass):
R1 canonical_path : artifact_path normalized to one canonical deployed path (no symlink/alias/.. traversal)
R2 hash_algorithm : on a governed allowlist (e.g. sha256); UNKNOWN -> reject
R3 canonicalization_version: declared + supported; mismatch -> reject
R4 carrier_readback : a PROVEN carrier row (NOT a caller copy) yields the hash for canonical_path@origin
R5 origin_proof : origin (path root / git_commit) matches the carrier row's origin
R6 per_artifact_binding : carrier row binds exactly ONE deployed artifact (not an aggregate manifest)
R7 artifact_type_match : declared artifact_type == admitted artifact type (closes D21 .ts-vs-bash)
R8 admission_binding : admission_ref proves this artifact is admitted (RS4A-02)
R9 immutable_admission : admission + carrier rows immutable/append-only for the replay horizon
R10 drift_state : carrier hash vs request_proposed.artifact_hash; == -> NONE; != -> HASH_MISMATCH (reject)
Output (only if R1..R10 pass): trusted_attested.artifact_hash, canonical_path, origin, drift_state=NONE,
source_carrier_ref, hash_algorithm, canonicalization_version, artifact_type
Consumer readback rule: registrar (RS4A-02) and replay (RS4A-07) MUST reread trusted_attested.artifact_hash;
NEVER accept request_proposed.artifact_hash directly.
Fail-closed: if any carrier/writer/readback/immutability is unproven, emit NOTHING in trusted_attested.* .
R6 is the v0.2 addition that closes the context_pack_manifest aggregate gap.
4. Negative cases
| Case | Input/state | Expected | Layer |
|---|---|---|---|
| F-N01 | only request_proposed.artifact_hash, no proven carrier |
SOURCE_UNPROVEN_FAIL_CLOSED (no trusted output) |
F |
| F-N02 | carrier hash ≠ proposed hash | HASH_MISMATCH |
F |
| F-N03 | snapshot hash used as authority |
CARRIER_NOT_SIGNATURE (integrity record ≠ attestation) |
F |
| F-N04 | path is symlink / alias / .. traversal |
NON_CANONICAL_PATH (R1) |
V/F |
| F-N05 | hash_algorithm not on allowlist |
UNKNOWN_HASH_ALGO (R2) |
V/F |
| F-N06 | extra_metadata jsonb carries a hash |
treated as request_proposed, not attestation |
V/F |
| F-N07 | context_pack_manifest checksum offered as the artifact hash |
CARRIER_NOT_PER_ARTIFACT (R6 — aggregate manifest) |
F |
| F-N08 | .ts declared vs bash artifact |
ARTIFACT_TYPE_MISMATCH (R7) |
V/F |
| F-N09 | carrier exists & parses, but no immutability / writer not enumerable | trust NOT inferred from existence/parse → fail-closed (R9) | F |
5. Required future surface (to lift fail-closed)
A selected carrier must prove ALL: (1) governed restricted writer with enumerable grants; (2) immutability (UPDATE/DELETE-blocking trigger/constraint — none today on any candidate); (3) UNIQUE binding of (canonical_path, origin) → hash; (4) per-DOT-artifact linkage (not an aggregate manifest); (5) observer independence (producer ≠ caller; credential evidence, not a string label); (6) retention across rollback/retry. Reuse-first: harden an existing surface before any new ledger — no new table authorized.
6. Status
- Interface F v0.2:
INTERFACE_F_FAIL_CLOSED— sharper than v0.1: no per-artifact hash carrier exists (G4 live-confirmed). - Lead future candidate remains a
context_pack_manifest-style row only if extended to per-artifact + UNIQUE + immutability + observer independence — UNPROVEN today. - Hash ≠ signature; caller path/hash ≠ authority; existence/parse ≠ trust. Gate
REGISTRATION_HOLD·CAN_PROCEED = NO.