Skip to content

docs(plan): break M6 into task subsections - #43

Merged
aenawi merged 1 commit into
mainfrom
aenawi/m6-task-breakdown
Sep 7, 2026
Merged

aenawi merged 1 commit into
mainfrom
aenawi/m6-task-breakdown

Conversation

@aenawi

@aenawi aenawi commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Docs only. No code changed.

M6 was a header, a status marker and one sentence of constraint:

M6 — PDF [ ]

PDF implements DocumentReader only.

Every other milestone in docs/PLAN.md carries numbered subsections with boxes. M7, also unstarted, already carries five. M6 had none — so "what is left" had no answer at the granularity the rest of the plan answers it. The three bullets in ROADMAP.md are goals, and goals are not tasks.

It now has 6.1 through 6.5, fifteen boxes, in dependency order behind the object layer.

§ Boxes
6.1 The object layer [ ] 3
6.2 Text extraction and its order [~] 3
6.3 text-reversed [~] 3
6.4 Embedded font coverage [~] 4
6.5 No writer, and the conformance suite [~] 2

Four things decided rather than left for the implementer

The parser is an ADR, not a Cargo.toml line. Own it as dom.rs and css.rs are owned, or take one. The constraints are stated — pure Rust, no C, no network, permissive, and no rasteriser, since most of what a PDF library carries is the rendering half this project has said it will never do — without naming a crate nobody has evaluated. This is the milestone's one real decision and it blocks everything below it.

text-reversed can be proved without a dictionary, which is the result that made the section worth writing. A presentation-form codepoint encodes its own contextual position — U+FEE3 is initial meem, U+FEF2 is final yeh — and joining::forms() already computes the position each letter should have from its neighbours. The two agree on a logically-ordered run and trade initials for finals on a reversed one. So ADR 0004 applies to the hardest case in the project rather than being waived for it.

Embedded font coverage is not behind --fonts. §4.2 gated the font checks because they read the machine, so the answer depended on who ran the tool. A font inside the document gives the same answer everywhere, and gating it would be an opt-out for a check carrying none of the cost the flag exists to declare. The inverse — a font referenced by name and not embedded — is the case that belongs in sources.unread.

Two rules are structurally silent, and one unread source is new. direction-unset cannot fire on a format where no attribute states a direction anyone chose, so it is a refusal like Word's hard left edge and HTML's unevenly filled font slots. And a font with no ToUnicode makes the text itself the source the adapter could not read — ADR 0009 in a sharper form than a stylesheet on a server or Excel's formula cache.

What M6 gets for free

presentation-forms and font-coverage are statements about text and a font, and a PDF has both. They should fire without a line of mirsam-core changing — and if either needs one, §3.5's instruction applies: fix the abstraction, not the rule.

Verification

make verify clean — 611 tests, clippy -D warnings, fmt, doc, release build. One codepoint cited in an early draft (U+FEF4 as initial meem; it is yeh medial) was corrected to U+FEE3 and checked against the Unicode database.

M6 was a header, a status marker and one sentence of constraint. Every
other milestone in this file carries numbered subsections with boxes;
M7, also unstarted, already carries five. M6 had none, so "what is left"
had no answer at the granularity the rest of the plan answers it.

It now has 6.1 through 6.5 and fifteen boxes, in dependency order behind
the object layer.

Four things were decided rather than left for the implementer.

The parser is an ADR, not a dependency line. Own it as `dom.rs` and
`css.rs` are owned, or take one — the constraints are stated (pure Rust,
no C, no network, permissive, and no rasteriser, since most of what a
PDF library carries is the rendering half this project has said it will
never do) without naming a crate nobody has evaluated.

`text-reversed` can be proved without a dictionary, which is the result
that made the section worth writing. A presentation-form codepoint
encodes its own contextual position, and `joining::forms()` already
computes the position each letter should have from its neighbours. The
two agree on a logically-ordered run and trade initials for finals on a
reversed one. So ADR 0004 applies to the hardest case in the project
rather than being waived for it.

Embedded font coverage is not behind `--fonts`. Section 4.2 gated the
font checks because they read the machine, so the answer depended on who
ran the tool; a font inside the document gives the same answer
everywhere. The inverse — a font referenced by name and not embedded —
is the case that belongs in `sources.unread`.

Two rules are structurally silent and one unread source is new.
`direction-unset` cannot fire on a format where no attribute states a
direction anyone chose, so it is a refusal like Word's hard left edge.
And a font with no `ToUnicode` makes the text itself the source the
adapter could not read, which is ADR 0009 in a sharper form than a
stylesheet on a server or Excel's formula cache.

Docs only. No code changed.
@aenawi
aenawi merged commit 66064cb into main Sep 7, 2026
7 checks passed
@aenawi
aenawi deleted the aenawi/m6-task-breakdown branch September 7, 2026 05:22
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