Repository navigation
feat(tasks): compare revisions on the task being changed - #168
Merged
Merged
Conversation
Main's retry-safe task creation (client_request_id, parent_ref, blocked_by_refs) meets the revision tokens: the revision check still runs before each task op and the revision advance after it, with main's task.create path (task id and replayed in the change) in between; the stored task drops both sides' op-only keys, and the MCP task create keys are the union. Main's new storage test compares a loaded task with the seeded map; a loaded task now carries its revision, so the test expects the untouched task at rev 0 (the failed batch published nothing).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An unrelated agent-state write invalidates the whole-Context
if_versiontoken, even when the task being changed is untouched. Callers cannot distinguish that case from another caller changing the same task.Tasks now expose an unsigned
rev: older task files without one read as 0, and new tasks start at 1. Existing-task operations acceptif_task_rev. A mismatch rejects the batch withtask_conflict, naming the task and its expected and actual revisions. The existing whole-Context guard remains independent; callers may use either guard or both.Each semantic task change increments its revision. An identical patch retains the revision and derived timestamp. Operations in a batch see preceding in-memory revisions; a later conflict commits none of the batch's task or Context changes. Targetless creates reject
if_task_rev, and callers cannot assignrevthemselves. Existing task-ID non-reuse protects against a deleted task being mistaken for a later incarnation. Direct YAML editors must follow the same revision protocol; API guards cannot fence writes that bypass the store.How we built it. Revision checks and advancement share the common Context operation boundary under its existing lock. Advancement compares all tasks after each operation, including indirectly changed tasks; legacy migration participates too. Read-only loading supplies revision zero without rewriting old files. Full/summary Context reads, individual tasks, task pages, the compact index and MCP bootstrap previews retain the revision. The daemon exposes the structured conflict. MCP preserves a guard once when one call expands into update plus move, and the schema and Context/IPC contracts document it.
How we tested it.
3969f7970f742760dc3b255ec58c611078c480cepassed all six jobs, includingrust-linux: run39777285737. The test-only reference run39763090179, based on upstream maina212cb04before it advanced tof1d27838, fails exactly the eight added tests while the other 2,715 pass; it is historical baseline evidence, not a test of current main.Tested on: GitHub-hosted Ubuntu 24.04 x86_64 runners, 4 vCPUs, Rust 1.88.0 (daemon probes); fork CI also passes Windows smoke.