Relationships
#974 swamp serve scheduled execution runs steps in an isolated data scope: readResource sees empty state, writeResource never reaches the model-scope chain — stateful scheduled workflows duplicate instead of deduplicating
Opened by magistr · 7/5/2026· Shipped 7/6/2026
Summary
A scheduled workflow on swamp serve executes and delivers correctly per-run, but the step's data scope is isolated per run: context.readResource(...) returns null/empty every scheduled run (it sees neither previous scheduled runs' writes nor CLI-run writes on the model-scope chain), and context.writeResource(...) outputs never become visible on the model-scope chain that swamp data get <model> <name> and subsequent runs' readResource resolve. The SAME workflow via in-container CLI (docker exec swamp-serve swamp workflow run <wf>) has normal semantics. Related but distinct from #914 (sensitive-resource reads in served execution): here NON-sensitive resources, both directions.
(Edit: the originally filed version of this report also claimed the method's Deno.Command("swamp", ...) notification subprocess fails silently — that was wrong; deliveries DO reach Telegram from scheduled runs. Corrected here and in the first ripple; the data-scope isolation is the whole defect.)
Environment
- swamp serve container (debian:stable-slim + install.sh stable),
--repo-dir /workspace, workdir/workspace,@keeb/mongodb-datastore+@webframp/hashicorp-vault - Model:
@anilist/apiv2026.07.04.1 methodrecent-activity— dedupe cursor viacontext.readResource("activity-cursor"), writesactivityFeed+activityCursor, sends Telegram via aswamp model method run <tg-model> sendMessage --stdinsubprocess and only advances the cursor on confirmed delivery - Workflow: single model_method step,
trigger.schedule: "7 * * * *", lookbackMinutes 120
Observed
- Scheduler fires hourly, every run reports
completed. - Model-scope artifacts are FROZEN across 19 scheduled runs:
swamp data get my-anilist current/activity-cursorstay at the version written by the last CLI run;checkedAtand the cursor floors never advance. Since the method'swriteResourceexecutes without error (a throw would fail the run), the writes must land in a scope invisible to model-scope reads. - The runs DO deliver: a scheduled run at 13:07Z posted a single-item digest whose content proves it computed with an EMPTY cursor and a fresh 2h lookback window (11:07–13:07Z). Had it read the model-scope cursor (last advanced by a CLI run a day earlier), its window would have included three additional older undelivered items — it posted only the one item inside the fresh window.
- Consequence: with lookback (2h) > cadence (1h), every activity is delivered by every scheduled run whose window covers it → systematic duplicates; and delivery-failure retry semantics (cursor hold) can never work because no state survives to the next run.
- Separate retrieval oddity, still unexplained: in-container
swamp data list --workflow <wf>attributes an unrelated model's months-old 86B artifact to the step,data get --workflow <wf> currentreturns that foreign artifact, andswamp data query 'tags.workflow == "<wf>"'/'tags.workflowRunId == "<id>"'return "No matching data found" even though artifacts fetched by plaindata getcarry exactly those tags (Mongo datastore). docker exec swamp-serve swamp workflow run <wf>: normal semantics —writeResourcebecomes the next model-scope version, the next run'sreadResourcesees it, dedupe cursor works.
Expected
Served scheduled execution should have the same data semantics as CLI workflow execution: step writeResource becomes the next model-scope version (or at minimum, readResource resolves what the previous scheduled run wrote). If per-run isolation is intended, it needs to be documented and a supported mechanism provided for methods that keep dedupe/cursor state across scheduled runs.
Impact / workaround
Any stateful scheduled workflow (notification dedupe, incremental sync cursors, rate-limit bookkeeping) silently degrades on serve: duplicates instead of dedup, no catch-up after downtime. Workarounds: (a) size the lookback window exactly to the schedule cadence and accept lost items on failure windows, or (b) drop trigger.schedule and drive the workflow from host cron via docker exec swamp-serve swamp workflow run <wf> (same class of workaround as #914).
Shipped
Click a lifecycle step above to view its details.
magistr commented 7/5/2026, 2:03:00 PM
Correction to the original report after more evidence: the Telegram-send subprocess does NOT fail in served scheduled execution — deliveries DO reach the chat. The defect is narrower and is the state scoping alone:
- Scheduled-run
readResourcegets empty/run-scoped state each run (it never sees prior runs' writes, nor CLI-run writes on the model-scope chain), and itswriteResourceoutputs never become visible on the model-scope chain. - Consequence for any cursor/dedupe-style method: every scheduled run starts from a fresh window, so the same item is delivered by every run whose window covers it (with an hourly schedule and a 2h lookback, roughly every item twice).
Observed sequence: a subscriber received a single-item digest at 13:07Z posted by the scheduled run (its 2h window contained exactly that one item), while swamp data get <model> current stayed frozen at the version written by the last CLI run, and the method's cursor floors never advanced. In-container CLI runs of the same workflow read/write the model-scope chain correctly.
So: title's "subprocess fails silently" is wrong, please read this as "served scheduled execution uses an isolated data scope for both reads and writes → stateful scheduled workflows duplicate instead of deduplicate". The data list/get/query --workflow mismatches from the original report still stand.
Sign in to post a ripple.