Refuse to move a bundle row with hey move - #390
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 4 files
You’re at about 96% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
A bundle row shares the box item ID space with threads but stands in for one sender's whole stream in the box they are delivered to. Moving it takes the container away, so the sender's next email arrives unbundled. HEY's web app offers a bundle no move at all. hey move now checks each ID against the bundles/unseen route before moving anything and refuses a batch holding a bundle row, naming every one. The check lives beside bundleNotFound so one file owns the route. Fixes basecamp#388.
407d905 to
4b0db4a
Compare
|
Looked this over against main for the maintainers' side of the draft question. The client-side probe is the right shape for now: Pushed 4b0db4a to keep the branch mergeable: rebased onto main, which moved the README's command reference to @JoshAntBrown, if this still matches what you intended, could you mark it ready for review? If we don't hear back a maintainer may carry it from here. |
|
Hey, thanks for the look and the rebase - that all matches what I intended. |
There was a problem hiding this comment.
🟡 Changes recommended
The preflight currently fails open when the bundle endpoint returns a successful nil response.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Prevents hey move from relocating bundle rows and unintentionally unbundling future mail.
Changes:
- Adds concurrent bundle-row preflight checks.
- Rejects entire mixed batches and identifies offending IDs.
- Updates tests, command help, and CLI documentation.
[!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 summaries
| File | Description |
|---|---|
internal/cmd/move.go |
Rejects detected bundles before moving. |
internal/cmd/bundle.go |
Implements bounded bundle detection and errors. |
internal/cmd/move_test.go |
Tests probes, rejection, and help text. |
docs/cli.md |
Documents bundle move refusal. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
A success with no page cannot be read as "not a bundle": a move must not proceed on an answer it cannot classify. Matches readBundlePage and hey bundle view, which already refuse nil here. Unreachable with the current SDK, which allocates the page on every success, but the guard should not rest on that.
Fixes #388.
hey movetakes box item IDs, andhey box viewhands out two kinds under one ID space: threads, and bundle rows — a bundle stands in for one sender's whole stream in the box they are delivered to, and carries notopic_id. The move endpoint accepts either, so a bundle row moves like a thread, the command reports "1 thread moved", and the sender's next email arrives loose in the box the bundle just left. The reporter's batch of 31 IDs held 13 bundle rows; all 13 senders unbundled. HEY's own web app offers a bundle only Mark Seen, Note and Ignore, so the CLI was exposing a move the product withholds.hey movenow refuses a bundle row before moving anything. Each ID is checked against the bundles/unseen route — the discriminatorhey bundle viewand the thread-read fallback from #378 already rely on: it answers only for a bundle, a plain thread 404s, and a bundle read through still answers with its contact and no postings, so detection does not depend on unseen mail. A batch holding a bundle row is refused whole, naming every bundle ID, so the caller is never left guessing which of their IDs landed. The error points athey contact bundle|unbundlefor changing a sender's grouping; the long help, agent notes and README say why.No new flag. Since the web app offers no way to move a bundle at all, an override would invent an escape hatch HEY itself does not provide.
.surfaceis unchanged.The cost is one extra GET per ID, bounded at 8 concurrent. That is the cheapest check the current API allows: the client exposes no posting lookup and no batch read, so the only way to learn a posting's
kindfrom an ID is this route or paging the whole box. A server-side rejection inMovePostingswould make the probe unnecessary and cover every client; if that is the direction, this can be dropped — the error shape, help text and tests would still apply to interpreting the server's refusal. Opened as a draft on that basis.The check lives in
bundle.gobesidebundleNotFound, so one file owns the route.move_test.go's fake server now answers the bundles route, and its recorder is mutex-guarded for the concurrent probes; four tests cover the refusal, a mixed batch moving nothing, every bundle being named, and the help text. Verified against a live bundle before the test data was cleaned up: the refusal fires, a mixed batch moves nothing, normal threads are unaffected.TMPDIR=/tmp/t make checkgreen.Summary by cubic
hey movenow refuses bundle rows instead of treating them as threads, preventing a sender's stream from becoming unbundled when the row is moved. A batch containing any bundle row is rejected before the move request is sent.Bug Fixes
hey contact bundle|unbundle.Written for commit 1e825db. Summary will update on new commits.