Skip to content

Teach the build prompt what a nine-round photo bug taught us - #12

Open
debtn wants to merge 1 commit into
mainfrom
claude/field-report-photo-bug
Open

Teach the build prompt what a nine-round photo bug taught us#12
debtn wants to merge 1 commit into
mainfrom
claude/field-report-photo-bug

Conversation

@debtn

@debtn debtn commented Sep 4, 2026

Copy link
Copy Markdown

Prompt-only. Two files, +13 lines, no code paths touched. Independent of #8, #10, #11.

The field report

Deb's Sahale Calendar (Kitsap Peninsula) has a feed where neighbors post what they notice on the land, often with a photo taken on the spot. Photos arrived blurry. A small, well-defined bug took nine exchanges, four of which were crashes the assistant introduced itself — each costing a full round trip, on a phone, on a rural connection, to report a typo. The fix that finally worked was simple and could have been the first attempt.

Round Deb sent The assistant did
1 "that is so blurry haha" Correct diagnosis. Built a chunked-photo system across 4 files.
2 "picture wouldn't shrink small enough" Theorised Safari ignores the quality dial. 3 edit blocks.
3 undefined is not an object ('small.fits') Caller expected a return shape the callee no longer had.
4 can't find variable: inKb A helper used in an error message, never written.
5 "29KB at 320 pixels" Theorised sparse downsampling → speckle. Rewrote the scaler.
6 can't find variable: kb Name drift, plus a value the function never returned.
7 "21KB at 320 pixels" Safari quality dial again. More edits.
8 can't find variable: thumb_from Constant invented in one hunk, defined in none.
9 Rewrote the file. Measure-and-scale, no theory. Worked.

Five patterns explain why. Each is now a rule, placed where the existing prompt already speaks rather than pasted on as a block.

What changed, and where

1. Edit blocks drift when they change a contractEditing Existing Files. All four crashes were one failure: SEARCH/REPLACE hunks changed a function's return shape or introduced a module-level name, and a sibling hunk didn't keep up. The existing "several distinct changes → multiple pairs in one block" rule is right for wording and local logic, and actively dangerous for interface changes. Now: a change that alters a signature/return shape or introduces a module-level name outputs the complete file; and a reply with edit blocks confirms every identifier it introduces has exactly one definition in the same reply.

2. Error paths are the one code path a build never runsQuality Rules. Three of the four crashes lived inside "couldn't shrink this photo" — a branch nothing in build-and-preview ever touches, so bugs there survive every check and surface on a neighbor's phone. Now: error, empty, and refusal branches carry no helpers and no values the working path doesn't already hold.

3 + 4. Three confident theories, none verified; fixes before diagnosis → new section, When the Bug Lives Somewhere You Cannot See. Rounds 2, 5, 7 each opened with a diagnosis stated as fact and a fix built on it; none was testable, because the assistant cannot run code on an iPhone. The fix that worked contained no theory. Now: prefer code that measures and adapts over code that encodes a model of the device; after one failed fix on device-side behaviour, stop fixing and ship the smallest thing that reports what the device actually did, saying plainly the round is for finding out; and say which kind of round it is.

5. Overconfident closing lines — the one Deb named as worstChat Style While Building. "It should just work." "A refusal is now essentially impossible." Four promises, all false, and each made the next failure a broken promise rather than a bug report. Now: never predict the outcome of a change you could not run. Say what changed, why it should address the cause, and what to look for — framed as a check, not a promise. Name untested assumptions and what would disprove them. When a fix already failed, say so before proposing another.

The gap underneathCommunity Cloud guidance (catalog.ts). Every workaround in that session existed to squeeze a photo through a 32KB JSON document. Base64 inflates by a third, so that's ~20KB of actual image — a thumbnail, not a photograph; Deb's own numbers (21–29KB at 320px) bear it out. The remaining blur she accepted is that arithmetic, not a bug. Until an upload capability exists, the guidance now says the ceiling out loud before anyone builds on it and gives the measure-don't-theorize shrink recipe, so nobody derives it during a live debugging session.

Cost

The build prompt grows ~3.5K chars (~875 tokens, ~7%), all in the cached prefix. The photo bullet adds ~1.1K only when Community Cloud is connected. Verified the composed prompt carries every rule in the intended section order, zero page errors; tsc -b clean, eslint clean on both files.

Not in this PR — the real fix

Blob storage for Community Cloud (an upload alongside the JSON document store: upload returns a URL, documents reference it). Photos are among the most natural things neighbors contribute — a noticing on a trail, a found cat, a finished repair — and today every builder who wants them reinvents the same chunking scheme, badly, and ends with soft pictures. There's a seed already: supabase/functions/story-photos hosts images on the Builder backend's public storage for commons stories, gated to signed-in builders. An app-files capability for neighbor uploads would need its own abuse posture (per-app quotas, size caps, moderation in the Cloud tab), which is why it's a platform decision rather than a line in this PR. The prompt rule is written so it becomes simply wrong the day that ships — "there is no file or image upload yet" — and should be removed with it.


Source: field report by Deb, Sahale Calendar, February 2026. Open items on her build (photos still softer than they should be; a photoparts collection and src/lib/photos.ts chunking that come out together if blob storage lands; untested on Android) belong to that project, not this repo.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RFnFvBZPsVQjc5Xwj7H9nZ


Generated by Claude Code

A field report from the Sahale Calendar (Kitsap Peninsula): a small,
well-defined bug — photos in a shared feed came out blurry — took nine
exchanges to resolve, four of them crashes the assistant introduced itself,
each costing a full round trip on a phone on a rural connection to report a
typo. The fix that finally worked was simple and could have been the first
attempt. Five patterns explain why it wasn't, and each is now a rule in the
prompt, placed where the existing guidance already speaks.

Edit blocks drift when they change a contract. All four crashes were the
same failure: SEARCH/REPLACE hunks changed a function's return shape or
introduced a module-level name, and a sibling hunk did not keep up —
`small.fits` read by a caller the callee no longer served, a `THUMB_FROM`
used in one hunk and defined in none. The "several distinct changes →
multiple pairs in one block" rule is right for wording and local logic and
actively dangerous for interface changes. Now: a change that alters a
signature or return shape, or introduces a module-level name, outputs the
complete file; and a reply with edit blocks confirms every identifier it
introduces has exactly one definition in the same reply.

Error paths are the one code path a build never runs. Three of the four
crashes lived inside a "couldn't shrink this photo" message — a branch
nothing in the build-and-preview cycle ever touches, so bugs there survive
every check and surface on a neighbor's phone. Now: error, empty, and
refusal branches carry no helpers and no values the working path doesn't
already hold.

Three confident theories, none verified. Three rounds each opened with a
diagnosis stated as fact (Safari ignores the quality dial; sparse
downsampling makes speckle; Safari again) and a fix built on it. None was
testable — the assistant cannot run code on an iPhone. The fix that worked
contained no theory: encode, measure, step down until it fits. A new
section, "When the Bug Lives Somewhere You Cannot See": prefer code that
measures and adapts over code that encodes a model of the device; after one
failed fix on such behaviour, stop fixing and ship the smallest thing that
reports what the device actually did, saying plainly that the round is for
finding out; say which kind of round it is.

Overconfident closing lines — the one the person named as worst. "It should
just work." "A refusal is now essentially impossible." Four promises, all
false, and each made the next failure a broken promise rather than a bug
report. Now, in the chat-style rules: never predict the outcome of a change
you could not run; say what changed, why it should address the cause, and
what to look for, framed as a check; name untested assumptions and what
would disprove them; and when a fix already failed, say so before proposing
another.

The gap under all of it is the platform's: Community Cloud has no blob
storage, so every photo workaround in that session existed to squeeze an
image through a 32KB JSON document — about 20KB of actual picture, a
thumbnail. The remaining blur is that arithmetic, not a bug. Until an upload
capability exists, the Community Cloud guidance now says the ceiling out
loud before anyone builds on it, and gives the measure-don't-theorize
shrink recipe so nobody derives it during a live debugging session.

Prompt cost: the build prompt grows about 3.5K chars (~875 tokens, ~7%),
all in the cached prefix; the photo bullet adds ~1.1K only when Community
Cloud is connected. Verified the composed prompt carries every rule in the
intended section order with zero page errors; tsc -b clean, eslint clean on
both files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RFnFvBZPsVQjc5Xwj7H9nZ
@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
relational-builder Ready Ready Preview Sep 4, 2026 8:26am UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants