Skip to content

Fix #1: Decompose build pipeline into collect/preprocess/render/index - #26

Open
AlexMikhalev wants to merge 3 commits into
mainfrom
task/1-pipeline-decomposition
Open

Fix #1: Decompose build pipeline into collect/preprocess/render/index#26
AlexMikhalev wants to merge 3 commits into
mainfrom
task/1-pipeline-decomposition

Conversation

@AlexMikhalev

Copy link
Copy Markdown
Contributor

Summary

Increment A of mdBook feature parity (docs/plans/mdbook-parity-implementation-plan.md).

Pure refactor with zero behaviour change: the monolithic build_sync_impl_sync is split into named pipeline stages so B–E each target one stage.

Changes

  • src/pipeline/ — collect → preprocess → render sequencing; async index
  • src/pipeline/preprocess.rs — identity seam for future P2 directives
  • src/render/markdown.rs — mdast + syntect + .md.html link rewrite
  • src/render/html.rs — Tera init, page/index writers, static assets
  • src/core.rs — Args + build() orchestration only

Gate evidence

  • make qa / clippy -D warnings green
  • Unit + integration + mdbook compatibility tests pass
  • SHA-256 byte-identical to pre-A baseline: 72/72 match
  • Wall-clock baseline for test_book_mdbook: 0.86 s (debug; Pagefind CLI absent)

Docs

  • docs/verification/verification-report-mdbook-parity-a.md
  • docs/validation/validation-report-mdbook-parity-a.md
  • docs/plans/review-mdbook-parity-a.md

Out of scope

  • SUMMARY.md model (B), CLI subcommands (C), path_to_root/Shoelace (D), themes (E)
  • Unrelated local WIP remains in git stash (not in this PR)

Refs #1

AlexMikhalev and others added 3 commits August 8, 2026 10:24
Phase 1 (disciplined-research) and Phase 2 (disciplined-design) for
bringing md-book to contract parity with mdBook.

Key finding: md-book has no SUMMARY.md parser. Structure is inferred
from a path-sorted walkdir with sections named after parent directories,
which accounts for 11 of 13 structural gaps and makes previous/next
incorrect. Two output defects rank above missing features: absolute
asset paths (breaks sub-path deployment) and CDN-loaded Shoelace
(breaks offline viewing).

Parity is scoped as the authored book contract, not mdBook internals;
local decisions (Pagefind, Tera, Web Components, markdown crate, twelf,
jiff, WASM) are retained and recorded as N/A rather than gaps.

Five sequenced increments tracked as terraphim/md-book #1-#5.

Refs #1, Refs #2, Refs #3, Refs #4, Refs #5

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three rounds of specification interview on the SUMMARY.md book model.
Two decisions went against the drafted recommendation and change the API:

- create-missing is honoured with mdBook's default of true, so the build
  writes stub files into src/; created paths are returned so the watcher
  can suppress the resulting events and avoid a rebuild loop.
- Summary errors are collected in one pass and reported together rather
  than failing fast, so migrating a large book takes one build
  round-trip. parse_summary now returns SummaryErrors.

The security dimension surfaced a requirement absent from the plan:
path containment. SUMMARY.md names files to read and republish, which in
CI can be untrusted PR input, so any path canonicalising outside src/ --
symlinks included -- is refused.

The accessibility decision (nested <ul>, aria-current, disabled draft
entries) is incompatible with a flat depth-tagged list because Tera
macros cannot recurse; NavEntry gains open_lists/close_lists deltas so a
single template loop emits correct hierarchy.

Refs #2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extract the monolithic build_sync_impl_sync into named stages so later
mdBook-parity increments target one stage each. Zero behaviour change:
output is byte-identical to the pre-A baseline (72/72 assets).

- src/pipeline: collect, run_sync, async index, identity preprocess seam
- src/render: markdown (mdast+syntect) and html (Tera/assets) modules
- src/core: Args + build orchestration only
- Tests relocated with their code; preprocess identity covered

Refs #1

@AlexMikhalev AlexMikhalev left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dual review — Increment A (structural + pi openai-codex/gpt-5.5)

Structural PR Review (orchestrator)

Summary

Increment A extracts the monolithic build_sync_impl_sync into pipeline + render modules with zero behaviour change. Preprocess is an identity seam; directory-walk collection and the hard-coded "Guide" section are intentionally preserved for B.

Done well: clear stage boundaries, tests moved with their code, identity preprocess covered, byte-identical gate met (72/72).

No structural findings from local equivalence scan (preprocess on every chapter + index path; index still async-only under search+tokio).

Confidence Score: 5/5

  • Safe to merge with minimal risk.
  • Byte-identical output + full test suite + clean dual review. No P0/P1/P2.
  • No files require special attention.

Important Files Changed

Filename Overview
src/pipeline/mod.rs Stage orchestration; directory collect preserved
src/pipeline/preprocess.rs Identity seam; unit tested
src/render/markdown.rs mdast + syntect extracted intact
src/render/html.rs Tera + assets extracted intact
src/core.rs Thin Args + build orchestration

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  build --> run_sync
  run_sync --> collect
  collect --> preprocess
  preprocess --> render_md[render_markdown]
  render_md --> render_page
  run_sync --> index{search+tokio?}
  index -->|yes| pagefind
  index -->|no| skip
Loading

Inline Findings

No P0/P1/P2 findings.

Last reviewed commit: 06d3362 | Reviews (1) | Reviewer: structural-pr-review (orchestrator)


pi openai-codex / gpt-5.5 review

Summary

Increment A is a clean structural extraction of the former monolithic build path into the intended pipeline shape:

  • collect in src/pipeline/mod.rs
  • identity preprocess in src/pipeline/preprocess.rs
  • markdown and HTML rendering in src/render/markdown.rs and src/render/html.rs
  • async-only Pagefind indexing retained behind search + tokio

The patch appears aligned with the stated constraints: no SUMMARY.md handling, no CLI changes, no path_to_root, no theme work, and preprocessing is explicitly identity today. The old build orchestration is preserved semantically: synchronous generation still happens first, and Pagefind indexing still only runs on the async tokio + search path after HTML generation.

I did not identify any P0/P1/P2 structural-semantic issues from the supplied diff. The main behavioural seams to keep covered in validation are golden-output equivalence across feature combinations, especially syntax-highlighting on/off and search on/off.

Confidence Score: 4/5

Confidence is high based on diff review: the moved functions appear equivalent, feature gates look coherent, preprocessing is invoked on page and index markdown, and Pagefind error swallowing remains behaviourally compatible with the old path. Confidence is not 5/5 because this review is based on the attached patch rather than running the full matrix locally.

Important Files Changed

File Role in Increment A Review Notes
src/core.rs CLI args and high-level build orchestration Correctly delegates sync generation to pipeline::run_sync; keeps async Pagefind indexing gated on search + tokio.
src/lib.rs Public module exports Exposes new pipeline and render modules.
src/pipeline/mod.rs Pipeline orchestration and collection stage Implements collect → preprocess → render; keeps indexing separate and async-only. Directory-walk collection appears equivalent to previous behaviour.
src/pipeline/preprocess.rs Preprocess stage seam Identity implementation with tests; correctly returns original markdown content unchanged.
src/render/markdown.rs Markdown-to-HTML fragment rendering Extracts markdown options, link rewriting, and optional syntax highlighting from old core.rs; behaviour appears preserved.
src/render/html.rs Tera setup, static assets, page/index rendering Extracts template loading, asset copying, syntax CSS writing, and page/index assembly; behaviour appears equivalent.
src/render/mod.rs Rendering module facade Re-exports expected rendering APIs.

Diagram

flowchart TD
    A["core::build / build_impl"] --> B["pipeline::run_sync"]
    B --> C["collect(input_dir)"]
    C --> D["CollectedPages<br/>entries + all_pages + sections"]

    D --> E["for each markdown page"]
    E --> F["preprocess(md)<br/>identity today"]
    F --> G["render_markdown"]
    G --> H["render_page"]

    D --> I["index.md present?"]
    I -->|yes| J["preprocess(index.md)<br/>identity today"]
    J --> K["render_markdown"]
    K --> L["render_index"]
    I -->|no| L

    H --> M["HTML output files"]
    L --> M

    M --> N{"features: search + tokio?"}
    N -->|yes, async path only| O["pipeline::index<br/>PagefindBuilder"]
    N -->|no| P["skip indexing message"]
Loading

Inline Findings

No P0/P1/P2 findings.

Last reviewed commit: 06d3362 | Reviews (1) | Reviewer: pi openai-codex/gpt-5.5

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

🚀 Deployment Preview

Your changes have been deployed to Cloudflare Pages!

🔗 Preview URL: https://preview-26.md-book.pages.dev

The deployment will be updated automatically when you push new changes to this 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.

1 participant