Skip to content

Commit 66f9cfe

Browse files
committed
articles: the demo did not prove the claim, and two of the pillar's three arguments were missing
"Prompt drift is almost never a prompt-only event. The field got renamed in the domain model." Directly under that, the page described its payload as "a projection of the same entities that drive your database and API" and showed a standalone value object with two bare strings and no entity anywhere in it — and the transcript below it was a rename of one of those strings. A reader who opened examples/showcase/ found the article's central demonstration proving something smaller than its sentence. The showcase is fixed upstream (metaobjects 82a12aeb5): the payload binds to Subscriber, and the fixture's rename moves onto the entity. But this site's deploy injects snippets from the newest npm-line RELEASE TAG, not main, so the published block stays the old one until the next release. The prose here is therefore written to be true of both: it says the payload CAN bind its members to those entities rather than asserting the visible snippet does, and the verify paragraph names the mechanism instead of a specific member. Once the snippet updates, both sentences get to be stronger. Also adds the two arguments the pillar makes that this page never did: - **Payload bloat as a reviewable diff** — absent entirely, and it is the argument with a number attached. An untyped bag means "what do we send this model" answers itself as whatever was in scope; a declared payload makes adding a field a line in a pull request. - **The cache-prefix consequence** — asserted twice ("cache stays warm") and never dramatised. Exact-prefix caching ends at the first differing byte, so a stray space does not throw, does not degrade the answer, and does not appear in a log. It appears on the invoice weeks later, unattributable. That is the whole reason determinism is a feature and not a detail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NTcEKXTQMYt84fAjuw5A2M
1 parent bbfe934 commit 66f9cfe

1 file changed

Lines changed: 6 additions & 2 deletions

File tree

www/articles/prompts-are-code.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,17 @@ <h2>What prompts-as-code looks like in practice</h2>
131131

132132
<p>(It grew out of a mess of my own — a few thousand lines of <code>StringBuilder</code> driving the characters in an LLM game. For the origin story, and the <em>data + text + render</em> decomposition that became the fix, the longer essay is <a href="https://dougmealing.com/writing/the-prompt-is-code/">The prompt is code — and yours is drifting too</a>.)</p>
133133

134-
<p>A prompt declares its input as a typed payload — a projection of the same entities that drive your database and API — and names its text by a logical reference, so the text itself stays a versioned file in your repo rather than a row in someone's cloud:</p>
134+
<p>A prompt declares its input as a typed payload — a value object that can bind its members to the same entities that drive your database and API, so a prompt's shape belongs to the model rather than sitting beside it as a lookalike — and names its text by a logical reference, so the text itself stays a versioned file in your repo rather than a row in someone's cloud:</p>
135135

136136
<pre class="example-code" data-snippet="showcase-prompt"></pre>
137137

138+
<p>Naming the members is not bureaucracy — it is the only thing that makes a prompt's cost legible. Fill a template from an untyped bag and the honest answer to &ldquo;what do we send this model?&rdquo; is <em>whatever the caller had lying around</em>. Someone passes the whole user object because it was in scope, thirty fields ride along on every call forever, and nothing anywhere records that it happened. When the payload is declared, <strong>adding a field to a prompt is a line in a pull request</strong> — with a name on it, in a review, next to the reason. Payload bloat stops being a mystery you diagnose from a bill and becomes a diff you either approve or don't.</p>
139+
138140
<p>From that one declaration you get a generated, typed <code>render</code> function per language — deterministic and byte-identical across all five ports (there's a shared conformance corpus that proves it), so snapshot tests pass and your exact-prefix prompt cache stays warm. Nothing reformats your prompt behind your back.</p>
139141

140-
<p>And because the payload is <em>declared</em>, the build can check it. Reference a variable the payload doesn't have — rename <code>subscriberName</code> in the model and forget the template, say — and <code>meta verify</code> says so and exits non-zero:</p>
142+
<p>That last one is worth spelling out, because it is the failure with no symptom. Provider prompt caching matches your prompt <em>from the first byte</em>, and the first byte that differs ends the match — everything after it is billed as new input, where a hit would have cost up to about a tenth as much. So a reordered key, a trailing space, a template helper that decides to pretty-print today does not throw, does not return a worse answer, and does not show up in a log or a test. <strong>It shows up on the invoice, four weeks later, as a number nobody can attribute to a change.</strong> Deterministic rendering is what makes that class of bug impossible rather than merely unlikely.</p>
143+
144+
<p>And because the payload is <em>declared</em>, the build can check it. Rename a field, carry the rename into the payload, and forget the one template still writing the old variable — <code>meta verify</code> says so and exits non-zero:</p>
141145

142146
<pre class="example-code" data-snippet="verify-transcript"></pre>
143147

0 commit comments

Comments
 (0)