The seventh tagged version of ethos-parser, and its fifth GitHub Release — 0.58.0 and 0.59.0 are tags with no release object, deliberately, because 0.60.0 descends from both. A PDF catalog's own /Outlines is read for the first time, and an ODF heading projects at the level its element declared.
Platforms
| Archive | Target | State |
|---|---|---|
ethos-parser-0.61.0-x86_64-unknown-linux-gnu.tar.gz |
Linux, x86-64 | verified |
ethos-parser-0.61.0-x86_64-pc-windows-msvc.tar.gz |
Windows, x86-64 | verified |
ethos-parser-0.61.0-aarch64-apple-darwin.tar.gz |
macOS, Apple silicon | verified |
ethos-parser-0.61.0-x86_64-apple-darwin.tar.gz |
macOS, Intel | verified |
All four come from one workflow run
(36033240012, 28m 8s), each
built and executed on the runner that built it.
Five files, not a zip. The four archives above and SHA256SUMS.txt, each attached separately,
so you download your own platform and the sums file and nothing else. The workflow's own output is
a single artifact named release-bundle, which GitHub serves as a zip — that is a convenience for
whoever attaches the files, not a shape a consumer wants. 0.60.0 shipped as the zip and could not
be repaired, which is why this one does not
(RELEASING.md §8).
verified means:
- built with the pinned Rust 1.88.0;
- executed on the runner that built it;
- its artifact digests over the gate corpus equal to every other runner's —
extractand
classifyon all eight gate documents, andmarkdown,htmlandgroundon six of them; the
two largest are compared throughextractandclassifyalone, so the comparison is 34 of the
40 rows a full one would hold.
SHA256SUMS.txt names every target's state in its header, above the digests, and carries one
bare digest line per archive. It exists only because every runner produced the same
fingerprint: the assembly refuses to write the file at all if any target's artifact digests
differ from the others'. The run's assembly step reports one fingerprint on all 4 runners and
4 artifact(s) assembled, every one verified across 4 runners. Nothing is published to crates.io,
npm or PyPI.
Install
Two downloads — your platform's archive and the sums file:
curl -fLO https://github.com/docushell/ethos-parser/releases/download/v0.61.0/SHA256SUMS.txt
curl -fLO https://github.com/docushell/ethos-parser/releases/download/v0.61.0/ethos-parser-0.61.0-aarch64-apple-darwin.tar.gz
shasum -a 256 -c SHA256SUMS.txt --ignore-missing
tar -xzf ethos-parser-0.61.0-aarch64-apple-darwin.tar.gz
./ethos-parser-0.61.0-aarch64-apple-darwin/ethos-parser --versionSubstitute your own target for aarch64-apple-darwin. On Linux the check is
sha256sum -c SHA256SUMS.txt --ignore-missing. On Windows the archive holds
ethos-parser.exe, so the last line is
.\ethos-parser-0.61.0-x86_64-pc-windows-msvc\ethos-parser.exe --version, and the digest check is
Get-FileHash compared against SHA256SUMS.txt rather than shasum.
--ignore-missing is what lets the check pass with only one of the four archives present; without
it the three you did not download are reported missing. The check also prints
WARNING: 1 line is improperly formatted — that is the blank line in the file's header, not a
failed digest. OK beside your archive, and exit status 0, is the result. -f makes curl fail
on an HTTP error instead of writing the error page to disk under the asset's own name.
The macOS binaries are not notarized. A copy downloaded through a browser is quarantined; once the
digest checks out, xattr -d com.apple.quarantine ethos-parser-0.61.0-*/ethos-parser clears it.
curl does not set the attribute.
What changed
Wire changes a 0.60.0 consumer sees:
- Schema versions move, and both are hard refusals in both directions.
REPRESENTATION_SCHEMA_VERSION0.6.0 → 0.7.0,EXTRACT_SCHEMA_VERSION0.4.0 → 0.5.0. This build
refuses a stored 0.60.0 representation or extract outright — "Refusing rather than
best-effort parsing an unknown shape" — and a 0.60.0 build refuses this one. Re-extract from the
source document; there is no migration path and deliberately so. - The representation carries an
outlinesarray. A new top-level record, besidetables— not
Nodes. On the PDF profilecapabilities.outlinesistrueandoutline_rulenames
outlines-v1; on the eight office profilescapabilities.outlinesis permanentlyfalseand
outline_rulecarriesnot-run-for-this-format, which is also whattext_box_rulecarries
there. A consumer assertingoutline_rule == "outlines-v1"across all nine profiles breaks. - Two office node attribute types gain
outline_level—OfficeParagraphAttributesand
OfficeOdfShapeAttributes, an optional integer, absent where the block stated no level. A
0.60.0 consumer deserializing office nodes withdeny_unknown_fieldsrejects it. markdown_ruleandhtml_rulemove tomarkdown-blocks-v10andhtml-blocks-v10. An ODF
<text:h>that declaredtext:outline-level="3"now projects as###and<h3>where it
projected as#and<h1>.text_box_ruleappears on the profile, namingadvance-over-font-envelope-v1. No box
changes shape — the field says what shape they always were.- Two new
coverage.structural_erasurescodes onethos.markdown.v1andethos.html.v1:
heading-level-unresolved-v1where an ODF heading stated no level, and
heading-level-unrepresentable-v1where it stated one past six. Both project as a paragraph, and
the code is what stops that flattening being silent. A consumer validating erasure codes against
a closed enumeration must add them. - Six new limitation codes can appear:
outlines-not-read,outline-absent,
outline-title-undecodable,outline-destination-unresolved,right-to-left-not-reordered,
document-metadata-not-read. Two are unconditional, not occasional:
document-metadata-not-readrides every representation and every classification across all nine
formats, andoutlines-not-readrides every artifact from the eight office profiles.
New:
- The PDF catalog's
/Outlinesis read. An outline is a hierarchy the author wrote down, so
it is consumed rather than inferred. Measured on the six gate documents that carry one:
2 273 entries, per-document 1251/433/347/160/69/13 at maximum declared depths 5/5/3/3/3/2,
zero unresolved destinations — and 69 titles (3.0%) absent rather than guessed, each holding
a byte in the range below. - An ODF
<text:h>projects at the level it declared. A stated level past six, and an absent
one, both project as a paragraph — ODF makes the attribute optional and the default lives in a
part these readers declare they did not open. Each case is counted, under the two codes above.
What it refuses, deliberately:
- An outline title is not quotable. A bookmark title is text no content stream painted, so it
has no native locator, and North Star #4 requires one on every node.locateand grounding both
readnodes. - A cycling
/First//Nextis refused by name, not followed or truncated. The depth is the
chain's own and is never renumbered. - No section end is emitted. An entry declares where a section begins. Two entries in this
corpus target a page before their predecessor's, where an inferred end would run backwards. - A title holding a byte in
0x80–0x9Fis absent and counted, not guessed — the 69 above.
That block is exactly where PDFDocEncoding, Latin-1 and Windows-1252 disagree, and the only table
in this tree is Windows-1252, which would renderBackup – Cryptographicas
Backup … Cryptographic. - No bidi algorithm is applied anywhere. A producer that resolved bidi draws Hebrew and Arabic
in visual order, so the run's text is the logical word reversed andchar_codescarries the
page's order beside it.right-to-left-not-reorderednow says so on the artifact of any document
that draws a scalar in one of three Unicode blocks — 1 of the 70 fixture PDFs — counting the
runs affected. It is a block test, not Unicode'sBidi_Class, so it over-declares slightly;
and it is emitted only by the PDF reader, so its absence from an office artifact says nothing
about that document. Text copied out of a viewer that preserves visual order matches this text; a
quote typed in logical order does not.
profile_sha256: sha256:78fcfe87e98e15faee5916b69a3dcf8d2e941ce7125c399015d5a7a9e250f7e6. The
full entry is in
CHANGELOG.md — its header
is frozen at the tag and was written before this Release existed, so it still says 0.61.0 carries
no release object.
If you build from source: main briefly carried an intermediate markdown-blocks-v10 /
html-blocks-v10 between d963edf and 51be844 that projected ODF heading levels without
counting the headings it flattened. Two commits in that window emit different bytes under the same
rule id. No tag, release or binary was ever cut from it; this release is 3bec4fa.
Known limits
The three gaps 0.60.0 named against another engine on a public benchmark are unchanged and still
open — reading order (the prescribed repair measures net −0.1042 over the four documents it
reaches), headings (a font-weight clause outside both of its bounds), and tables (a relaxation
that fabricates on five of eight gate documents).
Two more were settled this cycle without building anything. Neither is a refusal — nothing in
00-NORTH-STAR.md or 06-STEAL-REFUSE.md refuses either, and in this project's vocabulary REFUSE
means breaks a rule this project exists to keep:
- Left unbuilt on the number — form XObject text is not descended into. The broad case was
refuted by measurement: 47 of 208 documents carry one, but the text inside them totals
1 464 bytes across the whole corpus. A narrow case is real and unbuilt — 14 of 981
OmniDocBench documents are born-digital and produce an entirely empty artifact with the page
behind a form. It reopens on a redistributable fixture of that shape. - Deferred because there is no number — outline titles are not joined against page text. A rate
for that join was briefly published and withdrawn as unmeasured; nothing in the repository
produces it, and it is not re-derived here.
Every open item, and what it waits on, is tracked in
docs/OPEN-WORK.md.