Repository navigation
feat(witan): checkpoint comments so a cut-off task run can resume - #492
Merged
Merged
Conversation
Long autonomous runs get cut off by spend limits, network errors, machine sleep and OOM kills, and the next session that claims the task cannot tell how far the last one got. The witan-task skill now has the holder leave a one-line `checkpoint <step>: <ref> | next: <action>` comment after each durable step, and a claiming session verifies the last one against git and GitHub before resuming from the first step live state does not confirm. The context hook would have served every such comment back to its own author as a new comment on the next prompt, so the "New Comments on Work You Hold" block now skips `checkpoint ` comments by the task's holder. The comparison ignores the `#session` qualifier, using the same_person helper task_release already used (moved to readiness so the hook can share it). The task_comment docstring names checkpoints as the exception to "not for your own execution notes". Task: tk-witan-task-skill-checkpoint-comments-so-a-cut-of-de7aee Claude-Session: https://claude.ai/code/session_015nBsjMvN2iuLbUbCSFpsWT
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Normalizing bare comment authors can hide teammates’ checkpoints or echo the holder’s own checkpoints when identities contain hash suffixes.
1 open finding
What changed in this PR
Adds checkpoint comments to Witan’s task workflow so interrupted runs can resume from verified progress.
Changes:
- Documents checkpoint creation and recovery against live Git and PR state.
- Filters holders’ own checkpoints from injected context using shared identity matching.
- Adds local and remote filtering tests and updates tool documentation.
| File | Description |
|---|---|
| mcp/servers/witan/witan/skills/witan-task/SKILL.md | Defines checkpoint and resume workflows. |
| mcp/servers/witan/witan/server.py | Shares identity matching and documents checkpoints. |
| mcp/servers/witan/witan/readiness.py | Exposes the shared identity helper. |
| mcp/servers/witan/witan/context.py | Filters holders’ own checkpoints. |
| mcp/servers/witan/tests/test_context.py | Tests filtering on both transports. |
| mcp/servers/witan/changelog.d/20261015_163616_blarghmatey_witan_task_checkpoints.md | Records checkpoint behavior. |
| docs/reference/mcp-tools/tasks.md | Updates generated tool documentation. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
An identity is free-form (WITAN_AUTHOR, git user.name, a token's preferred_username or email), so it can end in something that looks like a #session qualifier. same_person strips that from both sides, so author alice#ops read as alice: a teammate alice#ops's checkpoint was hidden from holder alice#5e313f6d, and alice#ops's own checkpoint was shown back to holder alice#ops#5e313f6d. This compares the bare author to the holder and to the holder's session-stripped identity, which keeps unqualified claims matching. _held_by had the same two-sided problem for an unqualified claim by such an identity and now uses the same comparison. same_person goes back to server.py unchanged, since task_release compares two holders and is the only caller. Claude-Session: https://claude.ai/code/session_015nBsjMvN2iuLbUbCSFpsWT
feoh
approved these changes
Oct 16, 2026
rhysyngsun
added a commit
that referenced
this pull request
Oct 16, 2026
… findings Two reviews landed on #485. This covers both, less the packaging move that follows it. === Deferring to the witan skills, instead of restating them === references/witan-tracking.md restated witan's claim, session-id and project rules on the grounds that a consumer who installed the catalog without witan would have no witan-task SKILL.md for a link to reach. That does not hold: all four skills stop outright when the witan tools are missing, and `witan setup` installs the witan skills with the tools. The copies had already drifted -- witan-task requires reading a task's comments on claim, because a comment outranks the description, and the copy here had never been updated to say so. It now says WHEN to claim, advance and end, and links for HOW. Same for the restated session_id-not-assignee block in implement-plan, and for #492's checkpoint convention, which is linked rather than copied: its format and git commands already changed once during that review. Only scope-work started a workflow session, yet implement-plan's close-out called workflow_session_end(session_slug=...). A session picking up chunk 3 had no slug, so its work was attributed to no project and the end call had nothing to close. Both downstream skills now link a session on entry when the injected context shows none. plan-technical-approach created a SECOND task with the same external_uri for multi-chunk work, so the task scope-work claimed never closed -- it held a lease on work that had shipped. It now promotes that task with task_update(type="epic") and parents the chunks under it, passing the project_slug the example had omitted, without which chunks never roll up to the project. Chunk progress lived in three places with no stated authority. Task state is authoritative for chunk status, `gh stack view` for PR state, and the plan comment is the narrative derived from both -- so a reader without witan is served without the comment becoming a third thing to keep in sync. scope-work joined or created a project with no confirmation, unlike witan-workflow, which deliberately touches nothing until the user answers; this repo has 27 active projects. It now proposes the project with every field pre-filled and asks once. === Specs are not large ADRs === Tier 2 routed "large enough to need splitting into several pull requests" to an ADR, but how work is split is a delivery question owned by chunking-the-work.md, not a decision anyone will come back to ask about. That criterion is gone. In its place, a spec tier, on the distinction the review drew -- lifetime. An ADR records one decision that stays true as long as the code does; a spec is the plan for one body of work, with interlocking decisions, open questions and a sequence across PRs, sessions or repos, which changes in flight and becomes history when it ships. There are 33 such specs across the three repos and the routing had no place for them. Multi-PR, multi-session or multi-repo work now lands a spec where the repo already keeps them, with each decision extracted into its own ADR once it settles; and a call the team cannot make alone routes to an RFC with an ADR recording the outcome. That also gives witan's `spec` phase a concrete meaning: the spec exists and is under review. === Smaller things === Dropped the claim that the full process "costs ten minutes" -- unmeasured, and with a scoring pass, an ADR and a plan comment it is likely heavier. The asymmetry argument stands without a number. The remaining Copilot findings: both `## Verify` examples reported OK when the scan itself failed (`&& echo FAIL || echo OK` collapses "clean" and "could not scan", and exits 0 either way), so they now distinguish 0/1/>1 and carry the verdict in their exit status. The ADR approval query accepted any historical APPROVED, counting a reviewer who later requested changes and counting Copilot; it now takes each reviewer's latest verdict excluding bots, which required moving from `gh pr view` to `gh api` -- the former reports no `user.type` and strips the `[bot]` suffix. ADR discovery read only `applies_to`, silently skipping records predating that convention, and read only Decision and Consequences, missing the addenda this very workflow appends. A forward-looking glob was declared wrong at close-out when a later chunk had yet to create the path. Close-out's own edits had no way to reach the default branch and now ship as a follow-up PR. The "accepted untracked" workaround bypass contradicted the mandatory Follow-up URL and is gone. Helper paths no longer assume ~/.claude/skills, which is wrong for four of the five supported agents. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Long autonomous runs get cut off by spend limits, network errors, machine sleep and OOM kills, and the next session that claims the task has no way to tell how far the last one got. The dbt migration insights report that prompted this (per the task description) had one of six tasks finish in a run, with PRs left unopened. This adds a checkpoint convention to the witan-task skill and stops the context hook from echoing those checkpoints back to the agent that wrote them.
Witan task: tk-witan-task-skill-checkpoint-comments-so-a-cut-of-de7aee
task_commentper durable step (branch, change, validated, pushed, pr-opened, review-requested, blocked) ascheckpoint <step>: <ref or exact command> | next: <action>. "Resuming from a checkpoint" has a claiming session fetch, check the last checkpoint against git andgh pr view, and resume from the first step live state does not confirm. Live state wins on disagreement.checkpointcomments whose author is the task's holder. Without this, every checkpoint came back on the author's next prompt as a new comment to act on. The comparison ignores the#sessionqualifier on the holder only (_is_holderincontext.py), because an identity is free-form and may itself end in something qualifier-shaped._held_byuses the same comparison. The holder string comes from the held task'sassignee, so the filter works the same on the local and deployed paths without passing the caller's identity through either. A teammate's checkpoint on a task you hold still shows.task_commentdocstring said comments are not for your own execution notes. It now names checkpoints as the exception, so the tool and the skill don't contradict each other (docs/referenceregenerated).Two places where the skill differs from the spec. The spec's
git branch -a --list '<branch>'only matches the local branch, because-apatterns match remote refs asorigin/<branch>, so the skill uses--list '<branch>' 'origin/<branch>'. It also runsgit fetch origin <branch>first, because a resuming session may be in a different clone whose remote-tracking ref is stale and would read as "never pushed".New tests in
mcp/servers/witan/tests/test_context.pycover both transports: your own checkpoint (claimed as<you>#<session>, commented as<you>) is skipped, while your own plain comment and a teammate's checkpoint are shown. Both fail with the filter disabled.just test-witan-councilagainst omnigraph 0.13.0: 1572 passed, 1 failed. The failure istest_pre_upgrade_candidates_exclude_the_current_binary, which fails because I put a second omnigraph binary onPATHto get 0.13 (this machine's default is 0.11, which can't parse the GQ 2.1inoperator from #488).prekpasses on the changed files.Not done yet: the manual check from the task. Kill a session right after its
pushedcheckpoint and confirm a new session that claims the task goes straight to opening the PR. That needs a human driving a live session.https://claude.ai/code/session_015nBsjMvN2iuLbUbCSFpsWT