Skip to content

ci(book): Eisvogel 3.5.1 for pandoc 3.6.1, and let the workflow test itself - #135

Open
Kartikey1306 wants to merge 11 commits into
embeddedos-org:masterfrom
Kartikey1306:ci/book-pdf-eisvogel-3
Open

Kartikey1306 wants to merge 11 commits into
embeddedos-org:masterfrom
Kartikey1306:ci/book-pdf-eisvogel-3

Conversation

@Kartikey1306

@Kartikey1306 Kartikey1306 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Stacked on #115 (origin/master does not configure without it, and ci.yml/build.yml are not path-filtered — off master this PR would go red on jobs it never touches). Review e152d8e..abf0522 for this change: five commits, one file, .github/workflows/book-build.yml. Land #115 first. (Restacked from #115's previous head a276016 after its rebase onto master 682d005; the earlier range a276016..5e4a84c no longer applies.)

Closes #134

Problem

No run of Build & Release Book PDF in this repository's history has succeeded — every run since the step was added (ef0dc50, 2026-04-25) is failure or cancelled, from the May release runs (1bc7641, fa2b3b1) to master 84bbef0 on 09-08. Older logs have expired; every readable one dies with:

! LaTeX Error: Command \chead already defined.
Error producing PDF.
##[error]Process completed with exit code 43

The workflow installs pandoc 3.6.1 from the release .deb and Eisvogel 2.4.0, which predates pandoc 3.6. The 3.x line merges pandoc's default template through 3.6.1 and later (its CHANGELOG names each merge) and states pandoc 3 compatibility. The LaTeX-level cause was not known when this PR was opened; run 2 established it (see Verification) — it is this workflow's own header-includes, not the template version.

Change

  • The raw -V "author=Srikanth Patchava & EmbeddedOS Contributors" override is removed — a -V value reaches LaTeX unescaped and & is an alignment tab; the identical author in book.md's front matter is escaped by pandoc and is now the one source.
  • The injected fancyhdr header block is removed; header and footer go through Eisvogel's header-left, header-right and footer-center variables (page number is the template's default). This is the fix.
  • Eisvogel 2.4.0 → 3.4.0, as EISVOGEL_VERSION beside PANDOC_VERSION. The 3.x tarball extracts into Eisvogel-<v>/, not flat, so the copy names the directory — a bare version bump would have failed at the cp. Why 3.4.0 and not 3.5.1: the first run of this PR pinned 3.5.1 and got past the template clash — \chead already defined was gone — then failed on File sourcesans.sty' not found. Eisvogel 3.5.0 (2026-06-28) migrated its default font from the sourcesanspropackage tosourcesans, which the runner's texlive-fonts-extra (ubuntu-latest, 24.04 per the run log) does not ship. 3.4.0 is the last release on sourcesanspro(present intexlive-fonts-extra`, checked against the package's file list) and already carries pandoc's default template merged through 3.9.
  • No more tar xzf … 2>/dev/null || true. That was fail-open on the exact step that breaks: a missing or reshaped tarball failed silently and the diagnostic landed on the cp after it.
  • The workflow is added to its own paths: filter for push and pull_request. It fired only on docs/book/**, so a workflow-only change — this one included — could not get the run that proves it.

Verification

# the new install step, run verbatim against the real release (wget shimmed to curl on this Mac)
Eisvogel 3.5.1 template installed
rc=0  template bytes: 29929

# the OLD step's copy against the 3.x layout
cp: eisvogel.latex: No such file or directory

# parsed structure, asserted (not parse success)
push.paths == ['docs/book/**', '.github/workflows/book-build.yml']   pull_request.paths == same
push.tags == ['v*']   push.branches == ['master', 'main']   release.types unchanged   workflow_dispatch present
job list unchanged; template step contains no "|| true"

Run 1 (d42fa57, Eisvogel 3.5.1): Build PDF ❌ — sourcesans.sty not found (line ~672 of the template; 3.5.x needs a font package TeX Live 2021 lacks).

Run 2 (4be6d7b, Eisvogel 3.4.0): Build PDF ❌ — \chead already defined, exactly as master. (Correction to an earlier version of this body, which said run 1 showed "the template clash is gone": it showed no such thing — LaTeX had died on the font before ever reaching the header block at ~890.)

What run 2 established: the clash is not in the Eisvogel version at all. This workflow injects \usepackage{fancyhdr} + \fancyhead/\fancyfoot through header-includes, and Eisvogel builds its own header with KOMA's scrlayer-scrpage, which defines \chead. The template places $header-includes$ (line 541) before its header block (~890), so fancyhdr defines \chead first and scrlayer-scrpage's \newcommand fails. Two header packages, one command — both arrived in ef0dc50, which is why no run ever passed on any pandoc/Eisvogel pair.

Run 3 (5e4a84c): the fancyhdr block gone, header/footer through the template's own variables. Build PDF ❌ — but a different error, six seconds in, past the whole preamble: Misplaced alignment tab character & in Srikanth Patchava & EmbeddedOS Contributors. The step passed -V "author=…" raw, and a -V value is inserted into the LaTeX verbatim; book.md's metadata already carries the same author and is escaped by pandoc. Earlier runs never reached this line.

Run 4 (358009e): the -V author override removed. Build PDF ✅ — the first successful run in this job's history (run 34937342076): Validate Book Source, Build PDF, Verify PDFeBoot-guide.pdf (760K, 48 pages, 777012 bytes) — and Upload PDF artifact all success; build-pdf ran, it was not skipped on has_book.

Run 5 (abf0522, the head): one comment line corrected — run 4's log shows Image: ubuntu-24.04, not the 22.04 / TeX Live 2021 I had written. ✅ again: run 34937741463, eBoot-guide.pdf (760K, 48 pages, 777043 bytes).

Not run locally: the PDF itself — no xelatex on this host. The evidence is the two green runs above, on 358009e and on the head abf0522, with build-pdf executed (not skipped) in both.

Elsewhere

ebuild carries the identical step (book-build.yml:100) and is red the same way; the port waits for this run. eos is green only because its copy installs apt's pandoc 2.9 and no Eisvogel at all — its PANDOC_VERSION is dead — so it is not evidence for any pair. eBoot #133 is currently the only open PR that triggers this job; its Build PDF red is this defect, inherited.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

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

Files with missing lines Patch % Lines
tests/unit/test_fw_update_test_sigs.py 93.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@srpatcha srpatcha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — eBoot#135 "ci(book): Eisvogel 3.5.1 for pandoc 3.6.1, and let the workflow test itself"

head: d42fa57 author: Kartikey1306 ci: failBuild PDF red, 25 green (Attach PDF to Release, Create GitHub Release, Update Dev PDF, assign skipped)

Verdict: First look. The diagnosis is right, the change is a real step forward, and the body is
honest about what it had not yet proved — it says the PDF build was NOT RUN and promises to cite
the run or say what it failed on. That run has now happened and nobody has reported it, so here it
is: the template bump works and the build still fails. The \chead already defined error is
gone; Build PDF now dies on ! LaTeX Error: File 'sourcesans.sty' not found. at the same exit 43.
The PR does not achieve what it sets out to do, and needs one more step before it is worth merging.
Separately, and this is the reason the workflow could stay red since April: no status check is
required to merge to master in this repository.
I checked both the classic protection API and
rulesets.

Findings

# Severity File:line Finding Recommended fix
1 High (P1) .github/workflows/book-build.yml:101-123 Build PDF is still red on this PR's own head; Eisvogel 3.5.1 is necessary but not sufficient. Job 104160744680, run 34899177674, 2m40s: the template installs cleanly (Eisvogel 3.5.1 template installed, and the new cp Eisvogel-3.5.1/eisvogel.latex resolves, so the versioned-directory fix is correct), pandoc gets past the preamble, and then Error producing PDF. ! LaTeX Error: File 'sourcesans.sty' not found.exit code 43. The failure moving is itself the evidence the bump worked — I read the log on #133, which carries the old 2.4.0 step, and it dies earlier with ! LaTeX Error: Command \chead already defined. at l.1560 ...nel@ifstar {\@dblarg\@@@chead}{\@chead}}. So this PR converted a template/pandoc incompatibility into a missing font dependency: Eisvogel 3.x pulls in a typeface the 2.4.0 template did not, and the install step's texlive-fonts-recommended/texlive-fonts-extra/texlive-latex-extra set does not supply this one. --pdf-engine=xelatex is used at :168 with no mainfont/monofont variable among the twenty -V flags at :175-194, so the template's default typeface is what gets loaded. Two ways, both one step: (a) install the style — add a diagnostic to the install step so the answer is recorded rather than guessed (kpsewhich sourcesans.sty || tlmgr search --global --file sourcesans.sty), then add the package it names to the apt-get install list; or (b) stop depending on it — pass -V mainfont=... and -V monofont=... naming fonts already in the image, which is the smaller diff and removes a dependency on a template default that can change again on the next bump. I would take (b) and pin the fonts explicitly, since the whole lesson of this PR is that the template's defaults are not a stable interface. Either way, the fix is not merged until the run is green — this PR's own body sets that standard and it should be held to it.
2 High (P1) — repo-level, pre-existing, not introduced by this PR branch protection on embeddedos-org/eBoot@master No CI check is required to merge. Every one of the 26 checks on these PRs is advisory. GET /repos/embeddedos-org/eBoot/branches/master/protection returns required_pull_request_reviews (1 approval, dismiss-stale, require-last-push-approval), required_linear_history, required_conversation_resolution, allow_force_pushes: false — and no required_status_checks object at all. I checked the newer mechanism too, in case protection had been migrated: GET /repos/.../rules/branches/master returns exactly one rule type, copilot_code_review. So Build & Test (Linux x86_64), CodeQL, Host Build & Tests, Fuzz Harness Build and Build PDF can all be red and a PR still merges on one approval. This is the mechanism behind the very problem this PR fixes: gh run list --workflow book-build.yml shows 15 of 15 visible runs failure or cancelled, back through v1.4.0 and v1.5.0 in May 2026 — nothing ever had to stop, so nothing did. On a repository whose product is a bootloader, and in a batch that already contains a Critical finding (#129 finding 1, still open), a green wall that cannot block anything is worth more than a footnote. .ai/autoreview/apply-required-checks.sh already exists in this tree, which suggests the gap is known. Someone with admin should run it, or set required_status_checks.contexts to at least CI Gate, Host Build & Tests, Build & Test (Linux x86_64), Static Analysis (cppcheck + clang-tidy) and CodeQL. I did not run it: it mutates repository settings, which is outside what an unattended review should do on its own initiative, and choosing which contexts become blocking is a maintainer's call — Build PDF in particular should probably not be required until finding 1 is closed, or every PR in the repo goes red.

What this PR gets right

Three things, and the third is the one I would keep even if the rest were rewritten.

The diagnosis is properly bounded. The body says "the LaTeX-level cause of the clash is not
established here — both templates use \chead*, and pandoc 3.6.1's own default template contains no
\chead — so I am not claiming a mechanism"
, and the step comment repeats it. That is §28's
evidence policy applied to a CI fix, and it is rarer than it should be. I verified the surrounding
factual claim independently: 15 of 15 visible book-build.yml runs are failure or cancelled,
including both May release tags.

The || true is gone. tar xzf Eisvogel-2.4.0.tar.gz 2>/dev/null || true was fail-open on
precisely the step that breaks — a missing or reshaped tarball failed silently and surfaced as a
confusing cp error one step later. Removing it is a strengthened check, the opposite of the
weakening .ai/reviewer.md asks reviewers to hunt for, and it is what turned the 3.x layout change
into a caught problem rather than a mystery.

Adding the workflow to its own paths: filter is the durable part. The job fired only on
docs/book/**, so a workflow-only change — this one included — could not be tested by the thing it
changes. It now can be, and the proof is finding 1: this PR's own run is what shows the fix is
incomplete. A change that makes its own inadequacy visible on the first try has earned its place
regardless of what happens to the other two lines.

Verification performed for this review

No local build: there is no pandoc, xelatex or TeX distribution on this host, so the PDF path cannot
be exercised here at all. Everything below is from the repository, the GitHub API, and the two
failing jobs' logs, read rather than summarised from the checks table. The user's eBoot checkout
was not touched; nothing was committed or pushed. This review covers a276016..d42fa573 (one commit,
one file); the rest of the bundle diff belongs to #115.

Check Result
Build PDF on this head — log read (job 104160744680) Eisvogel 3.5.1 template installed ✅ → Error producing PDF. ! LaTeX Error: File 'sourcesans.sty' not found.##[error]Process completed with exit code 43. Finding 1.
Build PDF on #133 — log read (job 104156749612, old 2.4.0 step) ! LaTeX Error: Command \chead already defined. at l.1560 ...nel@ifstar {\@dblarg\@@@chead}{\@chead}}, exit 43. Confirms the two failures are different and the template bump advanced past the first.
gh run list --workflow book-build.yml --limit 15 15/15 failure or cancelledci/book-pdf-eisvogel-3, build/security-options-wired-to-nothing, master (09-08), fix/eboot-test-issue ×5, v1.5.0 ×3, v1.4.0 ×3. The body's "no run has ever succeeded" is supported for every run still visible.
GET /repos/embeddedos-org/eBoot/branches/master/protection no required_status_checks; 1 required approval, linear history, conversation resolution. Finding 2.
GET /repos/embeddedos-org/eBoot/rules/branches/master one rule type only: copilot_code_review. Confirms finding 2 is not an artefact of protection having been migrated to rulesets.
Workflow diff read against the job's actual steps EISVOGEL_VERSION: "3.5.1" reaches the step (it is echoed in the log's env block); cp Eisvogel-3.5.1/eisvogel.latex resolves; no || true remains on tar
paths: filter, both triggers push.paths and pull_request.paths both now ['docs/book/**', '.github/workflows/book-build.yml']; push.tags: ['v*'], release.types and workflow_dispatch unchanged. The run existing at all is the practical proof.
pandoc invocation --pdf-engine=xelatex at :168, --template=eisvogel at :170, twenty -V flags at :175-194, no mainfont or monofont — establishes finding 1's recommended fix (b)
mergeStateStatus BLOCKED · reviewDecision: REVIEW_REQUIRED. Given finding 2, the block is the review requirement, not the red check.

Architecture conformance

Conforms, and §21 is the only clause meaningfully engaged: eBoot is Tier 1 Foundation and
.github/workflows/ is Infrastructure within the owning repo, so §21.1 is not in play. §5.1
dependency direction is untouched — nothing compiles, links or ships differently. The design clauses
this PR sits against are §28 and §29. §29 lists the documentation architecture the book is part of,
and a book that has not built since 2026-04-25 means the Concepts, Guides and Operations
material §29 requires exists only as source. §28's evidence table is what the body honours by
refusing to claim a mechanism it had not established — and, applied to the PR itself, is what
finding 1 measures it against: the change is Planned until a green run makes it Implemented,
and it does not have one. Finding 2 sits against §28 more broadly: a status matrix and a CI wall are
both claims about a repository's state, and neither is worth anything if nothing enforces them.

Proposed changes

In this PR, before merge:
  book-build.yml   resolve the font dependency, then re-run and cite a green build-pdf:
                     (b) -V mainfont=... -V monofont=... naming fonts in the image, or
                     (a) kpsewhich sourcesans.sty || tlmgr search --global --file sourcesans.sty
                         in the install step, then add the package it names to apt-get
                   -> the body already sets "the run is the evidence"; hold to it   (finding 1)

Repository setting, a maintainer's call, not this PR:
  branch protection on master   set required_status_checks.contexts, e.g. via the
                                existing .ai/autoreview/apply-required-checks.sh;
                                exclude Build PDF until finding 1 is closed        (finding 2)

Noted by the author, worth not losing:
  ebuild's book-build.yml carries the identical step and is red the same way;
  whatever closes finding 1 should be ported there in the same week.

This branch is stacked on #115 and cannot land before it.

No fix PR opened. Finding 1 is High and the change is one line, which is the shape the brief
allows — but I cannot verify it. There is no pandoc, xelatex or TeX distribution on this host, so
fix-verify.sh could record nothing, and fix-submit.sh correctly refuses a PR with no recorded
verification. Guessing a font package name into a CI file and pushing it unverified is exactly the
failure mode this PR is fixing; the finding names the diagnostic that produces the right answer
instead. Finding 2 is a repository setting, not a diff.

Not checked

  • The PDF build was NOT run, at all. No pandoc, no xelatex, no TeX on this host. Every statement
    about Build PDF comes from the two jobs' logs.
  • Which package supplies sourcesans.sty is NOT established. I did not resolve it — no TeX
    installation here to query and no network package index available in this run — which is why
    finding 1's fix (a) is written as a diagnostic to run rather than a package name to add. Asserting
    one would be a guess.
  • That fix (b) works is Inferred, not Verified. Eisvogel honours mainfont/monofont and the
    invocation sets neither, so overriding them should bypass the template default; I have not proved
    that the 3.5.1 template has no other unconditional font \usepackage.
  • Runs older than the 15 listed were not examined — the author says their logs have expired and I
    did not attempt to retrieve them. The claim "no run has ever succeeded" is Verified for everything
    the API still returns.
  • ebuild's copy of this workflow was not inspected. The body's claim that it carries the
    identical step and is red the same way is taken on the author's word.
  • eos's copy was not inspected either, so the body's explanation of why that repo is green is
    unverified.
  • The #115 half of the bundle diff was not reviewed here. This review covers a276016..d42fa573
    only — one file.
  • The 25 green checks were not re-run and their logs were not read. In light of finding 2, note
    that none of them would have blocked this PR even if they had been red.

Automated architecture review of d42fa5736845 — scheduled, model claude-opus-5, checked against the EmbeddedOS Master Design v2.0. Advisory only: this reviewer never approves, requests changes, or merges. Reply here to discuss or push back — a wrong finding is a bug worth reporting.

Twenty PRs were merged into master in ninety minutes on 09-07, each on the
base it was written against. Master has not configured, compiled, linked or
passed its tests since. Every nightly and every eos simulation run (which
builds eBoot master) has been red for the same reason.

Configure:
- tests/CMakeLists.txt registered eboot_test_fdt_loader twice. embeddedos-org#84 added it,
  and embeddedos-org#85 -- stacked on embeddedos-org#84 -- re-added it at a different anchor when it was
  replayed onto a master that already had embeddedos-org#84. Same hunk as embeddedos-org#111.

Compile (eboot_core):
- embeddedos-org#55 restored a core/sha512.c from 02b7dac that keeps its byte count in
  ctx->count; the eos_sha512_ctx_t master ships has bitlen[2]/buffer_len
  (embeddedos-org#69/embeddedos-org#93). Back to the pre-embeddedos-org#55 file, blob-identical (d9aa57c).
- embeddedos-org#55's source-list "correction" dropped core/boot_log.c, core/secure_boot.c
  and core/fdt_loader.c, which embeddedos-org#72/embeddedos-org#84 had added after embeddedos-org#55 was written.
  CMakeLists.txt is blob-identical to pre-embeddedos-org#55 again (f8fe6eb).
- embeddedos-org#55 replaced the eos_boot_log_get_head() declaration with a second copy of
  eos_boot_log_read(); embeddedos-org#91 had already fixed the prototype it meant to fix.
  Header restored (964ebb8).
- embeddedos-org#94 and embeddedos-org#105 each repaired the Ed25519 verifier and each added an identical
  static scalarbase(); both merged. One copy removed.
- The same pair each added k_low_order[]/messages[] to test_ed25519.c. The
  embeddedos-org#105 copy is removed; embeddedos-org#94's stays because it also carries k_non_canonical[].

Tests that stopped passing because two merged PRs disagree on behaviour:
- embeddedos-org#104 verifies the image signature at install unconditionally, before the
  anti-rollback check embeddedos-org#103 added, so embeddedos-org#103's unsigned images are refused as
  EOS_ERR_SIGNATURE before they can be refused as EOS_ERR_ANTI_ROLLBACK, and
  test_fw_transport's XMODEM install can no longer finalize. Both suites now
  stream genuinely signed images. eBoot has no Ed25519 signer in C, so
  tools/gen_fw_update_test_sigs.py signs the exact header prefixes those
  suites build under the RFC 8032 section 7.1 TEST 1 key and emits
  tests/vectors/fw_update_test_sigs.h; the suites serve that key from a
  simulated OTP slot 0. Negative control: one flipped signature byte fails
  test_write_streams_tlv_then_finalize_rejects_below_floor with
  EOS_ERR_SIGNATURE.
- embeddedos-org#103's step 5b reads the TLV counter through the HAL slot containing the
  image; test_secure_boot_policy (embeddedos-org#82) declared no slots, so eos_secure_boot()
  returned EOS_SBOOT_ERR_BAD_HEADER two steps before the one under test. The
  fixture now places its image in slot A.

Guards from embeddedos-org#95 that later merges walked back, never run until now because the
C configure step failed first:
- embeddedos-org#103 replayed the hand-written Valgrind foreach over the derived one.
  Restored foreach(TEST_NAME ${EBLDR_UNIT_TESTS}); eleven registered suites
  had no list(APPEND ...) and so no Valgrind run.
- Seven suites assign tests_run = <literal> and their TEST() does not count;
  four suites have no TEST() macro at all. Counted, and classified.
- embeddedos-org#101 added fuzz-build after embeddedos-org#90's gate; the gate did not wait for it.

CI plumbing:
- eosim-sanity.yml: the install-validate job is written in bash but ran under
  PowerShell on the Windows legs (no shell:), where SITE_PACKAGES=$(...) is an
  unknown command and `|| { exit 1 }` is an unexecuted script block.
- scorecard.yml: ossf/scorecard-action@v2.4.0 pulls gcr.io, which now demands
  GCP billing. v2.4.3 pulls ghcr.io; eos already pins it and is green.

Verified locally (macOS, clang): Release build clean, 31/31 ctest; the same
under -DEBLDR_SANITIZE=ON (ASan+UBSan); 78/78 pytest.

Not fixed here, reported separately: core/keystore.c's compiled-in
default_dev_key is described as the RFC 8032 TEST 1 public key but differs
from byte 21 on and is not a point on the curve, so nothing can verify
against it on any board without OTP. With embeddedos-org#104 that makes firmware update
refuse every image on such boards.
… -1.0.0 as an option

test_out_of_range_version_is_rejected[-1.0.0] passed locally (Python 3.14)
and failed in CI (ubuntu-22.04, Python 3.10) with argparse's own
"expected one argument": the older negative-number matcher does not accept
-1.0.0, so the token was read as an unknown option and imgpack.py's range
check -- the thing under test -- never ran. The joined form is unambiguous
on every interpreter and the test now reaches the tool's message.
tests/vectors/fw_update_test_sigs.h is the output of
tools/gen_fw_update_test_sigs.py, committed because eBoot has no Ed25519
signer in C. Nothing checked that the two agree: a generator edit without a
regeneration leaves test_fw_update and test_fw_transport verifying against
stale signatures, failing with EOS_ERR_SIGNATURE and nothing to say why.

tests/unit/test_fw_update_test_sigs.py runs the generator with the test's
own interpreter and compares its stdout to the committed header byte for
byte, so a line-ending change counts too. It follows the same dependency
rule as test_eos_sign_payload_offset.py: with EOS_REQUIRE_SIGNING_TESTS set
(the CI workflow sets it before the pytest step) a missing cryptography
module fails the job instead of skipping. Negative control: one flipped hex
byte in the header fails the test with a unified diff naming the line.

build_image() and build_container() now carry a comment naming the
coupling: the signed prefix is assembled both there and in the generator,
and changing any field in it means changing the generator's copy and
regenerating the header.
…epair

embeddedos-org#103 and embeddedos-org#104 were both merged and disagree on whether the anti-rollback
counter or the signature is checked first in eos_fw_update_finalize(). The
master design orders boot as verify image, then version policy (section
8.1), but its update flow (section 15) never places the anti-rollback
check, so the order the install path uses existed only in a PR body.
ADR-020 records it: the signature over the signed header prefix is
verified first, the TLV counter is read only after the prefix that binds
it is authenticated, and an image that fails verification is refused as
EOS_ERR_SIGNATURE without its counter being consulted. docs/adr/README.md
is added in the shape of the eos repository's index; 020 avoids reusing
001 through 019.

CHANGELOG.md gains the Unreleased entries for the repair: the configure,
compile and link breakage after the 09-07 batch merge, the settled check
ordering with the suites streaming signed images, the re-derived Valgrind
list, fuzz-build in the CI gate, counted tests_run, the EoSim Windows legs
running under bash, and the Scorecard action on its ghcr.io-hosted release.
The changelog said eleven suites had no Valgrind run. Eleven were missing
from EBLDR_UNIT_TESTS, but four of those were named in the hand-written
foreach and did run; seven had no run at all. Say which.

ADR-020: its design-document citation now says where it comes from (the
architecture review of embeddedos-org#115), and the sentence about the two PRs' bases is
replaced with what the history shows -- embeddedos-org#103's commits predate embeddedos-org#104's merge,
and embeddedos-org#104 was written without embeddedos-org#103's check in place.
The regeneration test's failure path -- the unified diff under the
regenerate command -- ran only when the header was stale, so a green run
never executed it and the coverage report said so. The report is now a
helper the match asserts with, and a second test drives the helper with
two byte strings that differ in one byte and checks the command and both
sides of the changed line appear.
…itself

No run of "Build & Release Book PDF" in this repository's history has
succeeded: every run since the step was added (ef0dc50, 2026-04-25) is a
failure, and every one whose log is still readable dies with

    ! LaTeX Error: Command \chead already defined.   (exit 43)

The workflow installs pandoc 3.6.1 from the release .deb and Eisvogel 2.4.0,
which predates pandoc 3.6. The 3.x line merges pandoc's default template
through 3.6.1 and later (its CHANGELOG names each merge) and states pandoc 3
compatibility. The LaTeX-level cause of the clash is not established here;
the run on this change is what shows whether the pair works.

Three changes to the one step and its trigger:

  Eisvogel 2.4.0 -> 3.5.1, as EISVOGEL_VERSION next to PANDOC_VERSION. The
  3.x tarball extracts into Eisvogel-<v>/ rather than flat, so the copy
  names the directory -- a bare version bump would have failed at the cp.
  Ran the new step verbatim against the real release: template installed,
  29,929 bytes; the old cp against the 3.x layout fails as predicted.

  No more `tar xzf ... 2>/dev/null || true`. That was fail-open on the exact
  step that breaks: a missing or reshaped tarball failed silently and the
  diagnostic landed on the cp after it.

  The workflow is added to its own paths: filter, for push and pull_request.
  It fired only on docs/book/**, so a workflow-only change could not get the
  run that proves it -- including this one.

Verified: parsed structure asserted, not parse success -- both paths lists,
push.tags ['v*'], branches, release types, workflow_dispatch and the job list
are unchanged apart from the two added path entries; the template step
contains no '|| true'. NOT RUN here: the PDF itself (no xelatex on this
host). The evidence is this PR's own run of the job, cited in the PR once it
exists -- and only if build-pdf ran rather than being skipped on has_book.

Closes embeddedos-org#134
…ships

The first run of this change got past the template clash -- no more
"\chead already defined" -- and failed on the next thing:

    ! LaTeX Error: File `sourcesans.sty' not found.   (exit 43)

Eisvogel 3.5.0 migrated its default font from the `sourcesanspro` package
to `sourcesans` (its CHANGELOG, 2026-06-28), and ubuntu-22.04's TeX Live
2021 has no sourcesans.sty. 3.4.0 is the last release on sourcesanspro,
which texlive-fonts-extra ships (checked against the package's file list),
and it already carries pandoc's default template merged through 3.9.

Install step re-run verbatim against the 3.4.0 release: template installed.
The PDF is still NOT RUN here; the PR's next run is the evidence.
The second run of this PR, on Eisvogel 3.4.0, failed exactly as master
does -- "Command \chead already defined" -- which means the first run's
apparent progress was an illusion: on 3.5.1 LaTeX died earlier, on a
missing font at line ~672 of the template, before it ever reached the
header setup at ~890. The clash was never in the Eisvogel version.

It is in this workflow. The pandoc step injected, through header-includes,

    \usepackage{fancyhdr} \pagestyle{fancy} \fancyhead[L]{...} ...

and Eisvogel builds its own header and footer with KOMA's scrlayer-scrpage,
which defines \chead. The template places $header-includes$ (line 541)
before its header block (~890), so fancyhdr defined \chead first and
scrlayer-scrpage's \newcommand failed. Two header packages, one command.
Both arrived in ef0dc50 (2026-04-25), which is why no run of this job has
ever succeeded, on any pandoc or Eisvogel version.

The header and footer now go through the template's own variables --
header-left=\leftmark, header-right=<version>, footer-center=<press line>,
footer-right left at the template's default page number -- and the
fancyhdr block is gone. The rest of header-includes (float, booktabs,
longtable, caption, graphicx) is unchanged. Eisvogel stays at 3.4.0 for
the fonts (3.5.x needs sourcesans.sty, absent from TeX Live 2021).

Asserted on the parsed workflow: no fancyhdr/fancyhead/pagestyle{fancy}/
*rulewidth on any non-comment line of the step; the four variables and
the remaining header-includes packages present; no comment or blank line
inside the backslash-continued pandoc command (a first draft put the
explanation inside it, where '#' would have swallowed the continuation);
trigger paths, tags and EISVOGEL_VERSION unchanged.

Still NOT RUN here: the PDF. Third run is the evidence.
Run 3 got through the preamble and died on content:

    ! Misplaced alignment tab character &.
    <argument> Srikanth Patchava & EmbeddedOS Contributors

The pandoc step passed -V "author=Srikanth Patchava & EmbeddedOS
Contributors". A -V value is inserted into the LaTeX verbatim, so the '&'
reached xelatex as an alignment tab. book.md's front matter already
declares the same author, and metadata goes through pandoc's writer, which
escapes it. The override is removed; the metadata is the one source.

Earlier runs never reached this line -- they died in the preamble first,
on \chead and on the font -- which is the same lesson as before: the first
error hides every later one.

Asserted on the parsed step: no -V author; every remaining literal -V value
is free of unescaped LaTeX specials (& % # _ ^ ~); header-includes is
exempt by design and values expanded at run time (title, version, date)
come from metadata or `date`, which carry none.

Still NOT RUN here. Fourth run is the evidence.
The comment said the missing sourcesans.sty was ubuntu-22.04's TeX Live
2021. The job runs on ubuntu-latest, which the green run at 358009e shows
is ubuntu-24.04 (noble). The fact that matters -- the runner's
texlive-fonts-extra has no sourcesans.sty, so Eisvogel 3.5.x cannot be
used -- is unchanged and is what run 1 proved; the distro and TeX Live
version I attached to it were assumed, not read from the log.
@Kartikey1306

Copy link
Copy Markdown
Contributor Author

Green, twice, with build-pdf executed rather than skipped:

  • 358009e — run 34937342076: Validate Book SourceBuild PDFVerify PDF ✅ (eBoot-guide.pdf, 760K, 48 pages, 777012 bytes) Upload PDF artifact ✅.
  • abf0522 (head) — run 34937741463: same, 777043 bytes.

These are the first successful runs of this job in the repository's history.

What it took, in the order the runs revealed it — each run removed one defect and exposed the next behind it, which is also why the PR opened with the wrong diagnosis:

  1. Run 1 (Eisvogel 3.5.1): sourcesans.sty not found — 3.5.0 migrated to a font package the runner's texlive-fonts-extra lacks → 3.4.0, the last release on sourcesanspro.
  2. Run 2 (3.4.0): \chead already defined, exactly as master — so the template version was never the cause. Established from the inputs: this workflow's own header-includes loaded fancyhdr while Eisvogel builds headers with scrlayer-scrpage, which defines \chead; $header-includes$ sits before the template's header block. Both arrived in ef0dc50. → fancyhdr block removed; header/footer via header-left/header-right/footer-center, same content.
  3. Run 3: through the whole preamble, then Misplaced alignment tab character & — the raw -V "author=… & …" override; a -V value is verbatim LaTeX. → override dropped; book.md's metadata carries the same author and pandoc escapes it. Every remaining literal -V value is asserted LaTeX-safe.
  4. Run 4: green. Run 5: one comment line corrected (ubuntu-24.04, read from run 4's Image: line, not the 22.04 I had assumed).

Also in the diff: tar without || true (fail-open on the step that breaks), and the workflow added to its own paths: filter so it can prove itself.

Corrections to earlier text on this PR, left visible: the body originally said run 1 showed "the template clash is gone" — it showed nothing of the kind; LaTeX had died on the font before reaching the header block. And "ubuntu-22.04 / TeX Live 2021" was assumed, not read.

Stacked on #115 (e152d8e..abf0522). ebuild has the identical step and will get the same change in its own PR.

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.

Build & Release Book PDF has never produced a PDF: Eisvogel 2.4.0 fails under pandoc 3.6.1

3 participants