Skip to content

Fix todos update silently clearing completion subscribers#540

Merged
jeremy merged 5 commits into
mainfrom
fix-todos-update-completion-subscribers
Jul 18, 2026
Merged

Fix todos update silently clearing completion subscribers#540
jeremy merged 5 commits into
mainfrom
fix-todos-update-completion-subscribers

Conversation

@jeremy

@jeremy jeremy commented Jul 18, 2026

Copy link
Copy Markdown
Member

Fixes #538.

Problem

Every basecamp todos update wiped the todo's completion subscribers ("When done, notify…"). The BC3 todos PUT has replace semantics — omitted field = cleared — and neither update branch included completion_subscriber_ids. The #412/#413 read-modify-write merge couldn't preserve them because the SDK's Todo model drops completion_subscribers in todoFromGenerated (basecamp/basecamp-sdk#355), so the merge had nothing to carry forward.

Fix

Preservation — a plain update now reads the current subscriber ids via a raw GET of the flat /todos/{id}.json route (which serves the field the SDK model drops) and carries them into the PUT, in both the typed-merge and raw-clear branches. The read fails closed: an HTTP error, malformed JSON, or a response missing the completion_subscribers key aborts before any PUT — the command never reaches the write without either explicit user intent or a verified read of current state. The completionSubscriberIDs helper is commented as temporary; it and both call sites go away once the SDK round-trips the field and the CLI collapses onto the SDK's merge-safe update.

Explicit control — subscribers become directly editable:

  • todos create --notify-on-completion <names or ids> and todos update --notify-on-completion <names or ids> set them (comma-separated, people-name tab completion)
  • todos update --no-notify-on-completion clears them (clearing works by omission; explicit intent skips the preservation read entirely)

Tests

  • Unit: the update mock transport now records ordered requests and serves the flat route configurably. Coverage: preservation of existing subscribers through title-only, due-only, and --no-due updates; flat-route assertion (no /buckets/ read); explicit set/clear with no preservation GET; a fail-closed matrix (missing key / malformed JSON / HTTP 500 × merge / clear branch) asserting no PUT occurs; flag-conflict usage error; completion_subscriber_ids in the create body.
  • Live smoke: new BATS scenario — create with subscriber → title-only update preserves → --no-due preserves → --no-notify-on-completion clears → trash. Not yet run against a live server (no QA credentials in the authoring session); needs a make smoke pass before this counts as runtime-verified.
  • bin/ci fully green (fmt, vet, lint, unit, replay e2e, naming, surface, skill drift, bare groups, smoke coverage, provenance, tidy).

Bookkeeping


Summary by cubic

Stops basecamp todos update from wiping "When done, notify…" subscribers. Preserves existing subscribers and adds flags to set or clear them explicitly.

  • Bug Fixes

    • Preserve subscribers by reading completion_subscribers from /todos/{id}.json and sending completion_subscriber_ids in PUTs (both merge and clear paths).
    • Fail closed: abort on read errors, missing/malformed responses, or any subscriber with a missing/invalid id; no PUT on failure.
    • Read errors pass through convertSDKError to keep structured SDK codes/hints.
    • Use completion‑subscriber wording in --notify-on-completion errors; person resolution is parameterized so messages reference subscribers, not assignees.
    • Tests: cover name‑resolution failures, exact flat route usage, explicit set/clear skipping the read, and preservation in both branches.
  • New Features

    • todos create --notify-on-completion <names|ids> and todos update --notify-on-completion <names|ids> set subscribers (with people‑name completion).
    • todos update --no-notify-on-completion clears subscribers; explicit set/clear skips the preservation read.
    • Docs updated and flags added in .surface.

Written for commit de1f3c4. Summary will update on new commits.

Review in cubic

The BC3 todos PUT has replace semantics: any field omitted from the body
is cleared. Neither branch of todos update included
completion_subscriber_ids, so every update wiped the todo's "When done,
notify" list. The #412/#413 read-modify-write merge couldn't preserve it
because the SDK's Todo model drops completion_subscribers in
todoFromGenerated (basecamp/basecamp-sdk#355) — the merge had nothing to
carry forward.

Preservation now works via a raw GET of the flat /todos/{id}.json route
(which serves the field the SDK model drops), feeding the current
subscriber ids into both the typed-merge and raw-clear PUT paths. The
read fails closed: an HTTP error, malformed JSON, or a response missing
the completion_subscribers key aborts the command before any PUT rather
than risking a silent clear. The helper is commented as temporary and
goes away once the SDK round-trips the field.

Alongside the fix, subscribers become directly editable:

- todos create/update --notify-on-completion <names or ids> sets them
  (comma-separated, with people-name tab completion)
- todos update --no-notify-on-completion clears them (by omission —
  explicit intent skips the preservation read entirely)

Unit tests cover preservation in both branches, the flat-route
assertion, explicit set/clear bypassing the read, the fail-closed
matrix (missing key / malformed JSON / HTTP 500 in each branch), flag
conflicts, and the create body. A live smoke test exercises the full
sequence: create with subscriber, title-only update preserves, --no-due
preserves, --no-notify-on-completion clears.

.surface gains the three new flag records by hand (verified identical
to fresh generation); a full regeneration is deferred because the
snapshot has unrelated drift since #499 changed the generator script.
Copilot AI review requested due to automatic review settings July 18, 2026 01:04
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) skills Agent skills bug Something isn't working labels Jul 18, 2026

Copilot AI 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.

Pull request overview

Fixes basecamp todos update unintentionally clearing “When done, notify…” completion subscribers by preserving existing subscriber IDs across updates (despite the current SDK model dropping completion_subscribers), and adds explicit flags to set/clear them.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Changes:

  • Preserve completion subscribers on update by reading /todos/{id}.json and carrying completion_subscriber_ids into the PUT (fail-closed on read/parse/missing-key).
  • Add --notify-on-completion (create/update) and --no-notify-on-completion (update) for explicit subscriber control.
  • Extend unit tests + smoke coverage and document the new flags in the skill docs and .surface.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
skills/basecamp/SKILL.md Documents new completion-subscriber flags and preservation behavior.
internal/commands/todos.go Implements preservation read + new flags for setting/clearing completion subscribers.
internal/commands/todos_test.go Adds unit coverage for preservation, explicit set/clear, and fail-closed behavior.
e2e/smoke/smoke_todos_write.bats Adds a smoke scenario exercising preserve + clear behavior end-to-end.
.surface Records the new CLI flags for drift/surface tooling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/todos.go
Comment thread internal/commands/todos.go
Comment thread internal/commands/todos.go

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/commands/todos.go Outdated
--notify-on-completion resolved people through resolveAssigneeIDs, so
failures surfaced as assignee errors ("No valid assignees provided",
"Assignee ID must be a positive number") — misleading for a flag that
sets completion subscribers.

Parameterize the resolver with a role label: resolvePersonRoleID(s)
carry the wording, and resolveAssigneeID(s) stay as assignee-labeled
wrappers so existing call sites and messages are unchanged. The
subscriber call sites now go through resolveCompletionSubscriberIDs.

Tests cover both subscriber-worded messages and assert no PUT occurs
on resolution failure.
Copilot AI review requested due to automatic review settings July 18, 2026 05:02

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/commands/todos_test.go
The subscriber-wording tests covered the numeric-validation and
empty-list errors but not the ResolvePerson miss, so the "failed to
resolve completion subscriber" formatting was only exercised indirectly.

The update mock now matches the flat preservation route exactly
(/todos/999.json) instead of any .json GET, and serves /people routes an
empty directory so name resolution deterministically misses. New subtest
asserts the subscriber-worded resolve error and that no PUT occurs. The
explicit set/clear tests tighten their no-preservation-read assertions
to the exact route.
Copilot AI review requested due to automatic review settings July 18, 2026 06:02

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread internal/commands/todos.go
Comment thread internal/commands/todos_test.go Outdated
The preservation read's GET error now runs through convertSDKError
before wrapping, so structured codes/hints (rate limit, circuit
breaker) survive with the subscriber-specific context — matching every
other raw Account() call site.

The update mock's preservation branch now matches the account-scoped
flat route exactly (/99999/todos/999.json) instead of by suffix, so a
bucket-scoped GET can never satisfy it.
Copilot AI review requested due to automatic review settings July 18, 2026 06:18

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/todos.go
A completion_subscribers element without a positive id would have put a
zero into completion_subscriber_ids and reached the PUT, slipping past
the fail-closed contract. The preservation read now errors on any
non-positive id, and the fail-closed test matrix covers the case.
Copilot AI review requested due to automatic review settings July 18, 2026 06:29

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@jeremy
jeremy merged commit 51c3493 into main Jul 18, 2026
27 checks passed
@jeremy
jeremy deleted the fix-todos-update-completion-subscribers branch July 18, 2026 06:37
@jeremy jeremy added this to the v0.8.0 milestone Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working commands CLI command implementations skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

todos update silently clears completion subscribers (merge misses the field the SDK can't see)

2 participants