Skip to content

1.19: the Prompt builder, a fourth tab where an Ollama LLM asks questions and writes the prompt - #41

Merged
NoSQLKnowHow merged 20 commits into
mainfrom
prompt-builder
Nov 9, 2026
Merged

NoSQLKnowHow merged 20 commits into
mainfrom
prompt-builder

Conversation

@NoSQLKnowHow

Copy link
Copy Markdown
Owner

What this is

Version 1.19, built to docs/DESIGN.md §37 (criteria 221 to 257; specified in #39 and decided with you on 2026-10-28).

A fourth tab, Prompt builder. You type a rough idea; an LLM hosted in your Ollama (STUDIO_OLLAMA_URL, STUDIO_OLLAMA_MODEL in .env) asks up to three questions at a time (tap a chip to answer) until it has written a prompt. You see it think, you can Stop it, and nothing it writes is run: only a button you press queues anything.

  • Prompts are saved with every version kept (versions are only ever added), can be compared (changed words marked in text as well as colour), made current again (a copy), fleshed out in a chat, tagged, starred, searched and sorted, and filed in the same projects as your pictures, which then follow the prompt. A bin keeps deleted prompts and chats for 30 days.
  • Every chat is saved and can be continued; short standing preferences are told to the model in every reply; it is shown which of your saved prompts it was given as examples, and each can be left out.
  • Use in Images / Vector / Music fills the other tab's form (with an Undo and a From Prompt builder chip), Generate now queues a run from a prompt without touching the form, Quick try makes a Draft whose picture shows on the version; every run made from a prompt says From "title" v3 and opens it. Refine in Prompt builder (on a picture, in the viewer, in a prompt's detail), Help me write this (Edit), pictures attached to a chat (choose, drop, paste, or from your history) and Describe as a prompt.
  • Unload from memory asks Ollama to let its model go (the studio never starts or stops Ollama); the image model's "not enough memory" advice now mentions it.
  • Without an Ollama set up, saved prompts, versions, comparing, projects and preferences still work.

Back up first

The first start of 1.19 upgrades the database to schema 9 (new tables for prompts, versions, chats, messages, attachments and preferences; runs.prompt_id and runs.prompt_version as the last two columns so an upgraded database equals a new one). A copy is made first (data/studio.sqlite.before-schema-9); every run and project is kept. docs/SPARK_TEST.md section 30 is how to load it on the Spark (the branch, .env, Ollama) and what to check, and starts with ./scripts/backup.sh. The backup and restore scripts already cover prompts and chats (they live in ./data); their test now proves a chat's picture comes back.

How it was built

Server in backend/studio/builder/ (a stdlib Ollama client that never shows the address; a validator that drops anything the studio's own rules refuse and says so in words; one reply at a time; server-sent events; prompt_ref on POST /api/runs). Page: BuilderPanel and its parts, the rules as pure functions (builder.ts, promptUse.ts), the hooks useBuilder / useLibrary / usePromptUse. What was built, what the checks found and the small choices I made are in DESIGN.md §37.11.

Evidence (all local; the repo has no CI)

Run on the final tree (commit 9b98544, after merging main, which changed no file):

  • Backend 2361 passed, 3 skipped (1.18 had 1804). Front end 1123 (Vitest; 1.18 had 858). 295 in a real browser (Playwright; 1.18 had 281, +14 in e2e/builder.spec.ts): 294 pass and one does not, see below. Backup/restore script checks 303. Type check and production build clean.
  • Mutation checks, 932 mutants of the 1.19 code in two passes (server 460, page 472). The first pass left 162 survivors; the tests written for them killed 132; 30 remain, each judged one a test cannot tell apart (an alias spelling the API does not document, request types with nothing to coerce, a branch another makes redundant, one-past-the-end reads of a typed array…), listed by kind in §37.11. Details of what the survivors showed are in the commit messages of steps 6c to 6e.
  • Real bugs found on the way, all fixed: a Stop pressed between Send and the server listing the reply was lost (the reply ran on); the viewer on a 360 px phone wrapped once more because of the new Refine button and pushed the picture off the screen; a list read well wiped the error of another list that was not; a fresh copy of an open prompt replaced the title you were typing; attaching several pictures to a chat that did not exist yet made a chat for each; the toast after filing said "1 earlier picture's run is where they were"; and two browser tests of the tab bar still said Vector is the last tab.
  • The one browser test that fails is music.spec.ts Add lyrics shows Voice and the lyrics box… ("oh oh" is typed as "h oho"). DESIGN §36.9 records it for this machine's Chromium on earlier trees; it is in Music code 1.19 does not touch.

Not checked

  • Anything with your real Ollama and qwen3.8:27b: its speed, how long it thinks, whether it keeps to the structure (the studio asks again once with thinking off, then shows plain text, but I do not know how often that happens), whether think and the structured answer mix well in your Ollama version, whether host.docker.internal reaches it from the container, whether it reports it can look at pictures, and whether a 32768-token window fits next to Qwen-Image. SPARK_TEST.md section 30 measures each.
  • The instruction files (backend/studio/builder/instructions/*.md) are my first draft and nobody has read them with a model. They decide how good the questions are; please read them and tell me what to change. They are plain text.
  • A real phone and your own browsers (the browser tests use Chromium and a 360 px window); the upgrade of your real database (tested on a constructed schema 8 database only, hence the copy and the backup step).
  • The Spark itself. Nothing of 1.19 has run on the GB10.

Small choices made while building

All fourteen are in DESIGN.md §37.11. The ones most worth a look: (8) words used from The prompt so far are not a saved prompt, so Use in and Generate now from there carry no prompt reference and show no chip; (9) Use in for an Edit prompt puts the chat's pictures in the tray only if the tray is empty; (6) search looks at the title, the newest version's text and the tags, not older versions' words.

Known limits

One reply is written at a time (STUDIO_BUILDER_AT_ONCE, 1); a prompt's older versions are not searched; every picture attached to a chat is sent again with each later reply as far as the window holds them; nothing is exported (§37.10).

Notes

Version bumped to 1.19 (__init__.py, package.json, lock file, test data). Two commit messages on this branch are wrong in small ways that I could not fix because rewriting a pushed branch was blocked: 6530080 has a stray phrase ("STUBBED nothing else") and says 1081 Vitest tests where there were 1085; 316db4c says 1100 where there were 1097. The figures above are from the final run.



Generated by Claude Code

claude added 20 commits November 7, 2026 22:14
…nt, connection routes)

The first piece of DESIGN.md section 37, built so that nothing yet needs a
language model to be running:

- Settings for the Ollama server (STUDIO_OLLAMA_*, STUDIO_BUILDER_*), checked
  at start-up. A bad address is refused without echoing it; the address is
  kept out of repr, logs, capabilities and every message.
- A stdlib-only Ollama client: streamed chat with thinking, keep-alive and
  context settings, silence time-out versus an overall cap, Stop from another
  thread, redirects refused, errors reduced to fixed sentences with a hint.
- BuilderService: status (cached a few seconds), Test connection (always
  fresh), Unload from memory, and a cached view for the capabilities that
  never waits on the network.
- GET /api/builder/status, POST /api/builder/test, POST /api/builder/unload;
  capabilities.builder and limits.builder.
- compose.yaml and .env.example carry the settings, and extra_hosts so a
  container can reach an Ollama on the Spark itself.
- A fake Ollama server for the tests; tests check that compose, the example
  file and the parser agree.

No schema change yet and no page; the Prompt builder tab comes in later slices.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
DESIGN.md section 37.4, criterion 251:

- Seven new tables (prompts, prompt_versions, prompt_tags, chats,
  chat_messages, chat_attachments, preferences) and an FTS5 word index over a
  prompt's title, newest text and tags; where SQLite has no FTS5 the studio
  opens and keeps prompts without the index.
- runs gains prompt_id and prompt_version as its last two columns, plain and
  not foreign keys, so a migrated table equals a new one and deleting a prompt
  for good leaves them. A schema 8 database is copied to
  studio.sqlite.before-schema-9 first; an older studio refuses a schema 9 one.
- BuilderStore: chats and numbered messages, prompts with version 1 and tags,
  the index kept in step, the bin (bin, restore, delete forever, the
  clean-up, Empty bin), and the counts for the tab and its filters. The
  column for "For" is for_kind (for is an SQL keyword); the API will say for.
- Deleting a project deletes no prompt or chat and turns its preferences off
  while keeping them in it; the projects list counts prompts and chats that
  are on show.
- The app builds the store and rebuilds the index at start-up if it is behind.
- The schema-number tripwires move to 9; exact project counts gain
  prompts and chats; the 1.17 migration test no longer pins the number.

Still no routes for prompts or chats, and no page.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
Hand-picked mutants of BuilderStore showed four real gaps, now covered:
versions are listed oldest first (checked with three versions), a chat in
the bin and in no project is counted only under deleted, an index with a row
too many or a row for a prompt that is gone is rebuilt (by count and by a
full rebuild from nothing), and the store's refusal says what is wrong.
Stored message content is checked to be written one way.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
… schema)

Hand-picked mutants of the schema showed that nothing tested the tables
refusing a bad value, a version or message number below 1, a second message
with the same number in one chat, or the defaults (a new preference is on, a
new prompt is not a favourite). Every value of each allowed set is now
accepted and one outside it refused, straight in SQL; the sets are pinned
to the spec's; and the accent test no longer compares two empty searches.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…med replies, pictures)

DESIGN.md section 37.3 rules 6-11 and 13, 18, and section 37.5:

- Five instruction files (common, images, vector, music, edit), FIRST DRAFTS
  for the owner's review; the studio fills in its own numbers and a typo in
  a {{word}} is an error rather than text sent to the model.
- answer.py: the JSON schema sent as Ollama's format (reply first) and a
  validator that keeps only what is valid by the same rules as a run
  (shapes, guidance, steps, palette less white, sizes, lengths, three
  questions, three to five chips); what breaks a rule is dropped and the
  reply says so in words. An unreadable answer is asked again once with
  thinking off whatever the setting, then shown as plain text.
- context.py: earlier turns are sent as what they said (no draft, no
  reasoning); the oldest are dropped first when the window is full, never
  the instruction, preferences, examples, draft or the newest turn.
- engine.py: the person's message is saved first, so a failed reply never
  loses it; the reasoning streams but is never stored; Stop keeps what was
  written, marked; closing the connection keeps none of it.
- chat_routes.py: chats (list, create, read, rename, file, bin, restore,
  delete), the streamed message route, Stop, one reply at a time with
  waiting and busy-making-an-image events, and pictures attached to a chat
  (copied in, shrunk to 1536 px, checked as an edit's upload is, removed
  with the chat).
- A scripted model for STUDIO_BUILDER_LLM=fake that can be told to
  misbehave, so every failure path is reachable without a real model.
- Tests run a real server for Stop and a closed page, since TestClient
  delivers a streamed reply only when it is over.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…ences) and runs from a prompt

DESIGN.md section 37.3 rules 1-5 and 7, section 37.4; criteria 229, 230, 236-238, 245-247:

- Library: versions are only ever added; saving what is already the newest
  makes none and says "Nothing changed." (settings compared in one canonical
  form, so 4 and 4.0 are the same); Make this the current one copies an old
  version as the newest; tags, star, project and kind; search over title,
  newest text and tags (each word starts a word; plain match where SQLite has
  no FTS5); filters and sorts; the pictures made from each version.
- Compare: the words that changed (removed and added runs), the negative
  prompt and each setting, computed on the server so it is tested once.
- Preferences: add, edit, switch, delete; no duplicates; at most 50; a note
  of a project that is gone stays off until it is given a place.
- Routes under /api/builder: prompts, versions, compare, bin, restore,
  delete, file-runs ("Also file its pictures' runs": nothing moves until
  asked), preferences, counts, and Empty bin for the builder's own bin.
- POST /api/runs takes prompt_ref {prompt_id, version} for every kind. The
  prompt must exist (404) and not be in the bin (409) and have that version
  (422). A run from a prompt in a project is filed there and kept; a quick
  try (a draft) is linked but neither. The run's payload says where it came
  from, whether that prompt is deleted, and whether the words differ
  ("edited"); GET /api/runs?prompt= lists the runs made from one.
- Prompts and chats in the bin are deleted for good by the daily clean-up on
  the same clock as pictures, and with no bin (STUDIO_BIN_DAYS=0) Delete is
  for good at once; chat folders go with their chats.
- The Vector contract and the page's Run type gain prompt_ref.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
… rules

The foundation of the Prompt builder's tab, with no component yet:

- builderTypes.ts: the shapes the server sends (status, chats, messages and
  what a reply contains, prompts and versions, preferences, counts, the
  events of a reply), and capabilities.builder / limits.builder.
- sse.ts: a parser for server-sent events that hands over nothing until an
  event is complete, and a reader for a streamed POST (EventSource cannot
  POST); an error status becomes the studio's own error, a drop in the
  middle says the server can't be reached.
- builderApi.ts: every call of the builder, through the studio's request
  helper, with the X-Studio-Client header on each change.
- builder.ts: what a reply is doing; choosing chips (tap, tap again,
  Surprise me, Skip); reading a chat (open questions, newest draft); the
  words that changed; the length meter; how a prompt's settings are laid
  over the Images options and the exact words of the Undo toast; the
  request for Generate now and a quick try; where a run came from.
- prompt_ref is a wrapper type, not a field of the create bodies, which the
  Vector contract pins key for key.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
… saving

The fourth tab (DESIGN.md section 37.2, criteria 221-229, 244, 248, 250, 253, 255-256):

- A tab after Vector, remembered like the others, with a dot while a reply
  is being written; the panel stays mounted so a reply carries on while
  another tab is open. The tab is wider than the rest (list, chat, prompt);
  on a phone it is one column with a Chat | Prompt | Library switch.
- Connection: not set up says how, in the spec's words; an unreachable
  Ollama or a missing model says which, with its hint; Test connection shows
  the version, the models, whether yours is there and whether it can see
  pictures; Unload from memory only asks. The page never has the address.
- Chat: the person's words appear at once; the reply streams; thinking shows
  the seconds and a fold, and is dropped when the reply ends; chips toggle
  on a tap, Surprise me and Skip replace them; Stop keeps what was written,
  marked; a failed reply keeps the message and offers Retry; a lost
  connection reloads the chat; the model's text is only ever text.
- The prompt so far: editable (the next message starts from it), a length
  meter against the limit, the words the last reply changed marked with
  strike-through and underline, the settings that fit as switches.
- Save as prompt / Save as new version, with the title and tags the builder
  suggested, the project and what it is for; Nothing changed. when it is.
- Pictures: attach, drop or paste into a chat (a paste on this tab goes to
  the chat), shown numbered, taken back, refused in the server's words, off
  with the reason when the model cannot see.
- Server, for the page: the status says which way Think starts; a chat can
  be linked to a prompt through PATCH; a reply can be asked again without a
  saved prompt that was left out (retry with redo).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
The Prompt builder tab now has its library (DESIGN.md §37.2, criteria 229-233, 245-247):

- Chats, Prompts and Preferences at the left; Chats and prompts can be looked at as they
  are or as they are in Deleted (restore, delete for good, Empty bin, each asked first).
- Prompts: search (title, words, tags) once the typing pauses, Show All / starred /
  Deleted and Project / Tag / Sort, each with its count; star without opening.
- A prompt opened: title, star, For, Project, Tags; every version newest first with
  its pictures; Make this the current one (a copy as the newest); Compare two versions
  with the changed words and settings marked in text; Flesh out; Delete / Restore /
  Delete forever; a prompt's chats; the offer to file earlier pictures' runs.
- Preferences: add, switch, edit, delete, where each applies; notes of a deleted project
  listed apart.
- A chat's name and project, from the chat header.

Two faults found while testing it, both fixed here: a list that was read fine wiped the
words about another list that was not (one shared error); and a fresh copy of an open
prompt from the server replaced the title or tags the person was half-way through typing.

1000 Vitest tests pass (34 new); tsc and the production build are clean.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
Use in …, Generate now and Quick try (DESIGN.md §37.2, §37.3 rule 3; criteria 235, 236,
239, 242):

- Use in Images / Edit fills the prompt box, sets only the settings left on, switches to
  Generate (or Edit), says what it set and offers Undo, and shows the "From Prompt builder:
  "title" vN" chip. Generate carries the chip's prompt as prompt_ref; ✕ removes it; Reuse of
  a run made from a prompt brings it back, and Reuse of any other run takes it away.
- Use in Vector / Music asks the panel to fill its form (idea or description, kind, colours,
  inks, size; fields, lyrics, length), keeping to each form's own rules: what the form cannot
  take is left out and named in the toast, and Undo puts the form back.
- Generate now queues a run at once from the tab's own options with the prompt's settings
  over them, without touching the form; for Vector and Music it uses the saved form. Quick
  try makes a Draft and stays in the builder. A prompt that is not saved carries no reference.
- The builder re-reads an open prompt when a run made from a prompt appears or finishes, so
  a quick try's picture shows on its version.
- Help me write this (Edit) is on the prompt bar, off with its reason when it cannot open.

The rules are pure functions (promptUse.ts); the behaviour is a hook (usePromptUse.ts) tested
with a fake API: 1041 Vitest tests pass; tsc and the production build are clean.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…where a run came from

DESIGN.md §37.2, §37.3 rule 3; criteria 237, 241, 243, 244:

- Every run made from a saved prompt says so on its card: From "title" vN, with edited and
  deleted when they apply, opening the prompt in the Prompt builder. A prompt deleted for good
  is named as such and cannot be opened.
- Refine in Prompt builder, on an Images card, in the picture viewer, and on a picture in a
  prompt's detail: a new chat linked to the prompt (when it still exists) and its project,
  holding the run's words in the prompt box and, when the model can look at pictures, the
  picture. The next message is sent as a refinement of that run (the server tells the model
  the run's settings and seed). A picture not made from a prompt opens an unlinked chat and
  saves nothing.
- Help me write this (Edit): the builder opens For Edit with the tray's pictures attached in
  order, in one chat, even when the model cannot look at them (it then works from their count).
- Pick from my history and Describe as a prompt in the chat.
- The page asks the builder for these things through one command channel (a new seq each time).

Fixed on the way: attaching several pictures to a chat that did not exist yet made a chat for
each, because the loop held the chat as it was when the first was chosen; the hook now tracks
the open chat as it is now. And a test of mine that asserted on an effect's call too early.

1074 Vitest tests pass; tsc and the production build are clean.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…tray for Edit

DESIGN.md §37.2, §37.3 rule 5, §37.4; criteria 243, 247, 249:

- The Manage projects list counts prompts and chats beside the runs ("Logo: 4 pictures,
  1 track, 3 prompts, 2 chats"), and the question before deleting a project says that its
  prompts and chats stay too, no longer in a project. A count the server did not send is not
  said as 0.
- When the Prompt builder is set up, the advice that goes with "Not enough free memory"
  (on a run, on loading a model, on the worker's state) also says to press Unload from memory
  on the builder's tab. Without the builder the advice is exactly what it was.
- Use in Images for a prompt made For Edit puts the chat's pictures in the tray, in the order
  the prompt numbers them, but only into an empty tray: a tray with pictures in it is the
  person's, so it is left as it is and they are told why.

1080 Vitest tests and 2322 backend tests pass (3 skipped, as before); tsc and the production
build are clean.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…, backups

- frontend/e2e/builder.spec.ts: 14 browser tests of the Prompt builder against the real server
  with the scripted model (STUBBED nothing else): the tab, an idea to a finished prompt, saving,
  versions and Compare, Use in Images with Undo, Generate now and the run's line, Quick try,
  filing in a project (and the offer to file earlier runs), Refine, Help me write this,
  preferences, the bin, a failed reply and Stop, text shown as text, a 360 px phone.
  playwright.config.ts starts the server with STUDIO_BUILDER_LLM=fake.
- A Stop pressed in the moment between Send and the server listing the reply was answered
  "no reply" and lost, so the reply ran on. It is now tried again for about a second while the
  reply is being waited for (found by the browser test).
- The toast after filing a prompt in a project said "1 earlier picture's run is where they
  were"; it now says "it was" for one.
- Version 1.19. The backup and restore scripts say they hold prompts and chats too, and their
  test now proves a chat's picture (data/builder) is in the backup and comes back.

1081 Vitest tests pass; 303 script checks pass.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…a phone, the Spark test

The whole browser suite (295 tests) was run on the tree: 291 passed, 4 did not, and
this commit deals with them:

- Two tests of the tab bar still said Vector is the last tab; the Prompt builder is
  (music.spec.ts, vector.spec.ts). They now say what is true, and that the bar wraps round.
- On a 360 px phone the viewer's row of buttons wrapped once more because of Refine in
  Prompt builder, and pushed the picture 35 px off the screen (studio.spec.ts caught it).
  In the viewer the button now reads "Refine" and keeps its whole name for a screen reader
  and the tooltip.
- music.spec.ts "Add lyrics shows Voice…" fails as DESIGN.md 36.9 records for this machine's
  Chromium ("oh oh" is typed as "h oho"), in code 1.19 does not touch. Not changed here.

Mutation checks of the page's new pure logic found tests missing at the limits (colours, sides,
a field, lyrics, description and length exactly at their limit), for "1 ink", for naming the
tempo, and for "nothing was left out"; and of the server's comparison, a long text (where
the matcher must not give up on common words) and an object whose keys come in another order.
They are added.

Also: README describes the Prompt builder and says backups hold prompts and chats;
docs/SPARK_TEST.md section 30 is how to load 1.19 on the Spark (the branch, .env, Ollama)
and what to check there.

Note on the previous commit (6530080): its message has a stray phrase ("STUBBED nothing
else") and says 1081 Vitest tests; there were 1085.

1090 Vitest tests pass.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…d a word when Stop keeps nothing

Mutation checks of usePromptUse.ts (68 mutants, 9 survivors) and of answer.py (156 mutants, 51
survivors, 36 of them in docstrings) showed what the tests did not pin down. Added:

- the hook does nothing until the page has its capabilities and options; Generate now for Edit
  when the pipeline cannot edit; an edit's own size is checked; the queue-full message is shown
  as the server wrote it; a picture with no type gets one; the tray message in the singular.
- the answer: the limits cannot be changed by what reads them; a bare Answer is not done and has
  no draft; the stored message carries the draft exactly; a plain-text reply is cut only past
  the limit; the object is found when it is the first thing and something follows it; the two
  "not an answer" messages; questions without ids are numbered from 1; both notices about inks;
  lyrics exactly at the limit; and the streaming reply's decoder at every edge of an escape and
  of a surrogate pair.

Also: when Stop is pressed before anything has been written the server keeps nothing and sends
no message, and the page said nothing at all. The chat now says "Stopped before anything was
written, so nothing was kept. Your message is still there."

Frontend: 1100 Vitest tests pass.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…d DESIGN brought up to date

The mutation rounds on the server (answer, context, library, diff, prompt routes, chat routes, the
engine) and on the page (builder.ts, useLibrary.ts) left survivors; most were in code the tests
did not pin down, and those are now pinned:

- the server: both limits of every field (a prompt of exactly the most characters, exactly the
  most tags), a PATCH that names only some fields, values that only look like the right type, the
  four things a button can ask for (flesh out, refine, describe, help write) reaching the model,
  what a Refine tells the model about the run, deleting a chat for good with and without a bin,
  the most pictures a message may carry (only the waiting ones count), a picture exactly as large
  as the limit, which draft the model is given (the person's edit, the last it wrote, the one a
  retry carries), asking again for three wordings, a reply that cannot be read twice, the name a
  chat gets, a stopped reply being neither finished nor plain text, how a job is stopped and who
  decides whether what was written is kept, the whole of a long text when it is compared.
- the page: the words that changed, held to a plain longest-common-subsequence over three hundred
  random pairs; the settings at exactly the studio's limits; an Edit request with no pictures; the
  words for a Vector and a Music prompt's settings; the search box's pause (a word typed in two
  goes), one ask when the list opens, and the words of an error.

Not changed, because the mutants are equivalent or the behaviour is not a rule: the spelling `for_kind`
accepted as well as `for`; request types with nothing that could be coerced; defaults that the
routes always override; a defensive fallback in the preferences count.

DESIGN.md: the header, the 1.19 row, section 37's heading and section 9a now say 1.18 and 1.19 are built.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
…ked for

The last page and server rounds left survivors that were real; the tests that kill them:

- the hook that holds a chat: that it is testing, unloading, opening and attaching only while
  those are on their way; what a message looks like before the server has answered (the answers
  with their questions, the edited draft, whether it was to think), the server's number for it
  and the chat the reply leaves; a redo showing the old reply gone and a plain retry not; the
  difference between a page closing and a network failing; a stream that ends with no ending;
  a Stop that the server refuses for a reason of its own not being asked again; the choices of a
  chat that does not exist yet; and the note that Stop kept nothing going when another chat starts.
- the library: that an error with the prompts stays when the chats, being slower, are read well
  after it; that the search box waits for the typing to pause; that the list is asked for once
  when it opens; and that nothing says "no prompts" while it is still looking.
- the server: that a quick try is called a draft in what Refine tells the model, that answers still
  count after a message that got no reply, that a delta says whether the model thought first, and
  what a chat is called when the model gives no title and when the first message is a picture alone.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
… (DESIGN section 37.11)

Section 37.11 says what is where, what the checks found (all fixed), what has not been tried
(everything that needs your Ollama, the instruction files, a real phone) and the small choices
made while building, with the figures of a run on this tree:

- backend 2361 passed, 3 skipped; front end 1123; browser 295 (294 pass; the one that does not
  is the Music "Add lyrics" test that fails on this machine on earlier trees too); script checks 303.
- mutation checks: 932 mutants of the 1.19 code in two passes; 902 killed; 30 left, each judged
  one a test cannot tell apart, and listed by kind.

The test of Try 3 wordings now names criterion 240, the one criterion no test file cited.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
The two places in section 30 that said `./scripts/backup.sh` would only have printed its usage
and stopped: the script takes the folder to write into. They now say
`scripts/backup.sh --no-model ~/backups` (the data, the image and the settings, without the
models, which an update of the studio's own code does not touch).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011NDCKtu1QcLwawbdzwmFA1
@NoSQLKnowHow
NoSQLKnowHow merged commit 5f56081 into main Nov 9, 2026
NoSQLKnowHow added a commit that referenced this pull request Nov 9, 2026
Spec 1.20: Speech, text read aloud (DESIGN §38; stacked on #41)
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