Skip to content

client: a read-only window's face-room overview still draws the Room lead's Change, and a hint that is false there - #2513

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-face-lead-readonly
Nov 5, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-face-lead-readonly

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2512

Owner: Dev-2
Reviewer: Birfy
Written-by: FlyBot Dev-2
Claim-Id: 660434858f894844b50bfa7688ee56ae
Risk tier: T1

What changes

A read-only (locked) window's Drawer overview of a face-to-face room still drew the Room lead card's Change, and, for anyone the host reports as not able to pick, the sentence Only the person who created this room can change it.. Neither belongs there:

  • social/face-lead is registered without { read: true } (plugins/social/src/social.js:4684), so the host's channel layer answers it bot/read-only. Pressing Change is therefore a live-looking control whose only possible result is a refusal.
  • the "only the person who created this room" sentence is false for the creator in a locked window: the creator can change the lead, just not from this window, so the line explains the wrong reason.
  • FaceLead (core/src/client/group-settings.js) decided with lead.canPick === true && typeof pick === 'function', and the host reports canPick: true for the room's creator regardless of the window (plugins/social/src/face-rooms.js:519, core/src/host/face-lead.js:29 passes it through). The card already receives the roster, so it can tell a locked window from a writable one itself; nothing has to be threaded down from details-drawer.js.

The fix is one guard in the card: FaceLead reads lockedWindow(roster) (the same helper every other read-only surface uses, core/src/client/schedules.js:141), folds it into canPick (!locked && lead.canPick === true && typeof pick === 'function'), and skips the only-the-person hint when locked. A locked card keeps the lead's name, its Bot (person) label, its Lead tag and the sentence about what the lead does; it draws no Change, no picker, no Make lead, no Use the default lead and no refusal hint. A writable window is byte-identical to the base: Change → picker → one press sends exactly one social/face-lead, and a non-creator still reads the only-the-person sentence.

Rebased onto 523a384298f9f7989147ca25a2fd2b219ffd1d46 (#2510, merged after this branch was first pushed). The rebase again merged patches/ds-bot/0008-client-bundle.patch and patches/ds-bot/0012-room-membership.patch without a textual conflict; build-client + ds-bot-patches generate then rewrote the same bytes, so git status --porcelain is empty and no patch file was hand-edited.

Scope: core/src/client/group-settings.js, one new test file, one doc sentence, one changelog fragment, and the regenerated core/client.js plus the patches/ds-bot/ copies the repo's build requires. details-drawer.js, the host's social/face-lead registration, face-rooms.js and every other read-only surface are untouched.

Acceptance

In a read-only window, opening a face room's Drawer overview:

  • the Room lead card is still drawn and still names the lead (Room lead, Chief (Ann)) with the sentence about what the lead does;
  • the card offers no button at all — the case asserts buttonLabels(card) is [], not merely that a drawn button is disabled — so Change, Make lead and Use the default lead are all absent;
  • the Only the person who created this room can change it. hint is not drawn (it is false for the creator here), for the creator and for a non-creator alike;
  • drawing the card reaches the host with nothing (hostCalls is empty), so nothing is attempted and no bot/read-only can come back.

The neighbouring writable control, in the same test file, is unchanged: Change is drawn, pressing it lists the other seat with Make lead, one press is exactly [['social/face-lead', { roomId: 'face', bot: '@writer.bob.home' }]], someone who is not the creator still sees no Change and does read the only-the-person sentence.

Red first

On the clean base 523a384298f9f7989147ca25a2fd2b219ffd1d46 (the rebased base), in a throwaway detached worktree at that commit with the base source untouched and only this branch's test file added, node --import ./test/harness-resolve.mjs --test test/details-face-lead-readonly.test.js under TZ=UTC:

not ok 1 - a read-only window draws the room lead as text: no Change, no picker, no refusal hint
    the card itself offers no control
  + [ 'Change' ]  − []
not ok 2 - a read-only window draws no Change for the creator and no refusal hint for anyone else
    the creator cannot change the lead in a read-only window either
  + { type: 'button', props: { className: 'bt-mini', children: [ 'Change' ], onClick: [Function: onClick] } }  − undefined
ok 3 - a writable window keeps Change, the picker and exactly one social/face-lead write
# tests 3
# pass 1
# fail 2

These are the same two not ok lines the pre-rebase run produced on e5fc62dea0c067a308fbf8f122d691a35e455fb1: 3 tests, 1 pass, 2 fail. With the fix in place the same file is 3/3 green, and the writable positive control is unchanged from the base.

What I ran at b8e4b8fa66f7b00afacc8a5c9480c140d5c479b6 (TZ=UTC, clean tree, tree b50e5031)

  • node core/scripts/build-client.mjs then node scripts/ds-bot-patches.mjs generate on the committed tree: both wrote the same bytes back (git status --porcelain empty afterwards), and npm run verify's own canonical gate reports ok patches/ds-bot/ is what generate writes (generate is a no-op).
  • node scripts/ds-bot-patches.mjs check (inside verify) — three ok lines: ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5), ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/; canonical — ok patches/ds-bot/ is what generate writes (generate is a no-op); a second generate + build-client run afterwards leaves git status --porcelain empty (idempotent).
  • TZ=UTC ARCH_DOCS_BASE=523a384298f9f7989147ca25a2fd2b219ffd1d46 npm run verify — exit 0. Segment counts, each # fail 0 and # cancelled 0: core 2927 success + 0 cancelled, plugins/social 577 + 0, plugins/tree 137 + 0, plugins/timeline 141 + 0, plugins/workflow 440 + 0, .github/scripts + policy 671 + 0, test:interop 37 + 0, test:live-e2e 26 + 0 — 4956 success + 0 cancelled, 0 failed. arch-docs: OK (8 changed file(s)); every lint stage exit 0 with 0 errors (warning counts 81/36/9/2/16, unchanged from the base commit); build-client.mjs --check exit 0 in the same run.
  • The 13 neighbouring read-only suites (face-lead, settings-readonly-pages, settings-readonly-head, details-bot-settings-readonly, details-face-lead-readonly, details-group-overview-readonly, details-group-settings-readonly, details-overview-readonly, room-approvals-readonly, group-create-readonly, composer-send-readonly, readonly-window-reads, approvals-readonly): 52/52, 0 failed.
  • git status --porcelain — empty on the committed tree.

What I did not run

  • The host smoke test and a live service on a bench port — this change is client-only (core/src/client/**), no host code.
  • #2509 / #2510's surfaces and any other read-only card — out of scope for this issue and untouched here.

Files

8 files, +400/−11 (git diff --numstat 523a3842...b8e4b8fa), tree b50e5031:

  • core/src/client/group-settings.js (+8/−2) — FaceLead reads lockedWindow(roster), folds it into canPick, and skips the only-the-person hint when locked; hand-written.
  • core/test/details-face-lead-readonly.test.js (+187, new) — the two read-only cases plus the writable positive control; hand-written.
  • docs/subsystems/core-client.md (+1/−1) — the face-room lead paragraph gains the locked-window sentence and points at the test.
  • changelog.d/2512-face-lead-readonly.fixed.md (+1, new).
  • core/client.js (+3/−2), patches/ds-bot/0008-client-bundle.patch (+4/−3), patches/ds-bot/0012-room-membership.patch (+9/−3), patches/ds-bot/files/test/details-face-lead-readonly.test.js (+187, new) — generated by build + generate, never hand-edited.
{
  "pr": 2513,
  "claim": "Dev-2",
  "issue": 2512,
  "summary": "A read-only window's face-room overview no longer draws the Room lead card's Change: social/face-lead is a write the host answers bot/read-only, and the host still reports canPick true for the room's creator. FaceLead now reads lockedWindow(roster) itself, so canPick is false even for the creator and the 'only the person who created this room' hint is skipped as false there. A locked card keeps the lead's name and its sentence only; a writable window is unchanged, one press still sends exactly one social/face-lead.",
  "files": [
    "core/src/client/group-settings.js",
    "core/test/details-face-lead-readonly.test.js",
    "docs/subsystems/core-client.md",
    "changelog.d/2512-face-lead-readonly.fixed.md"
  ],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=523a3842 npm run verify (plus build-client and ds-bot-patches check/generate)", "result": "green", "at": "b8e4b8fa66f7b00afacc8a5c9480c140d5c479b6" },
  "next": "none — ready for review"
}

@HugoXK
HugoXK marked this pull request as draft November 5, 2026 07:11
@HugoXK
HugoXK force-pushed the dev/2-face-lead-readonly branch from aed40ab to fc6a6fa Compare November 5, 2026 08:03
@HugoXK
HugoXK marked this pull request as ready for review November 5, 2026 08:12
@HugoXK
HugoXK marked this pull request as draft November 5, 2026 08:18
The face room's lead card (FaceLead) offered Change whenever the room said canPick, and the host keeps canPick: true for the creator in a read-only window while refusing social/face-lead with bot/read-only. The card now reads lockedWindow(roster) too: the lead's name and its sentence stay, the button, its picker and the "only the person who created this room" hint go. A writable window is unchanged.
@HugoXK
HugoXK force-pushed the dev/2-face-lead-readonly branch from fc6a6fa to b8e4b8f Compare November 5, 2026 08:59
@HugoXK
HugoXK marked this pull request as ready for review November 5, 2026 09:29
@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Enqueue request — PR #2513 at b8e4b8fa66f7b00afacc8a5c9480c140d5c479b6

  • Closes client: a read-only window's face-room overview still draws the Room lead's Change, and a hint that is false there #2512; branch dev/2-face-lead-readonly (fork HugoXK/FlyBot), 1 commit, 8 files +400/−11
  • Base 523a384298f9f7989147ca25a2fd2b219ffd1d46 (live main)
  • mergeable: true, mergeable_state: clean; draft: false; maintainer_can_modify: true
  • Risk tier T1 (no PASS needed); the branch is ours
  • Checks at this tip: 17/17 success — 0 failure, 0 cancelled, 0 pending
  • Test advisory: PASS at b8e4b8fa66f7b00afacc8a5c9480c140d5c479b6
  • Advisory self-test at the same tip: verify 4956 passed / 0 failed / 0 cancelled (core 2927, social 577, tree 137, timeline 141, workflow 440, .github+policy 671, interop 37, live-e2e 26); arch-docs: OK (8 changed file(s)); build-client --check exit 0; 10 patches apply cleanly in order; core/ equals ds-bot/ + patches/ds-bot/; generate is a no-op; lint 81 warnings / 0 errors (the one new warning is in the new test, same pattern as an existing test)
  • Regenerated artifacts: only patches/ds-bot/0008-client-bundle.patch (+4/−3) and patches/ds-bot/0012-room-membership.patch (+9/−3), the patch that carries core/src/client/group-settings.js, plus the new mirror patches/ds-bot/files/test/details-face-lead-readonly.test.js (+187, byte-identical to the source test)
  • Red-first on a clean 523a3842 with only core/test/details-face-lead-readonly.test.js added: 3 tests / 1 pass / 2 fail; 3/3 after the fix

Please enqueue.

@Birfy
Birfy added this pull request to the merge queue Nov 5, 2026
Merged via the queue into ThinkFlowLab:main with commit d1ea853 Nov 5, 2026
17 checks passed
@Birfy
Birfy deleted the dev/2-face-lead-readonly branch November 5, 2026 09:40
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.

client: a read-only window's face-room overview still draws the Room lead's Change, and a hint that is false there

2 participants