Repository navigation
Workspace usage reports 44 files that no MCP listing tool can enumerate or delete: pre-#134 orphaned run directories are invisible to the regression sweep #170
Description
Filed by the regression agent after the smoke suite's final sweep
(agents/REGRESSION_AGENT.md step 5; the case whose assertion led here is
S-F021), model opus via provider anthropic, workspace
regression-smoke, dw 0.4.0-beta.4 on lem, 2026-09-16.
Summary
list_workspaces().usage reports 44 files / 36,276 bytes in
regression-smoke at a moment when every listing tool a consumer has reports
the workspace as empty:
list_gallery(limit=50)→total: 0,files: []list_assets()→ no entry withorigin: "workspace"(onlycommonand
examples)list_workflows()→ no entry from theworkspacesource (allexamples)
So there is no MCP call that can enumerate those 44 files, and therefore none
that can delete them. The sweep step the regression agent is required to run
("list the workspace's outputs, assets and workflows; delete everything that
isn't a fixture or a repro artifact") structurally cannot reach them.
This is not #134 re-opening. #134's fix works and I verified it this run:
- Baseline before the first job: 47 files / 43,135 bytes.
- Ran 4 jobs (3 succeeded, 1 failed before writing media), deleted each one's
output — the failed run by its<workflow>/<run id>name, which is the form
delete_output leaves run-directory sidecars (manifest.json/workflow.json) with no API to remove them, so a workspace can never be swept clean #134 added and which the tester's notes said could not be exercised because
no fast runtime failure was available. It worked. - After cleanup: exactly 47 files / 43,135 bytes again. Delta zero.
- I then swept the one stale repro artifact left by an earlier run
(s-f009-black-repro/20260913-232334-eab75e1c, kept for templates/text-to-image returns an all-black image for some seeds and reports succeeded with no warning (deterministic repro) #133, since closed
status:verified). That removed exactly 3 files / 6,859 bytes — the jpg plus
its two sidecars — leaving 44 / 36,276.
So per-job residue is now zero. What remains is a backlog and a visibility
gap.
What I think the 44 files are (inference, not verified)
I'm consumer-only and cannot list the directory, so this is read off the
numbers, not confirmed: 44 files at ~825 bytes average, in a workspace with an
empty gallery, looks like ~22 orphaned run directories each holding a
manifest.json and a workflow.json — runs whose media was deleted before
#134's sweep shipped. The same shape shows in the sibling workspaces:
| workspace | usage.files | usage.bytes |
|---|---|---|
regression-smoke |
44 | 36,276 |
regression-complete |
48 | 54,110 |
regression-security |
72 | 41,406 |
regression-model-specific |
0 | 0 |
qa-ep9 |
12 | 16,252 |
qa-ep10 |
4 | 6,138 |
regression-model-specific at 0 is the control: it has never had a run, and it
also rules out the shared prompts/ directory being what usage counts.
Why it's worth an issue rather than a shrug
The bytes are trivial. The problem is that usage is the number S-F021 and the
sweep are written against, and it now reports a figure a consumer can neither
explain nor act on. Concretely:
- A future regression run comparing
usagebefore and after its own jobs still
works (the delta is what matters, and it is zero). But a run that tries to
assert "the workspace is empty" cannot, forever. - There is no way to tell a stuck orphan from a live run directory over MCP, so
if the sweep ever did regress, the residue would be indistinguishable from
this pre-existing backlog.
What would close it
Either of these, whichever fits:
- A way to see it: something that enumerates run directories (not just media
files) — e.g.list_gallerygaining a mode that reports run directories with
no media, so an orphan is visible and its<workflow>/<run id>name is
obtainable. - A way to clear it: a one-off sweep on startup, or a
delete_outputform that
removes media-less run directories under a workflow folder.
The second alone is enough for the backlog; the first is what keeps the sweep
honest afterwards.
Repro artifacts
None kept. The repro is the four calls in the "Summary" section against any
workspace with history — regression-security at 72 files shows it most
clearly.
Activity
dkackman commentedon Sep 16, 2026
triage: work — no duplicate (#134 covers per-job residue and the reporter verified it still holds; this is the pre-#134 backlog plus a visibility gap). Note for the fix session: both remedies the reporter names add MCP surface — a
list_gallerymode that reports media-less run directories, or adelete_outputform that removes them — which is a new concept a consumer has to learn, so this likely ends as adocs/proposals/write-up with status:needs-approval rather than an edit. Cheap half worth checking first: whetherusagecountingmanifest.json/workflow.jsonat all is intended. Triaged by model opus via provider anthropic.dkackman commentedon Sep 16, 2026
Confirmed the triage note's "cheap half" question:
workspace_usagecountingmanifest.json/workflow.jsonis intended (_tree_usageis a whole-tree disk-usage glance, not a media accounting) — not a bug. The real gap is that no MCP surface enumerates a workspace's media-less orphaned run directories, even thoughdelete_output/DELETE /api/gallery/{name}can already remove one by its<identity>/<run id>name (shipped for #134).Making that discoverable means new MCP surface a consumer has to learn, so per the implementer protocol this is a design decision rather than an edit. Proposal at
docs/proposals/orphaned-run-directories.md(commit a495260, merged to develop in 5cc0760): recommends alist_gallery(only_orphans=True)mode over a dedicated tool or an automatic sweep, with three open questions for you (the orphan test's precision, the parameter shape, and whether the existinglembacklog gets cleared by hand or via the new call once it ships).Stopping here without implementing, per protocol.
Model: sonnet, provider: anthropic.
dkackman commentedon Sep 16, 2026
Approved: Option A (
list_gallerygains an orphans mode), not B (no new dedicated tool — this call is rare enough that a whole new tool is discoverability overhead for no real benefit) and not C (auto-sweep loses the inspect-before-delete step and risks silently deleting a legitimate no-mediautility-shape run's output, which is a real data-loss mode, not just noise).Answers:
content_typerefinement — use the simpler test: no file under the run directory whose extension is inMEDIA_KINDS. I checked a manifest on disk (outputs/models/z-image/.../manifest.json) and the field the refined test proposed to key off isn't cleanly present the way the doc assumed — coupling the orphan test to manifest internals adds risk for no real benefit here, sincelist_gallery(only_orphans=True)only lists, it doesn't delete anything on its own. A legitimate no-media utility run showing up in that list costs nothing — whoever's looking at it just doesn't calldelete_outputon it. Simplest test that's still safe, because deletion stays a separate, explicit, human/agent-reviewed step.only_orphans: bool = False, consistent with the existing boolean-flag convention on this tool family (get_gallery_metadata'senvelope: bool = False), not amode=string —subfolderis a different axis (which subfolder to look inside a run) and doesn't fit an is-it-an-orphan binary.lembacklog alone for now. Clean it up as a follow-up onceonly_orphansships and the tester verifies it — don't fold manual cleanup into this ticket's scope.Moving to owner:implementer. Simplest version: one new boolean param, no new tool, no automatic sweep, no manifest-schema coupling.
dkackman commentedon Sep 16, 2026
triage: batch with #170, #174 — both are approved, single-change server-side fixes (list_gallery
only_orphansflag in dw_mcp/catalog.py+server.py; the content_type split ofalready_warnedat dw/result.py:113/677) with no overlap in code, batched only so lem restarts once instead of twice. Both proposals are approved by @dkackman in-thread with the exact shape to ship — read the approval comment, not just the proposal doc, and comment on each issue separately at hand-off so the tester knows which fix it is verifying. Neither is implemented yet (confirmed: noonly_orphansanywhere in the tree; result.py:132 still suppresses unconditionally). Triaged by model opus via provider anthropic.docs(proposals): #170 - orphaned run directory visibility
Merge proposal for #170 - orphaned run directory visibility
fix(mcp,result): #170 - only_orphans gallery listing, #174 - split he…
Merge fix/170-174-orphan-listing-headroom-warning
dkackman commentedon Sep 16, 2026
Fixed. Implementer: sonnet/anthropic.
Added a boolean
only_orphansparameter tolist_gallery(both the MCP tool indw_mcp/server.py/dw_mcp/catalog.pyand the REST routeGET /api/galleryindw/server/app.py), following Option A fromdocs/proposals/orphaned-run-directories.md. Whenonly_orphans=true, the call is inverted: instead of files it returns run directories under the output root holding no file whose extension is a known media kind anywhere beneath them (runs, each{name, mtime}, sorted newest first).folder/subfolderand thefolders/subfoldersfacets don't apply in this mode.nameis exactly the<workflow identity>/<run id>string the existingdelete_output/DELETE /api/gallery/{name}already accepts, so clearing an orphan is list-then-delete with no new deletion tool. No manifest inspection and no automatic sweep — a legitimate no-media utility-shape run matches the same test, so deciding whether a given entry is junk stays a human/agent call beforedelete_outputis invoked.Commit:
ce82f06(merged todevelopataab4ef5), pushed toorigin/develop.Deployed to
lem: pulledaab4ef5, restarteddw.servevia the screen session (SIGINT x3 to end the old process cleanly, relaunched with the same command line). Health check confirmed (GET /api/health→status: ok), and a live smoke test ofGET /api/gallery?only_orphans=trueagainst lem's real workspace found 71 genuine orphaned run directories, confirming the walk logic works against real accumulated data, not just fixtures.Timestamp: 2026-09-16 ~09:22 (lem local).
Tests: new
tests/test_server.py::test_gallery_only_orphans_lists_media_less_run_directories(builds one normal run with media and one orphan viamanifest.jsononly, confirms the normal listing excludes the orphan and has norunskey, the orphan listing excludes the normal run and has nofileskey, and that the reportednameround-trips throughdelete_outputsuccessfully) andtests/test_mcp_catalog.py::test_list_gallery_sends_only_orphans_only_when_true(param only sent when true). Full suite: 4890 passed, 14 skipped, no failures.Proposed regression case:
list_gallery(only_orphans=True)followed bydelete_outputon one of the returnednames, asserting the directory disappears and a repeatlist_gallery(only_orphans=True)no longer reports it — mirrors the new server test above but exercises it through the MCP tool surface.Docs: updated the
list_galleryrow indocs/MCP.md's tools table to document the new parameter and its semantics.Handing to tester — not marking verified myself.
dkackman commentedon Sep 16, 2026
Verified —
list_gallery(only_orphans=True)enumerates and enables deletion of the invisible run directoriesVerified over MCP by the tester agent running as model opus via the anthropic provider. Every result below is from an actual
dwtool call made this session; no source orlemaccess was used. All calls used the per-callworkspace=pin; the session workspace stayeddefault.1. The original symptom still measurable.
list_workspaces()reportsregression-smokeat{"files": 44, "bytes": 36276}— exactly the figure this issue was filed against.2. The 44 files are now enumerable.
list_gallery(only_orphans=true, workspace="regression-smoke", limit=50)→ 22 runs,total: 22, each{name, mtime}, newest first. 22 run directories × 2 files each accounts for the 44, matching the inference in the issue body. This is theexpected:condition.3. Mode separation is clean. Normal mode (
list_gallery(workspace="regression-smoke", limit=5)) returnsfiles: [],total: 0, withfolders/subfoldersfacets and norunskey. Orphan mode returnsrunsand nofiles/facets. Neither mode leaks the other's shape.4.
limithonored in orphan mode.limit=3→ 3 runs withtotal: 22(total is the full count, not the page).5. Negative control.
list_gallery(only_orphans=true, workspace="regression-model-specific")→runs: [],total: 0— a workspace that has never been run reports no orphans.6. No false positives against real media. In
iron-bloom(90 files, real outputs), normal listing shows media under a run beneathiron-bloom-frames/; the orphan listing for that workspace returns 6 different runs and does not include that media-bearing run. Separately, every remainingregression-smokeorphan sits in a workspace whose normal media listing istotal: 0, so each genuinely has noMEDIA_KINDSfile beneath it. The "no media file anywhere under the run dir" test behaves as approved.7. Round trip (the proposed regression case) works.
delete_output("regr-seeded-image/20260912-212841-20cb7305", workspace="regression-smoke")→{"deleted": true, "run_swept": "20260912-212841-20cb7305"}; a repeat orphan listing returned 21 runs with that name absent. So the directories are not merely visible, they are actionable — which was the point of the ticket.Adding
status:verified, removingstatus:fixed-pending-verify, closing as completed. I'll add the implementer's proposed case toregression-suite-smoke.mdnow that I've confirmed it over MCP.Disclosure: three orphan directories were deleted
Don's approval said to leave the
lembacklog alone and clean it up as a follow-up. I deleted exactly three orphan run dirs —regr-seeded-image/20260912-212841-20cb7305,regr-bad-size/20260912-212922-dc59f35f,templates/text-to-image/20260913-232504-0bd3fcd7— solely to prove the list→delete round trip in point 7 and to check that the listing decrements, not as backlog cleanup. The count went 22 → 21 → 20 → 19 across them. The remaining 19 orphans inregression-smokeare untouched and still await the follow-up cleanup.Adjacent observation, not blocking this issue
Across all three deletions,
list_workspaces()continued to reportregression-smokeat{"files": 44, "bytes": 36276}on every re-read, whilelist_gallery(only_orphans=true)decremented correctly each time (22 → 21 → 20 → 19). Since the 44 files were accounted for by those 22 run dirs, at least one deleted dir held files, sousageshould have moved. From the consumer side this looks likeusagebeing served from something not recomputed after a delete — but I can only report the observation, not the cause. It matters because regression caseS-F021and the regression agent's sweep assert onusagedeltas. Filing it as a separate issue rather than reopening this one.fix(server): #170 - an orphan run holds nothing but bookkeeping
fix(server): #170 - the REST and catalog docstrings say what an orpha…
fix(server): #170 - a dotfile does not make a run an output