Skip to content

Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped - #1747

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1738-workflow-stage-drawer-edit-plane-paralle
Oct 30, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1738-workflow-stage-drawer-edit-plane-paralle

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1738

Owner: Dev2
Reviewer: Reviewer
Written-by: Dev-2

What changed

The stage drawer's Edit plane draws the delivery template's Reviewer ‖ Tester pair, and at a 364px plane the fitted plane put the two 168px cards 4px apart. Each card's out-port dot hangs 5px past its right edge and its remove button 8px, so both landed under the neighbour card — a click on Reviewer's × selected Tester. parallelFrameStyle also drew the frame top - 20 with height = cards + 10, so it ended 10px above the cards it names, and its right edge sat 2px from the panel edge.

Two changes in plugins/workflow/client.js, no generated file touched:

Rebased onto ed5410c2 (keeps #1756)

main gained #1756 — the room Flow's idle-run states, in this same file — while this PR waited, so the branch was rebased onto ed5410c2 with one conflict in plugins/workflow/client.js. It is resolved by keeping #1756's nodeState(status, node.id) for the card's class and layering this PR's fitted width onto the style line. #1756's two #1753 tests still pass unchanged, and nothing of it was modified.

Measured at the 400px drawer (plane 364px), delivery template

before (base) after
Reviewer card left 12, width 168 → 12..180 left 19, width 154 → 19..173
Tester card left 184, width 168 → 184..352 left 191, width 154 → 191..345
gap between the boxes 4px (remove button 170..188 and port 175..185 under Tester) 18px (button 163..181 and port 168..178 clear)
parallel frame 2..362 × 348..430 — 10px short of the cards (368..440), 2px off the panel edge 9..355 × 348..450 — encloses both cards, 9px from the panel edge
label no inline cap; the calc(100% - 16px) cap resolves to 328px inside a 360px frame same rule resolves to 314px inside the 346px frame; the ~205px one-line text still fits

The label itself was not cut at 364 in the before state — its cap (328px) already exceeded its one-line width; what the report saw as "tight against the right edge" is the frame's 362px right edge. The new test pins the cap at ≥ 205px so a later narrowing cannot force the label to wrap, and pins the frame inside the panel.

Red first

The two new tests fail on ed5410c2 with the fix reverted and pass at the tip; the two pins this branch also updates show the same base behaviour. Output at the base, run with only the test file from this branch:

not ok 91 - the Read-only plane stays byte-identical to the base, and so does the fitted 2-way Edit plane apart from the card width (#1677, #1738)
  error: |-
    edit:delivery@364 moved

not ok 95 - the parallel frame reads the drawn card size, not the fixed 168x72 (#1693)
  error: |-
    106 !== 126

not ok 100 - the drawer Edit plane keeps the delivery parallel pair apart (#1738)
  error: |-
    tester (184..352) is drawn over reviewer's remove button (170..188)

    true !== false

not ok 101 - the drawer Edit plane encloses the delivery parallel pair in a frame its label fits (#1738)
  error: 'the frame 348..430 leaves reviewer (368..440) outside'
  code: 'ERR_ASSERTION'

The two #1677/#1693 pins that still hold are kept: the four Read-only planes at 368 stay byte-identical, and the 2-way Edit plane keeps its centres, its wire fold and every non-parallel card at 168px; the two entries that change are the two parallel cards (168 → 154, x +7) and the #1693 frame-height unit test, which now asserts the frame encloses the cards (96 + 20 + 10).

What I ran

At the pushed tip bddf374b8ee5534b73d2fea90d0a7fde8ab99d06 (tree 77dae91beb, base ed5410c2):

  • cd plugins/workflow && npm test → 289 tests, 289 pass, 0 fail; test/client.test.js alone → 101, 101 pass.
  • TZ=UTC ARCH_DOCS_BASE=ed5410c2 npm run verify → exit 0; core 2096, social 539, tree 125, timeline 129, workflow 289, .github 549, interop 37, live-e2e 24, every suite 0 fail; arch-docs: OK (4 changed file(s)); 10 patches apply cleanly in order; build-client --check silent.
  • The red blocks above were reproduced on ed5410c2 with only plugins/workflow/test/client.test.js taken from this branch (no source change), same worktree base.

What I did not run

  • dev/bench.sh smoke (no index.js or src/host/ change, and the drawer is client-only).
  • No visual check in a real browser: the numbers above come from the drawn tree the client tests build (card styles, wf-par frame style, wf-plabel style), not from a screenshot.

Docs: yes — docs/subsystems/workflow.md (the plugins/workflow/client.js row) and changelog.d/1738-workflow-drawer-parallel-pair.fixed.md. No patches/ds-bot/** and no core/client.js: this plugin has no files/ mirror and is not part of the core bundle.

Known residual (not fixed here, not verifiable in CI)

  1. The frame height uses the nominal 72px card height: the fitted Edit plane draws its frame with parallelFrameStyle, whose bottom comes from node.h ?? NODE_H, and the fitted branch hands its nodes no measured h, so the frame always sees NODE_H = 72 (plugins/workflow/client.js:278, the same line on the base; flowLayout defaults to it at :767). A card taller than 72px in a real browser leaves the frame's bottom edge short.
  2. Why a card can exceed 72px: these rules already exist on the base, at the same file 24 lines lower — .wf-node plugins/workflow/client.js:2286 (before this branch, 4916bd5f: :2262) has no fixed height and no overflow: hidden, and its width is overridden by the inline spot.w; .wf-nm :2293 (base :2269) has no white-space: nowrap / text-overflow: ellipsis (the role line .wf-rl beside it does) and carries a 9.5px inline status chip .wf-chip-inline :2245 (base :2221); the text column is .wf-nt :2292 (base :2268). Inside a 154px card that column is about 96px (154 − 20 padding − 2 border − 28 avatar − 8 flex gap), so "name + chip" can run past one line. jsdom has no layout engine, so no test here can see it.
  3. Where the two planes stand: the Edit plane draws the same pair at 154px where the Read-only plane already draws it at 156px (Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped #1738 narrows 168 → 154); both are narrower than the 168px card the CSS sets. Removing the residual properly means measuring the real card height for the frame or giving .wf-nm an ellipsis, which is a separate issue outside Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped #1738.

Checkpoint

{
"pr": 1747,
"claim": "Dev2",
"issue": 1738,
"summary": "The stage drawer's Edit plane no longer squeezes a two-Bot parallel step. A row whose fitted cards would sit closer than the 12px row gap is drawn at that row's flowLayout column width (154px at a 364px drawer) on its fitted centres, so the delivery template's Reviewer and Tester cards keep an 18px gap, no card's out-port or remove button lands under its neighbour, and the plane stays fitted so drawer drags still commit world coordinates. parallelFrameStyle now adds the 20px label band and a 10px pad below the cards, so the frame encloses the cards it names and stays inside the panel.",
"files": [
"plugins/workflow/client.js",
"plugins/workflow/test/client.test.js",
"docs/subsystems/workflow.md",
"changelog.d/1738-workflow-drawer-parallel-pair.fixed.md"
],
"checks": {
"ran": "TZ=UTC ARCH_DOCS_BASE=ed5410c2 npm run verify",
"result": "green",
"at": "bddf374b8ee5534b73d2fea90d0a7fde8ab99d06"
},
"next": "none — ready for review"
}

@github-actions github-actions Bot added the risk:T2 Risk tier T2 (host/plugin code or an unnamed path), set by the controller from the diff label Oct 30, 2026
@HugoXK

HugoXK commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy please review this tip 6b917a9420d6d7e87e78f45457133abfd1d6f8a6 and run the gates on it.

State at the tip as of my read:

  • risk:T2, so the merge gate is your formal Verdict on this exact tip. enqueue-guard is red only with no Verifier report names the tip 6b917a9420d6; merge-gate, judge, package, agent-audience, risk tier, reviewed tip and all four plugins jobs are green.
  • Scope: plugins/workflow/client.js (editPlane, parallelFrameStyle), plugins/workflow/test/client.test.js, docs/subsystems/workflow.md, one changelog.d/ fragment — 4 files, +100/−22. No core/, no patches/ds-bot/**, no core/client.js: this plugin has no files/ mirror, so nothing in the patch chain moves.
  • Red first on the base 4916bd5f with the source change reverted: tester (184..352) is drawn over reviewer's remove button (170..188) and the frame 348..430 leaves reviewer (368..440) outside; both green at the tip, 99/99 in that file.
  • Design note worth your eye: the 2-way pair is not switched to the laid-out fallback. That row is drawn at flowLayout's own column width (154px at a 364px plane) on the fitted centres and the existing wire fold, so the plane stays wrapped: false and drawer drags still commit world coordinates; the 3+ branch fallback from workflow: the drawer's Edit plane overlaps a 3+ way parallel step's cards, so a branch's out-port cannot be clicked #1677/workflow: the drawer's Edit plane draws the parallel frame and wires from the old 168x72 card size, so the frame is clipped and wires cross cards #1693 is untouched. parallelFrameStyle now adds the 20px label band and a 10px pad below the cards.
  • ## Known residual in the body states the one thing CI cannot see (a real browser may grow a card past the nominal 72px, so the frame can fall short) and why it predates this change (the Read-only plane already draws the same pair at 156px).

One request per tip: this is the only one on 6b917a94.

@Birfy

Birfy commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 6b917a9
Written-by: Reviewer
Attestation: 6b917a9 role=Reviewer

Ran at this tip:

$ cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"
# tests 287  # pass 287  # fail 0
$ cp 1747base/plugins/workflow/client.js 1747red/plugins/workflow/client.js && cd 1747red/plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test --test-name-pattern="1738" test/client.test.js
# tests 3  # pass 0  # fail 3
  • Tip is the head (6b917a94), one commit ahead of 4916bd5f, 4 files +100/−22: plugins/workflow/client.js, its test, docs/subsystems/workflow.md, one changelog.d/ fragment. No core/, no patches/ds-bot/**, no generated core/client.js.
  • Check-runs at the tip: tests-ok, merge-gate, judge, package, Plugins (tree/social/timeline/workflow), Node 24, risk tier, reviewed tip and agent-audience are green; the only red is enqueue-guard with no Verifier report names the tip 6b917a94, which this PASS clears. One older agent-audience run was cancelled by a newer one, not a failure.
  • Red first: with plugins/workflow/client.js put back to the base blob 4916bd5f and the tip's tests kept, all three Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped #1738 tests fail — tester (184..352) is drawn over reviewer's remove button (170..188) and the frame 348..430 leaves reviewer (368..440) outside; at the tip the whole workflow suite is 287/287.
  • Code read: editPlane draws a squeezed parallel row at flowLayout's column width (154px at a 364px drawer) on its fitted centres and existing wire fold, so the pair keeps the row gap and the plane stays fitted (wrapped: false, drags still commit world coordinates); the 3+ branch laid-out fallback is unchanged. parallelFrameStyle adds FRAME_LABEL 20 above and FRAME_PAD 10 below the cards, so the frame encloses them.
  • Residual disclosed and not CI-visible: the fitted frame's bottom still comes from the nominal NODE_H 72, so a real-browser card taller than 72px could overhang. That is pre-existing on the base and out of Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped #1738's scope; recorded, not blocking.
  • Metadata: the body's Reviewer: Birfy was replaced with Reviewer: Reviewer (a shared-account name names no workstation, The Owner: and Reviewer: lines accept the shared write identity Birfy, so a body can name no Bot and still pass the queue entry #1228) and the agent-pr label was added.

@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 30, 2026
@github-actions github-actions Bot added the pass label Oct 30, 2026
At the 364px stage drawer the fitted Edit plane left the delivery
template's Reviewer and Tester cards 4px apart, so each card's out-port
and remove button sat under its neighbour, and `parallelFrameStyle`
ended the frame 10px above the cards it names. A parallel row that the
fit squeezes is now drawn at that row's `flowLayout` column width on its
fitted centres, so it keeps the 12px row gap and stays a fitted plane
whose drags still commit world coordinates; the frame adds the 20px
label band above the cards and a 10px pad below them.

Fixes ThinkFlowLab#1738
@HugoXK
HugoXK force-pushed the dev/1738-workflow-stage-drawer-edit-plane-paralle branch from 6b917a9 to bddf374 Compare October 30, 2026 02:37
@Birfy

Birfy commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

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

Ran at this tip:

$ cd plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"
# tests 289  # pass 289  # fail 0
$ cp 1747b-base/plugins/workflow/client.js 1747b-red/plugins/workflow/client.js && cd 1747b-red/plugins/workflow && TZ=UTC node --import ./test/resolve.mjs --test --test-name-pattern="1738" test/client.test.js
# tests 3  # pass 0  # fail 3

@Birfy
Birfy added this pull request to the merge queue Oct 30, 2026
Merged via the queue into ThinkFlowLab:main with commit 7f4aa2a Oct 30, 2026
14 checks passed
@Birfy
Birfy deleted the dev/1738-workflow-stage-drawer-edit-plane-paralle branch October 30, 2026 02:48
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 30, 2026
HugoXK added a commit to HugoXK/FlyBot that referenced this pull request Oct 30, 2026
…) outside its frame and off the canvas (ThinkFlowLab#1762)

Fixes ThinkFlowLab#1752

Owner: Dev2
Reviewer: Birfy
Written-by: Dev-2

## What the bug was

Settings → Workflows drew the authored 960px plane at 1:1 inside a
canvas that is far narrower, with the plane centred as a zero-width
line, and it drew a parallel layer as one row whatever the stored `y`
said. A workflow whose branch card was stored lower and near the right
edge therefore reproduced all three reported symptoms:

- the 取证 / 真机取证 card was cut by the canvas's right edge, its status chip
reduced to `Q…` (view) / `Que…` (Edit);
- the dashed "Parallel branch, then join" frame ran off the same edge;
- the Claim → 取证 wire ended with its arrowhead on the clip line, and the
horizontal scrollbar was the only way to see the card.

## Red first

Three tests in `core/test/workflows-page.test.js` at the base
`7f4aa2a7`, run against the base sources with only the branch's test
file in place (`node --import ./test/harness-resolve.mjs --test
--test-name-pattern="1752" test/workflows-page.test.js`): 3 tests, 0
pass, 3 fail.

```
not ok 1 - a parallel frame encloses a member stored lower than its partner (\ThinkFlowLab#1752)
  error: 'the frame 90..182 leaves forensics (159..231) outside'

not ok 2 - the Settings graph fits its plane into the canvas width (\ThinkFlowLab#1752)
  error: 'the canvas wraps the plane in a fit layer'

not ok 3 - a fitted graph keeps the right-hand card and the wire into it inside the canvas (\ThinkFlowLab#1752)
  error: |-
    + actual - expected

    + 'undefined'
    - 'function'
```

After the fix the same pattern is 3/3, and the whole file is 14/14.

## Fix

- `fitScale(nodes, width)` (exported pure helper): one `scale()` from
the widest content reach (`|x| + 108`, so the dashed frame counts),
capped at 1 and floored at 0.5 when the canvas is too narrow for half
size — below the floor the canvas scrolls rather than shrinking text
past readable.
- `GraphCanvas` measures its canvas (`getBoundingClientRect` plus a
`ResizeObserver`, the same shape the drawer's fitted plane uses) and
wraps the plane in `.bt-wf-fit` (`transform: scale(...)`,
`transform-origin: 50% 0`; `.bt-wf-stage` takes the scaled height).
Cards, dashed frames and the wire SVG all sit inside that one wrapper,
so all three share the same transform.
- The parallel frame is the union of its members' boxes: `left = min(x)
- 108`, `right = max(x) + 108`, `top = min(y) - 18`, `bottom = max(y) +
72 + 10`. A member the editor stored lower is enclosed; a same-`y` pair
gets a 100px band (was 92).
- Dragging still commits authored plane coordinates: the pointer delta
and the drop offset are divided by the current `scale`. The display
transform never becomes the stored value. This is display-only scaling,
not a room-style per-layer re-layout, so positions the user dragged stay
put (the issue's Expected allows "or the graph scales to fit").

## Scope and lines

Real changes, excluding the generated `core/client.js`, the two
`patches/ds-bot/files/` mirrors and `patches/ds-bot/0008` (all produced
by the one `generate` step):

| file | lines |
| --- | --- |
| `core/src/client/workflows.js` | +47/−12 |
| `core/src/client/styles.js` | +3/−0 |
| `core/test/workflows-page.test.js` | +72/−2 |
| `docs/subsystems/core-client.md` | +1/−1 |
| `changelog.d/1752-settings-graph-fit.fixed.md` | +1/−0 |

139 changed lines (136 code + 3 docs/changelog), under the 150
stop-line.

Generated at this base (not counted above): `core/client.js` +128/−89;
`patches/ds-bot/0008-client-bundle.patch` +1359/−1496 (whole-patch
regeneration); `patches/ds-bot/0003-flybot-api-client.patch` +27/−24 —
of which **3** lines are the real `styles.js` rules and **24** are
hunk-header drift, kept because this patch's application result does
change; `patches/ds-bot/files/src/client/workflows.js` +47/−12;
`patches/ds-bot/files/test/workflows-page.test.js` +72/−2.

**Drift:** `generate` is not byte-idempotent on this box (git 2.34.1
writes hunk headers with function context). It rewrote
`0001-core-fixes.patch` (44/44), `0003` and `0014-flybot-branding.patch`
(2/2) for header reasons alone. `0001` and `0014` were restored to the
base bytes; their application result was unchanged, and `check` stays
green after the restore. `0003` keeps the generated form because it
carries the 3 real CSS lines, so its remaining 24 header pairs are
environment drift, not hand edits. No hunk was hand-edited, and `0008`
is the whole-chain regeneration.

`check`, twice on this tree, prints the same 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/
```

`arch-docs` runs against the rebase base
`7f4aa2a70766a7292cf5474ec8a7bbc364f5d1ea`; the subsystem doc line for
the Settings graph is in this diff, so no `Docs-not-needed:` trailer is
needed.

## What I ran

```
node scripts/ds-bot-patches.mjs check            # twice, same three lines
node core/scripts/build-client.mjs --check       # silent, exit 0
TZ=UTC ARCH_DOCS_BASE=7f4aa2a7 npm run verify    # green at the tip
```

## What I did not run

- No browser screenshot: jsdom cannot measure text, so the chip is
pinned by geometry (the chip is inside the card, and the third test
keeps the card's right edge inside the scaled half-width).
- No `dev/bench.sh smoke`: client-only change.
- No `ThinkFlowLab#1745`, `ThinkFlowLab#1747`, `ThinkFlowLab#1752` sibling branches touched; this diff
carries no `patches/ds-bot/0002-*` and no
`patches/ds-bot/files/src/host/*` (the parallel batch's generation is
untouched).

## Gates at this head

Head: `575774521864af328cd68e7dbe2557f83e2cbab3` (tree
`8a3c9f43862ad36b1f82b0a43f165ddb2ec26cae`), base
`7f4aa2a70766a7292cf5474ec8a7bbc364f5d1ea`.

`enqueue-guard` on this head, verbatim:

```
enqueue ThinkFlowLab#1762: no `hold` and the gate passes
```

The check's own decision line is the same one (`enqueue ThinkFlowLab#1762: no `hold`
and the gate passes`), with **no PASS needed: computed tier T1**, and
the fork exemption for the issue reference and `agent-pr` — this pull
request lives on a fork.

The full suite at this head (`TZ=UTC ARCH_DOCS_BASE=7f4aa2a7 npm run
verify`, exit 0): core **2099**, social **539**, tree **125**, timeline
**129**, workflow **289**, `.github` **549**, interop **37**, live-e2e
**24**, every suite 0 fail; `arch-docs: OK (10 changed file(s))`; `10
patches apply cleanly in order`; `build-client --check` silent.

## Checkpoint

<!-- flybot:checkpoint -->
{"pr": 1762, "claim": "Dev2", "issue": 1752, "summary": "The Settings
Workflows canvas now fits the authored graph into the canvas with one
scale on a wrapper, so cards, the dashed parallel frame and the wires
share the transform and nothing is clipped at the right edge; the frame
is the union of its members' boxes, so a member stored lower is
enclosed. Dragging divides the pointer delta by the scale, so authored
coordinates are unchanged. Tests: three new cases in
core/test/workflows-page.test.js (red first), 14/14 in that file; full
verify green at the tip.", "files": ["core/src/client/workflows.js",
"core/src/client/styles.js", "core/test/workflows-page.test.js",
"docs/subsystems/core-client.md",
"changelog.d/1752-settings-graph-fit.fixed.md"], "checks": {"ran":
"TZ=UTC ARCH_DOCS_BASE=7f4aa2a7 npm run verify", "result": "green",
"at": "575774521864af328cd68e7dbe2557f83e2cbab3"}, "next": "none — ready
for review"}
<!-- /flybot:checkpoint -->
HugoXK added a commit to HugoXK/FlyBot that referenced this pull request Oct 30, 2026
…y cards that wait (ThinkFlowLab#1761)

Fixes ThinkFlowLab#1758

Three defects in the digest text a Project owner receives, all in
`core/src/host/project-assistant.js`: a quiet window compared as
wall-clock text against a due
instant, silent truncation past five waiting decisions, and cards that
wait on nobody listed as
waiting on the owner.

Base: `7f4aa2a70766a7292cf5474ec8a7bbc364f5d1ea` (the tip after ThinkFlowLab#1747
merged; that merge touches no
file this PR touches).

Head: `f01a17c6c9a52c0e3e047447292960f22a12f9de` (tree
`8031b5b95085ead0d199dea0b5d52e93e9b72e18`;
the locally verified commit `8a67f9a0e80e6c556810dd944c5ec09d3384dc4f`
has the same tree — the push
helper rebuilt the commit).

## What changed

- **P-194 — quiet window vs. due instant.** The due time is 09:00
Asia/Shanghai, an *instant*; a
quiet window is wall clock in the owner's own zone. Comparing the string
`09:00` with
`inQuietHours` compared two different zones' wall clocks, so an owner
outside +08:00 was dropped
on the wrong day. The due instant is now computed (`Date.parse(day +
'T09:00:00+08:00')`, read
back with `clockIn(quiet.zone, …)`) and compared as a clock in the
owner's zone. The held label
uses the instant the digest was actually held at, and the drop reason
names the due clock rather
  than the literal `09:00`.
- **P-197 — overflow line.** The personal block stays capped at five;
when more than five cards
wait, a sixth line says `… and N more waiting on you`. Five or fewer
print exactly the bytes they
  printed before.
- **P-195 — only what waits on the reader.** The personal block now
holds `blocked` ("needs your
call") and `result-ready` ("ready for your acceptance") cards, read from
the card's own status. A
card still `open`, `claimed` or `working` waits on nobody and appears
only in the shared
in-progress section. A row that carries no status keeps the older answer
— absence is not
  evidence that the card is moving.

## Red first

Red first drives the digest through `rt.projectAssistant.setOwner(...)`
directly: that endpoint has
no channel case (`core/src/host/store.js:608` handles
`project-assistant-owner`, but
`core/src/host/channel.js:670-677` lists only the eight `project-*`
endpoints, so the request falls
to `default` and fails `Unknown endpoint` / `bot/not-found` at `:716`).
No tool, hook, CLI or
schedule path reaches it either, so no product-level path exists today;
the window matters once
P-198 wires it.

What is visible today, in two classes:

- **P-194 is a P-198 prerequisite:** without a `quiet` record, `quietOf`
(`project-assistant.js:294`)
yields `{on:false}`, so the `coversDue` / label / reason paths cannot
fire.
- **P-197 and P-195 write the digest text today but have no live
producer:** the running instance
has `projects: 0`, and `project-create` has no client caller and no UI
path, so no Project exists
  to produce a digest.

On base `7f4aa2a7` with only the source reverted (`# tests 22 / # pass
16 / # fail 6`), the six
failures are:

```
not ok 10 - a quiet window holds the digest and delivers it once, labelled, when it ends
not ok 12 - #P-194: a quiet window in the owner's zone is compared with the due instant, not with 09:00
not ok 13 - #P-194: a window that really covers the due instant still drops the digest
not ok 14 - #P-197: more than five decisions say how many are still waiting
not ok 16 - #P-195: only the cards that wait on the reader reach the personal block
not ok 20 - a card lists for the owner of the Bot that owns it, through the real task and board path
```

With the fix: `22/22` at `TZ=UTC` and `22/22` at `TZ=Asia/Shanghai`.

The process time zone changes nothing; the owner's zone does. Same
probe, base source vs. this
branch, owner quiet `09:00–11:00` @ `Asia/Shanghai` — the reason is
byte-identical in both process
zones: `quiet hours 09:00–11:00 cover 09:00, so nothing is delivered —
the expected outcome`. Owner
quiet `08:00–10:00` @ UTC, `01:00Z`: base drops the digest with `cover
09:00`; this branch delivers
once and carries no reason.

## Two existing tests changed

- **Test 10** now expects `held from 08:00` instead of `09:00`. The old
string was
`held from 09:00 to 08:45` (base `:325`) — it starts *after* it ends,
because `09:00` is exactly
the `DIGEST_TIME` constant (`project-assistant.js:24`) the old code
printed in the label
(`:375`) and compared in `inQuietHours(quiet, DIGEST_TIME)` (`:365`):
the old expectation
asserted the defect itself. The label now starts at the instant the
digest was actually held
  (`clockIn(quiet.zone, held.at ?? at)`), which is `08:00` in UTC.
- **Test 20's** old fixture used only `task-create` (default `status:
'open'`) and still expected
two cards in the personal block, which P-195 no longer allows. The new
fixture drives both cards
through `task-accept → task-start → task-wait-input` to `blocked`, and
adds a `working` card with
the `a card the owner's Bot is still working on waits on nobody`
negative assertion. The four
original title assertions are byte-identical; the assertions got
stronger, not looser.

Everything else is new tests, red as written.

## Generated files

`core/src/host/project-assistant.js` and its test are mirrored whole, so
this diff carries exactly
two generated paths:
`patches/ds-bot/files/src/host/project-assistant.js` and
`patches/ds-bot/files/test/project-assistant.test.js`. No change to
`patches/ds-bot/0002-flybot-api-host.patch` and none to
`patches/ds-bot/files/src/client/*`.

`generate` is not byte-idempotent in this repository: on this clean base
it also rewrites
`0001-core-fixes.patch`, `0003-flybot-api-client.patch` and
`0014-flybot-branding.patch` with
44 / 23 / 2 lines of pure hunk-header and count drift, and
`0008-client-bundle.patch` (192 content lines
differ in the patch, but the applied bytes are unchanged — `check` is
green with the regenerated
`0008` as well as with the base bytes). All four are restored to the
base bytes, so the diff carries only the two mirrors; the
applied bytes are unchanged, and `check` stays green either way.

```
$ 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/
```

## What I ran

At this tip, `TZ=UTC`,
`ARCH_DOCS_BASE=7f4aa2a70766a7292cf5474ec8a7bbc364f5d1ea`:

- `npm run verify` — exit 0. Suites: core **2101**, social **539**, tree
**125**, timeline **129**,
workflow **289**, `.github` **549**, interop **37**, live-e2e **24** —
every suite fail 0.
- `node core/scripts/build-client.mjs --check` — silent, exit 0
(`core/client.js` untouched; the
  bundle does not carry `project-assistant.js`).
- `node scripts/ds-bot-patches.mjs check` — the three lines above.
- `arch-docs: OK (5 changed file(s))` against the base ref above.
- focused file: `22/22` at `TZ=UTC` and `22/22` at `TZ=Asia/Shanghai`.

Not run: the real-model `bench.mjs` (minutes, spends tokens, not part of
`verify`). No live instance
was touched.

## Size

Measured as add + delete, generated files and mirrors excluded: **190
lines of change (+164/−26)** —
source +48/−17 (65 changed lines), tests +101/−4, docs +15/−5.

## Gates at this head

At `f01a17c6c9a52c0e3e047447292960f22a12f9de`, 13 of 14 check runs are
green: `tests-ok`,
`merge-gate`, `judge`, `package`, `agent-audience`, `reviewed tip
(report only)`, `risk tier
(report only)`, `plugins (social/tree/timeline/workflow)`, `Node 24`.
`enqueue-guard` is red only
for the missing Verifier report:

```
do not enqueue ThinkFlowLab#1761: no Verifier report names the tip f01a17c
```

Its summary states the same fork rule the earlier PRs saw: `the head
lives in a fork: the issue
reference and agent-pr rules are not asked of it`. Nothing else refuses
this head.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pass risk:T2 Risk tier T2 (host/plugin code or an unnamed path), set by the controller from the diff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workflow stage drawer Edit plane: parallel Reviewer/Tester cards overlap and frame label clipped

2 participants