Skip to content

feat(core): let the catalog write app preferences outside document undo#19

Merged
nmrtist merged 1 commit into
mainfrom
feat/app-preference-property-storage
Jul 26, 2026
Merged

feat(core): let the catalog write app preferences outside document undo#19
nmrtist merged 1 commit into
mainfrom
feat/app-preference-property-storage

Conversation

@nmrtist

@nmrtist nmrtist commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

The property catalog could only write the document. An application preference
has no Action, so the seam reported a successful edit and wrote nothing at
all — the exact silent failure the catalog exists to remove. Closing that is the
point of this change; raster export resolution is the first preference to go
through it.

What now holds

  • One in-memory Settings on PlotxApp is the source of truth. The file is a
    flush target reached only through persist_settings, which reports a failed
    write instead of swallowing it. Writing is crate-private, so no caller can
    leave the live value and the file disagreeing.
  • A commit carries a document action, application preferences, or neither —
    never a silently empty one. A request that would cross both storages is
    refused while planning, not split while executing.
  • Editing a preference adds no undo entry, leaves the document clean, and does
    not advance the automation revision.
  • The raster export bound (72–1200 dpi) has one home. Preferences, the export
    dialog and the property schema all read it from there. An out-of-range value
    is refused naming both the value that was set and the actual bound, never
    quietly clamped.
  • The Preferences draft stays an in-progress edit rather than a second source of
    truth, and is realigned before every flush, so its debounce cannot overwrite
    an edit made elsewhere.

Adding another preference

A provider module, one catalog registration, one presentation entry. The
provider selects its storage on the transaction; the planner still chooses
nothing by scope, and adding a branch there for a new setting is out of bounds.

Two traps worth knowing before you do. persist_settings reports a failed write
through the status line, so it has to run after any optimistic success message
on the same path or the diagnostic is destroyed. And a preference that reaches
disk only because some later call flushes the whole struct as a side effect is
one reordering away from silently not persisting at all — flush it explicitly.

Deliberately not changed

The application target is not enumerated as an automation resource, so
properties.set cannot address this preference yet. The shared property-write
descriptor is statically marked reversible; advertising a non-undoing,
disk-writing target through it would make that metadata untrue. The effect model
has to grow first, and a half-answer here would be worse than the gap.

AGENTS.md is unchanged. Both rules this work suggested turned out to be
enforceable by machine instead — one by the planning guard and its test, the
other by narrowing write visibility — and that file is read by every session, so
a rule that restates a compiler or a test is a net loss.

Validation

  • cargo pr-check: all seven gates, both backend configurations.
  • Every new test was run against a deliberately broken implementation first and
    its failure observed, including the two halves that matter most: removing the
    preferences arm from the commit turns four of the six export-resolution tests
    red, and reordering the zoom flush ahead of its status line turns the zoom
    test red.
  • The round trip is exercised on a real path: setting the property, saving and
    reloading through a temporary settings file, then confirming the next export
    dialog opens at the stored resolution. No test writes the real user settings.
  • Failure path covered: when the write cannot land, the value still applies for
    the session and the status line says so.
  • npm run build from docs/: 67 pages, no warnings.

The property catalog could only write the document. An application
preference has no Action, so the seam reported a successful edit and
wrote nothing at all — the exact silent failure the catalog exists to
remove.

What now holds:

- One in-memory Settings on PlotxApp is the source of truth; the file is
  a flush target reached only through persist_settings, which reports a
  failed write instead of swallowing it. Writing is crate-private, so a
  caller cannot leave the live value and the file disagreeing.
- A commit carries a document action, application preferences, or
  neither — never a silently empty one. A request that would cross both
  storages is refused while planning, not split while executing.
- Editing a preference adds no undo entry, leaves the document clean,
  and does not advance the automation revision.
- The raster export bound (72–1200 dpi) has one home; Preferences, the
  export dialog and the property schema read it from there. An
  out-of-range value is refused naming both the value and the bound,
  never quietly clamped.

Adding another preference means a provider module, one catalog
registration and one presentation entry; it selects its storage on the
transaction, and the planner still chooses nothing by scope.

The Preferences draft stays an in-progress edit rather than a second
source of truth, and is realigned before every flush so its debounce
cannot overwrite an edit made elsewhere.

Deferred: the application target is not enumerated as an automation
resource, so properties.set cannot address this preference yet. The
shared property-write descriptor is statically marked reversible, and
advertising a non-undoing, disk-writing target through it would make
that metadata untrue; the effect model has to grow first.
@nmrtist
nmrtist merged commit 59a7eac into main Jul 26, 2026
11 checks passed
@nmrtist
nmrtist deleted the feat/app-preference-property-storage branch July 26, 2026 08:29
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant