Skip to content

review --since filters by feature status before intersecting with the diff, silently skipping changed code #167

Description

@youhaowei

Summary

clawpatch review --since <base> is documented as reviewing what changed since a base ref, and it is a natural fit for a pre-push or CI gate. But selection applies the status filter first and the changed-files filter second, so any feature not currently in pending or error is dropped before the diff is consulted — even when the diff modifies files that feature owns.

The result is that a review of changed code can complete successfully having reviewed none of it, and exit 0.

Where it happens

review.js:398-400:

const candidates = selectReviewCandidates(features, flags);          // status filter
const sinceFiltered = await filterFeaturesByFilesSince(loaded.root, candidates, flags);  // diff filter
return limitFeatures(sinceFiltered, flags);

selection.js:5-7:

const selected = featureId === undefined
    ? projectFeatures.filter((feature) => ["pending", "error"].includes(feature.status))
    : projectFeatures.filter((feature) => feature.featureId === featureId);

So reviewed, needs-fix, fixed, skipped, and claimed features are never candidates for a --since run, regardless of what the diff touches.

When the intersection ends up empty, review.js:27-36 returns {"next": "no features touched by diff"} — which reads as "your change touched nothing interesting" but actually means "everything your change touched was filtered out by status."

Why this matters

The status filter is sensible for the backlog workflow it was written for: clawpatch review with no diff scope should work through features that still need attention, and skipping already-reviewed ones is right. But --since expresses a different question — "review this change" — and for that question a feature's prior status is not a reason to skip it. A feature reviewed last month, then modified today, is exactly what a gate needs to look at.

The failure is silent and self-reinforcing. The more a repo uses clawpatch, the more features leave pending, so coverage decreases over time. On our repo:

total features                 490
eligible (pending|error)       237
silently skipped               253  (52%)

Over half the map cannot be selected by any --since run. In practice this meant a security-fix branch passed our gate with {"next": "no features touched by diff"} and exit 0, while the same diff resolves to nine owning features.

Reproduction

  1. clawpatch map
  2. clawpatch review --feature <id> on some feature, so it leaves pending (any terminal status works).
  3. Modify a file that feature owns, and commit.
  4. clawpatch review --since <base> — the feature is not reviewed, and if it was the only one touched, the command reports no features touched by diff and exits 0.

Suggested fix

Make the diff filter authoritative when a file filter is present — i.e. when hasFileFilter(flags) is true (review.js:421-423), select by changed files and skip the status narrowing:

const scoped = hasFileFilter(flags);
const candidates = scoped
    ? filterFeaturesByProject(features, stringFlag(flags, "project"))
    : selectReviewCandidates(features, flags);

If changing the default is too disruptive, an explicit opt-out (--ignore-status, or --all-statuses) would be enough — the important part is that a gate can ask "review everything this diff touches" and get exactly that.

A smaller, separate improvement: distinguish the two ways the result set empties. "No feature owns any changed file" and "every owning feature was filtered out by status" are very different messages to a user, and today both print no features touched by diff.

Environment

clawpatch 0.7.1 (latest at time of filing), macOS, node global install.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Urgent regression or broken agent/channel workflow affecting real users now.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.no-staleExempts this issue from stale automation.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions