Staleness reasons and acceptance (#58) #113

Merged
crowmaki merged 2 commits from issue-58-staleness into main 2026-10-09 07:09:48 +00:00
Owner

Closes #58

A Take is now judged stale when a re-roll with its Shot's current inputs would send a different job. The seed and the Generation profile are left out of the comparison. Staleness is computed, never stored: the Take's recorded inputs are compared with the job the Shot would build now. Each difference is a named Stale reason.

Core (studio-core)

  • New staleness module. take_staleness(take) returns the Take's reasons and a table of its inputs against the current ones.
    • References: an Atlas, Wardrobe mannequin, location angle, Prop or Voice reference that was added, dropped (excluded or over budget), moved to another slot, or made from another Lock snapshot. An Atlas also counts when its size or grouping changed its pixels.
    • Board/Keyframes: the same, compared by bytes.
    • Prompt: the prompt text differs. On a Shot with an override, the comparison uses the override text, so a composer change alone shows only on the Shot's "composer changed" marker.
    • Framing: the effective aspect ratio, or the length in frames.
    • Workflow: information only, raised only when the newer version is marked as changing output. A workflow the app no longer ships is shown, never an error.
    • Performance: the kind exists, but nothing produces it until Performances land (#63/#65).
  • The current job is worked out without building anything. Snapshot-made references compare by Lock snapshot, an Atlas by its cache key, and only the Board's small images are drawn.
  • Accepting a reason: the new accepted_reason table (migration V30) stores the input's value at the time of acceptance, so the acceptance lapses when that input changes again. accept_stale_reason and accept_all_stale_reasons are undoable, and accepting never touches provenance.
  • rebuild_take ("Rebuild with current inputs") rebuilds a waiting Take's job in place. It keeps the Take's number, seed, kind, profile, Rendition and queue position. The job build is split out of queue_take to make this possible.
  • Dailies Takes carry their stale_reasons. Shot views, including the ones in the script read, carry circled_stale.

UI

  • Dailies wall: an amber STALE tag on each stale Take; its tooltip lists the reasons. Shot heads show "N circled stale".
  • Dailies table: a Stale filter and a sortable Stale column naming the stale kinds.
  • Details panel:
    • the reasons grouped by kind, each with Accept, plus Accept all;
    • Rebuild with current inputs, for a waiting Take;
    • a table of Sent against Now, including the slot assignment;
    • an A/B wipe against another rendered Take of the Shot.
  • Promoting a stale Take (from details, a table batch or screening P) asks first and names the stale inputs.
  • Shot listings (Scenes) and the Scenes list show only "N circled stale".

Screenshots

1A-2's aspect-ratio reason has been accepted, so only its Prompt reason still counts. Under Wipe against, the A/B wipe lists the Shot's rendered Takes. No ComfyUI was available, so these Takes are queued, not rendered.

Wall and details panel

Table with the Stale column and filter

After Rebuild with current inputs

Not covered by screenshots

The A/B wipe and the "N circled stale" marker need rendered Takes. Tests cover both: shot_and_scene_listings_count_only_circled_stale_takes renders against the fake ComfyUI.

Tests

  • cargo test --workspace --all-features: 684 passed. Two ffmpeg proxy tests fail, both on main as well, because this machine's ffmpeg has no libopenh264.
  • bun test src: 200 passed.
  • bun run check: clean.
  • New: tests/staleness.rs, which covers each reason kind, acceptance lapse, Accept all, the override case, Rebuild and the listings. Also new: stale.test.ts and new table filter and sort tests.
Closes #58 A Take is now judged stale when a re-roll with its Shot's current inputs would send a different job. The seed and the Generation profile are left out of the comparison. Staleness is computed, never stored: the Take's recorded inputs are compared with the job the Shot would build now. Each difference is a named **Stale reason**. ## Core (`studio-core`) - New `staleness` module. `take_staleness(take)` returns the Take's reasons and a table of its inputs against the current ones. - **References:** an Atlas, Wardrobe mannequin, location angle, Prop or Voice reference that was added, dropped (excluded or over budget), moved to another slot, or made from another Lock snapshot. An Atlas also counts when its size or grouping changed its pixels. - **Board/Keyframes:** the same, compared by bytes. - **Prompt:** the prompt text differs. On a Shot with an override, the comparison uses the override text, so a composer change alone shows only on the Shot's "composer changed" marker. - **Framing:** the effective aspect ratio, or the length in frames. - **Workflow:** information only, raised only when the newer version is marked as changing output. A workflow the app no longer ships is shown, never an error. - **Performance:** the kind exists, but nothing produces it until Performances land (#63/#65). - The current job is worked out without building anything. Snapshot-made references compare by Lock snapshot, an Atlas by its cache key, and only the Board's small images are drawn. - Accepting a reason: the new `accepted_reason` table (migration V30) stores the input's value at the time of acceptance, so the acceptance lapses when that input changes again. `accept_stale_reason` and `accept_all_stale_reasons` are undoable, and accepting never touches provenance. - `rebuild_take` ("Rebuild with current inputs") rebuilds a waiting Take's job in place. It keeps the Take's number, seed, kind, profile, Rendition and queue position. The job build is split out of `queue_take` to make this possible. - Dailies Takes carry their `stale_reasons`. Shot views, including the ones in the script read, carry `circled_stale`. ## UI - **Dailies wall:** an amber `STALE` tag on each stale Take; its tooltip lists the reasons. Shot heads show "N circled stale". - **Dailies table:** a Stale filter and a sortable Stale column naming the stale kinds. - **Details panel:** - the reasons grouped by kind, each with Accept, plus Accept all; - Rebuild with current inputs, for a waiting Take; - a table of Sent against Now, including the slot assignment; - an A/B wipe against another rendered Take of the Shot. - **Promoting a stale Take** (from details, a table batch or screening `P`) asks first and names the stale inputs. - **Shot listings (Scenes) and the Scenes list** show only "N circled stale". ## Screenshots 1A-2's aspect-ratio reason has been accepted, so only its Prompt reason still counts. Under Wipe against, the A/B wipe lists the Shot's rendered Takes. No ComfyUI was available, so these Takes are queued, not rendered. ![Wall and details panel](https://git.crowmaki.me/attachments/7872bffa-87de-459f-96cd-d4d56cacbea5) ![Table with the Stale column and filter](https://git.crowmaki.me/attachments/228574cb-c7c7-49ac-8394-f28604200e4e) ![After Rebuild with current inputs](https://git.crowmaki.me/attachments/7f5167d0-aebe-4ead-a628-d03761825378) ## Not covered by screenshots The A/B wipe and the "N circled stale" marker need rendered Takes. Tests cover both: `shot_and_scene_listings_count_only_circled_stale_takes` renders against the fake ComfyUI. ## Tests - `cargo test --workspace --all-features`: 684 passed. Two `ffmpeg` proxy tests fail, both on `main` as well, because this machine's ffmpeg has no `libopenh264`. - `bun test src`: 200 passed. - `bun run check`: clean. - New: `tests/staleness.rs`, which covers each reason kind, acceptance lapse, Accept all, the override case, Rebuild and the listings. Also new: `stale.test.ts` and new table filter and sort tests.
A Take is stale when a re-roll with its Shot's current inputs would send a
different job, ignoring its seed and Generation profile. Staleness is computed
by diffing the Take's recorded inputs against the job the Shot would build
now. Each difference is a named Stale reason (References, Board/Keyframes,
Prompt, Framing, informational Workflow) that can be accepted per Take until
its input changes again.

- studio-core: staleness module, accepted_reason table (V30), undoable
  accept / accept all, rebuild_take for a waiting Take (same number and seed),
  stale reasons on Dailies Takes and circled_stale on Shot listings.
- Dailies: stale badges, a Stale filter and sortable column, a details panel
  with reasons, Accept, Rebuild, an inputs table and an A/B wipe, and a warning
  before promoting stale Takes.
- Shot and Scene listings show only "N circled stale".
- A Take whose workflow is no longer shipped shows that as information
  instead of failing the Dailies and script reads.
- A Workflow reason cannot be accepted; it never counts.
- STALE tag text per ADR-0006; one CircledStaleBadge for every listing.
- Shared judged_takes and with_circled_stale instead of copied loops.
- Internal names follow the glossary (no "diff" for a Stale reason).
- Test a new Voice snapshot as a References reason on its audio slot.
crowmaki deleted branch issue-58-staleness 2026-10-09 07:09:48 +00:00
Sign in to join this conversation.
No description provided.