Konubinix' opinionated web of thoughts

How to Do Literate Programming How to Write and Audit a Note How to Do Verified Promise Driven Development

Braindump

what
literate programming combines a programming language with a documentation language, the main idea being to treat a program as a piece of literature, addressed to human beings rather than to a computer1.

The rules this note works under

how to write and audit a note

what
a note is a self contained org-mode file digging into one subject — a question to answer, or a topic to explore.
how
the title summarizes that subject, and a heading states it in full when the title cannot.
who
the agent that writes is the writer, the agent that audits is the auditor, and the human is the user.
rule
the user talks informally, and the writer lands what they mean in the note’s own words and form.

values that an ia agent must respect

How one reads a note

why
a human reads a note top to bottom, following one thread.
rule
the note treats its subject and nothing else — no detour, no meta-commentary, no secondary justification, no iteration, no mistake, whatever the circumstances.
  • why: a writer drifts by default, and no one cares that the writer worked badly on the way.
rule
fewer words is the default.
  • check: note_hedges lists the hedges and emphasis markers lost between a passage and its rewrite.
rule
readability counts2.
rule
one word per meaning — a second name for the same thing reads as a second thing.
  • how: when the user gives a second word for something already named, the writer asks which of the two to keep, rather than adopting the new one.
rule
past 7 siblings or 50 lines of body before the first subheading, go deeper — headings under a parent heading, bullets into sub-bullets.
  • scope: where a heading has no subheading, the body runs to the end of its section.
  • scope: source blocks, export blocks and their results do not count toward the 50.
rule
a note whose outline has grown too long to hold in the head carries a table of contents.
  • why: the whole structure is then visible at a glance and every heading is one click away.
  • how: in org-mode, a #+TOC: headlines N directive placed where the overview belongs, or #+OPTIONS: toc:t to let the exporter render one.
  • scope: a short note with two or three headings does without it.

Where each piece goes

scope
an argdown map takes a graph — an objection, a premise two conclusions share, reasons that hold only combined — since bullet nesting already covers a tree.
rule
nothing is stated twice — inside a note the duplicate is cut, across notes it is refactored out and pointed at.
  • why: simple is better than complex3.
rule
the writer asks the user what to do with a cut piece.
rule
the writer reads or links another note only if the user agrees.
rule
the note being written is the only one edited.

The form of a bullet

rule
the narrative of a note is structured — every body line is a bullet of the form - <intention word> :: <claim>.
  • why: the writer pads when writing free-form text, so a list of bullets carries more than a paragraph of useless writer words.
  • why: the structure also makes a flaw easier to find, and that is worth the cost in readability.
  • how: the « intention word » is the single word before ::, naming what the line does; any word may serve.
  • scope: tables and footnote definitions keep their own form.
rule
one meaning per bullet.
rule
a reason the user holds is a why, and it needs no other backing.
rule
a why is written by the user.
  • scope: the writer rewrites its wording, never its meaning.
rule
a why the user has not explicitly accepted is never written.
  • why: a writer that writes a why unasked invents the user’s reason rather than recording it.
  • why: the user is the one who checks, a justification being easiest to fake and the writer worst-positioned to catch its own.
What a checker can decide
rule
only these flaws are mechanical — a body line that is not a bullet, a bullet with no ::, an « intention word » that is more than one word, a line of 120 characters or more with links counted as they render, a link that does not resolve, a heading with more than 7 children or more than 50 lines of body, a footnote whose text sits in the line instead of at the foot.
  • scope: one word is a run with no whitespace in it — au-delà, peut-être, tl;dr — so a mark inside a word is part of it.
rule
the rest is not mechanisable, and a silent checker is not conformance.
check
note_mechanics reports those flaws for an open note, and a count for each « intention word » in use.

How the file is typeset

rule
the user sets #+filetags, #+KONIX_ORG_PUBLISH_KIND and every :CUSTOM_ID:, and the writer neither adds nor edits one.
rule
a file is opened with the ensure_file_open MCP tool.
rule
the text under a heading is indented two spaces, as in this note.
rule
every line stays under 120 characters, text wrapping to fit.
  • how: a link counts only its visible part, the target being invisible in the rendered line.
  • scope: a keyword line and a table row cannot be wrapped and are exempt.
  • scope: a line babel wrote is not the writer’s line and is exempt too.
rule
French prose carries the espace insécable where French typography asks for one.
  • how: note_insecables inserts U+00A0 before : ; ? ! » and after «.
rule
the writer strips the insécables before editing a typeset note, and restores them after.
  • how: note_strip_insecables runs, then the whole edit pass, then note_insecables.

The audit loop

rule
the auditor is a different party from the writer, and judges without ever editing.
rule
each audit covers one fix — the whole patched passage against every rule, not « does this fix it? ».
  • why: a batch is read at one pace, and the fix that needed a fresh look goes by with the rest.
rule
each audit reports every objective flaw found, in one verdict.
  • why: subjective battles never end.
rule
each audit runs on the model the work needs — not Opus for a straightforward command.
rule
the writer asks the user to confirm a new term before using it.
  • why: writers coin very poor terms.
rule
when a fact changes, the writer asks rather than assumes.
  • why: the user may change their mind.
rule
a contested flaw escalates to an adversarial debate.

how to do verified promise driven development

what
a promise is a claim about what the program does for whoever uses it.
what
a story is the sequence of whats somebody really performs.
what
a test is the file on disk that runs a story.
how
the code holds the promise, and the test measures that it still holds in time.

The promise and its measure

A test asserts a promise
rule
a story names the promises it asserts.
  • why: everything else a test could check is a measure of a promise the program makes.
  • rule: a story with no promise to name is deleted rather than filed.
rule
the promise is written down, and the test only measures it.
  • why: a promise legible only as a test name is unreadable to the one it was made to.
  • why: the writing states the promise, the test holds it to time.
rule
the promise and its test stand or fall together, in both directions.
  • why: a promise held makes its test green, so a red names the promise that broke.
  • why: the other direction must be proved — a green means the promise holds only if breaking the promise would redden the test.
The promise decides what is measured
rule
a test tries the inputs the promise covers, not every input the code accepts.
  • why: an input the interface never presents measures a promise nobody made.
rule
the promise says when the work is done, never the coverage number.
rule
what links a promise and its stories is a reasoning, written beside the promise — these stories passing entails this promise held.
  • why: a red test then traces back to the promise that broke.
  • why: if unwritten, the next reader guesses the link, and a gap looks like a choice.

Stories are what matter

rule
we tell the stories, never the feature.
  • why: a use comes in whole stories — triaging a morning’s photos, running the cabinet frame, picking a few shots to send — and those stories are the promises the program makes.
  • why: a test written per feature asserts a promise nobody holds, since nobody opens a program in order to exercise one feature.
what
when described in text, the desired behaviour is a what
what
when described in text, the chosen technical approach is a how
rule
stories describe whats in the order the person performs them, carrying state from step to step.
  • why: a chain of gestures on one open program is what using it looks like, and an isolated one-gesture run is a path no human takes.
rule
every story is one somebody really lives.
  • how: the user tells the stories and the writer never invents one.
  • how: the writer writes the what, the how and the tests, and assembles them into the stories it was told.
  • why: there are very few of them, because a story is a whole real use rather than a feature.
rule
between them the stories reach every promise the program makes — that reach is the semantic coverage.
  • why: a promise no story reaches goes unmeasured.
  • how: the writer finds the gap and must propose it; the user decides.
  • how: a what that fits no story is that signal — either one is missing from the set, or nobody does that thing, and which it is is the user’s call.
rule
ground walked twice is cut.
  • why: overlapping stories cost CPU, RAM, time and money
  • how: the writer suggests the stretch to cut and the user cuts it.
  • scope: stories overlap a little whatever happens, each one opening the program and loading the same first screen, and that much is irreducible.
  • scope: the user may bend a story so that it stops short of showing the whole thing, when the reasoning shows the trimmed part is measured elsewhere.
    • why: what is protected is semantic coverage, not the walking of every path.
  • rule: the reasoning linking promises to stories capture the cut and indicate how a set of stories is fulfilling a given promise

The surface and the data

The promise is made at the seam the user touches
rule
whoever uses the work decides where the seam is — the end user of an application, the programmer calling a library.
  • why: the promise is made at that interface; below it is the how.
rule
assertions probe the observable surface — visible text, public API, exported artifact, ARIA role — not internals like private stores, test-only hooks or implementation-selector classes.
  • why: an internal is the how, no user should care about the fact that how works, but people care that the promise is fulfilled.
  • example: in web dev, the suite reaches for get_by_role, get_by_label and get_by_placeholder rather than CSS selectors that encode the current DOM.
rule
the code carries nothing that exists solely for the test.
  • why: an affordance that exists only so a test can reach something serves no one who uses the program.
  • example: in web dev, a data-testid or an attribute added for the suite — the final user never reads a test id.
  • how: when the program turns out hard to test at the seam the user touches, the difficulty is real information, and the fix belongs in the design.
    • why: usually the interface is just as unclear to the user.
A test seeds the world it reads
rule
the test world must be as close as possible to the real life
  • why: the product ends being used in real life, promises tested in a different env but that don’t work in real life are worth nothing.
rule
when possible, the real world is duplicated for the test purpose
  • example: if possible a pg_dump of the production database gives a good sandbox to check the promises.
rule
but a test creates the fixtures it depends on
  • why: it helps reproducible result by contrast to using the real world.
  • why: tests must assert there promises while not being disturbed by the changes of the real world
rule
the user decides the properties of the test world, not the writer
  • why: the writer is tempted to create a dummy world that has nothing to do with real life to make tests pass

When it goes wrong

Test, don’t patch
what
a bug is a promise found broken.
rule
every fix starts from a red, added to an existing story or by writing a new story. Observed red, then made green by the smallest change that satisfies it.
A flake is a diagnosis, not a knob
rule
an intermittent red is measured before any limit is touched.
  • why: widening a timeout is hiding the symptom, not fixing the problem
  • why: the expected time usually sits far under the ceiling, so the failure is a transient — a CDN stall, a resource race — to remove (e.g. by a fixture) or isolate.
rule
a timeout is raised only when the measurement shows the expected time nearing it.
  • rule: the new number is justified in a comment.
rule
any limit change must be validated by the user
rule
flakiness that is not obvious to fix gets meaningful logging.
  • why: it helps investigate the next time the flakiness occurs.
rule
moving on a flaky test is the choice of the user, never the one of the writer.

The cycle

rule
the cycle is the unit of change.
  • why: each step exists because the previous one is provably insufficient.
  • why: skipping a step leaves a gap the next regression will fall into.
rule
the baseline run covers THE WHOLE SUITE, not a subset.
  • why: a subset baseline says nothing about pre-existing reds of the whole baseline.
rule
the baseline run is gated like any other action.
rule
a codebase that is red and not flaky has its tests fixed before the task at hand resumes, unless the user explicitly asks otherwise.
rule
a promise is measured by the suite the cycle runs, and by nothing else.
  • why: a measure taken anywhere else is one no cycle can cite.
rule
the cycle is the succession of the following sub headings
1. focus on one promise at a time
rule
only one promise is fulfilled during a cycle
  • why: focusing on several creates a mess hard to untangle
rule
the other known promises are still taken into account when writing one
  • why: sometimes, we know that what we are doing is going to be put into question or factorized by a future promise
  • why: there are several minimal ways to fulfil a promise, choosing the one of least future friction is preferable
2. Red proves the test
rule
every test must be observed RED for the good reason at least once
rule
a test that passes for the wrong reason is worse than one that fails for the wrong reason.
  • why: a wrong-failure test still points at a real fault to hunt; a wrong-pass test sits green and hides a gap the suite reports covered, and its green is indistinguishable from outside, so it survives every whole-suite run.
rule
the test is written first and observed red before any production code changes.
  • why: that failure is what establishes that the test measures the promise it names.
rule
the failure mode and message are part of the test’s value.
rule
provided a given code, a test either always fails or always succeeds always for the same reasons
  • why: a flaky test cannot be trusted
rule
a test that was restructured rather than written is observed red again, by breaking the promise it names.
  • why: a restructuring starts and ends green, so the moment that would have shown the test still bites never arrives (see the wrong-pass rule above).
  • why: the failure names which test catches the break, so one that has drifted to where an earlier test already covers it is visible as well.
  • how: break one behaviour at a time, in the production code, and require the named test to be the one that fails; a break nothing catches is a test that claims a promise it does not read, and a break something else catches first is a promise measured elsewhere.
rule
a promise that cannot be broken from where the suite stands is recorded as such, in writing, with the reason NEVER without the user gating the decision.
  • why: otherwise it is indistinguishable from one nobody has got round to breaking, and the next reader spends the effort again.
  • why: the reason is itself a finding — it usually names a boundary the suite cannot reach past, which is worth knowing before trusting what lies beyond it.
3. Minimum to green, then a test before the next line of code
rule
new behaviour appears under a failing test, and the next line of code waits for the next test.
  • why: code beyond what the failing test demands is untested by definition and therefore unwanted.
  • why: the coupling keeps the suite a faithful description of the system, every branch tracing back to a test that was once red.
  • scope: a refactor pass adds structure no single test motivates.
  • rule: an anticipated edge case is written as the next failing test, not as a preemptive guard in the current change.
4. The whole suite measures the whole contract
what
the contract is every promise the program makes to whoever uses it.
rule
a change is verified only when the whole suite is green.
  • why: the new test going green proves its own promise realised, and says nothing about which of the others the change broke.
  • why: implicit dependencies between modules — shared state, cached values, ordering assumptions — surface only when every test runs.
  • why: the test you left out is the one most likely to catch the regression you did not predict.
  • why: a green-to-green refactor can still flip a subtle ordering, a fixture, or a shared helper.
  • why: what each run guards against is unknown ahead of time, which is what makes it a regression rather than an anticipated case.
5. Refactor lives under green
rule
structural change runs under a green suite.
rule
behaviour is held fixed by the tests, and structure is the only thing allowed to move.
  • why: mixing behaviour change with structure change loses the bisect signal — a test going red mid-refactor no longer tells you whether it caught a regression or reacted to an in-progress edit.
rule
the tests are refactored with the same discipline.
  • why: tests are code, and they drift.
  • why: the refactor-tests step is the only place in the cycle where test debt can be paid without losing signal, the suite being green on both sides of the edit.
  • why: a suite that takes too long stops being run.
  • why: a suite full of duplicated assertions gives false confidence that semantic coverage is broader than it is.

The export is the primary artifact

what
a code block is the technical translation of a bullet’s claim.
rule
a code block sits a glance away from the bullet it translates.
check
remove all code blocks mentally, and the remaining text still forms coherent and complete reasoning.
  • why: this is part of what makes the note literate — code and reasoning interleaved, not inserted side by side.
  • how: a gap means either a bullet is missing or an existing bullet was paraphrasing a block rather than advancing the reasoning, and the heading is rewritten accordingly.
  • how: the auditor reads the narrative-only version and judges whether the narrative fulfills the stated need.
    • why: narrative coherence has no binary signal, so that reading catches what a passing suite cannot.
rule
a code block carries the :exports header the reading needs.

When a code block appears in the export

rule
a code block appears in the export only when the narrative talks about it.
  • why: re-showing a block the reader has already seen adds nothing, even when the next block depends on it.
  • scope: repetition is justified when seeing the surrounding code genuinely helps the reading.
  • how: :noweb is yes or no-export depending on what makes the code readable.

The reader’s flow is sacred

rule
what breaks the flow — a technical derivation, a self-contained construction whose result the reasoning will consume — moves to its own heading or note, linked from the reasoning where its result is used.
rule
an ungrounded name breaks the flow wherever it appears — narrative, comments, docstrings, function names, variable names, symbols, any identifier in any form.
  • why: the reading flow does not care which fence a name sits behind.
  • how: where a forward-reference to a code-level term — a field, a function, a class — hides a readback, removing the term fixes both at once.
    • why: the narrative was reaching for the implementation when it should have been naming the need.
  • rule: a reference in the exported flow is grounded in the exported flow.
    • why: content kept out of what the reader will read does not exist for that reader, so grounding that lives only there leaves the reference ungrounded forever.
    • how: either the grounding moves into the export, or the reference leaves it.
  • rule: vocabulary lives in the narrative — the states a field can take, the thresholds that govern behavior and the constants that pace the system are named there, not in a type comment listing valid values, a magic number setting a tempo, or a literal fixing a bound.
rule
the narrative carries the reasoning a picture cannot state — the motivation, the texture, the judgment.
rule
the narrative stops re-describing what a picture states better.
  • why: a picture delivers in one glance what a bullet hands over clause by clause for the reader to reassemble.
rule
literate also means literary — the note is written to be read, not recited.
  • why: a note that is technically clear but emotionally flat loses readers as surely as one that breaks flow with detours.
rule
exported content links only to exported content.
  • why: a link from the export to what is not exported is a dead link.
  • scope: content that is not exported links wherever it likes.

When a block exists

rule
a block exists only where the narrative has made it necessary.
  • why: a block the narrative did not lead to means a piece of reasoning is missing.
  • how: the why, the reason for the choice, stays in bullets, never in a code comment.
    • scope: what remains in code is at most a one-liner annotating the specifics of the line below.
  • how: the what is translated into a test.
  • how: the how is translated into code.
  • rule: the narrative states the problem or need, never a readback of the code.
    • rule: a what is never stated without its why.
    • why: a narrative that paraphrases the block is duplication, not justification, and a note listing “this does X, that does Y” hands over facts no one asked for.
    • how: the note moves in a single register — I need to meet this objective, so I will do this, and so I will do it this way — need, then intent, then technique.
    • scope: where the gap between intent and form is wide enough that a short readback bridges it, the readback stands as a translation aside.
  • scope: this binds the reading, not the source — tangle scaffolding lives invisibly, usually under a :noexport: heading or marked :exports none, and needs no motivating narrative because it is not read.
rule
the code is carved along its own joints, never along the narrative’s.
  • how: noweb reassembles the pieces at tangle time, so the two structures owe each other nothing.

How a block is cut

rule
the reading flow is the only criterion for how the narrative and code are sliced against each other.
  • scope: one block per symbol, several symbols per block, several blocks per symbol are all legitimate.
  • how: the slicing has failed when the reader pauses on a function and asks “wait, what is this for? I was reading about something abstract and I don’t see the connection.”
  • how: boilerplate — every getter and setter of a Java bean, say — does not get a bullet each.
    • why: that would drown the reader in motivation no one needed.
  • how: a block dropping several unrelated functions under a single vague bullet calls either for more bullets or for splitting the block, whichever restores the flow.
    • why: it leaves the reader unmoored.
rule
a block is taken in at a glance — past 30 lines, it splits.
  • why: past that the reader loses the thread between the bullet that motivated the block and the code that is supposed to translate it.
  • how: the block splits along the seams the narrative already has, each responsibility that was introduced as a distinct idea becoming its own block with a bullet of motivation just before.
  • how: a block that resists splitting means the narrative has collapsed several ideas into one, so the narrative is expanded first and the block splits naturally.

Translation asides

rule
where the intent is clear but its shape in code is surprising, a short bullet acts as a translator’s note — “we want X, but in code this is written as Y because Z”.
  • scope: this explains the gap between intent and form, not what the code does.
  • how: an aside is clearly identifiable as such, introduced by something like “In practice,” or “Under the hood,”.
  • how: an aside that grows beyond its role, explaining more than the translation gap, moves to its own note the narrative points at with a short link.
    • why: it would otherwise break the reader’s flow.
rule
asides stay rare.
  • why: too many of them pollute the note.
rule
needing an aside is read as a diagnostic before it is written.
  • why: sometimes it reflects a genuine gap between what human language and code can express, which is what the aside is for.
  • why: it can also reveal that the code is poorly organized, the surprising shape that needs a translator’s note simply being the wrong shape.
  • how: where the shape is wrong the code is refactored rather than papered over with an aside.

Where blocks sit

rule
the stories come first, in a heading of their own.
  • why: the reader meets what the program is for before meeting its parts, and a block that is only a limb of a story cannot be read until the story binding it has been.
rule
the test, the what, comes before the code, the how.
  • why: that is how we talk to each other — the desired behavior first, then the technique used to achieve it.
  • how: the narrative states what is needed and what we are going to do — “we need the list to reject a duplicate,” “so we block creation” — and the block just below is that need made visible, code that happens to be a test.
    • why: the word test barely surfaces in the reading, and the reader meets a promised behavior and, right under it, the code that pins it down.
  • how: a test standing apart, not flowing from an explicit assertion in the narrative, means a bullet is missing.
  • scope: test-specific machinery — a tricky fixture, an unusual harness step — gets a bullet only when it is genuinely hard to follow, which is rare.
rule
a block is laid out against the narrative that promises it.
  • rule: one bullet promises one what, and one test block checks it.
    • why: a test block checking several whats under a single bullet breaks the narrative flow, and the reader cannot trace which bullet promised what the test is checking.
  • rule: the bullet that promises a what is the one above the block that pins it.
    • why: when a block is only a step — it cannot fail unless an earlier one fails with it — the promise it appears to pin is pinned upstream, so the narrative that named it here has sent the reader to the wrong bullet.
  • rule: each what stays a visible block in the story heading that motivated it.
    • how: the scattered blocks tangle into the test file.

Rewrite, don’t patch

rule
when something forces the note to change — a bug, an oversight, a change of mind, a breaking change in an upstream library, a refactor that obsoletes an earlier choice — the affected narrative is rewritten so it reads as if the issue never existed.
  • why: adding a test and an explanatory bullet describing the mitigation leaves a visible scar rather than restoring the narrative.
  • how: the result is not a narrative that fixes something but one that was always correct, betraying no trace of the path that led to it.
rule
a scar is retrospective — a trace of a revision already applied, a debate already settled.
  • how: the distinguishing test is tense — a bullet describing a fix already made is a scar and is rewritten, one naming an open question the reader should know about is a caveat and is kept.
  • scope: prospective language is not a scar — honest framing of a value still to validate empirically, of an explicit test plan, or of a guard-rail against a tempting wrong path.
rule
when reasoning leaves the code — a justification moved to the narrative, a constraint absorbed into a cleaner design — the code that only carried it leaves as well.
  • how: an empty body, a one-armed conditional, a vestigial helper is each a fragment whose work now lives elsewhere.
  • why: the artifact then reads as if neither narrative nor code remembered the revision.

Notes linking here


  1. Donald E. Knuth on Literate Programming (CSLI Lecture Notes no. 27, 1992), at https://www-cs-faculty.stanford.edu/~knuth/lp.html: “Literate programming is a methodology that combines a programming language with a documentation language, thereby making programs more robust, more portable, more easily maintained, and arguably more fun to write than programs that are written only in a high-level language. The main idea is to treat a program as a piece of literature, addressed to human beings rather than to a computer.”

     ↩︎
  2. « Readability counts. » — PEP 20, The Zen of Python, Tim Peters. ↩︎

  3. « Simple is better than complex. » — PEP 20, The Zen of Python, Tim Peters. ↩︎