igneum/docs/plans/history-rewrite.md

12 KiB

G14: the history rewrite, exact plan and dry-run result (4 October 2026, night)

Internal. Extends docs/fud-fixes.md section 5 (step 4) with the exact commands, what the dry run showed, what breaks, and the order for the morning. Nothing here has touched the real repository: the dry run ran on a throwaway mirror clone under the session scratchpad and nothing was pushed. The owner is not named in this file; "the first name" and "the login" stand for the values the script reads from the history itself.

1. What the history holds today (counts from the real repository, 4 October 2026, 22:30 UTC)

Item Count Where
Commits 363 on all branches
Commits stamped +0100 (author or committer) 291 of 363 the UK or Irish summer offset; 72 are +0000
Commits authored with the personal name 40 (31 on the old GitHub noreply address, 9 on the personal address) the commits before the 3 October identity rule
Commits as the standing login igneum-labs 323
The intake key 6 tracked files, 8 commits (78df757 to 4c9810f) packaging/mac/packaged-config.sh, infra/gpu-bench/upload.sh, proving/windows-wsl2/prove-block.sh, prove-shard.sh, proto-cuda/windows-miner/upload-log.bat, proto-cuda/windows-app/upload-log.bat
The dl token 1 tracked file, 1 commit (c47ff03) docs/plans/morning-2026-10-04.md
The .next rotations of both 0 files, 0 commits ~/.config/igneum/log-intake-key.next, dl-token.next (4 October 19:25) are not in the tree
The relay key and token (current and old) 0 files, 0 commits
The review files docs/fud-ledger.md (36 commits from 39c20b7), docs/fud-fixes.md (6 from e7545d5), docs/review/ (4 from 5ab296c), site/ledger.html (5 from 0ec11be) tracked, not ignored
Tracked files carrying the first name (case-insensitive) 71 at HEAD; 93 commits touch such content; 10 commit messages carry it CLAUDE.md, the agent file, plans, packaging, the app's WSL paths, the Chrome profile rule
The surname 4 files at HEAD
The other businesses' names, the registrar, the database id, home paths [other-business] 6, [other-business] 5, [other-business] 4, godaddy 7, soft-voice 3, /Users/ 22, quantum 4 identity terms are rewritten by the history pass below; providers and paths are the public-export scrub's job (tools/ci/forbidden-strings.txt), not this pass

2. The rewrite, exactly

Tool: git-filter-repo 2.47.0 (not installed on the Mac; the dry run used a pip install into the scratchpad, python3 -m pip install --target <dir> git-filter-repo, run as python3 <dir>/git_filter_repo.py). It refuses to run on anything but a fresh clone, which is the safety the plan relies on.

The script is dryrun.sh in the scratchpad (rewrite/); it reads every value from the history and from ~/.config/igneum at run time and writes the replacement files with mode 0600, then deletes them. The one invocation, with the files it writes:

git clone --mirror <repo> clone && cd clone
python3 git_filter_repo.py --force \
  --invert-paths --path docs/fud-ledger.md --path docs/fud-fixes.md --path docs/review --path site/ledger.html \
  --replace-text replace.txt \
  --replace-message messages.txt \
  --mailmap mailmap \
  --commit-callback '
for attr in ("author_date", "committer_date"):
    d = getattr(commit, attr); parts = d.split(b" ")
    if len(parts) == 2 and parts[1] != b"+0000":
        setattr(commit, attr, parts[0] + b" +0000")
'
File Lines (values never written in this plan)
replace.txt (blob text) literal:<intake key>==>***INTAKE-KEY-REMOVED***; literal:<dl token>==>***DL-TOKEN-REMOVED***; the two personal Name <email> strings to the standing login string; the personal email and the old noreply address to [removed]; regex:\bFirst's\b==>the project lead's; regex:\bFirst\s+Last\b==>the project lead; regex:\bFirst\b==>the project lead; regex:\bLast\b==>[removed]; regex:(?i)(?<!igneum-)\bfirst\b==>[user] (the lowercase user-name form in Windows and WSL paths, added after dry run 1 left 20 lines); regex:(?i)\b<second login>\b==>[second-owner-login]; regex:(?i)\b([other-business]|[other-business]|[other-business]|[other-business]|[other-business])\b==>[other-business]
messages.txt (commit messages) the first-name rules and the second-login rule
mailmap both personal identities to igneum-labs <337424239+[removed]>

The date callback keeps the instant and rewrites the offset to +0000, so no commit moves in time; only the +0100 fingerprint goes. --invert-paths drops the four internal files from every commit, which empties the commits that touched nothing else; filter-repo prunes those.

3. The dry run (two passes on the mirror clone, 4 October 2026, 22:35 to 22:55 UTC)

Check Before After pass 2
Commits 364 in the mirror (363 plus the in-progress branch head) 312: the 52 commits that only touched the dropped files are gone
Author and committer identities 3 1: the standing login on all 312
Timezone offsets (author and committer, 624 stamps) 291 x 2 +0100 624 +0000
git log -S<intake key> 8 commits 0
git log -S<dl token> 1 commit 0
Commits touching the four dropped files 51 0
Identity grep over every blob in the history (first name outside the login, surname, second login, personal addresses, the other businesses; case-insensitive) thousands of lines 0 lines
Identity grep over commit metadata (names, addresses, subjects, bodies) 0 lines
CLAUDE.md line 4 after the pass the full name "the project lead's project, started 3 October 2026"
Runtime 2 min 58 s for the filter, 3 min 15 s with the greps

Pass 1 (case-sensitive name rules only) left 20 blob lines and 2 message lines: the lowercase user-name form in C:\Users\<first> and WSL paths in app/igneum-app/src/jobrun.rs, prover.rs, docs/plans/shard-test-pc2.md, packaging/README-ship.md, packaging/ota/publish-jobs.sh, relay/playbooks/shard-test.ps1 and the Chrome-profile line of CLAUDE.md. The (?i)(?<!igneum-) rule closed them in pass 2.

What the pass does NOT do, by design, and must be done by hand or by the owner:

Gap Why Who
The standing login igneum-labs carries the first name inside it, in every commit's author line and in every file that names the login A login is a GitHub setting, not a text rule: renaming it is one setting, the numeric noreply id stays, then one more mailmap line (<new> <337424239+<new>@...> <337424239+igneum-labs@...>) and one more replace rule (igneum-labs to the new login) go into the same pass the owner (rename), then the script
CLAUDE.md as a public file (section 5 step 2 of docs/fud-fixes.md: the registrar, the database id, the browser-profile section, the tooling links) The pass replaces names; it does not rewrite paragraphs. The scrubbed CLAUDE.md of step 2 replaces the file in every commit with --path-rename or a blob callback once it exists Claude, after the owner approves the public text
The second owner login is still an organisation owner GitHub setting (decision e: one anonymous owner) the owner
Providers, hosts, home paths, machine names the public-export scrub (tools/ci/forbidden-strings.txt, igneum-public/tools/sync.sh); the private repository keeps them until the public date the export

4. What breaks when the rewrite is applied for real

What Why Recovery
Every worktree of the main checkout (16 today: igneum-wt-appui, bughunt, buildjob, devfee, eff, finality, latency, perf, redteam, release, reliability, ship, site, wallet, testnet, plus two under the scratchpad) Their HEADs point at old commit ids that no longer exist in the rewritten history; git status still works on the old objects, git pull and git rebase do not Each agent commits and pushes its branch before the freeze; after the rewrite every branch is re-created from the rewritten refs: git worktree remove, git worktree add ../igneum-wt-<name> <branch>
Agents' branches (15 local, 11 on origin) Rewritten with everything else (the mirror clone carries every ref), so the branch names survive with new ids; an agent that keeps an old local branch will have diverged from its rewritten twin by every commit No agent commits during the freeze; after it, every agent re-creates its worktree, never merges an old-id branch into a new one
Open pull requests, if any Their base and head ids vanish None open today (the project merges by hand); check gh pr list before the freeze
The Vercel GitHub integration (igneum project, deploys on push to master) The integration links by repository id, not by commit, so it survives a force-push; the first push of the rewritten master triggers one deploy of the same site (the public tree is unchanged by the pass except the dropped site/ledger.html, already a 307 redirect) Watch the deploy; nothing to relink. If the repository is re-created instead (section 5, option B), the integration is re-linked once in the Vercel project settings
The windows-ci and ci workflows Run on the rewritten push like any push; the DL_TOKEN secret is a repository setting and survives Re-set the secrets if the repository is re-created
Old commit ids in documents (docs/bench-log.md, plans, the ledger) and in the public export They name commits that will not exist; filter-repo writes commit-map (old id to new id) in .git/filter-repo/ and rewrites ids it finds in commit messages, not in files Keep commit-map with the private notes; the bench log keeps its short ids as historical labels (the public export already strips the history)
GitHub's copies of the old objects A force-push does not delete them from GitHub's object store; cached PR views, old commit URLs and forks keep serving them until GitHub runs a garbage collection, which support can be asked to do Option B below removes the question
The fork worktrees under vendor/ Separate repositories (vendor/ is gitignored); untouched Nothing
The intake key and the dl token Removing them from the history does not revoke them; every shipped package and every installed app carries the current key Rotate first (the .next values exist since 4 October 19:25): new key in relay/ and in packaging/mac/packaged-config.sh, repackage, republish; the old key keeps working for installed apps until they update, then dies

5. The order of operations for the morning

  1. Rotate the secrets: switch the relay and the intake to log-intake-key.next, the downloads folder to dl-token.next, repackage the Mac and Windows apps with the new values, publish, confirm an upload lands under the new key. Then the old values in the history are dead values.
  2. The owner renames the login igneum-labs (GitHub settings; the noreply id 337424239 stays), confirms the second login is no longer an organisation owner, and approves the public CLAUDE.md text (section 5 step 2).
  3. Freeze: every agent commits and pushes its branch, then stops; gh pr list must be empty; git worktree list is recorded.
  4. Mirror clone, run the pass (section 2) with the two extra lines from step 2 and the scrubbed CLAUDE.md blob; the greps of section 3 must all read 0; keep commit-map.
  5. Choose A or B. A: git push --mirror from the clone to the existing repository, then ask GitHub support to purge the unreachable objects. B (the route docs/fud-fixes.md step 4 prefers): create a fresh repository under the organisation, push the rewritten refs there, re-link Vercel and re-set the two secrets, archive the old repository private. B leaves no old object anywhere.
  6. Re-clone the main checkout from the new history; every agent re-creates its worktree from its rewritten branch.
  7. TZ=UTC on every path that commits: the agents' shells, the ship scripts, the relay; and git config --global cannot set a timezone, so the rule is in the environment. The CI identity grep and git log --format='%ad' --date=raw | grep -c +0100 become the daily check (0 is the goal).
  8. The public export (igneum-network/spec) is unaffected: it carries no history from this repository.

6. What waits for the owner

Decision Options
The new login name any handle without a name
A or B in step 5 B recommended
The public CLAUDE.md text section 5 step 2 of docs/fud-fixes.md
The day after step 1; before the public date in every case