Repository navigation
layers: the optional content, and the hidden one every verb was revealing - #45
Merged
Merged
Conversation
…ling
Doc.Layers, SetLayerVisible, AddLayer and DropLayer, with `pdfops layers` over
them. This closes BentoPDF's pdf-layers.
⛔⛔ AND IT CLOSES A DISCLOSURE. Measured before the change, with a probe
written for the purpose: a one-page drawing with a layer switched OFF, run
through `pdfops watermark`, came back with no /OCProperties at all — the
content still marked as belonging to a layer, the layer object still reachable
through the page's own resources, and NOTHING left saying which layer was
hidden. So the hidden layer showed. A drawing distributed with an "internal
pricing" layer turned off revealed it to any verb at all. The witness test
asserts the VISIBILITY and not the presence of the layers, because a carry that
kept both and lost which was off would have the same consequence.
The layers are constructed on the way out rather than carried, which is what
lets them survive a reorder AND a merge. keepCatalogue refuses to merge two
catalogues because two forms whose fields are named the same cannot honestly
become one — but two drawings' layers can: a layer is its object, and two
layers named "Markup" are two layers.
What the file says about its own layers is obeyed: /BaseState OFF inverts the
question (hidden unless /ON names it, which is how an alternatives document is
built); /Locked is the document asking that a layer not be switched, and -hide
on one is refused; /D /Order is the nesting, and a string inside it is the
group's LABEL rather than a layer.
⛔ Dropping a HIDDEN layer is refused: what was drawn on it stays in the page
and stops being optional, so the hidden drawing becomes permanently VISIBLE.
And an ambiguous name is refused with the count, because a name is not an
identifier.
⛔ THREE DEFECTS THE TESTS FOUND IN MY OWN CODE, each invisible to the one
before it:
- the layer ceiling was checked on ENTRY to the walk rather than inside its
loop, so it bounded the recursion and not the list: one flat /Order of six
thousand layers passed it once and added all six thousand. The test that
lowered the ceiling to two and got six back is what found it.
- /Order was written FLAT, so every hierarchy was lost on the way out. The
test that read a nested order could not see it; only the round trip could.
- with the nesting written, a child added under a parent landed after an
unrelated layer and became ITS child, because the order is positional. The
insertion goes after the parent's own subtree now, and the reported list
and the written file share that one rule so the report cannot be a lie.
Four guards were removed as dead code a coverage gap found: an explicit test
for a group's string label, which `add` already refuses by type, and three
not-found returns the validation upstream makes unreachable.
100% statement coverage with zero uncovered blocks, go vet and gofmt clean.
Eight mutations caught, including the state this package was in before.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Doc.Layers,SetLayerVisible,AddLayerandDropLayer, withpdfops layersover them. This closes BentoPDF'spdf-layers.⛔⛔ And it closes a disclosure
Measured before the change, with a probe written for the purpose: a one-page
drawing with a layer switched off, run through
pdfops watermark, came backwith no
/OCPropertiesat all — the content still marked as belonging toa layer, the layer object still reachable through the page's own resources, and
nothing left saying which layer was hidden.
So the hidden layer showed. A drawing distributed with an "internal
pricing" layer turned off revealed it to any verb at all.
/OCPropertiesafter a watermarkThe witness test asserts the visibility, not the presence of the layers: a
carry that kept both and lost which was off would pass a test that counted
them, and would have exactly the same consequence.
What the file says about its own layers is obeyed
/BaseState OFFinverts the question — everything is hidden unless/ONnames it. A reader that only looked at/OFFwould report every layerof such a document as visible, and a drawing that ships with all its layers
off but one is exactly how an alternatives document is built;
/Lockedis the document asking that a layer not be switched, and-hideon one is refused: a drawing's dimension layer is what everythingelse is positioned against;
/D /Orderis the nesting, written back nested, and a string inside it isthe group's label rather than a layer.
⛔ Dropping a hidden layer is refused. What was drawn on it does not go with
it: the content stays in the page and stops being optional, so the hidden
drawing becomes permanently visible — the opposite of what somebody deleting
a layer called "internal pricing" expects.
⛔ A name is not an identifier. A drawing assembled from two others often
has two "Markup" layers, so an ambiguous name is refused with the count.
A merge keeps every source's layers, which
keepCataloguewould not: itrefuses to merge two catalogues because two forms whose fields are named the
same cannot honestly become one — but two drawings' layers can.
⛔ Three defects the tests found in my own code, each invisible to the one before
/Orderof six thousand layers passed it once and added all six thousand. The test that lowered the ceiling to two and got six back found it/Orderwas written flatFour guards were removed as dead code a coverage gap found: an explicit test
for a group's string label, which
addalready refuses by type, and threenot-found returns the validation upstream makes unreachable.
Checks
100 % statement coverage with zero uncovered blocks,
go vetandgofmtclean. Eight mutations caught, including the state this package was in
before.
🤖 Generated with Claude Code