Skip to content

Let one task lead assign group cards and start the assignee in the group - #1185

Merged
Birfy merged 1 commit into
mainfrom
cursor/group-task-lead-drive-d54f
Oct 25, 2026
Merged

Birfy merged 1 commit into
mainfrom
cursor/group-task-lead-drive-d54f

Conversation

@Birfy

@Birfy Birfy commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev
Owner: Dev
Reviewer: Reviewer

Fixes #1182

What changed

A group can pick one task lead (总负责人) for the board. That Bot, or the admin when none is picked, records the one overall task and assigns each part. Another Main who is only a member no longer plans. Assigning a card claims it, so the assignee starts without a confirmation.

The assignee is woken in its group session as soon as the card is written. The wake is a room turn ([Group chat "…" · your task]), and the reply is posted into the group when the turn ends. A question stays in that reply. Own-chat tasks stay [Continue task].

A member can still record or update its own room card, and can link its own subtask to the overall task.

Rebased onto origin/main bb96cc8 (#1178, Inbox Needs-you full ask). The inbox CSS and client bundle from that merge stay. This branch still delivers a group card as a room turn (taskDrive, note your task) and keeps the task-lead planner, plus noteWake, expireWriteBacks, and the two-wake / one-day cap from #1179.

Claim: branch cursor/group-task-lead-drive-d54f. A claim comment, assignee, and labels could not be written on #1182 (token 403). #1099 and #1109 are the closed foundations; open board issues (#1173, #1172, #1166, #471, #427, #149) are different and were left open.

Why

#1182: a group board had one overall card but no single planner — any Main who was a member could record it — and a card the lead assigned was not yet work: the assignee only started on the next nudge. So a group either had two plans or a card that sat until someone spoke. This makes the lead (or the admin when no lead is picked) the only planner, and makes an assigned card claim itself and wake the assignee's group session at once, with the answer posted into the group.

Acceptance

Assign

  • update_group task_lead, update-room taskLead, or Make task lead sets room.taskLead to a local member. Use the admin / none clears it. A face-to-face room has no board lead.
  • Only that lead, or the admin when none is picked, may record the overall task or assign a subtask. A second Main cannot.
  • A member may still file its own room card and may link its own subtask. It cannot assign work to someone else.
  • A subtask assigned to another Bot is created claimed. There is no confirm step. The lead still cannot move that card with task-update.

Proactive drive

  • The board write wakes the assignee's group session without anyone speaking. The session is opened if the Bot has not spoken there.
  • The wake is role: room with taskDrive, header [Group chat "…" · your task]. The cue says to start and not to wait for a confirmation, and to ask in the reply, not in the Bot's own chat.
  • A non-empty reply is posted into the room when the turn ends. An empty reply is not posted. A late post calls only the Bots it names. The driver does not post the cue and does not open a round.
  • A later board write while that wake is queued does not queue another. A live group round still defers the wake.
  • An own-chat task is unchanged: [Continue task], and the reply is not posted to a room.
  • A pending decision comment still wakes at most twice, then stops; after a day the record turns unconfirmed (task write-back: a pending comment never expires, and two naming nits (#1154 follow-ups) #1172). That cap does not silence a task that is still real work.

Verification at the tip

Tip SHA: 9ef18b8e63e292ba3149e20834838e6550b8bd26

The earlier tip 6f3077f59ccadd9e6605424098aa867edb8f8905 was removed from the queue for merge_conflict. This rebase is a new tip.

Ran:

  • On base 2521aab1c17ebb91b016b3b85122ccc872e36847, before the fix: TZ=UTC node --import ./test/harness-resolve.mjs --test --test-name-pattern "only the task lead" test/task-drive.test.js (from core/). Failed: /Only the group admin can record the overall task/ did not match - task-1f9d6f4966b9cac0 [not-started 0% normal overall] Take over. That assertion is the defect (a second Main recorded the overall task). Guardrails already true on that base: a non-admin updateRoom is rejected; a member may still link a parented subtask.
  • npm run build in core/ after the rebase; node scripts/ds-bot-patches.mjs generate and check. The rebuilt client.js contains both the Show the whole Needs you ask in the Inbox #1178 Needs-you wrap rule and Make task lead.
  • TZ=UTC npm run verify at the repo root after the rebase: exit 0.

Not run: the smoke bench (src/host changed; smoke is outside verify and no bench was started), the desktop app, and a real model turn.

Risk

Host: task-drive.js, tasks.js, roster.js, groups.js, tools.js, delivery.js, prompt.js; client: group-settings.js, i18n.js; regenerated client.js and the patches. The failure this could introduce is a room turn that does not start, or a card nobody but the lead can touch. Guardrails kept: a member still files and links its own room card, a non-admin's update-room is still rejected, and the #1172 cap (WRITE_BACK_WAKES = 2, WRITE_BACK_EXPIRY_MS one day) is untouched. Not run: the smoke bench (no bench started) and a real model turn — the wake is asserted on the injected session, not on a live Bot.

Open in Web Open in Cursor 

@cursor
cursor Bot force-pushed the cursor/group-task-lead-drive-d54f branch from 13a7e85 to 6f3077f Compare October 25, 2026 13:35
@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 25, 2026
@Birfy

Birfy commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 6f3077f
Written-by: Reviewer
Posted-by: Birfy
Attestation: 6f3077f role=Reviewer

Ran:

No actionable findings at 6f3077f. One task lead plans; assignee wakes in the group session. Rebase kept #1179 noteWake / expireWriteBacks / two-wake one-day cap. Author-login PASS attested for tip (Attestation line).

@github-actions github-actions Bot added the pass label Oct 25, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 25, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 25, 2026
@github-actions github-actions Bot added the risk:T3 Risk tier T3 (needs a human approval), set by the controller from the diff label Oct 25, 2026
A second Main could record the overall task, and an assigned card stayed
open. The wake was a private continue-task turn, so the reply never
reached the room. The picked lead (or the admin) now divides the board,
the card is claimed, and the assignee's turn is posted into the group.

Fixes #1182

Co-authored-by: Danyang Chen <birfychen@gmail.com>
@cursor
cursor Bot force-pushed the cursor/group-task-lead-drive-d54f branch from 6f3077f to 9ef18b8 Compare October 25, 2026 13:59
@Birfy

Birfy commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 9ef18b8
Written-by: Reviewer
Posted-by: Birfy
Attestation: 9ef18b8 role=Reviewer

Ran:

Not run:

  • smoke bench — src/host changed; the wake, the room turn, and the late post are covered by task-drive.test.js
  • Desktop / browser click-through of Make task lead beside the Inbox
  • fail-without-change re-run on 2521aab — the new test's comment claims that base; this review ran the green side at this tip

No actionable findings at 9ef18b8. One task lead plans; assignee wakes in the group. #1178 Needs-you wrap still present. Prior PASS at 6f3077f does not cover this tip. Author-login PASS attested for tip (Attestation line). Tier T3.

@Birfy
Birfy added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit 604ffa3 Oct 25, 2026
13 of 14 checks passed
@Birfy
Birfy deleted the cursor/group-task-lead-drive-d54f branch October 25, 2026 14:11
Birfy added a commit that referenced this pull request Oct 25, 2026
#1173)

Rebased onto main 604ffa3 (#1185), where the group task lead changed i18n.js, channel.js,
client.js and the patch series in the same places. The two overlapping sources were re-applied
on the new tree (the delivery ZH block and the delivery-board channel case), the bundle was
rebuilt there and the patch topics that carry this PR were regenerated; the doc rows sit beside
the task-lead paragraph rather than replacing it.

The task dialog gains a Delivery tab beside Tasks: one snapshot of the repository, not of one
Bot. Issues sit by state label, pull requests in review, and pull requests merged or closed
(merged or not) since the Asia/Shanghai day start in done today. The host module only reads:
every request is a GET, the token stays in the process, the payload carries no credential, each
URL is cached with its ETag and revalidated with If-None-Match, and no timer is installed.

Tests: core/test/delivery-board.test.js (11 cases: GET only, no token in the payload, columns,
closed-without-merge and no duplicate for a merged pull, badges by tip, Shanghai boundary, cache
and 304, no timer), core/test/delivery-view.test.js and core/test/kanban.test.js.
Birfy added a commit that referenced this pull request Oct 25, 2026
#1173)

Five columns from one cached snapshot — Original issue, Ready to start,
In progress, In review, Done today — plus the header metrics: the
Asia/Shanghai day against the last 7, issue-close and pull-merge medians,
the open counts, and CI as counted of total. Every request is a GET, the
token is read host-side per request and never enters the payload, and the
host installs no timer.

A pull closed today without merging is finished work, and it appears only
on /issues?state=closed: that endpoint describes a pull through its
pull_request object and sends neither a top-level merged_at nor a head.
The merge test reads pull_request.merged_at, such a card carries no sha,
and the numbers already counted as merged are filtered out of that bucket
so one pull cannot land on the board twice.

Rebased onto main 604ffa3: #1185 landed in the same files, so the two
subsystem pages keep main's wording with our rows merged in, and the
client bundle and the patch series are regenerated on the merged sources.
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 25, 2026
HugoXK pushed a commit to HugoXK/FlyBot that referenced this pull request Oct 25, 2026
ThinkFlowLab#1173) (ThinkFlowLab#1183)

Owner: Dev
Reviewer: Reviewer

Fixes ThinkFlowLab#1173

## What changed

A second view on the task dialog: **Tasks** stays the per-Bot board
(ThinkFlowLab#1058), **Delivery** is one read-only snapshot of the repository GitHub
work, in five columns.

- Host: `core/src/host/delivery-board.js` (new) reads issues, pull
requests and the day's workflow runs, lays them into `raw` / `ready` /
`working` / `review` / `done-today`, and caches each URL with its ETag.
Before: there was no repository view at all; the only board was
`state.tasks`.
- Every request is a `GET` (`get()` refuses anything else by
construction — there is no other request helper), the token is read
host-side and never enters the payload, and `read({ force })`
revalidates with `If-None-Match`, reusing the cached body on a 304 and
serving the stale snapshot while a refresh runs. It installs **no
timer**: the browser asks.
- Placement: an issue with `agent-working` sits in In progress,
`agent-ready` in Ready to start, anything else in Original issue; a pull
request is in In review; a pull request merged since the Asia/Shanghai
day start is in Done today, and a pull request **closed** today without
merging is there too, read from `/issues?state=closed` — the only list
that shows it, because `/pulls?state=closed` cannot tell "closed
unmerged" from a page that never reached it. A pull request card carries
the newest `Verdict:` naming **its own tip** — a verdict on an older tip
is ignored and CI speaks (`inc`, `pass-enqueue`, `pass-merge`, `ci-red`,
`ci-running`, `no-verdict`) — plus its short sha. The header reports
today against the last 7 days, medians for issue close and pull merge,
the open counts, and CI as `counted` of `total` rather than pretending
the capped list is complete.
- Client: `core/src/client/delivery-view.js` (new) renders the board,
shows `as of <time>`, and replaces it with one honest line when there is
no GitHub connection. `kanban.js` gains a `role=tablist` with **Tasks**
/ **Delivery**, and the Delivery branch renders no `bt-board-rail` — a
per-Bot rail over a repository-wide board would be a lie, and it is not
pointing the board at a Bot.
- Wiring: `core/index.js` installs the module before `channel`;
`channel.js` answers `delivery-board`; `authz.js` allows it to any
signed-in member (it reads one repository, not an owner's Bots);
`client/index.js` exposes `actions.deliveryBoard`. i18n has the new copy
in Chinese.
- Token: `install` passes a getter, not a value, and `rt.deliveryBoard`
awaits `rt.loadSecrets()` first. Before: the token was read once at
install, while `secrets.js` loads the file asynchronously, so a host
with `GITHUB_TOKEN` stored signed none of its requests (measured: 16/16
anonymous) and the anonymous limit failed a refresh halfway.
- Verdict sha: the sha in `Verdict: PASS at <sha>` decides the tip a
conclusion is about; `Attestation:` is only the fallback when that line
carries no sha. When the two lines name different shas the Verdict line
wins — the test `a verdict line wins over an Attestation that names an
older sha` fails if the order is read back to front. Before:
`Attestation:` was preferred, so a PASS naming the current tip could
read as "no verdict".
- Unchanged on purpose: `kanban.js`'s `boardRail`, `boardColumns`,
`columnTree`, the Tasks view output, `shared/task-board.js` (`COLUMNS` /
`COLUMN_OF` / `columnOf`), `tasks.js` and `tools.js`. `git diff` on
those is empty except the additions above.

## Why

ThinkFlowLab#1173 M1+M2 as Triage scoped it (comment 6397767597): the owner needs
one place to see where each issue and pull request actually is, without
the host writing to GitHub and without a background job that burns turns
(ThinkFlowLab#1166).

## Verification at the tip

Tip SHA: 48ef5dd

**Branch rewritten:** everything before this tip is obsolete —
`bd04e9cd`, `9a033cef`, `632030ec`, `e09370d9`, `27abe2bd`, `38eaf366`,
`ca393125`, `7f98a43b`, `707d1407` and every conclusion written on them
included. This PR is judged only on
`48ef5ddd6bea2e57d34b3dcccffd69874901b9b6`, one commit on `main
604ffa3`. ThinkFlowLab#1185 landed in the same files this PR touches (`i18n.js`,
`channel.js`, `client.js`, the patch series, both subsystem docs), so
those were re-applied on the new tree rather than overwritten: the
delivery ZH block and the `delivery-board` channel case sit beside the
task-lead ones, the doc rows beside the task-lead paragraph, and the
bundle plus the five patch topics that carry this PR were regenerated
there. One rebase in between (9a033ce) rebuilt i18n.js from a copy
older than main and deleted 17 Chinese entries main already had, so
tests-ok went red on test/i18n.test.js; this tip restores that merge,
and its tests-ok is green. Any later tip must update this line.

Ran at this tip (`TZ=UTC`, `DSH_HARNESS` at the local DSH 0.2.0-rc.2
install):

```
node scripts/ds-bot-patches.mjs check        -> 10 patches apply cleanly; core/ equals ds-bot/ + patches
node core/scripts/build-client.mjs --check   -> exit 0 (client.js is the build of src/client)
node .github/scripts/changelog.mjs check     -> 54 fragments well formed
test/delivery-board.test.js                  -> 12 pass / 0 fail
delivery-board, delivery-view, kanban, i18n, client-bundle together -> 23 pass / 0 fail
test/api-route.test.js + test/authz.test.js  -> 22 pass / 0 fail
```

The patches were regenerated after the rebase by rebuilding `core/` and
re-diffing it against `ds-bot/` in this tree; `check` rebuilds `core/`
from `ds-bot/` + `files/` + the series and compares, so a wrong hunk
cannot pass it.

Red-without-the-change, one knife at a time:

- make `columnOfDelivery` place a PR in Done today → the placement case
reds.
- drop the `If-None-Match` header → the 304 case reds (it fetches
instead of reusing).
- add `setInterval` to the host module → the no-timer case reds.
- render `boardRail` in the Delivery branch → the kanban case reds on
`bt-board-rail` count.
- drop the empty-state branch (`if (!snapshot)`) → the honest-message
case reds.
- read the token once at install (`token: tokenOf()`) → only the token
case reds (installed board sends no Authorization).
- drop the `at <sha>` fallback in `verdictOf` → only the
verdict-without-attestation case reds.
- read the merge test from the wrong field (`!row.merged_at` instead of
`!row.pull_request?.merged_at`) → **two** cases red: the five-column
list (a pull merged today appears twice) and the new one.
- take the abandoned card's sha from `row.head?.sha` → only the new case
reds (`''` instead of `null`).
- delete the closed-unmerged lines in `snapshotFromGitHub` → only the
new case reds: Done today reads `[41, 14]` instead of `[41, 52, 14]`.

## Not run

The full `core` suite locally finished 1511/1520, and every red is
environmental on this box, not this diff: `jsdom` is not installed in
the DSH checkout (composer-label, header-effects, read-page), `git` is
absent so `check-arch-docs` cannot diff (`cannot diff against HEAD` —
both subsystem docs are updated in this PR), the `usage.sqlite` fixture
test needs a sqlite module this host lacks, and the three `ThinkFlowLab#896` part
tests are the known `TMPDIR` guard (they pass with `TMPDIR=/tmp`;
reported as ThinkFlowLab#1059). CI's full run is the authority.
`plugins/social`, `plugins/tree`, `plugins/timeline` are untouched by
this diff.

## Risk and follow-ups

A live read of this repository (read-only, no token in the payload) is
part of the evidence: the board listed the open work and the day CI as
`failed 17 of 2500` (`counted 1000`). The first live read showed CI as
`0 of 0` — GitHub silently matches nothing when `created` gets epoch
milliseconds — so the range is ISO 8601 now and a case pins the format.

The board is read-only by construction; the only new surface is one
endpoint that returns a cached snapshot to a signed-in member. GitHub
rate limits are bounded by the 5 min cache and the 60 s client poll only
while the dialog is open. M3 (background sync, richer empty states) is
not in this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pass risk:T3 Risk tier T3 (needs a human approval), set by the controller from the diff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Group kanban: one task lead assigns, and that Bot starts the card without a nudge

2 participants