The assumptions section is explicitly labelled "technical, free to change",
and it held a requirement that AC3 and a mutant already test as a fact. Read
literally, it invited splitting the write in two — reopening the very window
in which markers move. The point now states the opposite: everything else in
that section is free, this one is normative and lives in section 8.3.
Issue: #220
User-Visible: no
M1: the spec now carries the touch classification TOUCH-SUPPORT.md asks every
editor feature for — "Touch editor: not exposed", with the reason it is a
decision rather than an omission.
M2: the first draft denied adding a config field in one section while planning
to store an anchor in settings in another. Resolved by dropping the anchor:
reordering materialises the placement that was implicit, giving those markers
an explicit space in the same write. No new field, no schema change, and the
marker stays exactly where the user saw it.
Issue: #220
User-Visible: no
Written on the owner's product decisions of 2026-08-20: mouse only and only in
the editor modes, one warning about the positional `floor` from #210, no
keyboard alternative.
The spec carries the part that is easy to miss — the order of `config.spaces`
is not decoration. It feeds the marker placement fallback, the swipe
neighbour and the numeric `floor`, so reordering tabs must not move a single
marker. That is a named acceptance criterion with a mutant behind it.
Issue: #220
User-Visible: no
Import of a backup holding PDF attachments: the content resolver parses a url
as a url, and the three mutants guarding it are registered. The user-visible
change is documented in 4a84734, which carries both changelog entries — this
merge adds no behaviour of its own.
Code review r2 green (docs/reviews/CODE-REVIEW-225-r2.md). The third pass was
a rebase over #226, not a fix — owner arbitration on the review-4 the cycle
counter raised for it (PROCESS.md §4; counter defect filed as #227).
Issue: #225
User-Visible: no
Review CODE-REVIEW-225-r1.
M1: urlsplit(url).path was trusted even when the url carried a scheme or an
authority, so "https://evil.example/houseplan_files/files/m1/doc.pdf"
resolved onto a local file while _looks_internal kept calling it external —
the mirror image of the inconsistency this resolver exists to prevent. Only a
same-document reference is resolved by its path now.
M2: the three mutants the spec described are registered in
scripts/mutation-gate.mjs instead of living as a one-off manual run. The
traversal entry drops both structural checks at once on purpose: taken one at
a time the defence is layered (sanitize_marker_id turns ".." into "misc") and
the mutant would be equivalent — established by running it.
Issue: #225
User-Visible: no
A backup holding a PDF attachment could not be imported back: legacy links
carry a cache-buster (".../files/m1/doc.pdf?v=1783170649"), and the resolver
compared the raw tail with its sanitized form, so the query made the name
differ from itself. The reference then read as internal by prefix and
non-canonical by name, which is exactly the combination _content_state must
refuse — every such document failed with invalid_content.
Parse the url as a url: the path addresses the file, the query and the
fragment address the transfer. Path segments keep doing the guarding, so
dropping the query cannot widen what a segment is allowed to be.
Issue: #225
User-Visible: yes