Skip to content

feat(witan): checkpoint comments so a cut-off task run can resume - #492

Merged
blarghmatey merged 2 commits into
mainfrom
ia/witan-task-checkpoints
Oct 16, 2026
Merged

blarghmatey merged 2 commits into
mainfrom
ia/witan-task-checkpoints

Conversation

@blarghmatey

@blarghmatey blarghmatey commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

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

  • The skill's new "Checkpoint as you go" section has the holder post one task_comment per durable step (branch, change, validated, pushed, pr-opened, review-requested, blocked) as checkpoint <step>: <ref or exact command> | next: <action>. "Resuming from a checkpoint" has a claiming session fetch, check the last checkpoint against git and gh pr view, and resume from the first step live state does not confirm. Live state wins on disagreement.
  • The "New Comments on Work You Hold" block skips checkpoint comments 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 #session qualifier on the holder only (_is_holder in context.py), because an identity is free-form and may itself end in something qualifier-shaped. _held_by uses the same comparison. The holder string comes from the held task's assignee, 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.
  • The task_comment docstring 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/reference regenerated).

Two places where the skill differs from the spec. The spec's git branch -a --list '<branch>' only matches the local branch, because -a patterns match remote refs as origin/<branch>, so the skill uses --list '<branch>' 'origin/<branch>'. It also runs git 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.py cover 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-council against omnigraph 0.13.0: 1572 passed, 1 failed. The failure is test_pre_upgrade_candidates_exclude_the_current_binary, which fails because I put a second omnigraph binary on PATH to get 0.13 (this machine's default is 0.11, which can't parse the GQ 2.1 in operator from #488). prek passes on the changed files.

Not done yet: the manual check from the task. Kill a session right after its pushed checkpoint 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

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
Copilot AI balanced review requested due to automatic review settings October 15, 2026 20:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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.

Comment thread mcp/servers/witan/witan/context.py Outdated
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
@blarghmatey
blarghmatey merged commit 71863dc into main Oct 16, 2026
19 checks passed
@blarghmatey
blarghmatey deleted the ia/witan-task-checkpoints branch October 16, 2026 13:48
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>
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.

3 participants