Skip to content

HTML title-block parity with Quarto 1 (bd-gx9cic8z)#396

Merged
cscheid merged 26 commits into
mainfrom
feature/bd-gx9cic8z-title-block-parity
Jul 17, 2026
Merged

HTML title-block parity with Quarto 1 (bd-gx9cic8z)#396
cscheid merged 26 commits into
mainfrom
feature/bd-gx9cic8z-title-block-parity

Conversation

@cscheid

@cscheid cscheid commented Jul 16, 2026

Copy link
Copy Markdown
Member

Overview

Brings Q2's HTML title block to DOM parity with Quarto 1's (epic bd-gx9cic8z). All phases (P0–P7) are now complete on this branch; the epic and all its strands are closed, with follow-up strands filed for every deliberately deferred item.

Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md. Guiding principle: match Q1's element nesting and class names exactly inside #title-block-header (the already-ported SCSS and third-party extensions keep working), don't chase template whitespace.

What's implemented

  • P0 — harness (bd-xj96vafq): smoke-all fixture corpus (crates/quarto/tests/smoke-all/title-block/), insta baselines of the #title-block-header subtree driven through the real q2 render orchestrator path, Q1-vs-Q2 DOM diff research note.
  • P1 — DOM parity + partials (bd-tezzk9vp): the inline title block in FULL_HTML_TEMPLATE became built-in doctemplate partials (title-block / title-metadata / _title-meta-author), shadowable Q1-style via template-partials; Q1 markup shapes (subtitle lead, p.date, block-title, bare-div grid cells); AuthorsNormalizeTransform derives by-author, pluralized/overridable labels, author-meta; fixed bd-8v34zny5 (structured authors rendering as truetrue).
  • P2 — structured author model (bd-ez0hiowa): full authors.lua port to typed Rust (metadata/authors.rs): structured names, degrees, ORCID/email/URL, affiliations with ref: resolution, funding schema (Q7); two-column Authors/Affiliations grid; inline-SVG email + ORCID decorations (Q8); DocumentProfile v7 with structured authors.
  • P3 — metadata grid completeness (bd-j6huijli): Modified + linked-Doi cells, keywords + description blocks, category chips gated on quarto-template-params.title-block-categories (default true); description renders rich in the body while the head meta uses a derived plain-text description-meta (the Pandoc/Q1 split).
  • P5 — banner mode (bd-364ol5lu): TitleBannerTransform derives the banner flag and generates the include-in-header <style> for explicit colors/images (Q5); image banners are resource-copied to the output tree; header placement above #quarto-content and the quarto-banner-title-block class on <main> are template conditionals — no DOM postprocessor, per the project rule; page-columns page-full baked into the markup. VFS-aware file probe so image detection works in WASM/preview renders.
  • Q9 lockstep throughout: PreviewTitleBlock.tsx / PreviewDocument.tsx mirror every markup/placement change; vitest integration suites + Playwright smoke-all sweep (20 title-block tests) green.

Documented deviations from Q1

  • ORCID badge is an inline SVG instead of Q1's base64 PNG (Q8); email icon is an inline SVG of bootstrap-icons' envelope.
  • #quarto-header.quarto-banner not ported: Q2 has no #quarto-header wrapper element, and the class's only Q1 consumer styles the website secondary nav, which Q2 doesn't have yet.
  • toc-left banner header class has no producer yet (Q2 has no toc-location option); the template hook is ported and inert.
  • Dates are still unformatted (2026-07-01 vs Q1's forced date-format: long) — that's P4 on this branch.
  • English-only labels with *-title overrides (Q3); manuscript style skipped (Q6); citation/scholar meta tags out of scope (Q10).

Verification

  • TDD throughout: every phase started with failing fixture assertions/snapshots; snapshot diffs reviewed and called out per commit.
  • cargo nextest run --workspace green (10073 tests); phase5 byte-identity baseline unchanged (non-banner output byte-identical).
  • cargo xtask verify --skip-hub-mcp-tests green (the skipped leg's 20 failures are pre-existing live-test timeouts against the currently-down wss://sync.automerge.org, unrelated to this branch).
  • End-to-end renders inspected for each phase (cargo run --bin q2 -- render, including an output-dir project exercising the banner-image resource copy).
  • Browser screenshot comparison against a Q1 dev binary: banner pages visually identical apart from the P4 date formatting; explicit banner color/text-color beats the theme as designed.

Completed since the draft opened

  • P6 — title-block-style: plain / none (bd-vkiwhcny): typed TitleBlockStyle option, Pandoc-fallback block for none, and the title-block SCSS layer dropped from the per-document CSS compile for plain/none (native + WASM paths, cache-key-isolated; default docs stay byte-identical).
  • P4 — date parsing & formatting (bd-13f821l5), per the approved design doc (claude-notes/plans/2026-07-17-date-formatting-design.md): dates.rs (Q1 parse forms, English named styles, day.js tokens incl. ISO-week; locale-week/named-tz deferred with warnings), DateNormalizeTransform (keywords via WASM-safe runtime clock/mtime, ISO date-meta for machine slots, in-place formatted replacement with Q1's precedence incl. forced long), listings consuming date-format at record-build, feeds sharing the parser. Closes the last visible Q1-vs-Q2 delta (unformatted dates).
  • P7 — docs (bd-y71ga2l8): docs/guides/authoring/title-blocks.qmd + dates.qmd, rendered with q2, modeled on quarto-web's structure/style, sidebar-registered. Follow-up strands filed: bd-45tfp790 (localization design), bd-4j4okt4o (manuscript), bd-e2kpwy7n (toc-location), bd-xva3f8uy (quarto-banner/secondary-nav), bd-6reut449 (citation meta tags), bd-a949e2zu (editable preview title block).

Ready to come out of draft.

🤖 Generated with Claude Code

cscheid and others added 14 commits July 15, 2026 14:32
Phase 0 of the HTML title-block parity epic (bd-gx9cic8z, strand
bd-xj96vafq). Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

- smoke-all corpus at crates/quarto/tests/smoke-all/title-block/ (7
  fixtures: simple-default, rich-authors, metadata-grid, banner-true,
  label-overrides, style-plain, style-none) with current-truth
  ensureHtmlElements assertions, to be strengthened phase by phase.
- crates/quarto-core/tests/integration/title_block_pipeline.rs renders
  through ProjectPipeline/RenderToFileOptions (the q2-render
  orchestrator path) and pins the #title-block-header subtree.
- Research note claude-notes/research/2026-07-15-title-block-q1-q2-dom-diff.md
  records the Q1 DOM extracts, reproduction procedure, and the 11-row
  divergence table mapping each gap to its phase.

Snapshot changes: 8 NEW insta snapshots (no existing snapshots
modified): title_block_{simple,rich_authors,metadata_grid,banner_true,
banner_true_main_tag,label_overrides,style_plain,style_none}. They
deliberately pin today's imperfect output — structured authors render
as 'truetrue' (bd-8v34zny5); banner/style/label-override options are
ignored — so each parity phase surfaces as a reviewed snapshot diff.

Verified: full workspace suite green (10004 tests); real-binary render
of simple-default.qmd matches the insta baseline byte-for-byte.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 1 of the HTML title-block parity epic (bd-gx9cic8z, strand
bd-tezzk9vp). Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

Rust side:
- New AuthorsNormalizeTransform (authors.lua counterpart): derives
  by-author, labels (with author-title/published-title/abstract-title/
  modified-title/doi-title/description-title overrides + Author/Authors
  pluralization), author-meta (one head <meta name="author"> per
  author), and rendered.has-title-block into document metadata. Typed
  name parsing (literal/given/family/particles) in new
  quarto-core/src/metadata/authors.rs.
- FULL_HTML_TEMPLATE's inline title block replaced by built-in
  doctemplate partials (title-block / title-metadata, each also under
  a .html alias). User template-partials shadow them Q1-style; custom
  templates resolve them as a final fallback (new blanket &T
  PartialResolver impl in quarto-doctemplate).
- Q1-parity markup: p.subtitle.lead, bare-div meta grid cells,
  <p>-wrapped authors, p.date, abstract as div > div.abstract >
  div.block-title with real <p> paragraphs (block-context rendering);
  the quarto-title-meta grid is emitted whenever the title block
  renders (empty allowed, Q1 parity).
- Fixes: bd-8v34zny5 (structured authors rendered as 'truetrue');
  date-without-author now renders its Published cell; a document with
  authors but no title now renders the header (gated on
  rendered.has-title-block, not title).

Preview lockstep (plan decision Q9):
- PreviewTitleBlock.tsx rewritten to the same markup, consuming the
  same derived metadata; its vitest integration suite rewritten; the
  five smoke-all/q2-preview/title-block-*.qmd fixtures updated.

Tests: smoke-all title-block corpus strengthened to Q1-parity
selectors (RED first, then green); new fixtures two-authors.qmd and
date-no-author.qmd.

Snapshot changes (9 modified, 0 added/removed):
- 7 title_block_pipeline baselines: the intended P1 markup changes
  (subtitle lead, bare-div cells, p wrappers, block-title, label
  overrides honored, authors pluralized, truetrue replaced by names).
- attribution_off_baseline: whitespace-only (one extra blank line from
  the partial call site).
- phase5-single-doc-baseline expected_hashes.txt re-captured per its
  documented convention: doc.html gains the (empty) Q1-parity
  quarto-title-meta grid + partial whitespace; styles.css unchanged.

Verification: cargo nextest workspace green (10,020); preview-renderer
vitest 532+519 green; hub-client build:all + test:ci green; Playwright
smoke-all title-block sweep 14/14 in a real browser; real-binary
q2 render output inspected for simple/two-authors/label-overrides and
a metadata-less doc (no empty header). cargo xtask verify passed all
Rust + hub-client legs; its quarto-hub-mcp test leg failed on 20
timeouts contacting wss://sync.automerge.org, which is returning 502
from this network (same outage braid reports all session) — unrelated
to this change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port Quarto 1's authors.lua normalization to a typed Rust model and
render its full display surface in the HTML title block:

- metadata/authors.rs grows into the full Q1 author schema: structured
  names (given/family/particles; BibTeX-heuristic split of literals,
  documented deviation from Q1's bibtex round-trip), degrees, orcid,
  email, url, phone, fax, acknowledgements, notes (globally numbered),
  attribute flags (direct keys + attributes: list/map), CRediT roles
  (aliases + vocab decoration), affiliation schema with state->region /
  affiliation-url->url aliases and metadata bucketing, inline + ref: +
  top-level affiliations: block with dedup and ref remapping, and
  funding normalization (schema only, decision Q7). Undefined refs
  warn-and-drop instead of Q1's hard abort.
- AuthorsNormalizeTransform emits the Q1 meta shapes: authors (refs),
  affiliations, by-author (denormalized), by-affiliation, funding,
  labels (+ affiliations single/plural + affiliation-title override);
  normalization problems surface as render diagnostics.
- Built-in title-metadata partial gains Q1's two-column
  .quarto-title-meta-author grid ($if(by-affiliation)$/$elseif$ split);
  new _title-meta-author partial renders url-linked names with degrees
  inside the anchor, an email icon, and an ORCID badge — both inline
  SVGs (decision Q8; envelope from bootstrap-icons upstream, ORCID
  glyph in brand green). title-block.scss sizes the SVGs (documented
  deviation: svg joined img in the orcid rule).
- doctemplate: the bare-partial external scanner now accepts
  underscore-leading names ($_title-meta-author()$ — required for Q1
  template-partials compatibility); corpus + evaluator tests added.
- DocumentProfile v7: new authors_structured: Vec<ProfileAuthor> field
  (+ ProfileAffiliation); flat authors now derives from the same
  normalization. Contract doc change log updated (incl. retroactive v6
  entry). Fixes the Phase-0 deferred-author-model note.
- Preview lockstep (Q9): PreviewTitleBlock.tsx renders the two-column
  grid and author decorations from the same derived meta; also fixes
  the P1-noted multi-paragraph-abstract gap (one <p> per paragraph).
  Vitest suite grown to 26 tests; new q2-preview smoke fixture
  title-block-rich-authors.qmd (Playwright sweep 15/15 green).

Snapshot/baseline changes (2 files, both reviewed):
- title_block_rich_authors.snap re-captured: the intended P2 DOM (two-
  column grid, decorated authors) replacing the P1 single-column list.
- phase5 expected_hashes.txt: doc_files/styles.css hash re-captured for
  the title-block.scss svg-sizing rules (entry documents the delta;
  doc.html hash unchanged).

Verification: TDD red-first on the strengthened rich-authors smoke
fixture and new vitest/doctemplate tests; full workspace green (10,056
tests); smoke-all 191/191; hub-client build:all + test:ci green;
preview-renderer 519 unit + 539 integration tests green; end-to-end
`q2 render` output inspected and browser-screenshot checked (grid
layout, ORCID/envelope icons render correctly).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Complete the Q1-parity metadata grid in the HTML title block:

- TITLE_METADATA_PARTIAL: Modified cell (p.date-modified), Doi cell
  (p.doi > a linked to doi.org), trailing keywords block
  (div.keywords > div.block-title + comma-joined <p>), Q1-verbatim.
- TITLE_BLOCK_PARTIAL: category chips (div.quarto-categories >
  div.quarto-category) inside div.quarto-title, gated on Q1's
  quarto-template-params.title-block-categories (written by
  AuthorsNormalizeTransform unless title-block-categories: false, so
  Q1-ported custom template-partials keep working); description block
  with the hide-description gate ported verbatim (inert in Q2 until a
  project pipeline sets the flag — design decision Q11).
- description now renders rich (joins RICH_TITLE_BLOCK_FIELDS); the
  head <meta name="description"> switches to the plain-text
  description-meta derived by MetadataNormalizeTransform (the same
  description/description-meta split Pandoc's HTML writer and Q1's
  html.template use; an explicit description-meta wins). Head
  keywords meta now joins list values with ", " ($for/$sep$).
- has_title_block_content counts the new fields (date-modified, doi,
  keywords, description, categories), so a document with only grid
  metadata still gets its header.
- Q9 lockstep: PreviewTitleBlock.tsx renders the same chips /
  description / Modified / Doi / keywords from the derived meta;
  vitest integration suite +7 tests (547 pass); Playwright
  title-block sweep green (17 tests) against rebuilt WASM.

Snapshot changes (2): title_block_metadata_grid.snap updated with the
intended new grid markup (chips, description, Modified, linked Doi,
keywords — reviewed, matches Q1's DOM shape);
title_block_metadata_grid_no_categories.snap added (chips suppressed,
header intact). Phase5 expected_hashes.txt deliberately not
re-captured: its fixture has none of the new metadata, and the
byte-identity test passes unchanged.

New fixtures: smoke-all/title-block/categories-disabled.qmd,
smoke-all/q2-preview/title-block-metadata-grid.qmd; strengthened
smoke-all/title-block/metadata-grid.qmd assertions (TDD red first,
6 checks failing before the fix).

Verified end-to-end via `cargo run --bin q2 -- render` with markdown
in the description: <em> in the body block, plain text in the head
meta. Full workspace tests (10061) and `cargo xtask verify
--skip-hub-mcp-tests` green; the skipped leg's 20 failures are the
known live-test timeouts against the dead wss://sync.automerge.org,
present on the baseline.

Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port Q1's title-block banner without a DOM postprocessor:

- New TitleBannerTransform (Normalization phase, format-html only —
  deliberately not revealjs, which has a title slide): derives
  rendered.title-block-banner from title-block-banner
  (true | CSS color | image path, Q1's isBannerImage detection via
  the injected SystemRuntime so the probe also sees /project/ VFS
  files in WASM renders — a bare Path::is_file() failed the
  Playwright banner-image sweep); generates the Q5 include-in-header
  <style> for explicit colors/images (title-block-banner-color
  body/body-bg = theme default, per Q1's titleColor()), appended to
  the canonical rendered.includes.header list via the favicon
  transform's append_to_rendered_header (now pub(crate)) so it
  reaches both the native $header-includes$ and the q2-preview head
  injector; pushes a ResourceCopyIntent so image banners land in the
  output tree.
- TITLE_BLOCK_PARTIAL branches internally on the flag (one partial
  name preserves Q1's template-partials override semantics in both
  modes): banner branch is Q1's banner/title-block.html —
  title/subtitle/description/categories inside
  div.quarto-title-banner > div.quarto-title.column-body, meta grid
  below, no hide-description gate, page-columns page-full baked into
  header + banner div (Q1 gets these from its bootstrap grid DOM
  postprocessor). FULL_HTML_TEMPLATE emits the header above
  #quarto-content and gives <main> quarto-banner-title-block via
  template conditionals — the placements Q1 does with DOM surgery.
- Deferred, documented (module doc + plan): #quarto-header.quarto-banner
  (Q2 has no #quarto-header element; the class's only Q1 consumer is
  website secondary-nav styling) and the toc-left banner-header-class
  producer (Q2 has no toc-location option; the template hook is
  ported and inert).
- Q9 lockstep: PreviewTitleBlock banner branch (shared TitleMetaGrids
  fragment = Q1's shared title-metadata partial); PreviewDocument
  hoists the title block above #quarto-content + <main> class. +6
  vitest cases (553 pass); Playwright title-block sweep green
  (20 tests).

Snapshot changes (5): title_block_banner_true.snap updated to the
banner markup (reviewed — matches the P0 research doc's captured Q1
banner DOM); title_block_banner_true_main_tag.snap gains
quarto-banner-title-block; new title_block_banner_color.snap,
title_block_banner_color_style.snap, title_block_banner_image_style.snap
(generated style blocks, Q1's documentTitleIncludeInHeader shape).
Non-banner output is byte-identical — the phase5 expected_hashes
byte-identity test passed unchanged.

New fixtures: banner-color.qmd, banner-image.qmd + committed 1x1
banner.png, q2-preview/title-block-banner.qmd; banner-true.qmd
assertions strengthened (TDD red first: 5 checks failing).

Verified end-to-end: q2 render on an output-dir project copies
_site/banner.png and emits the background-image style; browser
screenshots (chrome-devtools MCP) of Q1 (dev quarto binary) vs Q2
banner pages are visually identical apart from P4 date formatting;
explicit #FFDDFF/#111111 banner beats the theme as designed. Full
workspace tests (10073) and cargo xtask verify --skip-hub-mcp-tests
green (skipped leg = known dead-sync-server timeouts).

Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@posit-snyk-bot

posit-snyk-bot commented Jul 16, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

cscheid and others added 12 commits July 16, 2026 16:02
…itle-block-parity

# Conflicts:
#	hub-client/changelog.md
Implement Q1's title-block-style option surface (manuscript
deliberately unsupported per design decision Q6 — silent fallback to
default, the AppendixStyle convention):

- New TitleBlockStyle enum in transforms/config.rs (default | plain |
  none, with `false` as Q1's boolean spelling of none). Q2 has no
  YAML-schema validation layer, so the typed enum IS the "schema
  entry", matching AppendixStyle/ReferenceLocation.
- `none`: Q1 renders Pandoc's own fallback title block
  (formats/html/pandoc/title-block.html) — the TITLE_BLOCK_PARTIAL
  gains that branch, gated on the derived `rendered.title-block-none`
  (bare header without quarto classes, h1.title, p.subtitle without
  `lead`, one p.author per normalized author name, p.date,
  div.abstract > div.abstract-title using $labels.abstract$ where
  Pandoc uses its own $abstract-title$ variable — documented
  deviation, the abstract-title override keeps working).
  TitleBannerTransform skips none (Q1 emits no banner partials for
  none/false) — covered by a new pipeline test (none + banner: header
  stays in <main>, no banner markup).
- `plain` (and `none`): drop the title-block SCSS layer from the
  compiled CSS, Q1's documentTitleScssLayer. ThemeConfig gains
  `title_block_layer` (read from title-block-style;
  quarto-sass-local reader documented as a deliberate duplicate of
  quarto-core's TitleBlockStyle, both matrix-tested). Honored in
  assemble_theme_scss and BOTH compile_with_doc_vars variants
  (native grass + WASM dart-sass bridge). The shared default-CSS
  fast path additionally requires the flag, so default docs stay
  byte-identical and cache-shared; a plain/none doc takes the
  fingerprinted path with the flag in its cache key.
- Found while testing: one responsive .quarto-title-banner margin
  rule lives in the *bootstrap* layer (in Q1 too,
  _bootstrap-rules.scss:1916) and correctly survives plain/none; the
  CSS assertions target selectors only the title-block layer
  produces (.quarto-title-meta-heading, .quarto-title-author-orcid).
- Q9 lockstep: PreviewTitleBlock.tsx none-branch renders the Pandoc
  fallback from the same derived meta (+2 vitest, 555 pass); new
  q2-preview fixture title-block-style-none.qmd; Playwright
  title-block sweep green (21 tests, incl. the html style fixtures
  under the WASM runner — the WASM sass path honors the flag).

Snapshot changes (1): title_block_style_none.snap re-baselined from
the styled block to the Pandoc fallback markup (reviewed — the
intended P6 behavior; plain changes no markup by design, so
title_block_style_plain.snap is untouched).

Fixtures: style-none.qmd / style-plain.qmd assertions strengthened
(TDD red first: 5 element checks + CSS negatives failing), new
q2-preview/title-block-style-none.qmd.

Verified end-to-end via cargo run --bin q2 -- render: none emits the
fallback header; plain and none CSS carry 0 quarto-title-meta-heading
rules vs 1 in a default-doc control. Full workspace tests (10158) and
cargo xtask verify --skip-hub-mcp-tests green (skipped leg = known
dead-sync-server timeouts).

Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ancillary design doc for the shared date helper: study of Q1's date
subsystem (core/date.ts, pandoc.ts pre-render rewrite, listing record
pre-formatting, documentTitleMetadata's forced long, setDateLocale)
and the quarto-web dates reference, plus a proposed familiar-not-
byte-compatible Q2 design. Key finding: Q1 formats every date before
templating — EJS never formats — so doctemplates being logic-less is
no obstacle; a Normalization-phase transform is structurally Q1's own
position. Design draft only; execution awaits approval.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ISO-week tokens (W WW GGGG) join the day-one subset (time provides
iso_week without locale data); locale-week (w ww wo gggg) and
named-timezone (z zzz) tokens stay deferred with diagnostics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implement the approved date design (claude-notes/plans/
2026-07-17-date-formatting-design.md). Key architectural point,
from the design study: Q1 formats every date BEFORE templating (its
EJS never formats — records are pre-formatted in TS, and pandoc.ts
rewrites date/date-modified in metadata pre-Pandoc), so Q2's
logic-less doctemplates need no new capability; a Normalization
transform is structurally Q1's own position.

- New crates/quarto-core/src/dates.rs: Q1's parse-form list
  (MM/DD/YYYY et al + ISO timestamps; NO guessing tail — a
  diagnostic names the accepted forms instead of Q1's moment-guess),
  named styles full/long/medium/short/iso (English-only per epic Q3;
  locale joins the localization design), and a day.js token
  formatter with [...] escapes. Token scope per Carlos: everything
  without i18n design cost — includes ISO-week W/WW/GGGG; deferred
  with warnings: locale-week w/ww/wo/gggg and named-tz z/zzz (tz
  database). Non-token characters pass through literally (day.js
  semantics, e.g. the T in YYYY-MM-DDTHH:mm:ssZ). Unit matrix
  mirrors Q1's docs-page examples table.
- New DateNormalizeTransform (Normalization, before
  AuthorsNormalize): resolves today/now (UTC via the WASM-safe
  SystemRuntime::unix_timestamp — documented deviation from Q1's
  local time) and last-modified (VFS-aware runtime mtime); writes
  ISO date-meta/date-modified-meta (explicit value wins, the
  description-meta precedent) and replaces date/date-modified in
  place with the formatted string. Precedence: field-local
  {value,format} > date-format > default, where the default is
  `long` for the styled HTML title block (Q1's
  documentTitleMetadata) and `iso` otherwise/for all formats. The
  head's dcterms.date switches to $date-meta$ — the machine slot
  stays ISO even under date-format (deliberate deviation; Q1 leaks
  the pretty string there). Parse failures diagnose and preserve
  the raw value.
- Listings: date-typed item fields are formatted at record-build
  (finally consuming the parsed-but-unused ListingConfig::date_format;
  doc date-format fallback; Q1's `medium` default); feeds' RFC-2822
  path now parses via the shared module (drift hole closed).
- Preview lockstep (Q9): zero TSX changes by design — the preview
  pipeline runs the transform, so PreviewTitleBlock receives
  formatted strings through its existing meta reads.

Snapshot changes (4, all reviewed): title_block_simple,
title_block_metadata_grid, title_block_banner_true,
title_block_label_overrides re-baselined with formatted dates
(2026-07-01 → "July 1, 2026", 2026-07-10 → "July 10, 2026") —
matching the Q1 extracts captured in the P0 research doc verbatim;
this closes the last visible Q1-vs-Q2 delta from the P0/P5
comparisons. Listing pipeline test pins updated to "Jan 15, 2026".

New fixtures: smoke-all/title-block/date-format.qmd (token format +
ISO dcterms + negative on raw ISO in the body) and
date-default-long.qmd (forced long) — TDD red first (5 regex checks
failing). Playwright title-block sweep green (23 tests; the date
fixtures run under the WASM runner).

Verified end-to-end: `date: today` with
date-format "dddd MMM Do, YYYY" renders
<p class="date">Friday Jul 17th, 2026</p> and
<meta name="dcterms.date" content="2026-07-17T00:00:00+00:00">.
Full workspace tests (10167) and cargo xtask verify
--skip-hub-mcp-tests green (skipped leg = known dead-sync-server
timeouts).

Plan: claude-notes/plans/2026-07-17-date-formatting-design.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two user-facing docs pages, rendered with q2 and modeled on
quarto-web's structure and style (content adjusted to Q2's supported
surface; prose written with the Gopen & Swan reader-expectations
methodology):

- docs/guides/authoring/title-blocks.qmd — overview, the three
  title-block-style options (with a callout that Q1's manuscript
  style is unsupported), structured authors + ref: affiliations,
  banners with custom backgrounds/foreground color, categories,
  dates, the label-override table (Q2's actual defaults, incl.
  auto-pluralization), and the template-partials escape hatch
  (Q1-compatible partial names).
- docs/guides/authoring/dates.qmd — parse forms (+ the
  no-guessing warning behavior), date keywords (+ UTC callout),
  named styles, the supported day.js token table with the deferred
  locale-week/named-tz tokens called out, bracket escaping, and a
  "Where Formatting Applies" section covering the title block,
  listings, and the always-ISO machine slots (dcterms, feeds).

Both pages registered in the docs sidebar; `cargo run --bin q2 --
render docs/` emits zero warnings for the new pages (Q1's
definition-list syntax is unsupported in qmd, so the style list uses
bullets); rendered output inspected in the browser — the pages
dogfood the title-block features they document.

Follow-up strands filed for every deferred item (discovered-from
bd-y71ga2l8): bd-45tfp790 localization design (labels, date locales,
locale-week tokens, local-tz keywords), bd-4j4okt4o manuscript style
(Q6), bd-e2kpwy7n toc-location (unlocks the inert banner toc-left
hook), bd-xva3f8uy quarto-header quarto-banner (needs secondary-nav),
bd-6reut449 citation/scholar meta tags (Q10), bd-a949e2zu editable
React title block (Q9).

Epic plan marked COMPLETE (P0–P7). Workspace tests green (10175).

Plan: claude-notes/plans/2026-07-15-html-title-block-parity.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cscheid
cscheid marked this pull request as ready for review July 17, 2026 15:18
@cscheid cscheid changed the title HTML title-block parity with Quarto 1 (bd-gx9cic8z): P0–P5 HTML title-block parity with Quarto 1 (bd-gx9cic8z) Jul 17, 2026
@cscheid
cscheid merged commit f407bde into main Jul 17, 2026
8 checks passed
@cscheid
cscheid deleted the feature/bd-gx9cic8z-title-block-parity branch July 17, 2026 16:05
cscheid added a commit that referenced this pull request Jul 17, 2026
…e title-block labels via compute_labels (bd-llhlzd7p)

PR #396 landed a partial-based title block whose labels.* metadata is
computed by AuthorsNormalizeTransform::compute_labels with per-document
*-title overrides. That supersedes this branch's template-context labels
helper (removed): compute_labels is now term-aware instead, with
precedence per label: *-title override > language term > English literal.
Terms wired: title-block-author-single/plural, -affiliation-single/plural,
-published, -modified, -keywords, section-title-abstract. doi and
description keep English literals (no Q1 term key exists — Q1 hardcodes
them too).

Post-merge: quarto-core suite (2579), localization smoke fixtures, and
full workspace (10207) green; Spanish end-to-end render re-inspected
(Autor/a, Fecha de publicación, Resumen through the new partials).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

2 participants