Skip to content

feat: acknowledge a fired schedule occurrence without finishing it (TASK-4536) - #2521

Merged
xarmian merged 19 commits into
mainfrom
rook/TASK-4536
Nov 13, 2026
Merged

xarmian merged 19 commits into
mainfrom
rook/TASK-4536

Conversation

@xarmian

@xarmian xarmian commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

Adds an acknowledged state for a fired schedule occurrence: "seen, still owed". Until now an occurrence could only be resolved as done, skip, snooze or move, so someone who had seen an alert but not finished the work had to mark it done, which ended a one-shot and showed the work as finished.

Behaviour

  • pad remind ack <ref> [--occurrence <RFC3339>] (also pad item remind ack), POST .../commitment/resolve with {"occurrence_at": ..., "state": "ack"}, and MCP pad_item schedule-resolve with state: "ack".
  • Only a fired, current occurrence can be acknowledged (409 not_fired before it fires, 409 stale once resolved). A repeat ack is a no-op that keeps the first timestamp.
  • Acknowledging silences the occurrence: it leaves pending reminders, project next/ready (including the ranked fallback), the needs-you due claim, and queued or claimed push notifications for that occurrence (cancelled in the same transaction). Pushes already delivered and webhook events already emitted stand.
  • The work stays owed: every agenda, Outstanding, bootstrap and calendar read keeps the entry with state: "acknowledged", acknowledged_at and acknowledged_by (who acknowledged it, user or agent). Overdue, missed and carried accounting are unchanged.
  • Ack never advances recurrence, ends a one-shot, opens gates or records completion. Done, skip, snooze and move keep their meaning; snooze and move clear the acknowledgement; a configured lapses deadline still closes the occurrence.
  • Any editor of the item may acknowledge, for every recipient. Hidden and missing items return identical 404s.
  • pad item ack still refuses schedule-managed reminders and now points at pad remind ack.
  • Export and import keep the acknowledgement; copies arm fresh, as before.

Schema

schedule_changes.change_type gains ack (SQLite migration 179 rebuilds the table, keeping rows, indexes and NUL triggers; Postgres migration 140 replaces the CHECK).

Web

Agenda and Outstanding offer Acknowledge on fired entries, show acknowledged entries as open work with an "Acknowledged" chip and an "Acknowledged by … · time" line, and keep Done, Skip, Snooze and Move. An agenda state the page does not recognise now renders a neutral chip instead of failing.

MCP

ToolSurfaceVersion 0.114 → 0.115; wire goldens regenerated.

Cover acknowledgement lifecycle, identity, concurrency, migrations, agenda projections, delivery cancellation, CLI selection, and MCP transport behavior.
… work

Preserve the current occurrence and date roles while journaling acknowledgement provenance, cancelling queued pushes, and projecting acknowledged work with batched account names. Carry delivery marks through workspace bundles and retain fresh arming for item copies.
Accept fired-only acknowledgement with strict field errors and idempotent activity. Include current-occurrence attribution in commitment and agenda projections, suppress ordinary next suggestions, and rebuild push metadata after held rows are pruned.
Add remind ack and its item alias with explicit occurrence selection, managed-reminder guidance, and acknowledgement details in agenda output. Preserve structured refusal details when adding stale-occurrence guidance.
Accept fired occurrence acknowledgement through both transports with matching validation and refusal codes. Advertise tool surface 0.115 and refresh the pinned wire contract.
…a neutral chip

Updates the tool surface version references, tidies unused test assignments, and renders an agenda entry whose state the web does not know as a neutral chip instead of indexing the state table.
Give acknowledged its own row in the occurrence state table and restore
the exhaustive type guard over the table. Shared predicates (resolve,
chips, attention keys, day and strip owed counts, deadline and forecast
markers, rail occurrences) treat acknowledged as open wherever
outstanding is. Calendar entries name who acknowledged and when.
Offer Acknowledge on a fired, outstanding occurrence in agenda rows (a
button on desktop, the first menu item on a phone) and in the Outstanding
panel. The page resolves it as ack, refreshes, and says the work stays
outstanding; a stale or not-fired refusal refreshes and explains without
retrying. Acknowledged rows keep Done, Skip, Snooze and Move and show who
acknowledged them and when.
… hint

The initialize instructions now say acknowledgement keeps work owed. The managed reminder refusal names pad remind ack alongside the resolve route.
…ligned

An imported acknowledgement keeps its actor_user_id only when that user is a member of the destination workspace. The acknowledgement time is read from the reminder row, so it shows even without a journal row. The CLI agenda puts the attribution in the last column instead of flushing the table mid-row, and the ack hint falls back to the item slug when the item has no number.
…ned occurrences by instant

A linked move that puts an acknowledged occurrence's target in the past now leaves its fired, acknowledged reminder in place, like any fired reminder, instead of deleting it, so the moved occurrence stays quiet and can still be acknowledged. The agenda page compares a pinned occurrence's instant as well as its wall time before resolving, so two occurrences sharing a wall time in a DST fall-back hour are not confused.
Imported acknowledgement journal rows are decoded through the same struct the agenda reader uses, which matches keys without regard to case, so a differently cased actor key is checked like the canonical one. Both before and after JSON are rewritten in canonical form, the actor user is kept only for a member of the destination workspace, the agent name is normalized as on the live path, and the row actor is limited to user or agent.
Imported acknowledgement journal rows keep their actor kind and normalized agent name but drop actor_user_id, as imported verifications store no user, so a bundle cannot attribute an acknowledgement to any account, member or not. Documents this and the past linked move behaviour.
…uted

The acknowledgement reader scanned after_json and actor into plain strings, so a NULL in either (an imported row may carry none) failed the schedule read, the agenda and bootstrap for the workspace. Both are now coalesced to empty, which reads as acknowledged with no attribution.
The JSON decoder matches member names without regard to case, so an ack request carrying Comment or Actual_Done_At was decoded but not refused. The ack combination check now treats a member as present when any key matches it ignoring case or when the decoder filled it.
@xarmian
xarmian merged commit 6e65700 into main Nov 13, 2026
15 checks passed
@xarmian
xarmian deleted the rook/TASK-4536 branch November 13, 2026 19:30
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