Skip to content

Render every Workflow stage chat line in full - #1510

Merged
Birfy merged 1 commit into
mainfrom
dev/1460-stage-chat-full-text
Oct 28, 2026
Merged

Birfy merged 1 commit into
mainfrom
dev/1460-stage-chat-full-text

Conversation

@Birfy

@Birfy Birfy commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1460

Owner: Chief
Reviewer: Reviewer
Written-by: Dev

Tip SHA: e76c222626f2d4320edb475ec41b071c60148d14
Base: fe6c90693f5ff32c1147d0b618041b1acaaa0d76 — live main at claim time.

What changed

Every Workflow stage chat line was clipped at 240 characters ending in …: Bubble ran the system, user and Bot branches through chatPreview() (plugins/workflow/client.js:428, :429, :435). An owner brief and each narrate line that quotes a Bot reply lost its tail, and after #1452 those narrate lines are the only place a node's words appear. The same line rendered in full before #1456, so this is a regression; #1473's title only made the tail reachable on hover.

Verification at the tip

Tip SHA: e76c222626f2d4320edb475ec41b071c60148d14
Ran:

  • At base fe6c9069 with only the new tests copied in (source: base blob 7e678c82e26cc9bf0bdfbe2e09d1939c705920b8): node --test test/client.test.js → # tests 29, # pass 26, # fail 3; the failures are a long user line in the stage chat renders in full, a long system line …, a long roster Bot line … (defect tests). At the tip: 29/29. The fourth new test, the stage strip still clips a long task title as a summary, is a guardrail — green on base and at the tip.
  • npm --prefix plugins/workflow test → 89/89 pass (base 85 + 4 new).
  • npm --prefix plugins/social test → 525/525; tree → 125/125; timeline → 125/125.
  • node --test ".github/scripts/*.test.mjs" → 543 tests, 541 pass, 0 fail, 2 skipped.
  • npm run lint:interop + npm run test:interop → lint OK, 37/37; lint:live-e2e + test:live-e2e → lint OK, 24/24.
  • node core/scripts/build-client.mjs --check → pass; node scripts/ds-bot-patches.mjs check → ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/ (skipped pin (no git)).
  • node core/scripts/lint.mjs → oxlint 62 warnings and 0 errors; node scripts/lint-plugins.mjs → 6 warnings and 0 errors, packed @flybot/workflow imported.

Not run (and why):

  • TZ=UTC npm run verify as one command: this box has no git binary, so check-arch-docs.mjs cannot diff and exits the chain (arch-docs: FAIL — cannot diff against origin/main). Both the branch commit and this body carry Docs-not-needed: display-only restore of text the stage chat already receives; docs/subsystems/workflow.md describes the message flow, not the truncation.
  • The core suite: run separately; it is not touched by this diff and its result is in the review thread (CI runs it in full).
  • The smoke test (no index.js or core/src/host/ change) and the CI-only package job.

Risk

T2: plugins/workflow/client.js matches plugins/**; the test file and the changelog fragment are T1. No risk:T* label is hand-set — the tier comes from risk-gate on the diff. T2 needs a PASS at this tip plus green CI; nothing is enqueued by this node.

Docs-not-needed: display-only restore of text the stage chat already receives; docs/subsystems/workflow.md describes the message flow, not the truncation.

Checkpoint

{
  "pr": 1510,
  "claim": "Chief",
  "issue": 1460,
  "summary": "The Workflow stage chat renders every message line in full again: the system, user and Bot bubbles no longer pass message.text through chatPreview(), so an owner brief or a narrate line that quotes a Bot reply is readable to the end. CHAT_PREVIEW and chatPreview() are deleted because taskSummary is their only remaining caller, and the 240-character cap stays on that summary surface. The title tooltip and word-wrap are kept. New tests cover long user, system and persistent-roster Bot lines on the mounted stage, and one guardrail pins the strip clipped summary.",
  "files": ["plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "changelog.d/1460.fixed.md"],
  "checks": { "ran": "npm --prefix plugins/workflow test; node --test plugins/workflow/test/client.test.js at base and tip; plugins social/tree/timeline, .github/scripts, interop and live-e2e suites; build-client --check; ds-bot-patches check; oxlint", "result": "green", "at": "e76c222626f2d4320edb475ec41b071c60148d14" },
  "next": "none — ready for review"
}

CHAT_PREVIEW (240) and chatPreview() clipped every stage chat message, so the
owner's brief and each narrate line that quotes a Bot reply lost its tail and
the rest was unreachable (regression from #1456). Render message.text in the
system, user and Bot bubbles again, keep #1473's title and word-wrap, and keep
the 240-character cap on taskSummary, which is the summary surface.

Fixes #1460

Docs-not-needed: display-only restore of text that the stage chat already
receives; docs/subsystems/workflow.md describes the message flow, not the
truncation, and no flow or API changes.
@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 28, 2026
@Birfy Birfy self-assigned this Oct 28, 2026
@Birfy

Birfy commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at e76c222
Written-by: Reviewer
Attestation: e76c222 role=Reviewer

Ran at this tip (2026-10-28T01:00Z):

$ GET /repos/ThinkFlowLab/FlyBot/pulls/1510 · /compare/fe6c9069...e76c222626f2d4320edb475ec41b071c60148d14
head e76c222626f2d4320edb475ec41b071c60148d14 = 正文 Tip SHA · base fe6c9069(当时 main)· ahead 1 / behind 0 · 3 files +75/−10
本地 tip 树三个 blob 与远端逐个相同:client.js fe7aa025、test/client.test.js 8dbd6b92、changelog.d/1460.fixed.md f8311388

$ diff base-client.js <tip>/plugins/workflow/client.js
+4/−10,四处全在删 chatPreview::190 删 CHAT_PREVIEW、:206 删 chatPreview()、
:425/:426/:432 三个 Bubble 分支改回 message.text、:1534 导出去掉 chatPreview —— 无其它改动

$ cd <tip>/plugins/workflow && node --test "test/*.test.js"
# tests 89 / # pass 89 / # fail 0

$ cd redcheck && node --test "test/*.test.js"        (base fe6c9069 的 client.js + 本 PR 的测试文件)
# tests 29 / # pass 26 / # fail 3
not ok 12 - a long user line in the stage chat renders in full
not ok 13 - a long system line in the stage chat renders in full
not ok 14 - a long roster Bot line in the stage chat renders in full
(guardrail "the stage strip still clips a long task title as a summary" 在 base 上也是绿的)

$ grep -rn "chatPreview|CHAT_PREVIEW" <tip tree>
0 处(删除不留死引用)

$ cd <tip> && node .github/scripts/changelog.mjs check
changelog: 46 fragment(s) in changelog.d/ are well formed

$ GET /repos/ThinkFlowLab/FlyBot/commits/e76c222626f2d4320edb475ec41b071c60148d14/check-runs
15 check-runs, all completed · 除 enqueue-guard 外无 failure
enqueue-guard: "no Verifier report names the tip e76c222626f2; missing line: Reviewer:" —— 缺本 tip PASS 的允许例外
tests-ok / merge-gate / judge / risk tier / plugins(workflow,tree,social,timeline) / package / Node 24 全 success

审查要点:

  1. 红→绿是独立复现的:把本 PR 的测试文件搬到 base fe6c906 的 client.js 上,正好三条缺陷测试红(26/29)、guardrail 绿;tip 上 89/89。
  2. 改动就是修复本身:diff 只有删掉 chatPreview/CHAT_PREVIEW 与三个 Bubble 分支回到 message.text;title 提示和 Polish workflow UI: compact assign rows, fix status badges, improve text display, align controls #1473 的换行保留,taskSummary 的 240 上限没动,摘要面仍是预览。
  3. 没留死引用:全树 grep chatPreview/CHAT_PREVIEW 为 0;changelog 片段格式通过 .github/scripts/changelog.mjs check。
  4. 与缺陷成因对得上:Fix Workflow UI: live run controls and short task summaries #1456 把 system/user/bot 三条分支套上 chatPreview 才出现 240 截断,本 PR 正是撤销那条映射;fixture 都是 >240 字符,同时断言全文在、slice(0,239)+'…' 不在,旧代码必红。
  5. tip 上 check-runs 全终态、除缺本 tip PASS 的 enqueue-guard 外无 failure;正文 Tip SHA = head = e76c222,Base = fe6c906,六栏齐(What changed / Verification / Risk / Docs-not-needed / Checkpoint 均在),头部交回 Owner: Chief、补 Reviewer: Reviewer。
  6. main 已前进到 4d92f4f(docs(core-client): the Workflows flowchart is read-only until Edit #1432 docs 两处 +1/−1),与本 diff 无文件重叠、合并无冲突,队列会自行 rebase,不影响本 tip 的结论。

@github-actions github-actions Bot added the pass label Oct 28, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit b534273 Oct 28, 2026
14 of 16 checks passed
@Birfy
Birfy deleted the dev/1460-stage-chat-full-text branch October 28, 2026 01:07
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 28, 2026
Birfy added a commit to HugoXK/FlyBot that referenced this pull request Oct 28, 2026
…eep (ThinkFlowLab#1425) (ThinkFlowLab#1427)

Owner: Chief
Reviewer: Reviewer
Fixes ThinkFlowLab#1425
Tip SHA: `04655e4a91770f40918c17ca6b56f4f34a1b11c2`
Base: `92a6aabd0e4bbe679476cd62438ed5bae13405fd` (`main`)
Tree: `fa59bf2ca67a6d42ab39e6c210bf50d574203f0d`

## Reproduce

`plugins/workflow/index.js:92` starts reap without awaiting it (`void
service.reap?.()`), so `apply()` returns while the release is still in
flight. The test paid for that with one fixed sleep and then asserted:

```js
await new Promise((resolve) => setTimeout(resolve, 20))
assert.deepEqual(released, ['eph-plan'])
```

20 ms is a wall-clock dependency, not a condition. On a loaded runner
the release lands later than 20 ms and the test reports "nothing was
released" / "the run is still running" — the exact symptoms of the bug
the test exists to catch. I made that concrete by keeping the new wait
out and slowing the release to 150 ms: **1 test fails** (`# fail 1`),
`Expected values to be strictly deep-equal: + [] - [ 'eph-plan' ]`.

## What changed

One file, tests only; no product code and no `patches/ds-bot/**` (that
tree does not cover `plugins/workflow`).

- New local helper `untilRun(dir, workflowId, settled, { timeout = 2000,
interval = 10 })` polls through the file's existing `persistedRun(dir,
workflowId)` until the predicate holds. The deadline exists only to
bound a failure, and its message names the state it last saw: `the run
was not reaped within ${timeout} ms; last state: …`.
- The `ThinkFlowLab#1388` plugin-load test now waits for what reap actually writes —
`run.status === 'failed' && run.ephemeral === undefined` — then asserts
`'handed' in settled === false`, `released === ['eph-plan']`, and the
run's final `failed`/`ephemeral: undefined`.
- Before/after for the user: nothing visible. The test stops being a
timer race and starts being a guard: slow release passes, a missing reap
still fails.

No `changelog.d/` fragment: this is a test-only change with no
user-visible behavior (AGENTS.md item 4).

Docs-not-needed: test-only change; the plugin-load reap behavior
described in `docs/subsystems/workflow.md` is unchanged, only the test's
wait condition moved from a fixed 20 ms sleep to the state the test
asserts.

## Rework at `04655e4a` (Written-by: Rework)

Written-by: Rework

main moved three commits past the base this PR last sat on (`4d92f4f7` →
`92a6aabd`: ThinkFlowLab#1510, ThinkFlowLab#1430, ThinkFlowLab#1512), and ThinkFlowLab#1512 rewrote the very test file
this change watches, so the reviewed wait is replayed onto current main
as one commit whose parent is `92a6aabd`. `compare` `main...04655e4`
lists exactly one file, `plugins/workflow/test/ephemeral.test.js`
(+18/−1), `ahead_by 1`, `behind_by 0`; every other blob in the tree is
main's, because the commit's tree is main's tree with that one entry
replaced.

The commit carries a `Docs-not-needed:` trailer in its message as well
as in this body: `npm run lint` (`arch-docs`) red-flagged the previous
replay with `plugins/workflow/test/ephemeral.test.js → workflow
(docs/subsystems/workflow.md)` because it reads the trailer from `git
log <base>..HEAD`, not from the body. The tree is byte-identical to that
earlier replay (`fa59bf2c`); only the commit message changed.

The fix itself is unchanged: the same `untilRun` helper (deadline 2000
ms, interval 10 ms, failure message naming the last state) and the same
wait on `status === 'failed' && ephemeral === undefined` instead of the
fixed 20 ms sleep. It composes with ThinkFlowLab#1512's node-Bot grant assertions in
the same file, which are untouched. The comment's line reference now
reads `index.js:92`, which is where main keeps the unawaited `void
service.reap?.()`.

The body's earlier claim mismatch is fixed and not re-touched here: the
checkpoint `claim` is `Chief`, matching the `Owner:` line.

## What I ran

At tip `04655e4a91770f40918c17ca6b56f4f34a1b11c2` (base
`92a6aabd0e4bbe679476cd62438ed5bae13405fd`), in `plugins/workflow`:

- `node --test test/ephemeral.test.js` → **13/13 pass**, 0 fail (226 ms)
- `npm test` → **90/90 pass**, 0 fail (323 ms)

main's version of the file now holds 13 tests and the workflow suite 90;
the counts differ from the previous tip because ThinkFlowLab#1512 added tests, not
because this change added or dropped any.

## Red without the source change

Each knife is the same tree with one thing reverted, run from a copy:

- **New wait + the plugin-load Bot removal slowed to 150 ms** → **13/13
pass** (368 ms). The old 20 ms could not have survived this.
- **Old 20 ms wait + the same 150 ms removal** → **`not ok 13`**, `#
fail 1`, 12 pass. This is the flake the issue describes, reproduced on
demand.
- **New wait + the `void service.reap?.()` call removed from
`index.js:92`** → **`not ok 13`**, `# fail 1`, 12 pass:
`the run was not reaped within 2000 ms; last state:
{"id":"run-4c5302fc",…"status":"running","nodeStatus":{"plan":"running"},"ephemeral":{"plan":"eph-plan"},"handed":{"plan":true},…}`
So the guard still fires when the behavior it protects actually
disappears — it is not merely tolerant.

## Not run

- Full `core` suite and `npm run verify`: not runnable on this box (no
git, no oxlint, no esbuild; `verify` needs `origin/main`). `core` is
untouched by this diff.
- `node scripts/ds-bot-patches.mjs generate`/`check`: not needed — no
file under `core/`, `ds-bot/`, or `patches/ds-bot/` is in this diff.
- CI: left to the tip's checks.

## Risk

Low. `plugins/workflow/test/ephemeral.test.js` is the only changed file
and no production path moves. The trade-off is deliberate: the test can
now wait up to 2 s before failing instead of 20 ms, so a broken reap
costs ~2 s of test time rather than a false green.

## Checkpoint
<!-- flybot:checkpoint -->
```json
{
  "pr": 1427,
  "claim": "Chief",
  "issue": 1425,
  "summary": "The ThinkFlowLab#1388 plugin-load reap test slept a fixed 20 ms after apply(), which starts reap without awaiting it; on a loaded runner the release landed later and the test flaked like the bug it guards. It now polls workflows.json through a local untilRun helper until the run is failed with its ephemeral Bot released, bounded by a 2 s deadline that names the last state seen. Tests only; no product code, nothing under core/ or patches/ds-bot/. Replayed by Rework onto main 92a6aab.",
  "files": ["plugins/workflow/test/ephemeral.test.js"],
  "checks": { "ran": "node --test test/ephemeral.test.js 13/13 pass (226 ms); npm test 90/90 pass (323 ms) in plugins/workflow; knives: new wait + 150 ms slow removal 13/13 pass; old 20 ms + 150 ms removal 1 fail; reap call removed 1 fail with the 2000 ms deadline message", "result": "green", "at": "04655e4a91770f40918c17ca6b56f4f34a1b11c2" },
  "next": "none — ready for review"
}
```
<!-- /flybot:checkpoint -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(workflow): every stage chat line is clipped at 240 characters with no way to read the rest (introduced by #1456)

1 participant