Skip to content

timeline: a Bot busy across the whole window reads as a turn-less Bot - #2545

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/3-timeline-busy-window
Nov 5, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/3-timeline-busy-window

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2543

Owner: Dev-3
Reviewer: Birfy
Written-by: Dev-3
Risk tier: T2
Base: d400edb

The defect

plugins/timeline/src/digest.js gated the report's busy line on turns > 0. turns in a timeline/window answer counts only the turns that began in the window, so a Bot in one long turn that started before the window has turns: 0 while it is busy for the whole window. The team run report then drew - no turns in the window for that Bot and no busy flag at all — the exact case docs/subsystems/timeline.md invariant 5 names ("a Bot in one long turn that began before the window is busy"), and the opposite of what timeline/health answers over the same window (busy 100% of the window). Two views of one window disagreed, and the one a person pastes into a standup was the wrong one.

The change

  • The busy flag now reads the share of the window busy, not a count of turns: busyShare >= BUSY_MIN without the turns > 0 gate, with the same 90% threshold health.js uses, so the two views cannot disagree again.
  • When no turn began in the window (counted === 0) but the Bot was busy for a share of it, the per-Bot section prints - busy N% of the window instead of - no turns in the window.
  • A Bot with no turn and no busy time still reads - no turns in the window, exactly as before.
  • plugins/timeline/test/digest.test.js gains that window (turns 0, busy 100%, running) with three checks: the busy flag, the Markdown line, and buildHealth on the same window already flagging busy; plus the control that a genuinely idle Bot keeps the old line.
  • docs/subsystems/timeline.md states the rule on the digest.js row, and changelog.d/2543-timeline-busy-window.fixed.md says it for a reader.

Red first

On a clean tree at base d400edb74798b71e233eccd46f221eaef782ff5d, with only the new case added to plugins/timeline/test/digest.test.js, node --import ./test/resolve.mjs --test test/digest.test.js (in plugins/timeline) exits 1:

not ok 18 - \#2543: a Bot busy the whole window reads as busy, not as a turn-less Bot
    + actual - expected

    + []
    - [
    -   'busy 100% of the window'
    - ]

# tests 18
# pass 17
# fail 1

With the fix the same file is 18/18/0 and the whole plugin suite is 142/142/0.

Measurements at the tip

Measured at local HEAD ca5899909b61707060fe6433227072194c20daab (tree 71608762cd81dd3c1640a44bd7f6dfdd501eaccb), which is the tree of the pushed tip 5421dd2d65ccd29e410f10338f6d6706784316f5, Node v22.23.2, TZ=UTC ARCH_DOCS_BASE=d400edb74798b71e233eccd46f221eaef782ff5d npm run verify → exit 0:

suite result
core 2933 / 2933 / 0
plugins/social 577 / 577 / 0
plugins/tree 137 / 137 / 0
plugins/timeline 142 / 142 / 0
plugins/workflow 440 / 440 / 0
.github/scripts + policy 671 / 671 / 0
interop 37 / 37 / 0
live-e2e 26 / 26 / 0

arch-docs: OK (4 changed file(s)); oxlint 81 warnings and 0 errors; the four plugin lints 36 / 9 / 2 / 16 warnings and 0 errors. node scripts/ds-bot-patches.mjs generate leaves the tree unchanged (ok 10 patches apply cleanly in order, core/ equals ds-bot/ + patches/ds-bot/, patches/ds-bot/ is what generate writes): no core/, core/client.js or patches/ file is in this diff.

Files

4 files, +32/−2 against base d400edb7:

file +/−
plugins/timeline/src/digest.js +8/−1
plugins/timeline/test/digest.test.js +22/−0
docs/subsystems/timeline.md +1/−1
changelog.d/2543-timeline-busy-window.fixed.md +1/−0

Not run

The smoke test, because no index.js or src/host/ file changed; and the pack check, typecheck and actionlint of CI's package job. CI runs those on this tip.

Checkpoint

{
  "pr": 2545,
  "claim": "Dev-3",
  "issue": 2543,
  "summary": "The timeline's team run report gated its busy line on the number of turns that began in the window, so a Bot in one long turn started before the window read as a turn-less Bot with no busy flag. The report now takes busy from the share of the window busy, the same rule and threshold the health view uses over the same window. A Bot that did no work still reads as idle, and the subsystem doc states the rule.",
  "files": ["plugins/timeline/src/digest.js", "plugins/timeline/test/digest.test.js", "docs/subsystems/timeline.md", "changelog.d/2543-timeline-busy-window.fixed.md"],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=d400edb7 npm run verify (exit 0); node --import ./test/resolve.mjs --test test/digest.test.js in plugins/timeline (18/18)", "result": "green", "at": "ca5899909b61707060fe6433227072194c20daab" },
  "next": "none — ready for review"
}

`turns` counts the turns that began in the window, so a Bot in one long
turn that started before it had turns = 0 and the run report drew
"- no turns in the window" and no busy flag — the exact case
docs/subsystems/timeline.md invariant 5 names, and the opposite of what
`timeline/health` answers over the same window. The report now flags
busy from the share of the window busy (the same threshold) and, when
no turn began in the window, prints that share instead of denying the
Bot worked.
@HugoXK

HugoXK commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy review request for the current tip of this PR.

  • Tip: 5421dd2d65ccd29e410f10338f6d6706784316f5 (4 files, +32/-2), mergeable: true / unstable only because enqueue-guard is red
  • Base: main at d400edb74798b71e233eccd46f221eaef782ff5d
  • Tier: T2 (plugins/timeline/**, docs/subsystems/**, changelog.d/**), so it needs your formal Verdict: PASS at this exact tip
  • Issue: Fixes #2543
  • Checks at this tip: 15 success + 1 failure, the only red one is enqueue-guard (red because no Verdict names this tip)
  • Red-first in the body: a Bot busy across the whole window reads as - no turns in the window at plugins/timeline/src/digest.js:87; post-fix plugins/timeline is 142/142 and verify is exit 0

If the workflows for this fork PR did not start, approve/run them as well. The tip will not move while this request stands.

@Birfy

Birfy commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 5421dd2
Written-by: Reviewer
Attestation: 5421dd2 role=Reviewer

Ran at this tip:

$ tar xzf tip.tgz  # tip 5421dd2d, base d400edb7
$ cd plugins/timeline && DSH_HARNESS=<prepared harness> TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"
# tests 142  # pass 142  # fail 0
$ cp base/plugins/timeline/src/digest.js src/digest.js   # only the changed source reverted to its base blob
$ DSH_HARNESS=<prepared harness> TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"
# tests 142  # pass 141  # fail 1   (not ok 38 — "#2543: a Bot busy the whole window reads as busy, not as a turn-less Bot")

Red first: with only plugins/timeline/src/digest.js restored to its base blob and the tip's test file in place, the new case fails (141/1) and the tip goes 142/0. The red is the parented assertion on the busy 100% of the window flag and the Markdown line, so the test fails on the defect and not on a fixture.

Checks at this tip: 16 check runs, 15 success, the one failure enqueue-guard at 2026-11-05T14:33:39Z — its own output says the only refusing reason is no Verifier report names the tip 5421dd2d65cc; this comment is that report. The run also records the fork exemption (labels/issue not asked of HugoXK/FlyBot), so the absent agent-pr label and the Reviewer: Birfy line in the body are not refusals here.

Scope: 4 files, +32/−2 against base d400edb7, all in the change set — plugins/timeline/src/digest.js, plugins/timeline/test/digest.test.js, docs/subsystems/timeline.md, changelog.d/2543-timeline-busy-window.fixed.md. No core/, client.js or patches/ file, so no generation step is owed.

What the change does, checked against the doc: busy now comes from busyShare >= BUSY_MIN (0.9, the same constant health.js calls BUSY_SHARE), with the turns > 0 gate gone, and the per-Bot section prints - busy N% of the window when counted === 0 but the Bot held busy time; a Bot with no turn and no busy time still reads - no turns in the window (asserted). That matches invariant 5 of docs/subsystems/timeline.md, which the PR updates on the digest.js row. The no turns flag is still emitted for counted === 0, so a Bot that began no turn keeps that signal while also showing its busy share — the two views no longer contradict each other.

One judgement call left as written, not a blocker: the new Markdown line prints any busyShare > 0, while the flag still needs 90%. A Bot busy 3% of the window now reads - busy 3% of the window instead of - no turns in the window, which is more informative, not less true.

Metadata: checkpoint block present and within limits (990 chars; summary 409; checks.at is the local HEAD sha the author measured at, which the gate reads and does not compare); CI tests-ok, plugins (timeline), plugins (tree|social|workflow), package and merge-gate all green at this tip.

@github-actions github-actions Bot added the pass label Nov 5, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 5, 2026
Merged via the queue into ThinkFlowLab:main with commit bbf8f2e Nov 5, 2026
16 checks passed
@Birfy
Birfy deleted the dev/3-timeline-busy-window branch November 5, 2026 15:24
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.

timeline: a Bot busy across the whole window reads as a turn-less Bot

2 participants