attest: drop v2 schema bump — no v1 records exist, cites is just a v1 field
The v1→v2 bump in 30aba0e was ceremony with no historical witnesses.
A sweep of every local SQLite (~/.arborist/shards/*.db,
~/.arborist/*.db) found zero ``attest_fingerprint`` audit rows; the
module was introduced on this branch with no commits outside test
fixtures. With no v1 bodies in the wild there is no canonical-bytes
divergence to mark — v2 is just better v1.
- ``SCHEMA_VERSION`` returns to ``fingerprint-v1``.
- ``cites: tuple[str, ...] = ()`` stays on the dataclass; it was the
actual feature, not the version bump.
- ``entity_chain_iter`` reads ``body["cites"]`` directly — no
``.get(..., ())`` defensive fallback for a missing-field case that
cannot arise.
- ``test_legacy_v1_body_without_cites_reconstructs_with_empty_tuple``
removed — it tested a backwards-compat path with no caller.
- ``blast_radius`` unchanged.
Net: -31 lines of compat scaffolding for a population of zero
records. Per CLAUDE.md "don't add backwards-compatibility shims when
you can just change the code" and the five-step algorithm step 2
("delete the part"). 66 attest tests pass.
This commit is contained in:
parent
ab7ae4c0fb
commit
0c588e4abd
3 changed files with 10 additions and 41 deletions
|
|
@ -154,7 +154,7 @@ def entity_chain_iter(
|
|||
skew_q10000=int(body["skew_q10000"]),
|
||||
error_taxonomy={k: int(v) for k, v in body.get("error_taxonomy", {}).items()},
|
||||
stress_params={k: int(v) for k, v in body.get("stress_params", {}).items()},
|
||||
cites=tuple(body.get("cites", ())),
|
||||
cites=tuple(body["cites"]),
|
||||
schema_version=body["schema_version"],
|
||||
)
|
||||
yield n, event_hash, fp
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Fingerprint schema + canonical encoder + Merkle leaf hash.
|
||||
|
||||
Schema version: ``fingerprint-v2``.
|
||||
Schema version: ``fingerprint-v1``.
|
||||
|
||||
All numeric fields are integers. Latency lives in microseconds.
|
||||
Skew is quantized to a 4-decimal-place integer (``skew_q10000``).
|
||||
|
|
@ -14,15 +14,13 @@ by ±1 in the last digit of ``skew_q10000`` or one of the std/mean
|
|||
fields. Acceptable for v1; a future revision can compute moments in
|
||||
integer arithmetic if required.
|
||||
|
||||
**v2 delta: optional ``cites`` field.** A fingerprint may declare a
|
||||
``cites`` tuple of other entities' chain hashes that it vouches for
|
||||
or depends on. The citation is a *claim of dependency*, not a
|
||||
verification — at commit time arborist does not re-verify the cited
|
||||
chain. The point is that if a cited chain hash is later falsified
|
||||
(KS / Mahalanobis drift, manual quarantine, etc.), the audit graph
|
||||
yields a deterministic blast radius via ``chain.blast_radius()``.
|
||||
Default empty tuple → equivalent to v1 semantics. Legacy v1 bodies
|
||||
in storage (no ``cites`` key) are reconstructed with ``cites=()``.
|
||||
**``cites`` field.** A fingerprint may declare a ``cites`` tuple of
|
||||
other entities' chain hashes that it vouches for or depends on. The
|
||||
citation is a *claim of dependency*, not a verification — at commit
|
||||
time arborist does not re-verify the cited chain. The point is that
|
||||
if a cited chain hash is later falsified (KS / Mahalanobis drift,
|
||||
manual quarantine, etc.), the audit graph yields a deterministic
|
||||
blast radius via ``chain.blast_radius()``. Default empty tuple.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
|
@ -35,7 +33,7 @@ from typing import Mapping, Sequence
|
|||
|
||||
from arborist.merkle import hash_leaf
|
||||
|
||||
SCHEMA_VERSION = "fingerprint-v2"
|
||||
SCHEMA_VERSION = "fingerprint-v1"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
|||
|
|
@ -240,32 +240,3 @@ def test_blast_radius_misses_unrelated_chain_hash(tmp_path):
|
|||
)
|
||||
assert blast_radius(conn, "f" * 64) == []
|
||||
|
||||
|
||||
def test_legacy_v1_body_without_cites_reconstructs_with_empty_tuple(tmp_path):
|
||||
"""v1 events in storage (no `cites` key) must round-trip through entity_chain_iter."""
|
||||
from arborist.store import append_audit
|
||||
|
||||
conn = connect(tmp_path / "t.db")
|
||||
legacy_body = {
|
||||
"entity_id": "alice",
|
||||
"session_id": "s-legacy",
|
||||
"timestamp_utc": "2026-06-05T15:30:00Z",
|
||||
"domain": "python-debug",
|
||||
"host_hash": "0" * 64,
|
||||
"count": 3,
|
||||
"mean_us": 1000,
|
||||
"std_us": 100,
|
||||
"p50_us": 1000,
|
||||
"p90_us": 1100,
|
||||
"p99_us": 1200,
|
||||
"skew_q10000": 0,
|
||||
"error_taxonomy": {},
|
||||
"stress_params": {},
|
||||
"schema_version": "fingerprint-v1",
|
||||
}
|
||||
append_audit(conn, event_type=EVENT_TYPE, body=legacy_body, subject_root="alice")
|
||||
seen = list(entity_chain_iter(conn, "alice"))
|
||||
assert len(seen) == 1
|
||||
fp = seen[0][2]
|
||||
assert fp.cites == ()
|
||||
assert fp.schema_version == "fingerprint-v1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue