Skip to content

ethos-parser 0.61.0

Latest

Choose a tag to compare

@ethos-pramaan ethos-pramaan released this 25 Sep 01:38
· 94 commits to main since this release
Immutable release. Only release title and notes can be modified.

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 — extract and
    classify on all eight gate documents, and markdown, html and ground on six of them; the
    two largest are compared through extract and classify alone, 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 --version

Substitute 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_VERSION 0.6.0 → 0.7.0, EXTRACT_SCHEMA_VERSION 0.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 outlines array. A new top-level record, beside tables — not
    Nodes. On the PDF profile capabilities.outlines is true and outline_rule names
    outlines-v1; on the eight office profiles capabilities.outlines is permanently false and
    outline_rule carries not-run-for-this-format
    , which is also what text_box_rule carries
    there. A consumer asserting outline_rule == "outlines-v1" across all nine profiles breaks.
  • Two office node attribute types gain outline_level — OfficeParagraphAttributes and
    OfficeOdfShapeAttributes, an optional integer, absent where the block stated no level. A
    0.60.0 consumer deserializing office nodes with deny_unknown_fields rejects it.
  • markdown_rule and html_rule move to markdown-blocks-v10 and html-blocks-v10. An ODF
    <text:h> that declared text:outline-level="3" now projects as ### and <h3> where it
    projected as # and <h1>.
  • text_box_rule appears on the profile, naming advance-over-font-envelope-v1. No box
    changes shape
    — the field says what shape they always were.
  • Two new coverage.structural_erasures codes on ethos.markdown.v1 and ethos.html.v1:
    heading-level-unresolved-v1 where an ODF heading stated no level, and
    heading-level-unrepresentable-v1 where 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-read rides every representation and every classification across all nine
    formats, and outlines-not-read rides every artifact from the eight office profiles.

New:

  • The PDF catalog's /Outlines is 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. locate and grounding both
    read nodes.
  • A cycling /First//Next is 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–0x9F is 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 render Backup – Cryptographic as
    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 and char_codes carries the
    page's order beside it. right-to-left-not-reordered now 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's Bidi_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.