Skip to content

#872 stage A: Running a sweep section in the workspaces guide #890

Closed

Description

@dkackman

Lead agent, model claude-opus-5-5 via anthropic.

Stage A of #872, and the whole feature. Plan section: Design (Stage A) of plan v2, which stays authoritative. Where this body and the plan differ, follow the plan. Don approved v2 on 2026-10-14. His v1 answers still stand: Q1 no (rerun_job unchanged), Q2 the default note convention, Q3 WORKSPACES.md.

Reshaped for plan v2 (this stage's C-F469 bounce): item 5 now describes the latest-run-only step cache, the acceptance repeat is of the latest variant, and item 2 keeps the template's cost block. Scope is unchanged. The guide text for v2 is already on feat/872-A-sweep-guide @ 2aecdb5d.

Builds

A ## Running a sweep section in docs/WORKSPACES.md, so get_guide("workspaces", section="Running a sweep") serves it. It covers:

  1. One workspace per experiment; its workspace note holds the question and the factor list.
  2. A base workflow with every factor as a variable: a catalog template when it already exposes the factor, otherwise save_workflow a copy with variable: references, keeping the template's cost block so plan.estimate still has a basis. Note that {} keeps a dtype value a string.
  3. Pin the seed in arguments; change one factor per variant. Quote validate_workflow's plan.estimate per variant and get one go-ahead for the whole list.
  4. One run_workflow per variant, with a note whose first line is the overrides (steps=20 attention=sage). wait_for_job before submitting the next, because of host RAM (bug: two int8 H3 jobs on two cards OOM-kill the host - dispatch is VRAM-aware only, and the earlier job was the one killed #869); that sentence is dropped once bug: two int8 H3 jobs on two cards OOM-kill the host - dispatch is VRAM-aware only, and the earlier job was the one killed #869 ships.
  5. Only the latest run of a step is cached. A variant identical to the latest run (the same variant submitted twice in a row) is reused. Going back to an earlier variant after another has run re-renders it. Each card's worker has its own cache, and a restart empties it. A re-render is expected, not a failed variant.
  6. The results table: list_jobs(workspace=…) for job, status and note; get_job for timing and files.
  7. Assessments with set_note on the output file. First line score N/5 · judged_by <who>, then one key: value line per facet (faces, staging, speech, defects).
  8. Then keep_output the winner, and put the conclusion in the workspace note.

Owes

  • A test asserting the section exists and names the tools it tells an agent to call, in the style of tests/test_mcp_guides.py / tests/test_server_guides.py.
  • No change to dw_mcp/, the REST API, or SURFACE_BUDGET.

Deploy

Server: the guide text ships with the server checkout get_guide reads, so lem pulls the new text.

Passes when

Its own repro works (plan v2, Acceptance intent: the section is served and names only real tools; following it on text-to-image with steps = 4 / 8 / 12, seed pinned, in a fresh qa-* workspace gives three noted jobs with the same seed and differing outputs; a fourth variant repeating the latest variant's overrides shows reused; a Q2-form set_note reads back in full in get_gallery_metadata and its first line in list_gallery), and every pending: #<this issue> case the tester writes passes.

No blockers. It does not wait on #869 or #865; if #865 is declined, step 2's "save a copy with variables" path covers the H3 knobs.

Activity

  1. added
    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)
    owner:leadFeature lead's turn (harnest R11)
    stageA child issue: one stage of a feature
    on Oct 14, 2026
  2. added
    target:mini-aiFound against a non-lem server (DW_TARGET=mini-ai); Don triages
    on Oct 14, 2026
  3. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Lead agent, model claude-opus-5-5 via anthropic.

    Shipped

    • Commit: 776267a2 on develop (merge of feat/872-A-sweep-guide).
    • Deploy: none from this session. The driver deploys develop to mini-ai before the tester runs. This is a docs-only stage: get_guide reads the server checkout, so the new text arrives with that deploy.

    Plan items (plan v1, Design (Stage A))

    ## Running a sweep is in docs/WORKSPACES.md, between Copying between workspaces and Where this is going.

    1. One workspace per experiment: create_workspace + use_workspace. The question and factor list go in set_note("workspace:<name>", …).
    2. Base workflow with every factor as a variable: use the template if it already exposes the factor (get_workflow(…, variables_only=true)); otherwise get_workflow, add the variable, and save_workflow a copy. The {} dtype note links Types and escaping.
    3. Pinned seed in arguments, one factor per variant: validate_workflow each variant, quote its plan.estimate, and get one go-ahead for the whole list.
    4. One run_workflow per variant: the note's first line is the overrides (steps=8, steps=20 attention=sage). Call wait_for_job before submitting the next variant. The bug: two int8 H3 jobs on two cards OOM-kill the host - dispatch is VRAM-aware only, and the earlier job was the one killed #869 host-RAM sentence is there, to be dropped once bug: two int8 H3 jobs on two cards OOM-kill the host - dispatch is VRAM-aware only, and the earlier job was the one killed #869 ships.
    5. Repeats: a repeat is a cache hit ("reused": true), not a failed variant.
    6. Results table: list_jobs(workspace=…) for job, status and note; get_job for arguments, timing and files.
    7. Assessments: set_note on the output's gallery name, in the Q2 form (score N/5 · judged_by <who>, then one key: value line per facet). The full note is in get_gallery_metadata. Listings clip it at 200 characters.
    8. The winner: keep_output it, and put the conclusion in the workspace note.

    Test: tests/test_server_guides.py::…::test_the_sweep_section_names_the_loop_and_only_real_tools. It serves the real section through guides.get_guide, asserts that each tool in the loop is named, and checks every backticked snake_case name in the section against build_server(...).list_tools().

    No change to dw_mcp/, the REST API or SURFACE_BUDGET.

    Deviation from the plan

    • text-to-image does not expose steps as a variable. It hard-codes num_inference_steps: 25. The acceptance repro (steps 4/8/12) therefore goes through step 2's "save a copy" path. The section uses that as its worked example: add "steps": 25 under variables and set "num_inference_steps": "variable:steps". Following the guide literally means saving that copy first. Passing steps straight to the catalog template does nothing.

    Test state

    • ruff is clean.
    • pytest tests/: 17 failures, which fail the same way on develop without this change. They are in test_examples.py (9), test_plugin_skills.py (5, Kandinsky 6) and test_component_type_errors.py (3), and are unrelated to this stage.

    Nothing here is CUDA-specific: the repro runs on SD 1.5, which runs on mps.

  4. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 14, 2026
  5. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Verify of #890 (stage A): FAIL on C-F469. Bouncing to the lead.

    Tester: claude-opus-5-5 via anthropic. Server: mps on mini-ai.lan, develop @ 9e8f15d. I ran the stage's own repro plus the four pending: #890 cases in regression-suite-complete.md. Their pending: lines stay in place.

    case result
    C-F467 (guide section reachable, content) PASS
    C-F468 (sweep: save copy, vary steps, note each run) PASS
    C-F469 (repeat of an earlier variant served from step cache) FAIL
    C-F470 (judge, keep winner, workspace note) PASS, with one caveat (below)

    C-F469: the guide's step 5 doesn't hold for an earlier variant

    Workspace regression-sweep, workflow sweep-base (a copy of text-to-image with num_inference_steps: "variable:steps", seed a variable). I ran three variants at seed 42:

    • steps=4: job 59b0c2eb6ede
    • steps=8: job 00bfd1dced41, run 20261014-094347-cd1f1c83
    • steps=12: job 2c7b87cc523b

    All three succeeded.

    1. run_workflow(sweep-base, {seed:42, steps:8}, wait_seconds=55) → job 1770448d66ec, run 20261014-094410-cd1f1c83. Re-rendered: 9 passes, denoise_s 3.1, a new image file, no reused anywhere. The guide's step 5 says "A variant whose step is unchanged from an earlier run with the same seed is served from the step cache". steps=8/seed 42 had already run (00bfd1dced41), but steps=12 had run since.
    2. validate_workflow(sweep-base, {seed:42, steps:8}) right after → plan.cached_steps: 1.
    3. The same steps=8 run again → job 2069ea8093d0, reused: true. Its files were sweep-base/20261014-094410-cd1f1c83/final/test_image-0.0.jpg, which is call 1's run, not variant 2's 20261014-094347-cd1f1c83.
    4. validate_workflow(sweep-base, {seed:42, steps:4}) → plan.cached_steps: 0, though steps=4/seed 42 ran earlier.
    5. Control: seed 43 / steps 8 → job b3f837859bce, not reused (correct).

    What this shows from outside: the step cache holds only the most recent entry per workflow step. In a sweep, the variant you go back to is almost never the latest, so step 5's promise fails in the common case. Either the guide should say only the latest run of a step is cached (and C-F469 be amended to match), or the cache should keep one entry per input fingerprint. That is a design call for you. If the guide changes, the suite amendment goes through the approval route.

    C-F470: one caveat

    • Note A on the steps=12 file was returned in full by get_gallery_metadata. The listing showed its first line.
    • A long note starting score 3/5 · judged_by claude-opus-5-5 · xxx… was accepted. list_gallery(folder=sweep-base, version=3) clipped it to its first ~200 characters with … and note_truncated: true.
    • Over-limit notes were refused with a note is at most 4000 characters, got 4099 (and got 4010, got 4101). The listing still showed the accepted note afterwards.
    • Caveat: I type a padded note by hand, so I can't prove the accepted one was exactly 4000 characters rather than a few under. The 4000/4001 boundary is not pinned to the character by this run.
    • keep_output(..., asset_name="sweep-winner.jpg") returned asset:sweep-winner.jpg.
    • set_note("workspace:regression-sweep", …) worked: list_workspaces shows the three-line note on the entry.

    Minor, not blocking

    My copy of the template dropped its cost block, so validate_workflow's plan.estimate came back with minutes: null, basis: "unknown". The section's "save a copy" step doesn't say to carry the cost block over. That is worth a line if the section is revised.

    Cleanup: delete_workspace("regression-sweep", acknowledged_cost=true) removed 1 workflow, 3 assets and 23 output files.

  6. added
    owner:leadFeature lead's turn (harnest R11)
    and removed on Oct 14, 2026
  7. added a commit that references this issue on Oct 14, 2026
  8. 6 remaining items

  9. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Don approved plan v2 on #872 (2026-10-14). Back to the lead: re-spec C-F469 against v2 (repeat the latest variant), then merge feat/872-A-sweep-guide @ 2aecdb5d and hand off to the tester.

  10. added
    owner:leadFeature lead's turn (harnest R11)
    and removed
    owner:donParked for human decision
    status:needs-approvalParked pending a written proposal + human approval
    on Oct 14, 2026
  11. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Body reshaped for #872 plan v2: item 5 is latest-run-only step caching, the acceptance repeat is of the latest variant, item 2 keeps the template's cost block. Scope unchanged. The tester re-specs before the next build.

    Lead agent, model claude-opus-5-5 via anthropic.

  12. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 14, 2026
  13. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Lead agent, model claude-opus-5-5 via anthropic.

    Shipped to develop for verify (plan v2)

    • Merge: c243b994 on develop (branch feat/872-A-sweep-guide @ 2aecdb5d, plus a merge of develop). This session doesn't deploy: the driver deploys develop to mini-ai before the tester runs.
    • Gate: ruff check is clean. pytest: 14358 passed, 18 failed. The same 18 fail on origin/develop without this branch (the kandinsky6 example workflows and test_api_contract's committed document), so none are new.

    Plan v2 items → change

    docs/WORKSPACES.md ## Running a sweep, served by get_guide("workspaces", section="Running a sweep"):

    1. One workspace per experiment, with the question and factors in its note: step 1.
    2. A base workflow with factors as variables. It uses a template when the template exposes the factor, else save_workflow a copy. The {} dtype note is there, and the copy keeps the template's cost block (new in v2): step 2.
    3. Pin the seed, one factor per variant, plan.estimate per variant, one go-ahead: step 3.
    4. One run_workflow per variant, with the note's first line holding the overrides, and wait_for_job between variants because of bug: two int8 H3 jobs on two cards OOM-kill the host - dispatch is VRAM-aware only, and the earlier job was the one killed #869: step 4.
    5. Only the latest run of a step is cached (rewritten for v2). Repeating the latest variant is reused. Going back to an earlier one re-renders it. Each card has its own cache, and a restart empties it: step 5.
    6. list_jobs(workspace=) and get_job for the table: step 6.
    7. set_note on the output in the Q2 form (score N/5 · judged_by …, then key: value facets): step 7.
    8. keep_output the winner and put the conclusion in the workspace note: step 8.

    Test: tests/test_server_guides.py::TestTheRealDocs checks that the section is served and names each tool of the loop. It checks that every backticked tool it names exists in list_tools, and it pins plan.estimate, reused, latest run, score and judged_by.

    Deviations: none. No change to dw_mcp/, the REST API or SURFACE_BUDGET, and no MCP shape changes. The repro runs on mini-ai, and nothing in it needs CUDA.

  14. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Verified on mps on mini-ai.lan (develop @ c243b99). Tester: claude-opus-5-5 via anthropic.

    I ran the stage's repro and all four pending: #890 cases exactly as written, in workspace regression-sweep, all over MCP. All pass, so I removed the pending: #890 line from each case.

    C-F467: PASS.

    C-F468: PASS.

    • Setup: sweep-base, a text-to-image copy with num_inference_steps: "variable:steps", cost block kept.
    • All three validates came back clean: estimate 0.2 min, basis other_device.
    • I ran steps 4, 8 and 12 at seed 42, one noted job each. Every job succeeded with one file and none was reused:
      • 8e92178908e6: steps=4
      • 00d36241a08e: steps=8
      • 958aafaadca6: steps=12
    • The three images are visibly different.

    C-F469: PASS. Device was mps Apple M5 Pro (MPS) throughout.

    • 0b849aad4991 repeated steps=12: reused: true, and its files are variant 3's file.
    • 7e90dbfd5ffa went back to steps=8: not reused, rendered as a new run.
    • 0bccd3761055 used seed 43: not reused.

    C-F470: PASS.

    • The Q2-form note: read back in full by get_gallery_metadata. list_gallery shows it from the first line.
    • A 4000-char note (counted, ASCII apart from two ·, first line starting score 3/5 · judged_by):
      • accepted, and read back in full by get_gallery_metadata;
      • list_gallery clips it at ~200 chars with note_truncated: true, starting with that first line.
    • 4001 and 4002 chars: refused with a note is at most 4000 characters, got 4001 (and got 4002). After the refusal, the stored note was still the 4000-char one.
    • The conclusion: keep_output → asset:sweep-winner.jpg worked. A workspace:regression-sweep note set with set_note shows up in list_workspaces.
    • Cleanup is done:
      • delete_output(job_id=…) for all 6 jobs;
      • delete_asset, delete_workflow;
      • delete_workspace(acknowledged_cost=true).
      • list_workspaces no longer lists regression-sweep.

    Note on the cases, not the code. list_jobs(workspace="regression-sweep") returned 12 jobs. Six of them were "historical": true: leftovers from an earlier spec run, in a since-deleted workspace with the same name. The six non-historical ones were exactly what C-F468/C-F469 expect, newest first, with correct notes. A rerun in a reused workspace name will meet the same thing, so the cases should count non-historical jobs only. I'll propose that on the harness repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)owner:testerTester's turn to actstageA child issue: one stage of a featurestatus:verifiedTester confirmed the fix via a real MCP calltarget:mini-aiFound against a non-lem server (DW_TARGET=mini-ai); Don triagesverified-on:mps

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions