Skip to content

feat(overleaf): coordinator step 2 — inventory, review and review registry - #556

Merged
yaacovcorcos merged 13 commits into
mainfrom
claude/overleaf-review-20261013
Oct 22, 2026
Merged

yaacovcorcos merged 13 commits into
mainfrom
claude/overleaf-review-20261013

Conversation

@yaacovcorcos

@yaacovcorcos yaacovcorcos commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Overleaf manual sync, coordinator step 2: the review. Step 1 (#536) is merged; this PR targets main. Plan, contract and decisions: #535, docs/internals/overleaf/ (contract §5, §8, §11; plan §4.1–4.4, §4.9).

Nothing here is wired into the app, and nothing writes to a manuscript folder or contacts Overleaf.

What it adds

Module What it does
OverleafInventory.ts Walks the manuscript folder within the limits: 5,000 entries walked, 2,000 files, 50,000,000 bytes per file, 250 MiB in total. Classifies every entry: managed, selected addition, local-only, unchecked (build output or hidden folder), or excluded (repositories under any name, links, Git's and Scient's folders, droppings, staging, invalid names, LFS pointers). Only managed files, selected additions and requested collision paths are read in full; other additions get a 200-byte prefix read to recognise LFS pointers. Each limit is checked before reading the bytes it bounds. A file or folder that changes while it's read fails the capture. A manuscript folder inside Git's own folders is refused.
OverleafReview.ts Builds a review from a capture and a fetched Overleaf head: the three-way merge, the planner guard, conflict groups with their allowed choices, the candidate tree, incoming and outgoing changes, warnings, and the exact WorkspaceApplyPlan the applier would run. Overleaf's tree is checked against the limits before any of its content is read (A24). Local files that Overleaf now has content at, under or above are captured and reviewed rather than treated as absent (A30). The digest covers every input a confirmation must still match.
OverleafReviewRegistry.ts Keeps one current review per connection for 15 minutes, in memory only, consumed once by ID, digest and acknowledgements. A replaced review is refused as replaced. The staleness check names what changed: connection revision, base, checkout or credential epoch, authority, folder identity, capture, or Overleaf head (a new commit with the same tree counts).
OverleafRepository.treeSizes Reads file sizes in a tree without reading its blobs.

What a review refuses before it can be confirmed

A review is never offered for a plan the file layer or the applier would refuse partway:

  • Overleaf content the folder could never hold (remote-forbidden): droppings, LFS pointers, Git's or Scient's folder names as the file layer compares them (letter case, .gıt, GIT~1), or files that would turn a folder into a Git repository.
  • Two spellings of one file by letter case or Unicode form, which a Mac disk treats as one: in the current files (path-alias), or since the last sync (alias-rename), whether or not Git saw a rename and whatever is chosen. Contract §5 keeps these typed refusals. To get past one: undo it on Overleaf, or rename through another name with a sync in between. PR C must explain this.
  • A path the applier would check that reaches something the review never read (unreviewed-path): an unchecked, local-only or skipped entry, the inside of a skipped folder, or another spelling of a folder. This covers names kept from an interrupted apply and names Git makes up for a file meeting a folder.

Warnings and acknowledgements

  • Must be acknowledged on confirm: first sync, no sync history, outgoing rename, restores an older version (an outgoing file equals its content in one of the 20 prior bases).
  • Shown only: over Overleaf's recommended 100 MB, a text file over 2 MB, text over 7 MB in total.
  • Separately reported: recorded Scient conflict markers still present in captured files, as unresolvedMarkers. Step 4 must refuse to publish while any remain.

Tests (real Git, real folders)

  • OverleafInventory.test.ts (16): classification, exclusions (Git's folders under every name, bare repositories, linked worktrees), a file replaced by a folder, links and nested repositories, LFS pointers, collision capture, the exact 50,000,000-byte boundary, walk/file/total limits, a file changing mid-read, case and Unicode aliases, folders swapped for links mid-capture, a manuscript folder inside Git's folders.
  • OverleafInventory.host.test.ts (2): runs the production WorkspaceFileSystem: every Git path it refuses, the inventory excludes; folders it treats as repositories, the inventory skips.
  • OverleafReview.test.ts (26): up to date, first sync, clean two-way merge, each conflict choice with a new digest, determinism, collisions as forced decisions, every refusal above with the scenario Codex used to find it, the canonical digest, size limits before reading, the local-only cap, warnings, interrupted files and unresolved markers.
  • OverleafReview.apply.test.ts (2): runs the real applier on a real review's plan and checks the folder ends up exactly as reviewed. Skipped where the applier cannot publish natively (Linux CI), as the applier's own suites are.
  • OverleafReviewRegistry.test.ts (21): consume once, replaced, expiry, sweeping, count and byte bounds, digest, acknowledgements, unresolved conflicts, invalidation, each staleness reason.
  • Mutation checks: every fix from rounds 1–8 has a test that fails with the fix removed.
  • vp test run src/scient/overleaf: 15 files, 248 tests. pnpm run typecheck (tsc) exits 0; lint, formatting and knip:check are clean.

Codex review (gpt-6.1-sol, high reasoning): merge-ready

Nine rounds, all recorded in the PR comments. Rounds 1–3 fixed 4 P1, 8 P2 and 1 P3. Rounds 4–8 ran after merging main, where #353 had rewired the applier through the shared file layer. They found one P2 about Git folder names and, in turn, every way two spellings or an unread entry could reach the applier. Each was fixed and its fix re-checked. Round 9 on b40513cb88: merge-ready, no findings. It walked every path the applier reads, writes or guards, and checked that the ordinary flows are not refused. 7405ad84f5 after it only changes which machines run two tests.

Not done in step 2

  • Running a prepare end to end (operation reservation, fetch, capture, build, offer): step 3, with the checkout barrier.
  • Obligations for step 3: confirming must re-capture and rebuild the review and refuse it if stale (overleafReviewStaleness compares the two); a swap-and-restore between checks can make one capture see a false deletion (contract §2.8).
  • Obligation for step 4: publication must independently verify bytes and absence.
  • Agent-activity acknowledgement: needs the activity query (step 3/5).
  • Text diff previews (1 MiB cap): with the routes in step 5.
  • Private-repository storage policy (5 GiB) and fetch growth monitoring: with the fetch in step 3/4.
  • Registry sweep timer: expired reviews are dropped on every registry call; the owner (step 3/5) should also call sweep on a timer.
  • Applier test coverage: feat(documents): add visual LaTeX authoring and reusable templates #353 removed about 20 applier tests from WorkspaceApplier.test.ts (620 → 194 lines). Codex re-probed two of their guarantees (an editor save just before apply survives; a root replaced by a link is refused) and both hold; restoring the rest should come before step 3.

🤖 Generated with Claude Code

yaacovcorcos and others added 2 commits October 13, 2026 19:57
Walks the manuscript folder within Overleaf's and Scient's limits, classifies
every entry (managed, selected addition, local-only, unchecked build output or
hidden, excluded) and reads only what the review needs. Limits are enforced
before the bytes they bound are read; a file that changes while it is read
fails the capture. Unmounted; step 2 of the coordinator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nnection

The review of a manual sync, built from a captured folder and a fetched
Overleaf head: the merge, conflict groups with their allowed choices, the
candidate tree, incoming and outgoing changes, warnings and the exact plan the
applier would run. It writes nothing to the folder and sends nothing.

- Overleaf's content is held to the limits before any of it is read.
- Local files Overleaf now has content at are captured and reviewed, never
  treated as absent; content at an excluded entry refuses the review.
- The digest binds every input a confirmation must still match. Different
  choices or inputs give a new review.
- The registry keeps one current review per connection for fifteen minutes,
  in memory only, consumed once by ID, digest and acknowledgements.
- A staleness check names what changed: revision, base, epochs, authority,
  folder, capture or Overleaf head.

Unmounted; step 2 of the coordinator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Oct 13, 2026
yaacovcorcos added a commit that referenced this pull request Oct 13, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.6 KiB 5.6 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 4.3 KiB 4.3 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.3 KiB 1.3 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 26.2 KiB 26.2 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 5.6 KiB 5.6 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 4.3 KiB 4.3 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.3 KiB 1.3 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 26.6 KiB 26.6 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: 8d7e8b9 · PR result: 7405ad8 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Full compact HTTP snapshot with live cursor.

  • Codex decoded thread snapshot: 133.1 KiB
  • Claude decoded thread snapshot: 133.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

- A never-synchronized local file that meets Overleaf content is a forced
  conflict decision; capturing it no longer enrols it in a clean merge.
- Overleaf content is held to the folder's own rules (droppings, reserved
  names, staging, invalid paths, LFS pointers) before it can reach a plan.
- Case and Unicode aliases are refused: a managed file on disk under another
  spelling is not a deletion, and differing spellings across sides stop the
  review.
- Captures re-check every folder above a file before and after reading it,
  and that the path still names the file read.
- Directories are iterated within the walk limit instead of read whole;
  nested repositories are recognised without listing them.
- Candidate sizes are checked before any blob is read; merge-in-editor text
  is read only for an eligible group within the file limit.
- Local-only decisions the connection cannot remember are refused.
- The digest is canonical JSON and binds collisions and recorded markers.
- Staleness compares a fresh rebuild of the review and names what changed,
  including inventory changes that leave the captured tree alone.
- The registry drops expired reviews on every call and bounds how many
  reviews and target bytes it holds.
- Typecheck fixes (widened limit types, explicit class field, typed test
  helpers, approved ID helper).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, round 1 (gpt-6.1-sol, high reasoning, read-only)

Verdict on 2251c34eed: no. 4 P1 and 7 P2 findings, all addressed in 8300836e8c:

# Finding Fix
P1 Capturing a never-synchronized collision enrolled it in a clean merge: an unchecked file in a folder that replaced a synced file could be published, and the synced file deleted, with no choice Collisions are forced conflict decisions (new collision origin in conflictGroups), including the Overleaf paths they meet. Identical bytes still ask. Only exactly the colliding paths may be captured as collisions.
P1 A managed file on disk under another Unicode or case spelling was treated as deleted The inventory refuses alias; the review refuses path-alias across both sides.
P1 Swapping a folder above a file for a link mid-capture read bytes from outside the manuscript Every folder above a file is re-checked against its walked identity before and after the read, and the path must still name the file read.
P1 Overleaf content the folder could never hold (LFS pointer, .DS_Store) reached confirmable plans Overleaf entries are held to the same name rules plus a prefix check of small changed blobs; refused as remote-forbidden.
P2 27 typecheck errors (my local check wasn't running the real command) Fixed; pnpm run typecheck exits 0.
P2 Digest missed recorded markers and collisions, and wasn't canonical Canonical JSON with sorted keys; binds collisions, recorded and unresolved markers; interrupted groups and conflicts in code-unit order.
P2 Staleness missed inventory changes that leave the captured tree alone Staleness compares a fresh rebuild and names the first difference, including inventory and review.
P2 Marker text read before choices, and candidate read before its size was checked Sizes come from tree listings before any read; marker text is read only for an eligible group within the file limit.
P2 Directory listing wasn't bounded by the walk limit Directories are iterated and stop at the limit; nested repositories are recognised by a single check.
P2 Local-only decisions could exceed what the connection can store Refused as local-only-limit before applying.
P2 Expired reviews kept their bytes until the same connection was touched Every call sweeps all connections; count and byte limits evict the oldest.

Each P1 fix has a test that fails with the fix removed. 314 Overleaf tests pass. Round 2 is reviewing 8300836e8c.

🤖 Generated with Claude Code

@github-actions github-actions Bot added size:XXL and removed size:XL labels Oct 13, 2026
… identity

A folder swapped for a link to an empty folder just before it was listed made
its managed files look deleted, and the review proposed deleting them from
Overleaf. Each folder's chain is now verified before and after it is listed,
and every walked folder once more after the walk, before absence is trusted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, round 2 (gpt-6.1-sol, high reasoning, read-only)

Verdict on 8300836e8c: no, one P2 left. All eleven round-1 fixes were confirmed by direct attempts to break them. For example, an oversized candidate was refused with zero blob reads, and a new unchecked file was reported as inventory.

Finding Fix
P2: a folder swapped for a link to an empty folder just before it was listed made its managed files look deleted. The review then built a confirmable deletion from Overleaf; a fresh capture would have refused it. b0df400fe6: each folder's chain is verified before and after it's listed, and every walked folder once more after the walk, before any absence is trusted. The regression test fails with the checks removed.

315 Overleaf tests pass, and typecheck, lint and knip are clean. Round 3 is reviewing b0df400fe6.

🤖 Generated with Claude Code

…s whole chain

Round 3 measured the folder checks growing with depth: 49 chains of 100
folders took 11.6 s instead of about 1 s. Each check now looks at one or two
folders, and a sweep after the walk and another after the reads cover every
walked folder once. Same tree: 1.2 s. The swap regressions still refuse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, round 3 (gpt-6.1-sol, high reasoning, read-only)

Verdict on b0df400fe6: yes with follow-ups, as an unmounted stacked PR. No P0–P2 findings. Codex tried to break the round-2 fix and each attempt was refused as unstable:

  • a swap between the check and the listing;
  • replacement by a real folder with another inode;
  • an ancestor swap;
  • a root swap.

A nested repository still gives managed-excluded. Ordinary content and permission changes don't trigger false refusals.

Finding Status
P3: folder checks grew with depth (49 chains × 100 folders: 1.4 s → 11 s) Fixed in 53cbd71292. Each check looks at one or two folders, with one sweep after the walk and one after the reads. Same tree on one machine: 11.6 s before, 1.2 s after.

Accepted limit, and what later steps must do about it. A folder swapped and then restored between two checks can still make a file look missing for one capture. That is the non-atomic sampling the contract accepts (§2.8). Codex confirmed that a fresh capture and rebuilt review removes the false deletion, and that staleness reports capture. So:

  • Step 3: confirmation must actually re-capture and rebuild the review, and refuse it if stale, before applying.
  • Step 4: publication must independently verify bytes and absence (contract §5). The applier's per-file checks don't cover a deletion that is only outgoing.

315 Overleaf tests pass; typecheck exits 0; lint and knip are clean.

🤖 Generated with Claude Code

…e-20261013' into claude/overleaf-review-20261013
yaacovcorcos and others added 2 commits October 21, 2026 00:12
…an apply

Codex round 4 on 82568ed found two plans a review would offer that the
current file layer or applier refuses partway:

- Git's folders: names now compare as the host's file layer compares them
  (upcased, so `.gıt` is `.GIT`; Windows' trailing dots, spaces and stream
  suffix; `GIT~1`). The inventory skips a repository folder under any name
  (HEAD plus objects and refs, or HEAD plus commondir) and refuses a
  manuscript folder inside Git's folders (`git-folder`). The review refuses
  Overleaf content that would make a folder a repository
  (`remote-forbidden`, kind `repository`). A test runs the production
  WorkspaceFileSystem against these rules.
- Case-only renames: a path absent before and after, but spelled like a
  present file, stays in the review and the base and leaves the applier's
  plan with its renames. On a case-insensitive disk it resolves to the
  present file, and the applier cannot rename a file to its own name.

Each fix has a test that fails with it removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, round 4 (gpt-6.1-sol, high reasoning, read-only)

Brought up to date with main (82568ed925, merge, no conflicts). Main had moved about 1,500 commits since round 3, including #353, which rewired the applier through the shared file layer, and the Git-folder write guard (5984a68166).

Verdict on 82568ed925: no, two P2s. Both fixed in ecbe66f627:

Finding Fix
P2: a review could plan writes the file layer refuses. Overleaf content at .gıt/config (dotless ı, which upcases to .GIT) made a confirmable review; applying it failed with WorkspaceFilePathEscapeError. The inventory also listed a bare repository's files as additions. Reserved names compare as the file layer compares Git's (upcased, Windows' trailing dots, spaces and stream suffix ignored, GIT~1). The inventory skips a repository folder under any name and refuses a manuscript folder inside Git's folders (git-folder). The review refuses Overleaf content that would make a folder a repository (remote-forbidden, kind repository). A new test runs the production WorkspaceFileSystem against these rules.
P2: a rename on Overleaf that only changes letter case (Upper.tex → upper.tex, deleted locally, "theirs") gave a confirmable plan the applier rejects. Fixing it showed a second cause: on a case-insensitive disk the applier's check of Upper.tex finds the new upper.tex. A path absent before and after but spelled like a present file now stays in the review and the base, and leaves the applier's plan. Safe because a review never changes a spelling on disk (the alias checks refuse that). The test runs Codex's scenario through the real applier.

What held:

  • The speed fix (53cbd71292): swapping an ancestor or the root for a link or another real folder was refused as unstable. A 4,900-folder capture went from 11.5 s to 0.9 s.
  • Both review-to-applier tests pass on the merged applier.
  • Probes for two applier guarantees whose tests feat(documents): add visual LaTeX authoring and reusable templates #353 removed both held: an editor save just before a step survived, and a root replaced by a link after preflight was refused.

Each fix has a test that fails with it removed. 361 Overleaf, workspace and file-layer tests pass; typecheck, lint and knip are clean. Round 5 is reviewing ecbe66f627.

🤖 Generated with Claude Code

Codex round 5 on ecbe66f showed that leaving such a rename's old spelling
out of the applier's plan loses the old base identity when the apply is
interrupted (contract section 2.5), and that choosing "mine" still left an
alias-only rename the applier rejects, for case and NFC/NFD alike.

The contract keeps alias-only renames a typed preflight refusal and says
the coordinator does not work around them (section 5). The review now
refuses with `alias-rename` whatever is chosen, and the plan filtering is
gone. The refusal's test fails with it removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, round 5 (gpt-6.1-sol, high reasoning, read-only)

Verdict on ecbe66f627: no, two P2s, both against the case-only rename fix. The Git-folder fix held: host-parity tests, repository shapes across disk and Overleaf, bare ancestors, worktree boundaries, and ordinary HEAD files.

Finding Fix in d24a81800f
P2: leaving the old spelling out of the applier's plan lost its base identity when the apply was interrupted (contract §2.5). The plan filtering is removed.
P2: choosing "mine" still left an alias-only rename the applier rejects, for letter case and for NFC/NFD forms. The review now refuses alias-rename (from, to) whenever either side renamed a file by letter case or Unicode form alone, whatever is chosen.

Contract §5 already says alias-only renames "remain typed preflight errors; the coordinator does not invent a workaround". The round-4 filtering was such a workaround. To get past the refusal, undo the rename on Overleaf, or rename through another name with a sync in between. PR C must explain this.

The refusal's test (case and NFC/NFD, no choice, "mine" and "theirs") fails with it removed. 361 tests pass; typecheck, lint and knip are clean. Round 6 is reviewing d24a81800f.

🤖 Generated with Claude Code

yaacovcorcos and others added 2 commits October 21, 2026 01:30
…tected renames

Codex round 6 on d24a818: checking each rename's endpoints missed
aliases across renames. With a.tex and z.tex synced and both deleted
locally, Overleaf's A.tex (z's content) and b.tex (a's content) pair as
z→A and a→b; "theirs" was confirmable, and the applier wrote A.tex, then
found it under a.tex and stopped with attention.

Every path the applier touches is in the base, Overleaf's tree or the
capture, so the review now refuses `alias-rename` when two distinct paths
among them share a collision key, before staging, whatever is chosen and
whether or not Git saw a rename. The test adds the cross-rename case and a
respelling with new content; it fails with the refusal removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex round 7 on fe80a5a: conflict groups add paths the applier checks
that are outside base, Overleaf's tree and the capture. A group kept from an
interrupted apply (A.tex) met Overleaf's a.tex; a name Git makes for a file
meeting a folder (p~Scient) met an unchecked P~scient on disk. Either made a
confirmable review whose apply stopped with attention.

After conflict groups are built, and before any choice or blob read, every
path the applier can check (base, Overleaf, capture, merge, rename ends,
group paths) is compared with each other and with everything on disk;
two spellings of one whole path refuse `path-alias`. Its test fails with
the check removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, rounds 6 and 7 (gpt-6.1-sol, high reasoning, read-only)

Both rounds found more ways for two spellings of one file (letter case or Unicode form) to reach the applier. On a Mac disk those are one file, so the apply stops partway with attention.

Round Finding (P2) Fix
6 on d24a81800f Checking each rename's ends missed aliases across renames: Git paired z→A and a→b, so a.tex and A.tex met. fe80a5a279: before staging, two spellings of one path anywhere in the base, Overleaf's tree and the capture refuse alias-rename (from = the synced spelling), whether or not Git saw a rename.
7 on fe80a5a279 Conflict groups add paths outside those three: a group kept from an interrupted apply (A.tex meeting Overleaf's a.tex), and a name Git makes for a file meeting a folder (p~Scient meeting an unchecked P~scient). d94606d909: once conflict groups are built, before any choice or blob read, everything the applier can check is compared with everything else and with everything on disk: base, Overleaf, capture, merge, rename ends and group paths. A match refuses path-alias.

What round 7 confirmed held:

  • Case, NFC/NFD and new-content respellings refuse whatever is chosen.
  • File/folder substitutions in history and renamed parents apply correctly.
  • No over-broad refusal. Refusing a respelling with new content fits contract §5.

Each check's test fails with it removed. 362 tests pass; typecheck, lint and knip are clean. Round 8 is reviewing d94606d909.

🤖 Generated with Claude Code

yaacovcorcos and others added 2 commits October 21, 2026 02:10
…ead entry

Codex round 8 on d94606d: comparing spellings missed two ways the applier
reads a file nobody reviewed. Git's file/folder name `p~Scient` exactly
matched an unchecked `p~Scient`, and a path kept from an interrupted apply
(`p/x.tex`, or `P/x.tex`) lay inside a nested repository the walk skipped.
Both gave confirmable reviews whose apply stopped with attention.

The late check is now about occupancy: a path the applier can check that
this review did not read is refused `unreviewed-path` (path, onDisk) when it
matches an unchecked, local-only or skipped entry by collision key (same
spelling or not), is another spelling of a walked folder, or lies below a
skipped entry. Two spellings among the applier's own paths still refuse
`path-alias`. Each part's test fails with it removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ublish

Since #353 the applier writes only through native file publication and
refuses elsewhere, so on Linux CI both review-to-applier tests failed with
WorkspaceFileMutationUnavailableError. They now skip unless
nativePublicationHost(), as the applier's own suites do. The file-layer
agreement test treats an unavailable publication as "not refused": the Git
folder refusal comes before any write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Codex review, rounds 8 and 9 (gpt-6.1-sol, high reasoning, read-only)

Round 8 on d94606d909: no, two P2s. Both were ways the applier could read a file the review never read. Fixed in b40513cb88:

Finding Fix
Git's file/folder name p~Scient exactly matched an unchecked p~Scient. The spelling check only compared different spellings, so it passed. The late check is now about occupancy. A path the applier can check that the review didn't read is refused unreviewed-path (path, onDisk) when any of these hold:
A path kept from an interrupted apply (p/x.tex or P/x.tex) lay inside a nested repository the walk skipped without listing. • it matches an unchecked, local-only or skipped entry, by the same spelling or another
• it is another spelling of a walked folder
• it lies below a skipped entry.

Two spellings among the applier's own paths still refuse path-alias.

Round 9 on b40513cb88: merge-ready, no findings.

  • Both round-8 reproductions refuse, including a real interrupted apply.
  • Codex listed every path the applier reads, writes, stats or guards, and each is covered:
    • captured and target paths, rename ends, merged names, every group path and marker path;
    • ancestors that are unchecked files resolve to absence without being read;
    • folders under the exact spelling stay usable for structural changes;
    • journals, retention and staging have their own authority.
  • Ordinary flows aren't refused: unchecked and local-only collisions through needs-capture, file→folder and folder→file, and a base file replaced by a folder.
  • 23 extra probes through the real applier passed.

After round 9, CI only (7405ad84f5). Since #353 the applier publishes only through the native helper, so on Linux CI the two review-to-applier tests failed with WorkspaceFileMutationUnavailableError. They now skip unless nativePublicationHost(), as the applier's own suites do. The file-layer agreement test treats "unavailable" as "not refused", because the Git-folder refusal comes before any write. No product code changed.

🤖 Generated with Claude Code

@yaacovcorcos
yaacovcorcos marked this pull request as ready for review October 20, 2026 23:54
@yaacovcorcos

Copy link
Copy Markdown
Contributor Author

Ready to merge: Codex round 9 merge-ready on b40513cb88. 7405ad84f5 after it only gates two applier-backed tests to machines with native publication. CI is green (28 pass, 9 skipped).

Two LaTeX editor browser tests from #353 failed on this branch's CI runs and passed on re-run:

  • LatexVisualEditor "types and undoes below unused declaration \newcommand% name follows"
  • latexVisualStability "typing, splitting and joining keep content above still"

This PR changes no web code, main is green at the merged commit, and both files pass locally (45/45). They are timing flakes on the CI runners, worth a separate fix on main.

🤖 Generated with Claude Code

@yaacovcorcos
yaacovcorcos added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 4d3e010 Oct 22, 2026
68 of 71 checks passed
@yaacovcorcos
yaacovcorcos deleted the claude/overleaf-review-20261013 branch October 22, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant