fix: mint record ids across git refs and add a spec-id uniqueness lint#137
Open
REPPL wants to merge 3 commits into
Open
fix: mint record ids across git refs and add a spec-id uniqueness lint#137REPPL wants to merge 3 commits into
REPPL wants to merge 3 commits into
Conversation
Sequential record ids (iss-N, itd-N, spc-N) were minted from the local working tree only, so two branches cut from the same base silently minted the same next id (iss-115, iss-120): invisible on each branch, surfacing only at merge where it breaks the bidirectional intent-spec link. Consolidate the git-ref side of the maximum onto one canonical primitive, recordid.MaxAcrossRefs, and fold it into all three allocators (capture's reservePath, intent's nextIntentID, spec's NextID) so minting is max+1 over the union of the working tree and every local/remote-tracking branch tip. Once one branch commits an id, the other mints past it. A repository git cannot read degrades loudly to working-tree-only minting on stderr (never a silent fallback); a non-repository directory has no refs to collide with and mints quietly. The residual window (two branches minting before either commits) is accepted and caught by the armed record-lint uniqueness rules on the merged PR union. Complete the class for detection: add the spec_id_unique record-lint rule through the shared validateIDUnique primitive (mirroring issue_id_unique and the intent-id guard), flagging every file that claims a duplicate spc-N. Assisted-by: Claude:claude-opus-4-8
Both close on the refs-union allocator + spec_id_unique lint landed in the preceding commit. Resolved with --impact fix (a bug-class correctness fix). Assisted-by: Claude:claude-opus-4-8
The iss allocator already refuses near math.MaxInt, but the itd and spc mints
computed max+1 with no guard. A hand-crafted MaxInt filename on any scanned
source — a local file or a fetched remote-tracking ref carrying
itd-<MaxInt>-x.md / spc-<MaxInt>-x.md — parses to math.MaxInt with no error,
so max+1 wrapped to math.MinInt and minted a negative id (itd--… / spc--…).
That malformed record was persisted by WriteFileAtomic BEFORE Validate ran,
and the family's mint was DoS'd while the hostile source was present.
Mirror the capture allocator's ceiling guard in both nextIntentID and spec
NextID: refuse loudly ("counter near the integer ceiling; refusing to
allocate") before the arithmetic, so nothing is written.
Also restore .abcd/record-lint.json to its original compact formatting (a
prior commit reflowed it pretty via a one-off serializer, inflating a 1-line
semantic change); the spec_id_unique rule addition is preserved.
Assisted-by: Claude:claude-opus-4-8
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One allocator fix for the record-id minting class (ledger issues iss-115, major + iss-120, minor): sequential ids (
iss-N/itd-N/spc-N) were minted from the local working tree only, so two branches cut from the same base silently minted the same next id — the 2026-07-21 episode cost four renumber commits when two programmes both took spc-10, spc-11, iss-110 and iss-111.Chained PR: base is
fix/iss-117-impact-write-paths(#136), not main — this branch ledger-resolves its issues with the--impactverb that #136 introduces. Merge #136 first; GitHub retargets this PR automatically.What changed
internal/core/recordid(MaxAcrossRefs): every family allocator now mints max+1 over the union of the working-tree scan and the highest id in filenames on every local + remote-tracking branch tip (git for-each-ref→git ls-treeper tip). A parallel branch can no longer re-mint an id its sibling has committed. One shared home, wired into all three allocators (capture/alloc.go,intent/create.go,spec/store.go) — no fourth copy.validateIDUniqueprimitive (mirrors the issue/intent rules iss-74 added), flagging every file in a colliding set..abcd/work/DECISIONS.md): id-range leases, mint-at-merge, non-sequential ids — all trade away human-readable sequential ids without a maintainer mandate.Verification
make preflightexit 0 (build, gofmt, vet, tests, race) andrecord-lintexit 0 — re-run after every commit.impact: fixstamped.itd/spcmints lacked the integer-ceiling guard theisspath already had, so a hostile ref-carrieditd-<MaxInt>filename could wrap the id negative — fixed in the third commit (guard mirrored into both paths, watched-fail tests proving loud-refuse plus zero-write), then re-reviewed PROMOTE with no bypass found.