v0.3.162 - Honest Mint-Receipt Reconcile
v0.3.162 - Honest Mint-Receipt Reconcile
v0.3.162 adds archive remint-reconcile, an honest way to re-issue a mint
receipt's recorded sha256 values after a canonical zet drifts on disk — for
example a CRLF/BOM re-checkout under core.autocrlf, or a human content edit —
without ever masking corruption or waiving human review. It also lands additive
BOM/newline parse tolerance and a doctor/retire route to the new command.
Governing Doctrine (v0.3.162 decision log)
Reconcile NEVER masks corruption, and classification NEVER waives human review.
The draft snapshot only anchors the raw draft bytes (body + draft frontmatter),
while the client's real mutation (a title correction) lives in the
mint-transformed canonical frontmatter. A body-only comparison is therefore
blind to frontmatter edits, so:
- Every
--approveshows the current on-disk content and requires
--reviewed-by. No computed class unlocks a lower-friction, human-skipped
path. - Classification only DECORATES the human decision (it names which fields
changed). It never REPLACES it. - The default class is the stricter
content_change.format_driftis granted
ONLY on positive, byte-level, independently re-derivable proof of
content-identity. Any doubt falls tocontent_change. - Hard refusals run BEFORE classification. A state that cannot be honestly
reconciled is REFUSED; it is never "fixed."
What Changed
- New command
archive remint-reconcile <archive-root> (--zettel-id <id> | --path <rel>) [--dry-run | --approve] [--reviewed-by <actor>] [--content-changed-ack] [--format text|json].--dry-run(default)
classifies and previews with zero writes;--approvere-issues after review. format_driftis proven positively: the current canonical body must be
identical to a CLEAN draft snapshot (raw sha matches the recorded sha) AND the
FULL content frontmatter — every draft key re-derived from the snapshot, with
source_refstransformed exactly as mint does — must match the current
canonical field-by-field. Only the mint-injected keys (status,updated_at,
mint{},promotion{}) are excluded from the diff, andstatusis separately
required to equalcanonical. Because the comparison spans every content field
rather than a hand-picked subset, an edit to ANY field (title, id, kind,
visibility, facets, provenance, edges, created_at, …) is caught: a
canonical-only title edit leaves the body identical but the title differs, so it
is correctlycontent_change, and the same holds for every sibling field — no
content field is invisible to the classifier.- Snapshot drift is a first-class fail-safe: a missing, BOM'd, or
otherwise-mutated snapshot is never treated as a clean anchor and classification
falls back tocontent_change. - Approval writes BOTH: an in-place mint-receipt update (recomputed shas plus an
append-onlyreconcile.historyblock with anormalized_content_digest) AND a
separate immutable audit receipt underreceipts/mint/reconciles/. Repeats get
a monotonic suffix. Both writes are atomic (temp file + os.replace). archive doctorroutes canonical byte drift: a previously-reconciled receipt
that re-drifted by newline/BOM only emits the new
mint_receipt_target_byte_drift_suspected_formatERROR; an un-reconciled sha
mismatch keeps the plainmint_receipt_sha_mismatchERROR plus a suggested
remint-reconcile --dry-runcommand. Both stay non-clean (faildoctorand
--strict). The edge-receipt evolution path is unchanged. A UTF-8 BOM on a
canonical zet surfaces a newzettel_has_bomWARN advisory.archive retire-draftnow surfaces aremint-reconcile --dry-runnext-safe
action when — and only when — retirement is blocked by the mint-target
sha-mismatch blocker. No retire gate was relaxed.- Additive parse tolerance: frontmatter parsing and receipt/JSON reads tolerate
a single leading UTF-8 BOM (utf-8-sig/ one-BOM strip). sha256 hashing still
reads raw bytes, so BOM and newline drift stay visible as a sha mismatch. New
mints pin the canonical write to LF newlines to prevent immediate re-drift. - Schemas: added
wom-kit/schemas/mint-reconcile-receipt.schema.jsonand a
reconcileobject property onmint-receipt.schema.json(not required; legacy
receipts validate unchanged).
Safety Boundary
- No archive migration and no hash change: BOM/newline tolerance affects
parse/read helpers only, never the sha256 functions. - Reconcile never edits zet content.
--approverecords the sha of the bytes as
they are; it does not rewrite the canonical. - Hard refusals (missing/non-mint receipt, id mismatch, non-canonical or
unparseable target, target.path mismatch) block before any classification, so a
swap-corrupted or foreign receipt is never laundered into a fresh integrity
record.mintstill refuses to re-mint an already minted zet.
Still Future
- The
remint-reconcile-batchtier is deferred (its receipt directory name is
reserved). Per-id human judgment on eachcontent_changeis the point of the
doctrine, so a bulk content-change ack is intentionally not shipped yet.
Verification
cd wom-kit
python -m pytest tests/ -q
python tools/check_public_privacy.py
python tools/check_release_readiness.pyUpgrade Notes
No data migration is required. The new command, BOM/newline parse tolerance, and
the LF write pin are additive; existing receipts and canonical files are
unaffected until you choose to run remint-reconcile. See
UPGRADE.md.