Skip to content

fix: prevent task overwrites when filenames collide - #102

Open
ShubhSingh wants to merge 2 commits into
ClawRunr:mainfrom
ShubhSingh:fix/task-file-collisions
Open

ShubhSingh wants to merge 2 commits into
ClawRunr:mainfrom
ShubhSingh:fix/task-file-collisions

Conversation

@ShubhSingh

Copy link
Copy Markdown
Contributor

Creating two tasks with the same name within the same second currently produces the same task ID and truncates the first task file. Different names can also collide after sanitization (for example, check mail and check?mail). Both queued jobs then refer to the same file.

This change reserves each new task path with atomic Files.createFile. An existing filename is retried with a numeric suffix. Updates keep using the existing task ID, and the original filename is retained when there is no collision.

Regression coverage

  • Same name and timestamp: distinct IDs, independent descriptions, and updating one task does not change the other.
  • Different names that sanitize identically remain independent.
  • Twenty concurrent creations with the same name and timestamp retain twenty independent tasks and their descriptions.

Validation

The first two regression tests failed on upstream d0600b4 before the fix. All 11 FileSystemTaskRepositoryTest cases pass after it, including the concurrent case. The published files were fetched and compared against the locally tested working tree with no differences. git diff --check passes.

Commands (Java 25):

./gradlew :base:test --tests "*FileSystemTaskRepositoryTest"
./gradlew :base:test

The broader base suite ran 103 tests: 99 passed and 4 failed. All four failures also reproduce in an untouched checkout of d0600b4 on this Windows machine: YamlParserTest.parseMultiLineFrontmatterValue, two TaskHandler filename tests, and SkillsJarSupportTest.loadsSkillsFromJarResource. They are not introduced by this change. For the broader local run, Mockito was supplied with an external Gradle init script as a JVM javaagent to avoid a local attach failure; repository build settings are unchanged.

No live LLM, external messaging service, or paid API was used. This prevents new-task filename collisions; it does not add atomic replacement of existing task contents or coordination of simultaneous updates to the same existing task.

@arefbehboudi arefbehboudi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @ShubhSingh , nice fix!

Two small things:

  1. Needs a rebase, it conflicts with #103.
  2. Please write the content directly with StandardOpenOption.CREATE_NEW instead of creating an empty file first. Right now a failed write leaves an empty file that breaks getTasks for that day.

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.

2 participants