From bd18b5ae32fa344b3dff270555d422045e0eb20e Mon Sep 17 00:00:00 2001 From: Jason Hoku Date: Wed, 4 Nov 2026 00:56:25 -0800 Subject: [PATCH] docs: sweep attach rule, wf_params dashboard, job prompt route, Builder session load Co-Authored-By: Claude Fable 5.1 --- ProjectStructure.md | 7 +++++-- README.md | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ProjectStructure.md b/ProjectStructure.md index 65e0ccb..62d0775 100644 --- a/ProjectStructure.md +++ b/ProjectStructure.md @@ -82,6 +82,7 @@ ComfyUI-Ultimate-Sampler-Grid/ │ ├── logic_state.js # State Store (Redux-style: filters, favorites) (104 lines) │ ├── logic_pipeline.js # Data Processing (Filter -> Sort -> Layout) (510 lines) │ ├── logic_ratings.js # Pairwise review pure logic: axis normalisers, Bradley-Terry, pairing, scoreboard (no DOM, node-testable) +│ ├── logic_wfparams.js # Workflow Sweep wf_params helpers (keys, numeric detection, match, short labels); Quick/Logic Filter + label overlay use them (pure, node-testable) │ ├── logic_compare.js # Pairwise review DOM glue: compare overlay, vote queue, scoreboard modal, rating getters │ ├── logic_virtual.js # Virtual DOM / Infinite Scroller Engine (925 lines) │ ├── logic_ui.js # UI Renderer (DOM creation, Modal handling) (1780 lines) @@ -227,7 +228,8 @@ All routes registered via `PromptServer.instance.routes`. | POST | `/config_tester/scan_directory` | 746 | Scan external dir, create symlinks, generate manifest | | POST | `/config_tester/sweep/parse` | - | Workflow Sweep: describe an API-format workflow `{api_json}` (nodes, outputs, image sources, suggested bindings) | | POST | `/config_tester/sweep/dry_run` | - | Workflow Sweep: first N concrete prompts + validation of job 1 `{state or configs_json, limit}`; queues nothing | -| POST | `/config_tester/sweep/start` | - | Workflow Sweep: start a sweep `{state or configs_json, node_id?}` (400 invalid, 409 one already active) | +| POST | `/config_tester/sweep/start` | - | Workflow Sweep: start a sweep `{state or configs_json, node_id?}` (400 invalid; 200 `attached:true` when the IDENTICAL sweep is already active; 409 `{error, sweep_id, session_name}` for a different one) | +| GET | `/config_tester/sweep/job_prompt` | - | Workflow Sweep: `?session_name=&sweep_id=&job_index=` -> `{prompt, params, fingerprint, ...}`, the job's API prompt without the collector (ids only, no paths; 400 bad id/index, 404 unknown) | | GET | `/config_tester/sweep/status` | - | Workflow Sweep: `?sweep_id=` or `?session_name=` (state, counts, ETA, last errors) | | POST | `/config_tester/sweep/pause`, `/resume`, `/cancel` | - | Workflow Sweep controls `{sweep_id}` | @@ -297,7 +299,7 @@ All routes registered via `PromptServer.instance.routes`. * **`html_generator.py`** (57 lines) * `get_html_template(title, manifest_data, node_id)` — reads all `/resources/` files, inlines into `template.html` - * **JS Load Order:** `logic_state.js` → `logic_utils.js` → `logic_ratings.js` → `logic_ui.js` → `logic_upscale_modal.js` → `logic_virtual.js` → `logic_pipeline.js` → `logic_compare.js` → `logic_events.js` → `logic_init.js` → `logic_standalone.js` (all files share ONE inlined script: top-level names must be unique across them) + * **JS Load Order:** `logic_state.js` → `logic_utils.js` → `logic_ratings.js` → `logic_wfparams.js` → `logic_ui.js` → `logic_upscale_modal.js` → `logic_virtual.js` → `logic_pipeline.js` → `logic_compare.js` → `logic_events.js` → `logic_init.js` → `logic_standalone.js` (all files share ONE inlined script: top-level names must be unique across them) * Replaces placeholders: `__CSS_CONTENT__`, `__JS_CONTENT__`, `__TITLE__`, `__NODE_ID__` * Zero external HTTP requests — everything inlined @@ -900,6 +902,7 @@ __init__.py | `logic_utils.js` | `loadSession()`, `exportFavorites()`, `scanDirectory()`, `triggerGen()`, `toggleFullscreen()`, `deleteNonFavorites()` | | `logic_virtual.js` | `renderDOM()`, `updateVisibleItems()`, `calculateVisibleRange()`, `autoFitZoom()`, `goToImage()` | | `logic_pipeline.js` | `updateDataPipeline()`, `executePipeline()`, `processNewData()`, `incrementalFilter()` | +| `logic_wfparams.js` | `wfParamKeys()`, `wfParamValue/Number()`, `wfParamMatches()`, `wfShortLabel()`, `wfDisplay()` (pure; tests in `tests/js/wfparams.test.js`) | | `logic_ratings.js` | `computeBradleyTerry()`, `buildPairSource()`, `nextPair()`, `axisDiff()`, `computeScoreboard()` (pure; tests in `tests/js/ratings.test.js`, run `node --test tests/js/*.test.js`) | | `logic_compare.js` | `openCompareMode()`, `cmpVoteSide()`, `cmpUndo()`, `openScoreboard()`, `getItemRating()`, `compareRatings()`, `onComparisonsReplaced()` | | `logic_events.js` | Message handler for `progress_update`, `update_data`, `distribution_status` | diff --git a/README.md b/README.md index 42a2036..143d951 100644 --- a/README.md +++ b/README.md @@ -814,9 +814,13 @@ How it behaves: * Jobs are queued two at a time through ComfyUI's normal queue (so you can keep using ComfyUI, and nothing blocks the executor). Axes are ordered so loader values stay adjacent (checkpoint outermost, sampler settings innermost), which lets ComfyUI's cache keep models loaded between jobs. `--cache-none` or very tight RAM reloads models every job. * Each job has a fingerprint of the exact substituted workflow. Starting the same sweep again (also after a ComfyUI restart) skips jobs already in the session; *Overwrite existing* re-runs them and replaces the old image. * A failed job is recorded and the sweep continues; three failures in a row pause it. Pressing Cancel in ComfyUI during a job, or clearing the queue, pauses the sweep instead of silently finishing; Resume re-runs the affected jobs. -* Manifest items get the normal fields (model, sampler, scheduler, steps, cfg, seed, denoise, vae, size, prompts) read from the workflow, plus `wf_params` (your bound values), `wf_fingerprint`, `wf_sweep_id`. Dashboard REVISE is hidden for these items. +* Manifest items get the normal fields (model, sampler, scheduler, steps, cfg, seed, denoise, vae, size, prompts) read from the workflow, plus `wf_params` (your bound values), `wf_fingerprint`, `wf_sweep_id`. Sweep items show a **JOB** button instead of REVISE (see *Dashboard for sweeps* below). * Each sweep writes `benchmarks//workflow_sweeps/.json` (templates, bindings, per-job status) so any executed prompt can be reconstructed. -* v1 limits: one image output per job (no video), one sweep at a time, a workflow sweep cannot share a Generator run with standard configs (use two Builders), no upscale/distribution/trigger-word features, and Revise does not apply. +* **Re-running the same sweep attaches to it.** Queueing the Generator again (or pressing Start) while the identical sweep is active does not fail and does not queue anything twice: it attaches to the running sweep (console: "Same workflow sweep already running ... attaching") and a paused sweep stays paused (Resume is the Builder's button). "Identical" means the same session name, the same ordered job fingerprints, the same *Start at job* and the same *Overwrite existing*. Anything else gets a clear refusal ("A workflow sweep is already active (session ..., sweep ..., n/m done, state). This run was NOT started. Pause or cancel it ..."; ComfyUI shows it in its error dialog, the route answers 409 with `session_name`). Limitation: with *Add random seeds* > 0 every start draws new seeds, so a re-queue never matches and always gets the refusal. +* **Loading a sweep session in the Builder** (Load Session) restores the Workflow Sweep arrays (workflow, output, bindings, custom prompts) from the `configs_json` that sweep sessions now store in their manifest meta. Sessions made before this change have no saved configs: the Builder shows a notice ("Load the workflow JSON again into a Workflow Sweep array; finished jobs are skipped by fingerprint") and leaves the arrays alone. +* v1 limits: one image output per job, one sweep at a time, a workflow sweep cannot share a Generator run with standard configs (use two Builders), no upscale/distribution/trigger-word features, and Revise does not apply. **Video outputs are not collected yet** (planned: core `SaveVideo.video` / `CreateVideo` VIDEO sockets and the frames feeding `VHS_VideoCombine.images`, through a `USCGSweepCollectVideo` node). + +**Dashboard for sweeps.** Items carry `wf_params` (the bound values, numbers or strings). The **Quick Filter** gets one extra type per *varied* key (`WF cfg`, `WF sampler_name`, ...; picking a value filters and the facet panel lists them), the **Logic Filter** gets a *Workflow params* group of the numeric keys (`wf:KSampler.cfg >= 5`), and the **Labels** panel has a *Workflow params* checkbox that tags each card with its varied values (`cfg:4`). Standard sessions show none of this. The **JOB** button opens a read-only *Workflow job* panel (source, output, sweep id, job number, parameter table) with **Download job prompt (API JSON)** and **Copy job prompt**: `GET /config_tester/sweep/job_prompt?session_name=&sweep_id=&job_index=` rebuilds the prompt exactly as it ran (template + substitutions) minus the USCG collector node, so queueing it in ComfyUI reproduces the image. If the browser blocks the download inside the dashboard iframe, use Copy. ---