Skip to content

client: a read-only window's new-group composer still draws a Send arrow that silently does nothing once an admin is chosen - #2504

Open
HugoXK wants to merge 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-composer-groupadmin-locked
Open

HugoXK wants to merge 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-composer-groupadmin-locked

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2503
Fixes #2506

Owner: Dev-2
Reviewer: Birfy
Written-by: FlyBot Dev-2
Claim-Id: 7a28ae9f7eb744ac9719db7351b3e7e2
Risk tier: T1

What changes

Two read-only shapes still drew a control whose press could only earn the host's bot/read-only. They sit on the same screen and the same bundle lane, so one PR closes both; each has its own case and its own acceptance below.

#2503 — a new group chat that already picked its admin. #2499/#2501 stopped the writes, but the composer ternary excluded exactly the group && admin !== null shape from the host's sentence (that sentence is drawn on the To: line, where Create group chat would be), so the composer fell through to a live Send button in a window where sendMessage returns at new-chat.js:146 before any branch. In a locked window the composer now draws no Send in any shape: where the button was it shows the host's own sentence (hostText(roster.readOnly), .bt-hint.bt-read-only, role="status"), and in the group-with-admin shape that sentence already stands on the To: line, so the composer draws nothing and the view carries it exactly once.

#2506 — the New… menu's Add coding agent row. addAgent is add-agent, a write the host refuses (core/src/host/channel.js:310-312, READS does not carry it), and the row's if ((roster.agents ?? []).length === 0) never read lockedWindow even though the same function computes locked at :42. A locked menu now does not draw the row at all — it is not replaced by a sentence, the menu is a preview — while the other rows (New chat, New Bot, New group chat, a plugin row) stay drawn, and a writable window keeps the row.

Scope is those two guards, the two regression cases in one test file, the #2501 docs sentence made true per shape plus the menu's own item, and two changelog fragments. The send path, makeGroup's own locked guard, the To:-row sentence, the Create paths #2496 already locked, service.js and core/src/host/** are untouched.

Acceptance — #2503

In a read-only window, New… → New group chat → choose the admin → pick one more Bot → type a line:

  • the composer draws no Send control at all — the case asserts sendButton(nodes) === undefined, not merely that a drawn button is disabled;
  • Enter in the composer reaches the host with nothing: calls is empty, so no send and no create-room;
  • the host's own sentence appears exactly once, in one .bt-hint.bt-read-only whose text is hostText(roster.readOnly), on the To: line where Create was;
  • the writable control next door is unchanged: Send is drawn and enabled, one press is [['send', 'scout', 'hello there'], ['open-session', 'scout']], several picks are create-room then send then open-session, and no read-only line is drawn.

Acceptance — #2506

In a read-only window, the New… menu (mode: 'new', no To: row, no composer):

  • the menu itself is drawn (New group chat is there) and the Add coding agent row is not: the case asserts the row is absent, not that a drawn row does nothing;
  • with the row absent there is no press to make, and drawing or pressing nothing writes nothing: calls stays empty; no add-agent reaches the host, so no bot/read-only comes back;
  • the writable control next door is unchanged: the row is drawn and exactly one press sends exactly one ['add-agent'].

Red first

Both cases fail on the clean base 550fb3ac with the base source in place and only the test file from this branch:

not ok 4 - a read-only window draws no Send for a group that still has its admin chosen
    the composer draws no live Send control
  - undefined
  + { type: 'button', className: 'bt-nc-send', disabled: false, onClick: [Function: sendMessage] }
not ok 6 - a read-only New… menu draws no Add coding agent row
    no Add coding agent row in a read-only window
    true !== false
# tests 7
# pass 5
# fail 2

They are independent: with both fixes in place, putting back only the composer ternary (locked && !(group && admin !== null)) leaves # pass 6 / # fail 1 with case 4 the only red, and dropping only !locked from the Add coding agent guard leaves # pass 6 / # fail 1 with case 6 the only red. With both in place the file is 7/7 green.

What I ran at 4a3798c0ef4f2d2a8f18b23b4e69eb7892a97b92 (TZ=UTC, clean tree, tree bf57d007)

  • npm run build (core), then node scripts/ds-bot-patches.mjs generate twice and a third time: the working diff is byte-identical between rounds (git diff | sha256sum equal), so generate is idempotent here.
  • node scripts/ds-bot-patches.mjs check — ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70, ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/.
  • TZ=UTC ARCH_DOCS_BASE=550fb3ac7d8eb74b749c1accf7586b0eb6d8a321 npm run verify — exit 0. Segment counts, each # fail 0: core 2915 passed, plugins/social 577, plugins/tree 137, plugins/timeline 141, plugins/workflow 440, .github/scripts + policy 671, test:interop 37, test:live-e2e 26 — 4944 tests, 0 failed. Lint: 0 errors (78/36/9/2/16 warnings, none in the files this PR touches); build-client.mjs --check and ds-bot-patches check/canonical green in the same run.

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.

Files

9 files, +123/−21 (git diff --numstat 550fb3ac...4a3798c0ef4f2d2a8f18b23b4e69eb7892a97b92), tree bf57d007:

  • core/src/client/new-chat.js (+7/−4) — the composer ternary and the menu row's guard, hand-written.
  • core/test/composer-send-readonly.test.js (+48/−2) — both regression cases plus the two writable controls, hand-written.
  • docs/subsystems/core-client.md (+1/−1) — the #2499 bullet now says the sentence stands on the To: line for this shape and the composer draws nothing, and the New… menu's item joins it.
  • changelog.d/2503-composer-group-admin-locked.fixed.md (+1), changelog.d/2506-newchat-add-agent-locked.fixed.md (+1) — new fragments.
  • core/client.js (+2/−2), patches/ds-bot/0003-flybot-api-client.patch (+11/−7), patches/ds-bot/0008-client-bundle.patch (+4/−3), patches/ds-bot/files/test/composer-send-readonly.test.js (+48/−2) — generated by build + generate, never hand-edited.
{
  "pr": 2504,
  "claim": "Dev-2",
  "issue": 2503,
  "summary": "Two read-only shapes that drew a control the host refuses are gone: a group composer whose admin is already chosen no longer draws a Send arrow that does nothing (the host's sentence stays once, on the To: line), and the New… menu no longer draws Add coding agent, whose add-agent the host answers with bot/read-only. Each has its own failing case and its own writable control, and this PR closes #2503 and #2506.",
  "files": [
    "core/src/client/new-chat.js",
    "core/test/composer-send-readonly.test.js",
    "docs/subsystems/core-client.md",
    "changelog.d/2506-newchat-add-agent-locked.fixed.md"
  ],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=550fb3ac npm run verify (plus npm run build and ds-bot-patches generate/check)", "result": "green", "at": "4a3798c0ef4f2d2a8f18b23b4e69eb7892a97b92" },
  "next": "none — ready for review"
}

@HugoXK
HugoXK force-pushed the dev/2-composer-groupadmin-locked branch from 999a8ac to 4a3798c Compare November 5, 2026 05:53
@HugoXK
HugoXK marked this pull request as ready for review November 5, 2026 05:59
@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Queue request — please take this tip to the merge queue.

  • Head 4a3798c0ef4f2d2a8f18b23b4e69eb7892a97b92, base 550fb3ac7d8eb74b749c1accf7586b0eb6d8a321, closes #2503 and #2506.
  • enqueue-guard on this tip: enqueue #2504: no hold and the gate passes — decision enqueue client: a read-only window's new-group composer still draws a Send arrow that silently does nothing once an admin is chosen #2504, and it records no PASS needed: computed tier T1.
  • Tip state: non-draft, mergeable: true / clean, maintainer_can_modify: true, 17 check runs = 17 success + 0 cancelled, 0 failure.
  • tests-ok is green on this exact tip.
  • FlyBot Test's independent advisory is PASS at the same tip (4a3798c0): verify 4944 passed / 0 failed; red-first 7/5/2 on base 550fb3ac with case 4 (#2503) and case 6 (#2506) each failing on its own; each half-revert leaves exactly its own case red (6/1 twice); writable render trees are deep-equal to the base. Advisory only, as usual for T1.
  • Two defects, one evaluable bundle: #2506 was folded into this PR after #2504's branch already carried #2503, with Chief's conditions met — a separate failing case per defect, two Fixes lines, two acceptance sections, and a pointer comment on #2506. If review wants them split, say so and Dev-2 will split.
  • FlyBot Dev-2 is standing by and will not push a new tip; the branch is dev/2-composer-groupadmin-locked in HugoXK/FlyBot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant