Skip to content

Release 0.14.0 - #929

Merged
dkackman merged 284 commits into
masterfrom
develop
Oct 16, 2026
Merged

dkackman merged 284 commits into
masterfrom
develop

Conversation

@dkackman

Copy link
Copy Markdown
Owner

Merges develop into master for 0.14.0. This is 284 commits since v0.13.0. The release notes are drafted in docs/RELEASING.md under 0.14.0.

Highlights:

Fixed during the pre-release review:

  • Develop CI had been red since 0.14.0-alpha.1 opened. Three causes:
    • Notes traversal test (Linux only): its snapshot caught jobs.sqlite being written whenever the garbage collector closed a leftover connection. JobHistory._connect now closes its connections.
    • UI ratchet: App.svelte is back under the size ceiling and figure() under the complexity limit.
    • Backend ratchet: plan.py, server/jobs.py, api_models.py and pipeline.py were split under the 1,100-line ceiling, and the long function, complex function and prefix literal were fixed in code. Only modules (211 → 219) and test patch targets (326 → 327) were raised, approved, in 318a74b, which names each module.
  • Model downloads write refs/main. Since cancel_download has no visible effect: download stays status downloading with frozen byte count, no pending-cancel state #899, a downloaded model read as incomplete and failed to load offline.
  • An inline copy of a list-driven template is priced by its list length. It was quoted the template's default-length figure, unscaled and unflagged. v0.13.0 reported that case as unknown.
  • The host-RAM gate takes the per-entry fit for a list longer than its history. Before, it gated an 8-shot shots-batch at 30 GB while validate warned about 50 GB.
  • Whole-module compile: {fullgraph: true} no longer fails at the first denoise step. The new timing hook ran inside the compiled region.
  • The gallery sort is now linear. It used to stall each keystroke on large libraries.
  • All outputs are tagged "final" #928, all outputs tagged final.
    • A file a later run in the same workspace consumed, through output: or a kept asset:, lists as intermediate.
    • A step that declares result.role: "final" is never demoted.
    • The script-to-video and series-episodes skills have ingredient workflows declare "role": "intermediate".

Checks:

  • Develop CI is green (backend, ui, e2e) at 93ca8db, and CodeQL is green.
  • Locally, 14,724 backend tests and 673 vitest tests pass. ruff, lint, svelte-check, both ratchets and the generated API client are clean. The wheel builds and includes every new module.

Review notes, not blocking:

🤖 Generated with Claude Code

dkackman and others added 30 commits October 13, 2026 17:37
The server inferred roles for older runs from the realized workflow,
falling back to subfolders and single-step runs, which labelled nearly
every pre-roles file final. Drop the inference: an entry without a
recorded role is unknown, not guessed, and the UI shows no tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… segments and bad destination names refused

- set_note was documented in docs/MCP.md and named in the server
  instructions but never registered as a tool; it is now (WRITES), with
  EXPECTED_TOOLS, TOOL_WIRING, the tool count 63 -> 64 and SURFACE_BUDGET
  raised by its measured 150 tokens.
- A runs entry with an empty segment ("wf/", "wf//<run>") is refused
  rather than normalized.
- The copy route takes {destination:path}, and api_path encodes a segment
  that is only dots, so "../x", "/tmp/x", ".", ".." and "" reach the route
  and are refused as "No such workspace: <name>", as the same names are
  for source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
copy_to_workspace takes assets: files or folders, keeping their library
path, hard-linked, with their notes and kept shots merged into fresh
destination sidecars. An identical file is already present; a different
one refuses the whole request. Uploads replace a file rather than writing
into it, so a linked copy's bytes stay put.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pying

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…one unit

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…with assess.sample_span, honour audio_replaced_downstream

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…corded shot map; accept the short @name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…series cinema path

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…windows, with the tonal closest miss

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…path.md

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…keys; map names the shot-name preflight

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…mer template

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…WORKFLOW_GUIDE, minimax README and the minimax-h3 skill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mber_keys and validate_variable_name both read it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…000, others 0

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ents, both CFG contexts labeled

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
dkackman and others added 29 commits October 15, 2026 20:19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d0565f8 let inherited_observed fall back to the template's default
driver bucket when the caller's (shots=6, say) has no runs, trusting
_scale_past_template to scale. It could not see list length: a for_each
step counted as one pipeline step, pipeline_values read the authored
step (item:num_frames -> None), and sets_differently compares sets of
values, so 6 x 124 frames equalled 3 x 124. An inline six-shot copy of a
template with one three-shot 30-min run was quoted 30 min, unscaled,
differs [], no low_confidence.

The fix scales rather than withholds, on the rule the block already
uses for authored steps: vram_inheritance.pipeline_steps expands
for_each with variables resolved (the expansion reference_counts and
sets_differently use), and both the step count and the per-step values
are read from it, the template's against the bucket's own list. A
six-shot request against the three-shot bucket is 2x, with `scaled`
naming "6 steps, template measured 3", which plan._observed already
turns into low_confidence - the same basis/scaled/low_confidence shape
the catalog figure's list re-price and #866's axes use. Mean frames,
steps and canvas are now per member, so shorter shots scale down too.
A step count of zero on either side is withheld with a reason rather
than divided by.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
projected_peak let the observed max over the memory key always beat the
list-run fit, and the key leaves list length out by design. For a shape
that holds its pipeline across the list (shots-batch, music-video,
best-of-n-to-video, restore-long), an 8-shot request with history at
2 shots/20 GB and 4 shots/30 GB was gated at 30 GB by dispatch and
plan.host_memory, while validate's host_memory_warnings, from the same
rows' fixed+per-entry fit, warned ~50 GB.

Now, when the definition does not release between iterations and the
fit is larger than the observed max, the fit is the figure (basis
"fit"), so dispatch, plan.host_memory and the validate warning agree.
A list inside the observed range keeps the observed max (the fit is
not larger there), and a released shape keeps it whatever the length:
its peak is one entry's, not the list's (#901). Under-projecting is the
failure this gate exists for, so the larger figure wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
App.svelte was 604 lines (ceiling 600). The bell button moves to
lib/AlertToggle.svelte, and alertsOn with toggleAlerts to the shared
lib/alerts.svelte.ts store, which announce() and the chime-unlock
listener still read. Behaviour is unchanged; the toggle gets tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The visible derived sorted with runs.indexOf in the comparator and built
runs with includes - quadratic, ~208 ms a keystroke at 10k files. Each
run's place is now its first file's index from a Map; the order is the
same, held by the existing newest-first-between-runs test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… block

_connect returned a bare connection, and `with connection:` only commits
or rolls back - the connection was closed by GC, which checkpoints the
WAL at an arbitrary later moment and rewrote jobs.sqlite under a test
watching its bytes. _connect is now a context manager that commits on
success, rolls back on an exception and always closes; every call site
already used it as `with self._connect() as connection`, so none change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
denoise_start_hook registered a forward pre-hook on every denoiser. A
denoiser compiled whole (compile without repeated_blocks) runs its hooks
inside the compiled _call_impl, where Dynamo cannot trace the clock read
(time.monotonic / device sync): fullgraph: true failed every job at the
first denoise step, and a non-fullgraph compile broke its graph there.

A whole-compiled denoiser (_compiled_call_impl set) now has that callable
wrapped for the call instead: the wrapper marks once, outside the compiled
region, then hands over, and is restored on the way out. The mark is the
same instant a pre-hook stamped, so first_pass_s and the slow-first-pass
warning (#924) read the same. Eager and repeated_blocks denoisers keep the
self-removing pre-hook on the eager top-level module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
plan.py was 1,315 lines, over the 1,100 module ceiling. The cost-driver
scaling helpers and the basis labels move out unchanged; plan.py imports
them back, and dw/server/deps.py imports scale_curated from its new home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s.py

JobManager's _next_dispatch, _forget_dispatch, _held_for_host_ram and
_host_ram_wait, with _HostReading, _worker_rss_mb and
HOST_RAM_RECHECK_SECONDS, move verbatim into dw/server/dispatch.py as the
Dispatcher mixin JobManager inherits. No behaviour change; jobs.py is
1,061 lines, back under the 1,100 ceiling. The host-RAM gate tests'
monkeypatch targets follow the names to dw.server.dispatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The workspace, workflow, prompt and enhancer models (and the Origin,
Shape and Trait literals) move verbatim into api_models_library.py, and
ApiModel, STRICT, sometimes and send_rejected_responses into
api_models_base.py so the library module can derive from them without an
import cycle. api_models.py re-exports every name, so routes and tests
import as before; the OpenAPI document and the generated UI types are
unchanged. api_models.py is 947 lines, back under the 1,100 ceiling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sixteen ALTERs JobHistory.__init__ ran one if-block each become
_ADDED_COLUMNS, a (column, ddl) list applied by _add_missing_columns;
the workspace and device-field backfills still run once, when their
columns were just added. Same DDL, same order, same comments; __init__
drops from C901 complexity 18 to under the limit. A new test opens a
v0.13.0-shaped jobs.sqlite (no note/memory_key/rerun_of/kept) and checks
it gains the four.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pipeline.py was 1,103 lines, over the 1,100 module ceiling. Reading a
step's guides entries into frames and soundtrack sits beside
guide_frames_array and guide_audio_waveform, which it already called;
moved unchanged as prepared_guide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atchet)

concat_videos was 152 lines, over the 150-line function limit. The loop
that lays each input's frames, soundtrack and shot record onto the joined
tracks moves unchanged into its own helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
short_name spelled "asset:" as a literal, the one prefix_literals hit.
It now asks references.is_ref with references.ASSET, as dw/assets.py does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… run read

annotate_roles marks a role result.role stated (role_declared) so a
later reading never demotes it. consumed_outputs walks an output root's
runs once and resolves each run's output: inputs (and asset: inputs kept
from an output) to the file that run read; an unpinned 'latest' is the
newest run started before the reader (resolve_output_reference gains
`before`). listed_role applies the read-time rule; nothing is rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/gallery (and its role= filter, which the web UI and MCP
list_gallery use) and the gallery metadata route report a file another
run of the workspace read as intermediate, unless its step declared the
role. The MCP list_gallery description says later step or run; the
surface stays within SURFACE_BUDGET. Docs: ARCHITECTURE roles row,
WORKFLOW_GUIDE, WORKSPACES, SERVER, MCP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
script-to-video and series-episodes tell the agent that a workflow made
for a shot, narration, score or cue, still or reference sets
"role": "intermediate" in its saving step's result, so only the
assembly's or episode's cut reads as final. series-episodes makes room
under the 12 KiB cap by tightening three restated passages (no rule
dropped); it is 12,182 bytes, script-to-video 8,728.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regenerated openapi.json and api-schema.ts (description only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dkackman
dkackman merged commit 1b1a043 into master Oct 16, 2026
16 checks passed
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