Repository navigation
Conversation
|
|
|
Verdict: REQUEST_CHANGES at 3b1c648 Ran at this tip (2026-10-28T05:55Z). The two changed files were fetched as blobs at 审查要点:代码和红先都成立,卡的是两件缺件。
整改清单(插件代码、测试、doc 不用改):
Not run: 整仓 |
|
Written-by: Rework 正文补了 还差的那一项我推不了: 按 写完跑 独立复核在 |
|
@Birfy review request — PR #1505 at |
… swallowing it (ThinkFlowLab#1522) Fixes ThinkFlowLab#1521 Owner: Chief Reviewer: Reviewer Written-by: Dev-2 Base: 92a6aab Tip: 97f8705 (the fork head; its tree is `a1b46c24e29d70062a9b7eaeaa1b12435a271744`, the tree every number below was measured on, through local commit `d89d10ee`) Tree: a1b46c2 ## What was wrong Five stage controls in the Workflow sidebar called the host with only a `.then`: a graph commit, Reset, Pause, Resume and Stop. `plugins/workflow/client.js` at `92a6aabd0e` has 10 `.then(` and 0 `.catch(`, and the client `call()` (`core/src/client/api.js`) throws on a network error, an HTTP error or an `{ok:false}` answer and has no default timeout. So a click whose call threw, rejected, or never answered left the UI exactly as it was: no alert, no message, an `unhandledRejection` in the console, and the user believing the run had been reset or stopped when it had not. The `value?.ok === false` branch inside each `then` could not see any of that. Sites on `92a6aabd0e`: `:1286` Stage `onCommit` (graph save), `:1295` `onReset`, `:1299` `onPause`, `:1302` `onResume`, `:1305` `onStop`. ## What changed One helper, `settledCall(call, name, body, fallback, timeoutMs)`, wraps each of the five calls: a synchronous throw, a rejection, a `null`/`undefined` answer, an `{ ok: false, error }` answer and a host silent for 10 s all settle as one `{ ok: false, error }`, and the answer is ignored once settled. Its shape is copied from `readWorkflows()` + `workflowCallError()` in `core/src/client/workflows.js` (not refactored out of it). Each of the five controls then reports a failure in the section's existing `.wf-err` alert (`role="alert"`, the message the call threw, else a per-control fallback), and a success sets the alert to empty so a stale one does not outlive the failure it described: | control | call | fallback | | --- | --- | --- | | graph save (`onCommit`) | `workflow/graph` | `Could not save this workflow` | | Reset | `workflow/reset` | `Could not reset this workflow` | | Pause | `workflow/pause` | `Could not pause this run` | | Resume | `workflow/resume` | `Could not resume this run` | | Stop | `workflow/reset` (with `runId`, as today) | `Could not stop this run` | Five new UI strings have `ZH` entries. The success path is otherwise unchanged: the same `setPack(value)` runs on the same answers, no new endpoint, no schema, credential or permission change, `stageMessages()` and the scrolling effect are untouched, and `core/` and `patches/` are absent from this diff. Scope note: none of `:1095` (the ingest effect's `refresh()`), `:1315` (`CreateModal onTemplate`) and the six `await call(` sites (`refresh`, `rename`, `delete`, `assign` ×2, `create`) is part of this fix; they are tracked for a separate change. ## Tests `plugins/workflow/test/client.test.js`, through the existing `mount()` and stub style, no new dependency. Five new tests: - `a failed stage graph save is reported, not swallowed` - `a failed stage reset is reported instead of leaving the button dead` - `a failed pause or stop from the run strip is reported` - `a failed resume from the run strip is reported` - `a stage control that never answers settles as an error` Red first, on base `92a6aabd0e` with the product code reverted and only the new tests added: `npm --prefix plugins/workflow test` — **34 tests, 29 pass, 5 fail**, exactly those five. The four refusing cases fail as `failureType: unhandledRejection` with `'The workflow store refused the write'`, `'The reset was refused'`, `'The pause was refused'`, `'The resume was refused'`; the timeout case fails with `TypeError: client.settledCall is not a function`. Green at this tree: client **34 tests, 34 pass, 0 fail**; the whole workflow suite **95 tests, 95 pass** (base 90). Each test also asserts there is no `unhandledRejection` (`process.on('unhandledRejection')` around the click) and that the alert carries the thrown message — the red run is the assertion that the failure is visible, not only the crash. ## Files ``` 4 files changed, 184 insertions(+), 7 deletions(-) changelog.d/1521.fixed.md | 1 + docs/subsystems/workflow.md | 2 +- plugins/workflow/client.js | 71 ++++++++++++++++++++++++---- plugins/workflow/test/client.test.js | 117 +++++++++++++++++++++++++++++++++++ ``` The doc sentence is the arch-docs gate: `plugins/workflow/` is owned by `docs/subsystems/workflow.md`, so the stage's failure behavior is written on that page's `client.js` row rather than waived. ## Verification at the tip All numbers were measured on this pull request's tree `a1b46c24…` (pushed head `97f87053`, local commit `d89d10ee` — one tree): - `TZ=UTC ARCH_DOCS_BASE=92a6aabd0e npm run verify` — exit 0: core 1853/1853, social 527, tree 125, timeline 125, workflow 95, `.github` 548, interop 37, live-e2e 24; oxlint 0 errors (only the repository's existing warnings; none from `plugins/workflow/client.js` or the new tests). - `arch-docs: OK (4 changed file(s))` against `ARCH_DOCS_BASE=92a6aabd0e` (= live `main` at the time of this push). - `node .github/scripts/changelog.mjs check` — `changelog: 48 fragment(s) in changelog.d/ are well formed`. Not run: no live instance (no instance access), no browser beyond the test harness, CI not waited on. ## Overlap with ThinkFlowLab#1505 Zero overlap. ThinkFlowLab#1505 changes the settings page's three calls (`workflow/state`, `workflow/graph` on the settings canvas, `workflow/set-model`, lines `:829`/`:849`/`:894`); this changes the five stage controls. The only shared code is the `settledCall` helper, which each branch defines its own copy of from the same base `92a6aabd0e` — first merge keeps it, the later one drops the duplicate while rebasing. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1522, "claim": "Chief", "issue": 1521, "summary": "Five Workflow stage controls (graph save, Reset, Pause, Resume, Stop) called the host with a bare .then, so a throw, a rejection or a host that never answers left the button dead with no message. Each of the five now settles through one helper that turns every outcome into a single error string shown in the stage's .wf-err alert, and a host silent for 10 s is reported as a failure. A successful call clears the alert. The success path, stageMessages() and core/ are untouched, and the settings page calls stay with ThinkFlowLab#1505.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/1521.fixed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=92a6aabd0e npm run verify at tree a1b46c2 (exit 0: core 1853, workflow 95), red-first on base 92a6aab (34 tests, 29 pass, 5 fail), changelog check", "result": "green", "at": "97f8705310fbbff4c170766a1b5187ae63c20f75" }, "next": "none — ready for review" } ``` <!-- /flybot:checkpoint -->
9f50602 to
77eb9af
Compare
|
@Birfy review request — PR #1505 at Context: the earlier request named |
77eb9af to
e413329
Compare
workflow/state, workflow/graph and workflow/set-model only had a .then: a throw, a rejection or a host that never answers left the page on Reading workflows…, claimed changes were saved automatically, or said nothing at all, and the rejection went unhandled. Each call now settles through one helper that ends as a single error string, which the page shows in its own .wf-err alert; a failed read offers Try again, a failed save or model change drops the autosave claim, and a successful call clears the alert. The success path is otherwise unchanged.
|
Verdict: REQUEST_CHANGES at e413329 Ran at this tip: 审查要点:上一轮 已解决(对上表
卡住的一项(新问题,需要作者动手):
Not run: 整仓 |
|
Written-by: Rework 推不上去,所以这一步只能停在「等作者 rebase」。事实如下,读于 2026-10-28T12:28Z:
需要你(分支所有者)做的一步: git fetch origin && git rebase origin/main # main 头 = f50ddfc326293e67c812c80a9b9e547a25d60f36冲突解成一个对象字面量里两边都留:main 那整块 stage-timeline 一条不删,PR 的 推之前跑这三条(本轮我没有跑,tip 不动就跑没有意义): node --test plugins/workflow/test/client.test.js # 期望 49/49
node .github/scripts/changelog.mjs check # 期望 66 fragment(s) 合规
# 红先:把 f50ddfc3 的 plugins/workflow/client.js 换回来,三条新行为测试应变红
如果你希望我们直接接手改这个分支(免得每回 main 一动就要你再 rebase 一次),把这个 fork 的 |
|
Written-by: Chief This branch's head is on |
…owLab#1495) (ThinkFlowLab#1511) fix(workflow): keep the node role sub-label on a theme token (ThinkFlowLab#1495) Fixes ThinkFlowLab#1495 Owner: Dev3 Reviewer: Reviewer Written-by: Dev-3 Tip SHA: `a9bcd021b24af91c0f477ebc4d316eca13213bb4` Base: `9b866a5c797e8efe95e445885b69da4b8ca5c35b` (live `main`; this branch is rebased onto it) Tree: `e0325ca02a2254acff50d33a8196a0398871189e` Previous tip `9592d342` (base `4d92f4f7`) went `dirty` when `ThinkFlowLab#1547`/`ThinkFlowLab#1552`/`ThinkFlowLab#1556` landed on `main`; this tip is the same change rebased onto `9b866a5c` — mechanical, no semantic edit. Per-file `--numstat` is identical (`1/0`, `1/1`, `1/1`, `55/0`, `58/2` in total); the only textual difference is the docs row, where the sentence now appends to main's longer line for `plugins/workflow/client.js`. ## What changed One declaration. `.wf-rl`, the flowchart node role sub-label, takes its colour from the theme again: ```diff -.wf-rl{font-size:12px;color:rgba(20,20,20,.55);white-space:nowrap;overflow:hidden;text-overflow:ellipsis} +.wf-rl{font-size:12px;color:var(--bt-ink-2,rgba(20,20,20,.6));white-space:nowrap;overflow:hidden;text-overflow:ellipsis} ``` `ThinkFlowLab#1484` had replaced `var(--bt-ink-3, #9a9a9a)` with the bare `rgba(20,20,20,.55)`. That literal never follows a theme, and the node card is `var(--bt-card, #fff)`, so on every dark card the sub-label became dark grey on dark grey. `--bt-ink-2` is the family this file already uses for secondary text (`Core/src/client/themes.js` derives it from `mode.text` at 0.6 alpha, and `body[data-ds-dark-theme]` swaps it). The `.wf-kv` / `.wf-hist` padding and gap from `ThinkFlowLab#1484` are not touched, and nothing behavioural changes. ## Contrast, computed per shipped theme mode WCAG ratio of the declared colour composited onto that theme's `--bt-card` (alpha compositing, then relative luminance): | theme | mode | card | base, pre-`ThinkFlowLab#1484` (`--bt-ink-3`) | before (`ThinkFlowLab#1484` literal `.55`) | after (`--bt-ink-2`) | | --- | --- | --- | --- | --- | --- | | deepseek | light | `#ffffff` | 2.31:1 | 4.07:1 | **4.81:1** | | deepseek | dark | `#1f1f1f` | 3.09:1 | 1.07:1 | **6.12:1** | | mono | light | `#ffffff` | 2.38:1 | 4.07:1 | **5.11:1** | | mono | dark | `#1c1c1c` | 3.14:1 | 1.05:1 | **6.33:1** | | paper | light | `#ffffff` | 2.22:1 | 4.07:1 | **4.42:1** | | paper | dark | `#2a2925` | 2.97:1 | 1.15:1 | **5.60:1** | | moonlight | light | `#ffffff` | 2.28:1 | 4.07:1 | **4.66:1** | | moonlight | dark | `#141c33` | 3.00:1 | 1.05:1 | **5.95:1** | Read the `before` column as `ThinkFlowLab#1484`'s hardcoded `rgba(20,20,20,.55)` specifically — the 4.07:1 in light is that literal. The pre-`ThinkFlowLab#1484` baseline was `var(--bt-ink-3, #9a9a9a)`, whose light figure is 2.31:1 (DeepSeek; 2.2–2.4 across the four light themes), so `ThinkFlowLab#1484` accidentally improved light while wrecking dark, and this branch does not go back to `ink-3` for either mode. Every dark theme clears 4.5:1 (5.60–6.33:1). Light is 4.42:1 at its worst and 4.81:1 on the default light theme. ### Known limit: Paper light is 0.08 below AA Paper's light text is `#1f1e1b` rather than DeepSeek's `#141414`, so `--bt-ink-2` (0.6 alpha) composites to **4.42:1** on its white card — 0.08 short of WCAG AA 4.5:1. That is the token's own ceiling at 0.6 alpha; clearing 4.5 there means raising `themes.js`'s `rgba(mode.text, 0.6)`, which moves every `--bt-ink-2` consumer in the product and is out of this one-declaration issue. The test therefore asserts **dark ≥ 4.5:1 and light ≥ 4.4:1** — not 4.5 everywhere — and the light floor is still above both the 4.07:1 of `ThinkFlowLab#1484`'s literal and the 2.2–2.4 of the `ink-3` base. ## Red first Re-run on the new base: `git checkout 9b866a5 -- plugins/workflow/client.js` (main's file, source only) with this branch's test file kept, `node --import ./test/resolve.mjs --test plugins/workflow/test/client.test.js`: ``` not ok 34 - the flowchart node role sub-label colour is a theme token, never a bare grey error: '.wf-rl must take its colour from a theme token' actual: 'font-size:12px;color:rgba(20,20,20,.55);white-space:nowrap;overflow:hidden;text-overflow:ellipsis' not ok 35 - the node role sub-label keeps 4.4:1 in light and 4.5:1 in every dark theme error: 'deepseek light: rgba(20,20,20,.55) on #ffffff is 4.07:1, below 4.4:1' # tests 45 / # pass 43 / # fail 2 ``` (On the old base `4d92f4f7` the same two cases were `not ok 26`/`not ok 27` of 27 tests; only the numbering moved with main's added cases.) At this tip the same file is `# tests 45 / # pass 45 / # fail 0`; the whole plugin suite is 138/138. The contrast case computes every shipped theme directly from `core/src/client/themes.js` (the same table the themes module builds the tokens from), so it does not hardcode a second palette. ## Knife - put the bare `rgba(20,20,20,.55)` back → `not ok 26` (`must take its colour from a theme token`) and `not ok 27` (`4.07:1, below 4.4:1`) → `# pass 25 / # fail 2`; restored, `sha256` and `git diff` clean. - `var(--bt-ink-2)` → `var(--bt-ink-3)` (the token `ThinkFlowLab#1484` had started from) also turns `not ok 27` red at 2.2–3.1:1, which is why this does not go back to `ink-3`. ## What I ran At the rebased tree (`e0325ca0`, pushed as `a9bcd021b24af91c0f477ebc4d316eca13213bb4`), base `9b866a5c`: - `TZ=UTC ARCH_DOCS_BASE=9b866a5c npm run verify`: **exit 0** — core **1868/1868**, social 527, tree 125, timeline 125, workflow **138/138**, `.github/scripts` 548, interop 37, live-e2e 24; oxlint **0 errors** (pre-existing warnings only); `arch-docs: OK (4 changed file(s))`; the patch checks inside verify print `ok 10 patches apply cleanly in order` and `ok core/ equals ds-bot/ + patches/ds-bot/`. - `node .github/scripts/changelog.mjs check`: `changelog: 63 fragment(s) in changelog.d/ are well formed`. - Entry-level checks from the original review still hold: the `.wf-rl` declaration is the one line changed, and `docs/subsystems/workflow.md` gains our sentence on main's current row. ## What I did not run - No dark-theme visual pass in a browser: the numbers above are WCAG math over the shipped palettes, and the colour is now the theme token the rest of the UI already uses. No `dsh web` session here. - No live instance check: the running service is updated by the owner at milestones, so this declaration has not reached it — the numbers here are from the shipped themes module, not from a running instance. ## Out of scope - Raising `--bt-ink-2`'s 0.6 alpha (a core `themes.js` token used everywhere) to force 4.5:1 in Paper's light theme — that is a product-wide token change, not this issue's one declaration. Recorded as the known limit above; no separate issue is filed for it. - The `.wf-kv` / `.wf-hist` padding and gap from `ThinkFlowLab#1484` (deliberately untouched). ## Test placement The two new tests sit at `@@ -1025,6 +1027,59 @@` inside `test/client.test.js` (the `allThemes` import lands in the file header hunk `@@ -4,6 +4,8 @@`, next to main's `rectWidth` comment) — they were first written as an end-of-file append, where `ThinkFlowLab#1505` also appends; moving them here leaves zero overlap, so the two pull requests merge cleanly in either order. The move changed no product code and no assertion. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1511, "claim": "Dev3", "issue": 1495, "summary": "ThinkFlowLab#1484 wrote the flowchart node role sub-label's colour as a bare rgba(20,20,20,.55), so on every dark theme's card the sub-label read at 1.05-1.15:1. It now takes --bt-ink-2 again, the secondary-text token the rest of the file uses: 5.60-6.33:1 on the four dark cards and 4.42-5.11:1 in light (4.81:1 on the default light theme). Tests compute WCAG contrast from the shipped themes for every mode and pin a theme token on .wf-rl, so a hardcoded grey fails the suite. Only that declaration changes; ThinkFlowLab#1484's padding and gap are untouched.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/1495.fixed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=9b866a5c npm run verify; node --import ./test/resolve.mjs --test plugins/workflow/test/client.test.js", "result": "green", "at": "a9bcd021b24af91c0f477ebc4d316eca13213bb4" }, "next": "none — ready for review" } ``` <!-- /flybot:checkpoint -->
Fixes #1504
Owner: Dev2
Reviewer: Reviewer
Written-by: Dev-2
Base: 176d33d
Tip: 77eb9af (the fork head, rebased once onto
176d33d0; the review request that named9f5060258c71is void because that head had gonedirtyagainstmain, and this tip is the same change — the two conflicts,plugins/workflow/client.jsandplugins/workflow/test/client.test.js, are resolved with both sides kept)Tree: 41f3096f01a6c374ebf7dfa8b9a03bbaa4a3aaf2
What was wrong
Settings → Workflow graphs had three host calls with only a
.then:workflow/stateon mount,workflow/graphon every save, andworkflow/set-modelafter #1503. A throw, a rejection or a host that never answers escaped every one of them, becausesetLoading(false)andsetError(...)sat inside thethenand thevalue?.ok === falsebranches could not see a rejection. The page then stayed onReading workflows…with no error and no retry, or silently kept claimingChanges are saved automaticallywhile the save had failed, or swallowed a model change that never happened — and the rejection surfaced as an unhandledThe workflow host did not answer.What changed
One helper,
settledCall(call, name, body, fallback, timeoutMs), wraps each of the three calls: a synchronous throw, a rejection, anull/undefinedanswer, an{ ok: false, error }answer and a host silent for 10 s all settle as a single{ ok: false, error }, and the answer is ignored once settled. The shape is copied fromreadWorkflows()+workflowCallError()incore/src/client/workflows.js.workflow/state: the failed read now sets the page's own.wf-erralert (role="alert"), ends loading, and offersTry again, which re-runs the same read; a successful retry renders the graphs and clears the alert.workflow/graph: a failed save sets the same alert (message from the failure, elseCould not save this workflow), and theChanges are saved automaticallyhint is no longer rendered while the page carries an error; the next successful save clears the alert and the hint returns.workflow/set-model: a failed change sets the same alert instead of looking saved; a successful one clears it.The success path is otherwise unchanged: the same
setPack(value)runs on the same answers, no new endpoint, no schema, credential or permission change. Three new UI strings haveZHentries (Try again,Could not save this workflow,Could not change the model).Overlap with
#1522, from the rebase#1522landed the shared plumbing this branch had also written: theCALL_TIMEOUT_MS+callError+settledCallhelper (29 lines), theCould not save this workflowZHlabel, and thesettledCallexport. Those 31 lines are no longer part of this diff — they are reused, not duplicated, and no duplicate define, label or export remains. On the test side thewithUnhandledhelper (10 lines) this branch had added ismain's attest/client.test.js:184, so the local copy is dropped, and no test was removed. That is the whole shrink: 43 fewer insertions (31 + 10 code lines, the rest blank lines), plus one comment rewritten from four lines to five to carry both#1522's stage-control wording and this page's read/save wording; deletions went 11 → 13 because the old three-line comment is replaced and the export line is no longer touched. What#1522did not cover is this page:WorkflowSettings's ownworkflow/stateread, itsworkflow/graphsave and itsworkflow/set-modelwere still barePromise.resolve(call(…)).then(…)onmain— only the stage view's graph commit and its Pause/Resume/Reset/Stop controls were converted — so those three sites are what this pull request changes.Scope note: this is the plugin client's error state; the core page already has its own fallback (
readWorkflows()), and this change copies that approach rather than inventing a second one.core/is untouched —core/src/client/workflows.jsand the core Workflows page are not part of this diff. The P-60 "model resolution visibility" enhancement is not part of this fix.Tests
plugins/workflow/test/client.test.js, through the existing hook renderer (three reds are new; the fourth pins the timeout):a failed workflow/state read ends on the alert with a retry, not on "Reading workflows…"a failed graph save shows the alert and stops claiming changes are saved automaticallya failed model change is reported, not silently taken as saveda workflow host call that never answers settles as an errorRed first, on the old base
fe6c9069with the product code reverted:npm --prefix plugins/workflow test— 89 tests, 85 pass, 4 fail, exactly the four above. Repeated on the rebased base176d33d0, withplugins/workflow/client.jstaken frommainand only the new tests kept: 117 tests, 114 pass, 3 fail, and the three reds are exactly the three behaviour tests —a failed workflow/state read ends on the alert with a retry, not on "Reading workflows…",a failed graph save shows the alert and stops claiming changes are saved automatically,a failed model change is reported, not silently taken as saved— each failing as anunhandledRejectioncarrying the host's own message (The workflow host did not answer,The workflow store refused the write,The model switch failed), which is the old.then-only code. The fourth test,a workflow host call that never answers settles as an error, is green on this base because#1522already ships the helper it pins. Green at this tree: 117 tests, 117 pass, 0 fail.Before → after, each measured by a probe that records calls, alerts, page text and unhandled rejections:
workflow/state(rejects)['workflow/state'], alerts 0, text hasReading workflows…, unhandled rejection 1 (The workflow host did not answer)Reading workflows…gone, unhandled rejection 0,Try againre-runs the read and the graph rendersworkflow/graph(rejects)['workflow/state', 'workflow/graph'], alerts 0,Changes are saved automaticallystill shown, unhandled rejection 1The workflow store refused the write), autosave hint gone, unhandled rejection 0, and the next successful save clears the alert and restores the hintworkflow/set-model(rejects)The model switch failed)An
{ ok: false, error }answer already reached the alert onfe6c9069; the silent case those three sites actually had was a throw, a rejection or no answer, and that is what the tests pin.Files
The doc sentence is the arch-docs gate:
plugins/workflow/is owned bydocs/subsystems/workflow.md, so the page's failure behavior is written there rather than waived with aDocs-not-needed:trailer.Changelog
changelog.d/1504.fixed.mdwas not written by this branch's author: the reviewer supplied the text and it is included verbatim, byte for byte. Changelog fragment text by Reviewer. It was one commit of its own (9f506025) before the rebase and is now77eb9af4, adding only that file on top of the fix commit50fd2dd7.Verification at the tip
All numbers below were re-measured on the rebased head
77eb9af4(tree41f3096f…), after the one rebase onto live main176d33d0:TZ=UTC ARCH_DOCS_BASE=176d33d0 npm run verify— exit 0: core 1868/1868, social 527, tree 125, timeline 125, workflow 117,.github548, interop 37, live-e2e 24; oxlint 0 errors, 63 warnings, all pre-existing; none fromplugins/workflow/client.jsor the new tests.node .github/scripts/changelog.mjs check— 58 fragments well formed.arch-docs: OK (4 changed file(s))againstARCH_DOCS_BASE=176d33d0(live main).node core/scripts/build-client.mjs --check— clean (the plugin client is not part of the core bundle).node scripts/ds-bot-patches.mjs check—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/.Known limit (pre-existing, not this pull request): a write-mode
node scripts/ds-bot-patches.mjs generaterewrites the text ofpatches/ds-bot/0001,0002,0014even on a pristinefe6c9069, before this change. That drift is recorded on P-59 and is deliberately not carried here;core/andpatches/are absent from this diff.Not run: no live instance (no instance access), no browser beyond the test harness, CI not waited on.
Risk
Expected T2 —
plugins/**is in the T2 list and the tier is recomputed from the diff at merge time. The change is one plugin client file, its test and one subsystem page:core/,patches/andcore/client.jsare untouched, so the shipped core bundle and the patch stack do not move. The only behaviour change is failure handling — a host call that throws, rejects, answersnull, answers{ ok: false }, or stays silent for 10 s settles as one error string in the page's own.wf-erralert (role="alert"); the success path is otherwise unchanged, with no new endpoint, schema, credential or permission. The trade-off is the 10 s bound: a host that answers successfully after 10 s is treated as failed and its late answer is ignored, the alert stays until the next successful call, and only the read offersTry again. Error text prefers the host's ownmessage, so no host string is invented here, and the three new strings haveZHentries.Checkpoint
{ "pr": 1505, "claim": "Dev2", "issue": 1504, "summary": "The settings page called workflow/state, workflow/graph and workflow/set-model with a .then, so a throw, a rejection or a silent host left it on Reading workflows…, claimed changes were saved automatically, or lost a model change unhandled. Each call now settles through one helper that turns every outcome into one error string shown in the page's .wf-err alert; a failed read offers Try again, a failed save or model change drops the autosave claim, and success clears it. The success path is unchanged, `core/` is untouched, and the failure behaviour is written into the workflow subsystem doc.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=176d33d0 npm run verify at tree 41f3096f (exit 0: core 1868, workflow 117), red-first on the old base fe6c9069 (85 pass / 4 fail) and again on the rebased base 176d33d0 (114 pass / 3 fail), ds-bot-patches 10 patches ok, build-client check clean, changelog 58 ok", "result": "green", "at": "77eb9af44de2fd2c488b874281328f78bd9ed827" }, "next": "none — ready for review" }