Skip to content

fix(social): accepting an invite shows the shared Bot at once and never grants ours back; live People with access (#228) - #240

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
Birfy:fix-228-accept-invite
Oct 18, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
Birfy:fix-228-accept-invite

Conversation

@Birfy

@Birfy Birfy commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #228

Accepting a Bot invite had three problems: the Talk through tooltip implied a Bot is granted back, the inviter's open People with access stayed stale, and the shared Bot showed up ~10 s after the success toast.

What

  • No grant back, and the Bot shows with the toast (social.js social/join-invite): the offered Bot is marked inbound before the first roster refresh. Before, the grant sync started by that refresh saw Bot Social's talk-through grant on the joiner's Chief (grantee = the shared Bot) before the Bot was inbound, so isTalkThroughGrant missed it: it was stored as a core grant on the joiner's Chief for the inviter's Bot (the Granted friend Bot never shows for the grantee: the talk-through grant hides it (regression from the #161 fix) #178 class: a usable grant, until a later sync dropped it), and the re-filter could drop the shared Bot until the next refresh, which is the late row.
  • A late grant re-filter of an older roster fetch no longer overwrites a newer one: a fetch counter replaces the millisecond timestamp guard, which two fetches in the same ms could pass.
  • Copy (client.js): Talk through shows only when the joiner has more than one Bot. Its tooltip says plainly: "Talks for you. Not shared: your friend can't use it unless you invite them to it."
  • People with access re-reads social/access every 5 s while the page is visible (only re-renders on a change). social/access now syncs only that Bot's grants (syncOutgoingGrants({ only })), so the poll costs one list_bot_grants call.
  • Design holds: per-Bot grants only, no publish, nothing new is granted. Bot Social itself still records the talk-through side as a grant on the joiner's Bot (list_bot_grants). FlyBot filters it on both sides (Regression of #138: joining a friend's invite still puts the joiner's Chief on the inviter's main list #161, Granted friend Bot never shows for the grantee: the talk-through grant hides it (regression from the #161 fix) #178), and changing that needs a Bot Social change.

Tests

  • #228: accepting an invite … never grants our talk-through Bot back fails at base (core grant on Chief for @helper.bob.home) and passes at tip. It also checks the shared Bot is listed when the join returns and after the background sync, and that Chief's People with access is empty.
  • #228: an open People with access shows a friend who accepts, without reopening fails at base (no poll).
  • Updated #136 / #181 (no picker with one Bot, tooltip copy) and #138 (copy).
  • ARCH_DOCS_BASE=upstream/main npm run verify green locally (TZ=UTC). The social suite passed 6/6 repeated runs. One unrelated core test (an untagged hold stamps the latest working task…) failed once and passed on rerun. Docs: social.md. Fragment 228-accept-invite-grant.fixed.md.
  • Not run: a live two-home accept. The ~10 s delay cause comes from reading the code plus the unit race, not from a live trace.

…grants ours back; live People with access (ThinkFlowLab#228)

- social/join-invite marks the offered Bot inbound before its first roster
  refresh. The grant sync that refresh starts saw the talk-through grant on
  our Bot before the Bot was inbound, stored it as a core grant on our
  Bot for the inviter's Bot, and its re-filter could drop the shared Bot
  until a later refresh (the late row after the toast).
- A grant re-filter of an older roster fetch never overwrites a newer one
  (fetch counter instead of a millisecond timestamp).
- Talk through shows only with more than one Bot; its tooltip says that
  Bot is not shared.
- An open People with access re-reads social/access every 5 s while
  visible; social/access syncs only that Bot's grants.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T00:41:58.365361Z 1cde0bc PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Birfy
Birfy added this pull request to the merge queue Oct 18, 2026
Merged via the queue into ThinkFlowLab:main with commit a38b26c Oct 18, 2026
7 checks passed
@Birfy
Birfy deleted the fix-228-accept-invite branch October 18, 2026 00:41

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1cde0bc7a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Mark the shared Bot inbound before the first refresh: the grant sync that refresh starts
// must already see the talk-through grant on our Bot as talk-through, or it stores it as us
// sharing that Bot back and the re-filter drops the shared Bot until the next refresh (#228).
if (offeredHandle) rememberInbound(offeredHandle)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Drain older grant syncs before returning from join

When a remoteBots or social/access grant sync is already in flight while the user accepts an invite, setting only inboundBots here is insufficient: isTalkThroughGrant also requires the new relationship to be present in remote.homes, which is not updated until the fresh roster call below. If that older list_bot_grants finishes after the server creates the relationship but before the roster applies, it writes the shared Bot as a real core grant on the joiner's Bot; the new sync is fire-and-forget, so a failure there can leave that grant passing the reach gate beyond the success toast. Version or serialize grant writes, or await a post-roster sync before returning.

Useful? React with 👍 / 👎.

Comment thread plugins/social/client.js
useEffect(() => {
void load()
if (typeof setInterval !== 'function') return undefined
const timer = setInterval(() => { if (typeof document === 'undefined' || !document.hidden) void load() }, ACCESS_POLL_MS)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep access polls from overlapping

When a social/access request takes longer than 5 seconds (the MCP timeout is 30 seconds), every interval tick starts another load while the prior request is pending. Each backend handler performs syncOutgoingGrants({ only }) and writes flybot.grants, so responses that finish out of order can overwrite a newer accept/revoke snapshot and then regress this component through setView; an outage can also accumulate six concurrent requests. Use a single-flight guard or schedule the next poll only after the previous load settles.

Useful? React with 👍 / 👎.

Comment thread plugins/social/client.js
useEffect(() => {
void load()
if (typeof setInterval !== 'function') return undefined
const timer = setInterval(() => { if (typeof document === 'undefined' || !document.hidden) void load() }, ACCESS_POLL_MS)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid saving team state on every access poll

While People with access is open with no changes, this 5-second tick still calls social/access; its syncOutgoingGrants unconditionally calls flybot.grants.set, and core's setGrants calls rt.save() even when grantsEqual is true. save() increments the team revision and rewrites state.json, so merely viewing this panel produces a full state write and global UI revision about 12 times per minute despite the setView equality check. Skip the core set when the grant list is unchanged or poll through a side-effect-free query.

Useful? React with 👍 / 👎.

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.

Accept invite: 'Talk through' copy implies a Bot is granted back; People with access stays stale; Helper appears ~10 s after the toast

1 participant