镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(bestie): open Bestie DM links in the Bestie nav at the linked message - #2775

Open
matt2e wants to merge 9 commits into
mainfrom
links-to-bestie-dm-dont-open-bestie-top-level-nav
Open

matt2e wants to merge 9 commits into
mainfrom
links-to-bestie-dm-dont-open-bestie-top-level-nav

Conversation

@matt2e

@matt2e matt2e commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

What

The In DM · <Bestie name> link at the top of a Bestie DM thread, such as one opened from Activity, now opens the Bestie page. The thread opens in Bestie's thread pane, and the chat history scrolls to the thread's root message with a brief highlight. Before this change the link opened Messages, which hides the promoted Bestie DM from its sidebar.

Before / after

Left: f9ce9dfc4 lands in Messages, whose sidebar lists no row for the Bestie DM; right: e6d86f54e opens the Bestie page with the thread on the right and the root message highlighted.

bestie-linkback-before-after.mp4

Cause

Every link to a DM, a thread or a message opened Messages. Nothing routed links into the promoted Bestie DM to the Bestie page.

Fix

  • Handoff to Bestie. When Messages starts presenting a pending visit to the promoted Bestie DM or one of its threads, it hands the visit to the Bestie page before drawing it. The visit keeps its history entry. A thread visit opens in Bestie's thread pane under the thread placement preference. Messages hands off only its own pending visit, not a settled visit kept on screen under Settings (ChannelsPage.tsx, bestie/routes.ts).
  • Root reveal. Bestie reuses Messages' message opening (useMessageOpening and the timeline's inlineTarget reveal). It reads older history until the root loads, then scrolls to the root and highlights it. The root is the one the thread pane verifies, so a buzz:// link whose thread hint names an unrelated message reveals the reply's real root, not the hint.
    • For a thread visit, the chat stays on screen and usable while Bestie looks for the root.
    • The reveal happens once, on the first presentation of a handed-off visit. It doesn't happen for Bestie's own View thread, including View thread activated again on the thread already shown, or for Back/Forward, and it stops if the reader scrolls the chat or sends from the main composer first.
    • The thread pane keeps keyboard focus.
  • Single-message route. A link to a single message in the Bestie DM opens the Bestie page scrolled to that message when it is a top-level message in history. This covers notifications, ⌘K results and buzz:// links without a thread. A reply, or a message that isn't found, opens as its thread, as in Messages. Back/Forward to such a visit returns to the reply's thread or the chat, without revealing the message again. This holds even when the reader left before history answered or reloaded the app.
  • Other entry points fixed by the same path: Activity's "Open in channel", notifications for thread replies, buzz:// thread permalinks, choosing the Bestie DM from a channel result in search, and Back/Forward to an older visit of the DM or its threads.
  • Unchanged: other DMs and channels; Forward and Members, which have no Bestie route and stay in Messages; and a visit Messages had already opened before the promotion was known.

Shared-code changes

Each change is additive or opt-in for existing callers:

  • ChannelTimeline: an onReaderIntent callback, fired only by real wheel, touch, key and pointer input on the history. Its inlineTarget.focus type widens from false to boolean. The thread pane keeps focus through the timeline's existing useMessageReveal support for marking an arrival without focusing it. This PR doesn't change useMessageReveal.
  • Navigation history: the dismiss predicate also receives each visit's id. Closing a thread then retires the visits recorded for it, however they were addressed.
  • Bestie provider: BestieNavigationProvider memoizes its value, so channel-list churn no longer re-renders Messages while a Bestie is promoted. useBestieConversation no longer matches a missing session when no Bestie provider is mounted.

docs/buzz-help.md, docs/navigation-history.md and src/bundled/bestie/README.md are updated.

Validation

  • Vitest: 72 files, 1,744 tests, all passing. They cover Bestie, ChannelsPage, the shell, channel navigation, Inbox/Activity, the timeline, the reveal hook and navigation history. The new tests fail without the fix.
  • Static checks: tsc --noEmit and biome are clean.
  • Real browser: headless Chromium at 1440×900 against tests/browser/fixture.mjs, with the same seed and the same flow on both commits: Activity → the Bestie's reply → open its thread ("1 reply") → "In DM · Jitter". The run had no console errors. This produced the video above.
  • No browser journeys were added or removed.

Known limits

  • Not checked against a real account. Dev builds can't sign in to the production relay. It requires an organization sign-in token (requires_nip_fi) that browser-host/relay-broker.mjs doesn't send. The fix was checked on the fixture relay in real Chromium instead.
  • One no-op Back stop. Reopening the Bestie place already on screen from search or a notification leaves one Back stop that does nothing. Those callers open links themselves, so there's no single place to intercept them.
  • Handed-off entries stay Bestie visits. A history entry Messages handed to Bestie becomes Bestie's address. If the Bestie plugin is later disabled or the Bestie changes, Back treats that entry like Bestie's own thread visits instead of reopening it in Messages. This is documented in src/bundled/bestie/README.md.

🤖 Generated with Claude Code

@matt2e
matt2e marked this pull request as ready for review November 6, 2026 09:26
@matt2e
matt2e requested a review from a team as a code owner November 6, 2026 09:26
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch 2 times, most recently from 5c9e1c3 to e72ff49 Compare November 6, 2026 12:39

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot coverage.

Reviewed head e72ff49de9248a0bfb723780ed9792ec5cdb2f20 against base/merge-base 3bcf1c4bb1111d924a84d9b710c1da2db80ccf0b. Two P2 navigation findings are inline: an unresolved exact reply is lost on Back, and a repeated internal View thread opening unexpectedly reveals the root in the main history. The documented no-op Back stop and continued Bestie ownership of handed-off addresses were treated as intentional constraints.

Optional description cleanup: the Shared-code changes section attributes changes to useMessageReveal, but that file is unchanged against this base; this PR reuses its existing focus/mark support and widens the timeline’s inline-target focus type.

Source-only review of the diff, callers, tests and relevant product/design/history contracts. No tests, builds, apps or browser/native workflows were run; validation claims in the PR were not independently reproduced. The linked video was not inspected, so its contents and demonstrated behavior remain unverified.

matt2e added a commit that referenced this pull request Nov 6, 2026
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>

@kalvinnchau kalvinnchau 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.

🤖 One navigation correctness issue remains with conflicting thread hints.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source follow-up via Wes’s account, integrating independent Rocket, Mantis and Groot coverage.

Reviewed head 893b4e66c94689197c3c11d764d2843d001aef3d against base/merge-base 3bcf1c4bb1111d924a84d9b710c1da2db80ccf0b, focusing on the repair since e72ff49de9248a0bfb723780ed9792ec5cdb2f20. Both prior P2 findings are addressed in source; no new actionable findings in this repair delta.

Unrecorded exact-message returns now resolve their destination before applying the visit, independently of revealing the message. Repeating View thread records internal ownership before restarting the same history entry, preventing an unintended root reveal. The three added regression tests cover the prior failure cases; the README and corrected shared-hook description match the implementation. Earlier source coverage and the documented history tradeoffs remain unchanged.

Separately, kalvinnchau’s conflicting thread-hint finding remains relevant at this head. The hinted-root selection predates this repair and is unchanged here. This follow-up closes our two earlier findings; it does not resolve that separately reported issue or independently reproduce its browser results. No duplicate inline added.

Source-only: tests were read, not executed. No builds, apps, browser/native workflows or live reload/scroll-anchoring behavior were exercised; the PR’s validation claims were not independently reproduced. The linked video remains uninspected.

@tellaho

tellaho commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

🤖 Drip design review at 893b4e66c94689197c3c11d764d2843d001aef3d.

The intent is to open linked Bestie messages and threads where people already find that conversation.

Must-fix, already reported: a conflicting thread hint can highlight an unrelated message beside the correct thread. Reveal the verified root, or suppress the conflicting hint. The existing finding remains applicable: BestieConversation.tsx:150–152,614–625 uses the hinted root for the chat reveal independently of the thread's resolved root. No duplicate inline added.

No additional design findings. The existing chat/thread composition fits this bug fix.

Checked the source and frames from the linked wide, light-theme recording; its after-state is e6d86f54e, not this head. Not independently checked: current-head runtime, narrow layouts, dark theme, enlarged text, keyboard/screen-reader behavior, empty/loading/error recovery, long content or many-agent activity. Tests were read, not run.

matt2e added a commit that referenced this pull request Nov 9, 2026
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
Addresses review finding r4494330145 on PR #2775.

A handed-off thread visit sought and marked the message its link named as
the thread's root. A permalink such as
buzz://message?channel=<bestie-dm>&id=<reply>&thread=<unrelated-top-level>
opened the reply's real thread, since the thread reader resolves the
ancestry itself, while the chat history scrolled to and highlighted the
unrelated hinted message.

The context reveal now follows the root the thread's reader verifies. The
tab store records that root for the visit once it resolves, and the visit's
tab carries it as its verified root; until then nothing is sought, so a
conflicting hint never marks a message. Consistent links reveal the same
root as before, after the thread resolves rather than beside it. Reader
intent is armed from the start of every handed-off thread visit, so a
scroll or send while the thread is still resolving still cancels the
reveal. Message visits, Back and Forward and View thread are unchanged.

Tests (PinnedBestie.test.tsx), both confirmed to fail without the fix:
- a reply link whose thread hint names an unrelated top-level message
  opens the reply's real thread and reveals its verified root in the
  chat, never the hinted message;
- with the thread read held, a root already in the loaded history is not
  revealed until the thread arrives, and the thread keeps focus once it is
  (replacing the "revealed first" ordering, which trusted the hint).

The README records that the marked root is the verified one.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch from 893b4e6 to 4c24a68 Compare November 9, 2026 05:26

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source review via Wes’s account, integrating Rocket, Mantis and Groot.

Reviewed the verified-root repair at 4c24a68a689911981ad690cf91b532f5f90b6215 against base/merge-base 4ea0a40490d3900570734957cca6df0945780fa4, retaining the prior feature review. One residual P2 is detailed inline: a conflicting hint can still reveal an unrelated root when that thread already has a verified open tab. The fresh-tab case is repaired, and the two previously repaired Back/View thread findings remain addressed.

Source-only: regression tests were read, not run; no builds or app execution. The PR description was inspected, but the linked video remains uninspected. Live scrolling, focus and visual behavior remain unverified.

matt2e added a commit that referenced this pull request Nov 9, 2026
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
Addresses review finding r4494330145 on PR #2775.

A handed-off thread visit sought and marked the message its link named as
the thread's root. A permalink such as
buzz://message?channel=<bestie-dm>&id=<reply>&thread=<unrelated-top-level>
opened the reply's real thread, since the thread reader resolves the
ancestry itself, while the chat history scrolled to and highlighted the
unrelated hinted message.

The context reveal now follows the root the thread's reader verifies. The
tab store records that root for the visit once it resolves, and the visit's
tab carries it as its verified root; until then nothing is sought, so a
conflicting hint never marks a message. Consistent links reveal the same
root as before, after the thread resolves rather than beside it. Reader
intent is armed from the start of every handed-off thread visit, so a
scroll or send while the thread is still resolving still cancels the
reveal. Message visits, Back and Forward and View thread are unchanged.

Tests (PinnedBestie.test.tsx), both confirmed to fail without the fix:
- a reply link whose thread hint names an unrelated top-level message
  opens the reply's real thread and reveals its verified root in the
  chat, never the hinted message;
- with the thread read held, a root already in the loaded history is not
  revealed until the thread arrives, and the thread keeps focus once it is
  (replacing the "revealed first" ordering, which trusted the hint).

The README records that the marked root is the verified one.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch from 4c24a68 to 4f36be0 Compare November 9, 2026 06:29
matt2e added a commit that referenced this pull request Nov 9, 2026
…s root

Addresses review finding r4509744434 on PR #2775.

The context reveal took a handed-off thread visit's verified root from the
tab the visit's recorded root named. When that hinted thread was already
open and verified, a link to a reply from another thread with that hint
reused the open tab: the tab took the reply as its message while keeping
its earlier verified root, so the hinted root counted as verified for the
reply and was scrolled to and marked while the reader was still looking
the reply up. The later diversion to the reply's real thread could not undo
that arrival.

Verification is now recorded on the visit, for its own message. The thread
reader reports its root together with the message it settled on, which a
retarget into the shown thread changes only once the reader agrees, and the
tab store marks a visit verified only when that message is the visit's.
Bestie reveals from that record alone and no longer borrows a tab's root,
so an open thread's earlier verification is no evidence for a new link into
it; a consistent link into an open thread still reveals its root once the
reply is confirmed there. Re-entering a visit keeps its verified record.

Tests, each confirmed to fail without the fix:
- PinnedBestie: with the hinted thread open and verified and the reply's
  lookup held, a link to the reply with that hint never reveals the hinted
  root; releasing the lookup opens the reply's real thread and reveals
  only its root.
- useChannelTabState: a visit's root is verified only for the message its
  reader confirmed, not when the open tab's reader reports its own root
  again, and the verified record survives re-entering the visit.

The README records that the marked root is verified for the visit's own
message, even when that message's thread is already open.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@matt2e

matt2e commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Re: Drip design review @ 893b4e6: the must-fix is resolved.

  • 48317d6 ("reveal a thread visit's verified root, not its link's hint") makes the chat reveal follow the root the thread reader verifies, not the URL's threadRootId. Until the thread resolves nothing is sought, so a conflicting hint never highlights an unrelated message. It adds a test for exactly this case: a reply link whose hint names an unrelated top-level message reveals the verified root and never the hinted message.
  • 4f36be04ff10 then closes a follow-on gap (r4509744434). Verification is now recorded per visit for that visit's own message, so an already-open hinted thread's earlier verification can't stand in for a new link.

At head 4f36be04ff, BestieConversation.tsx reveals only record.rootId when record.verified. CI is green.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source follow-up via Wes’s account, integrating independent Rocket, Mantis and Groot coverage.

Reviewed head 4f36be04ff6e45d7add98237179c9fbfe2d8d96c against base/merge-base 7444eb12992a237eec786f5b81b94cdf48ff9c65, focusing on the retained-tab verification repair. The prior conflicting-hint P2 is addressed: a new reply cannot borrow an open tab’s earlier root verification. One repair-introduced P2 is inline: a fresh in-page visit to the same message already selected in a retained reader never gets its verification notification, so Bestie omits the expected chat-root reveal. Earlier Back/View thread repairs remain addressed.

Source-only: tests and relevant callers/contracts were read, not executed. No builds or apps were run, and the PR’s validation claims were not independently reproduced. The public PR description was inspected; the linked historical video remains uninspected. Live scrolling, focus and visual behavior remain unverified.

Comment thread src/features/messages/ThreadPanel.tsx Resolved
matt2e added a commit that referenced this pull request Nov 9, 2026
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
Addresses review finding r4494330145 on PR #2775.

A handed-off thread visit sought and marked the message its link named as
the thread's root. A permalink such as
buzz://message?channel=<bestie-dm>&id=<reply>&thread=<unrelated-top-level>
opened the reply's real thread, since the thread reader resolves the
ancestry itself, while the chat history scrolled to and highlighted the
unrelated hinted message.

The context reveal now follows the root the thread's reader verifies. The
tab store records that root for the visit once it resolves, and the visit's
tab carries it as its verified root; until then nothing is sought, so a
conflicting hint never marks a message. Consistent links reveal the same
root as before, after the thread resolves rather than beside it. Reader
intent is armed from the start of every handed-off thread visit, so a
scroll or send while the thread is still resolving still cancels the
reveal. Message visits, Back and Forward and View thread are unchanged.

Tests (PinnedBestie.test.tsx), both confirmed to fail without the fix:
- a reply link whose thread hint names an unrelated top-level message
  opens the reply's real thread and reveals its verified root in the
  chat, never the hinted message;
- with the thread read held, a root already in the loaded history is not
  revealed until the thread arrives, and the thread keeps focus once it is
  (replacing the "revealed first" ordering, which trusted the hint).

The README records that the marked root is the verified one.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
…s root

Addresses review finding r4509744434 on PR #2775.

The context reveal took a handed-off thread visit's verified root from the
tab the visit's recorded root named. When that hinted thread was already
open and verified, a link to a reply from another thread with that hint
reused the open tab: the tab took the reply as its message while keeping
its earlier verified root, so the hinted root counted as verified for the
reply and was scrolled to and marked while the reader was still looking
the reply up. The later diversion to the reply's real thread could not undo
that arrival.

Verification is now recorded on the visit, for its own message. The thread
reader reports its root together with the message it settled on, which a
retarget into the shown thread changes only once the reader agrees, and the
tab store marks a visit verified only when that message is the visit's.
Bestie reveals from that record alone and no longer borrows a tab's root,
so an open thread's earlier verification is no evidence for a new link into
it; a consistent link into an open thread still reveals its root once the
reply is confirmed there. Re-entering a visit keeps its verified record.

Tests, each confirmed to fail without the fix:
- PinnedBestie: with the hinted thread open and verified and the reply's
  lookup held, a link to the reply with that hint never reveals the hinted
  root; releasing the lookup opens the reply's real thread and reveals
  only its root.
- useChannelTabState: a visit's root is verified only for the message its
  reader confirmed, not when the open tab's reader reports its own root
  again, and the verified record survives re-entering the visit.

The README records that the marked root is verified for the visit's own
message, even when that message's thread is already open.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
…hows

Addresses review finding r4510225492 on PR #2775.

The thread reader reported its verified root only when the root or the
message it settled on changed. A fresh visit to the message a retained
thread already shows, as when a reader selects the plain Bestie
destination with the thread tab kept and then follows a chat permalink
to that reply, creates a new history entry without remounting the page
or its reader: the same-message retarget succeeds and leaves the
reader's root, message and revision unchanged, so nothing was reported.
The new visit's record stayed unverified, and Bestie never sought or
marked its root, though the thread opened.

The reader now reports its verified root and message again on each
confirmed routed selection, including one that changes neither. A
pending retarget leaves the reader's opening untouched and a failed one
never adopts the request, so neither reports; a selection diverted to a
different thread reports the kept message, which the new visit's record
does not match. The tab store's verification is unchanged and idempotent
for an already-verified visit.

Test (PinnedBestie.test.tsx), confirmed to fail without the fix at the
reveal: a reply's handed-off visit reveals its root; a plain Bestie visit
keeps the thread tab and its reader; a fresh visit at the permalink's own
page address, as openLink produces, reveals the root again, with focus on
the linked reply in the thread, not on the revealed root.

The README records that a fresh link to the message a retained thread
shows is verified and marks its root the same way.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch from 4f36be0 to 0d61905 Compare November 9, 2026 07:30

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source follow-up via Wes’s account, integrating independent Rocket, Mantis and Groot coverage.

Reviewed head 0d61905757e4622790b33191ff7bbbcad3441d05 against base/merge-base 40e6ccb597cf9d8b47f9692de8285458cc304017, focusing on the same-message retained-reader repair. The prior P2 is addressed in source; no new actionable findings in this repair or its relevant integration.

The root report now follows the settled opening’s navigation, so a fresh visit receives verification after a successful retarget even when its root and message are unchanged. Pending, failed and superseded retargets do not adopt the new opening; diversion can only re-report the prior confirmed message. The added regression covers an intervening plain Bestie visit, a fresh link to the retained message, a second root reveal and focus remaining in the thread. Earlier Back/View thread and conflicting-hint repairs remain addressed; prior feature coverage and documented history tradeoffs are retained.

Source-only: tests were read, not run; no builds or apps were executed, and the PR’s validation claims were not independently reproduced. The public PR description was inspected; the historical linked video remains uninspected. Live scrolling, focus and visual behavior remain unverified.

matt2e added a commit that referenced this pull request Nov 9, 2026
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
Addresses review finding r4494330145 on PR #2775.

A handed-off thread visit sought and marked the message its link named as
the thread's root. A permalink such as
buzz://message?channel=<bestie-dm>&id=<reply>&thread=<unrelated-top-level>
opened the reply's real thread, since the thread reader resolves the
ancestry itself, while the chat history scrolled to and highlighted the
unrelated hinted message.

The context reveal now follows the root the thread's reader verifies. The
tab store records that root for the visit once it resolves, and the visit's
tab carries it as its verified root; until then nothing is sought, so a
conflicting hint never marks a message. Consistent links reveal the same
root as before, after the thread resolves rather than beside it. Reader
intent is armed from the start of every handed-off thread visit, so a
scroll or send while the thread is still resolving still cancels the
reveal. Message visits, Back and Forward and View thread are unchanged.

Tests (PinnedBestie.test.tsx), both confirmed to fail without the fix:
- a reply link whose thread hint names an unrelated top-level message
  opens the reply's real thread and reveals its verified root in the
  chat, never the hinted message;
- with the thread read held, a root already in the loaded history is not
  revealed until the thread arrives, and the thread keeps focus once it is
  (replacing the "revealed first" ordering, which trusted the hint).

The README records that the marked root is the verified one.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
matt2e added a commit that referenced this pull request Nov 9, 2026
…s root

Addresses review finding r4509744434 on PR #2775.

The context reveal took a handed-off thread visit's verified root from the
tab the visit's recorded root named. When that hinted thread was already
open and verified, a link to a reply from another thread with that hint
reused the open tab: the tab took the reply as its message while keeping
its earlier verified root, so the hinted root counted as verified for the
reply and was scrolled to and marked while the reader was still looking
the reply up. The later diversion to the reply's real thread could not undo
that arrival.

Verification is now recorded on the visit, for its own message. The thread
reader reports its root together with the message it settled on, which a
retarget into the shown thread changes only once the reader agrees, and the
tab store marks a visit verified only when that message is the visit's.
Bestie reveals from that record alone and no longer borrows a tab's root,
so an open thread's earlier verification is no evidence for a new link into
it; a consistent link into an open thread still reveals its root once the
reply is confirmed there. Re-entering a visit keeps its verified record.

Tests, each confirmed to fail without the fix:
- PinnedBestie: with the hinted thread open and verified and the reply's
  lookup held, a link to the reply with that hint never reveals the hinted
  root; releasing the lookup opens the reply's real thread and reveals
  only its root.
- useChannelTabState: a visit's root is verified only for the message its
  reader confirmed, not when the open tab's reader reports its own root
  again, and the verified record survives re-entering the visit.

The README records that the marked root is verified for the visit's own
message, even when that message's thread is already open.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch from 0d61905 to 9a013a3 Compare November 9, 2026 14:30
matt2e added a commit that referenced this pull request Nov 9, 2026
…hows

Addresses review finding r4510225492 on PR #2775.

The thread reader reported its verified root only when the root or the
message it settled on changed. A fresh visit to the message a retained
thread already shows, as when a reader selects the plain Bestie
destination with the thread tab kept and then follows a chat permalink
to that reply, creates a new history entry without remounting the page
or its reader: the same-message retarget succeeds and leaves the
reader's root, message and revision unchanged, so nothing was reported.
The new visit's record stayed unverified, and Bestie never sought or
marked its root, though the thread opened.

The reader now reports its verified root and message again on each
confirmed routed selection, including one that changes neither. A
pending retarget leaves the reader's opening untouched and a failed one
never adopts the request, so neither reports; a selection diverted to a
different thread reports the kept message, which the new visit's record
does not match. The tab store's verification is unchanged and idempotent
for an already-verified visit.

Test (PinnedBestie.test.tsx), confirmed to fail without the fix at the
reveal: a reply's handed-off visit reveals its root; a plain Bestie visit
keeps the thread tab and its reader; a fresh visit at the permalink's own
page address, as openLink produces, reveals the root again, with focus on
the linked reply in the thread, not on the revealed root.

The README records that a fresh link to the message a retained thread
shows is verified and marks its root the same way.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
matt2e added a commit that referenced this pull request Nov 10, 2026
## Summary

On the Bestie page, ⌘F (Ctrl+F) opened nothing and ⌘K (Ctrl+K) had no
"Search conversation with <name>" row. `PageSearch` only recognised a
`conversation` navigation target as the current conversation, and the
Bestie page is a `page` target that presents the promoted Bestie DM.

`PageSearch` now derives the current channel from the conversation
target's channel, or, on the Bestie page, from the shell's Bestie
projection via `useBestieConversation` (provided by `AppShell` above
it). That channel drives the ⌘F guard, the scoped search and ⌘K's "This
conversation" row. Other `page` targets still open nothing with ⌘F. The
header menu is out of scope.

## Before / after

Left is `main` (58116b8), right is this branch. The fixture runs on
Linux, so the shortcuts show as Ctrl+F and Ctrl+K. Both sides start on
an ordinary DM with Ada, where Ctrl+F already works, then switch to the
Bestie page ("Bestie · Pollen").


https://github.com/user-attachments/assets/c4871a39-f5d1-4c28-bca7-ce4b87db5e2e

![Ctrl+F on the Bestie page: main opens nothing (left); the fix opens a
search scoped to Pollen that finds "gym"
(right)](https://github.com/user-attachments/assets/331488a6-7be9-4c7c-a5b6-216d1c1d4ce1)

Ctrl+F on the Bestie page: main opens nothing (left); the fix opens a
search scoped to Pollen that finds "gym" (right).

![Ctrl+K on the Bestie page: main shows only Recent activity (left); the
fix adds "Search conversation with Pollen" under This conversation
(right)](https://github.com/user-attachments/assets/6792ab2d-fdfb-400a-ae32-80ccdcbe5a1a)

Ctrl+K on the Bestie page: main shows only Recent activity (left); the
fix adds a "Search conversation with Pollen" row under This conversation
(right).

## Commits

- b5135e9 `fix(search): make Command F search the Bestie
conversation` — `PageSearch` takes the current conversation from the
conversation target or, on the Bestie page, from
`useBestieConversation`; tests for ⌘F and the ⌘K row scoped to the
Bestie DM, and for ⌘F opening nothing on another page; Bestie README and
Buzz help updated.
- 2ea0ff5 `refactor(search): name the Bestie page check and cover
other conversations` — adds `isBestiePage(target)` next to `BESTIE_PAGE`
in `bestie-context.ts`, makes `useBestieConversation` require a session
explicitly, and tests that ⌘F on another DM with a Bestie DM present
scopes to that DM.
- 86f4ffc `docs(bestie): mention Command K's conversation row on the
Bestie page` — Buzz help mentions the ⌘K "Search conversation with" row.

## Testing

- Typecheck and lint pass.
- PageSearch, BestieNavigation and ChannelInventory suites: 119/119.
- Full `vitest run`: 20,060 passed, 27 skipped, 0 failed.
- Still to do: the native-app run that `AGENTS.md` requires (agent, then
human). The reproduction and recording used a browser fixture with a
device-local Bestie choice.

## Related PRs

Open PRs #2775 and #2804 touch `bestie-context.ts` only cosmetically and
do not conflict with this change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: mtoohey <mtoohey@squareup.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
matt2e and others added 9 commits November 10, 2026 14:33
Every conversation link opened Messages, which hides the promoted Bestie
DM's row. Following a Bestie DM thread's "In DM" link from Activity
therefore landed in Messages with neither the DM nor the thread showing.

Messages now hands a pending visit to the promoted DM, or to one of its
threads, to the Bestie page in place, before Messages presents it. The
visit keeps its history entry, and a thread visit opens in Bestie's
thread pane under the thread placement preference.

Entry points that share this path and are fixed with it:
- the thread tab's "In DM" link and Activity's "Open in channel"
- notifications for thread replies in the Bestie DM
- buzz:// permalinks that name a thread
- choosing the Bestie DM from a channel result in search
- Back and Forward to an older visit of the DM or its threads

Unchanged: other DMs and channels; a link to a single top-level
message, Forward and Members, which have no Bestie route yet and stay
in Messages; and a visit Messages had already opened before the
promotion was known.

useBestieConversation no longer matches a missing session when no
Bestie provider is mounted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
A link to a thread in the Bestie DM now scrolls Bestie's chat history to
the thread's root message and marks it, beside the thread it opens in
its pane. Bestie reuses the message opening Messages already has: it
reads older history until the root loads, holding the list until then,
and reveals it with the same scroll, focus and arrival cue.

Links to a single message in the Bestie DM, from notifications, search
results and buzz:// links without a thread, now open Bestie too, instead
of Messages. The message is shown the same way when it is a top-level
message in history; a reply, or a message not found, opens as its
thread, as Messages does. Forward and Members still open in Messages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Bestie sought and revealed the thread's root for every thread visit,
including its own View thread and Back/Forward, and hid the chat behind
"Loading messages…" while it looked. It now does so only on the first
presentation of a visit handed off from Messages; its own thread opens
and traversals leave the chat where the reader left it. For a thread
visit the list stays mounted and the root is marked once it is loaded
or found, quietly doing nothing if it never is. Message visits still
hold the list while the message is sought, as Messages does.

The thread pane keeps focus: inlineTarget can decline focus, and
useMessageReveal marks the arrival independently of focusing it. A
covering Members dialog still suppresses both.

Also from review:
- Messages hands off only its own pending visit, not a settled visit
  kept shown while Settings opens over it.
- A chat link into the Bestie DM opens as Bestie's own visit instead of
  a Messages stop that resolves to the same place.
- BestieNavigationProvider memoizes its value, so channel-list churn no
  longer re-renders Messages while a Bestie is promoted.
- Closing a View thread tab no longer retires a message visit that
  showed the chat; a message visit is retired only when it opened a
  reply's thread.
- A message visit that opened as a thread returns to that thread.
- The README records that a handed-off entry becomes Bestie's address:
  disabling the plugin or changing the Bestie later treats it like
  Bestie's own thread visits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
…y showed

Second review round of the Bestie handoff.

A message visit that opened as its thread was kept when that thread closed
whenever the message was top-level but not in history (older than the seek,
deleted, or behind a failed read): the tab's root equalled the message, so the
address alone could not show that the visit had resolved as a thread. Close
now retires the visits the tab store recorded for a closing thread, however
they were addressed, through a dismiss predicate that also receives each
visit's id; the address heuristic remains for unrecorded visits after reload.

How a message visit resolved lived in a per-mount map, so Back after leaving
Bestie for another page remounted it as a channel visit and deselected the
thread. The page now reads the tab store's routedVisits record, which outlives
the mount and is pruned with history.

The marker for threads Bestie opens itself was cleared by any render still on
the originating visit, so a View thread visit could count as handed off and
reveal its root. The marker records the visit it was opened from and ignores
renders on it. The View thread test now waits two frames past the visit and
asserts no chat row was revealed; it fails with the guard removed.

A thread visit keeps the chat interactive while an older root is sought, so a
late reveal could pull a reader away from where they scrolled, or stop the tail
following after a send. The timeline reports reader input on the history, and
Bestie drops the context reveal, and the seek, once the reader scrolled the
chat or sent from the main composer during the visit. A message visit still
decides between the chat and its thread.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Reader intent was armed to cancel the reveal of message visits as well as
thread visits. A message visit holds the list until its message is found, so
the only gesture that can land is one after the reveal; that gesture cleared
the inline target, and a revealed agent update the chat otherwise hides
disappeared from under the reader, dropping focus to the body.

Arm cancellation only for a thread visit's context reveal. A message visit's
reveal is the visit itself and stays for the whole visit, as the navigation
target does in Messages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
…thread's own

Addresses the two P2 review threads on PR #2775 (head e72ff49).

Review finding r4493927979, unrecorded message visits on Back/Forward:
an exact message visit is recorded in the tab store's routedVisits only
once its first presentation decides it opened as a thread. A visit left
before history answered, or returned to after a reload, had no record.
On traversal it was not handed off, so useMessageOpening never ran, and
the visit was entered as a channel visit: the linked reply's thread never
opened, even after the read finished.

- A message visit with no recorded resolution now asks history where the
  message is on every presentation, Back and Forward included.
- The visit is committed only once that answer is in: enterVisit waits
  while a message visit has neither a thread nor an answer.
- The reveal stays tied to the handed-off first presentation. Traversal
  neither holds the list nor reveals the message; it only chooses between
  the chat and the thread.

Review finding r4493927990, View thread on the shown thread:
activating View thread for the thread the current visit already shows
restarts that visit under the same entry id (controller.ts start()). The
ownership marker waited for a new entry id that never came, so the
restarted visit counted as handed off and sought and revealed the root
in the chat history. A same-target open now marks the current entry as
this page's own immediately.

Tests (PinnedBestie.test.tsx), each confirmed to fail without its fix:
- leaving Bestie while a reply link's history read is held, then Back
  after the read is released, opens the reply's thread;
- Back through message visits with no stored resolution opens a reply's
  thread, then the chat for a top-level message without revealing it
  (this case also fails if traversal reveals);
- View thread activated again on the shown thread, after a chat gesture,
  restarts the same visit and leaves the root unrevealed.

The README records the re-decision on an unrecorded return and the
repeated View thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Addresses review finding r4494330145 on PR #2775.

A handed-off thread visit sought and marked the message its link named as
the thread's root. A permalink such as
buzz://message?channel=<bestie-dm>&id=<reply>&thread=<unrelated-top-level>
opened the reply's real thread, since the thread reader resolves the
ancestry itself, while the chat history scrolled to and highlighted the
unrelated hinted message.

The context reveal now follows the root the thread's reader verifies. The
tab store records that root for the visit once it resolves, and the visit's
tab carries it as its verified root; until then nothing is sought, so a
conflicting hint never marks a message. Consistent links reveal the same
root as before, after the thread resolves rather than beside it. Reader
intent is armed from the start of every handed-off thread visit, so a
scroll or send while the thread is still resolving still cancels the
reveal. Message visits, Back and Forward and View thread are unchanged.

Tests (PinnedBestie.test.tsx), both confirmed to fail without the fix:
- a reply link whose thread hint names an unrelated top-level message
  opens the reply's real thread and reveals its verified root in the
  chat, never the hinted message;
- with the thread read held, a root already in the loaded history is not
  revealed until the thread arrives, and the thread keeps focus once it is
  (replacing the "revealed first" ordering, which trusted the hint).

The README records that the marked root is the verified one.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
…s root

Addresses review finding r4509744434 on PR #2775.

The context reveal took a handed-off thread visit's verified root from the
tab the visit's recorded root named. When that hinted thread was already
open and verified, a link to a reply from another thread with that hint
reused the open tab: the tab took the reply as its message while keeping
its earlier verified root, so the hinted root counted as verified for the
reply and was scrolled to and marked while the reader was still looking
the reply up. The later diversion to the reply's real thread could not undo
that arrival.

Verification is now recorded on the visit, for its own message. The thread
reader reports its root together with the message it settled on, which a
retarget into the shown thread changes only once the reader agrees, and the
tab store marks a visit verified only when that message is the visit's.
Bestie reveals from that record alone and no longer borrows a tab's root,
so an open thread's earlier verification is no evidence for a new link into
it; a consistent link into an open thread still reveals its root once the
reply is confirmed there. Re-entering a visit keeps its verified record.

Tests, each confirmed to fail without the fix:
- PinnedBestie: with the hinted thread open and verified and the reply's
  lookup held, a link to the reply with that hint never reveals the hinted
  root; releasing the lookup opens the reply's real thread and reveals
  only its root.
- useChannelTabState: a visit's root is verified only for the message its
  reader confirmed, not when the open tab's reader reports its own root
  again, and the verified record survives re-entering the visit.

The README records that the marked root is verified for the visit's own
message, even when that message's thread is already open.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
…hows

Addresses review finding r4510225492 on PR #2775.

The thread reader reported its verified root only when the root or the
message it settled on changed. A fresh visit to the message a retained
thread already shows, as when a reader selects the plain Bestie
destination with the thread tab kept and then follows a chat permalink
to that reply, creates a new history entry without remounting the page
or its reader: the same-message retarget succeeds and leaves the
reader's root, message and revision unchanged, so nothing was reported.
The new visit's record stayed unverified, and Bestie never sought or
marked its root, though the thread opened.

The reader now reports its verified root and message again on each
confirmed routed selection, including one that changes neither. A
pending retarget leaves the reader's opening untouched and a failed one
never adopts the request, so neither reports; a selection diverted to a
different thread reports the kept message, which the new visit's record
does not match. The tab store's verification is unchanged and idempotent
for an already-verified visit.

Test (PinnedBestie.test.tsx), confirmed to fail without the fix at the
reveal: a reply's handed-off visit reveals its root; a plain Bestie visit
keeps the thread tab and its reader; a fresh visit at the permalink's own
page address, as openLink produces, reveals the root again, with focus on
the linked reply in the thread, not on the revealed root.

The README records that a fresh link to the message a retained thread
shows is verified and marks its root the same way.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e force-pushed the links-to-bestie-dm-dont-open-bestie-top-level-nav branch from 9a013a3 to aa94a1f Compare November 10, 2026 03:38

This branch has not been deployed

No deployments
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.

4 participants