Ruling 2: every tracked text mention of the login's pre-rename spelling becomes igneum-labs (29 files); the commit identity in the scripts becomes igneum-labs <337424239+igneum-labs@users.noreply.github.com> (the same noreply id); the three scripts that hand the stored gh keyring name to gh (register.sh, fetch-ci-artifacts.sh, ship-app.mjs) read it from ~/.config/igneum/gh-user (never in the repository), default igneum-labs; fresh-repo.sh reads the login to rewrite from the encoded list's row 10; the old spelling joins the founder-strings list, so no tracked file may spell it; CLAUDE.md's GitHub paragraph rewritten. The red watcher's self-test fixtures use a neutral author. Ruling 4: docs/ledger-public.md, one row per ledger item (id, the claim in one line, status, what was done in one line, the evidence link or the evidence in words), generated by tools/ledger/export-public.mjs from docs/fud-ledger.md: no round or status-update sections, no commit ids, no time of day, no lane, agent or branch names. 190 items. The gate runs its self-test (a fixture with a commit id, a time, a lane and a branch name comes out clean; --check fails on drift) and its --check on every merge; the founder check reads the output like every tracked file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
121 lines
12 KiB
Markdown
121 lines
12 KiB
Markdown
# 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 | the other business 6, the earlier entity 5, the earlier 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(the other business\|the earlier entity\|the earlier business\|another brand\|another brand)\b==>[other-business]` |
|
|
| `messages.txt` (commit messages) | the first-name rules and the second-login rule |
|
|
| `mailmap` | both personal identities to `igneum-labs <337424239+igneum-labs@users.noreply.github.com>` |
|
|
|
|
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 |
|