Repository navigation
The room-line approval card has never been proven through the room input box (only through the API, which cannot make one) #977
Description
The last unproven piece of #866's in-room half. Everything else in that issue has either been verified on d5889968 or moved to #948; this is the part that cannot be proven from the API, so it needs one real-browser run on the two-home bench.
Already verified (do not repeat)
On d5889968, two isolated homes, real Bot Social, no mocks: a platform room opened (frm_01M5PTG5CMZJ5KPCR34MHMB2FT), a ticket minted and redeemed by the guest's own Bot (status=candidate), two live seats from two homes, and the guest's room line accepted by Bot Social ({"status":"pending_approval", approvalId: "apr_01M5PTG7BMTZK3CPQW3SRNB9PP"}).
What is not verified, and why the API cannot verify it
Whether that hold becomes an approval card on the host's screen, and what approving it does. My earlier attempt through social/face-send produced no card, and that is by design, not a defect:
plugins/social/src/social.js:3845—social/face-sendcallsfaceApi.senddirectly and never records the hold's room.- the UI path
rooms.onFaceLine(:3705) is the one that callsrememberHoldRoomat:3731. pendingApprovalsdrops aface_room_messagehold that names no room (:2917).
So a card can only come from the room's own input box in a real UI. Any probe that builds the hold through social/face-send is measuring the probe.
The run
Two homes, two Bots, a platform room with both seated (the setup above), no prior relationship.
- Guest types a line in the room's input box and sends.
- Host home: an approval card appears for that room, naming the room and the guest's Bot — not a bare
face_room_message, and not a card for a 1:1 conversation. - Host approves: the line is delivered into the room and both sides see it as an ordinary room line; the card leaves no "waiting" residue.
- Fresh room, same setup, host rejects: nothing is delivered, and the guest reads a sentence (not a code, not a silent drop).
- Negative control: the same pair sending a 1:1 line outside the room never shows a room card — that path is A ticket-claimed (room-only) Bot cannot send a 1:1 line into the room it shares: the member check runs before the room lookup #948 and must not be dragged in here.
Acceptance
Either the five steps hold on one clean run (then #866's in-room half is done and this issue closes with the evidence), or the step that breaks becomes its own bug with the exact reading (endpoint, response, screenshot) — and this issue then closes as superseded by it.
No code change is expected in this issue. A red here is a bug report, not a fix candidate, unless the red is in the card's own wording, which would be a one-line follow-up.
Related
- Wrap up bot-social #43 on the FlyBot side: a send into a claimed room must name its room #866 — the umbrella (in-room half; its 1:1 half is A ticket-claimed (room-only) Bot cannot send a 1:1 line into the room it shares: the member check runs before the room lookup #948).
- A ticket-claimed (room-only) Bot cannot send a 1:1 line into the room it shares: the member check runs before the room lookup #948 — the ticket-claimed Bot refused at
social.js:1603-1608before the room path runs. - A line to a friend's Bot that is gone fails with a raw, doubled reason and an unusable Retry #954/A send that can never succeed still shows \"Not sent: peer has not granted chat.public. Try again.\" #971 — the "one sentence, never a raw code" rule this should follow.
Written-by: Triage
Corrected 2026-10-24, from the first real run (SelfTest)
Two corrections to the steps above, one of them mine:
- The held line is not "the guest's line arriving at the host". With Auto-send off, what is held is each home's own Bot's room reply: the host's screen shows its own Bot (
Chief (SelfTest B2) → the room,holdReason: face_room_auto_send_off,roomId: frm_01M5Q12SJ9…), the guest's screen shows its own. The card correctly names the Bot whose reply is held — step 2 read as "name the guest's Bot" describes a different mechanism. Corrected expectation: the card names the Bot whose reply is being held, that Bot's home, and the room. → the roomis not enough. The card shows no room name and no number, so two open rooms make it ambiguous which line it holds. That is a wording defect, not a blocker, and it belongs in the same run: the card should carry the room's name or its number.
Steps 3 and 4 (what approving and rejecting does to the transcript) are blocked on #979 — the room transcript currently fails with Maximum call stack size exceeded (gateway/internal), so "did the line land in the room" cannot be read. The room is still open; the re-run should use it rather than spend another face-join.
#866 stays open until this run completes: a card that appears is not the same as a card that works.
Activity
Birfy commentedon Oct 24, 2026
Ran this on
main 90f4bb5a(two isolated installs, real UI, one room with both seats). One step is now proven, two are blocked by a new client bug, and one premise needs correcting.What is proven (new)
The room's own input box does make the card — the thing
social/face-sendcould never do:kind: face_room_message,roomId: frm_01M5Q12SJ9K380478GVN5A3B49,toName: "the room",holdReason: face_room_auto_send_off,autoSendHold: true.Waiting for approval / Chief (SelfTest B2) → the room / <the line> / Approve / Reject / Auto-send from now on. So it is not a bareface_room_message, it names the Bot that wants to speak, and it offers the two decisions plus the standing toggle.Premise that needs correcting
The held line is each home's own Bot reply, not the guest's line arriving at the host. With Auto-send off for face rooms, the guest's typed line goes into the room, and then the guest's Bot reply is held on the guest's screen (
Chief (SelfTest B2) → the room), while the host's own Bot reply is held on the host's screen (Chief (SelfTest A2) → the room). Both cards carry the same mock reply text because both models answer the same line.So step 2 as written ("an approval card appears for that room, naming the room and the guest's Bot") describes a different mechanism than the one the code implements. The card does name the Bot — the one whose line is held. If the intent was "the guest's message is held at the host", that is not this design and the acceptance should say so.
One wording nit that survives: the card says
→ the roomand never names the room or its number, even though the hold carriesroomIdand the room has a name (Face-to-face · SelfTest A2, SelfTest B2 · 647181). With two rooms open, "the room" is ambiguous. Not worth its own issue unless it is bundled with other card copy.What is blocked
Steps 3 and 4 (approve → line enters the room; reject → nothing delivered and the guest reads a sentence) could not be observed, because the room's transcript does not render on this tip:
on both homes, plus
pageerror: Maximum call stack size exceededtwice per page, across five page loads. Filed as #979.My automation also could not reliably click
Approveon the card (the card stayed after the click) — I will not call that a defect until #979 is fixed and the transcript can confirm what happened; it may be my selector.Recommendation
Per this issue's own acceptance: #977 is superseded by #979 rather than closed green. Once #979 is fixed I will rerun the same probe and finish steps 3 and 4 (the room is still open, so no new join quota is needed).
Repro script:
probe-977b-room-card.mjsandprobe-977c-approve-reject.mjson the self-test bench.Birfy commentedon Oct 24, 2026
Steps 3 and 4 do not need the room transcript — everything the card decides is visible through FlyBot's own API, so this can finish before #979 is settled. Read the room's local id first:
flybot/social/face-rooms→ the entry whosefaceRoomIdisfrm_…hasroomId(that is the idroom-historywants; do not pass thefrm_one).Step 3 — approve.
flybot/social/approvalson the home holding the card → the item hasid,kind: "face_room_message",roomId,botId,text.flybot/social/decide-approval { approvalId: <id>, decision: "approve" }→{ approvalId, status: "approved" }.room-history { roomId: <local room id> }must now contain a line whosetextis exactly the held text (author is the Bot's label, e.g.Chief (SelfTest B2)), and the item must be gone fromflybot/social/approvals.Step 4 — reject.
Same three calls with
decision: "reject", on a fresh held line:room-historyon both homes must be unchanged (same length, same last line), the item gone fromsocial/approvals. The "not sent" sentence and the grey line are client-only, so only assert those in the UI if you want them — they are not API-visible.Negative control: a 1:1 line outside the room never appears in
room-historyof any room, and never changes the room's length.room-historyis a plain/api/botendpoint with the member cookie;decide-approvalgoes throughflybot/on the same route. Written-by: Dev2Name the room on a held room-line approval card (ThinkFlowLab#991) (T…
Birfy commentedon Oct 25, 2026
Written-by: Triage
Re-triaged on
main 97065bac: this isneeds-info, and the label is precise rather than a parking space. What it asks for is a reading, not code — the issue itself says no code change is expected — and two things gate that reading:#979— the room transcript currently dies withMaximum call stack size exceeded; without the transcript, steps 3 and 4 (“did the line land in the room” / “what did the guest read after a reject”) cannot be observed. The fix has to land first, and the note in the body already says to reuse the open room rather than spend another face-join.social/face-send(social.js:3845) never callsrememberHoldRoom,rooms.onFaceLine(:3705) does at:3731, andpendingApprovalsdrops aface_room_messagehold that names no room (:2917). A probe that builds the hold throughsocial/face-sendmeasures the probe, which is what the earlier attempt did.Correction from the first real run is already in the body and it stands: with Auto-send off, the held line is each home's own Bot reply (
holdReason: face_room_auto_send_off), so the card must name the held Bot, its home, and the room — and “→ the room” alone is not enough to disambiguate two open rooms. That second half is a one-line wording follow-up if the run confirms it.Not
agent-ready: no Dev can close this by opening a PR, and marking it ready would put a permanent entry in the “ready and no PR” count. It closes on a run report, or on the broken step becoming its own bug.Birfy commentedon Oct 28, 2026
Written-by: Triage
agent-ready — promoted for the bench run. The blocker recorded on 2026-10-25 is gone: #979 is closed completed, fixed by #1587 (merge commit
43502f99, onmain fbbf3c069d), so the face-room transcript renders and steps 3 and 4 can actually be read. The expected card reading is the one corrected in the body: the card names the Bot whose reply is held, that Bot's home, and the room.Files to touch: none in
core/orplugins/expected — this is a verification card, not a fix. The run is the recorded two-home bench probesprobe-977b-room-card.mjs(card creation, already green on90f4bb5a) andprobe-977c-approve-reject.mjs, real UI, no mocks. Reuse the open roomfrm_01M5Q12SJ9K380478GVN5A3B49if it is still live, so no new face-join is spent; otherwise one fresh room.Acceptance — run at
fbbf3c069d, on both homes, paste the raw responses:flybot/social/face-rooms→ take the entry whosefaceRoomIdisfrm_…and use itsroomId(never thefrm_id itself).flybot/social/approvalson the home holding the card → an item withid,kind: "face_room_message", thatroomId,botId,text.flybot/social/decide-approval { approvalId, decision: "approve" }→{ status: "approved" }; thenroom-history { roomId }on both homes carries exactly one line whosetextequals the held text, and the item is gone fromflybot/social/approvals.room-historyon both homes is unchanged (same length, same last line), and the item is gone fromflybot/social/approvals.room-historyand never changes a room's length.Red first: before deciding anything, assert on both homes that
room-historydoes not yet carry the held text, and record itslengthas the baseline. That assertion is the red — it fails if the line lands without a decision, or if the transcript still refuses to load. Then run 3–5 and keep those lengths as the delta the card has to move by exactly one.Per the issue's own acceptance, a red step becomes its own bug with the exact reading (endpoint, response, screenshot); do not fix it in this card. The one exception remains the card copy (
→ the roomwith no room name or number): if the run confirms it, that one-line follow-up belongs here.Birfy commentedon Oct 28, 2026
Written-by: Chief
Parked to
needs-human(owner decision still open), so no workflow line picks it up again.What the card needs — the room-line approval card has to be proven end to end on a real two-home bench: two homes on :3090 / :3091, a Bot in a shared room, and a human typing in the room input box so the approval card is actually produced and clicked. No line in the pipeline can do that: the issue fast line (
wf-1cdf6ec5) runs Triage>Claim>Gate>Enqueue and has no bench step, and the PR lines only read diffs.The one thing needed from the owner: run it once on the instance the owner actually uses (
flybot98b8ecba), or say that a bench-capable verification exit should be added to the issue fast line. Until then this stays here instead of blockingagent-ready.Checked at 2026-10-28T20:35Z:
agent-readywas this issue alone, maina00658ccc97b, 0 open pull requests.Birfy commentedon Oct 28, 2026
Written-by: Chief
验证出口已经加进 issue 快线(
wf-1cdf6ec5),这一单按「取证型」重新排队(i977-verify)。Claim现在先判形态:需要源码改动就走原来的认领→开分支→PR;不需要源码改动(本单就是)就直接status: verify-only,不 assign、不打agent-working、不开分支。这一步不改变本单的验收:房内输入框真能做出审批卡、并能在卡片上批一次。
Birfy commentedon Oct 28, 2026
Written-by: cadb
环境(先列缺件,再说补了什么)
a00658ccc97b(bench 拉到的 main,Release v0.2.13)。.dsh-test-a(web 3096 / mock 8796)与.dsh-test-b(web 3097 / mock 8797),真实 Bot Social(social.botawaken.com),mock 模型。3090/3091 本机没有监听;bench 的固定端口是 3096/3097。/opt/flybot);无 DISPLAY,全部 headless。/data/uiprobe已不存在(原 playwright/browser 目录被清掉),本机也没有 chromium。本次重建了/data/uiprobe:Playwright 1.56.1 + Chromium 141.0.7390.37(build 1194)+ Debian bookworm 的 sysroot(libnss3/libgbm/libasound/libX*/libsqlite3 等)。frm_01M62AF8TZMPVAYFEY4HJZC1TE,Face-to-face · SelfTest A2, SelfTest B2 · Oct 28 22:35,两席(@chief.selftesta2.home / @chief.selftestb2.home),open。最后一轮复用了这间房,没有新花 face-join;它的 10 分钟加入窗口过了,但 open 状态一直保持。跑了什么
node run.mjs --keep --skip-fetch(selftest bench)起两 home;报告state/run-2026-10-28T22-36-55-344Z.json。node clean-977.mjs:A 的房内输入框(placeholderMessage Face-to-face · … · Oct 28 22:35)type 一行 + Enter → 取 hold/卡片 → 在卡上点 Approve;再来一行 → 在卡上点 Reject;最后发一条 1:1 作对照。node reject-card.mjs:单独复核 Reject 卡在轮询稳定后是否可点、点后是否真的不送达。flybot/social/face-rooms(faceRoomId→每 home 自己的 localRoomId)、flybot/social/approvals、flybot/social/decide-approval(只在卡片点不动时兜底,本轮没用上)、room-history {roomId: <localRoomId>}。观测(按验收的 5 步)
1. 房内输入框做出审批卡:做到了。
在房内输入框发送后,A 侧出现 hold:
kind: face_room_message、roomId: frm_01M62AF8…、botId: bot_01M5CM8SSS…、holdReason: face_room_auto_send_off、autoSendHold: true、text: 我负责自己那一摊,有需要直接点我。。屏上卡片:2. 卡面写明被 hold 的 Bot、它的 home、房名:做到了。 卡面是
Chief (SelfTest A2) → the room Face-to-face · … · Oct 28 22:35,不是裸face_room_message。本 tip 卡面已经带上房名/号码,原来“→ the room 无法区分两间房”的文案跟进在这一版已经不成立(只是读起来是 “the room <房名>”,略拗口)。3. 在卡上批准:点得动,另一端 +1;但“两 home 各 +1”按实际读数不成立。
Approve(没有走decide-approval兜底):hold 条目消失;B 13→14,新行正文等于被 hold 的正文(远端包装成<untrusted-message from="Chief (SelfTest A2)">…)。4. 在卡上拒绝:做到了,但验收基线要按“回显之后”取。
Reject:hold 条目消失;6 秒后 A 13→13、B 16→16,末行也不变,B 侧没有出现 A 的第二条 Bot 回复。Chief · Not sent(截图里可见),不是静默丢弃;这句是客户端文案,API 不可见。5. 1:1 对照:做到了。 B 给 A 发一条 1:1(
social/send,返回action: hold,approvalIdd43860a9…):A/B 的 room-history 都不变(13/16),flybot/social/approvals里没有face_room_message条目,A 屏上也没有→ the room的卡。没做到 / 需要下一轮
Face-to-face · … · Oct 28 22:35;B 的侧栏 9 行 Face-to-face 里没有它(刷新页面后仍没有),但 B 的face-rooms/room-historyAPI 都正常。所以“来客在自己的房内输入框发一句、自己点一次”这半边本轮没跑;B 侧只验了 API 和 transcript。Waiting for the owner's approval、没有按钮(同一时刻 approval 已经 pending)。代码里是waitingOthers = mine.length === 0 && (room?.pendingCount ?? 0) > 0,而 approval 列表 5s 轮询;reject-card 那轮 +1s 已经可点。属轻量 UI 竞态,不挡批准/拒绝,但值得记一笔。face-start后 1–3 秒内房间在一侧变closed(当时两边 UI 都还没开房;先是 B 侧、后是 A 侧),随后另一侧也跟着关。第三次改成“两 home 先打开房间视图,再 face-start”,房间就一直 open。形态像social.js的faceSnapshotPast在成员列表瞬时为空时走peersGone关闭(Revoke access silently degrades shared face-to-face room #1072/Face room titles/Past rooms: number dropped from title, Past rows show start or future deadline time, staying home marked 'Left' and never leaves on Bot Social, closed tab title (#250 regression) #304 一带),但本轮没定性,也没开新单。证据
本机路径(都在
/data/dsh/bot/workspace/v977/evidence/):20-card-approve.png、21-after-approve.png、22-card-reject.png、24-reject-card.pngresult-clean.json(hold/卡片文本、批准前后的长度)、reject-card-dom.json(可点卡 + Approve/Reject 按钮 + pending 条目)timing.png(房内输入 → hold + 卡片同时存在)clean-977.mjs、reject-card.mjs、probe-977.mjs;bench 报告在selftest/reports/。一句话:房内输入框真能做出卡片,卡片能点 Approve/Reject,批准把行送到另一端且条目消失,拒绝不送达且留一句 “Not sent”,1:1 不冒充房卡;没验到的是 B 侧屏上的那一份(B 侧栏缺这间房),以及“两 home 各 +1”这条验收文本与实际的本地回显不一致。没有改代码、没有动标签、没有入队。
Birfy commentedon Oct 28, 2026
Written-by: Chief
取证回来了(
run-4063302a的「取证」节点,2026-10-28T22:53Z 完成;原始记录见上面Written-by: cadb的评论)。三条结论:1. 这条 issue 的原始命题已不成立,按 completed 关闭。 房内输入框确实能做出审批卡,卡面写明
Chief (SelfTest A2) → the room Face-to-face · … · Oct 28 22:35,卡上 Approve 与 Reject 都点得动——不是「只能走 API」。原来的文案跟进「→ the room无法区分两间房」在 v0.2.13 上也不成立了(已带房名)。2. 验收文本更正一条:第 3 步的「两 home 各恰 +1」与本版实际行为不符。 发话方本地先回显(自己的房间立刻能看到自己那条 Bot 回复),批准只把行送到房间另一端,所以批准后的读数是发话方 +0、另一端 +1。这是有意的本地回显,不按缺陷处理;这条验收改按「批准把行送到房间另一端」读,已做到。若以后要验收「本地回显」本身,另开单。
3. 拒绝与 1:1 对照都成立。 Reject 后两边长度不变、B 侧没有出现第二条,房内 transcript 留一句
Chief · Not sent(不是静默丢弃);1:1 那条 returnedaction: hold但不出房卡,不冒充。没验到的两半是别的缺陷,各自开单,不记在这条上:
face-roomsAPI 正常,刷新无效),所以「来客自己那半」做不出来。face-start后 1–3 秒房间翻成closed(两边 UI 都没开房时);把顺序倒过来才稳。Waiting for the owner's approval且无按钮(approval 已 pending,5s 轮询落后一拍)。三条都是
needs-info:单次观测、要确定性复现才能写红先测试,等一次 Triage 轮决定要不要做成agent-ready。bench 已停,3096/3097 无残留。