Skip to content

feat(store,api): hard-delete a feature alongside cancel — the tombstone edge (v0.23.0) - #55

Merged
mabry1985 merged 1 commit into
mainfrom
feat/hard-delete-feature
Jun 21, 2026
Merged

feat(store,api): hard-delete a feature alongside cancel — the tombstone edge (v0.23.0)#55
mabry1985 merged 1 commit into
mainfrom
feat/hard-delete-feature

Conversation

@mabry1985

Copy link
Copy Markdown
Member

Follow-up to #47

#47 shipped cancel-with-audit (br close -r + a cancelled lane). The issue's proposed direction was an and/or — cancel and/or a hard delete — with an open question for the maintainer about which the intent was. Rather than bake one in, this adds the hard-delete sibling so the operator chooses per-case.

What

  • store.delete_feature(fid, reason)br delete --reason "deleted: …" — a tombstone in the JSONL (recoverable, not a history nuke), run through the board so board ↔ JSONL stay in step (vs the raw br reach-around the issue warned desyncs the board). Refuses (BoardError, via br's non-zero exit) when the feature has dependents — deleting would orphan them; cancel or re-point first. Returns the pre-delete snapshot as the API echo.
  • DELETE /features/{fid} — the route the issue proposed; reason optional (body or none).

cancel vs delete

  • cancel (default, recommended) — keeps a visible, reopenable cancelled lane; full audit trail.
  • delete — for a feature that should leave no trace on the board (a pure mistake/duplicate). Still a recoverable tombstone, still dependent-guarded.

Verification

  • Against real br 0.1.23: br delete --reason tombstones (removed from br list), and a feature with a dependent is refused ("Use --force to orphan… No changes made") → surfaces as a 400, not a silent orphan.
  • Tests: delete_feature (tombstone + reason, unknown-id raises) and DELETE …/features/{fid} (with + without a body).
  • Full suite: 193 passed; ruff check + ruff format --check clean.

Ref #47

🤖 Generated with Claude Code

…ne edge (v0.23.0)

Follow-up to #47: that shipped cancel-with-audit (close + `cancelled` lane); this adds
the hard-delete sibling the issue's "and/or" also called for, so the operator chooses
per-case instead of the maintainer baking one in.

  • store.delete_feature(fid, reason) → `br delete --reason "deleted: …"` — a tombstone
    in the JSONL (recoverable), run THROUGH the board so board ↔ JSONL stay in step
    (vs the raw `br` reach-around the issue warned desyncs the board). Refuses via `br`'s
    non-zero exit when the feature has dependents (deleting would orphan them) — cancel
    or re-point first. Returns the pre-delete snapshot for the API echo.
  • DELETE /features/{fid} (the route the issue proposed; reason optional, body or none).

cancel stays the recommended default (visible, reopenable audit lane); delete is for a
feature that should leave no trace. Verified `br delete` tombstones + the dependent
guard against real `br` 0.1.23; unit-tested both methods + the route.

Ref #47

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@protoquinn

protoquinn Bot commented Jun 21, 2026

Copy link
Copy Markdown

👀 Quinn is reviewing — verdict (PASS / WARN / FAIL) + findings to follow.

@mabry1985
mabry1985 merged commit 3e9bbe7 into main Jun 21, 2026
1 check passed
@mabry1985
mabry1985 deleted the feat/hard-delete-feature branch June 21, 2026 18:23

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

QA Audit — PR #55 | feat(store,api): hard-delete a feature alongside cancel — the tombstone edge (v0.23.0)

VERDICT: WARN (non-blocking — CI is still queued; upgrade to PASS once terminal-green)


CI Status

  • test: queued

Diff Review

  • Adds store.delete_feature(fid, reason) mirroring cancel_feature — captures pre-delete snapshot via _require, tombstones via br delete --reason, returns the snapshot as API echo. Correctly captures before the operation (unlike cancel which re-fetches after) since the tombstoned feature would be unfetchable post-delete.
  • New DELETE /features/{fid} route following the identical _guard + Body(default={}) pattern as the cancel route — clean and consistent.
  • Version bumps (0.22.0 → 0.23.0) in both pyproject.toml and protoagent.plugin.yaml are in sync.
  • 193 tests passing; ruff check + ruff format --check clean per PR description.

Observations

  • LOW: clawpatch_review not available for this repo (not in project registry) — structural review skipped. Manual diff review shows no cross-file hazards given the small, pattern-following change.
  • LOW: test_delete_route_calls_delete_feature asserts 200 + store call but doesn't inspect the response body for the pre-delete snapshot echo. The store-level test covers this — non-blocking.
  • No unresolved CodeRabbit threads.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jun 21, 2026

Copy link
Copy Markdown

Submitted COMMENT review on #55.

Summary: Clean, pattern-following change — delete_feature mirrors cancel_feature with the correct pre-delete snapshot capture. CI is still queued so this is a non-blocking WARN; the merge loop will re-dispatch for a formal PASS once test completes terminal-green.

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