Added
-
fix.fragment_wrong_path— a link whose#fragmentis real but has moved
to another document (RSC-012/opf.content_document.dangling_fragment,
ConfirmNeeded). If exactly one document in the book defines that anchor, the
path is written in front of the fragment, relative to the referring document;
where the anchor turns out to be in the referring document itself, the link
becomes a plain same-document#fragment.On real books this is an editor splitting a file at a page break and leaving a
footnote link and its return link as bare fragments pointing into the wrong
half. Third member of the family besidefix.reference_wrong_pathand
fix.ncx_src_wrong_path, sharing their machinery and their discipline:
exactly one answer, or decline.It declines an anchor defined in several documents (which one the link meant
is a guess), an anchor defined nowhere (only "drop the fragment" is available,
and that loses the author's target), a target outside the reading order, and a
reference not visible as a whole quoted attribute value. -
--format json'ssummaryreports every counter it has a concept of.
Seven fields appear:proposed, andwarnings_before/warnings_after,
infos_before/infos_after,usages_before/usages_after.Under
--dry-runthe summary used to sayapplied: 0, skipped: 0while every
item carried"outcome": "proposed"— so the summary and the items disagreed
about the size of the run, and a consumer asking the summary how many fixes
there were got zero while two sat initems. Every number was true and the
document misled. The identity a consumer may now rely on is
applied + skipped + proposed == items.len().The severity counters are the same defect one field over. Three fixers here
dispatch onusageorwarningfindings, so a run can clear real work while
errors_before/errors_afterdo not move at all — and the summary described
that as no change whatsoever.revertedstays absent rather than zero: a build
that cannot revert has no concept of the value, and0would claim no revert
happened where the truth is that none could.The wasm binding's
Summarygains the same seven fields, itsskipped
remaining zero because the browser never declines.
Changed
-
The envelope claims convention
0.5. The stability key is an assertion
about this crate, not about its detector: it moves when epubsana implements a
convention release, and the seven counters above are that release. -
fix.non_preferred_media_typetakes the replacement from the finding
instead of from a table of its own. epubveri has named the preferred media
type inparams[1]since 0.12.3; this crate went on consulting a five-row
table written before that existed, which made it a second answer to a question
the detector was already answering.It closes a hole the table could not see. Where epubveri declines to name a
replacement — because the resource's own signature rules the candidate out, an
OTTO(CFF) font declaredapplication/x-font-ttfbeing the shape — a
table-driven fixer renamed it anyway. No book on the 474-book shelf carries
that shape (121application/vnd.ms-opentype+ 285application/x-font-ttf
declarations, none contradicted by its own bytes), so this closes a hole
rather than repairing damage.Two declines are new and deliberate: a finding that names no replacement, and
two findings about one declared type that name different replacements —
which epubveri 0.14.1 can now legitimately produce for
application/font-sfnt, because it answers that row from each file's own
signature. The fix renames per declared type across a manifest, so it cannot
honour both and proposes neither. -
application/font-sfntis now repaired where the detector decides it. It
was declined outright because SFNT is the container TrueType and OpenType
share and EPUB 3.3 lists the spelling on both rows — the name cannot say
which the file is. epubveri 0.14.1 answers it from the font's own signature
(onlyfont/otfadmitsOTTO), on its side of the boundary, where deciding
what the defect is belongs. This crate still never opens a font. Zero books on
the shelf carry the spelling, so nothing here moves today. -
The envelope states epubsana's own convention version. epubveri 0.13.x
hard-coded its own key into every envelope built through
Envelope::for_tool, so this crate's--format jsonwas claiming epubveri's
convention version; it happened to be right, both beingv0.4. 0.14.0 made
the key a required parameter. epubsana claims"0.4"and will move it
when it implements v0.5.0, not when its dependency does. No output changes.
Dependencies
- epubveri floor raised to
0.14(from0.13.7) — a capability floor: the
paramscontract the OPF-090 fixer now reads (an absentparams[1]meaning
decline, and only a real media type ever appearing in it) does not exist
below it. Measured across the boundary on 474 books: the whole-shelf plan
digest and the entire regression audit are byte-identical — 194 books planned,
2,337 proposals, errors 40,584 → 15,719, 73 books fully valid, zero
regressions at any severity.
Documentation
-
fix.navdoc_empty_nav's safety argument was overstated in 0.14.0 and is
corrected. That entry says the finding cannot say which<ol>it means. Only
paramscannot:navdoc.ol.emptyis emitted with anelement_path, which on
every shelf book names the exact node. The fixer does not read it — a choice,
not an absence.What actually makes its file dispatch safe is a subset property: for a
typed<nav>whose single element child is an<ol>, epubveri always reaches
the check that reports an empty list, so every node this fixer selects is one
epubveri reported. No code changed and no behaviour was wrong; the reasoning
was, and it is the reasoning a future session would rely on.
Full notes: CHANGELOG.md. Also on crates.io.