%unimsg 0 document/prose-profile/v0 -- The first document in @rd/profile/prose/v0, written to find out whether the -- profile is usable rather than to assert that it is. -- -- THE OTHER TWO EXAMPLES ARE TYPESETTING. The tenancy agreement is paginated -- and sets its margins; the Japanese article embeds two font faces and chooses -- a leading in points. Both are the vocabulary working as designed, and both -- are what somebody asking for an "enhanced markdown" did not want. -- -- THIS ONE DECLARES NO TYPE AT ALL. Its defaults are the profile's, verbatim, -- and after that there is not a single length in the file. What is left is the -- part markdown cannot do: a table with a spanning header, a footnote, an -- ordered list that is really numbered, a derived contents list, and an anchor -- somebody can link to. -- -- WHAT WRITING AND THEN RENDERING IT FOUND, and the count is the evidence -- rather than a confession: six. Two changed the profile, three were this -- document lying about the vocabulary, and one is a renderer's to fix. -- -- THE THREE THIS DOCUMENT GOT WRONG were all the same mistake, and a renderer -- found them where reading did not: a :table-cell, a :quotation and a note -- entry all take BLOCKS under :children, and this document put runs in -- :content on the first two and a bare block sequence on the third. All three -- parsed. They rendered as an empty three-column grid, a quotation with a -- source and no words, and a note card with a number and no note — each found -- by looking at a rendering, none by reading the file. -- -- THE LESSON IS ABOUT WHERE THE TRUTH IS. The structural table has a column -- headed `carries-runs` and it answers `no` for every one of them; note-keys -- requires :doc and :children. A parser cannot catch this, because a document -- with a key the vocabulary does not define there is still well-formed -- unimsg — so the gate that would catch it is a vocabulary checker, and until -- one exists a renderer is the checker. -- -- THE RENDERER'S ONE is the ordered list: this document names a :decimal -- scheme and neither renderer wrote a number. The document says what to write, -- so that is a gap on the reading side rather than the writing side. An -- UNORDERED list is different and is nobody's bug — there is no bullet counter -- style, a list with no :numbering is simply unordered, and the marker is the -- reader's to choose. That is exactly why the profile now carries -- what-a-reader-still-owes. -- -- A LIST IS ORDERED ONLY BY CARRYING :numbering. The first draft refused -- numbering schemes as typography, which would have refused the ordered list — -- the one construct nobody would give up. -- -- THERE IS NO INLINE-CODE RUN KIND. Inline code is a :text run whose :family is -- :mono, so the draft that refused :family outright had no inline code in a -- profile written to be a superset of a markdown subset that has it. :family is -- now restricted to the three generic names rather than refused, which is the -- honest line: a generic name is a request the reader satisfies, not a -- measurement. -- -- AND :styles SURVIVES USEFULLY only because a style may still say WHAT -- something is. The moment it says how big, it is out. prose-profile @document/prose-profile/v0 { title "Reading a document without typesetting it" status :draft at 2026-09-01 flow :reflowable targets [ external -> @rd/profile/prose/v0 ] locale { language "en", direction :ltr } -- The profile's block, verbatim. Every conforming document carries this -- same five lines, which is what lets a profile reader skip resolution: it -- knows the answer before it opens the file. defaults { family :sans size pt 12 weight 400 colour :on-surface line-height em 1.4 } -- A style may say WHAT a thing is. It may not say how big. styles { caution { doc "a paragraph the reader should not skim", applies-to :block, properties { fill :muted } } term { doc "a term on first use", applies-to :text, properties { slant :italic } } strong { doc "a run the sentence turns on", applies-to :text, properties { weight 700 } } code { doc "code, in the line", applies-to :text, properties { family :mono } } } numbering { steps { doc "the steps of the procedure", style :decimal } } notes { why-not-a-sibling { doc "why this is a profile rather than a fourth vocabulary" children [ { block :paragraph, content [ "A fourth vocabulary would duplicate the block table, and two block tables drift." ] }, ] } } content [ { block :contents, over :sections, depth 1 }, @what { block :section, name [ "What the profile is" ], children [ { block :paragraph, content [ "A prose document is an ordinary rich document that has declined to make any ", { kind :text, text "typographic", style -> @styles.term }, " decision. It carries the profile's defaults unchanged, sets no length anywhere, and is therefore readable by a renderer that never implements resolution", { kind :note, to -> @notes.why-not-a-sibling }, "." ] }, { block :paragraph, style -> @styles.caution, content [ "It is still a rich document. A full reader renders it exactly as it renders any other, and nothing here narrows the vocabulary." ] }, ] }, @keeps { block :section, name [ "What survives that markdown cannot hold" ], children [ { block :list, children [ { block :list-item, children [ { block :paragraph, content [ "a table whose header spans two columns" ] } ] }, { block :list-item, children [ { block :paragraph, content [ "a footnote with a real body, rather than a line at the bottom of the file" ] } ] }, { block :list-item, children [ { block :paragraph, content [ "an anchor another document can point at — see ", { kind :link, to -> @what, content [ "the section above" ] }, "" ] } ] }, ] }, @comparison { block :table, name [ "Where each format stops" ], children [ { block :table-row, repeat :header, children [ { block :table-header, scope :column, span { columns 2 }, children [ { block :paragraph, content [ "structure" ] } ] }, { block :table-header, scope :column, children [ { block :paragraph, content [ "type" ] } ] }, ] }, { block :table-row, children [ { block :table-cell, children [ { block :paragraph, content [ "markdown" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "headings, lists, links" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "none, and that is the point" ] } ] }, ] }, { block :table-row, children [ { block :table-cell, children [ { block :paragraph, content [ "this profile" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "tables, notes, citations, navigation" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "none, declared" ] } ] }, ] }, { block :table-row, children [ { block :table-cell, children [ { block :paragraph, content [ "the full vocabulary" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "the same" ] } ] }, { block :table-cell, children [ { block :paragraph, content [ "pages, fonts, inks, lengths" ] } ] }, ] }, ] }, ] }, @writing { block :section, name [ "Writing one" ], children [ { block :list, numbering -> @numbering.steps, children [ { block :list-item, children [ { block :paragraph, content [ "copy the profile's ", { kind :text, text "defaults", style -> @styles.code }, " block, unchanged" ] } ] }, { block :list-item, children [ { block :paragraph, content [ "name the profile in ", { kind :text, text "targets", style -> @styles.code } ] } ] }, { block :list-item, children [ { block :paragraph, content [ "write the document, and set no length" ] } ] }, ] }, { block :quotation, source [ "@rd/profile/prose/v0" ], children [ { block :paragraph, content [ "Declaring this profile is an author saying they have none." ] }, ] }, { block :code, lines [ "targets [ external -> @rd/profile/prose/v0 ]", ] }, ] }, ] }