fix: mixed vaults publish through the real Boris engine (#210) - #219
Conversation
…blish through Boris (#210) Boris's link audit counts only its own emitted pages plus assets, so a mixed vault always failed: content/index.md linked Recipes/Risotto.html while the rendered recipe was written to .publish/ only after compile. Render Textile/Cooklang pages through Oliver before staging and write them into content/ as Markdown sources whose bodies are the finished HTML — CommonMark passes raw HTML blocks through byte-for-byte, so Boris emits them as first-class pages (layout + nav included) and its audit resolves every route. The builtin compiler pastes prebuilt bodies into the theme layout directly; the post-compile extras pass is gone.
|
SummaryCoverage spans publishing happy paths, mixed Markdown and rendered recipe content, nested pages, themes, navigation, assets, feeds, ordering, source preservation, retries, skipped content, cleanup, and failure handling. It also exercises boundary and adversarial behavior around empty output, unrenderable notes, compiler failures, retries, and overlapping publishes, with broad support for the expected application behavior. Safe to merge — the only finding is a medium-severity concurrency defect in overlapping publishing, and it is explicitly unrelated to this PR rather than a regression or existing PR failure. The PR introduces no attributable failures or merge-blocking risk; the concurrency issue is a flag for later. Tests run by ItoAdditional Findings DetailsThese findings are unrelated to the current changes but were observed during testing. 🟡 Overlapping publishes can mix site files
Evidence PackageTip Reply with @itoqa to send us feedback on this test run. |

Fixes #210.
Problem
Publishing a mixed vault (Markdown +
.cook) with Boris resolvable always failed:EROUTEMISSING/LinkAuditFailed. Oliver rendered recipe pages intoextras, but their HTML was written to.publish/afterboris --input content …ran — and Boris's link audit is set membership against its own intended output manifest, socontent/index.md's link toRecipes/Risotto.htmlfailed the audit before that page ever existed. Pre-seedingdist/does not satisfy the audit, and the builtin path never exercises it, which is why the existing mixed-vault test (preferBoris: false) and the Markdown-only Boris test missed it.Fix
Render Textile/Cooklang pages through Oliver before staging, and stage them as Markdown sources whose bodies are the finished HTML (verified: CommonMark-style HTML blocks pass through Boris's renderer byte-for-byte). Each rendered recipe becomes one of Boris's own emitted pages — layout and nav included — so every route resolves in the audit. Concretely:
BorisPagegainsprebuiltBodyHTML;BorisAdapter.stageacceptsmarkupHTML, maps each rendered note to a<entityID>.mdstaged source (same closed frontmatter grammar), and writes it intocontent/.BuiltinSiteCompileremits prebuilt bodies directly into the theme layout (identical.publish/shape as before);BorisCLICompileris untouched.BANALPublisher.publish()drops the post-compile extras pass entirely — both compiler paths converge on staging.This lands ROADMAP M4's "Textile/Cooklang via Oliver in the same
.publish/folder" without touching Boris or widening its grammar; the rendered pages use the exact frontmatter keysserializeBorisSourcealready writes (id,title,status,tags). No reimplementation of any markup engine — the HTML still comes from Oliver.Tests
testMixedVaultPublishesThroughBorisBinary— the Publish: mixed vault + Boris fails — recipe pages are written after Boris's link audit #210 repro end-to-end against the real boris + oliver binaries (skips when either is absent): publish succeeds,Recipes/risotto.htmlis emitted by Boris, index links it, source file untouched on disk.testStageWritesRenderedMarkupAsMarkdownBody— binary-free unit coverage for staging (.mdsource with verbatim HTML body) and builtin emission.Docs updated per policy:
docs/STATUS.mdPublish Site entry andCHANGELOG.mdunder[Unreleased].