Fill in only the missing acts when a proposal is part-drafted

The beat generator had one brief, which assumed the proposal was a prose
premise and asked for a whole three-act sheet at "roughly four to eight
beats per act". Handed a proposal that already had acts beaten out past
that, it would regenerate them — compressing the author's own work into a
shorter paraphrase, losing the specific detail that made it worth
keeping, and burying the one act they actually wanted among two they did
not.

`mistral::analyse` now reads a proposal's act headings and counts the
numbered beats under each, in whatever notation the author used. An act
with three or more beats is drafted; fewer, or an act never mentioned, is
still to write. Two stray numbered lines are a note to self, not an act.
When some acts are drafted and some are not, a second briefing is sent.

That briefing asks for the missing acts only, and asks for them under the
author's own heading text and depth, so what comes back drops into their
document. It drops the per-act cap in favour of matching the density of
the drafted acts, and states which acts are context and which to write.
The drafted acts are canon: not to be rewritten, reordered, summarised,
condensed or reproduced, and — since a reveal often lands in a later act
— the model is told to work backwards from those reveals and plant what
they need using setups already placed.

The model is asked not to reproduce the drafted acts at all, rather than
to echo them unchanged. Reproducing twenty-odd beats verbatim is exactly
the drift being avoided; not asking makes it impossible.

Because the output is then partial, it is labelled: the status line names
the acts written, the file is saved as `<proposal> — beats Two.md`, and
its title says what it holds, so a partial sheet is not later mistaken
for a whole one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ZGoPiDuZ7vmryNCJWjYSD
This commit is contained in:
2026-08-23 16:12:20 -05:00
parent 41c3f088cd
commit e951d57d45
4 changed files with 593 additions and 31 deletions
+43
View File
@@ -328,6 +328,49 @@ using the [Mistral](https://mistral.ai/) chat API.
(auto-numbered if that name is taken) and opens it in the editor, or
* **⧉ Copy** — copies the beats to the clipboard.
### Filling in an act you haven't written
If the proposal is **already partly beaten out**, the generator switches to a
different brief: instead of producing a whole sheet, it writes only the acts you
are missing and leaves the ones you have written alone.
It counts the numbered beats under each act heading it finds (`### Act One:`,
`## Act 2`, `# Act III — Resolution` — the notation doesn't matter). An act with
**three or more** beats is treated as drafted; anything fewer, or an act you
never mention, is treated as still to write. If at least one act is drafted and
at least one is not, you get the fill-the-gaps brief.
So a proposal whose Act One and Act Three are beaten out in detail and whose
Act Two is a note saying *"this is what I need help with"* sends this:
```
It is already partly beaten out:
- Act One: 11 beats already drafted — context only
- Act Two: write this one
- Act Three: 10 beats already drafted — context only
Write only the missing act(s), under exactly these headings:
### Act Two
Do not output the drafted acts.
```
Why it matters: the full-sheet brief tells the model to aim for *four to eight
beats per act*, which would **compress** an act you had already written to
eleven. The fill-the-gaps brief drops that cap, tells the model to match the
density of your drafted acts, and treats them as canon — including any reveal
that lands in a later act, which it must work backwards from and plant for.
It also reuses your own heading text and depth, so what comes back drops
straight into your document.
The result is labelled accordingly: the status line says which acts were
written, the saved file is named `<proposal> — beats Two.md` rather than
`<proposal> — beats.md`, and its title says which acts it contains — so a
partial sheet is never mistaken for a whole one.
To force a full three-act regeneration anyway, run it against a copy of the
proposal with the act headings removed.
The chosen proposal text is sent to Mistral to generate the beats; nothing else
in your workspace is transmitted. The API key is stored in the app's config file
in plain text. Because the request uses the pure-Rust `ureq`/rustls stack, the