Skip to content

fix(style): the style's generation prompt never reached the user - #47

Merged
catomean merged 1 commit into
mainfrom
fix/style-prompt-reaches-the-user
Sep 7, 2026
Merged

fix(style): the style's generation prompt never reached the user#47
catomean merged 1 commit into
mainfrom
fix/style-prompt-reaches-the-user

Conversation

@catomean

@catomean catomean commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

The bug

Picking an art style stored style_id and lit a progress checkmark. That was the entire effect.

prompt_template and negative_prompt are seeded on every style row, declared on the Style type, and already shipped to the browser on every project page — GET /api/projects/[id] joins style:styles(*). They were then read by nothing.

Meanwhile the figures step told the user, in its own words:

Use an AI tool (Grok, Midjourney) to generate a styled version

…and never showed the prompt the style was written for. In Phase 1 the styled image is produced by hand and uploaded back, so that instruction is the handoff from app to human — and it was empty. Every figure got whatever prompt its user happened to recall.

Figures only merge into one scene when they were all generated the same way, so a per-figure prompt typed from memory is a Ground Truth #3 failure ("Style consistency across all figures… if any element feels pasted in, the illusion breaks"), not a missing convenience.

The fix

The figures step now shows the chosen style's prompt and negative prompt with copy buttons, and links to the style step when no style is chosen yet.

The prompt is rendered exactly as stored. The seeded templates carry no {placeholders} despite the data-model doc saying they might, so there is no substitution to do and none is invented (YAGNI).

No API, schema, or hook change — the data was already on the wire.

Why the guard is narrow

Same shape as the orphaned /api/compositions route fixed in #25, one level down: there a route with no caller, here a column with no reader.

A blanket "every modelled column is rendered somewhere" check would have to allowlist all of Export, face_embedding and face_confidence — deliberately unbuilt Phase 2/T2 surface — so it would be noise, not a gate. Per the never-twice rule this is the second sighting of the family: recorded as a pattern, automated only if it recurs.

Verification

  • Root pnpm run verify green: format + lint (0 errors, 8 pre-existing warnings) + tsc + 101 tests, up from 98
  • Production-parity next build green using CI's placeholder env
  • New guard mutation-verified: reverting the wiring fails all three of its assertions

Not verified: the panel rendered in a real browser against real data. Local app/.env.selfhost.local (git-ignored, untracked) points at hosted Supabase ref ckpynkpsfnuqndplaapc, which is NXDOMAIN from a public resolver, while production is built against self-hosted https://supabase.orangecat.ch and is healthy (GET /api/projects{"success":true,...}). Guest mode needs the service-role key, which this session does not have.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SZGjXtzLGk2q9zPUkA3vMf

Picking a style stored `style_id` and lit a progress checkmark, and that was
the whole effect. `prompt_template` and `negative_prompt` were seeded on every
style row, declared on the `Style` type and shipped to the browser on every
project page — GET /api/projects/[id] already joins `style:styles(*)` — and
then read by nothing.

Meanwhile the figures step told the user, in its own words, to "use an AI tool
(Grok, Midjourney) to generate a styled version" without ever showing the
prompt the style was written for. In Phase 1 the styled image is produced by
hand and uploaded back, so that instruction is the actual handoff from app to
human, and it was empty: every figure got whatever prompt its user recalled.
Figures only merge into one scene when they were all generated the same way,
so a prompt typed from memory per figure is a Ground Truth #3 failure, not a
missing convenience.

The figures step now shows the chosen style's prompt and negative prompt with
copy buttons, and links to the style step when no style is chosen yet. The
prompt is rendered exactly as stored — the seeded templates carry no
`{placeholders}`, so there is no substitution to do and none is invented.

Same shape as the orphaned /api/compositions route fixed in #25, one level
down: there a route with no caller, here a column with no reader. Guarded
narrowly rather than generically — a blanket "every modelled column is
rendered" check would have to allowlist all of `Export`, `face_embedding` and
`face_confidence`, which are deliberately unbuilt, so it would be noise. Per
the never-twice rule this is the second sighting of the family: recorded as a
pattern, automated only if it recurs.

Verified: full root `verify` green (format + lint 0 errors/8 pre-existing
warnings + tsc + 101 tests, up from 98). Production-parity `next build` green
with CI's placeholder env. The new guard is mutation-verified — reverting the
wiring fails all three of its assertions.

Not verified: the panel rendered in a real browser against real data. Local
`app/.env.selfhost.local` (git-ignored, untracked) points at hosted Supabase
ref `ckpynkpsfnuqndplaapc`, which is NXDOMAIN from a public resolver, while
production is built against self-hosted https://supabase.orangecat.ch and is
healthy. Guest mode needs the service-role key, which this session does not
have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SZGjXtzLGk2q9zPUkA3vMf
@catomean
catomean merged commit dd60140 into main Sep 7, 2026
1 check passed
@catomean
catomean deleted the fix/style-prompt-reaches-the-user branch September 7, 2026 04:16
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.

1 participant