Files
alkblobs/tasks/c1-git-object-family-impl.md
T
glm-5.3-flash 9134d4444d feat(hashing): the git-object derivation family lands — review-002 C-1's implementation half (wave 13)
The hash registry extends per ADR-018: bytes 0x03/0x04 (git-object
sha-1/sha-256), preimage-identity hashing over git's loose-object form
as the stored preimage — the digest byte-identical to git's oid, every
kind included. Re-derived from poc-o-git-objects, ADR-stamped, not
merged.

- Registry + Algorithm members after the blob members (total order
  rides the registry bytes, 0x02 < 0x03 < 0x04); the derivation arms
  (derive's len parameter inert for the family — documented,
  test-pinned); the BlobHasher no-preamble arms (finish pinned equal
  to derive); from_git_oid_hex's contract pinned blob-family-only.
- keys.rs: the extended physical layout round-trips in total order;
  rejects-never-guesses unchanged (0x05 is the unknown-tag example).
- put path: put_git_object(algorithm, len, stream) public — family
  members only (KeyInvalid otherwise), known-length only, the
  inherited Verification/Io mappings — via put_known_as; the
  unknown-length drivers take their derivation from callers.
- fleet threading (ADR-018 §7): every hasher site
  derivation-parameterized (put_known_as; fleet_put_pglo_known/
  _unknown); put_git_object under a fleet declaration lands through
  the joint entry+pin tx / pg-lo consolidation / pin-first staged
  forms — pinned by two env-driven tests with exact-count sweep
  outcomes (kv joint form byte-exact + dedup row-alone; consolidation
  form with LO pages landing and dying exactly).
- git_interop: the family tests green against the real git CLI
  (tree/commit/tag byte-exact, dedup, the blob-tag negative, the
  sha-256 sibling), the seam guard (blob algorithms reject), the
  preimage-length stat assertion; in-module empty-tree known-answer
  vectors.
- Conformance: the INV-1/2/6 reference rows gain family legs
  (round-trip incl. the staged form, dedup-by-oid, the stored-preimage
  stat semantic); backlog pins + README inventory updated.
- kind-decision delta (ADR-018 §2): behavior unchanged, texts honest —
  the ops module doc's digest-wire-form paragraph, digest_ingress's
  doc, the specs' headers.
- fuzz: the key_encoding generator + shared battery extended to the
  four-member registry (family keys, known-answer vectors, the len
  inertness pin, 0x05 as the invalid tag); committed corpus
  regenerated per policy (0x03 was an invalid-tag seed — 117 rewritten,
  67 added); idempotent after landing.

Verification: cargo test (default, 153+54+7+2), cargo test
--all-features server-less (skip-clean) and against the live pglo-poc
harness (336+125+7+3), cargo clippy --all-targets both feature
variants (-D warnings), cargo fmt --check, cargo doc --no-deps, Cargo
test --manifest-path fuzz/shared/Cargo.toml (the corpus-replay gate).
Task: tasks/c1-git-object-family-impl.md (status completed, notes +
summary recorded).
2026-10-18 00:00:46 +00:00

12 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
c1-git-object-family-impl C-1 (implementation half) — the git-object family lands: registry, derivation, put path, fleet threading, interop tests completed
alkcall-010-bump
c1-adr-git-object-family
broad medium project implementation
wave-13
review-002
hashing
store
fleet
one-way-door

Description

Review-002 C-1's implementation half, per ADR-018 (the prior task's record — read it first; where the prototype and the ADR disagree, the ADR wins). Re-implement from the prototype branch poc-o-git-objects (f0b045c) — re-derive, don't merge:

  • Registry + Algorithm (src/hashing.rs): bytes 0x03/0x04, the GitObjectSha1/GitObjectSha256 members, the preimage-identity derivation arms (derive's no-preamble arms — the len parameter is ignored for the family), the BlobHasher no-preamble arms (the known-length path's one-pass form feeds no preamble — the loose-object header is inside the stored preimage).
  • Key decode/order (src/keys.rs): the new tags decode round-trip; total order follows the registry bytes (0x02 < 0x03 < 0x04); rejects-never-guesses unchanged (unknown/truncated are KeyInvalid).
  • The put path (src/store/put.rs): put_git_object(algorithm, len, stream) public per ADR-018's pinned shape, via the derivation-parameterized internal put_known_as (the canonical blob put routes the preamble hasher; the family put routes the plain hasher; everything after hasher construction is pin-before-publish identical). Known-length only; the family members only (KeyInvalid otherwise); kv-only over-threshold rejection inherited.
  • Interop tests (tests/git_interop.rs): the branch's family tests — byte-exact against real git hash-object -t (tree/commit/tag round-trips), dedup, the negative (the same oid unreachable through the blob tags — no cross-family collision), the empty-tree known-answer vectors (sha1 4b825dc6…, the sha-256 sibling), the sha-256 sibling CLI-validated.

Plus what the branch deliberately skipped (review-002's not-carried list — the merge-time work):

  1. Fleet threading. The fleet/non-fleet hasher sites still hardcode the canonical blob derivation (representative anchor: src/store/fleet.rs:786 — Key::derive(content, …) in the fleet put path; src/local.rs:899 is the non-fleet large-tier site). The derivation must thread through the fleet put path uniformly: a fleet-declared store's put_git_object lands through the joint entry+pin tx with pin-before-publish ordering intact, and the fleet hasher sites are derivation-parameterized, not family-branching copies. Mechanical per the POC, but it is the merge-time work.
  2. The ops-surface delta per ADR-018's kind decision (likely docs-only — the digest ingress staying blob-family — but whatever the ADR decided lands here: the ingress, the section doc, the specs' wire-form text).
  3. The stat semantic per the ADR: the stored value is the loose form, so stat's code may need no change — but the docs and the conformance rows must state the preimage-length semantic explicitly (a deliberate difference from the blob family, not an accident).

Fuzz consistency: the key_encoding target's surface (Key::from_bytes / Digest::from_git_oid_hex / the registry / derive) gains the new tags — the committed seeds regenerate per the corpus policy if the target's input shape changes (python3 fuzz/gen_fuzz_seeds.py; a no-op diff on the committed set is the expected outcome unless the seeds encode the registry constants — check, and record either way).

Acceptance Criteria

  • The family lands per ADR-018: registry bytes, Algorithm members, derivation + hasher arms, key decode/order, put_git_object public with the ADR's pinned shape
  • Fleet threading: the fleet hasher sites derivation-parameterized; put_git_object under a fleet declaration lands through the joint entry+pin tx (exact-count fleet sweep outcome test)
  • tests/git_interop.rs family tests green against the git CLI (tree/commit/tag, dedup, the blob-tag negative, empty-tree vectors, the sha-256 sibling)
  • The stat semantic documented per the ADR; conformance rows extended (the family's round-trip/dedup/verification rows)
  • The ops surface matches ADR-018's kind decision (code or docs, as decided)
  • The fuzz key_encoding target/seeds consistent with the extended registry (disposition recorded)
  • Gates green: the full AGENTS block — cargo test (default), cargo test --all-features server-less and against the live pg harness (ALKBLOBS_PG_HOST=localhost, ALKBLOBS_PG_PORT=15432, ALKBLOBS_PG_USER=postgres, ALKBLOBS_PG_PASSWORD=poc, ALKBLOBS_PG_DB=blobs — the pglo-poc container; server-less runs skip cleanly), both clippy variants, cargo fmt --check, cargo doc --no-deps, the fuzz corpus-replay gate (cargo test --manifest-path fuzz/shared/Cargo.toml)

References

  • tasks/c1-adr-git-object-family.md (the ADR — this task's contract)
  • docs/reviews/002-first-consumer-review.md (C-1)
  • branch poc-o-git-objects (f0b045c) — the working reference
  • docs/architecture/decisions/002-canonical-hash-and-key-encoding.md; hashing-and-keys.md; store-api.md; ops-surface.md (as amended)
  • src/hashing.rs; src/keys.rs; src/store/put.rs; src/store/fleet.rs:786; src/local.rs:899; tests/git_interop.rs
  • fuzz/README.md (the corpus policy); fuzz/gen_fuzz_seeds.py

Notes

  • Re-derive landed per ADR-018 (no merge of poc-o-git-objects): the registry/derivation shape tracks the prototype byte-for-byte, the docs are ADR-018-stamped (the prototype's "POC-O prototype, not an ADR" markers replaced), and the five prototype-uncarried decisions landed per the ADR's §Deviations.
  • Fleet threading (deviation 1): every hasher site is derivation-parameterized, not family-branching — put_known → put_known_as(algorithm, …) (src/store/put.rs); fleet_put_pglo_known(algorithm, …) (the pg-lo consolidation tx's hasher); the unknown-length drivers (put_unknown, fleet_put_pglo_unknown) take the derivation from their callers, whose single caller passes the canonical blob derivation (blob-family by construction — ADR-018 §Decision 6 rejected the family's unknown-length arm). put_git_object under a fleet declaration routes: kv tier → the joint entry+pin tx (fleet_put_kv), pg-lo → the one-tx consolidation form, local shared-media → pin-first/publish-second. Two new env-driven tests in src/store/fleet.rs pin the family forms end to end: fleet_kv_put_git_object_lands_through_the_joint_tx (byte-exact joint landing, the empty-tree oid under tag 0x03, the dedup re-put's row-alone form, and the exact-count sweep outcome — held pins protect (0/0/0), the expired shape stages (1/0/0) then deletes exactly once (1/0) across the executor sweep) and fleet_pglo_put_git_object_lands_through_the_consolidation_tx (over-threshold loose form through the one-tx consolidation, LO pages land and die exactly, the stat semantic on the LO medium, the same exact-count sweep outcome).
  • The kind-decision delta (deviation 2): behavior unchanged, texts honest — Digest::from_git_oid_hex's contract doc pins the blob family (the physical-encoding path for family-explicit construction named), the ops module doc's digest-wire-form paragraph states the blob-family scoping (S-5: schema gate and ingress agree by construction), digest_ingress's doc carries the posture; ops-surface.md's header noted. The wire schema, ingress, and put cross-check are byte-for-byte unchanged.
  • The stat-semantic record (deviation 3): no code change (the stored value is uniformly the returned length) — store-api.md's per-family semantic stands; the conformance rows pin it (see below), and the put_git_object doc states it.
  • Fuzz-seed disposition (deviation 4): the committed seeds did encode the registry constant (0x03 in the invalid-tag battery of both fuzz/gen_fuzz_seeds.py and the shared replay) — regeneration was expected and done. The generator now derives valid 0x03/0x04 family keys (loose-form oids), loops all four algorithms for truncation/over-long forms, battery-tests tag/digest-width mismatches per family member, and retires 0x03-as-invalid in favor of 0x05; 117 committed seeds rewritten, 67 added. The shared replay battery gains the family keys, the family known-answer vectors (the empty-tree oids), the derive-len inertness boundary pin, and the registry sweep's width-mapping-by-family fix. Regeneration is idempotent after landing (a replay-only diff).
  • The derive-len quirk (deviation 5): documented in Algorithm::derive's contract and pinned by git_object_derive_len_parameter_is_inert (src/hashing.rs — every len incl. u64::MAX equals the plain hash).
  • Conformance rows extended in place (the INV-1/2/6 reference rows gained family legs rather than new rows — the columns inherit via the shared row bodies, INV-7's uniformity mechanism): INV-1 round-trips both family members (sub-threshold and, against the dual-tier columns, staged forms alike), INV-2 pins the family re-put's CAS dedup through sweep outcomes, INV-6 pins the stored-preimage stat semantic as a deliberate per-family property. Backlog pins and the README inventory updated. The fleet-tier family coverage is the two env-driven store-core tests above (the conformance columns run non-fleet factories by design).
  • Interop tests: the prototype's two family tests landed (CLI-validated tree/commit/tag byte-exactness incl. the sha-256 sibling; the facade round-trip with the blob-tag negative), plus a new seam-guard test (put_git_object_rejects_blob_algorithms — the ADR's pinned Error::KeyInvalid mapping) and the stat-semantic assertion folded into the round-trip test.

Summary

The git-object derivation family landed per ADR-018 — review-002 C-1 complete. src/hashing.rs: registry bytes 0x03/0x04 (GIT_OBJECT_SHA1/GIT_OBJECT_SHA256), the Algorithm family members after the blob members (total order rides the registry bytes), the preimage-identity derivation arms (derive ignores len for the family — documented and test-pinned), the BlobHasher no-preamble arms (finish pinned equal to derive), from_git_oid_hex's contract pinned blob-family-only. src/keys.rs: the extended physical layout, family keys round-trip in total order, rejects-never-guesses unchanged (0x05 is the unknown-tag example now). src/store/put.rs: put_git_object(algorithm, len, stream) public per the ADR's pinned shape (family members only, key-invalid otherwise; known-length only; the inherited Verification/Io error mapping), via the derivation-parameterized put_known_as; the unknown-length drivers take their derivation from callers. src/store/fleet.rs: the pg-lo known/unknown drivers derivation-parameterized; put_git_object under a fleet declaration lands through the kv joint entry+pin tx / pg-lo one-tx consolidation / local pin-first-publish-second forms, pinned by two env-driven tests with exact-count sweep outcomes. tests/git_interop.rs: the family tests green against the real git CLI (tree/commit/tag byte-exact, dedup, the blob-tag negative, the empty-tree vectors, the sha-256 sibling CLI-validated). Conformance: INV-1/2/6 rows extended with family legs (round-trip incl. the staged form, dedup-by-oid, the stored-preimage stat semantic), backlog/README updated. Ops-surface texts honest (behavior unchanged). Fuzz: the key_encoding generator and shared battery extended to the four-member registry; the committed corpus regenerated per policy (0x03 was an invalid-tag seed — a no-op was not the expected outcome). Gates green: default cargo test (153+54+7+2), cargo test --all-features server-less and against the live pglo-poc harness (336+125+7+3), both clippy variants, cargo fmt --check, cargo doc --no-deps, and the fuzz corpus-replay gate.