Skip to content

Mark a Bot unread for a friend's line, say who is talking on first contact, and list per-Bot friendships - #432

Merged
Birfy merged 3 commits into
ThinkFlowLab:mainfrom
Birfy:fix/420-friend-line-unread
Oct 19, 2026
Merged

Birfy merged 3 commits into
ThinkFlowLab:mainfrom
Birfy:fix/420-friend-line-unread

Conversation

@Birfy

@Birfy Birfy commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Fixes #420

A friend's line in one of my Bots' own chats no longer slips by unnoticed, and social/overview lists per-Bot friendships. This follows the owner-delegated decision on the issue: a grantee's lines stay in the Bot's own chat (social.md invariant 8), there is no thread per person, and a friend with no Bot shared to me gets no row.

What changes

  • Host (delivery.js): a friend's line that reaches a Bot's own chat sets friendLineAt on that Bot. The stamp goes out with the roster, and the save moves the revision so open windows read it. The host also remembers which senders it has seen per Bot (state.remoteContacts, host only, capped at 200, removed when the Bot is deleted). A sender's first line carries source.remote.firstContact. Group lines, refused sends and re-deliveries (deferred / resumed / retried / resent) leave no stamp.
  • Client unread (friend-lines.js, index.js): the browser saves the last stamp it showed for each Bot (ds-bot:friend-lines). When a newer stamp arrives and that Bot's chat is not open, the Bot is marked unread the same way Mark as Unread does. The row shows the blue dot until the chat is opened, and this also works when the line came while FlyBot was closed. Stamps are compared only with stamps, not with the browser's clock. A browser with no saved record treats what is already there as seen. Another member's shared Bot and a friend's Bot chat are skipped. The Main Bot tile now shows the same dot (before, a tile showed no unread mark at all).
  • First contact (cells.js FirstContact): a sender's first line gets one muted line above it, e.g. SelfB1238 is talking to Chief through Bot Social. It names the person for a typed line and Bot (owner) for a Bot's line. zh copy added.
  • Social (friendsOverview): it asks list_friends for the home and for every active member identity (as setAutoAccept already does) and lists each relationship once. A row found through a member carries botId / botName. Pending requests come in the same way, so Add friend shows per-Bot requests. If one member can't be read, only that member's rows are missing; if the home read fails, the call still fails.
  • Docs: core-host.md, core-client.md, plugin-runtime.md, social.md (new "Friends listed per Bot" section). Changelog fragment.

Live first line (acceptance item 1): I could not find a FlyBot-side cause in the code for "the first line only showed after a reload", and I could not reproduce it without two live homes. Delivery goes through the same agent.followup path as lines 2 to 5, which did show live. Inbox polling is 15 s and the line showed after about 25 s, so the reload may just have happened right after the line arrived. If the next self-test still sees it, it needs its own issue with a timed repro.

Not in this PR: #275 (the NEW divider stays during the visit). The divider uses the per-visit seen / entered clock, while this change uses its own stamp, so a fix for #275 does not come out of this one.

Tests: core/test/friend-lines.test.js (marking, seen live, no record, remote/other member skipped), core/test/flybot.test.js #420 (stamp, revision, first contact once per sender, contacts not in view), core/test/inbound-ui.test.js #420 (first-contact line for person and Bot), social #420 overview (per-Bot friendship + request, dedupe, home + member asked once each, failed member read).

Ran: ARCH_DOCS_BASE=origin/main TZ=UTC npm run verify at the tip, passes (arch-docs OK; core, social, tree, timeline, scripts, interop, live-e2e all 0 failures).
Not run: smoke bench, two-home live run against prod Bot Social (live first line, badge in a real browser), Desktop app.

Birfy added 2 commits October 19, 2026 17:07
…hinkFlowLab#420)

A friend's line lands in the receiving Bot's own chat (social.md invariant 8),
so DSH's completion mark did not flag it. The host now stamps the Bot with
friendLineAt and the first line from a sender with remote.firstContact; the
client marks the Bot unread when a newer stamp arrives while its chat is not
open, and shows a quiet first-contact line. social/overview asks the home and
every member identity, so per-Bot friendships and requests are listed.
@Birfy Birfy added agent-pr Pull request opened by an agent bug Something isn't working area:social Friends, invites, grants, Bot Social area:ui Web/desktop UI and copy labels Oct 19, 2026
@Birfy Birfy self-assigned this Oct 19, 2026
…nread

# Conflicts:
#	patches/ds-bot/0003-flybot-api-client.patch
#	patches/ds-bot/0008-client-bundle.patch
@Birfy

Birfy commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

Self-review (Birfy, owner's Bot)

I read the full diff at the tip, including the merge of main c5d9c3f (#431). Only generated files conflicted (0003, 0008); I took main's version and regenerated them with the repo's conflict recipe.

Findings:

Verdict: PASS
Tip SHA: 048af7d
Ran: ARCH_DOCS_BASE=origin/main TZ=UTC npm run verify at the tip (core 973, social 264, tree 56, timeline 80, scripts 88, interop 37, live-e2e 16, 0 failures; arch-docs OK). CI tests-ok green at the tip.
Not run: smoke bench, two-home live run against prod Bot Social, Desktop app.

@Birfy
Birfy added this pull request to the merge queue Oct 19, 2026
@Birfy Birfy added the awaiting-approval PR is green and waits for the maintainer's approval (T2/T3) or a review PASS at its tip label Oct 19, 2026
Merged via the queue into ThinkFlowLab:main with commit 1711d59 Oct 19, 2026
8 checks passed
@Birfy
Birfy deleted the fix/420-friend-line-unread branch October 19, 2026 09:16
Birfy added a commit to Birfy/FlyBot that referenced this pull request Oct 20, 2026
…inboxes fast while a window is on screen (ThinkFlowLab#505)

Fixes ThinkFlowLab#497

**Root cause.** Nothing on FlyBot's live path regressed since ThinkFlowLab#432. On a
two-home bench at main `a7adfe0` (local Bot Social + mock model, browser
on A's Chief chat), B's first line, the held reply's **Waiting for
approval** card, the Inbox count and the badge all show without a
reload. They just show late: the social plugin reads a Bot's Bot Social
inbox only on its idle timer (`inboxPollMs`, 15 s), and the card also
waits for the model's reply. ThinkFlowLab#432 never fixed acceptance item 1; its PR
said it found no cause and pointed at the 15 s poll. The self-test logs
match: B sent at 12:39:26, A delivered at 12:39:34 (+8.5 s), and the
card arrived at 12:39:41 (+15 s). Someone watching for about 8 s sees
nothing and then reloads.

**What changes**
- Client (`index.js`): the roster poll sends `watching:
!document.hidden` with each `state` call.
- Host (`channel.js`, `hooks.js`): `state` notes when a window on screen
last read the team. A hidden window does not count; an older client that
sends nothing does. That is `rt.watched()` (8 s), offered to plugins as
`flybot.watched()`. Process-local, nothing saved.
- Social (`social.js`): while a window watches, a second timer reads the
inbox at the live cadence (`facePollMs`, 4 s). It skips ticks the shared
timer already covers (a live face room) and ticks within half a period
of the last read. With no window open nothing changes (15 s).
- Docs: core-host, core-client, plugin-runtime, social. Changelog
fragment.

**Measured on the two-home bench** (B sends, until the line is in A's
open Chief chat, 5 lines each): main 7.7–12.5 s, this branch 1.3–3.1 s.
The card and the Inbox count follow on the same host revision, after the
mock model's reply.

**Tests**
- `core/test/flybot.test.js` ThinkFlowLab#497: a window that keeps polling with
`since` gets the friend's first line (`friendLineAt`), then the held
reply (`pendingCount` 1, `heldReplies` pending on the turn it answers),
with no reload. Also `flybot.watched()`: hidden does not count, it
expires after 8 s, and an older client counts. The second test fails on
main.
- `plugins/social/test/social.test.js` ThinkFlowLab#497: with no window the live
timer reads nothing. With a window, B's first line is delivered on the
first 4 s tick. Once the window is gone it stops. Fails on main.

Ran: `ARCH_DOCS_BASE=origin/main TZ=UTC npm run verify` at the tip,
passes (arch-docs OK; plugin lint OK; core 1079, social 297, tree 80,
timeline 83, scripts 93, interop 37, live-e2e 16; 0 failures). Two-home
live bench (local Bot Social at 6a97ba0, mock model, headless and
headful Chrome) before and after.
Not run: prod Bot Social, real model, the Mac instances, the Desktop
app, smoke bench.

Risk tier: T2 (estimate; the controller sets the label)

Co-authored-by: Birfy <15378933+Birfy@users.noreply.github.com>
@Birfy Birfy removed awaiting-approval PR is green and waits for the maintainer's approval (T2/T3) or a review PASS at its tip agent-pr Pull request opened by an agent labels Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:social Friends, invites, grants, Bot Social area:ui Web/desktop UI and copy bug Something isn't working

Projects

None yet

1 participant