Repository navigation
Fail when Basecamp drops a requested assignee - #981
Merged
Merged
Conversation
Basecamp ignores an assignee_ids entry it cannot assign on the recording, such as a card column's ID or a person outside the project, and saves the rest. `cards create --to <column id>` therefore exited 0 with an unassigned card, and `cards update --assignee <bad id>` cleared the card's real assignees just as quietly. Every command that sets assignees now compares what it asked for with the assignees on the record Basecamp returns, and fails with a usage error naming the record, the dropped IDs and what the record was saved with. The check needs no extra request, and it uses the server's own answer, which no client-side person lookup could reproduce: bc3 filters through reachable_people(include_admissible_people: true). cards create's --to help now says it is the person to assign, and that the column is --column.
`assign A B --to <person>` exits 0 when it assigns some of the items, by design, and --agent prints only the data. An item Basecamp dropped the person from, or any other item that failed, was therefore invisible there. The batch now carries a diagnostic naming each failed item and why, which quiet mode writes to stderr.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Recovery hints omit the required project and can overwrite successfully saved subtask assignees, causing recovery to fail or remove existing assignments.
2 open issues
What changed in this PR
This PR checks saved assignees against requested IDs so CLI commands report when Basecamp silently drops an assignment, without additional API requests.
Changes:
- Add post-write checks across 11 assignment paths for to-dos, cards, steps, and subtasks.
- Surface partial-batch failures in quiet/agent output and clarify
cards create --tohelp. - Add dropped/retained-assignee tests and update mock responses to echo assignments.
[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or rungh pr ready --undo.
Click "Ready for review" or rungh pr readyto reengage.
| File | Description |
|---|---|
| internal/commands/todos.go | Check assignees after creating or updating to-dos. |
| internal/commands/subtasks.go | Check assignees after creating or updating subtasks. |
| internal/commands/subtasks_test.go | Echo saved assignees in the creation fixture. |
| internal/commands/cards.go | Check card and step assignments; clarify assignee help. |
| internal/commands/cards_test.go | Echo assignees in step-update responses. |
| internal/commands/assignees_saved_test.go | Test dropped and retained assignments, batch diagnostics, and error details. |
| internal/commands/assign.go | Add shared validation, recovery hints, and batch diagnostics. |
| internal/commands/assign_test.go | Echo assignees in step-assignment responses. |
Review effort: Balanced
Following the subtask hint would have replaced the assignees the subtask kept, since subtasks update replaces the whole set, so the hint now lists them before <person>. The assign hints name --project, which assign needs when no default project is configured.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

basecamp cards create … --to <column id>exited 0 and created an unassigned card. Oncards create,--tois the assignee, and Basecamp answers success while silently dropping anyassignee_idsentry it can't assign on that recording. Every command that sets assignees had the same hole, andcards update/todos updatewere worse: they replace the set, so a bad ID cleared the real assignees too.What bc3 does (measured against local bc3)
cards create --to <column id>cards create --assignee <account person not on project>cards update --assignee <column id>on a card assigned to DHHcards step create,todos create/update,subtasks create,assign(to-do, card)bc3 filters every assignee write through
recording.reachable_people(include_admissible_people: true): project members, clients when the recording is visible to them, agents, and any admissible employee on an all-access project. Ids outside that set are ignored, not rejected.The fix
Each write compares the IDs it sent with the assignees on the record Basecamp returns. Missing ones fail with a usage error that names the record, the dropped IDs and what it was saved with, and a hint that assigns that record (so an agent doesn't create a second one):
Why check after the write rather than validate before it: no client-side lookup can reproduce bc3's rule.
/people.jsonpasses a person who isn't on the project (measured: dropped), and the project's people list would reject admissible people on an all-access project that bc3 accepts. The response is the authority, and reading it costs no extra request. The record exists by the time we fail; that matches the existingcard %d created but assignment failedpath incards create.Covered:
cards create,cards update,cards step create/update,todos create/update,subtasks create/update,assign(to-do,--card,--step).unassigncan't drop an ID and is untouched; the TUI picks from a people list and is out of scope. Name and email resolution is unchanged.The second commit covers a mixed
assign A Bbatch, where the person is kept on A and dropped on B. Partial batches still exit 0, which is the tested contract, but--agentprints only data, so B's failure was invisible. The batch now carries a diagnostic naming each failed item and why; quiet/agent mode writes it to stderr.cards create --tostays as is. Its help now reads "Person to assign (alias for --assignee); the column is --column", sincecards move --tois a column.Verification
TestAssigneeWritesFailWhenBasecampDropsTheAssigneedrives all 11 write paths against a mock that drops the ID; all 11 failed before the fix.TestAssigneeWritesSucceedWhenBasecampKeepsTheAssigneeis the paired control. Three existing fixtures answered writes without the assignees they were sent; they now echo them, as bc3 does.20261027-235034-assignee-droppedbefore/after,20261027-235248-assignee-keptfor all 11 paths with valid people,20261027-235440-assign-batch-mixed). Created records trashed.bin/cigreen.Summary by cubic
Commands that assign people now fail when Basecamp silently drops a requested assignee, instead of exiting 0 with an unassigned or de-assigned record.
cards create --to, or a person not on the project, now produce a usage error naming the record, the dropped IDs, and what the record was saved with.cards update/todos updatepreviously replaced the assignee set, so a bad ID also cleared the real assignees; that is now caught too.cards create/update,cards step create/update,todos create/update,subtasks create/update, andassign(to-do, card, step).assignbatches still exit 0, but under--agent/--quietthey now write a diagnostic to stderr naming each item that dropped the assignee.--projectflag, whichassignrequires.Written for commit 614dec9. Summary will update on new commits.