fix: a captioned quote is a figure in both directions again - #69
fix: a captioned quote is a figure in both directions again#69dereuromark wants to merge 1 commit into
Conversation
The spec withdrew the quote attribution model in markup-carve/carve#1213, so a captioned quote is a `figure` whose target is a `block_quote` and whose caption is the `^ ` line. This bridge still carried the withdrawn model, and that was not merely stale bookkeeping - it was two live defects against the pinned engine, both measured rather than argued. The exchange AST did not validate. `pandocToCarveAst` put an `attribution` field on a `block_quote`, and `resources/ast-schema.json` refuses it: the node declares `additionalProperties: false`, so reversing a `Figure[BlockQuote]` produced a document the published schema rejects with `{"keyword":"additionalProperties","params":{"additionalProperty":"attribution"}}`. The one thing an exchange AST has to be is the exchange AST. Caption numbering disagreed with the engine. For a captioned quote followed by a captioned image, both spelling `Figure #`, the engine renders `Figure 1` then `Figure 2`. The bridge kept the quote's `#` literal and started the sequence at the image, so pandoc's HTML writer printed `Figure #: Hamlet` and `Figure 1: Second` - a placeholder that never resolves and an off-by-one on every later figure and cross-reference. A quote figure now lowers through the ordinary figure path, and a `Figure[BlockQuote]` reverses to `figure{target: block_quote}`. The runtime probe of the engine's serializer and the lowering that rewrote the shape on the way out are both gone with the model they served. The attribution lowering existed for a real reason and the reason still holds: pandoc's plain and rst writers drop a `Figure`'s caption. Measured on pandoc 3.5, that is not quote-specific. The plain writer drops the caption of EVERY figure, image figures included; the rst writer keeps one only through the `.. figure::` directive, which is the image case. A figure wrapping a code block loses it identically. So the loss belongs to pandoc's writers for non-image figures, and routing around it by moving the caption inside the quote puts the attribution in the one place the HTML Standard forbids - which is what the spec withdrew. latex, html, markdown, docbook and org all keep it, and the roundtrip test now asserts both halves of that table so the day pandoc changes, the test says so. Nothing had to be kept working: `block_quote.attribution` never appeared in any published engine (the carve npm package is at 0.1.3, which has no such field), and this bridge has no tag and no npm release, so no document produced by the withdrawn model exists outside a working tree. Reading the `[X]{.attribution}` span back in was therefore dropped rather than kept: nothing emits it anymore, and re-importing it would move content out of a blockquote on the strength of a class name this bridge itself invented. Measuring the new path surfaced a separate crash that predates it. Pandoc's own HTML reader emits a `Figure` with an EMPTY caption for `<figure><img src="a.png"></figure>`, and both figure branches built a `figure` node with no `caption` field from it - refused by the schema, which requires the field, and fatal in the writer with `Cannot read properties of undefined (reading 'forEach')`. Emitting `caption: []` instead is not the fix: `renderCarve` writes a lone `^` line for it, and that line re-parses as a lazy continuation, so `> q` comes back as the two-line paragraph `q\n^` inside the quote. An uncaptioned figure is emitted as its host instead - a shape Carve source can spell - and the dropped wrapper is reported.
|
Superseded. Closing rather than rebasing, because the behavior this asks for is already on It was opened at 12:29 and never rebased. Three PRs landed after it, all touching the same files:
That is why it reports Verified on current Forward, the top-level block is a {"t":"Figure","c":[["",[],[]],[null,[{"t":"Plain","c":[{"t":"Str","c":"Hamlet"}]}]],[{"t":"BlockQuote","c":[{"t":"Para","c":[...]}]}]]}Reverse, it comes back byte-identical: And Rebasing this branch would replay a removal against a tree the removal already happened in. Nothing is lost by closing it; the branch is preserved. |
Clears the P4 rows of markup-carve/carve#1210 (cross-repo, so it does not auto-close anything there).
markup-carve/carve#1213 withdrew the quote attribution model: a captioned quote is a
figurewhose target is ablock_quoteagain. This bridge still implemented the withdrawn model, which was not stale bookkeeping but two live defects against the pinned engine.What was broken
The exchange AST did not validate.
pandocToCarveAstput anattributionfield on ablock_quote, andresources/ast-schema.jsonrefuses it - the node declaresadditionalProperties: false. Reversing aFigure[BlockQuote]produced:Caption numbering disagreed with the engine. For
the engine renders
Figure 1: HamletthenFigure 2: Second. The bridge kept the quote's#literal and started the sequence at the image, so pandoc's HTML writer printed:A placeholder that never resolves, and an off-by-one on every later figure and cross-reference.
What changed
A quote figure lowers through the ordinary figure path, and a
Figure[BlockQuote]reverses tofigure{target: block_quote}. The runtime probe of the engine's serializer and the shape-rewriting lowering go with the model they served.The reason the old lowering existed still holds, and is not quote-specific
Pandoc's plain and rst writers do drop a
Figure's caption. Measured on pandoc 3.5:Figure[BlockQuote].. container:: float)The plain writer drops the caption of every figure, image figures included; rst keeps one only through the
.. figure::directive, which is the image case. A figure wrapping a code block loses it identically. So the loss is pandoc writer behavior for non-image figures. Moving the caption inside the quote to dodge it puts the attribution in the one place the HTML Standard forbids, which is what the spec withdrew. The roundtrip test now asserts both halves of that table, so the day pandoc changes it, the test says so.No transitional shape is accepted
block_quote.attributionnever appeared in a published engine (the carve npm package is at 0.1.3 and has no such field), and this bridge has no tag and no npm release. No document produced by the withdrawn model exists outside a working tree.Reading the
[X]{.attribution}span back in was therefore dropped rather than kept. A review pass argued for retaining it for documents produced by the previous forward converter; declining, because nothing emits it anymore and re-importing it would move content out of a blockquote on the strength of a class name this bridge invented. Such a document still round-trips with its text intact, spelled as what it literally says.A crash found while measuring, fixed here too
Pandoc's own HTML reader emits a
Figurewith an EMPTY caption for<figure><img src="a.png"></figure>. Both figure branches built afigurenode with nocaptionfield from it - refused by the schema, which requires the field, and fatal in the writer:It predates this change on the image branch; the quote branch would have joined it. Emitting
caption: []is not the fix -renderCarvewrites a lone^line for it, and that line re-parses as a lazy continuation, so> qcomes back as the two-line paragraphq\n^inside the quote. An uncaptioned figure is emitted as its host instead, which is a shape Carve source can spell, and the dropped wrapper is reported.