Skip to content

Remove the latex-review names and keep paper settings in .git/papilot - #134

Merged
cu1ch3n merged 10 commits into
mainfrom
chore/remove-latex-review-names
Nov 11, 2026
Merged

cu1ch3n merged 10 commits into
mainfrom
chore/remove-latex-review-names

Conversation

@cu1ch3n

@cu1ch3n cu1ch3n commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

The review engine still used the name of its retired standalone skill for each paper's state, task refs, settings file and browser storage. This removes it and moves existing papers on first open.

What changes

Before After
.git/latex-review/ .git/papilot/
refs/latex-review/<task>/… refs/papilot/<task>/…
.latex-review.json in the working tree (also committed by the import commit) .git/papilot/settings.json
localStorage latex-review:* (also playground:latex-review:*) papilot:review:*
snapshot commits by latex-review <latex-review@localhost> Papilot <papilot@localhost>

Importing or opening a folder no longer writes a file into the paper or its first commit. The engine's separate LICENSE and notices entry are removed (same MIT license and author as Papilot), as is engine/.github, which GitHub never ran. The example paper drops its .latex-review.json, and its preview PDF/SyncTeX is rebuilt for the reworded sentence (same 26 pages, same SyncTeX inputs).

Migration for existing users

  • stateDir() in engine/src/core/git.ts is the only way to get a state folder. Its first call per Git directory in a process runs moveLegacyState (engine/src/core/legacy-state.ts), so nothing can create .git/papilot before the earlier state has moved.
  • Refs move in a single update-ref --stdin transaction; a ref whose new name exists stays (its commits stay reachable). Every Git directory's folder moves the same way: the main checkout's and each linked worktree's, which is a paper's whole state when that worktree was added as a paper. Nothing is ever deleted; if both names exist, both are left.
  • A link stays under the former name (a junction on Windows). Cached builds, their SyncTeX, rounds and jobs record absolute paths into the folder, and Papilot names a manuscript build by its PDF's path (notes find their earlier PDF by it). SyncTeX cannot be rewritten to a path of another length (its ! byte offsets), so rewriting some records would leave others inconsistent. With the link every earlier path stays valid: cached PDFs are reused, notes keep their builds, earlier rounds keep their positions and further places. cachedPdf accepts a PDF reached through the link. Papers that never had the earlier state get no link.
  • Papilot's server moves every registered paper at startup, before serving, and when a paper is added (src/server/state.ts). A review server of the earlier version may still run after an update: on macOS/Linux it keeps working through the link (its lock and files resolve to the same place) until Papilot replaces it as it replaces any server of another version; on Windows its open files keep the folder from moving, so Papilot stops it first (stopServerIn) and waits until the process has exited. Update probes use a separate data folder and move nothing.
  • Once nothing is left to move, each start only checks a few paths, without running Git (2 ms on the thesis copy). Empty ref folders Git leaves after the move are removed.
  • Settings from .latex-review.json are copied into the paper's settings.json once; the author's file is never modified. An unreadable settings.json or an unusable .latex-review.json is reported, as before, instead of silently falling back to detection.
  • Browser keys move in engine/src/web/legacy-storage.ts, imported first by each web entry point; blocked storage is tolerated.
  • On an APFS copy of the author's real thesis (539 refs, 56 worktree folders, 24 places.json, 19 job logs, 302 tasks, 652 rounds) the move took 0.4 s; every places.json stayed byte-identical, all 19 job logs were readable through their recorded paths, and the database passed integrity_check.
  • Known limit, also in the changelog: once this version has opened a paper, an older Papilot cannot work with its tasks (their refs moved).

Also

  • src/server/manuscript.ts was the only file with CR line endings (whole file committed as CRLF in 6b5e165 before .gitattributes existed, then mixed with LF edits). It is normalized to LF in its own commit; git diff --ignore-cr-at-eol is empty.
  • The two import error messages about .latex-review.json are gone, so their translations are removed.

Tests

  • New engine/tests/ts/legacy-state.test.ts: moving the folder, packed and loose refs, worktree folders and settings, with earlier absolute paths readable through the link; a linked worktree added as a paper; both names present (nothing deleted, repeated); a paper without earlier state left untouched; unusable settings reported; stopServerIn against a real review server.
  • New tests/legacy-state.test.ts: the startup sweep (and skipping a missing paper); browser storage keys, including the demo prefix and a key already saved under its new name.
  • tests/imports.test.ts: an earlier version's .latex-review.json is honored and moved on import.
  • Ran locally: engine tests for core, server, server-lock, review, round-first, verify, cancel, applied, legacy-state; root tests for app, workspace, imports, doctor, fast-builds, incremental-build, projects, references, review-servers, review-snapshot, stop-builds, licenses, desktop-demo, example-paper, pdf-reader, annotated-pdf, windows, legacy-state. Browser checks and the remaining suites run in CI.

The review engine's state, task refs, settings file and browser storage
keys still carried the name of its retired standalone skill. Papilot now
uses .git/papilot/, refs/papilot/ and papilot:review: keys, and keeps a
paper's settings in .git/papilot/settings.json instead of writing
.latex-review.json into the author's repository and its first commit.

Existing papers move on first open. Every path into the state folder
comes from stateDir(), which moves the old folder, refs (in one
update-ref transaction) and worktree indexes before anything reads or
creates the new folder; the server also moves every registered paper at
startup and when one is added. Settings from .latex-review.json are
copied once and the file is left untouched. Browser keys move in a
module each web entry point imports first.

The engine's own LICENSE and its separate notices entry go (same MIT
license and author as Papilot), as does engine/.github, which GitHub
never ran. The example paper drops its .latex-review.json and its
preview is rebuilt for the reworded sentence.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-11T15:40:01.816620Z 3118b50 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7eb31f7700

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread engine/src/web/legacy-storage.ts Outdated
Comment on lines +6 to +7
export function moveLegacyStorage(storage: Storage | undefined = globalThis.localStorage) {
try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Read localStorage inside the migration's try block

When browser policy blocks storage access, reading globalThis.localStorage itself can throw a SecurityError. Default arguments are evaluated before entering the function, so the surrounding try does not catch this failure. Because each web entry point now imports this module and immediately calls moveLegacyStorage(), blocked storage prevents the entire workspace or review viewer from loading instead of allowing the existing storage fallbacks to operate. Resolve the default storage object inside the protected block.

Useful? React with 👍 / 👎.

Comment thread engine/src/core/legacy-state.ts Outdated
const common = commonDir(gitDir);
moveRefs(git, refs);
if (!exists(path.join(common, FOLDER))) return;
moveFolder(path.join(common, FOLDER), path.join(common, folder), false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Migrate the build paths retained by published comparisons

For an existing review with additional effect locations that have not yet been expanded, renaming the state directory leaves its saved rounds/.../places.json pointing to PDFs under .git/latex-review/cache/builds. engine/src/render/round.ts stores absolute build paths there, and Publisher.more() checks those paths before rendering additional locations, so expanding them after upgrading fails with “The builds of this round were removed” even though the PDFs were moved intact. Recompiling the manuscript does not update an existing round's places.json; migrate these retained paths or resolve them against the new state directory when reading them.

Useful? React with 👍 / 👎.

6b5e165 committed the whole file with CRLF before .gitattributes
(text=auto eol=lf) existed, and Git leaves a file whose committed
version already contains CR unnormalized, so later edits mixed LF lines
into it. It was the only file in the repository with CR. Content is
unchanged (git diff --ignore-cr-at-eol is empty); from now on
.gitattributes keeps it LF.
Importing no longer reads .latex-review.json itself, so its two error messages are gone and the i18n check reported their translations as unused.
Rounds keep the builds they compare in places.json, and failed jobs keep
their log, as absolute paths into the state folder. Expanding a round's
further places after the move failed with "The builds of this round were
removed". Those paths now point at the new folder before it moves, by
replacing only JSON strings that start with the folder, so a move that
stops halfway is simply done again. On a copy of a real thesis (537
refs, 24 places.json, 19 job logs, 56 worktree indexes) the whole move
takes 1.7 s.

Reading localStorage itself throws where the browser blocks storage; the
default argument was evaluated outside the try, so the page would not
load. The storage is now looked up inside it.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 8d4a8bf39f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

On Windows fs.realpathSync keeps 8.3 short names (RUNNER~1), while the engine's realPath expands them, and stored build paths use native separators.
A review found the move unsafe in several cases:

- A linked worktree added as a paper keeps its whole state in its own
  Git directory. It was skipped when the main checkout had no earlier
  folder, and could be deleted as a "disposable" index when both names
  existed. Every Git directory now moves the same way, and nothing is
  ever deleted.
- Cached builds, their SyncTeX, rounds and jobs record absolute paths
  into the folder, and Papilot names a manuscript build by its PDF's
  path, so notes find their earlier PDF by it. SyncTeX cannot be
  rewritten to a path of another length. Instead of rewriting some
  records, the move leaves a link (a junction on Windows) under the
  former name: every earlier path stays valid, cached PDFs are reused
  and notes keep their builds. cachedPdf accepts a PDF reached through
  the link.
- A review server of the earlier version may still run after an
  update. Elsewhere it keeps working through the link until Papilot
  replaces it; on Windows its open files keep the folder from moving,
  so Papilot stops it first and waits until it has exited.
- Settings that cannot be read, and an unusable .latex-review.json,
  are reported again instead of silently falling back to detection,
  and messages name the settings file where it really is.
- Once nothing is left to move, starting Papilot checks a few paths
  without running Git; empty ref folders Git leaves are removed.

Papilot uses the engine's REFS, and opening a folder runs one Git
command fewer.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9b52e3e57

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread engine/src/core/legacy-state.ts Outdated
Comment on lines +31 to +32
for (const dir of [common, ...(lstat(worktrees)?.isDirectory() ? fs.readdirSync(worktrees).map((name) => path.join(worktrees, name)) : [])])
moveFolder(path.join(dir, FOLDER), path.join(dir, folder));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop legacy servers for every state directory being moved

On Windows, opening a linked-worktree paper can fail if an earlier review server is still running for the main checkout or another linked worktree. moveLegacyStates() stops only the server belonging to the requested root, but this loop also renames the main checkout's state and every linked worktree's state. An open database in any of those other directories makes moveFolder() throw, preventing the requested paper from opening even after its own server has stopped. Stop the legacy servers for all directories being migrated, or restrict folder migration to the requested Git directory.

Useful? React with 👍 / 👎.

Opening one paper also moves the folders of the repository's other papers. On Windows an earlier server of another paper can hold its files; that folder now moves when its own paper opens, and only the opened paper's own folder must move.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 3118b50a6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cu1ch3n
cu1ch3n merged commit 4cde974 into main Nov 11, 2026
12 checks passed
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.

1 participant