Skip to content

Carry links and bookmarks over, and add sanitize and flatten - #4

Merged
tannevaled merged 1 commit into
mainfrom
safety-and-structure
Aug 25, 2026
Merged

Carry links and bookmarks over, and add sanitize and flatten#4
tannevaled merged 1 commit into
mainfrom
safety-and-structure

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

This package rebuilds a file rather than editing it, which quietly cost two
things and quietly kept a third it should not have.

Links were copied as they stood. A link pointing at page three of the source
still pointed at the source's own page object — which the copy then followed,
dragging that file's whole page tree into a file that was meant to hold one
page. Destinations are now remapped: a link or a bookmark is pointed at the
page it became here, in whatever shape the file wrote it — an array, a
dictionary, a name in either of the two places a name tree may live. That
needed pages to be numbered before they are written, since what goes on one may
name another.

Bookmarks were dropped altogether, so a merge lost every one. They are now
carried over from each source document in turn, and a bookmark whose target was
removed goes with it — but one that led nowhere in the source stays, without a
destination. That distinction matters: 7% of the corpus's bookmarks are already
broken where they are, and dropping them would have been reported as this
package losing them.

Sanitize removes what runs rather than shows: page and annotation actions,
JavaScript, launching, form submission, and the annotation types that exist to
play or embed something. It also drops /AF, which is how a page carries a file
with it in PDF 2.0 — and how, in two corpus files, an embedded file survived a
catalogue this package had rebuilt from nothing. A link to the web is not
executable and stays. Flatten draws each annotation's own appearance where it
sits, honouring the state it says it is in and the matrix it says it has, and
then drops the annotations.

Measured on the corpus: 84 929 of 84 935 annotations and all 19 386 bookmarks
survive an identity write, no destination points outside the document it was
written into, and a sanitised file holds nothing executable. The four earlier
whole-corpus checks still hold.

One thing the campaign found and this does not fix: 355 files come out more
than three times their input, because a large dictionary has nowhere to be
compressed. Object streams in the writer are what that needs, and they are the
next thing.

Exact 100% statement coverage over the package and the command, go vet clean,
nine cross-compilation targets.

This package rebuilds a file rather than editing it, which quietly cost two
things and quietly kept a third it should not have.

Links were copied as they stood. A link pointing at page three of the source
still pointed at the source's own page object — which the copy then followed,
dragging that file's whole page tree into a file that was meant to hold one
page. Destinations are now remapped: a link or a bookmark is pointed at the
page it became here, in whatever shape the file wrote it — an array, a
dictionary, a name in either of the two places a name tree may live. That
needed pages to be numbered before they are written, since what goes on one may
name another.

Bookmarks were dropped altogether, so a merge lost every one. They are now
carried over from each source document in turn, and a bookmark whose target was
removed goes with it — but one that led nowhere in the source stays, without a
destination. That distinction matters: 7% of the corpus's bookmarks are already
broken where they are, and dropping them would have been reported as this
package losing them.

Sanitize removes what runs rather than shows: page and annotation actions,
JavaScript, launching, form submission, and the annotation types that exist to
play or embed something. It also drops /AF, which is how a page carries a file
with it in PDF 2.0 — and how, in two corpus files, an embedded file survived a
catalogue this package had rebuilt from nothing. A link to the web is not
executable and stays. Flatten draws each annotation's own appearance where it
sits, honouring the state it says it is in and the matrix it says it has, and
then drops the annotations.

Measured on the corpus: 84 929 of 84 935 annotations and all 19 386 bookmarks
survive an identity write, no destination points outside the document it was
written into, and a sanitised file holds nothing executable. The four earlier
whole-corpus checks still hold.

One thing the campaign found and this does not fix: 355 files come out more
than three times their input, because a large dictionary has nowhere to be
compressed. Object streams in the writer are what that needs, and they are the
next thing.

Exact 100% statement coverage over the package and the command, go vet clean,
nine cross-compilation targets.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 7765a89 into main Aug 25, 2026
1 check passed
@tannevaled
tannevaled deleted the safety-and-structure branch August 25, 2026 11:10
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