Skip to content

[BE-0061] feat(roadmap): make BE-ID allocation collision-proof#175

Merged
0x0c merged 4 commits into
mainfrom
claude/lucid-banzai-681f3e
Jun 21, 2026
Merged

[BE-0061] feat(roadmap): make BE-ID allocation collision-proof#175
0x0c merged 4 commits into
mainfrom
claude/lucid-banzai-681f3e

Conversation

@0x0c

@0x0c 0x0c commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Two open PRs allocating a BE id in the same window could still take the same number, and a number contested only between open PRs (none merged) had no arbiter — the three-way BE-0056 collision (#166 / #169 / #170) was exactly this failure. This adds two layers, filed born-implemented as BE-0061 (a sibling to BE-0043).

Prevention — atomic reservation. Allocation claims each id as a refs/be-claims/<NNNN> git ref through GitHub's create-ref API (a compare-and-set — HTTP 422 if the ref already exists), so two branches cannot both take a number; the loser re-picks. Claims are released when a PR closes and swept daily (roadmap-claims-gc.yml).

Backstop — generalized auto-repair. allocate_roadmap_ids.py --repair generalizes its authority from "origin/main only" to "main first, else the lowest open-PR number" (ROADMAP_LOWER_PR_IDS, computed from open_pr_be_map.sh), and roadmap-id-repair runs on a daily schedule as well as on push-to-main. The Python script stays pure (no GitHub coupling); the create-ref calls and retry loop live in the workflows.

No tool behavior, runtime, or scenario semantics change; the deterministic gate is untouched.

Changes

  • scripts/allocate_roadmap_ids.py — repair authority generalized (lower_pr_ids via env), docstrings; tests/test_allocate_roadmap_ids.py +5 (lower-PR detection, tiebreaker, e2e renumber, parsing).
  • scripts/be_claims.sh (claims ledger: list/claim/release) and scripts/open_pr_be_map.sh (PR→id map for the tiebreaker).
  • .github/workflows/: roadmap-id.yml (claim + retry loop), roadmap-id-repair.yml (daily schedule + lower-PR tiebreaker + claim new ids), new roadmap-claims-gc.yml (release on PR close + daily orphan sweep).
  • Docs: BE-0061 item (en + ja), docs/ai-development.md (en + ja), Makefile (shellcheck list + repair comment), regenerated index.

Test plan

  • make check green locally: 1020 passed, coverage 89.81%; shellcheck + actionlint clean; no index drift.
  • Allocator logic is unit-tested. ⚠️ The workflow runtime (claim CAS, retry loop, schedule sweep) can only be exercised on real Actions runs — to be validated on this PR / a follow-up.

Notes

🤖 Generated with Claude Code

Two open PRs allocating in the same window could still take the same BE
id — a BE-XXXX placeholder carries no digits, so ROADMAP_RESERVED_IDS
can't see a not-yet-allocated number — and a number contested only
between open PRs (none merged) had no arbiter, since repair's authority
was origin/main alone. The three-way BE-0056 collision (#166/#169/#170)
was exactly this failure.

Prevention: allocation now claims each id atomically as a
refs/be-claims/<NNNN> git ref via GitHub's create-ref API (a
compare-and-set — 422 if the ref exists), so two branches cannot both
take a number; the loser re-picks. Claims are released when a PR closes
and swept daily (roadmap-claims-gc.yml).

Backstop: allocate_roadmap_ids.py --repair generalizes its authority
from "origin/main only" to "main first, else the lowest open-PR number"
(ROADMAP_LOWER_PR_IDS, computed from open_pr_be_map.sh), and
roadmap-id-repair runs on a daily schedule as well as on push-to-main.
The Python script stays pure (no GitHub coupling); the create-ref calls
and the retry loop live in the workflows.

Filed born-implemented as BE-0060, a sibling to BE-0043. Adds
scripts/be_claims.sh + scripts/open_pr_be_map.sh, extends the allocator
tests (lower-PR collision detection + tiebreaker), and updates
docs/ai-development.md (+ja).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot enabled auto-merge June 21, 2026 14:09
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@0x0c 0x0c requested a review from hirosassa June 21, 2026 14:11
PR #173 (run-report-zip-export) also holds BE-0060 and is the lower PR
number, so it is the authority and keeps it; this item (the higher PR,
#175) moves to the next free id. BE-0061 is free on main and across open
PRs. Renamed the directory and files, rewrote the self-references and the
docs/ai-development.md (+ja) link, and regenerated the index. The
BE-0060 left in tests/test_allocate_roadmap_ids.py is a synthetic
next-free value in a fixture, not a reference to this item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@0x0c 0x0c changed the title [BE-0060] feat(roadmap): make BE-ID allocation collision-proof [BE-0061] feat(roadmap): make BE-ID allocation collision-proof Jun 21, 2026

@hirosassa hirosassa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@0x0c 0x0c disabled auto-merge June 21, 2026 23:18
@0x0c 0x0c added this pull request to the merge queue Jun 21, 2026
@0x0c 0x0c removed this pull request from the merge queue due to the queue being cleared Jun 21, 2026
@0x0c 0x0c merged commit ea4abfc into main Jun 21, 2026
15 checks passed
@0x0c 0x0c deleted the claude/lucid-banzai-681f3e branch June 21, 2026 23:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants