Skip to content

feat(tasks): add subtask_progress to every vault_list_tasks entry - #536

Merged
aliasunder merged 3 commits into
mainfrom
worktree-list-tasks-subtask-progress
Sep 6, 2026
Merged

feat(tasks): add subtask_progress to every vault_list_tasks entry#536
aliasunder merged 3 commits into
mainfrom
worktree-list-tasks-subtask-progress

Conversation

@aliasunder

@aliasunder aliasunder commented Sep 5, 2026

Copy link
Copy Markdown
Owner

What

vault_list_tasks entries gain subtask_progress: { done, total } — the task's direct checklist children, aggregated in the same query.

  • Present only when the task has a checklist — an absent field means no checklist items, so leaf entries carry no extra weight on large filtered pages.
  • done counts children with status done only; a cancelled child counts toward total but not done (three abandoned stages should not read as progress).
  • Direct children only — a grandchild counts toward its own parent, matching how the Tasks and Kanban plugins render a card's checklist.
  • The counts ignore the query's filters: a filtered or top_level_only read still shows each card's full checklist progress, because progress is a property of the card, not of the query.

Why

A filtered or limited board read (folder + a due bound + limit, or top_level_only: true) could not see whether a card has a checklist or how far along it is: checklist items are separate depth-1 rows that either compete with real cards for result slots or disappear entirely, and the parent row said nothing about them.

How

One grouped self-join in listTasks (search-queries.ts): a LEFT JOIN on (note_path, parent_line) computing COUNT(*) and SUM(status = 'done') per parent. The group key is unique per parent, so the join never multiplies rows, and the aggregate subquery sits outside the outer WHERE by design. A partial index on tasks(note_path, parent_line) WHERE parent_line IS NOT NULL keeps the aggregate an index-only scan over child rows (EXPLAIN QUERY PLAN verified — no full-table hash aggregation). TaskRow/TaskEntry gain the fields, rowToTaskEntry maps the pair conditionally, and the tool description's Returns line documents the contract. ARCHITECTURE.md's task-query section gains the design bullet.

Tests

  • Unit (task-queries.test.ts): leaf → field omitted; mixed checklist (2 done, 1 todo, 1 cancelled) → {2,4} under the default not_done filter, which also fails if the aggregate ever inherits the query's filters (the done/cancelled children are excluded from the result rows there); grandchild counts toward its direct parent only; top_level_only rows carry the pair; direct rowToTaskEntry mapping test for non-zero counts.
  • Integration (server-integration.test.ts): fixture board card with a mixed-status checklist asserted over real HTTP — exact pair on the parent, and a "subtask_progress" in task guard on the parsed JSON proving the key is genuinely absent from leaf entries on the wire.
  • Mutation-checked: SUM(status = 'done')'cancelled' fails the cancelled-vs-done test; dropping the COALESCE fails the leaf test; forcing the field to always emit fails 8 tests.
  • Full suite: 3558 passed; the one failure is the pre-existing local-only OAuth DST test (passes on CI/UTC). Lint and build green.

Live validation

Exercised against a live test deployment of this branch (test_deploy.yml → the real instance) through a production MCP connector:

  • A real board card with one open checklist item returned { done: 0, total: 1 }; cards without checklists carried no subtask_progress key.
  • Full round-trip: created a card with 3 checklist stages → { done: 0, total: 3 }; completed one stage via vault_update_task{ done: 1, total: 3 } under the default not_done filter, with the completed child excluded from the result rows but still counted — filter-independence confirmed live.
  • Deletion semantics: removing a todo stage → {1,2}; removing the done stage → {0,1}; removing the last stage → field absent. Counts always reflect the current file with no staleness (server-side writes index synchronously).

🤖 Generated with Claude Code

Filtered or top_level_only board reads could not see whether a card has
a checklist or how far along it is. Every entry now carries
subtask_progress: { done, total } over its direct checklist children —
{ done: 0, total: 0 } means no checklist, done counts status done only,
and the counts ignore the query's filters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread src/vault-mcp/search/search-queries.ts
@umm-actually

umm-actually Bot commented Sep 5, 2026

Copy link
Copy Markdown

umm-actually re-reviewed at 6da58dc

No new findings (1 tracked finding(s) across all runs).

Context notes
  • Priority docs already in context: ARCHITECTURE.md

umm-actually · deepseek/deepseek-v4-flash-0731

A partial index on tasks(note_path, parent_line) WHERE parent_line IS
NOT NULL lets the grouped aggregate scan only child rows in GROUP BY
order instead of hash-aggregating the whole tasks table on every
listTasks call (EXPLAIN QUERY PLAN: temp B-tree eliminated).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aliasunder

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aliasunder

aliasunder commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review


🔍 ship-check · pr-monitor · claude-fable-5

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 5c8d8174-7a91-4cad-b6f9-b2042cb5f356

📥 Commits

Reviewing files that changed from the base of the PR and between bba2728 and dc73bd0.

📒 Files selected for processing (11)
  • ARCHITECTURE.md
  • src/__tests__/integration/fixtures/vault/Projects/board.md
  • src/__tests__/integration/server-integration.test.ts
  • src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts
  • src/vault-mcp/mcp-core/tools/task-tools.ts
  • src/vault-mcp/search/__tests__/search-helpers.test.ts
  • src/vault-mcp/search/__tests__/search-index.test.ts
  • src/vault-mcp/search/__tests__/task-queries.test.ts
  • src/vault-mcp/search/search-helpers.ts
  • src/vault-mcp/search/search-index.ts
  • src/vault-mcp/search/search-queries.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

vault_list_tasks now returns direct-child checklist progress for every task. The query aggregates completed and total children independently of filters. Types, row mapping, indexes, documentation, fixtures, unit tests, and integration tests reflect the new response field.

Changes

Task subtask progress

Layer / File(s) Summary
Progress result contract and query aggregation
src/vault-mcp/search/search-index.ts, src/vault-mcp/search/search-queries.ts
Task rows include aggregated child counts. Task entries expose subtask_progress. A partial parent-line index supports the grouped child query.
Task result mapping and tool contract
src/vault-mcp/search/search-helpers.ts, src/vault-mcp/mcp-core/tools/task-tools.ts
Row mapping returns subtask_progress. Tool documentation defines direct-child counting, cancellation, and filter semantics.
Progress behavior validation and documentation
src/vault-mcp/search/__tests__/*, src/vault-mcp/mcp-core/__tests__/*, src/__tests__/integration/*, ARCHITECTURE.md
Tests cover status counts, direct-parent scope, leaf tasks, filters, top-level results, and response shape. The fixture and architecture documentation reflect the new behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to dc73b

The task progress contract is implemented and covered across query, mapping, and tool layers with no actionable merge-blocking risk identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 9…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding subtask_progress to every vault_list_tasks entry.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-list-tasks-subtask-progress

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

@aliasunder: I will review the new changes in PR #536.

⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Present only when the task has direct checklist children — absence means
no checklist, exactly as unambiguous as { done: 0, total: 0 } while
saving the field on the majority of rows (most tasks are leaves), which
matters for LLM clients reading large filtered pages. Matches the wire
convention that metadata a task doesn't have is omitted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aliasunder

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Requesting an incremental review of 6da58dc — subtask_progress is now omitted for tasks without a checklist (previously always-present { done: 0, total: 0 }).


🔍 ship-check · pr-monitor · claude-fable-5

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit metadata and changed files ==='
git show --no-ext-diff --format=fuller --stat 6da58dc4
echo
echo '=== Commit patch ==='
git diff --no-ext-diff --find-renames 6da58dc4^ 6da58dc4 -- \
  ARCHITECTURE.md \
  src/vault-mcp/search/search-index.ts \
  src/vault-mcp/search/search-helpers.ts \
  src/vault-mcp/search/search-queries.ts \
  src/vault-mcp/search/__tests__/task-queries.test.ts \
  src/vault-mcp/search/__tests__/search-helpers.test.ts \
  src/vault-mcp/mcp-core/tools/task-tools.ts \
  src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts \
  src/__tests__/integration/server-integration.test.ts

echo
echo '=== Changed TypeScript file outlines ==='
git diff --name-only 6da58dc4^ 6da58dc4 -- '*.ts' |
while IFS= read -r file; do
  [ -z "$file" ] && continue
  echo "--- $file ---"
  ast-grep outline "$file" --items all || true
done

echo
echo '=== All subtask_progress references with context ==='
rg -n -C 4 '\bsubtask_progress\b|\bsubtask_done\b|\bsubtask_total\b' \
  src ARCHITECTURE.md

Length of output: 41881


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== vault_list_tasks registration and response construction ==='
ast-grep run --pattern 'registerTool($$$)' --lang typescript \
  src/vault-mcp/mcp-core/tools/task-tools.ts || true
rg -n -A80 -B12 '\bvault_list_tasks\b|listTasks\s*\(' \
  src/vault-mcp/mcp-core src/vault-mcp/search \
  -g '*.ts'

echo
echo '=== TaskEntry construction and consumption ==='
rg -n -C 5 '\bTaskEntry\b|rowToTaskEntry\s*\(' src -g '*.ts'

echo
echo '=== Output schema and JSON serialization sites ==='
rg -n -C 5 'JSON\.stringify|structuredContent|outputSchema|z\.object|serialize' \
  src/vault-mcp/mcp-core src -g '*.ts'

echo
echo '=== Remaining former-contract wording ==='
rg -n -i -C 2 \
  'subtask_progress.*every|every.*subtask_progress|progress.*every entry|no checklist.*\{ done: 0, total: 0 \}' \
  . -g '!node_modules/**' -g '!dist/**' -g '!build/**'

Length of output: 200963


@aliasunder I reviewed commit 6da58dc4.

I found no actionable issues. The optional TaskEntry.subtask_progress type, row mapping, JSON.stringify wire behavior, tool documentation, and integration test are consistent.

I did not run tests in the sandbox.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aliasunder
aliasunder merged commit 1147119 into main Sep 6, 2026
20 checks passed
@aliasunder
aliasunder deleted the worktree-list-tasks-subtask-progress branch September 6, 2026 00:19
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.

1 participant