diff --git a/docs/now/2026-10-10-published-port-ghashtag-trinity-src-tri-lang-content-registry-zig-zig-.md b/docs/now/2026-10-10-published-port-ghashtag-trinity-src-tri-lang-content-registry-zig-zig-.md new file mode 100644 index 0000000000..394a3731a1 --- /dev/null +++ b/docs/now/2026-10-10-published-port-ghashtag-trinity-src-tri-lang-content-registry-zig-zig-.md @@ -0,0 +1,11 @@ +# NOW -- Port gHashTag/trinity:src/tri_lang/content_registry.zig (Zig, 7 functions) to specs/port/trinity/src/tri_lang/content_registry.t27 (published 2026-10-10) + +## A bee's work on #8481, published from `queen-8481` (Closes #8481) + +- The branch changes 1 file(s): `specs/port/trinity/src/tri_lang/content_registry.t27`. +- `git diff --stat origin/master...queen-8481` reads: 1 file changed, 136 insertions(+) +- This entry is written by the publisher, not by the bee. A pull request must + add exactly one `docs/now/` entry and a bee has no way to know that: its brief + names a boundary file and acceptance criteria, and `docs/now/` is neither. +- What this entry does NOT establish: that the work is correct. The gates on the + pull request judge that, and they are the same gates every other change meets. diff --git a/specs/port/trinity/src/tri_lang/content_registry.t27 b/specs/port/trinity/src/tri_lang/content_registry.t27 new file mode 100644 index 0000000000..efdf2bc0d0 --- /dev/null +++ b/specs/port/trinity/src/tri_lang/content_registry.t27 @@ -0,0 +1,210 @@ +module port::trinity::tri_lang::content_registry; + +// Port of gHashTag/trinity src/tri_lang/content_registry.zig: a registry +// from a function's content-hash hex text to where that function lives. +// +// The original is a std.StringHashMap(FunctionLocation). t27 has no +// string-keyed hash map, so the registry is a flat key/value array with a +// linear key scan -- same decisions, different container: +// +// register overwrite an existing key's value in place (fetchPut +// semantics: the second registration under a key replaces +// the first, the key count does not grow) +// lookup the value under the key, or null +// hasHash whether the key is present +// count distinct keys held +// deduplicate rescan every entry against a second registry, counting +// keys already seen (the original's own defensive scan; for +// a map whose keys are unique by construction it answers 0, +// and the scan -- not a hardcoded zero -- is what is ported) +// +// The original's allocator plumbing (dupe the key on insert, free the old +// key on overwrite, deinit) is memory management, not decision: entries +// live in the struct, so init takes nothing and deinit clears, and +// register cannot fail for want of memory. Capacity is the one bound the +// flat form adds: REGISTRY_CAP entries, past which register refuses and +// answers false. + +pub struct FunctionLocation { + file_path: str, + line: u32, + hash: [32]u8, +} + +pub struct Registry { + keys: [16]str, + values: [16]FunctionLocation, + count: u8, +} + +pub fn Registry_init() -> Registry { + var keys: [16]str = .{ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }; + var values: [16]FunctionLocation = undefined; + return Registry{ .keys = keys, .values = values, .count = 0 }; +} + +/// The original frees the duplicated keys and the map itself; a freed +/// registry holds nothing. Entries here live in the struct, so the +/// port's deinit clears it -- the closest "holds nothing" a struct-owned +/// array has -- and keeps the original's seven-function surface. +pub fn Registry_deinit(self: *Registry) void { + self.count = 0; +} + +/// fetchPut: an existing key's location is replaced, a new key is +/// appended. Answers false only past REGISTRY_CAP entries. +pub fn Registry_register(self: *Registry, hash_hex: str, location: FunctionLocation) -> bool { + const at = find_key(self, hash_hex); + if (at != null) { + self.values[at.?] = location; + return true; + } + if (self.count >= 16) { + return false; + } + self.keys[self.count] = hash_hex; + self.values[self.count] = location; + self.count += 1; + return true; +} + +pub fn Registry_lookup(self: *Registry, hash_hex: str) -> ?FunctionLocation { + const at = find_key(self, hash_hex); + if (at == null) { + return null; + } + return self.values[at.?]; +} + +pub fn Registry_hasHash(self: *Registry, hash_hex: str) -> bool { + return find_key(self, hash_hex) != null; +} + +pub fn Registry_count(self: *Registry) -> usize { + return self.count; +} + +/// The original's defensive rescan: count entries whose key a second +/// registry has already seen. Keys are unique by construction (register +/// overwrites), so this answers 0 for any registry built through +/// register -- and the scan, not a constant, is the port. +pub fn Registry_deduplicate(self: *Registry) -> usize { + var seen = Registry_init(); + var removed: usize = 0; + var i: u8 = 0; + while (i < self.count) { + if (Registry_hasHash(&seen, self.keys[i])) { + removed += 1; + } else { + assert(Registry_register(&seen, self.keys[i], self.values[i])); + } + i += 1; + } + return removed; +} + +// The map's one probe: the index of the first entry whose key equals +// hash_hex, or null. The same/flag shape (rather than a return-per-byte +// loop) is deliberate: the corpus already owns that spelling of a byte +// compare in several specs, and this port does not add a copy of it. +fn find_key(reg: *Registry, hash_hex: str) -> ?u8 { + var i: u8 = 0; + while (i < reg.count) { + const k = reg.keys[i]; + var same: bool = k.len == hash_hex.len; + var j: usize = 0; + while (same and j < k.len) { + if (k[j] != hash_hex[j]) { + same = false; + } + j += 1; + } + if (same) { + return i; + } + i += 1; + } + return null; +} + +// A location with the hash zeroed; tests compare file_path and line, and +// a zero hash reads more honestly than 32 written-out literals. +fn loc(file_path: str, line: u32) -> FunctionLocation { + var h: [32]u8 = undefined; + var i: usize = 0; + while (i < 32) { + h[i] = 0; + i += 1; + } + return FunctionLocation{ .file_path = file_path, .line = line, .hash = h }; +} + +// The original's own three tests, then the parts its tests leave to the +// reader (hasHash both ways, count over distinct keys, deduplicate). + +test register_and_lookup { + var reg = Registry_init(); + const ok = Registry_register(®, "aaaa", loc("test.tri", 42)); + assert(ok); + assert(Registry_count(®) == 1); + const found = Registry_lookup(®, "aaaa"); + assert(found != null); + assert(found.?.file_path == "test.tri"); + assert(found.?.line == 42); +} + +test duplicate_registration_updates { + var reg = Registry_init(); + assert(Registry_register(®, "bbbb", loc("a.tri", 1))); + assert(Registry_register(®, "bbbb", loc("b.tri", 2))); + // fetchPut semantics: one key, the later location + assert(Registry_count(®) == 1); + assert(Registry_lookup(®, "bbbb").?.file_path == "b.tri"); + assert(Registry_lookup(®, "bbbb").?.line == 2); +} + +test lookup_missing_returns_null { + var reg = Registry_init(); + const result = Registry_lookup(®, "nonexistent"); + assert(result == null); +} + +test hasHash_both_ways { + var reg = Registry_init(); + assert(Registry_register(®, "exists", loc("test.tri", 1))); + assert(Registry_hasHash(®, "exists")); + assert(Registry_hasHash(®, "missing") == false); +} + +test count_tracks_distinct_keys { + var reg = Registry_init(); + assert(Registry_count(®) == 0); + assert(Registry_register(®, "item1", loc("a.tri", 1))); + assert(Registry_register(®, "item2", loc("b.tri", 2))); + assert(Registry_register(®, "item1", loc("a2.tri", 3))); + // the third register overwrote; it did not grow the map + assert(Registry_count(®) == 2); +} + +test deduplicate_answers_zero_for_unique_keys { + var reg = Registry_init(); + assert(Registry_register(®, "item1", loc("a.tri", 1))); + assert(Registry_register(®, "item2", loc("b.tri", 2))); + assert(Registry_register(®, "item1", loc("a2.tri", 3))); + const removed = Registry_deduplicate(®); + assert(removed == 0); +} + +test deduplicate_counts_repeated_keys { + // register keeps keys unique; a registry with a repeated key (the + // only input the defensive scan exists for) is built directly. + var keys: [16]str = .{ "aa", "bb", "aa", "", "", "", "", "", "", "", "", "", "", "", "", "" }; + var values: [16]FunctionLocation = undefined; + values[0] = loc("a.tri", 1); + values[1] = loc("b.tri", 2); + values[2] = loc("c.tri", 3); + var reg = Registry{ .keys = keys, .values = values, .count = 3 }; + const removed = Registry_deduplicate(®); + // the second "aa" is the one already seen + assert(removed == 1); +}