Skip to content

fix: integrate 22 reviewed bug fixes with combined validation - #186

Merged
DWAA1660 merged 59 commits into
AlienTechSoftware:mainfrom
DWAA1660:chore/pr-audit-20261112
Nov 12, 2026
Merged

DWAA1660 merged 59 commits into
AlienTechSoftware:mainfrom
DWAA1660:chore/pr-audit-20261112

Conversation

@DWAA1660

@DWAA1660 DWAA1660 commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Integrates 22 reviewed fix/test PRs into current main, preserving their original commits. The fixes cover Unicode crashes, CSV and Markdown round trips, visible-text search, attachment ownership, page-size protection, source editing, external-notebook search, image previews, ink history, image resizing, page titles, typing history, search shortcuts, and starting text on a new page.

Included: #118, #119, #120, #121, #122, #123, #140, #141, #142, #143, #144, #145, #146, #151, #175, #176, #179, #180, #181, #183, #184, #185.

Conflicting test insertions retain every regression. Removed the obsolete find_raw helper after the combined parser changes removed its last callers. No CI workflows or repository protections were changed by this PR.

Validation on final head 183f67bb49bd03dfae27bc2eef4de11170eb5d4e:

  • Local cargo xtask ci: 1,055 tests passed, zero failed, three ignored; all lint/static/demo checks passed.
  • Local cargo build --workspace --locked: passed on Windows.
  • GitHub Linux: 1,056 tests passed; Windows: 1,055; macOS: 1,057. Zero failures and three ignored per platform.
  • All nine GitHub checks passed, including the required CI summary, WASM build, formatting, Clippy, static checks, and coverage.
  • Coverage: 85.8% overall. The non-blocking store warning (90.5% baseline versus 87.3% measured) was reviewed; baseline unchanged.
  • Superseded original-PR CI runs were cancelled to free runner capacity; the complete combined validation ran successfully on this final head.

Merged as edb5cbe8b47ba99c65c6b558b722903fc9430cdd. Verified all 22 original PRs are marked MERGED and every reviewed head is in main. Local main was fast-forwarded to the same commit and is clean. Maintainer edits were enabled while the PR was open.

Five PRs remain outside this integration with existing findings: #96 is a draft with failing voice checks; #174 can create reserved filenames; #177 and #178 need browser virtual-filesystem support; #182 applies the wrong UTC offset to dates in another daylight-saving period. Detailed reproductions are on those PRs. PR #187 merged independently before this integration and was retained as part of current main.

DWAA1660 and others added 30 commits November 12, 2026 10:12
`resolve_in` checked for the `notecraft:` scheme by slicing the link's
first ten bytes. A link such as `../日本語.txt` has a character across
byte 10, so the slice panicked, and a Ctrl+click on such a link took the
window down (AlienTechSoftware#102). The prefix is now read with `str::get`, which returns
nothing there instead of panicking.

Fixes AlienTechSoftware#102

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`saves_asked_for_meanwhile_write_only_the_newest_text` slept 50 ms after
the first save and assumed the worker had picked it up by then. Under a
loaded parallel run it sometimes had not, so all three saves were rightly
made as one and the test failed (AlienTechSoftware#116).

The first write now says when it has begun and holds until the later
saves are queued, so the interleaving is certain. The test also checks
that the second write answers for both saves and nothing is left in
flight.

Fixes AlienTechSoftware#116

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`csv::to_table` ran every cell through the inline Markdown parser, so a
spreadsheet value such as `*literal*` came back as an italic `literal`
and `[a](b)` as a link. Writing the table out again lost the characters
(AlienTechSoftware#110). A cell is now one plain span holding its value as written.

Fixes AlienTechSoftware#110

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CSV reader skipped every line whose one cell was blank, which also
dropped a blank row of a one-column table, so every row under it moved
up (AlienTechSoftware#112). The writer now quotes a blank cell that is alone on its row,
and the reader keeps a line that held a quoted cell. Lines with nothing
on them are still skipped.

Fixes AlienTechSoftware#112

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`save_body` capped only the body at MAX_PAGE_BYTES, while `load_page`
caps the whole file. A body at the limit was saved, but the head round
it pushed the file over, so the page could not be opened again (AlienTechSoftware#113).

The cap is now on the whole page file in `write_atomic`, which every
writer of a page file goes through, and the save is refused before the
current file is replaced.

Fixes AlienTechSoftware#113

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`html::strip_tags` put a space after every tag, so `for<b>mat</b>` came
out as `for mat` and search could not find `format` on an HTML page
(AlienTechSoftware#105). Inline formatting tags now leave nothing behind; block tags,
line breaks and cells still separate words. A `>` outside a tag is now
kept as text.

Fixes AlienTechSoftware#105

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Search read a CMGFM page as its Markdown source, so `Hello world` did not
find `Hello **world**`, while the same page in HTML was found (AlienTechSoftware#104). A
Markdown page is now read into blocks, written as the HTML the same page
would be, and stripped of tags exactly as an HTML page is, so both
formats are searched the same way.

Fixes AlienTechSoftware#104

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A code block whose text had a line of three backticks was written inside
a three-backtick fence, so that line closed the block early and the rest
became a paragraph and an empty code block (AlienTechSoftware#106). The HTML to Markdown
conversion wrote the same colliding fence.

Both writers now fence code with one more backtick than the longest run
starting one of its lines, and the parser follows CommonMark: only a run
at least as long as the opening fence, with nothing after it, closes it.

Fixes AlienTechSoftware#106

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Inline code was always written between single backticks, and the reader
closed it at the next backtick, so code holding one lost its boundary
and the rest became text (AlienTechSoftware#107). The HTML to Markdown conversion wrote
the same single backticks round <code>.

The reader now follows CommonMark: a code span closes at the next run of
exactly as many backticks as opened it, and one space each side is
padding when both are there. Both writers use a delimiter one longer
than any run inside, and pad when the code starts or ends with a
backtick or a space.

Fixes AlienTechSoftware#107

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reader ended a link's address at the first `)`, so
`[file](https://example.test/a(b).pdf)` linked to `.../a(b` and showed
`.pdf)` as text (AlienTechSoftware#108). It now pairs parentheses inside the address and
skips `\(` and `\)`. The Markdown writer and the HTML to Markdown
conversion write an address with balanced parentheses as it is, and
escape them when they do not pair up.

The XSS assertion in html_escapes_everything_that_matters now checks the
escaped quote itself: the address keeps its balanced `(1)` now, so the
old substring test matched the attribute's own closing quote.

Fixes AlienTechSoftware#108

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A resized picture is kept as an <img> tag in CMGFM, and its alt text and
address were written into it unescaped. An alt text such as `a"b` ended
the attribute early and came back as `a` (AlienTechSoftware#109). The HTML to Markdown
conversion, which unescapes the attributes it reads, wrote the same
broken tag.

Both writers now escape the values, and the reader of that tag unescapes
them.

Fixes AlienTechSoftware#109

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Any `<file>.png` or `<file>.svg` beside an attachment `<file>` was taken
for its generated icon: hidden from the attachment list and deleted with
the attachment, even when the user had attached it as a picture of its
own (AlienTechSoftware#103). `ensure_icon` could also write over such a file.

A generated icon is now recorded in the page's `.notecraft/icons` when it
is made, and only a recorded icon, or one the page shows as the picture
of an attachment card (how icons made before this change are known), is
hidden and removed. `ensure_icon` never writes over a user's file.

Fixes AlienTechSoftware#103

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`svg::is_ink` looked at the first 4096 bytes with a plain slice, which
panicked when a character crossed byte 4096. The page scan reads such a
head from every SVG beside a page, so an ordinary picture with a long
comment took the window down while its page opened (AlienTechSoftware#126). The head is
now cut with `floor_char_boundary`.

Fixes AlienTechSoftware#126

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The code view shows at most MAX_SHOWN bytes of an Office document's
text, and cut it with a plain `truncate`, which panics when a character
crosses the limit. Picking such a DOCX in the code view took the window
down (AlienTechSoftware#125). The text is now cut with `floor_char_boundary`, and the view
still says it was cut.

Fixes AlienTechSoftware#125

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The code view reads at most MAX_SHOWN bytes of a file and adds a notice
when it cuts one. The cut text stayed editable, so one typed character
wrote the cut text, notice and all, over the whole file and lost the
rest of it (AlienTechSoftware#124). A file that was cut is now shown read-only, and the
header says so.

Fixes AlienTechSoftware#124

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`search.query`, behind the window's Search all pages, searched only the
notebooks folder, so a notebook opened from elsewhere could be read but
never found in (AlienTechSoftware#127). Search now also walks every notebook the session
has open from elsewhere, finds a page once however it is reached, and
applies the limit to all of them together.

Fixes AlienTechSoftware#127

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The code view gave egui each picture as `bytes://source-view/<name>`.
egui keeps a picture by that name, so after viewing one page's
`assets/a.png`, another page's `assets/a.png` showed the first page's
picture, and a replaced picture kept showing the old one (AlienTechSoftware#135).

The name now carries the file's whole path, its size and its time, as
the page view's pictures already do, for pictures and for document icons.

Fixes AlienTechSoftware#135

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading `\)` as a quoted parenthesis broke links written before quoting
existed whose address is a Windows folder, `[Folder](C:\Notes\)`: the
last backslash belongs to the path, so no end was found and the link
became text (structure_on_save failed on Windows CI). The address is now
read with quoting first, and with the backslashes as they stand when
that finds no end or one that takes in the words after the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Undo on a page just opened, with nothing done, took away a stroke that
had been saved with the page: with no change to go back to, the pad fell
back to popping the drawing's last stroke (AlienTechSoftware#156). And a stroke taken back
could never be put back: the pad kept no redo steps, and Redo only knew
the page's text history (AlienTechSoftware#155).

The pad now takes back only changes made since the page was opened, and
keeps what it took back for redo until a new change starts another
branch. The window remembers whether each Undo went to the ink, the page
or both, and Redo goes back the same way; the Undo and Redo buttons
count the ink too.

Fixes AlienTechSoftware#155
Fixes AlienTechSoftware#156

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clearing a page's title left the title area blank, but nothing was
saved: the window only renamed a page to a non-empty title, and the
store refused an empty one. The tree kept the old title and it came back
when the page was opened again (AlienTechSoftware#132).

A page may now be given an empty title, which the store writes as an
empty title key, the same state a new untitled page is in, leaving the
page's heading alone. The window commits a cleared title box on a page
that had a title, and then shows the page as untitled. Notebooks and
sections still need a title.

Fixes AlienTechSoftware#132

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DWAA1660 and others added 29 commits November 12, 2026 11:58
`History::record` dropped the redo steps and then let new typing fold
into the step it was on. After an Undo, that is the state Undo had just
restored: typing in the same block within the pause replaced it, so the
next Undo went past it and the restored state was lost (AlienTechSoftware#160).

A step recorded while there were redo steps now always starts a new
step. Ordinary runs of typing still fold into one.

Fixes AlienTechSoftware#160

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the caret in a page, Ctrl+F did nothing and the words typed next,
meant as a search, were written into the note (AlienTechSoftware#134). Ctrl+F, and
Ctrl+E as OneNote has it, are now taken before the page sees them and
put the keyboard in the Search all pages box. The code view keeps its
own Ctrl+F Find while it is open.

Fixes AlienTechSoftware#134

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

# Conflicts:
#	crates/formats/src/render.rs
…-audit-20261112

# Conflicts:
#	crates/formats/src/render.rs
…-audit-20261112

# Conflicts:
#	crates/formats/src/render.rs
The keyboard's Ctrl+Y and Ctrl+Shift+Z still called the page history's
step directly, so a stroke taken back with Ctrl+Z could only be put back
with the Redo button. They now go through the same redo as the button.

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

# Conflicts:
#	crates/ui-egui/src/codeview.rs
…-audit-20261112

# Conflicts:
#	crates/ui-egui/src/codeview.rs
A new page's box holds only its date and is drawn tall, like OneNote's
first note area, but nothing under the date took a click: the space
looked ready for writing, no caret appeared, and what was typed was lost
(AlienTechSoftware#148). A click there now adds a line under the date, in the same box,
and puts the caret on it.

Fixes AlienTechSoftware#148

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

# Conflicts:
#	crates/ui-egui/tests/ui.rs
@DWAA1660
DWAA1660 merged commit edb5cbe into AlienTechSoftware:main Nov 12, 2026
9 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.

2 participants