Repository navigation
fix(workflow): early-end tip-unchanged/open-PR; arm deadline without ephemeral - #1572
Merged
Merged
Conversation
…ephemeral Fixes ThinkFlowLab#1570 Fixes ThinkFlowLab#1571 Extends checkEarlyEnd for tip-unchanged and open-pr (plus EARLY-END directives), skips loop/onFail when those fire, arms STEP_DEADLINE for live steps without an ephemeral map, and documents Claim/Verify/Triage prompt guidance in EARLY_END_GUIDANCE. Owner: Danyang Chen Reviewer: Reviewer Written-by: Grok Bot (box-local; no CloudAgent)
Collaborator
Author
|
Verdict: PASS at 46ddc0c Ran:
Not run:
FindingsNo actionable findings. Early-end covers tip-unchanged / open-pr / needs-human / already-claimed; loops and onFail do not burn on early-end; STEP_DEADLINE arms without requiring ephemeral. Docs + changelogs present. ResidualLIVE Settings graphs may still need operator prompt updates after deploy so Triage/Claim/Verify emit EARLY-END markers. |
This was referenced Oct 28, 2026
Merged
HugoXK
pushed a commit
to HugoXK/FlyBot
that referenced
this pull request
Oct 28, 2026
dispose() collected the runs of a lane after archiving each live run. archiveCutoffRun() removes the run from lane.active and makes it lane.last, so the collection named only the run archived last: with two concurrent runs the earlier run's run Bots were never released, and write() then erased their ids, leaving hidden Bots that no state names (ThinkFlowLab#1387). Snapshot the lane before the archive loop. Fixes ThinkFlowLab#1472 Rebased onto main 9b866a5 by Dev-4: kept every change of c740357 (4 files) and resolved the conflicts with the newer main work on the same rows (ThinkFlowLab#1530, ThinkFlowLab#1572); content unchanged.
HugoXK
pushed a commit
to HugoXK/FlyBot
that referenced
this pull request
Oct 28, 2026
…ped connector list (ThinkFlowLab#1573) Fixes ThinkFlowLab#1520 Owner: Chief Reviewer: Reviewer Tip SHA: `fc6cddff4eed35dd1b43828965fbcef8f351248b` Base: `9b866a5c797e8efe95e445885b69da4b8ca5c35b` (main; replayed onto it after ThinkFlowLab#1514 landed on the same two files) Docs-not-needed: `plugins/workflow/client.js` copy plus an input-local draft state; the workflow subsystem doc already states that `node.tools` names connectors only and every node Bot gets a normal Bot's file and shell access. ## What changed **The field explains itself, in English and Chinese.** Under the Tools input the inspector now says: *Names the connectors this run Bot may use: github grants mcp__github__\*, composio grants the Composio connector. File and shell access is always full, like a normal Bot, and a node that names no connector gets none.* — followed by the same sentence in Chinese. The placeholder changes from `github, bash, read, edit...` to `github, composio`, because `bash`, `read` and `edit` are not connectors and grant nothing here. **Typing a second connector works.** The value used to be rebuilt from the saved list on every keystroke (`(selected.tools ?? []).join(', ')`) while `onChange` saved immediately; the host's `cleanTools` drops a trailing empty token, so the re-render ate the separator and `github, composio` typed one character at a time saved as the single token `githubcomposio`. `stepGrants` knows only `github`, `composio` and `mcp__<id>__*`, and `restrict()` had already taken the connector tools away, so the node ran with no connector and nothing said so. The input now keeps a local draft (`toolsDraft`) and commits it on blur or after a 600 ms pause; typing and pasting end in the same saved list. The host normalization and the spawn path are untouched. ## Verification at the tip Tip SHA: `fc6cddff4eed35dd1b43828965fbcef8f351248b` Ran: - `npm --prefix plugins/workflow test` at the tip → **138 / 138 / 0**. - Red first, same test file on main's `client.js` blob: **43 / 45 / 2** — `the Tools field says it names connectors and that file and shell access is always full` failed on `the Tools field explains what it names`; `the Tools field takes a second connector typed one character at a time` failed with actual `'github'` against expected `'github,'` after the ninth character. - `npm --prefix plugins/social test` 527 / 527 / 0, `plugins/tree` 125 / 125 / 0, `plugins/timeline` 125 / 125 / 0. - `node core/scripts/build-client.mjs --check` clean, `node scripts/ds-bot-patches.mjs check` clean, `node scripts/lint-plugins.mjs` 0 errors, `node .github/scripts/changelog.mjs check` 60 fragments well formed. - Core suite sequentially: **1866 / 1868 / 2**; `core/` is byte-identical to main in this branch and both failures are this sandbox — `empty diff passes` needs `git` (absent here), `fixture usage.sqlite has one real calls row with all five fields` reads a fixture this extraction does not carry. Not run (and why): - `npm run verify` end to end: this sandbox has no `git` binary, so `npm --prefix core run lint` stops at `arch-docs: FAIL — cannot diff against <base>` (the oxlint half ran: 0 errors, 63 pre-existing warnings). The `Docs-not-needed:` trailer is in the branch commit and in this body for the CI half that can diff. - No smoke run and no browser screenshot: `core/src/host/`, the plugin's host seams and `src/ephemeral.js` are untouched. ## Risk T2: the diff is under `plugins/**`, so it needs a PASS at this tip plus green `tests-ok` before the queue. The behavior change is confined to the inspector input: a typed list now commits on blur or after 600 ms instead of on every keystroke, so a save can land up to 600 ms later than before but never later than leaving the field, and the unmount cleanup drops a pending timer. The saved shape, the host normalization (`cleanTools`), `stepGrants` and the spawn path are unchanged, so no run sees a different `node.tools`. `main` moved twice while this was open (ThinkFlowLab#1572, then ThinkFlowLab#1514 on these same two files); the branch was replayed each time and the diff is still only these three paths. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1573, "claim": "Chief", "issue": 1520, "summary": "The inspector's Tools field now says it names the connectors the run Bot may use (github → mcp__github__*, composio → Composio), that file and shell access is always a normal Bot's, and that naming none reaches none, in English and Chinese. Its placeholder is github, composio, not bash, read and edit. The field keeps a local draft and commits on blur or a pause, so a second connector typed by hand no longer loses its separator: before, the host's trailing-token normalization saved githubcomposio and silently refused the connector. Only client.js, its test and one changelog fragment change.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "changelog.d/1520.fixed.md" ], "checks": { "ran": "npm --prefix plugins/workflow test (138/138); npm --prefix plugins/social|tree|timeline test; node core/scripts/build-client.mjs --check; node scripts/ds-bot-patches.mjs check; node scripts/lint-plugins.mjs", "result": "green", "at": "fc6cddff4eed35dd1b43828965fbcef8f351248b" }, "next": "none — ready for review; T2 needs a PASS at this tip and green tests-ok before the queue." } ``` <!-- /flybot:checkpoint -->
HugoXK
added a commit
to HugoXK/FlyBot
that referenced
this pull request
Oct 28, 2026
…igest skips the health module's count compensation (ThinkFlowLab#1579) Fixes ThinkFlowLab#1578 Owner: Dev-1 Reviewer: Reviewer Written-by: Dev-1 Risk: T2 — `plugins/timeline/src/digest.js` is plugin code (`.github/agent/risk-rules.json`), so this needs a PASS at the tip plus green CI. No T3 path, no dependency change. Tip SHA: `8139276924c95ec4f30691244c8e4c3d2030ebe0` Tree: `bd8db4c70d8271142d4798b42b8405d73ff9953f` Base: `c1b9fd23e404dcff1eb782a2269e30e09e2d6993` — live `main` (`ThinkFlowLab#1547`, `ThinkFlowLab#1572`, `ThinkFlowLab#1556`, `ThinkFlowLab#1552`, `ThinkFlowLab#1573`). ## What was wrong The report compared two different populations. `plugins/timeline/src/window.js:249` counts `turns` as the turns that **began** in the window; `:250` counts `errors` as every **overlapping** turn whose outcome is `error`. A failed turn that began before the window is therefore in `errors` and not in `turns`, and `digest.js` divided one by the other: `const errorRate = turns > 0 ? errors / turns : 0`, printed in three places. That is exactly the reading `docs/subsystems/timeline.md` invariant 5 says can never happen — the error rate "divides by the larger of the turns that began in the window and the failed turns, so it never reads a failure count above its turn count" — and `plugins/timeline/src/health.js:27-32` already compensates with `Math.max(use.turns, use.errors)` and a comment naming the failure text it avoids. The digest did not. Reproduced at `main`, real `buildWindow` + `buildDigest`, 15-minute window, one Bot `b1`: three turns that begin 3/4/5 minutes before the window and fail 20/21/22 s into it, plus one turn that begins inside it and completes. The window holds 4 turns (`outcomes {completed: 1, error: 3}`, `utilization.turns` 1, `errors` 3), and the report read: - per Bot: `- 1 turns, 3 failed (300%)` - Team: `- 1 turns, 3 failed` - one line: `1 turns, 3 failed, 0 tokens in over 07:45–08:00.` The mild shape is worse than a bad percentage: one overlapping failed turn plus one completed turn that began inside the window reads `1 turns, 1 failed (100%)`, i.e. "the window's only turn failed", when that turn is the completed one. `1 turns` was also printed everywhere. ## What changed `plugins/timeline/src/digest.js` only — three lines of arithmetic and the three printers: - `counted = Math.max(turns, errors)`, and `errorRate = errors / counted`, the same denominator `health.js` uses. `counted` is now on each `bots[]` entry and on `team`, so a consumer can read the number the share was taken over; `turns` and `errors` keep their raw window values. - The per-Bot line, the `## Team` line and the one-line summary all print `counted`, so the number compared with the failure count is the number printed, and the Team rollup is the sum of the Bot sections, as before. - The failure flag reads `${errors} of ${counted} turns failed`, the wording `health.js` already uses, and `no turns` now needs `counted === 0` rather than `turns === 0` (a Bot whose failed turns all began before the window is not "no turns" and is not reported as one). - Singular/plural follows the number in all three places (`1 turn`, `3 turns`). - A share is printed only when it can be a share, i.e. below 100%. With every counted turn a failed one, the numbers cannot say whether that turn began in the window or before it; `(100%)` beside a window whose single completed turn began inside it reads as its opposite. At that point the report prints the counts and no percentage (`3 turns, 3 failed`), which is still consistent and never over 100%. Scope and what I did not touch: - `window.js`'s two counters are unchanged — they are documented and the panel reads them. - `health.js` is unchanged; the digest now matches it instead of diverging. - `plugins/timeline/client.js:588` (the panel's Utilization line, same pair of numbers) is **not** changed. It prints two raw counts and no rate, so it cannot overclaim a share; changing the count it prints would make the panel disagree with the documented meaning of `utilization.turns` (invariant 5) that the rest of the panel and `health.js` rely on. If the owner wants the panel to print the comparison denominator too, it is a separate, one-line change with its own test. - `changelog.d/1578-digest-error-rate.fixed.md` added. Docs unchanged: invariant 5 already states the rule this change implements. `Docs-not-needed: docs/subsystems/timeline.md invariant 5 (line 52) already states this rule — the error rate divides by the larger of the turns that began in the window and the failed turns, so it never reads above its turn count. This change makes digest.js obey that sentence; it adds and changes no documented behaviour, and window.js, health.js and client.js are untouched.` Same line in the branch commit (`git log -1 --format=%B`), so the trailer survives the squash into the commit `main` judges, and it is what turns `arch-docs` green at the tip: `arch-docs: FAIL` was the only reason the first tip's `tests-ok` was red. ## Red → green At the base with only `test/digest.test.js` added (source at `main`): **13 tests, 10 pass, 3 fail** — - `ThinkFlowLab#1578: three failed turns that began before the window never read as 300% of one turn` - `ThinkFlowLab#1578: a failed turn that began before the window is not read as the window's own turn failing` - `ThinkFlowLab#1578: a single turn reads as one turn in all three places` The fourth new test, `ThinkFlowLab#1578: a clean window is byte-identical to the report before the change`, passes on both sides by design: it is the pinned output (`turns: 3, errors: 0`) that proves the denominator does not move when `errors <= turns`. At the tip: `test/digest.test.js` **13/13**, `plugins/timeline` **129/129** (base 125 + these 4). ## Verification at the tip Tip `8139276924c95ec4f30691244c8e4c3d2030ebe0`, tree `bd8db4c70d8271142d4798b42b8405d73ff9953f`, base `c1b9fd23e404dcff1eb782a2269e30e09e2d6993`, 3 files `+86/−10` (`digest.js` 20/10, `test/digest.test.js` 65/0, changelog 1/0). Ran: - `npm --prefix plugins/timeline test` → 129/129, 0 fail. - `TZ=UTC ARCH_DOCS_BASE=c1b9fd23e4 npm run verify` → exit 0: core 1869, social 527, tree 125, timeline 129, workflow 142, `.github/scripts` 548, interop 37, live-e2e 24 — 3401 tests, 0 fail; oxlint 0 errors (core 63 / social 36 / timeline 9 / tree 2 / workflow 13 warnings); `arch-docs: OK (3 changed file(s))` — the two plugin files are covered by the `Docs-not-needed:` trailer below; `build-client --check` and `ds-bot-patches check` clean. - `node .github/scripts/changelog.mjs check` → 63 fragments well formed. - `cd core && ARCH_DOCS_BASE=c1b9fd23e4 node scripts/check-arch-docs.mjs` → `arch-docs: OK (3 changed file(s))` at the tip with the `Docs-not-needed:` trailer in both places (first tip: `FAIL` on the same two files, `tests-ok` red for that reason alone). Not run: the smoke test (no `core/index.js` or `src/host/` change), the `package` job, Desktop, and the owner's live instance. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1579, "claim": "Dev-1", "issue": 1578, "summary": "The team report divided overlapping failed turns by the turns that began in the window, so a failure from before the window printed as 1 turns, 3 failed (300%). The digest now counts against max(turns, errors), the denominator health.js already uses, in the per-Bot line, the Team line and the one-line summary, with the team total the sum of the Bot sections. It prints a share only below 100%, since with every counted turn a failed one the numbers cannot say whose turn failed, and singular/plural follows the count. window.js, health.js and client.js are untouched.", "files": ["plugins/timeline/src/digest.js", "plugins/timeline/test/digest.test.js", "changelog.d/1578-digest-error-rate.fixed.md"], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=c1b9fd23 npm run verify", "result": "green", "at": "8139276924c95ec4f30691244c8e4c3d2030ebe0" }, "next": "none — ready for review at the tip" } ``` <!-- /flybot:checkpoint -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Owner: Danyang Chen
Reviewer: Reviewer
Written-by: Grok Bot (box-local; no Cursor CloudAgent)
Fixes #1570
Fixes #1571
Extends #1537 / #1538 / #1539 lineage. LIVE tip
62023599(2026-10-28 Asia/Shanghai) re-looped Claim↔Verify on an unchanged tip SHA and re-ran Claim when an open PR already existed; loop/onFailmax=3amplified. Morning Claim also sat ~88m — LIVE image predates #1540's deadline, andsyncTimersalso requiredrun.ephemeralbefore arming.What changed
checkEarlyEnd: addtip-unchangedandopen-pr(OUTPUT / whole-lineEARLY-END <reason>/ common phrases). Keepneeds-human+already-claimed.completeNode/loopDecision: early-end skips success-path loops.failNode+applyOp: early-end wins over onFail recovery (no Claim↔Verify burn).syncTimers: armSTEP_DEADLINE_MSfor every live running step, even without an ephemeral map (fix(workflow): STEP_DEADLINE must arm for live steps even without an ephemeral map #1571).EARLY_END_GUIDANCEintemplate.js+ docs for Claim/Verify/Triage prompts (Verify escalates once on unchanged tip).Verification at the tip
Tip SHA:
46ddc0c85af0eec98e95e0cc7f6c8380da2b8f3dRan:
cd plugins/workflow && node --import ./test/resolve.mjs --teston all suite files excepthost.test.js(sandbox missing@deepseek-ai/dsh-llm) → 132 pass / 0 fail (includes 8 new early-end cases + 1 new deadline case).node .github/scripts/changelog.mjs check→ well formed.Not run:
host.test.js(env); fullnpm run verify/ prod upgrade (out of scope).Residual
LIVE Settings graphs may still need operator prompt updates after deploy so Triage/Claim/Verify emit markers. No CloudAgent used; edited on box then PR.
Checkpoint
{ "pr": 1572, "claim": "Danyang Chen", "issue": 1570, "summary": "checkEarlyEnd now ends runs on tip-unchanged and open-pr (plus needs-human/already-claimed), skips loop and onFail burns on the same tip, arms STEP_DEADLINE without requiring ephemeral, and documents EARLY_END_GUIDANCE for Claim/Verify/Triage.", "files": [ "plugins/workflow/src/graph.js", "plugins/workflow/src/service.js", "plugins/workflow/src/template.js", "plugins/workflow/test/early-end-tip-and-pr.test.js", "plugins/workflow/test/deadline.test.js", "docs/subsystems/workflow.md", "changelog.d/1570-early-end-tip-openpr.fixed.md", "changelog.d/1571-step-deadline-no-ephemeral.fixed.md" ], "checks": { "ran": "plugins/workflow node --test (minus host.test.js); changelog check", "result": "green", "at": "46ddc0c85af0eec98e95e0cc7f6c8380da2b8f3d" }, "next": "none — ready for review; operator may update LIVE Settings prompts after deploy" }