Skip to content

client: a read-only window's Settings → Workflows graph page draws the host sentence twice - #2535

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/4-workflows-duplicate-sentence
Nov 5, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/4-workflows-duplicate-sentence

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2524

Owner: Dev-4
Reviewer: Birfy
Written-by: Dev-4
Claim-Id: 8a85ea8d0d52462688308708bb3f234c
Risk tier: T1
Base: 90a5944

What changed

In a read-only window, Settings → Workflows drew the host's standing read-only sentence twice as soon as a graph was open. The Settings dialog header prints that sentence once per page, with Reload (core/src/client/settings.js, the bt-readonly-line-head line); the open graph's edit bar printed a second copy under role="status" (core/src/client/workflows.js, the locked branch of the edit bar). Two live regions carrying the same words are not only a visual duplicate: they are announced twice. The repo's own contract is core/test/settings-readonly-pages.test.js — "the standing sentence stays in the dialog header, once per page" — but its PAGES list and readonly-reload-lines.test.js's SURFACES never listed workflows, so CI stayed green.

After: with a workflow graph open in a read-only window the screen carries exactly one copy of the sentence, in the header, with Reload; the edit bar keeps Back only and adds neither a second live region nor a second Reload. A writable window is unchanged: Edit / Finish editing and Use this behave exactly as before.

The change is the edit-bar branch — locked ? null : … — plus dropping hostText from that module's imports. No page is left without a copy of the sentence: WorkflowsView is rendered only by WorkflowsPage, which is rendered only by the Settings dialog (settings.js), so the header's sentence and its Reload cover the whole screen. No second Reload is added here on purpose; the header's one is that screen's way out.

Tests. New core/test/workflows-readonly-once.test.js renders the real SettingsDialog({page:'workflows'}) header and the real WorkflowsView({phase:'ready', pack, opened:{source:'own', id:'w1'}, roster: locked}) edit bar, counts the sentence by text on the rendered tree (not by class, not by role), and asserts header + edit bar = 1, editing bar = 0, and that the edit bar is not a live region. It also keeps Back, hides Edit in a locked window, and checks a writable window keeps Edit and draws no sentence.

core/test/workflows-page.test.js's #2176 case changes with the contract: it asserted the page itself draws the sentence, which is exactly what this issue reverses. That is a test of the old contract moving, not a test bent to make a fix pass — it fails on the base with the new contract, and the negative it carries ("the edit bar adds no second copy of the host sentence") is the assertion that catches this bug.

docs/subsystems/core-client.md's Workflows line said the page "draws that sentence where Edit was", now the opposite of the code; it says the Settings header prints the sentence once per page (#2202) and the graph's edit bar shows Back only. One user-visible line in changelog.d/2524-workflows-duplicate-sentence.fixed.md.

Hand-written files: core/src/client/workflows.js, core/test/workflows-page.test.js, core/test/workflows-readonly-once.test.js, docs/subsystems/core-client.md, changelog.d/2524-workflows-duplicate-sentence.fixed.md. core/client.js and patches/ds-bot/* are regenerated, never hand-edited: npm run build in core/, then node scripts/ds-bot-patches.mjs generate.

Verification at the tip

Every reading below was taken on the tree 6878e85d4fdc3a1a004cb8422652f5beb64248ca after the single generate run against main at 90a594471b5886737b433e116f6397aa8ca2b6f2; main had not moved since the branch was cut, so the rebase was a no-op and nothing was carried over from an earlier base. The push helper re-created the local commit 7c5f655b7789ade67fa347129599cf9f1d79c58f as the tip 849abfd3aa7235071a1b2fa2237f337f3531e948 from that same tree, so the tree the checks measured is the tree at the tip.

Ran:

  • failing test first, on a clean 90a594471b5886737b433e116f6397aa8ca2b6f2 tree with only the two test files (the new core/test/workflows-readonly-once.test.js and this branch's core/test/workflows-page.test.js), the rest of the tree untouched: # tests 50 / # pass 48 / # fail 2. The red ones, verbatim:
not ok 43 - #2176: a read-only graph draws no editing control and leaves the host sentence to the header
  the edit bar adds no second copy of the host sentence
  true !== false
not ok 48 - a read-only window draws the host sentence once, not twice, with a workflow graph open
  the open graph does not repeat the sentence the header already carries
  1 !== 0
  • the same test files on the fixed tree: # tests 3 / # pass 3 / # fail 0 for the new file, and the workflow: a read-only window still offers Edit in Settings → Workflows #2176 case green.
  • the neighbouring suites (test/settings-*.test.js, test/workflows-*.test.js, test/*readonly*.test.js): # tests 154 / # pass 154 / # fail 0.
  • full core suite, TZ=UTC npm test: # tests 2930 / # pass 2930 / # fail 0, exit 0.
  • node .github/scripts/changelog.mjs check → changelog: 36 fragment(s) in changelog.d/ are well formed.
  • node scripts/build-client.mjs --check (in core/) → exit 0, client.js matches src/client.
  • node scripts/ds-bot-patches.mjs check → three 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/
  • node scripts/ds-bot-patches.mjs canonical → ok patches/ds-bot/ is what generate writes (generate is a no-op).
  • ARCH_DOCS_BASE=90a594471b5886737b433e116f6397aa8ca2b6f2 node scripts/check-arch-docs.mjs (in core/) → arch-docs: OK (10 changed file(s)).
  • working tree after the build and generate ran: git status --porcelain lists only the two untracked node_modules symlinks of this bench checkout (core/node_modules, core/dev/harness/node_modules), so the committed bundle and patches are exactly what the generators produce from this source.

Diff: 10 files, +350 / −25 (git diff --numstat 90a594471b5886737b433e116f6397aa8ca2b6f2..HEAD):

1   0  changelog.d/2524-workflows-duplicate-sentence.fixed.md
1   1  core/client.js
8   7  core/src/client/workflows.js
6   4  core/test/workflows-page.test.js
159 0  core/test/workflows-readonly-once.test.js
1   1  docs/subsystems/core-client.md
1   1  patches/ds-bot/0008-client-bundle.patch
8   7  patches/ds-bot/files/src/client/workflows.js
6   4  patches/ds-bot/files/test/workflows-page.test.js
159 0  patches/ds-bot/files/test/workflows-readonly-once.test.js

Generated carrier is exactly {0008 + three mirrors}, four files:

1   1  patches/ds-bot/0008-client-bundle.patch
8   7  patches/ds-bot/files/src/client/workflows.js
6   4  patches/ds-bot/files/test/workflows-page.test.js
159 0  patches/ds-bot/files/test/workflows-readonly-once.test.js

Not run (and why):

  • npm run verify as one command: it begins with core lint, and oxlint is not installed in this checkout (core/node_modules/.bin/oxlint is absent and npx cannot fetch it here), so the command would fail on a missing tool rather than on a defect. Its individual steps are listed above instead; the two plugin suites and plugin lint are irrelevant here because no plugin file changed.
  • the two-Bot live smoke: it needs a running instance, and the surface is covered by rendering the real dialog and the real graph view.
  • smoke/dev/bench.sh: no change to core/index.js or core/src/host/.

Checkpoint

{
  "pr": 2535,
  "claim": "Dev-4",
  "issue": 2524,
  "summary": "In a read-only window, Settings → Workflows drew the host's standing read-only sentence twice once a graph was open: the Settings header prints it once per page, and the graph's edit bar printed a second copy under role=status. The edit bar now keeps Back only (locked ? null : …), so the screen carries one copy and one Reload, and a writable window is unchanged. The new test mounts the real dialog header and the real graph edit bar and counts the sentence by text; the #2176 case in workflows-page.test.js moves to the header contract; the subsystem doc and one changelog fragment follow.",
  "files": [
    "core/src/client/workflows.js",
    "core/test/workflows-page.test.js",
    "core/test/workflows-readonly-once.test.js"
  ],
  "checks": {
    "ran": "red-first on 90a59447: 2 failures; TZ=UTC npm test 2930 pass; build-client --check exit 0; ds-bot-patches check 3 ok lines; arch-docs OK (10 files)",
    "result": "green",
    "at": "849abfd3aa7235071a1b2fa2237f337f3531e948"
  },
  "next": "none — ready for review"
}

The Settings header already prints the host's standing sentence for every page
it shows, and the open graph's edit bar drew a second copy of it under
role="status" — two live regions read out twice, against the one-sentence-per-page
contract the header keeps (ThinkFlowLab#2202). The edit bar keeps Back; the header's Reload
is the screen's way out, and a writable window keeps Edit exactly as it was.
@Birfy
Birfy added this pull request to the merge queue Nov 5, 2026
Merged via the queue into ThinkFlowLab:main with commit fa820e3 Nov 5, 2026
16 checks passed
@Birfy
Birfy deleted the dev/4-workflows-duplicate-sentence branch November 5, 2026 14:13
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 Settings → Workflows graph page draws the host sentence twice

2 participants