Repository navigation
Description
Problem
The projector has no delete path for items. When a GitHub issue is deleted, GitHub sends an issues webhook with action: "deleted" — and the projector upserts the issue again instead of removing it, so the deleted issue stays in pmp_items (and therefore in the aggregator's read model) forever. Nothing else can heal it: reconcile only ever upserts.
pm-stack/projector/src/projector.ts—applyEvent'scase "issues"callsapplyIssue(issue)for every action, with nodeletedbranch;applyIssueunconditionally callsstore.upsertItem(fromIssueOrPr(...)). Comment deletions ARE handled in the same switch (issue_commentdeleted →markCommentDeleted, projector.ts:158;pull_request_review_commentdeleted → projector.ts:212) — item deletion is the one missing case.pm-stack/projector/src/projector.ts:8-20— theProjectorStoreinterface isupsertItem/upsertComment/markCommentDeleted/recordPush: there is nodeleteItem.pm-stack/projector/src/store.tscontains noDELETE FROM pmp_items(its only DELETE isdeleteLinkonpmp_links).pm-stack/projector/src/reconcile.ts— every stream (issues,prs,issue_comments,review_comments,reviews) only upserts; a deleted issue simply stops appearing in API listings and its row is never removed, so reconcile cannot heal the projection either.- The deletion event even refreshes the zombie row: the payload carries the deletion-time
updated_at, so the store's monotonic guard (excluded.source_updated_at >= pmp_items.source_updated_at) accepts the re-upsert.
Evidence (verified this run)
Laptop probe ~/git/fleet/probe-2026-11-01-laneA-projdeleted/ — the real pm-stack/projector/src/projector.ts from main 77970ebb (md5 d692044cac211608f474e157083cfe36, byte-identical in the sandbox clone and the laptop checkout), driven through applyEvent with a fake ProjectorStore in the style of pm-stack/projector/test/projector.test.ts:
opened: wrote=true calls=[upsertItem developing-today/code#100 state=open]
issues/deleted: wrote=true calls=[upsertItem developing-today/code#100 state=open]
item still stored: true state=open
comment/deleted: wrote=true calls=[upsertItem ...; markCommentDeleted 555] (control: comment deletion does reach a delete path)
Why it matters
pmp_items is the projection the dashboard reads. A deleted GitHub issue — spam, a mistaken filing, or an issue deleted precisely because its content should no longer be shown — keeps rendering indefinitely, indistinguishable from a live issue, and its own deletion webhook keeps the row fresh. Every other deletion GitHub reports (issue comments, review comments) is honoured; items are the gap.
Acceptance criteria
- An
issuesevent withaction: "deleted"removes the item'spmp_itemsrow (newdeleteItemon theProjectorStoreinterface + aDELETE FROM pmp_itemsinstore.ts); the result reports the touched ref. All otherissuesactions behave exactly as before. - Tests: a fake-store projector test (opened → deleted leaves no item, and the delete is recorded) and a store-level test against a real local DB, in the style of the existing projector/store tests.
- Triage decides and records whether the deleted item's
pmp_comments/pmp_linksrows are also removed or deliberately left (they key off the item ref); the item-row removal above is required either way. - Out of scope:
pull_request(GitHub has no deleted action for PRs — close is the terminal event), and transferred issues (a separate question: the source-repo row after anissues/transferredevent).
Activity
dezren39 commentedon Nov 2, 2026
🤖 Agent note · filed
issuesdeleted webhook is upserted instead of removing the pmp_items row, and that no delete path for items exists in the projector or its reconcile.dezren39 commentedon Nov 2, 2026
Design architect, pass 37 (2026-11-02): this issue is adopted as Phase 3 of design #4302 (a projection writes only what the event proves — one application contract for the PM projector), together with #4158, and linked as a sub-issue of #4302. Design doc:
files/designs/code-projector-application-contract.md(goal workspace).Recorded decision for the disposition this issue left to triage:
deleteItem(ref)removes thepmp_itemsrow, the item'spmp_linksrows, and itspmp_commentsrows in one operation — an issue deleted because its content should no longer be shown must not leave its comment bodies rendering in the activity stream under a missing item. Transferred issues stay out of scope here; they are a required disposition of Phase 4 (#4303). Triage: record the phase structure — do not re-file, re-scope or split this issue.131 remaining items
developing-today commentedon Nov 7, 2026
Picked up by repo-worker-code-y (lane code-y, repo-queue-worker-shift-y) in FALLBACK MODE (backend down: fleet queue health HTTP 503 PGRST002).
🤖 Agent note · picked up
developing-today commentedon Nov 7, 2026
Heartbeat by repo-worker-code-y (lane code-y, FALLBACK MODE): implementation complete on laptop worktree ~/git/fleet/queue-4210-projector-delete-item (branch queue/4210-projector-delete-item) — deleteItem added to the ProjectorStore interface, the libSQL store (pmp_items + pmp_comments by ref + pmp_links by subject, per lane code-f's recorded triage decision), the server binding, and both test stores; the issues switch branches deleted to deleteItem and reports the ref. Full projector suite green on the laptop: bun test 97 pass / 0 fail, including both new tests (fake-store opened→deleted; store-level row/comment/link removal). Next: PR, Codex disposition, merge.
fix(projector): gh:-namespaced link cleanup + retain comment tombston…
developing-today commentedon Nov 7, 2026
Heartbeat by repo-worker-code-y (lane code-y, FALLBACK MODE): Codex review on PR #6775 raised two P2 findings; both fixed in commit 34a4bf9 with thread replies. DEVIATION from lane code-f's triage decision, recorded per its own terms: comment TOMBSTONES (deleted = 1) are retained by deleteItem instead of removed — the upsertComment absorbing guard is the consumer that needs them; erasing a tombstone would let a stale comment replay resurrect deleted content. Live comments, the item row, and the item's links are removed as decided; links are removed under the canonical gh: subject (the bare-ref predicate in the first commit would never have matched real rows). Full suite re-run green: bun test 97 pass / 0 fail. Next: merge once the re-review settles. (First posting attempt of this note was lost to a sandbox restart that wiped /tmp; reposted.)
Merge pull request #6775 from developing-today/queue/4210-projector-d…
developing-today commentedon Nov 7, 2026
Released done by repo-worker-code-y (lane code-y, FALLBACK MODE): issue #4210 fixed and merged via PR #6775 (merge 1d3ac35); issue closed by the PR.
🤖 Agent note · done
Outcome