fix(clone): clones that were empty, cut off, or still ending are handled safely by the next sync #175

Merged
james.maes merged 5 commits from fix/174-interrupted-clones into main 2026-11-11 05:23:31 +00:00
Owner

What

The git client and the WSL clone handle three kinds of unfinished clone safely: one whose origin was empty, one whose first checkout was cut off, and one whose operation is still ending when the next sync starts. See the commit message for the six changes.

Why

Closes #174

Deferred from the review of #148. The first two are data-safety defects: a forced first checkout could replace a file the user had put into the folder, and a cut-off first checkout was reported as up to date with an empty or half-written tree.

How it was tested

  • InterruptedCloneTests (10 tests, real repositories on disk): origin's first commit on another branch; a file, a folder, and a file-where-a-folder-is-needed in the way (refused, nothing changed, the user's content intact); an unrelated file stays; a checkout cut off after its branch was created is completed by the next sync; a branch started by hand with staged files is left alone; an origin that names no default branch; a second operation in a busy folder is refused and works afterwards; a clone without an index.
  • WslClonerTests: the script clones under a temporary name, moves it into place, keeps the cleanup armed until then, and removes only old leftovers.
  • The WSL script was run for real with a POSIX shell against local repositories: fresh clone, repeat (pull), a failing clone leaves nothing behind, a plain folder in the way is refused, an old leftover is removed and a young one kept.
  • Gates: build, 1,084 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13.

Notes for review

  • BeforeFirstCheckoutForTesting is a second internal test seam next to AfterFetchForTesting; it is how the suite produces the cut-off state deterministically.
  • The in-flight registry is static: it is per process, not per client, because several workspaces of one process can target the same folder. It does not protect against another gclo process.

Checklist

  • Commits are signed and signed off (git commit -S -s)
  • Zero build warnings; format and lint are clean
  • Tests added or updated; the 100% coverage gate still passes
  • Docs updated for user-visible changes; threat model updated if the attack surface changed (threat model revision row)
  • No secrets, credentials, or personal data
  • New dependencies are justified below, or none were added (none)
  • Substantial AI assistance, if any, is noted here (written with Claude Code)

🤖 Generated with Claude Code

## What The git client and the WSL clone handle three kinds of unfinished clone safely: one whose origin was empty, one whose first checkout was cut off, and one whose operation is still ending when the next sync starts. See the commit message for the six changes. ## Why Closes #174 Deferred from the review of #148. The first two are data-safety defects: a forced first checkout could replace a file the user had put into the folder, and a cut-off first checkout was reported as up to date with an empty or half-written tree. ## How it was tested - `InterruptedCloneTests` (10 tests, real repositories on disk): origin's first commit on another branch; a file, a folder, and a file-where-a-folder-is-needed in the way (refused, nothing changed, the user's content intact); an unrelated file stays; a checkout cut off after its branch was created is completed by the next sync; a branch started by hand with staged files is left alone; an origin that names no default branch; a second operation in a busy folder is refused and works afterwards; a clone without an index. - `WslClonerTests`: the script clones under a temporary name, moves it into place, keeps the cleanup armed until then, and removes only old leftovers. - The WSL script was run for real with a POSIX shell against local repositories: fresh clone, repeat (pull), a failing clone leaves nothing behind, a plain folder in the way is refused, an old leftover is removed and a young one kept. - Gates: build, 1,084 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13. ## Notes for review - `BeforeFirstCheckoutForTesting` is a second internal test seam next to `AfterFetchForTesting`; it is how the suite produces the cut-off state deterministically. - The in-flight registry is static: it is per process, not per client, because several workspaces of one process can target the same folder. It does not protect against another gclo process. ## Checklist - [x] Commits are signed and signed off (`git commit -S -s`) - [x] Zero build warnings; format and lint are clean - [x] Tests added or updated; the 100% coverage gate still passes - [x] Docs updated for user-visible changes; threat model updated if the attack surface changed (threat model revision row) - [x] No secrets, credentials, or personal data - [x] New dependencies are justified below, or none were added (none) - [x] Substantial AI assistance, if any, is noted here (written with Claude Code) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 1 commit 2026-11-11 02:12:10 +00:00
- The first checkout of a clone that was empty refuses, before anything
  changes, when something is already where the repository has a file or needs
  a folder: a forced checkout would have replaced it.
- The folder is marked unfinished before its branch is created, so a checkout
  that is cut off is completed by the next sync instead of being taken for up
  to date.
- An empty clone follows origin's default branch when origin does not have the
  branch the local HEAD names.
- One git operation per folder at a time in a process. A canceled sync stops
  waiting for its operations without stopping them; a second operation in the
  same folder is refused until the first has ended.
- A clone without .git/index says so and how to rebuild it, instead of git's
  count of conflicts.
- Clone in WSL clones under a temporary name and moves the folder into place
  when it is complete; leftovers of killed runs are removed once a day old.

Closes #174

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
james.maes added 1 commit 2026-11-11 02:40:47 +00:00
The first review reproduced two ways in which this change itself replaced a
user's files, and several holes in what it claimed.

- A repository that has local branches is left alone when its HEAD names a
  branch without commits: that is a branch somebody started, not an empty
  clone. Origin's default branch is followed only by a repository that has no
  branch of its own, and nothing changes before every check has passed.
- The first checkout and the completion of a cut-off checkout go through the
  refusals of the path recovery before anything changes: a link on the way, a
  file where a folder is needed, a folder with files where a file is needed,
  a file that is not what the unfinished checkout wrote, and anything but an
  empty folder where the repository has a submodule. The file a cut-off
  checkout was writing counts as gclo's and is finished.
- A branch's upstream is configured before the branch exists, and a marker
  without a branch starts the first checkout over instead of reporting an
  empty folder as done.
- The WSL clone uses a temporary folder of gclo's own, removes it on signals
  too, does not move into a destination that appeared meanwhile, accepts an
  empty folder at the destination, and removes old leftovers only from its own
  folder. The script is now also run for real by the tests.
- One operation per folder: the long-path spelling of a folder is the same
  folder, and the message fits every holder.

Refs #174

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Author
Owner

Review round 1: DO NOT MERGE. Reworked in 9c53d98; round 2 is running.

The first review reproduced two ways in which this change itself replaced a user's files:

  1. A branch started by hand in an ordinary clone (git switch --orphan) looked like an empty clone to the default-branch switch; HEAD was moved and the next sync force-wrote the tree. Now only a repository with no local branch at all follows origin's default branch, and nothing is changed before every check has passed.
  2. The retry after a cut-off first checkout forced the tree without looking. Now the completion goes through the path recovery's refusals before the branch moves: a file at a destination is replaced only when it is what the unfinished checkout wrote (or the beginning of it: the file it was writing when it was cut off).

Also fixed from that review: submodule places (anything but an empty folder is refused); a link where a folder is needed; a marker without a branch no longer reports an empty folder as done; a branch's upstream is configured before the branch exists; the WSL clone uses a temporary folder of gclo's own, cleans up on signals, does not move into a destination that appeared meanwhile, and accepts an empty folder; the long-path spelling of a folder is the same folder for the one-operation rule.

Tests added: each scenario the reviewer reproduced, a marker-ordering test, and WslCloneScriptRunTests, which runs the script for real with a POSIX shell (five cases). Six deliberate breakages of the fixes were tried; five fail a specific test, the sixth did not compile.

Gates: build, 1,101 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13.

## Review round 1: DO NOT MERGE. Reworked in 9c53d98; round 2 is running. The first review reproduced two ways in which this change itself replaced a user's files: 1. **A branch started by hand in an ordinary clone** (`git switch --orphan`) looked like an empty clone to the default-branch switch; HEAD was moved and the next sync force-wrote the tree. Now only a repository with no local branch at all follows origin's default branch, and nothing is changed before every check has passed. 2. **The retry after a cut-off first checkout** forced the tree without looking. Now the completion goes through the path recovery's refusals before the branch moves: a file at a destination is replaced only when it is what the unfinished checkout wrote (or the beginning of it: the file it was writing when it was cut off). Also fixed from that review: submodule places (anything but an empty folder is refused); a link where a folder is needed; a marker without a branch no longer reports an empty folder as done; a branch's upstream is configured before the branch exists; the WSL clone uses a temporary folder of gclo's own, cleans up on signals, does not move into a destination that appeared meanwhile, and accepts an empty folder; the long-path spelling of a folder is the same folder for the one-operation rule. **Tests added:** each scenario the reviewer reproduced, a marker-ordering test, and `WslCloneScriptRunTests`, which runs the script for real with a POSIX shell (five cases). Six deliberate breakages of the fixes were tried; five fail a specific test, the sixth did not compile. **Gates:** build, 1,101 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13.
james.maes added 1 commit 2026-11-11 03:24:28 +00:00
The second review showed that telling gclo's files from a user's by exact
content does not hold: with line endings being converted, the completion
refused files its own cut-off checkout had written, and a retry interrupted
after the branch had moved refused them for ever. It also found a user's file
deleted where a submodule's parent folder is needed.

- A marked folder is an unfinished checkout only while it has no index (git
  writes the index when a checkout has reached its end). A marked folder with
  an index is updated like any clone, without force.
- An unfinished checkout is completed at the commit its branch is on, before
  the branch moves; what origin has got since comes with the ordinary pull.
  When that commit or origin's cannot be written on Windows, the typed failure
  and the marker are kept as before.
- A file is the unfinished checkout's own when it holds the commit's content
  or the beginning of it, carriage returns aside.
- Refused as well: a file where a submodule's parent folder is needed, a link
  at a destination, a folder there that is not empty.
- Only a repository without branches of its own is an empty clone, and it
  follows origin's default branch only when its folder holds nothing but .git.
- An ordinary update that would replace files changed or added here says so.
- The refusals are Windows' rules and apply on Windows.
- WSL: 'mv -T'; the temporary folder's name is refused as an organization.
  The run tests find Git for Windows' shell beside git.exe and say when they
  had nothing to run.

Refs #174

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Author
Owner

Review round 2: DO NOT MERGE. Redesigned in 099c2b5; round 3 is running.

Round 2 confirmed the round-1 fixes for the reported cases and found that the approach behind them does not hold:

  • N1 (high): the completion of a cut-off checkout refused files that checkout itself had written whenever line endings are converted (core.autocrlf with a .gitattributes), so an interrupted clone of such a repository failed for ever. On main it completed by forcing.
  • N3: a retry interrupted after the branch had moved judged the files against the wrong commit and refused for ever.
  • N2: a user's file where a submodule's parent folder is needed was still deleted.
  • Smaller: links replaced without a refusal, an unborn branch taken over in two states, WSL details, the run tests passing vacuously when sh is not on the path, path aliases.

What changed in the design

Before Now
"Unfinished" = the marker "Unfinished" = the marker and no index. git writes the index when a checkout has reached its end; a marked folder that has one is updated like any clone, without force.
Completion moved the branch to origin's tip, then forced Completion forces the commit the branch is on; what origin has got since comes with the ordinary pull that follows. (When that commit, or origin's, cannot be written on Windows, the typed failure and the marker are kept as on main.)
A file is gclo's when it is exactly what the commit has, as checked out A file is gclo's when it holds the commit's content or the beginning of it, carriage returns aside
Refusals for files and folders Also: a file where a submodule's parent folder is needed, a link at a destination, a non-empty folder at a file's place
Origin's default branch followed when there are no local branches ...and only when the folder holds nothing but .git. A repository that has branches of its own is not an empty clone.

Tests: one for each round-2 finding, among them a real checkout that fails half-way (a file held open) with line endings being converted, which also asserts that such a checkout leaves no index. Seven deliberate breakages were tried; six fail a specific test. The seventh (removing a signal trap from the WSL script) cannot be caught here because the test shell is bash, which cleans up on signals either way; the reviewer verified that case under dash and busybox.

Gates: build, 1,115 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13.

## Review round 2: DO NOT MERGE. Redesigned in 099c2b5; round 3 is running. Round 2 confirmed the round-1 fixes for the reported cases and found that the approach behind them does not hold: - **N1 (high):** the completion of a cut-off checkout refused files that checkout itself had written whenever line endings are converted (`core.autocrlf` with a `.gitattributes`), so an interrupted clone of such a repository failed for ever. On `main` it completed by forcing. - **N3:** a retry interrupted after the branch had moved judged the files against the wrong commit and refused for ever. - **N2:** a user's file where a submodule's parent folder is needed was still deleted. - Smaller: links replaced without a refusal, an unborn branch taken over in two states, WSL details, the run tests passing vacuously when `sh` is not on the path, path aliases. **What changed in the design** | Before | Now | |---|---| | "Unfinished" = the marker | "Unfinished" = the marker **and no index**. git writes the index when a checkout has reached its end; a marked folder that has one is updated like any clone, without force. | | Completion moved the branch to origin's tip, then forced | Completion forces **the commit the branch is on**; what origin has got since comes with the ordinary pull that follows. (When that commit, or origin's, cannot be written on Windows, the typed failure and the marker are kept as on `main`.) | | A file is gclo's when it is exactly what the commit has, as checked out | A file is gclo's when it holds the commit's content **or the beginning of it, carriage returns aside** | | Refusals for files and folders | Also: a file where a submodule's parent folder is needed, a link at a destination, a non-empty folder at a file's place | | Origin's default branch followed when there are no local branches | ...and only when the folder holds nothing but `.git`. A repository that has branches of its own is not an empty clone. | **Tests:** one for each round-2 finding, among them a real checkout that fails half-way (a file held open) with line endings being converted, which also asserts that such a checkout leaves no index. Seven deliberate breakages were tried; six fail a specific test. The seventh (removing a signal trap from the WSL script) cannot be caught here because the test shell is bash, which cleans up on signals either way; the reviewer verified that case under dash and busybox. **Gates:** build, 1,115 engine and 212 CLI tests, 100% line coverage, format, UI suite 13 of 13.
james.maes added 1 commit 2026-11-11 04:30:44 +00:00
The third review confirmed, under real process kills, that a checkout that
was cut off leaves no index, and found no way left to replace or delete a
user's file. It found five narrow cases in which gclo refused, failed or said
done where it used to complete the tree.

- When the branch of an unfinished checkout must move before it is written
  (a tree Windows cannot write, or a history origin rewrote), the commit it
  leaves is recorded, and its files on disk are recognised by it as well.
  A history origin rewrote is followed again, as on main.
- A file is the unfinished checkout's own when it holds what the commit
  stores or what the checkout filters make of it (the 'ident' attribute).
- Where the repository has a symbolic link, a link in the folder is the
  checkout's own.
- A marked folder is taken for finished only when its index and its files
  hold the whole tree of its commit: an index somebody's git wrote over an
  unfinished tree does not make it whole.
- A link where the repository has a submodule is refused; a link is something
  with a target, not anything with a reparse point.
- Tests for each, for a file stored with carriage returns, for a completion
  that fails half-way, and for the order of what following origin's default
  branch writes. The message of an ordinary update that would replace files
  no longer says who changed them.

Refs #174

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Author
Owner

Third review: fixes pushed (41f3712)

The third independent review confirmed, under real process kills, that a checkout that was cut off leaves no index, and found no path left on which a file of the user's is replaced or deleted. Its verdict was merge after fixes: five narrow cases in which gclo refused, failed, or reported done where it used to complete the tree. All are fixed in 41f3712.

Finding What happened Fix
D1 A tree that Windows cannot write, then one it can: the files of the first attempt were refused for ever The commit an unfinished checkout leaves is recorded (gclo.checkoutwrittenbefore, the last 16), and its files are recognised by it as well
D2 Origin rewrote history while a checkout was unfinished: the sync failed The branch is moved before the tree is written, as on main
D3 ident (and other checkout filters): gclo's own files were not recognised A file is the checkout's own when it holds what the commit stores or what the filters make of it
D4 A symbolic link of the repository itself was refused Where the repository has a link, a link in the folder is the checkout's own
D5 An index written by the user's git over an unfinished tree made the folder count as finished A marked folder is finished only when index and files hold the whole tree of its commit

Also: a link at a submodule's place is refused; a link is something with a target, not anything with a reparse point; the message of an ordinary update that would replace files no longer says who changed them; README and threat model corrected; one doc comment moved to the member it describes.

Tests. 45 in InterruptedCloneTests (one per finding, a file stored with carriage returns, a completion that fails half-way with the file held open, the order of what following origin's default branch writes). Eight deliberate breakages of the new code were each caught by a test.

Gates on 41f3712. Build with warnings as errors: 0. Engine 1,127 passed, CLI 212 passed, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13.

A narrow fourth review of this delta runs before the merge.

🤖 Generated with Claude Code

## Third review: fixes pushed (41f3712) The third independent review confirmed, under real process kills, that a checkout that was cut off leaves no index, and found no path left on which a file of the user's is replaced or deleted. Its verdict was *merge after fixes*: five narrow cases in which gclo refused, failed, or reported done where it used to complete the tree. All are fixed in 41f3712. | Finding | What happened | Fix | |---|---|---| | D1 | A tree that Windows cannot write, then one it can: the files of the first attempt were refused for ever | The commit an unfinished checkout leaves is recorded (`gclo.checkoutwrittenbefore`, the last 16), and its files are recognised by it as well | | D2 | Origin rewrote history while a checkout was unfinished: the sync failed | The branch is moved before the tree is written, as on `main` | | D3 | `ident` (and other checkout filters): gclo's own files were not recognised | A file is the checkout's own when it holds what the commit stores or what the filters make of it | | D4 | A symbolic link of the repository itself was refused | Where the repository has a link, a link in the folder is the checkout's own | | D5 | An index written by the user's git over an unfinished tree made the folder count as finished | A marked folder is finished only when index and files hold the whole tree of its commit | Also: a link at a submodule's place is refused; a link is something with a target, not anything with a reparse point; the message of an ordinary update that would replace files no longer says who changed them; README and threat model corrected; one doc comment moved to the member it describes. **Tests.** 45 in `InterruptedCloneTests` (one per finding, a file stored with carriage returns, a completion that fails half-way with the file held open, the order of what following origin's default branch writes). Eight deliberate breakages of the new code were each caught by a test. **Gates on 41f3712.** Build with warnings as errors: 0. Engine 1,127 passed, CLI 212 passed, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13. A narrow fourth review of this delta runs before the merge. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 1 commit 2026-11-11 05:22:46 +00:00
The fourth review looked only at the changes of the third and found two ways,
both opened by those changes, in which finishing an unfinished checkout cost
the user something, and a few smaller things.

- A file somebody added to the index with git, and that the commit does not
  have, was removed by the forced checkout. The completion is now refused,
  names the file, and says how to go on ('git reset', or move the folder).
- Where the repository has a symbolic link, the folders on the way to it were
  no longer checked for links, so a link behind a linked folder could be
  replaced outside the clone. The way is checked again, and a link in the
  folder is the checkout's own only when it leads where the repository's does
  (also on a first checkout, where any link was taken before).
- Whether a marked folder holds its whole tree is asked of the files, not of
  the index: what the index says is whoever's git wrote it.
- A path recovery of an unfinished checkout whose branch had to move accepts
  the files of the commit it left (whole content), and takes the list of those
  commits off when it has written the tree.
- Tests for each, for a list that holds what is not a commit, for the list's
  cap and its entries being recorded once, for a file written before the
  attributes that change it, and for a link to a folder in a finished tree.
  The test of a rewritten history now writes the file it makes a statement
  about, and states what happens to it: it stays, untracked.
- README and threat model say what the code does, and name what is not
  covered: a marked folder whose index somebody's git wrote and whose last
  file was cut off is taken for finished; files of a commit the branch left
  stay in the folder.
- The tests that run the WSL clone script use the shell Git for Windows'
  launcher starts, not the launcher: it puts git's folders in front of the
  path, so the stand-in for git was never found when the tests were started
  from PowerShell (as CI starts them), and two of them failed there.

Refs #174

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
Author
Owner

Fourth review (of the third round's changes only): fixes pushed (5124ed3)

Verdict was merge after fixes. It found two ways, both opened by the third round's changes, in which finishing an unfinished checkout cost the user something, and some smaller things. All verified against the code and fixed.

Finding What happened Fix
1 A file added to the index with git, which the commit does not have, was removed by the forced checkout The completion is refused, names the file, and says how to go on (git reset, or move the folder)
2 The folders on the way to a symbolic link of the repository were no longer checked for links The way is checked again; a link in the folder is the checkout's own only when it leads where the repository's does (this also closes finding 6, a link replaced on a first checkout)
3 README and threat model claimed more than the code did Corrected, and the limits below are named
4 A path recovery after the branch of an unfinished checkout had to move refused the files of the commit it left It accepts a file that is, whole, what a recorded commit has
5 The list of recorded commits outlived a recovery Taken off with the marker
8 Six behaviours no test pinned; one assertion that held before the act Tests added; the index clause of "whole" removed instead of pinned (what the index says is whoever's git wrote it); the assertion now states what happens

Named as not covered (finding 7): a marked folder whose index somebody's git wrote and whose last file was cut off is taken for finished (git shows that file as changed); files of a commit the branch left that the new commit does not have stay in the folder, untracked.

Not pinned by a test: that a link is recognised by its target and not by the reparse-point attribute (a reparse point that is not a link cannot be made offline).

Also found while running the gates: the tests that run the WSL clone script failed when started from PowerShell (as CI starts them). They picked Git for Windows' launcher bin\sh.exe, which puts git's folders in front of the path, so the stand-in for git was never used. They now use the shell the launcher starts, and pass from PowerShell and from Git Bash.

Checks. Eleven deliberate breakages of the new code, each caught by a test. The reviewer's reproductions run against 5124ed3: those of every fixed finding pass; the two that do not are the limits named above. Gates on 5124ed3, started from PowerShell: build with warnings as errors 0, engine 1,141, CLI 212, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13.

🤖 Generated with Claude Code

## Fourth review (of the third round's changes only): fixes pushed (5124ed3) Verdict was *merge after fixes*. It found two ways, both opened by the third round's changes, in which finishing an unfinished checkout cost the user something, and some smaller things. All verified against the code and fixed. | Finding | What happened | Fix | |---|---|---| | 1 | A file added to the index with git, which the commit does not have, was removed by the forced checkout | The completion is refused, names the file, and says how to go on (`git reset`, or move the folder) | | 2 | The folders on the way to a symbolic link of the repository were no longer checked for links | The way is checked again; a link in the folder is the checkout's own only when it leads where the repository's does (this also closes finding 6, a link replaced on a first checkout) | | 3 | README and threat model claimed more than the code did | Corrected, and the limits below are named | | 4 | A path recovery after the branch of an unfinished checkout had to move refused the files of the commit it left | It accepts a file that is, whole, what a recorded commit has | | 5 | The list of recorded commits outlived a recovery | Taken off with the marker | | 8 | Six behaviours no test pinned; one assertion that held before the act | Tests added; the index clause of "whole" removed instead of pinned (what the index says is whoever's git wrote it); the assertion now states what happens | **Named as not covered** (finding 7): a marked folder whose index somebody's git wrote and whose last file was cut off is taken for finished (git shows that file as changed); files of a commit the branch left that the new commit does not have stay in the folder, untracked. **Not pinned by a test:** that a link is recognised by its target and not by the reparse-point attribute (a reparse point that is not a link cannot be made offline). **Also found while running the gates:** the tests that run the WSL clone script failed when started from PowerShell (as CI starts them). They picked Git for Windows' launcher `bin\sh.exe`, which puts git's folders in front of the path, so the stand-in for git was never used. They now use the shell the launcher starts, and pass from PowerShell and from Git Bash. **Checks.** Eleven deliberate breakages of the new code, each caught by a test. The reviewer's reproductions run against 5124ed3: those of every fixed finding pass; the two that do not are the limits named above. Gates on 5124ed3, started from PowerShell: build with warnings as errors 0, engine 1,141, CLI 212, line coverage 100% on the three gated assemblies, format clean, UI suite 13 of 13. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes merged commit 388b57ea94 into main 2026-11-11 05:23:31 +00:00
Sign in to join this conversation.