Companion Essay № 008 · August 2026

Unit Tests for Prose

Companion to The Architecture of Nonfiction
Contents

During development of The Architecture of Nonfiction, we rewrote a paragraph almost completely.

The first version used a spine metaphor to distinguish the stable argument from examples, sources, and other material that should remain easy to change. The revision removed the metaphor, named the stable structure directly, and specified which supporting components could be added, replaced, or removed.

The wording changed. The form changed. The paragraph still did the same job.

That is what made the revision safe. We were not preserving sentences. We were preserving a contract.

Software engineers have a familiar way to express this kind of confidence. A unit test establishes the required setup, exercises one behavior, and checks the result. The implementation may be refactored beyond recognition. If it still satisfies the same behavior, the test passes.

Paragraphs are not deterministic functions, and readers are not test runners. Still, the comparison gives writers something more useful than “this flows better.” It gives us a way to state what a paragraph requires, what it must accomplish, and what must be available when the reader reaches the next component.

Flow Is Not an Expected Result

“The paragraph flows” sounds evaluative without identifying what was evaluated. It may mean that the sentences are grammatical, the cadence feels natural, the transition is unobtrusive, or the reader did not have to stop. Those are useful observations, but none tells us whether the paragraph performed its responsibility.

A beautifully flowing paragraph can still be wrong for the argument.

Consider a section explaining why staged rollouts reduce release risk. One paragraph introduces blast radius, the extent of harm a failed release can cause. The next explains feature flags, controls that expose a change selectively, and the third compares staged exposure with a full release. Replace the feature-flag paragraph with a polished history of continuous delivery, and the section may remain readable. The topic is still software delivery. The sentences may connect at a surface level.

The contract fails because the third paragraph expects an explanation the replacement never supplied.

Testing prose begins by replacing a feeling with an expected result. Instead of asking whether the paragraph sounds good, ask what the next part of the argument is entitled to assume after the paragraph ends.

Arrange, Act, and Assert

Bill Wake named Arrange, Act, and Assert as a pattern for focused unit tests. The test establishes the relevant state, exercises one behavior, and verifies the expected result. The separation makes the test readable because its dependencies, action, and expectation remain visible.

A paragraph contract has a compact parallel:

Unit testParagraph contractReview question
ArrangePreconditionsWhat context may this paragraph assume?
ActResponsibilityWhat rhetorical purpose must it serve?
AssertPostconditionsWhat must the text make available afterward?

The mapping is useful because it separates three failures that often get collapsed into “unclear writing.”

A paragraph may fail before it begins because a prerequisite was never supplied. It may fail internally because it serves two competing purposes. It may fail at the handoff because the next paragraph needs a definition, distinction, or conclusion that never arrived.

Those require different revisions.

Write the Test Before Polishing the Paragraph

Suppose a section argues that code review cannot rescue an incoherent requirement. The previous paragraph has already established that a requirement can be grammatically clear while permitting incompatible implementations. The paragraph under review must connect that ambiguity to the limits of downstream review. The next paragraph will introduce refinement, a requirements-review step, as the first opportunity to expose missing decisions.

Its contract could be written like this:

Preconditions:
- The reader understands that a requirement can be clear at the sentence level
  while remaining behaviorally ambiguous.

Responsibility:
- Explain why reviewing the resulting code cannot reliably recover decisions
  the requirement never made.

Postconditions:
- The reader can distinguish code-quality review from requirement validation.
- The next paragraph may introduce refinement as an earlier check.

Now consider two implementations.

Implementation A

Code review can identify code-quality defects such as a race condition, a leaky abstraction, or missing input validation. It cannot determine which user should receive a failure notification when the requirement never says. By the time the ambiguity reaches a pull request, a proposed code change, the developer has already supplied a product decision through code.

Implementation A passes. It begins from the established ambiguity, distinguishes two kinds of review, and leaves the reader prepared for an earlier intervention.

Implementation B

Code review remains one of the most important practices in software engineering. Experienced reviewers improve maintainability, share knowledge, and catch defects before production. Teams should protect enough time for thoughtful review.

Implementation B is accurate, relevant to the general subject, and reasonably written. It fails this contract. It does not explain why code review cannot repair an underspecified requirement, and it leaves no clean handoff to refinement.

Topic similarity is not behavioral compatibility.

The same failure appears outside technical subjects. In an essay about housing affordability, one paragraph may establish that rents rose while wages remained flat so the next can explain the growing burden on tenants. A polished replacement about the history of local zoning remains topically related to housing, but it fails the contract. The next paragraph still needs the missing comparison between rents and wages.

Test the Specification, Not the Wording

A brittle unit test knows too much about implementation. It passes only when private methods are called in a particular order or internal data has a particular shape, even though the public behavior remains correct. Such a test makes refactoring harder because it protects incidental structure.

Writers create the same problem when they treat memorable phrasing as the specification.

The contract for Implementation A does not require “race condition,” “leaky abstraction,” or “missing input validation.” A revision could replace all three examples. It could divide the idea into shorter sentences, use a different product decision, or alter the cadence. The test should fail only if the paragraph stops distinguishing code review from requirement validation or stops preparing the refinement discussion.

That boundary frees the editor to improve the implementation.

It also explains why a paragraph can change substantially while remaining the same paragraph architecturally. “Same” refers to its role in the argument, not its words. A rewrite that preserves the required inputs, responsibility, and outputs is substitutable. A light copyedit that leaves the wrong responsibility intact is not.

Given, When, and Then Is a Parallel, Not a Restatement

Gherkin uses Given, When, and Then to describe executable examples of system behavior. Given establishes an initial context. When describes an event or action. Then describes an observable outcome. The format helps people share a concrete understanding of how a system should behave.

That sequence resembles a paragraph contract:

Gherkin scenarioParagraph contract
Given an initial contextPreconditions already established for the reader
When an event occursThe paragraph performs its responsibility
Then an outcome is observableA postcondition becomes available to the argument

The resemblance is real. The equivalence is not.

A Gherkin When normally identifies an event in the system: the user submits a form, the payment fails, or the timer expires. A paragraph’s responsibility is rhetorical. It may define a term, distinguish two ideas, qualify a conclusion, answer an objection, or connect evidence to an inference. Serving one purpose can require several sentences and techniques.

Likewise, a Then describes observable system behavior. A prose postcondition cannot guarantee a reader’s internal response. A paragraph can make a distinction explicit. It cannot guarantee that every reader accepts, remembers, or feels it.

The author tests what the text supplies, not what another mind must do.

This matters when AI evaluates a draft. Asking a model whether a paragraph “makes the reader understand” invites confident speculation. Asking whether the paragraph explicitly distinguishes requirement validation from code review creates an inspectable condition. The second check remains interpretive, but its evidence exists on the page.

Every Test Needs an Oracle

A test oracle determines what the correct outcome should be. In code, that might be an expected return value, state change, or emitted event. In writing, the author must define what the component is supposed to contribute to the argument.

No editing tool can recover that purpose reliably from the paragraph alone.

An AI can describe what a passage appears to do. An editor can identify competing readings. A colleague can report where the reasoning broke. Those observations are valuable, but they do not possess automatic authority over the piece. The author still decides the governing purpose, intended reader, evidentiary standard, and acceptable ambiguity.

Without that decision, “test the paragraph” becomes another request for general improvement. The model may optimize cadence, simplify vocabulary, or add context while preserving the actual structural defect. It may also delete a deliberate tension because the expected outcome was never stated.

Write the oracle first:

After this paragraph, the text must have established ____________________
so that the next component can ________________________________________.

If the blank cannot be completed precisely, the paragraph may not be the problem. The author may not yet understand the argument well enough to assign it one responsibility.

Unit Tests Do Not Prove the System Works

Every paragraph in an essay can satisfy a local contract while the essay still fails.

The sections may answer the wrong governing question. Two chapters may establish incompatible definitions. The evidence may not support the conclusion. The sequence may require the reader to understand an idea before it is introduced. Local correctness does not guarantee successful composition.

Software teams distinguish unit tests from integration and system tests for the same reason. A component can behave correctly in isolation and fail when its dependencies, sequence, or environment become real.

Writing needs checks at several levels:

LevelPrimary check
SentenceIs the statement true, precise, grammatical, and appropriate to its role?
ParagraphDoes it satisfy its preconditions, responsibility, and postconditions?
SectionDoes the sequence resolve its assigned question and support the chapter?
DocumentDo the sections compose into the intended outcome for the reader?

This is why paragraph testing belongs inside a broader editorial process. It is good at detecting malformed handoffs, mixed responsibilities, and rewrites that preserve the topic while losing the job. It cannot establish the validity of the whole argument by itself.

Work Small, Then Run the Next Check

When a contract fails, change the smallest component that can repair it.

Rewrite one paragraph, then inspect the handoffs on both sides. Move one definition, then find every later component that assumes its location. Delete one sentence, then confirm that the paragraph still meets its postcondition. A small change narrows the cause when a new failure appears.

This mirrors disciplined refactoring. You do not need to preserve the implementation, but you do need fast feedback about behavior.

Use this card during revision:

Component:
Reader state before it:
One responsibility:
Required outcome:

Check:
[ ] Every prerequisite appears earlier or is supplied here.
[ ] Every sentence contributes to the responsibility.
[ ] The required outcome is explicit enough to inspect.
[ ] The next component may safely depend on that outcome.
[ ] The check protects behavior, not preferred wording.
[ ] The surrounding section still composes after the change.

The checkboxes will not turn writing into computation. They will expose assumptions that prose usually leaves implicit.

That is enough to make revision safer. Define the contract. Change the implementation. Inspect the result. Then move one level up and see whether the whole still works.

Receipts

  • Arrange, Act, Assert. Bill Wake’s “3A: Arrange, Act, Assert” describes the focused unit-test pattern and states that he observed and named it in 2001.
  • Current testing guidance. Microsoft Learn’s unit-test basics defines Arrange as setup, Act as invoking the behavior, and Assert as verifying the expected result.
  • Gherkin semantics. Cucumber’s Gherkin reference defines Given, When, and Then, while its BDD overview explains the collaborative purpose of concrete examples.
  • Applied paragraph model. The Paragraph as a State Transition develops the reader-state model that this essay turns into a review procedure.
  • Requirements as testable artifacts. The Feature-to-Story Pipeline is a first-party example of moving from product intent toward specific, verifiable behavior.
← The canonical essay