Skip to content

Make staged page composition bounded without whole-artifact recompilation #882

Description

@chubes4

Problem

The staged compiler API serializes artifact partitions, but its terminal composition is not computationally staged. prepareShared() and preparePage() normalize and persist file envelopes; compose() materializes every envelope, concatenates all files, and calls compile() on the complete artifact.

A consumer can therefore checkpoint payload hydration and page enumeration, but the final invocation still repeats the full multi-page transformation. This blocks Automattic/static-site-importer#827: a 54-route browser artifact can persist every page plan and still spend more than 15 minutes in one terminal compose() call without a durable compiled receipt.

This is separate from #879. Compositional stylesheet caching reduces repeated analysis inside a full compile; this issue owns a staged contract whose expensive page work is performed and persisted per page so terminal composition does not recompile the whole artifact.

Current contract

ArtifactCompiler::preparePage() returns a normalized page artifact envelope. ArtifactCompiler::compose() merges the shared and page artifact files and delegates to compile().

A minimal reproduction can wrap or instrument compile(), prepare 50 page plans, then call compose(): the terminal call performs complete document compilation rather than bounded aggregation of previously compiled page outputs.

Required generic contract

  • Prepare immutable shared analysis once, including shared stylesheet and source metadata needed by page transforms.
  • Compile one page against that shared plan in bounded work and return a serializable compiled page plan.
  • Compose shared plus compiled page plans without invoking whole-artifact compile() again.
  • Keep plan digests bound to shared identity, page identity, payload references, compiler options, and output schema.
  • Preserve deterministic route order, shared shell extraction, stylesheet cascade/order/media/provenance, generated block namespaces, diagnostics, quality evidence, assets, and source reports.
  • Expose phase timings and bounded cache/work counters without putting duration fields into canonical equality.
  • Preserve current inline compile() and existing staged envelope APIs for callers that do not need compiled plans.

Acceptance

  • A fixture with at least 50 pages, shared CSS, and varying page-local content proves each page can be compiled and persisted independently.
  • Terminal composition performs bounded aggregation and does not call whole-artifact compile().
  • Uninterrupted compilation and shared-plus-compiled-page composition produce identical canonical WordPress site plans and diagnostics after removing observational timings/counters.
  • Interrupted execution can resume from persisted compiled page plans without recompiling completed pages.
  • Missing, duplicate, corrupt, option-mismatched, or shared-digest-mismatched page plans fail deterministically.
  • Mixed inline and file-backed payload callers retain existing behavior and schema compatibility.

Related: #865, #879, Automattic/static-site-importer#827

AI assistance

OpenAI gpt-5.6-sol via OpenCode reviewed current Blocks Engine trunk, the staged compiler implementation, and a rejected SSI candidate that exposed terminal whole-artifact recompilation. Chris Huber reviewed and owns this report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions