feat: relabel events story ↔ table note, and emphasise one into the summary (#607) #608

Merged
claude-bot merged 1 commit from feat/607-relabel-emphasise into main 2026-09-11 19:54:26 +00:00
Collaborator

Closes #607. Round two of #424's corrections, asked for by the owner after using strike and rewrite on the dev replay.

What it adds

Relabel. The GM can mark any event as a table note, or turn a table note back into story, choosing a kind (default other).

  • The new run's copied beat gets the new kind, and gm_original_kind keeps the model's.
  • Relabelling back to the model's own kind clears the marker.

Emphasise and un-emphasise. The GM can mark events the summary must include.

  • They go on top of the cap (owner decision). Emphasised, verified story beats are taken out first, the usual stratified pick (#589, #603) runs over the rest with its normal limit, and the union is re-sorted.
    • An emphasised beat never takes a sampled slot or moves the buckets or anchors, so k emphasised events over the cap gives limit + k.
    • At or under the cap, counted without the emphasised beats, the selection is still the identity.
  • Compose sees them marked (EMPHASIS_MARKER), and COMPOSE_SYSTEM_PROMPT gains EMPHASIS_RULE.
  • The dropped-event retry prefers the draft that misses fewer emphasised events.
  • unemphasise exists because emphasis carries forward across regenerates, as strikes do.

Corrections combine. A beat may take several entries. Each refusal is a 422 with a test:

  • At most one of each action per beat.
  • A strike excludes everything else.
  • emphasise and unemphasise together are refused.
  • No emphasis on a beat that ends up a table note.
  • No emphasis on a beat that stays struck.
  • summary is only allowed with rewrite, and kind only with relabel.
  • A relabel must name a real, different kind.
  • No re-emphasising an emphasised beat, or un-emphasising an unemphasised one.

Visibility. The GM sees a star and a "was: reveal" marker. Players see the result, with relabelled events folded or shown accordingly, and never the markers.

Migration a0f1a2b3c4d5 (down 9e0f1a2b3c4d) adds session_beats.gm_original_kind TEXT NULL and gm_emphasised BOOLEAN NOT NULL DEFAULT false.

Worth reviewing

  • EMPHASIS_RULE is in every compose prompt, even with nothing emphasised. That's harmless, but prompt-sensitive eval baselines may shift slightly.
  • A carried-over emphasis is dropped silently when the same event is struck or relabelled to a table note in a later regenerate. Asking for both in one request is still a 422.
  • Detecting a missing emphasised event is looser than for ordinary events: any of its content words counts. Missing ordinary events are still judged as before.
  • A pending relabel keeps its row in place until regenerate. It doesn't jump into or out of the table-notes fold.

Checked

  • Full backend suite: 3397 passed, 13 skipped. That includes a request-level test asserting that EMPHASIS_RULE and the marker are in the compose request actually sent.
  • Frontend: 868 passed, and ESLint is clean.
  • Lint: ruff 0.4.4 check and format --check are clean.
  • Base: rebased onto e82d343, which has #606 merged.

🤖 Generated with Claude Code

Closes #607. Round two of #424's corrections, asked for by the owner after using strike and rewrite on the dev replay. ## What it adds **Relabel.** The GM can mark any event as a table note, or turn a table note back into story, choosing a kind (default `other`). - The new run's copied beat gets the new `kind`, and `gm_original_kind` keeps the model's. - Relabelling back to the model's own kind clears the marker. **Emphasise and un-emphasise.** The GM can mark events the summary must include. - **They go on top of the cap** (owner decision). Emphasised, verified story beats are taken out first, the usual stratified pick (#589, #603) runs over the rest with its normal limit, and the union is re-sorted. - An emphasised beat never takes a sampled slot or moves the buckets or anchors, so k emphasised events over the cap gives `limit + k`. - At or under the cap, counted without the emphasised beats, the selection is still the identity. - **Compose sees them marked** (`EMPHASIS_MARKER`), and `COMPOSE_SYSTEM_PROMPT` gains `EMPHASIS_RULE`. - **The dropped-event retry** prefers the draft that misses fewer emphasised events. - **`unemphasise`** exists because emphasis carries forward across regenerates, as strikes do. **Corrections combine.** A beat may take several entries. Each refusal is a 422 with a test: - At most one of each action per beat. - A strike excludes everything else. - `emphasise` and `unemphasise` together are refused. - No emphasis on a beat that ends up a table note. - No emphasis on a beat that stays struck. - `summary` is only allowed with rewrite, and `kind` only with relabel. - A relabel must name a real, different kind. - No re-emphasising an emphasised beat, or un-emphasising an unemphasised one. **Visibility.** The GM sees a star and a "was: reveal" marker. Players see the result, with relabelled events folded or shown accordingly, and never the markers. **Migration `a0f1a2b3c4d5`** (down `9e0f1a2b3c4d`) adds `session_beats.gm_original_kind TEXT NULL` and `gm_emphasised BOOLEAN NOT NULL DEFAULT false`. ## Worth reviewing - **`EMPHASIS_RULE` is in every compose prompt,** even with nothing emphasised. That's harmless, but prompt-sensitive eval baselines may shift slightly. - **A carried-over emphasis is dropped silently** when the same event is struck or relabelled to a table note in a later regenerate. Asking for both in one request is still a 422. - **Detecting a missing emphasised event is looser** than for ordinary events: any of its content words counts. Missing ordinary events are still judged as before. - **A pending relabel keeps its row in place** until regenerate. It doesn't jump into or out of the table-notes fold. ## Checked - **Full backend suite:** 3397 passed, 13 skipped. That includes a request-level test asserting that `EMPHASIS_RULE` and the marker are in the compose request actually sent. - **Frontend:** 868 passed, and ESLint is clean. - **Lint:** ruff 0.4.4 `check` and `format --check` are clean. - **Base:** rebased onto `e82d343`, which has #606 merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: relabel an event and emphasise one before regenerating the summary (#607)
All checks were successful
CI / Backend lint (ruff) (pull_request) Successful in 51s
CI / Docker image build (pull_request) Successful in 21s
CI / Bot/backend version sync (pull_request) Successful in 24s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m24s
CI / Bot tests and audit (pull_request) Successful in 2m21s
CI / Frontend tests, audit, and build (pull_request) Successful in 2m35s
CI / Backend migration, tests, and audit (pull_request) Successful in 11m41s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 12m32s
096718405c
Two more GM corrections on the session event log, beside #424's strike and
rewrite, applied to a copy of the run's beats like them.

Relabel switches an event between story and table note: to table_admin
(folded, never narrated) or to a story kind the GM picks, default "other".
The copy gets the new kind and gm_original_kind keeps the model's; relabelling
back to the model's kind clears it.

Emphasise marks an event the summary must include (gm_emphasised). Owner's
call: emphasised events go ON TOP of the compose cap. select_beats_for_compose
takes emphasised verified story beats out first, runs the normal stratified
selection over the rest with the normal limit, and re-sorts the union, so k
emphasised events on a session over the cap give limit + k and never take a
sampled slot. render_beats_for_compose marks them "(the GM marked this as
essential)" and COMPOSE_SYSTEM_PROMPT gains EMPHASIS_RULE. unrepresented_beats
no longer assumes an emphasised event present when it has no words of its own,
and recover_dropped_events ranks a retry by emphasised events missing first.
An emphasised or rewritten beat is narrated even if it failed validation; its
problems are kept. unemphasise takes a carried-over emphasis off.

Combinations: at most one of each action per beat; strike excludes everything
else; no emphasis on a beat that ends up a table note, or stays struck. Strike
or relabel-to-table-note drops a carried emphasis. Each refusal is a 422.

The event log gives everyone the result (the GM's kind) and only a GM the
markers (original_kind, emphasised). The session page gets Mark as table note /
Mark as story (with a kind picker), Emphasise / Un-emphasise, per-correction
pending tags and undo, a count of every pending correction, and a star and
"was: …" on a recomposed run's rows, GM only.

Migration a0f1a2b3c4d5 (raw DDL): session_beats.gm_original_kind TEXT NULL and
gm_emphasised BOOLEAN NOT NULL DEFAULT false. The head pin moves to it; the
#424 migration test becomes a chain assertion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-09-11 19:41:09 +00:00
claude-bot deleted branch feat/607-relabel-emphasise 2026-09-11 19:54:27 +00:00
Sign in to join this conversation.
No description provided.