Skip to content

aggregator: a REJECTED restore still cancels its target in card-state — dismissed/snoozed cards resurface even though the consumer refused the restore #1474

Closed

Description

@dezren39

aggregator: a REJECTED restore still cancels its target in card-state — the card resurfaces even though the consumer refused the restore

Summary

pm-stack/aggregator/src/card-state.ts derives each dashboard card's effective state at render time. Its documented contract (module header, lines 13–21) is that consumer rejections are non-effective: "A consumer REJECTION lifts the suppression again (the item resurfaces, with the rejection badge explaining why)." Every verb family honours that rule — snooze (:73), dismiss (:77), done (:79), answer (:86), ack (:92) all check state !== "rejected" — except restore. cancelledActionIds (:52–58) cancels the action named in a restore's supersedes for any restore whose state is merely not "superseded", so a restore the consumer rejected still cancels its target at render time.

Evidence (verified this run, main 7eca828)

Probe: the verbatim aggregator src/ tree (card-state.ts sha256 76f9f438…, identical on both sides) driven under Bun on the laptop, using the same mkAction fixture shape as test/dashboard-overhaul.test.ts:

control applied-dismiss + new restore:      suppressed=null       cancelled=da-dismiss  eff=da-restore
control applied-dismiss alone:              suppressed=dismissed  cancelled=            eff=da-dismiss
applied-dismiss + REJECTED restore:         suppressed=null       cancelled=da-dismiss  eff=da-restore   <-- BUG
future snooze + REJECTED restore:           suppressed=null       cancelled=da-snooze   eff=da-restore   <-- BUG
applied ack + REJECTED restore of ack:      acked=false           cancelled=da-ack                      <-- BUG

So with an applied dismiss in place and a restore that the consumer rejected (with a note, per actions.ts:43-44), the dashboard renders the card as restored — it leaves the hidden strip and returns to its main list — even though the restore never took effect. The same happens for a live snooze (card resurfaces before its until) and for an applied acknowledge (card loses its "seen, not resolved" quiet state).

Root cause: card-state.ts:54 —

if (a.verb === "restore" && a.state !== "superseded" && a.supersedes) out.add(a.supersedes);

state === "rejected" must also exclude a restore from cancelling, exactly as the other verbs are excluded. (A pending restore must keep cancelling — that is the verified control above and the committed test at dashboard-overhaul.test.ts:123.)

Why it matters

The dashboard is Drew's triage surface: a card that resurfaces reads as "this needs you again". A rejected restore (consumer could not apply it, e.g. the underlying object changed) silently resurrecting dismissed/snoozed items re-adds noise the user explicitly removed, and the rendered state disagrees with the store's applied truth — the exact class of divergence #1442/#1443 built this derivation layer to eliminate. No error is shown; the rejection badge logic never gets a chance to explain anything because the target action is filtered out of effectiveActions entirely.

Acceptance criteria

  • cardState([appliedDismiss, rejectedRestore(supersedes=dismiss)]) returns suppressed.kind === "dismissed"; the dismiss remains in effectiveActions.
  • Same for snooze (future until → still snoozed) and acknowledge (applied ack + rejected restore → acked === true).
  • Pending (new) and applied restores still cancel their target (existing test at dashboard-overhaul.test.ts:123 keeps passing).
  • New regression tests in pm-stack/aggregator/test/dashboard-overhaul.test.ts cover the rejected-restore cases, mirroring the existing rejected-dismiss test at :120.
  • Full aggregator test suite passes in CI.

Scope notes

Activity

  1. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 27, 2026
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator (lane A, new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-10-27 12:05 CDT
    • Found via: filed this run
    • Task: Filed after verification on main 7eca828 — verbatim pm-stack/aggregator/src tree (card-state.ts sha256 76f9f438, identical both sides) driven under Bun on the laptop: applied dismiss + REJECTED restore → suppressed=null (card resurfaces), future snooze + rejected restore → snooze cancelled, applied ack + rejected restore → acked=false; controls correct. Root cause: cancelledActionIds (card-state.ts:54) excludes only state "superseded", unlike every other verb's rejected check. Triage packet enqueued to repo-health-code-pilot.
    • Expectation: effort/s — one-condition fix in cancelledActionIds plus rejected-restore regression tests in dashboard-overhaul.test.ts; pending/applied restores must keep cancelling.
    • Links: packet hidden_files/packet-1474.json (goal workspace); probe hidden_files/probe-2026-10-27-laneA-restore/out.log
  4. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  5. 6 remaining items

  6. added
    status/parkedDeliberately paused with a recorded resume condition
    on Oct 28, 2026
  7. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  8. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up (resume)

  9. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 28, 2026
  10. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions