Symptom
The cover-page subtitle v<version> (<sha>) reads the short HEAD of the outer repo checkout that ran doc_build, regardless of which content ref is actually being rendered. When the outer HEAD happens to match the content ref (e.g., a regular build_docs.yml checkout of the same ref it builds), the subtitle looks correct. As soon as outer HEAD diverges from the content ref, the subtitle is wrong on every produced PDF.
The most common case this surfaces in is --diff <from> <to>, where all three rendered PDFs (before / after / diff) get the same outer-HEAD SHA on the cover. Notably this includes after_<to_short>.pdf — the file we typically rename to aousd_core_spec_<version>_<to_short>.pdf and ship as the standalone draft candidate. So the bug isn't cosmetic to the visual diff PDF; it taints the headline spec artifact too.
Concrete repro from a recent core-spec-wg run:
| File |
Filename SHA |
Cover-page SHA |
aousd_core_spec_1.1.0_e98ceb3.pdf (regular build, outer HEAD = e98ceb3) |
e98ceb3 |
e98ceb3 ✓ |
aousd_core_spec_1.1.0_60e060e.pdf (after-render from --diff, outer HEAD = 37cccfc) |
60e060e |
37cccfc ✗ |
aousd_core_spec_1.1.0_diff_e98ceb3_to_60e060e.pdf (diff render, same workflow) |
e98ceb3→60e060e |
37cccfc ✗ |
In other words: filenames are correct because generate_combined_diff resolves from_ref / to_ref through commit_hash(ref, repo_root, short=True) (doc_builder.py:654-655), but the cover-page subtitle never sees those.
Repro
git checkout <some_branch_with_HEAD=A>
pixi run main build --diff <ref_with_SHA=B> <ref_with_SHA=C>
# All three of build/diff_from/before_*.pdf, build/diff_to/after_*.pdf,
# build/diff/diff_*.pdf show "v<ver> (<short of A>)" on the cover.
# Expected: before -> short of B, after -> short of C, diff -> some
# representation of B->C.
Root cause
_render_combined is the only renderer; it's called three times in diff mode (doc_builder.py:259-282), all on the outer builder. It computes the subtitle by calling self.get_subtitle(spec):
# doc_builder.py:308-327
def _render_combined(self, args, combined, filename, *, ..., output_dir=None, from_pretty=None, to_pretty=None):
...
spec = self.get_metadata_defaults_file()
subtitle = self.get_subtitle(spec)
get_subtitle reads HEAD of the outer repo, ignoring whatever ref the combined markdown was actually flattened from:
# doc_builder.py:917-922
def get_subtitle(self, defaults_file_path: Path):
with open(defaults_file_path, \"r\") as f:
spec_data = yaml.load(f, Loader=yaml.SafeLoader)
commit = git_utils.commit_hash(\"HEAD\", self.get_repo_root(), short=True)
subtitle = f\"v{spec_data['metadata']['version']} ({commit})\"
return subtitle
_build_combined_for_ref correctly creates an inner builder rooted at the ref's worktree (doc_builder.py:638-647), but that inner builder is only used for the markdown flatten/preprocess step. The PDF render that produces the cover still runs on the outer builder.
This is the same shape as the prior #90 bug (parent args not forwarded to per-ref renders) that #85 fixed.
Suggested fix
Thread a per-render subtitle through _render_combined so each render gets the SHA of its own content ref:
before -> from_ref
after -> to_ref
diff -> to_ref for the headline SHA (or a <from_short> -> <to_short> form, since from_pretty / to_pretty are already passed through)
- regular build -> unchanged (defaults to current behavior of reading outer HEAD)
Two reasonable shapes:
- Optional
subtitle: Optional[str] = None parameter on _render_combined; get_subtitle retained as the default when caller doesn't pass one. Diff path computes the right value per render.
- Optional
subtitle_ref: Optional[str] = None parameter; get_subtitle(spec, ref=subtitle_ref or \"HEAD\"). Slightly more invasive on get_subtitle but keeps the formatting logic in one place.
Either is fine; #2 keeps the subtitle string format ("v{version} ({short})") authoritative in get_subtitle.
Impact
Any consumer of the diff workflow (e.g., core-spec-wg's build_diff.yml) ends up with wrong SHAs on:
- the diff PDF cover (visible to anyone scanning red/green deltas), AND
- the after-render PDF cover (visible on the file we ship as the standalone candidate spec, since that's what we rename and distribute)
Filename and rendered content are correct; only the embedded subtitle is wrong. Because the after-render is what people use as the de facto authoritative artifact, the misleading SHA propagates anywhere that PDF is shared.
Symptom
The cover-page subtitle
v<version> (<sha>)reads the short HEAD of the outer repo checkout that randoc_build, regardless of which content ref is actually being rendered. When the outer HEAD happens to match the content ref (e.g., a regularbuild_docs.ymlcheckout of the same ref it builds), the subtitle looks correct. As soon as outer HEAD diverges from the content ref, the subtitle is wrong on every produced PDF.The most common case this surfaces in is
--diff <from> <to>, where all three rendered PDFs (before / after / diff) get the same outer-HEAD SHA on the cover. Notably this includesafter_<to_short>.pdf— the file we typically rename toaousd_core_spec_<version>_<to_short>.pdfand ship as the standalone draft candidate. So the bug isn't cosmetic to the visual diff PDF; it taints the headline spec artifact too.Concrete repro from a recent core-spec-wg run:
aousd_core_spec_1.1.0_e98ceb3.pdf(regular build, outer HEAD = e98ceb3)aousd_core_spec_1.1.0_60e060e.pdf(after-render from--diff, outer HEAD = 37cccfc)aousd_core_spec_1.1.0_diff_e98ceb3_to_60e060e.pdf(diff render, same workflow)In other words: filenames are correct because
generate_combined_diffresolvesfrom_ref/to_refthroughcommit_hash(ref, repo_root, short=True)(doc_builder.py:654-655), but the cover-page subtitle never sees those.Repro
Root cause
_render_combinedis the only renderer; it's called three times in diff mode (doc_builder.py:259-282), all on the outer builder. It computes the subtitle by callingself.get_subtitle(spec):get_subtitlereads HEAD of the outer repo, ignoring whatever ref thecombinedmarkdown was actually flattened from:_build_combined_for_refcorrectly creates an inner builder rooted at the ref's worktree (doc_builder.py:638-647), but that inner builder is only used for the markdown flatten/preprocess step. The PDF render that produces the cover still runs on the outer builder.This is the same shape as the prior #90 bug (parent args not forwarded to per-ref renders) that #85 fixed.
Suggested fix
Thread a per-render subtitle through
_render_combinedso each render gets the SHA of its own content ref:before->from_refafter->to_refdiff->to_reffor the headline SHA (or a<from_short> -> <to_short>form, sincefrom_pretty/to_prettyare already passed through)Two reasonable shapes:
subtitle: Optional[str] = Noneparameter on_render_combined;get_subtitleretained as the default when caller doesn't pass one. Diff path computes the right value per render.subtitle_ref: Optional[str] = Noneparameter;get_subtitle(spec, ref=subtitle_ref or \"HEAD\"). Slightly more invasive onget_subtitlebut keeps the formatting logic in one place.Either is fine; #2 keeps the subtitle string format ("v{version} ({short})") authoritative in
get_subtitle.Impact
Any consumer of the diff workflow (e.g., core-spec-wg's
build_diff.yml) ends up with wrong SHAs on:Filename and rendered content are correct; only the embedded subtitle is wrong. Because the after-render is what people use as the de facto authoritative artifact, the misleading SHA propagates anywhere that PDF is shared.