Skip to content

Resolve a bundle's thread out of app_bundle_url - #301

Merged
robzolkos merged 1 commit into
mainfrom
fix/bundle-topic-id-fallback
Aug 24, 2026
Merged

Resolve a bundle's thread out of app_bundle_url#301
robzolkos merged 1 commit into
mainfrom
fix/bundle-topic-id-fallback

Conversation

@robzolkos

@robzolkosrobzolkos commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

A bundle posting's app_url names its sender's contact page, so resolvePostingTopicID always answered zero for one: hey box view --json served bundle rows with no topic_id, and nothing said how to reach the thread such a row opens. The skill meanwhile documented topic_id on every posting, so an agent following it into a bundle either got a missing field with no guidance or substituted the box item id — which hey threads answers with not_found.

haystack's bundle_posting route (config/routes.rb) points app_bundle_url at a topic exactly when the bundle holds one unseen thread — the thread the row opens in the web app. Several unseen threads get a bundle view of their own; none gets the contact page. So the URL fallback is faithful to what clicking the row does.

Code:mail.TopicIDOf resolves a posting's thread out of app_url, falling back to app_bundle_url. mail.NewPosting (the TUI's path) and resolvePostingTopicID in internal/cmd (every --json/styled/markdown listing) both use it, so a one-unseen-thread bundle now carries a usable topic_id everywhere. A bundle with several unseen threads, or none, still answers zero.

Skill: the Boxes section now says what a bundle row is (name is the -joined subjects), that topic_id can be absent on one, that a present one opens as that thread, and that the remedy for an absent one is hey contacts unbundle <contact_id> (contact in the posting's contacts) or the HEY app — never the box item id. The Threads ID note points at it.

AGENTS.md: the "a bundle's URL names a contact instead and answers zero" sentence now describes the fallback.

Supersedes the guidance half of #157, which documented this as a manual workaround for agents; resolving it in the CLI keeps the skill's contract true instead. Related: #156 remains the gap for bundles of several unseen threads — there is still no command that lists the topics inside one.

The two internal/tui calendar test failures (TestDayLabelsCoverTodosAndHabits, TestWeekDrawsTheHabitsKeptEachDay) pre-exist on main and are unrelated.


Summary by cubic

Resolve a bundle posting’s thread from app_bundle_url when app_url points to a contact, so bundle rows expose a usable topic_id where one exists. Previously we parsed only app_url, so bundles always returned topic_id = 0 and hey box view --json offered no way to reach the thread the row opens.

  • Add mail.TopicIDOf: returns TopicIDIn(app_url) or falls back to TopicIDIn(app_bundle_url). A bundle with one unseen thread now emits its thread ID; bundles with several unseen threads or none still return 0.
  • Use TopicIDOf in mail.NewPosting and internal/cmd’s resolvePostingTopicID, so CLI listings (--json/styled/markdown) and the TUI agree.
  • Tests cover URL precedence and bundle cases.
  • Update skills/hey/SKILL.md and AGENTS.md to explain bundle rows, that topic_id can be absent, and to use hey contacts unbundle <contact_id> rather than passing a box item id to hey threads.

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

Review in cubic

A bundle posting's app_url names its sender's contact page, so the
topic_id resolved out of it was always zero and hey box view --json
served bundle rows with no way to read the thread they open.
haystack's bundle_posting route points app_bundle_url at a topic exactly
when the bundle holds one unseen thread — the thread the row opens in
the web app. mail.TopicIDOf now tries app_url and falls back to
app_bundle_url, so those rows carry a usable topic_id in the CLI's
listings and the TUI alike. A bundle with several unseen threads (or
none) still answers zero, and the skill now says what a bundle row is,
that topic_id can be absent on one, and to reach the bundled mail
through hey contacts unbundle rather than passing the box item id to
hey threads.
Surfaced by #157, which documented the workaround; resolving it in the
CLI keeps the skill's contract (every posting names its thread where one
exists) true instead.
CopilotAI balanced review requested due to automatic review settings August 24, 2026 13:14
@robzolkos
robzolkos requested a review from a team as a code ownerAugust 24, 2026 13:14

CopilotAI 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.

Pull request overview

Resolves thread IDs for single-thread bundles via app_bundle_url, aligning CLI, TUI, and agent guidance.

Changes:

  • Adds shared bundle-aware topic ID resolution.
  • Tests URL precedence and bundle cases.
  • Documents bundle behavior and recovery options.

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.

Reviewed changes

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

Show a summary per file
FileDescription
internal/mail/posting.goAdds bundle-aware topic resolution.
internal/mail/posting_test.goCovers resolution scenarios.
internal/cmd/sdk.goReuses the shared resolver.
skills/hey/SKILL.mdExplains bundle IDs and alternatives.
AGENTS.mdUpdates architectural guidance.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@robzolkos
robzolkos merged commit 9ed1b43 into mainAug 24, 2026
24 checks passed
@robzolkos
robzolkos deleted the fix/bundle-topic-id-fallback branch August 24, 2026 14:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@robzolkos