Skip to content

fix: withdraw the quote attribution, a captioned quote is a figure again - #1264

Merged
dereuromark merged 1 commit into
mainfrom
fix/withdraw-quote-attribution
Aug 15, 2026
Merged

fix: withdraw the quote attribution, a captioned quote is a figure again#1264
dereuromark merged 1 commit into
mainfrom
fix/withdraw-quote-attribution

Conversation

@dereuromark

Copy link
Copy Markdown
Contributor

What

A caption on a block quote is a figure caption again. block_quote.attribution is gone, figure.target admits a block_quote, and the spec submodule moves onto the withdrawal.

Implements markup-carve/carve#1213, which withdraws PART 9 section 4a and PART 11 section 10d.

Why the clause fell

The HTML Standard's blockquote section:

Attribution for the quotation, if any, must be placed outside the blockquote element.

and its recommended pattern, given as the way "to clearly relate a quote to its attribution (which is not part of the quote and therefore doesn't belong inside the blockquote itself)":

<figure>
 <blockquote>
  <p>The truth may be puzzling. ...</p>
 </blockquote>
 <figcaption>Carl Sagan, in "<cite>Wonder and Skepticism</cite>", ...</figcaption>
</figure>

Section 4a put the attribution inside the quote, in a <footer>, and asserted in its own text that both spellings were valid HTML.

Its model argument fails too. figure is already the generic captioned wrapper in this engine: a captioned code block is a figure whose target is the code block. What a captioned thing is called and counted as comes from the caption's own label, not from the host's node type, so a quote was never a special host.

Nothing shipped. 0.1.4 predates #1239, so this removes code no release carried, and the CHANGELOG loses those entries rather than gaining a reversal.

What comes back

> To be
^ Hamlet
<figure>
  <blockquote><p>To be</p></blockquote>
  <figcaption>Hamlet</figcaption>
</figure>

The caption numbers like any other. Measured on this branch:

{#ep}
> To be
^ Figure #: Hamlet

![x](/i.png)
^ Figure #: An image

See </#ep>.
<figure id="ep">
  <blockquote><p>To be</p></blockquote>
  <figcaption>Figure 1: Hamlet</figcaption>
</figure>
<figure>
  <img src="/i.png" alt="x">
  <figcaption>Figure 2: An image</figcaption>
</figure>
<p>See <a href="#ep">Figure 1</a>.</p>
  • BlockQuote::$attribution is gone from the node, the AST codec, the ProseMirror bridge and the renderers. resources/ast-schema.json is re-copied from the spec submodule, which moves onto the withdrawal.
  • HtmlToCarve reads <figure><blockquote>…<figcaption> back as the figure, and a <footer> inside a quote is ordinary quoted content again.
  • The Markdown, plain-text and terminal writers lose the attribution-specific handling section 10d added (the <footer> element, the quote bar carried onto the attribution line, the removed blank line) and render a quote's caption the way they render any other figure caption.

What stays

PART 11 section 10e landed in the same commits and is untouched: a table caption still survives the Markdown target, and a code fence's title and grouping label still survive plain text and the terminal. Measured on this branch:

| H |
| --- |
| a |

Table caption

Multi-block captioned quotes also keep working. The pre-4a oracle refused them; that regression does not come back.

One fixture worth a note

tests/fixtures/ast-schema.json is the reflection-derived FIELD MAP, not a copy of the published schema, and AstCodecSchemaTest compares it against AstCodec::schema(). It loses exactly one entry: block_quote.fields drops attribution. That golden is the rename detector for the wire format; the vendored-copy check is a different file (resources/ast-schema.json), and conflating the two would have removed a guard while appearing to refresh a fixture.

Downstream

markup-carve/carve-js and markup-carve/carve-rs get the same revert. markup-carve/carve-grammars#219 tracks the tiptap projection.

markup-carve/carve#1213 withdraws PART 9 §4a and PART 11 §10d. A caption on a
block quote is not an attribution; it is a caption like any other, so a captioned
quote is a `figure` whose target is the quote - the shape this engine produced
before #1239.

WHY THE CLAUSE FELL. The HTML Standard's `blockquote` section requires that
"attribution for the quotation, if any, must be placed outside the `blockquote`
element", and gives a `<figure>` wrapping the quote with a `<figcaption>` as the
way to attach it, "which is not part of the quote and therefore doesn't belong
inside the `blockquote` itself". §4a put it inside, in a `<footer>`, and asserted
that both spellings were valid. Its model argument fails too: `figure` is already
the generic captioned wrapper, since a captioned code block is a `figure` whose
target is the code block, and what a captioned thing is called and counted as
comes from the caption's own label rather than the host's node type.

Nothing had shipped - 0.1.4 predates the port - so this removes code no release
carried, and the CHANGELOG loses those entries rather than gaining a reversal.

WHAT COMES BACK:

  `> To be` + `^ Hamlet` renders

      <figure>
        <blockquote><p>To be</p></blockquote>
        <figcaption>Hamlet</figcaption>
      </figure>

  The caption numbers like any other and shares the Figure bucket with images, so
  a numbered cross-reference to the quote's id resolves again.

  `BlockQuote::$attribution` is gone from the node, the AST codec, the ProseMirror
  bridge and the renderers, and `figure.target` admits a `block_quote`.
  `resources/ast-schema.json` is re-copied from the spec submodule, which moves
  onto the withdrawal.

  `HtmlToCarve` reads `<figure><blockquote>…<figcaption>` back as the figure, and
  a `<footer>` inside a quote is ordinary quoted content again.

  The Markdown, plain-text and terminal renderers lose the attribution-specific
  handling §10d added and render a quote's caption the way they render any other
  figure caption.

WHAT STAYS. PART 11 §10e landed in the same commits and is untouched: a table
caption still survives the Markdown target, and a code fence's title and grouping
label still survive plain text and the terminal.

`tests/fixtures/ast-schema.json` is the reflection-derived field map, NOT a copy
of the published schema, so it loses exactly one entry - `block_quote.fields`
drops `attribution` - and `AstCodecSchemaTest` keeps comparing it against
`AstCodec::schema()`. That golden is the rename detector for the wire format and
is not the vendored-copy check; conflating the two would have removed a guard
while appearing to update a fixture.
@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Parser/BlockParser.php 81.81% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@dereuromark
dereuromark marked this pull request as ready for review August 15, 2026 01:27
@dereuromark
dereuromark merged commit 1757d1e into main Aug 15, 2026
5 of 6 checks passed
@dereuromark
dereuromark deleted the fix/withdraw-quote-attribution branch August 15, 2026 01:28
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