Skip to content

feat(cv): publish CV variants and explain empty selections - #15

Merged
eduardstan merged 3 commits into
mainfrom
fm/lp-cv-variants-implement
Jul 30, 2026
Merged

eduardstan merged 3 commits into
mainfrom
fm/lp-cv-variants-implement

Conversation

@eduardstan

Copy link
Copy Markdown
Owner

Intent

Publish all three bundled CV variants from the deploy workflow, and stop a bundled variant from failing silently on a stranger's record.

Two captain decisions land here. Scope was corrected before work started: the variant machinery (cv/short.tex, cv/teaching.tex, cv/supervision.tex, cv/preamble.tex, cv/header.tex, and the short and teaching baselines) already exists on main and must NOT be rebuilt.

Part 1 - publish all three. .github/workflows/deploy.yml built cv.tex alone and staged one PDF, so the two variants built for review in cv.yml never reached a reader. It now builds all three, checks each baseline, and stages them as cv.pdf, cv-short.pdf and cv-teaching.pdf. Deliberate naming decision: cv.pdf keeps the exact address every existing link and the check-deployment-base assertion already use, and the cv- prefix means a downloaded variant still says 'CV' once it has left the site (a bare short.pdf would not). The full CV deliberately STAYS the primary link on /cv/; the two variants are secondary links beside it, each rendered only when its file is really staged, so a repository whose workflow builds only cv.tex still shows exactly one link as before. A new test in scripts/build-cv-data.test.mjs fails when deploy.yml and cv.yml disagree about the document set, since one builds for review and the other alone publishes. The link blurbs deliberately describe what each variant curates rather than a page count: length depends on the adopter's record, and AGENTS.md forbids hand-written numbers the build never derived (short.pdf is in fact 1 page on the bundled record, not 2).

Part 2 - make a variant fail loudly rather than emptily. A bundled variant references record fields a stranger will not have. The prose case was already handled by the \ifx ... \cvempty idiom and was verified to still work both ways (teaching_statement, Short Bio and Research Focus headings all vanish when absent). The real work was the bibliography case: a \printbibliography whose filter matches nothing prints nothing at all, its own heading included, so cv/short.tex's hand-written 'Selected Publications' section left a title over silence for any adopter with publications but nothing marked 'selected'. New \cvbibfiltered in cv/preamble.tex prints such a block and, when nothing matched, repeats the heading biblatex swallowed and names the filter. Deliberate decision, argued rather than dictated: a one-line placeholder, NOT a hard build failure - an adopter who has simply not marked any work yet has a valid record, and a variant they never asked for must not stop their CV from building. The generated sections in cv/generated/cv-data.tex are deliberately exempt and must stay so, because cv.tex prints one heading over the whole sequence, so a section matching nothing correctly leaves no trace there.

Constraints the user imposed: the full CV must not move (data/cv-baseline/cv-baseline.txt still passes byte-exact and the page count is unchanged - verified, all three baselines pass byte-exact, cv.pdf still 3 pages); apply ponytail laziness - no new content-interface field, no configuration key, no registry, just a workflow change, two links and one guard; do not create a root CLAUDE.md or any root instruction pointer; invent no real organisations in the record (the record was just swept clean of them).

Verification already performed: all three PDFs build and reach web/public/assets/; /cv/ checked in a real Chrome browser under the real /ledgerpress/ deployment base - 3 PDF links, all HTTP 200, served bytes cmp-identical to the built PDFs; cold-start proof done against a minimal record (profile and appointments only, no teaching_statement, no selected keywords) showing the reader sees a named placeholder instead of a silent empty heading; the new guard test was mutation-checked and fails when the guard is reverted; scripts/check-cv-baseline.sh (all three), scripts/check-adopter-build.mjs, scripts/check-deployment-base.mjs, npm test and the full npm run check all pass.

Docs were updated to match: README.md, web/README.md, and AGENTS.md (its Delivery section and one new load-bearing constraint), plus .gitignore for the two new staged names.

What Changed

  • Build, baseline-check, and publish the full, short, and teaching CVs, with conditional variant links beside the primary full-CV download.
  • Add \cvbibfiltered so hand-authored filtered sections show a named placeholder when no bibliography entries match.
  • Add workflow-parity and empty-filter regression coverage, and update the related documentation and staged-asset ignores.

Risk Assessment

✅ Low: The two-line fix correctly triggers the CV workflow for deploy-only changes, closes the prior guard gap, and introduces no new source risk.

Testing

Focused guard tests passed; all three XeLaTeX documents built and matched their byte-exact baselines (full CV remained 3 pages); real /ledgerpress/ builds showed three working byte-identical PDF downloads and the correct full-only fallback; a no-selection short CV visibly named the unmatched filter; evidence was captured and the worktree was left clean at the target commit.

  • Evidence: CV page with all three downloads (local file: /tmp/no-mistakes-evidence/01KYSSQF6H3EHV34BW0TF5PWPF/cv-page-three-downloads.png)
Evidence: Built full CV
%PDF-1.5
%

... [56203 bytes truncated] ...

�]�MK
endstream
endobj
startxref
55603
%%EOF
Evidence: Built short CV
%PDF-1.5
%

... [43082 bytes truncated] ...


endstream
endobj
startxref
42578
%%EOF
Evidence: Built teaching CV
%PDF-1.5
%

... [43432 bytes truncated] ...


endstream
endobj
startxref
42926
%%EOF
Evidence: Published PDF download verification

All three URLs returned HTTP 200 and were byte-identical to the corresponding built PDFs.

http://127.0.0.1:4321/ledgerpress/assets/cv.pdf -> HTTP 200, 56258 bytes
http://127.0.0.1:4321/ledgerpress/assets/cv-short.pdf -> HTTP 200, 43132 bytes
http://127.0.0.1:4321/ledgerpress/assets/cv-teaching.pdf -> HTTP 200, 43482 bytes
All three served PDFs are byte-identical to their built documents.
- Evidence: CV page fallback with only canonical PDF staged (local file: /tmp/no-mistakes-evidence/01KYSSQF6H3EHV34BW0TF5PWPF/cv-page-full-only.png) - Evidence: Short CV showing named empty-selection placeholder (local file: /tmp/no-mistakes-evidence/01KYSSQF6H3EHV34BW0TF5PWPF/short-no-selected.png)
Evidence: Short CV built without selected publications
%PDF-1.5
%

... [43227 bytes truncated] ...

54
endstream
endobj
startxref
42719
%%EOF

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ scripts/build-cv-data.test.mjs:555 - This new guard reads deploy.yml, but its CI owner (cv.yml) does not include deploy.yml in either path filter, while deploy.yml runs only web tests. A deploy-only change can therefore make the document sets disagree with all triggered checks green. Add .github/workflows/deploy.yml to both cv.yml path lists or execute this root test from deploy.yml.

🔧 Fix: Trigger CV workflow for deploy workflow changes
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • npm ci and npm --prefix web ci (test setup)
  • node --test --test-name-pattern='both workflows build every printed document|cv/.*announces a filtered bibliography|cvbibfiltered prints' scripts/build-cv-data.test.mjs
  • latexmk -xelatex -cd cv/cv.tex
  • latexmk -xelatex -cd cv/short.tex
  • latexmk -xelatex -cd cv/teaching.tex
  • bash scripts/check-cv-baseline.sh
  • bash scripts/check-cv-baseline.sh cv/short.pdf
  • bash scripts/check-cv-baseline.sh cv/teaching.pdf
  • Workflow-equivalent staging followed by LEDGERPRESS_SITE='https://eduardstan.github.io/ledgerpress/' npm --prefix web run build
  • Real Chrome verification at http://127.0.0.1:4321/ledgerpress/cv/ under the /ledgerpress/ base
  • Downloaded all three rendered PDF links with curl, confirmed HTTP 200, and compared each response byte-for-byte with cmp
  • Removed only staged variant PDFs, rebuilt, and verified Chrome rendered exactly the canonical cv.pdf link
  • Temporarily removed all selected keywords, rebuilt cv/short.tex, and visually/textually verified the placeholder names shortselected and cv/short.tex
  • Restored the record and removed all generated worktree artifacts; final git status --short --ignored was empty
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

eduardstan and others added 3 commits July 30, 2026 17:17
The deploy workflow built cv.tex alone and staged one PDF, so the two
bundled variants built for review in cv.yml and never reached a reader.
It now builds all three, checks each baseline, and stages them as
cv.pdf, cv-short.pdf and cv-teaching.pdf: cv.pdf keeps the address every
existing link uses, and the cv- prefix keeps a variant saying what it is
once it has left the site. /cv/ keeps the full CV as its primary
download and offers each variant beside it, only when that file is
really staged. A test fails when the two workflows disagree about the
set, since one builds for review and the other alone publishes.

A \printbibliography whose filter matches nothing prints nothing at all,
its own heading included, so cv/short.tex's hand-written "Selected
Publications" section left a title over silence for any adopter with
publications but nothing marked `selected`. \cvbibfiltered now prints
such a block and, when nothing matched, repeats the heading biblatex
skipped and names the filter. It does not fail the build: an adopter who
has marked nothing yet has a valid record, and a variant they never
asked for must not stop their CV from building.

The full CV is unmoved — all three baselines still pass byte-exact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@eduardstan
eduardstan merged commit 43af96c into main Jul 30, 2026
3 checks passed
eduardstan added a commit that referenced this pull request Jul 31, 2026
* feat(cv): publish all three CVs and announce an empty filtered section

The deploy workflow built cv.tex alone and staged one PDF, so the two
bundled variants built for review in cv.yml and never reached a reader.
It now builds all three, checks each baseline, and stages them as
cv.pdf, cv-short.pdf and cv-teaching.pdf: cv.pdf keeps the address every
existing link uses, and the cv- prefix keeps a variant saying what it is
once it has left the site. /cv/ keeps the full CV as its primary
download and offers each variant beside it, only when that file is
really staged. A test fails when the two workflows disagree about the
set, since one builds for review and the other alone publishes.

A \printbibliography whose filter matches nothing prints nothing at all,
its own heading included, so cv/short.tex's hand-written "Selected
Publications" section left a title over silence for any adopter with
publications but nothing marked `selected`. \cvbibfiltered now prints
such a block and, when nothing matched, repeats the heading biblatex
skipped and names the filter. It does not fail the build: an adopter who
has marked nothing yet has a valid record, and a variant they never
asked for must not stop their CV from building.

The full CV is unmoved — all three baselines still pass byte-exact.

* no-mistakes(review): Trigger CV workflow for deploy workflow changes

* no-mistakes(document): Refresh CV publication and filter documentation

---------
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