Remove general-purpose content hashing #66
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
The content hash (
def_hash/module_hash/type_hash, BLAKE3 overthe canonical JSON-AST) was introduced on the thesis that an LLM author
references symbols by hash to verify identity "without spending context
window" (
CLAUDE.md, the AILang-identity section;crates/ailang-core/src/lib.rs:11).That thesis is not borne out. No LLM author references a symbol by hash:
the Form-A grammar has no syntax for a hash reference, the AST has no
hash-reference field, and the workspace loader resolves imports by name
only. The hash flows out of the toolchain (manifest display, diff,
registry keys) but never back in as anything an author writes. The
content-addressing surface is structurally absent, not merely unused.
A content hash has exactly one real use: fast equality comparison. Where
that is needed, a specialised local key is the better tool — it is
collision-safer by construction (a small, bounded value-base rather than
the global space of all defs) and clearer at the comparison site. A
single global hash buys cross-codebase uniformity, which is worth less
than collision-safety and locality.
Separately, the persistent hash-pin test values
(
crates/ailang-core/tests/hash_pin.rs,crates/ailang-surface/tests/prelude_module_hash_pin.rs,crates/ail/tests/mono_hash_stability.rs,crates/ailang-core/tests/embed_export_hash_stable.rs) carry recurringregeneration cost. The prelude pin alone records six intentional re-pins
and zero documented accidental catches
(
prelude_module_hash_pin.rs:13-48); five separate value-pins assert theidentical
sum/IntListhashes (hash_pin.rs:79,101,155,170,279).In scope — removed
def_hash—crates/ailang-core/src/hash.rs:43; re-export atlib.rs:78.module_hash—crates/ailang-core/src/workspace.rs:409; re-export atlib.rs:79.type_hash—crates/ailang-core/src/canonical.rs:65.blake3::hashcall sites:canonical.rs:67,hash.rs:45,workspace.rs:411.CLAUDE.md,lib.rs:11,design/glossary.md(thecontent-addressedandJSON-AST … hashableentries), and the hash mention in
design/contracts/0009-roundtrip-invariant.md.Explicitly NOT in scope — retained
canonical::to_bytesand the entire canonicalisation machine(
crates/ailang-core/src/canonical.rs:47and below: sorted keys, nowhitespace, IEEE-754 float-bit encoding). This is the substrate,
not the hash. It carries the round-trip invariant
(
design/contracts/0009-roundtrip-invariant.md) independently of anyhash, and BLAKE3 merely ran on top of it.
#[serde(skip_serializing_if = …)]on AST fields. Still needed forround-trip idempotency and compact canonical form; its rationale
shifts from "hash-stable" to "round-trip-stable", so
design/contracts/0002-data-model.mdwording is amended, not theattribute removed.
Replacement per consumer (proposals — not yet designed in detail)
type_hash, the largest leg): the registryand instance lookup key
(class, type_hash(t))is used acrossailang-check—mono.rs:139,605,673,678,903,1722,1982,lib.rs:2627,2778,2887,…, andworkspace.rs:653,660,731,747. Proposal:key on the canonical type representation directly (the normalised
type's canonical bytes/string), collision-free by construction, no hash.
This is the highest-risk leg — it touches the hot path of instance
resolution.
type_hashatcrates/ailang-codegen/src/dropmono.rs:68): needs a fixed-length,LLVM-symbol-safe token. Proposal: a local mangling hash specialised to
the type-argument domain — this is the one site where a hash earns its
place, and a bounded local hash is collision-safer than the global one.
module_hashatworkspace.rs:1564): proposal —direct canonical-bytes comparison, no hash.
ail diff(def_hash/module_hashatmain.rs:1626-1660,2025-2058;ailang-check/src/lib.rs:1491): proposal — structural /canonical-byte comparison instead of hash comparison.
ail manifest(def_hashatpretty.rs:34,main.rs:396,521-546,737): proposal — drop the hash column, show signatures only.mono_hash_stabilitypin: replace the body-hash assertion with agolden pretty-printed term, which is a diagnosable, human-readable
"hash" — a drift shows what changed, not just
a → b.hash_pin.rsvalue-pins,embed_export_hash_stable.rs):delete or rewrite as the value-free two-path property tests already
present (
hash_pin.rs::iter19b_empty_suppress_preserves,iter22b1_classdef_empty_optionals_hash_stable,forall_without_constraints_hashes_bit_identical). These cover theskip_serializing_ifinvariant structurally, without any frozen value.Acceptance
blake3dependency or call remains in the production crates.design/contracts/0009) stay green.CLAUDE.md,lib.rs,design/glossary.md,design/contracts/0009.Shape
A non-breaking removal: no language semantics, on-disk format, or ABI
changes. The only observable change is cosmetic —
ail manifestandail diffstop printing hash columns. Internally the instance-resolutionre-key (the
type_hashleg) is the delicate part and the natural firsttask to land and verify in isolation; the rest (double-load guard, CLI,
test-pin removal, doc cleanup) is mechanical. This is the tracking item,
not the design.