Skip to content

Per-file configuration staleness query; sanitize() records disk facts only - #18

Merged
ShadobaDev merged 10 commits into
mainfrom
feature/config-staleness-query
Nov 10, 2026
Merged

ShadobaDev merged 10 commits into
mainfrom
feature/config-staleness-query

Conversation

@ShadobaDev

Copy link
Copy Markdown
Owner

What changed and why

Whether a file is out of sync with the settings was a status that sanitize() wrote and a consumer had
to re-run to refresh. It is now a query, so a consumer can show the effect of a settings change at once,
on every repaint, without touching the disk.

  • Breaking — ProjectEditor::sanitize() records disk facts only. It takes no arguments and no longer
    writes FileStatus::Desynchronized. Ask ProjectItem::detectFileStaleness() which files are out of
    sync, and detectStaleness() whether the project needs a render. replaceInputFile() and
    mergeFileScan() no longer mark the slices either. Desynchronized stays in the enum, as a display
    value. The version goes to 0.7.0.
  • ProjectItem::detectFileStaleness() says, for each input and output, which setting put it out of
    sync since the render: a canvas profile, the page order, an unrendered page, the output profile, or the
    grade and overlays. It reads no file, and it accepts any canvas-profile list, such as one still being
    edited.
  • sanitize()'s disk pass in three parts, so a consumer can check files on its own threads:
    diskCheckRequests(), the thread-safe static checkOnDisk(), and applyDiskChecks(). A result is
    ignored when the project no longer has the file, or when a render has recorded a new hash for it since.
  • The render hashes each input as it reads it (AppliedCanvasProfile::sha256), so recording a render
    reads no file. The recorded hash is that of the content rendered.
  • Files are read through fread with a 1 MiB buffer. With MSVC, std::ifstream read a Google Drive
    folder at about 25 MB/s, whatever its buffer.
  • WorkspaceEditor::metaChanges(before, after) says what a workspace-level step changed, so a
    consumer can show what an undo touched.
  • Build: dist-* presets for Linux and MSVC that skip the tests.

Verification

  • MinGW Release (-Werror) and MSVC Release: 398/398 tests.
  • Linux coverage: 434/434 tests (fault-injection included), 100% of lines, 93.0% of branches.
  • Golden render (18 pages, no profile, PNG): 60 slices, byte-identical to the baseline taken before the
    work.

🤖 Generated with Claude Code

ShadobaDev and others added 10 commits November 8, 2026 02:13
- ProjectItem::detectFileStaleness() says, for each input and output, which
  configuration axis puts it out of sync: canvas profile, composition,
  an unrendered page, output profile, processing steps
- Pure and built on detectStaleness(): it touches no file and accepts any
  canvas-profile list, so a consumer can judge a palette before committing it

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

- sanitize() takes no arguments and no longer writes Desynchronized: what a
  configuration change put out of sync comes from detectFileStaleness(),
  whether to render from detectStaleness()
- replaceInputFile() and mergeFileScan() no longer mark the slices; a Pending
  or removed page is what the query reports
- CLI project status reads DESYNC and up-to-date from the queries
- Version 0.7.0: sanitize()'s signature changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- diskCheckRequests() lists what to look at, checkOnDisk() looks at one file
  and is safe on any thread, applyDiskChecks() sets the statuses from the
  results by path, ignoring any for a file the project no longer has
- sanitize() is the three in sequence, with unchanged rules

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

- DiskCheckRequest and DiskCheck carry the hash recorded when the check was
  asked for; applyDiskChecks() ignores a result whose record has changed since,
  so a result measured before a render cannot mark the new slice modified

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The strip builder hashes a page right after reading it, on the render's
thread, into the new AppliedCanvasProfile::sha256.
ProjectEditor::applyProcessingResults() takes input hashes from the
outcome and reads no file, so a consumer can record a render on its UI
thread; the recorded hash is that of the content rendered. An input with
no hash in the outcome becomes FileStatus::Error with InputHashFailed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
std::ifstream read Google Drive at about 25 MB/s with MSVC, whatever
its buffer, so hashing a chapter's files took ten seconds and slowed
every other read of the drive meanwhile. A new internal FileReader
(fread, 1 MiB buffer, wide path on Windows) reads at the drive's own
speed; FileMetaData::computeFileSha256() and the workspace packager
read through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WorkspaceEditor::metaChanges(before, after) reads two snapshotMeta()
strings and returns MetaChanges: the canvas profiles edited, added or
removed, those whose templates alone changed, the output profiles, and
the renamed projects. A consumer can show what an undo touched without
reading the snapshot, whose format stays the library's.

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

FileReader reads through fread, and glibc's stdio reaches the read system
call past the exported read(), so the hash test armed a wrapper nothing
called: the harness now wraps fread. Its counters are never destroyed,
since libgcov still calls fread while the program exits. The
metaChanges test also removes an output profile, the one case no test
reached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ShadobaDev
ShadobaDev merged commit f01c5ba into main Nov 10, 2026
5 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