Developing the book and program together

In an ordinary codebase, editing a source file and editing its design document are two separate acts. In Literate they are one act: authoritative chapters contain the explanation and the fragments from which much of the program is generated. A good contributor workflow must therefore protect two products at once—the program that runs and the book that explains why it has that shape.

The central discipline is simple:

Change the authoritative work, regenerate its derived artifacts, and review both meanings before accepting either.

This chapter gives a durable method for doing that. Exact tool releases and host installation details belong in the package manifest and contributor reference; the method remains useful as those details change.

Know which artifact has authority

Not every repository file has the same role. Authoritative .literate chapters own the generated implementation fragments and their rendered HTML. Generated source is checked in so a fresh checkout can bootstrap and ordinary language tools can work with it, but it is not the place to make lasting implementation edits.

Other files may remain ordinary authoritative sources: package metadata, styles, templates, fixtures, licenses, build configuration, and tests not generated from a chapter. Some tests are themselves generated, so a contributor must determine the owner of the particular test before editing it. “The book is the source” does not mean that every byte in the repository must be hidden in a fragment. It means that code represented by the book must be changed there rather than patched in its derived file.

flowchart TD
    Intent[Design or behavior change] --> Authority{Which source owns it?}
    Authority -->|Explained generated code| Chapter[Edit prose and fragments]
    Authority -->|Ordinary source not generated from a chapter| Ordinary[Edit ordinary source]
    Chapter --> Generate[Regenerate derived source and HTML]
    Ordinary --> Review[Review direct changes]
    Generate --> Review
    Review --> Verify[Verify behavior, explanation, and artifacts]

The branches identify ownership, not importance. An ordinary test can be as critical as a generated engine module. The distinction prevents a successful local patch from being erased by the next generation.

Begin with an invariant, not a file

Before editing, state the change in terms a reader and reviewer can test. Examples include:

An invariant provides a better search key than a filename. Use inspection, fragment navigation, references, and the assembly maps to find the fragments and ordinary files that realize it. Read the surrounding explanation before changing an implementation detail; the prose may reveal constraints that the generated source no longer makes obvious.

This approach also improves the chapter. If the intended change cannot be explained without naming a private helper, the design may not yet be stated at the right level.

Edit explanation and implementation as one unit

A durable chapter normally introduces the human problem, gives a conceptual model, states its safety or correctness boundary, and only then presents the selected implementation. When behavior changes, revise every part whose truth changes:

Do not add prose that merely translates each statement into English. Explain why the statements belong together, what must remain true, and what is deliberately not supported. Conversely, do not leave an important invariant only in prose if a test can make its failure visible.

Fragment boundaries deserve the same review as function boundaries. A fragment should express one explainable responsibility, have a name that reads naturally in the surrounding sentence, and compose with its siblings into a useful outline. Mechanical imports, gathering roots, and routine registration belong in the assembly or integration references when they would interrupt the main argument.

Regeneration is a semantic comparison

Generation is not clerical cleanup at the end of a change. It is the operation that reveals what the authoritative edit means to compilers, browsers, and readers. After regeneration, classify every changed artifact.

A useful review matrix has three common cases:

Unexpected absence matters as much as unexpected presence. If a fragment edit produces no source diff, the contributor may have edited an unused family or the wrong contribution. If moving a chapter changes source bytes, contribution order may carry more semantics than the edit intended.

The ordinary loop is concise:

yarn literate generate
yarn literate check
yarn test
yarn esbuild

The repository's contributor reference remains authoritative for available scripts and prerequisites. The important sequence is generate, compare, test, and build—not the permanence of one wrapper command.

Use a validation ladder

No single command answers every question. Validation should move from the smallest relevant claim to broader integration.

flowchart TD
    Source[Authoritative edit] --> Inspect[Inspect fragments and planned outputs]
    Inspect --> Focused[Run focused parser or subsystem tests]
    Focused --> Generated[Check generated files are current]
    Generated --> Self[Verify the generation fixed point when relevant]
    Self --> Suite[Run the complete automated suite]
    Suite --> Package[Build the shipped entry points]
    Package --> Real[Exercise real hosts or external tools where needed]

Each arrow adds evidence of a different kind:

  1. Inspection checks that definitions, references, roots, and destinations are the ones intended.
  2. Focused tests give fast feedback near the changed policy.
  3. Generated-file checks compare the complete in-memory plan with tracked artifacts without treating stale output as source.
  4. Self-host verification type-checks fresh generated sources and asks the fresh engine to reproduce the plan.
  5. The full suite catches interactions outside the contributor's first model.
  6. Packaging builds prove that actual extension and runtime entry points can be assembled, not merely imported by tests.
  7. Real-host acceptance covers behavior that mocks cannot establish, such as editor UI, a language server, a browser, or a typesetter.

Not every change needs every expensive final step. The choice should follow the claim. A typography change needs rendered screen and print inspection; a protocol change needs framing and real-server evidence; an engine change needs the fixed point. Record skipped environmental checks honestly rather than implying that a headless suite performed them.

Changing the generator requires a bridge

Self-hosting creates a bootstrapping problem: the old generated engine must first understand enough of the edited book to produce the new engine. A safe generator change therefore has two conceptual generations.

sequenceDiagram
    participant B as Authoritative book
    participant O as Known-working engine
    participant N as Fresh engine
    participant V as Verification

    B->>O: Generate candidate outputs
    O-->>N: Candidate engine source
    N->>V: Type-check and build
    V->>N: Generate from the same book
    N-->>V: Candidate outputs again
    V->>V: Compare paths and bytes

If the first candidate does not build, repair the literate source and use a known-working bootstrap executable again. Do not hand-edit generated TypeScript as a second source of truth. A syntax migration may need a compatibility bridge so the old parser can generate the new parser before the book adopts the new form.

The fixed-point check is intentionally narrower than the test suite. It proves that the generated engine agrees with its own authoritative input. It does not prove that command-line effects, editor activation, or publication tools behave correctly. Those remain separate layers in the validation ladder.

Review changes in both reading orders

A literate program has at least two meaningful orders:

Review the chapter while skipping code blocks. The argument should remain coherent, technical terms should be introduced before use, and diagrams should answer a specific question. Then read parent fragments as outlines and inspect the generated diff. The assembly should remain complete, and fragment names should explain why pieces are connected.

This double reading catches opposite failures. A program can compile while its book has become a change log or a source dump. A chapter can read beautifully while its fragments assemble an unintended program. Neither is a successful literate change.

Treat generated files as review evidence

Checked-in generated files serve practical purposes: bootstrapping, ordinary language tooling, packaging, and transparent review of what the book produces. They should be committed with the authoritative chapters that changed them.

Review them without granting them authority. Useful questions include:

Generation does not delete obsolete destinations automatically. Renaming or removing a root therefore requires an explicit inventory review; an old file can remain plausible long after it has stopped belonging to the plan.

Package what users will actually run

Tests often import modules directly, while users run bundled entry points with packaged assets. Before release, build those entry points and inspect the package contents. Confirm that runtime bundles, browser programs, templates, styles, licenses, and declared contributions are present, and that development-only or private material is absent.

External publication tools and language servers deserve separate acceptance. A mock can prove how Literate reacts to a response; it cannot prove compatibility with every real executable. Test representative supported configurations, record the boundary of that evidence, and keep missing-tool diagnostics actionable. The program should not download compilers, browsers, fonts, or servers merely to make a release check pass.

Version and release the whole contract

A release version describes more than executable bytes. It also describes syntax, commands, settings, generated-file expectations, publication formats, packaged resources, and known limitations. Release review should therefore include:

  1. update the version and user-facing change record consistently;
  2. regenerate and require a clean generated-file check;
  3. run the relevant fixed-point, test, lint, and package builds;
  4. inspect the distributable archive rather than assuming its manifest is enough;
  5. exercise installation or host acceptance for changed integration surfaces;
  6. review third-party notices and portable asset licenses;
  7. verify that examples and contributor instructions match the shipped behavior;
  8. publish only the reviewed artifact, preserving a traceable source state.

A release command can automate these steps, but it cannot decide whether the book is clear, a diagram is legible, or a PDF has an awkward page break. Human review is part of the release contract for a program whose documentation is itself a primary product.

Keep the loop sustainable

The method works only if contributors can run it repeatedly. Keep focused tests fast, make diagnostics point back to authoritative chapters, preserve a dependable bootstrap, and avoid requiring a graphical editor for core generation. Expensive real-tool checks can be explicit without being forgotten; package scripts and contributor references should make their purpose clear.

Most of all, keep the claims proportional to the evidence. “The fixed point passed” is not “the extension is correct.” “The headless suite passed” is not “every language server is compatible.” “The PDF compiled” is not “the typography needs no review.” This precision makes both maintenance and release more trustworthy.

The method keeps book and program aligned, but it cannot remove every cost of literate programming or every limitation of the surrounding tools. The next chapter states those boundaries directly.