Shipped workflow templates and manifests (#33) #79

Merged
crowmaki merged 2 commits from issue-33-shipped-workflows into main 2026-10-07 17:57:19 +00:00
Owner

Closes #33. Part of #24.

What

  • crates/studio-core/workflows/: an API-format template and a manifest for each of h3.draft, h3.promotion, h3.final, image.t2i and image.board.
    • The H3 graphs follow the verified graphs on research/h3-latent-reuse. The owner's helper nodes (easy seed, rgthree switches, ImpactSwitch, Pixaroma LoRA loader, resolution and math nodes, SimpleCalculatorKJ, the media loader, splitter and prompt IDE) are gone, so Rust fills sizes, length and seed directly. The only custom packs left are VideoHelperSuite and the H3 latent upscaler.
    • h3.promotion always freezes the loaded draft audio with a SetLatentNoiseMask (SolidMask 0).
    • Both image workflows run Qwen-Image 2.1. image.board builds its text from a fixed rough-storyboard style string plus the caller's prompt (StringConcatenate), so it can drift from image.t2i.
  • Each manifest has: id, hand-bumped integer version, changes_output, bindings (name -> node_id.input), outputs, node_packs (name, URL, class types), models (folder, file, URL and where the template names it), speed_modes (binding values for Distilled/Full), and for H3 the reference_slots and lora_chain splice points.
  • studio_core::shipped_workflows() loads them and exposes id, version, changes_output, template_hash (blake3 of the canonical JSON, so formatting and key order don't matter), the template and the manifest. ShippedWorkflow::problems() lists every way a manifest fails to line up with its template.
  • workflows/hashes.json records (id, version, hash) for each workflow.

Tests

tests/shipped_workflows.rs:

  • The five workflows load with an id, a version and distinct hashes.
  • Every manifest resolves against its template: each binding, speed-mode key, model location and output node exists, bindings point at scalars (not links), every non-core class_type is covered by a node pack, no pack lists a class the template lacks, and all links point at real nodes.
  • Both image workflows name the Qwen-Image 2.1 files, and only the board template has the style prompt.
  • The H3 manifests name the splice points.
  • The "CI check": there is no CI config in this repo, so it is a cargo test that compares the shipped hashes with hashes.json. It fails with "template changed but version is still N" when a hash changes without a version bump. It also fails when the record is stale after a bump, and the message prints the line to paste. I checked by hand that changing a template value fails the test.

Checks

  • cargo test --workspace --all-features: pass.
  • cargo clippy --workspace --all-targets --all-features -- -D warnings: pass.
  • cargo fmt --check -p studio-core: pass. The workspace-wide cargo fmt --check fails on src-tauri/src/lib.rs and src-tauri/tests/smoke.rs, which are already unformatted on main. I left them alone as unrelated.
  • bun run check: not run, because no frontend files changed.
  • The templates have not been submitted to a real ComfyUI. Node inputs for the H3 graphs come from the captured graphs on the research branch. The rest is written from memory and docs and is unverified.

Known gaps / follow-ups

  • Audio is FLAC (resolved). Core SaveAudio writes lossless FLAC. The owner accepted FLAC, and the spec (#24, #51) now says FLAC.
  • Forced Performance audio (resolved). It is in no template on purpose. The owner allowed a third structural edit, so the job builder adds the VAEEncodeAudio -> 0 mask branch for Performance-driven Takes (#65).
  • Promotion sizing. h3.promotion sizes the upscale with upscale_megapixels, not W x H. For non-16:9 ratios the upscaled output may not match the conditioning W x H. Needs verifying in #57.
  • LoRA chain placement. lora_chain splices user LoRAs after node 5 (ModelAttentionBackend), upstream of the DMAD distill LoRA (node 6). The owner confirmed that the order relative to the shipped LoRAs doesn't matter. This spot just gives one rewire point, because node 6 is node 5's only consumer.
  • Distilled final at 8 steps is not backed by a ticket. The 8 comes from the owner's draft graph, and h3.final reuses it.

Open questions

Everything below is a best guess, not something the tickets or research settle:

  1. Model URLs. The Qwen-Image 2.1 URLs follow the Comfy-Org split_files/<folder>/ layout. The H3 VAEs and DMAD LoRA point at the MiniMax H3 integration index, and the upscaler points at its HF repo page. These are landing pages, not direct downloads.
  2. Upscaler weights folder is upscale_models, and the file is the ..._3d_bf16 one seen in the captured promotion graph. Research #15 saw ..._conv_v1_fp16. The folder the node actually reads is unconfirmed.
  3. DMAD LoRA name keeps the owner's Windows-style MinimaxH3\... combo value. Preflight should compare it with separators normalized.
  4. Speed-mode step counts. Distilled uses the owner's tested values (draft 8, refine 4, LoRA 0.75). Full uses invented values: draft and final 30, refine 12, LoRA strength 0.
  5. Final ProRes master. I used VHS_VideoCombine with format: "video/ProRes" and profile: "hq". I couldn't confirm VHS offers these. Preflight's combo-value check will tell.
  6. WAV Resolved: FLAC is accepted.
  7. Prompt input. The H3PromptIDE / reference-input chain is dropped and prompt is bound as a string straight on MiniMaxH3ReferenceToVideo. I haven't confirmed it accepts a literal, and the <Picture N> tags rely on slot order.
  8. Forced Performance audio Resolved: the job builder may make a third structural edit for it (#65).
  9. Image details. I omitted ModelSamplingAuraFlow. Sampler settings are the Qwen-Image 2.1 doc defaults (25 steps, cfg 1, euler, simple). The board style text is my wording.
  10. Upscaler target. It takes a megapixels value (upscale_megapixels, default 2.1), so the job builder has to turn the final W x H into megapixels.
  11. Defaults. Template sizes (1376x768 draft, 1984x1120 final, 124 frames) are only the research values. The job builder overwrites them.
Closes #33. Part of #24. ## What - `crates/studio-core/workflows/`: an API-format template and a manifest for each of `h3.draft`, `h3.promotion`, `h3.final`, `image.t2i` and `image.board`. - The H3 graphs follow the verified graphs on `research/h3-latent-reuse`. The owner's helper nodes (`easy seed`, rgthree switches, `ImpactSwitch`, Pixaroma LoRA loader, resolution and math nodes, `SimpleCalculatorKJ`, the media loader, splitter and prompt IDE) are gone, so Rust fills sizes, length and seed directly. The only custom packs left are VideoHelperSuite and the H3 latent upscaler. - `h3.promotion` always freezes the loaded draft audio with a `SetLatentNoiseMask` (`SolidMask` 0). - Both image workflows run Qwen-Image 2.1. `image.board` builds its text from a fixed rough-storyboard style string plus the caller's prompt (`StringConcatenate`), so it can drift from `image.t2i`. - Each manifest has: id, hand-bumped integer `version`, `changes_output`, `bindings` (`name -> node_id.input`), `outputs`, `node_packs` (name, URL, class types), `models` (folder, file, URL and where the template names it), `speed_modes` (binding values for Distilled/Full), and for H3 the `reference_slots` and `lora_chain` splice points. - `studio_core::shipped_workflows()` loads them and exposes `id`, `version`, `changes_output`, `template_hash` (blake3 of the canonical JSON, so formatting and key order don't matter), the template and the manifest. `ShippedWorkflow::problems()` lists every way a manifest fails to line up with its template. - `workflows/hashes.json` records `(id, version, hash)` for each workflow. ## Tests `tests/shipped_workflows.rs`: - The five workflows load with an id, a version and distinct hashes. - Every manifest resolves against its template: each binding, speed-mode key, model location and output node exists, bindings point at scalars (not links), every non-core `class_type` is covered by a node pack, no pack lists a class the template lacks, and all links point at real nodes. - Both image workflows name the Qwen-Image 2.1 files, and only the board template has the style prompt. - The H3 manifests name the splice points. - **The "CI check":** there is no CI config in this repo, so it is a `cargo test` that compares the shipped hashes with `hashes.json`. It fails with "template changed but version is still N" when a hash changes without a version bump. It also fails when the record is stale after a bump, and the message prints the line to paste. I checked by hand that changing a template value fails the test. ## Checks - `cargo test --workspace --all-features`: pass. - `cargo clippy --workspace --all-targets --all-features -- -D warnings`: pass. - `cargo fmt --check -p studio-core`: pass. The workspace-wide `cargo fmt --check` fails on `src-tauri/src/lib.rs` and `src-tauri/tests/smoke.rs`, which are already unformatted on main. I left them alone as unrelated. - `bun run check`: not run, because no frontend files changed. - The templates have **not** been submitted to a real ComfyUI. Node inputs for the H3 graphs come from the captured graphs on the research branch. The rest is written from memory and docs and is unverified. ## Known gaps / follow-ups - **Audio is FLAC (resolved).** Core `SaveAudio` writes lossless FLAC. The owner accepted FLAC, and the spec (#24, #51) now says FLAC. - **Forced Performance audio (resolved).** It is in no template on purpose. The owner allowed a third structural edit, so the job builder adds the `VAEEncodeAudio` -> 0 mask branch for Performance-driven Takes (#65). - **Promotion sizing.** `h3.promotion` sizes the upscale with `upscale_megapixels`, not W x H. For non-16:9 ratios the upscaled output may not match the conditioning W x H. Needs verifying in #57. - **LoRA chain placement.** `lora_chain` splices user LoRAs after node 5 (`ModelAttentionBackend`), upstream of the DMAD distill LoRA (node 6). The owner confirmed that the order relative to the shipped LoRAs doesn't matter. This spot just gives one rewire point, because node 6 is node 5's only consumer. - **Distilled final at 8 steps** is not backed by a ticket. The 8 comes from the owner's draft graph, and `h3.final` reuses it. ## Open questions Everything below is a best guess, not something the tickets or research settle: 1. **Model URLs.** The Qwen-Image 2.1 URLs follow the Comfy-Org `split_files/<folder>/` layout. The H3 VAEs and DMAD LoRA point at the MiniMax H3 integration index, and the upscaler points at its HF repo page. These are landing pages, not direct downloads. 2. **Upscaler weights folder** is `upscale_models`, and the file is the `..._3d_bf16` one seen in the captured promotion graph. Research #15 saw `..._conv_v1_fp16`. The folder the node actually reads is unconfirmed. 3. **DMAD LoRA name** keeps the owner's Windows-style `MinimaxH3\...` combo value. Preflight should compare it with separators normalized. 4. **Speed-mode step counts.** Distilled uses the owner's tested values (draft 8, refine 4, LoRA 0.75). Full uses invented values: draft and final 30, refine 12, LoRA strength 0. 5. **Final ProRes master.** I used `VHS_VideoCombine` with `format: "video/ProRes"` and `profile: "hq"`. I couldn't confirm VHS offers these. Preflight's combo-value check will tell. 6. ~~WAV~~ Resolved: FLAC is accepted. 7. **Prompt input.** The `H3PromptIDE` / reference-input chain is dropped and `prompt` is bound as a string straight on `MiniMaxH3ReferenceToVideo`. I haven't confirmed it accepts a literal, and the `<Picture N>` tags rely on slot order. 8. ~~Forced Performance audio~~ Resolved: the job builder may make a third structural edit for it (#65). 9. **Image details.** I omitted `ModelSamplingAuraFlow`. Sampler settings are the Qwen-Image 2.1 doc defaults (25 steps, cfg 1, euler, simple). The board style text is my wording. 10. **Upscaler target.** It takes a megapixels value (`upscale_megapixels`, default 2.1), so the job builder has to turn the final W x H into megapixels. 11. **Defaults.** Template sizes (1376x768 draft, 1984x1120 final, 124 frames) are only the research values. The job builder overwrites them.
Five API-format templates with manifests (h3.draft, h3.promotion, h3.final,
image.t2i, image.board), a core loader exposing id, version and template
hash, a binding-resolution check, and a checked-in (id, version, hash)
record that fails cargo test when a template changes without a version bump.
- SOURCES carries the id via a source! macro; manifest id must match it.
- ShippedWorkflow reads id, version and changes_output from its manifest.
- ModelFile.at becomes ModelFile.input, and node_id.input addresses parse once
  into InputRef at deserialize time.
- Manifest types no longer derive Serialize.
crowmaki deleted branch issue-33-shipped-workflows 2026-10-07 17:57:19 +00:00
Sign in to join this conversation.
No description provided.