Skip to content

The reference tables are checked against the code, and the claims the pages make are tested - #15

Merged
fabeat merged 36 commits into
mainfrom
feature/integrated
Oct 28, 2026
Merged

fabeat merged 36 commits into
mainfrom
feature/integrated

Conversation

@fabeat

@fabeat fabeat commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The site's tables of names are written by hand, and they had already drifted. This makes them generated from the code and adds a test suite for the prose.

What drifted, and is now checked

The site said The code has
"Four themes ship" five — pitch was missing
"Every exception Markdown Presentation throws, in one place" five were missing
"Four read-friendly aliases" six are accepted
"the thirteen style keys" twelve
a Word style-slots table of 7 19
the free shapes not documented at all — twelve names
the Word options table on two pages, and the copies already differed

tools/check-reference.php now reads 24 vocabularies and 227 names out of the class that owns each one, and compares the page that carries it — in both directions. A documented name the code does not have, and an existing name the document does not list, are both failures.

And the rule extends past the site: a vocabulary may be read out of both halves and compared with each other, so a half that grew a ninth attribute is caught in the deck and in the document.

The claims, which a table cannot carry

tests/Claims/ holds the prose claims as tests — the counts, the completeness, the rules. Every one fails against main, because main predates the features they are about.

Three were already waiting on this work and are now real tests rather than pending ones: "refuses a note that is closed but is not last, and says why", "says how the attributes of a shape are separated", and "finds a theme that sits beside the deck" — the last of which is REVIEW.md §8, from before this work began.

What this pull request adds to the site

The slide templates and ::slide-number in the slides half, and the seven object directives in the Word half, with a loss matrix saying what ODT and RTF cannot carry. The slides half's error page grows by fourteen exceptions. The frontmatter key set now seven, the free shapes thirteen, the Word directives ten.

The order of the merges

This pull request must be merged last. The site's continuous integration checks the libraries out from main, so the reference checks compare the pages against libraries that do not have the templates, the object directives or the text styles until those pull requests are merged. Merge the two libraries first.

Three things the writing turned up

The site was wrong about :::toc, and so was a snippet. It said the body of a container is "silently dropped" — nothing is claimed, and DocumentRenderer draws the body as ordinary Markdown with the fence gone. And content/general/errors.md showed a Loss by two methods it does not have: MarkdownWord\Loss has public properties, so the snippet was a fatal error. It was wrong on main too, before this work. Both are corrected, and the old phrasings are in the FORBIDDEN map so they cannot come back.

The deck's own frontmatter is the first slide's — so a deck that opens with a --- block and then another --- gets an empty first slide, and chrome: has to be on the slide that opens the deck. The site now says so.

And a bug in the Word half, not in the documentation: the Word README's format table says a table's column alignment is "carried | dropped | carried", and the ODT really does drop it — but Format::Odt::drops() does not list it, so pendingLosses() says nothing. A reader who aligns a column and converts to ODT loses it in silence. That is a library fix and it is not in this pull request; it is reported there.

The two commands the command line gained

mdoffice theme init <deck.pptx> writes a theme from a deck, and mdoffice slides diff a.pptx b.pptx says what changed between two decks. The site had a page for neither, and the check that compares the pages against the program said so:

The parts table does not list the part "theme".
The commands table does not list the command "slides diff", which the program has.
The commands table does not list the command "theme init", which the program has.

There is now a page for the new part, content/command-line/theme.md, and the options of theme init are checked against it the way the options of the other commands are — tools/check-command-line.php reads the program's own help and compares it with the page, in both directions.

And the duplication

The new code was 3.6% duplicated against SonarCloud's limit of 3%. The repeated parts were the walk over a directory's files, the read of a page's blocks and markers, the finding of a section of the help, the failure report of the two checkers, the terminal preamble of all six tools, and the "write a fixture, use it, take it away" block that four claims shared.

They are shared now — tools/lib/Cli.php and tools/lib/Report.php for the tools, tests/Support/Directory.php, Refusal.php, Run.php and Types.php for the claims — and the estimate at Sonar's own threshold of 65 tokens is 0.00%.

The order of the merges

This pull request must be merged last. The site's continuous integration checks the libraries and the command line out from main, so the reference checks compare the pages against libraries that do not have the templates, the object directives or the text styles until those pull requests are merged. The workflow takes the branch of each from a repository variable, which is set to feature/integrated while these pull requests are open and defaults to main otherwise.

fabeat added 21 commits October 27, 2026 16:23
The tables that list a vocabulary are written by hand, and they had drifted: the
site said four themes shipped when five did, its error page said it listed every
exception the package throws and left five of them out, and the Word options
table was on two pages and the two copies already differed.

Every vocabulary is now read out of the library that owns it and compared with
the page that carries it, in both directions. A page says which of its blocks is
the list of what by marking it, and a second copy of a list is a failure as well:
two copies drift apart and the one nobody reads is the one that is wrong.

The drifted claims are corrected, and the tables that were in two places are in
one now.
A table can be checked against the code and a sentence cannot: the counts, the
claims of completeness and the rules a page states are prose, and a prose claim
is correct only until the code moves.

The suite in tests/ asks the code how many there are and the page how many it
says, checks a page that claims to list every exception against the classes the
package throws, and checks the rules against the library that has to behave that
way. The phrases that were wrong and have been corrected go into the FORBIDDEN
map, which now covers the whole site and not only the command-line pages: a
sentence that was wrong is wrong wherever it is written, and the pages that
drifted most were the ones nothing was checking.
The workflow built the site with npm run build, which renders "This example did
not build" into the page and succeeds anyway: a broken example was a green
build. The strict build is the one that is asked for now, and the two checks
that keep the pages true of the code run beside it.
The index of the site is a template, and a template carries a page's summary in
the page it builds from — so a phrase that was wrong is looked for in the
Markdown and in the templates that render it.
The frontmatter keys of the Word half are open-ended — the library validates
two of them and reads the rest — so there is no list of them to check a page
against. The options, the style slots and the themes are.
Both halves can write a word in a style of its own, and the syntax and the
attributes are the same in the two. The page that explains how a directive
works is where the shared vocabulary belongs, and the eight attributes are a
vocabulary the reference check reads out of both halves and holds to one list —
so a half that grew a ninth attribute is caught rather than documented.
An inline directive in a deck is a text style, so every one of them is either
a name the theme has or a build that stops with the styles it has named. The
page says so, and the claims check it: the refusal, the message, the theme's
file, and the three forms the raw one takes.

The example is the raw form, because no theme that ships carries named styles
yet — the named one is proved by a theme of the test's own.
A name the theme does not have, a label that holds Markdown, an attribute
nobody reads — each of them reaches the document as the characters the author
typed, because a sentence and a parser nobody asked to change should not change
the syntax of every document converted after it.

The round trip keeps the word and loses the style, and the page says so: a
style is written as direct formatting, and the reader reads bold, italic and
strike and no colour.
Three directives and not two, three methods on the renderer and not two, and
the exception a theme naming a face there is no table for — each of them a
count the code is asked about, and each of them now checked.

The index pages carry the inline directive as well, because a deck's dialect
now has one and the index is where the dialect is listed.
Three sentences were wrong and have been corrected: the round-trip page's
count of what does not survive, the Word index's count of the directives, and
the presentation index's count of the renderer's methods. A count that was
wrong once tends to come back, because the code moved on and the sentence did
not — so the phrases are here, and a page that says one again is a failure.
The reference tables are read out of the libraries and compared with the pages
that carry them, and a vocabulary the two halves share is read out of both of
them and held to one list — so the attributes an inline style takes are the
same eight in the deck and in the document.
A word in a named style comes back as the word, without the style and without
the colour it was drawn in, and the package's own list of what does not travel
now says so. The index summarised that list, and the summary was one item
short.
A template is the furniture of a deck — the wordmark, the rule, the page
number — written once and drawn on every slide that names it. It is a slide
of the deck's own Markdown whose frontmatter names a template and nothing
else, and it is not a slide of the deck: it is not drawn, it has no number,
and it does not count towards the number of slides.

Four things decide what one is, and the pages now say them: the body holds
chrome and nothing else, a slide may name several templates, `layout:` and
`template:` are independent, and the deck's own templates override the
imported ones of the same name. A template may also live in a file beside
the deck, named with `chrome:` in the deck's own frontmatter. `::slide-number`
is a shape like any other, and `of=true` writes the number of the deck after
the number of the slide.

A rule is a sentence rather than a name, so each is checked against the
library that has to behave that way: a definition that is drawn, a template
that holds a heading, a chrome file that is not there, an imported template
the deck overrides, and a page number that is the number of the deck.
Seven directives place objects in a document: a picture, a caption, a page
break, a section, a floating box, a shape and a form field. The Word half
never refuses — a directive a writer cannot express is given the author's own
characters back and the loss is reported — so the pages say which format
carries what, and the round trip says what comes back of each.

The reference table carries the ten names the library draws, and a new
vocabulary carries the four features a format cannot hold for them, read out
of the class that names them. A caller that builds its own registry draws
fewer than ten, and the page says so: the handlers that are not given are not
drawn, and a conversion through `MarkdownToWord` hands over all of them.
Ten sentences were wrong and have been corrected: the counts of the
frontmatter keys, the free shapes and the Word directives, the two examples
that claimed to use every frontmatter key, the claim that the container form
of a drawn name is claimed rather than drawn, and the snippet that read a
loss by two methods it does not have. A count that was wrong once tends to
come back, because the code moved on and the sentence did not — so the
phrases are here, and a page that says one again is a failure.
The reference tables are read out of the libraries and compared with the
pages that carry them. A vocabulary joins them: the features a Word format
cannot carry, which the pages list beside the directives they belong to.
Four places threw a generic exception, and a reader of the failure had to
work out from the message what had gone wrong. Each has its own class now:
the page of the site that is not there, the package that could not be
opened, the page that lists no type at all, and the package a class
belongs to.

The rule that is not one of them is caught by name, which is what a catch
is for.
The path of a page was written out in every claim that read it, and the
deck that names a theme and writes a word in a named style was written out
four times over. Each is named once now: the pages have constants in the
class that knows the site, and the deck and the theme that go with it have
constants in the class that holds the themes.

A claim says which page it is about rather than spelling the path, and the
page a claim is about is a thing that has a name.
@fabeat fabeat changed the title The site's reference tables are checked against the code, the claims it makes are tested, and it says what the two new commands do The reference tables are checked against the code, the claims are tested, and the two new commands are documented Oct 28, 2026
@fabeat fabeat changed the title The reference tables are checked against the code, the claims are tested, and the two new commands are documented The reference tables are checked against the code, and the claims the pages make are tested Oct 28, 2026
A dropdown with no entries protects nothing, a footnote needs the whitespace in front of it to
be a directive at all, and an RTF keeps the section break and loses the columns. The pages said
the opposite in all three places, and the example wrote `::toc{depth=2, title="Contents"}`,
which the parser reads as the depth `2,` and therefore as no depth at all.
… list of types

The count of the things that do not survive came from the page's own headings, so the page
agreed with itself and nothing else; the page break and the columns of a section were named
by one test and exercised by another; and the list of types a page names was cut off at the
first full stop, so a type nobody draws could be written down after it.
…ibrary

The attributes a directive reads and the keys a document's frontmatter may carry were written
down on the pages and checked against nothing, so a library that stopped reading one of them
was a page that stayed wrong. They are read out of the code now, and a table that lists part
of a list is a second copy of it, so the images page keeps no copy of three options and the
command line is on the page that has it.
A loss is reported in a sentence the library writes, and the page quoted four of them
verbatim without anything checking that they were the sentences the library still writes.
The slides half reads a chrome file with a ceiling and bounds the shapes on a slide, and the
page that lists every exception it throws did not list either of them.
The names in the first column of the errors tables were checked and the second was not,
though the code says which of its exceptions sit beside InvalidInput rather than under it —
and a page that calls one of them an InvalidInput says the caller can fix it.
The carried and lost columns were prose nothing checked, and the code says which of the
formats carries each of the four objects and which drops it.
The number in a cell was compared with the number in the code and with the number as a
reader writes it, and a phrase with a number that happened to be in the cell passed; the
page's list of what does not survive is now the list the library answers with.
Seven vocabularies were added and the rule about a second copy now covers a copy of part of
a list, so the page that explains the mechanism says what the mechanism does.
The slides half grew three: the size of a chrome file, the shapes one slide may carry, and the size of one part of a theme's template. The table listed three of the six.
Every comment in the code this session added was read again by the rules the documentation policy sets: what restates the code, what counts a thing that rots, and what is only padding. The reasons stay.
The loop updated its counter inside its own body; the walk now advances once, at the end of a line, and a block still moves past its own rows.
The word was used before it was defined, and a reader who met it in the prose had to guess.
@sonarqubecloud

Copy link
Copy Markdown

@fabeat
fabeat merged commit da1a803 into main Oct 28, 2026
4 of 5 checks passed
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