Skip to content

fix: per-action write state so one write failure doesn't block the rest#20

Merged
mattmezza merged 1 commit into
mainfrom
fix/manage-jobs-per-action-write-state
Jun 25, 2026
Merged

fix: per-action write state so one write failure doesn't block the rest#20
mattmezza merged 1 commit into
mainfrom
fix/manage-jobs-per-action-write-state

Conversation

@mattmezza

Copy link
Copy Markdown
Owner

Summary

Fixes #8 — a write failure (or skip/deny, or even a successful write) in manage_jobs blocked every subsequent write action in the same turn.

Root cause

_execute_tool tracked write actions with two request-wide values in request_state:

  • write_executed (a single bool) — set True after the first successful write.
  • write_decision (a single value) — set to the first write's approve/skip/deny outcome.

Because both are global to the turn, the guards at the top of _execute_tool rejected any later write once one write had completed ("Request already fulfilled") or been skipped/denied ("User skipped this action") — even a completely different action. Scheduling two reminders in one interaction, or retrying after a skip, failed.

Fix

Track write state per distinct action, keyed on a stable signature of the tool name + its arguments (_write_signature, order-insensitive):

  • executed_writes — a set of completed action signatures. Only an identical repeat is suppressed, preserving the original guard against accidental double-sends.
  • write_decisions — per-signature approval decisions, reused only for the identical action, so a skip/deny never leaks onto a different write.

Read-action approval caching (per match_key, with persisted ALWAYS rules) is unchanged.

Tests

Added regression tests in tests/test_tools.py:

  • distinct writes both succeed after one completes (the issue's main case)
  • an identical repeated write is still deduplicated
  • skipping one write does not block a different one
  • signature distinguishes distinct params and is key-order insensitive

Full suite: 310 passed. ruff check / ruff format clean.

A single successful, skipped, or denied write set a request-wide flag
(`write_executed` / `write_decision`) that blocked every subsequent
write in the same turn. Creating two jobs in one interaction, or
retrying after a skip, failed with "Request already fulfilled" or
"User skipped this action".

Track write state per distinct action instead, keyed on a stable
signature of the tool name plus its arguments:

- `executed_writes`: set of completed action signatures — only an
  identical repeat is suppressed (still guards accidental double-sends).
- `write_decisions`: per-signature approval/skip/deny decisions —
  reused only for the identical action, so a skip/deny never leaks onto
  a different write.

Distinct writes (e.g. scheduling several reminders) now each run and
prompt independently. Fixes #8.
@mattmezza mattmezza merged commit 40be040 into main Jun 25, 2026
1 check passed
@mattmezza mattmezza deleted the fix/manage-jobs-per-action-write-state branch June 25, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix manage_jobs tool — write failures block all subsequent writes

1 participant