Skip to content

Refuse agac clean and reset_workflow --full during a run - #1711

Merged
Muizzkolapo merged 7 commits into
mainfrom
issue-1699-clean-run-lock
Nov 8, 2026
Merged

Muizzkolapo merged 7 commits into
mainfrom
issue-1699-clean-run-lock

Conversation

@Muizzkolapo

@Muizzkolapo Muizzkolapo commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

Closes #1699. Now based on main, which has #1713 (#1698) merged. Main is merged in, so this PR shows only the #1699 change.

Problem

agac clean --all deleted agent_io/store/ while a run was in progress. With #1696 the run lock lives in that folder, so the lock file went with it and a second agac run then passed the lock check. clean also deleted the live database and the run's staging inputs. reset_workflow.py --full deleted store/ the same way.

Change

  • Cleaner: holds the workflow's run lock in every mode (default, --target, --all) before it confirms or deletes anything. It exits with RunInProgressError while a run or retry holds the lock, and that error is no longer wrapped as "Cleaning failed". With no store folder there is no lock to take, and none is created.
  • reset_workflow.py --full: holds the same lock, through agac's own hold_run_lock where the framework imports, else the same flock from plain python3 (the documented invocation). The soft reset is unchanged.
  • Docs: cli/run.md drops "do not run it during a run" and says clean refuses. cli/utilities.md says so in the clean section. The realtime manifest is updated.

Verification

Muizzkolapo and others added 5 commits November 8, 2026 01:08
LockDefaults.SIMPLE_LOCK_TIMEOUT_SECONDS had no reader. Every portalocker
lock in the code is in the run tracker, and each one uses the atomic
timeout. The internal defaults page described a shared/read lock that
does not exist. Remove the constant, the tests that pinned its value, and
its docs row.
Nothing above SQLite stopped a second `agac run` of a workflow. Two runs
started half a second apart both did all the work, and in batch mode both
submitted a batch job, which doubles the spend with a real vendor.

`agac run` and `agac retry` now hold an advisory, non-blocking, exclusive
file lock beside the workflow's database for the whole command. They take
it before the workflow loads, because `--fresh` clears the store inside
the load; a later lock would wipe the first run's rows before refusing.
A second run exits 1 and names the holder's pid. The operating system
releases the lock when the holder exits or is killed, so no stale lock
can remain and no bypass flag is needed. Read-only commands, `retry
--dry-run` and `retry --filter` do not take the lock.
--filter goes to RetryFilterCommand before RetryCommand.execute, so it
never took the run lock #1696 adds. It rewrites dispositions,
checkpoint rows, stored target rows, the status file and the retry
manifest. During a run or retry of the same workflow, the run's next
status save could drop its change, or the retry could put its snapshot
back over the filter.

RetryFilterCommand.execute now holds hold_run_lock for the whole
command, taken before the store is opened, as RetryCommand does. A
dry run writes nothing and still reads past the lock.

Closes #1698

Signed-off-by: Muizz Lateef <Lateefmuizz@gmail.com>
agac clean --all deleted agent_io/store/ while a run was in progress.
With #1696 the run lock lives in that folder, so the lock file went
with it and a second agac run then passed the lock check. clean also
deleted the live database and the run's staging inputs.
reset_workflow.py --full deleted store/ the same way.

The Cleaner now holds the workflow's run lock, in every mode, before it
confirms or deletes anything, and exits with RunInProgressError while a
run or retry holds it. With no store folder there is no lock to take,
and none is created. reset_workflow.py --full holds the same lock:
through agac's own module where the framework imports, else the same
flock from plain python. The run.md sentence asking users not to clean
during a run now says clean refuses.

Closes #1699

Signed-off-by: Muizz Lateef <Lateefmuizz@gmail.com>
…-lock

Signed-off-by: Muizz Lateef <Lateefmuizz@gmail.com>

# Conflicts:
#	agent_actions/cli/_MANIFEST.md
#	docs.agent-actions/docs/reference/cli/retry.md
#	tests/integration/test_a_second_run_of_a_workflow_is_refused.py
… issue-1699-clean-run-lock

Signed-off-by: Muizz Lateef <Lateefmuizz@gmail.com>
@Muizzkolapo
Muizzkolapo changed the base branch from issue-1698-filter-run-lock to main November 8, 2026 17:05
…lock

Signed-off-by: Muizz Lateef <Lateefmuizz@gmail.com>

# Conflicts:
#	tests/integration/test_a_second_run_of_a_workflow_is_refused.py
@Muizzkolapo
Muizzkolapo merged commit a18d1b0 into main Nov 8, 2026
5 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agac clean --all deletes the run lock while a run is in progress

1 participant