Skip to content

fix(kanban): keep a scratch dir another live task still uses - #126513

Closed
686f6c61 wants to merge 4 commits into
NousResearch:mainfrom
686f6c61:fix/126508-shared-scratch
Closed

686f6c61 wants to merge 4 commits into
NousResearch:mainfrom
686f6c61:fix/126508-shared-scratch

Conversation

@686f6c61

Copy link
Copy Markdown

What does this PR do?

kanban gc, task completion and the deferred parent cleanup deleted a scratch directory as soon as one task that pointed at it went terminal. Decompose children can share that workspace_path. The other task, still ready or running, then lost its files.

Before rmtree or git worktree remove, the three sites now skip the path when another task that is not done, archived, failed or cancelled resolves to the same directory. The skip is logged and recorded as workspace_cleanup_deferred_shared. The last task to go terminal still removes the directory. A scratch dir that nobody else uses is still collected.

Related Issue

Fixes #126508

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • hermes_cli/kanban_db_workspace.py: _workspace_in_use_by_other() compares resolved paths. Completion and parent cleanup use it.
  • hermes_cli/kanban_ops.py: kanban gc uses the same guard for scratch dirs and worktrees.
  • tests/hermes_cli/test_kanban_gc_retention.py: a live task sharing the dir keeps note.txt through both gc and _cleanup_workspace.

How to Test

uv run --group dev python -m pytest tests/hermes_cli/test_kanban_gc_retention.py -q

10 passed. Without the guard, test_cmd_gc_keeps_a_scratch_dir_a_live_task_still_uses failed: gc printed 1 workspace(s) removed and note.txt was gone. ruff check on the three files was clean. The full pytest tests/ -q suite was not run.

This does not change decompose so children get their own directory, and it does not add kanban gc --dry-run.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux 7.0.0-34-generic x86_64

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

gc, completion and deferred parent cleanup removed a shared
workspace_path as soon as one of its tasks went terminal.
Comment thread hermes_cli/kanban_db_workspace.py Outdated
return True
if not key:
return False
rows = conn.execute(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug] (blocking) This query checks only the board database behind conn, but a task on another board can point to the same workspace_path. I reproduced that case on this exact head with an archived task on the default board and a ready task on a named board sharing one scratch directory. _cleanup_workspace() deleted the file that the ready task still needed. The new tests put both tasks in one connection, so they do not cover this boundary. Please make the ownership check cover every board database, or fail closed when global ownership cannot be established.

The live-task check only read the board database it was given. A ready
task on a named board can point at the same directory.
@686f6c61

Copy link
Copy Markdown
Author

_workspace_in_use_by_other now reads every other board database on disk, not only the connection it was given. If that set cannot be read, cleanup is skipped.

pytest tests/hermes_cli/test_kanban_gc_retention.py -q
11 passed.

On 2ace1a9 the cross-board case deleted the scratch file. On 00334af the ready task on the named board keeps it.

@ehz0ah ehz0ah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST_CHANGES

The new head fixes the previously reported cross-board lookup gap. The added regression fails on 2ace1a93 and passes on 00334af8, and all 11 focused retention tests pass. The change also merges cleanly with current upstream/main at cf9dbe59, where the same 11 tests pass.

One cross-board identity case can still delete a live task's shared workspace. Task IDs are unique only within each board database. The inline comment includes the reproduction and impact.

No hosted check runs or commit statuses are reported for this head.

Comment thread hermes_cli/kanban_db_workspace.py Outdated
other = sqlite3.connect(uri, uri=True, timeout=1.0)
try:
other.row_factory = sqlite3.Row
return _conn_uses_path(other, task_id, key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug] (blocking) A sibling board must not reuse the current board's task ID as an exclusion. Task IDs are generated independently and are unique only inside each board database. I reproduced this on the current head by creating t_same_id on both boards, archiving the default-board task, and leaving the named-board task ready with the same workspace_path. _other_board_uses_path() passed t_same_id into WHERE id != ?, filtered out the live row, and _cleanup_workspace() deleted note.txt. The same failure remains after composing this head with current upstream/main. Please query sibling boards without excluding the current board's task ID and add a matching-ID regression.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Task ids are only unique inside one board, so the sibling lookup no longer drops a row with the same id.

Pushed cbfb444: a matching-id regression keeps the scratch file.

uv run --group dev python -m pytest tests/hermes_cli/test_kanban_gc_retention.py -q

12 passed

Task ids are unique only inside one board database. Excluding the id
being cleaned up hid a live task on a sibling board that reused it.
The sibling-board case was pasted twice. Pytest only collects one.
kshitijk4poor pushed a commit to kshitijk4poor/hermes-agent that referenced this pull request Oct 3, 2026
gc, completion/archive cleanup and deferred parent cleanup rmtree'd a
task's workspace_path as soon as that task went terminal, even when
another non-terminal task (on this board or a sibling board) pointed at
the same directory, destroying its in-progress work.

Before removing, compare the resolved path against every live task on
this board and on every other board's kanban.db; if any still uses it,
skip the delete, log, and record a workspace_cleanup_deferred_shared
event. When the sibling-board set cannot be read, refuse the delete.

Salvaged from NousResearch#126513 (squash of its commits).
Fixes NousResearch#126508.
kshitijk4poor pushed a commit that referenced this pull request Oct 3, 2026
gc, completion/archive cleanup and deferred parent cleanup rmtree'd a
task's workspace_path as soon as that task went terminal, even when
another non-terminal task (on this board or a sibling board) pointed at
the same directory, destroying its in-progress work.

Before removing, compare the resolved path against every live task on
this board and on every other board's kanban.db; if any still uses it,
skip the delete, log, and record a workspace_cleanup_deferred_shared
event. When the sibling-board set cannot be read, refuse the delete.

Salvaged from #126513 (squash of its commits).
Fixes #126508.
@686f6c61

686f6c61 commented Oct 3, 2026 •

Copy link
Copy Markdown
Author

Carrier: #130536 (merged by kshitijk4poor as c508891, cherry-pick preserving original authorship). Closing this PR since the carrier landed. No further action needed.

@686f6c61 686f6c61 closed this Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: kanban gc / archive / complete delete a scratch workspace still used by a non-terminal task (shared workspace_path)

3 participants