Expand description
Cross-source diagnostic coalescing.
When a single underlying problem produces a diagnostic on many
pages — for example, one bad theme: key in _quarto.yml
triggering Q-14-1 once per rendered
page — the renderer should collapse them into a single emission
that lists the affected pages, rather than printing the same
ariadne block hundreds of times.
§The primary key is the source location
Two diagnostics whose location resolves to the same source
span in the same file are presumed to be the same error and are
grouped together. We deliberately do not include the code or
title in the grouping key — the source location alone is the
relation’s primary key (decision recorded in
claude-notes/plans/2026-05-22-theme-diagnostic-epic.md).
If two unrelated checks ever land at the same span this is a
design risk; the v1 cost (one merged emission with a possibly
mixed-content representative) is low. We will widen the key to
(location, code) if it turns out to bite.
§File identity is the resolved path, not the raw FileId
A raw FileId is only globally meaningful when it is hash-based
(path-derived, e.g. quarto_yaml::file_id_for_filename).
Sequential per-context ids are not: every document’s primary file
is FileId(0) in its own SourceContext, so keying on the raw
id would falsely merge diagnostics from different files that
happen to sit at identical byte offsets.
Each input entry carries its own Option<SourceContext>, so the
group key resolves the file component through it: if the
location’s FileId is registered in the entry’s context, the key
is the registered file path; otherwise it falls back to the
raw id (hash-based ids that aren’t registered in per-document
contexts stay stable and collision-safe). The two key flavors
never compare equal to each other.
Both fallback edges fail toward splitting groups, never toward false merges:
- paths are compared verbatim (no canonicalization), so two
contexts registering the same file under different spellings
(
./_quarto.ymlvs_quarto.yml) form two groups; - the same id resolving in one entry’s context but not another’s (e.g. one entry has no context at all) forms two groups.
§What does not coalesce
Diagnostics whose location is one of:
None,SourceInfo::Concat, orSourceInfo::FilterProvenance,
pass through as singleton groups (one entry each). These shapes
don’t reduce to a single contiguous byte range, so we can’t form
a stable group key for them. This is the same conservative
contract as SourceInfo::resolve_byte_range.
Structs§
- Coalesced
Diagnostic - One entry from a coalesced render summary.
Constants§
- AFFECTED_
FILES_ CAP - Maximum number of file names rendered inline in the “Affected files:” tail before switching to “… (and N others)”.
Functions§
- coalesce_
by_ source - Group the input by source location and return one
CoalescedDiagnosticper group, in encounter order.