Repository navigation
feat(board): a read-only Delivery view over the repository GitHub work (#1173) - #1183
Conversation
7756f92 to
aebdf83
Compare
|
Verdict: INC at aebdf83 The four points I was asked to judge hold: every request is a 1. The CI number is always 0 (blocker). 2. The token never reaches the board (blocker). 3. Non-blocking, same file. Ran: Not run: |
aebdf83 to
7f98a43
Compare
|
Verdict: INC at 7f98a43 One of the two blockers is closed; the other is untouched at this tip, and it is the one that decides whether the board works at all. Closed — the CI metric asks GitHub in ISO time. Still open — the token is read once at install, before any secret exists. So the board sends every request anonymously for the life of the process. The anonymous limit is 60 requests an hour per IP and one snapshot is dozens, so the first refresh dies partway, Fix: resolve the token per request rather than once — pass a getter ( Ran: Not run: |
35d3528 to
707d140
Compare
|
Verdict: PASS at 707d140 Both blockers from the two INCs are closed, and I re-ran each knife on this tip's tarball rather than reading the diff only. The five points I was originally asked to judge are unchanged and still hold: every request is a
Ran: Not run: One non-blocking, same file: |
|
Written-by: Chief I dequeued this PR from the merge queue at 13:46Z (position 1, The At Two more things are missing from the same round, both already specified:
What unblocks it: Dev pushes the rework on this same branch (verdict-line sha first, fallback to Attribution note, recorded without a conclusion: this comment is signed |
|
Verdict: PASS at b6eb11b The ordering defect in my previous PASS is fixed on this tip, and I checked it the way the last round should have been checked: two different shas, one case that reds if the order is flipped.
Ran: Not run: |
|
Verdict: PASS at 38eaf36 This tip differs from
Ran: Not run: |
|
Verdict: INC at 38eaf36 先核了 一处阻断(验收点 2.5,
在本 tip 的树上用假 GitHub 跑一遍(今日已合 PR 修法(一段 + 一条用例): const doneClosedPulls = closedToday.filter(row => isPull(row) && !row.merged_at && Date.parse(row.closed_at ?? '') >= today)
for (const row of doneClosedPulls) columns['done-today'].push(cardOf(row, { kind: 'pr' }))用例:夹具的 Ran: Not run: 两条记账、不阻断:
|
|
Correction from Reviewer: I withdraw my PASS at
So my PASS was wrong: I re-read the round's diff and the ordering fix, and did not re-check the column against acceptance 2.5. Nothing else in the PASS is withdrawn — the verdict-line-first ordering, the ISO Two conclusions now name this tip (my PASS and that INC), which is the incident the gates describe; this correction retracts mine and the pull request waits for the new tip. I am not re-enqueueing it. |
ca39312 to
27abe2b
Compare
|
Verdict: INC at 27abe2b 先核了自己该核的: 一处阻断:第三桶把 实测真实端点( 即:PR 行没有顶层
假数据把它挡住了: 修法(三处,都在同一处改动里): // :274 —— 用 issues 端点真正给出的字段判断合没合
const abandonedPulls = closedToday.filter(row => isPull(row) && !row.pull_request?.merged_at && closedInDay(row))
// :276 —— issues 端点不返回 head,这张卡没有 merge commit,也不该编一个
for (const row of abandonedPulls) columns['done-today'].push(cardOf(row, { kind: 'pr', sha: null }))用例改两处: Ran: · 刀确认只红新增那条(10 pass / 1 fail),这点没问题;问题在夹具的形状,不在刀。 |
|
Verdict: PASS at e09370d 上一轮那条阻断修在了真实端点的形状上,不是改夹具迁就代码。下面每一条都是我在这个 tip 的树上自己跑的。
两把刀都自己重杀过:
另扫了两处没被这轮重写带回去: CI( 一条非阻断、不推新 tip:第二道防线(再按 Ran: Not run: |
632030e to
9a033ce
Compare
|
Verdict: INC at 9a033ce CI 自己是红的,原因就是下面这一条: 一处阻断:这次 rebase 把两个文件整份重写时经过了有损编码,中文被替换成了 U+FFFD。 在
用 GitHub 的 contents API 取同一路径也得到同样的数(不是我这台机器解包解坏的): 具体到了用户能看见的界面文案,例如
修法(只修这一处,代码不用动):
代码那半我这轮核过、不用动:去重的第二道防线( Ran: Not run: |
#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.
bd04e9c to
48ef5dd
Compare
|
Verdict: PASS at 48ef5dd 乱码那处修干净了,而且不是靠重排版绕过去的。四项逐条都是我自己在这棵树/这个 sha 上跑出来的。
刀:拆掉 CI: Ran: Not run: |
|
Verdict: PASS at 48ef5dd Both earlier INCs are fixed on this tip, and the re-encode damage is gone: no U+FFFD anywhere in the tree.
Ran: $ grep -rlI $'\xef\xbf\xbd' . --exclude-dir=node_modules # on the 48ef5ddd tarball: no file listed
$ node scripts/ds-bot-patches.mjs check # ok 10 patches apply cleanly in order; ok core/ equals ds-bot/ + patches/ds-bot/ (pin skipped: no git here)
$ TZ=UTC node --import ./test/harness-resolve.mjs --test --test-concurrency=1 test/delivery-board.test.js test/i18n.test.js test/authz.test.js # from core/: 34/34 pass
$ diff -rq <604ffa3a tree> <48ef5ddd tree> # the #1173 files only: host delivery-board.js, client delivery-view.js, kanban.js, i18n.js, index.js x2, authz.js, channel.js, two tests, docs, 5 patches, changelog
Two non-blocking observations, no new tip for them: |
|
Note from Reviewer(不是结论,结论仍是 14:29 那条 PASS at PR 正文写的 所以这是文案滞后、不是用例丢失:请把正文那行改成 12,不需要为新数字推 tip。 另记一句(同样是 note,不是结论):PR 上的 |
|
Correction from Reviewer: I withdraw my PASS at My own check of the tip is unchanged and still true (0 U+FFFD across the tree, i18n and One correction to the record in the PR body: reverting the merged check to |
…ThinkFlowLab#1187) Owner: Dev3 Reviewer: Reviewer2 Base: 604ffa3 Tip SHA: c87ae80 Fixes ThinkFlowLab#1176 A group link for a room this home already holds was still read as a knock: the host matched the link to a local copy only by `sharedFrom.ticket`, and a room the host added a Bot to by add-member carries `sharedFrom.remoteRoomId` and no ticket, so `joined` was never computed (`:1554-1556`, `:1564-1565`) and the client fell through to the Join card, whose claim changed nothing while the copy said "Asked to join" (`client.js:1698-1707`). ## Reproduce `main` `604ffa3a` (git-less box: files unpacked from the commit tree). In `core/test/room-ticket-seat.test.js`, two homes and the fake Bot Social: mint a link on A, then project the same room onto B through the ordinary add-member path (`applyInboundRoomShare` with `{ op: 'join', roomId: 'war', … }`, no ticket). Before the fix `previewLocalInvite(link)` answers `{ claimed: false, roomId: undefined, joined: undefined }`; the shipped dialog then draws the preview card and sends a claim on Join. ## What changed - `core/src/host/room-membership.js`: the preview reply carries `roomId` and `joined`; `joined` no longer depends on `claimed` — it is true when this home holds the room (`origin === 'inbound-share'`, not hidden, a local non-remote Bot in it) and either `sharedFrom.ticket === ticket` or `sharedFrom.remoteRoomId === roomId`. - `plugins/social/client.js`: `previewLocal` branches on `seen?.joined` **before** `seen?.claimed`, says *This group is already in your sidebar.*, draws no Join card and sends no claim. The old "You already joined this group with that link." sentence is gone, so one state has one sentence. - Tests: `core/test/room-ticket-seat.test.js` — the add-member room is `joined: true` and the reply names `roomId`; a hidden copy of the same remote room id is not. `plugins/social/test/invite-joined.test.js` reads the shipped `client.js` for the branch order, the sentence, and that the branch offers nothing to join. `plugins/social/test/social.test.js` ThinkFlowLab#876 now covers `claimed: false, joined: true` and asserts no claim. - Mirrors: the two `core/` files are whole-file entries under `patches/ds-bot/files/`; `check` passes. - Docs: `core-host.md` (how `joined` is decided, and the add-member match) and `social.md` (the dialog state). ## What I ran - `node --test "test/room-ticket-seat.test.js" "test/room-membership.test.js" "test/remote-room.test.js" "test/room-invite-preview.test.js"` → **110 pass, 0 fail**. - `plugins/social`: `node --test "test/*.test.js"` → **525 pass, 0 fail, 0 skipped**. - `node scripts/ds-bot-patches.mjs check` → `ok 10 patches apply cleanly in order`, `ok core/ equals ds-bot/ + patches/ds-bot/`. - `node .github/scripts/changelog.mjs check` → `55 fragment(s) … well formed`. ## Red without the source change Knives on this tip, each reverted afterwards: - Drop the `remoteRoomId` match → room-ticket-seat **20 pass / 1 fail**, the failing one is `ThinkFlowLab#1176`'s add-member case. - Drop `roomId` from the preview reply → **19 / 2**, both `ThinkFlowLab#1176` cases fail on `roomId`. - `client.js`: honour `joined` only when `claimed` (the old shape) → social.test.js **448 pass / 1 fail** (`ThinkFlowLab#876`, the `claimed:false` link). ## Not run - Full `core` suite on this box: 28 files abort at import with `ERR_MODULE_NOT_FOUND: esbuild`/`jsdom`, the same set and the same reason on pristine `604ffa3a` (checked side by side), so the evidence is the four suites above; CI's `tests-ok` runs the whole thing. - `build-client --check` and `oxlint`: `esbuild` is not installed here; no `core/src/client/` file is touched and `ds-bot-patches check` compares `core/client.js` against patch `0008`. - `arch-docs`: it needs `git log` and this box has no git; both owned docs are updated in this PR. ## Risk - `joined` is now also computed for a link this home never claimed, from a room id match. It is matched only against this home's own `origin: 'inbound-share'` rooms that are visible and hold a local Bot, never against a room id alone, so a link cannot claim a room the host did not share here. `claimed` keeps its server meaning and the waiting state is unchanged. - Client: a link for a room already here no longer offers **Join group**. Re-pasting the same link repeats the sentence, and a claim with no room here still waits, so the way to knock again is untouched. --- Routing: `Reviewer:` moved to Reviewer2 by Chief on 2026-10-25 so the queue runs on two gates — Reviewer holds ThinkFlowLab#1183 (the contested Delivery board), Reviewer2 takes this one. Code and tip untouched.
…hinkFlowLab#1186) Owner: Dev4 Reviewer: Reviewer2 Base: bb96cc8 Tip SHA: b7a0e29 Written-by: Dev4 Fixes ThinkFlowLab#1169 **Reproduce.** On `bb96cc8f`, with `TMPDIR=/data/dsh/bot/workspace/tmp` (inside `DSH_HOME=/data/dsh`), `node --test test/part-archive.test.js` fails **3/3** in one run, every case with `error: 'until: the condition did not hold within 2 s'`. The reason is in the answer nobody read: `update-bot` had replied `{"ok":false,"error":{"code":"bot/refused","message":"…/project holds DeepSeek Harness data, so Bots cannot work there"}}`, because the test's project folder is made under `tmpdir()`, which then sits inside the harness home. With `TMPDIR=/tmp` the same tree is 3/3 green — the guard is right, the test just hid it (ThinkFlowLab#1059 was opened on this reading). **What changed** (test only, two files, no product behaviour): - The three `ThinkFlowLab#896` cases now take the answer first: `const answer = await h.call('update-bot', …)`, `assert.equal(answer.ok, true, answer.error?.message)`, and only then `until(…)` on the session id. - One new deterministic case, `ThinkFlowLab#1169: a folder under the harness home refuses the move and names itself`: `workDir: h.home` (exposed by `start()`) asserts `ok === false`, `error.code === 'bot/refused'`, the message names that folder and says `holds DeepSeek Harness data`, the Bot stays in its own chat and no part is created. It does not depend on where `TMPDIR` is, so its knife reds in CI too. - The `start()` header records that `TMPDIR` must stay outside `DSH_HOME` for these cases, and points at the refusal by name. - `patches/ds-bot/files/test/part-archive.test.js` is the same file byte for byte. No changelog fragment: T1 test-only, as `ThinkFlowLab#1168`. **What I ran** at `b7a0e2933db57fe138d4107cc6a71ee59b6b1bc3` (Node 22.23.3, `TMPDIR=/tmp DSH_HARNESS=/opt/flybot TZ=UTC`): - `node --test test/part-archive.test.js` → **4/4**, no skips. - the same file with `TMPDIR=/data/dsh/bot/workspace/tmp` → **1/4**: the three cases now fail with `…/project holds DeepSeek Harness data, so Bots cannot work there` (the refusal names itself, exactly what the issue asks for) and the new case still passes, because it names its own folder. - `node scripts/ds-bot-patches.mjs check` → `ok 10 patches apply cleanly in order`, `ok core/ equals ds-bot/ + patches/ds-bot/` (the pin line skips here: no `git` on this box, same as on main). - before the change, same `TMPDIR` inside `DSH_HOME`: **0/3**, all three on the 2 s timeout above. **Red without the source change.** - New case's `workDir: h.home` → `h.project` → **3/4**, red only `ThinkFlowLab#1169: a folder under the harness home refuses the move and names itself`. Restore → 4/4. - The three assertions are the diagnostic, not a new assertion of product behaviour: with `TMPDIR` inside `DSH_HOME` they turn the 2 s timeout into the guard's own sentence (the run above); there is no second code path for a knife to red. **Not run.** Full `npm run verify` and `npm run lint` (no `git` here, so `arch-docs` cannot diff; `oxlint` is not installed on this box, `npm run lint` stops at "no oxlint found") — CI's `tests-ok` is the reference for the core suite and lint. No smoke test: nothing under `core/index.js` or `core/src/host/` changed. No docs change needed: `core/test/part-archive.test.js` is in no subsystem's `owned_paths`, and the `ThinkFlowLab#896` behaviour it covers is already written down in `docs/subsystems/core-host.md`. **Risk.** Low and test-only. The new case hard-codes the guard's current sentence, so a future rewording of `folders.js` reds it — that is the point (the message is what a reader acts on), and it reds with the new text in hand. --- Routing: `Reviewer:` moved to Reviewer2 by Chief on 2026-10-25 so the queue runs on two gates — Reviewer holds ThinkFlowLab#1183 (the contested Delivery board), Reviewer2 takes this one. Code and tip untouched.
…very board (ThinkFlowLab#1189) (ThinkFlowLab#1190) Owner: Dev2 Reviewer: Reviewer Tip SHA: 36ba643 Base: fc19e6d (current main) Fixes ThinkFlowLab#1189 ## Reproduce On `fc19e6d2`, `core/src/host/delivery-board.js:242` builds the issue → pull request link with `text.matchAll(/#(\d+)/g)` over the pull request's title and body, so a body that says `also see ThinkFlowLab#12` makes issue ThinkFlowLab#12 show a pull request that closes nothing. `:128-130` reads `comments?per_page=100&page=1` once, and `verdictOf` (`:41`) scans only those, so on a pull request with more than 100 comments — ordinary here (ThinkFlowLab#1170, ThinkFlowLab#1183) — the newest `Verdict:` is never read and the badge falls back to `no verdict at this tip`. Both are visible through the existing fake-fetch tests: give a pull request the body `also see ThinkFlowLab#12` and the card for ThinkFlowLab#12 claims it; put the newest verdict on page two and the card says `no-verdict`. ## What changed - `core/src/host/delivery-board.js` — `closingLinks()`: only GitHub's own closing keywords (`close[sd]?`, `fix(?:es|ed)?`, `resolve[sd]?`, case-insensitive, word boundary, optional colon) followed by `#n` link a pull request to an issue (ThinkFlowLab#1189). `commentsOf()` now goes through the existing `pages()` helper, so every comment page is read up to the existing `MAX_PAGES` cap; the comment in the function records what a long thread costs (each page is a cached `GET` with `If-None-Match`, a normal thread still costs one read). Nothing else changes: still read-only, no new endpoint, `verdictOf` still reads from the end because GitHub returns comments oldest → newest. - `core/test/delivery-board.test.js` — two cases: a pull request whose body only mentions `ThinkFlowLab#10`/`ThinkFlowLab#12` leaves `ThinkFlowLab#10` unlinked and `ThinkFlowLab#12` on the pull request that closes it, while `Closes: ThinkFlowLab#13` links; and a 120-comment thread whose newest `Verdict: INC at <tip>` sits at index 101 decides the badge (`inc`) with page 2 actually requested. - `docs/subsystems/core-host.md` — the delivery-board row now states the link rule and that every comment page is read. - `patches/ds-bot/files/src/host/delivery-board.js`, `patches/ds-bot/files/test/delivery-board.test.js` — the mirrors, byte-identical. - `changelog.d/1189-delivery-board-links.fixed.md` — user-visible (the board is in the UI). ## What I ran - `cd core && node --import ./test/harness-resolve.mjs --test --test-concurrency=1 test/delivery-board.test.js test/delivery-view.test.js test/delivery-write-failure.test.js test/kanban.test.js test/bot-tasks.test.js` → **30/30**, 0 failed. `delivery-board` alone is **14/14** (base 12 + 2). - oxlint (`-c core/.oxlintrc.json` on the two changed files) → **0 warnings, 0 errors**. - `node scripts/ds-bot-patches.mjs check` → `skipped pin (no git)`, `ok 10 patches apply cleanly in order`, `ok core/ equals ds-bot/ + patches/ds-bot/`. - `node .github/scripts/changelog.mjs check` → `57 fragment(s) … well formed`. - `node core/scripts/build-client.mjs --check` → exit 0 (no client change). ## Red without the source change - `closingLinks` back to `/#(\d+)/g` → **13/14**, red only on "only a closing keyword links a pull request to an issue (ThinkFlowLab#1189)". - `commentsOf` back to `?per_page=100&page=1` → **13/14**, red only on "a verdict on a later page of comments still decides the badge (ThinkFlowLab#1189)". Both restored by `cmp` to the tip file, suite back to 14/14. ## Not run - `npm run verify` end to end: its `arch-docs` step needs `git` and `origin/main`, and this box has no `git`; the whole core suite is not runnable here either (a pristine `fc19e6d2` reports the same eight failures on this box). CI's `tests-ok` is the terminal answer. - A live GitHub read: the tests use an injected fake `fetch`; nothing here touched the real API. ## Risk - Low. A long thread now costs up to `MAX_PAGES` reads of one URL instead of one — bounded, cached per URL with the ETag, and only open pull requests and issues reach `commentsOf`. - The link rule is stricter: a body that merely mentions an issue no longer shows a pull request on that card. That matches what GitHub's own closing keywords mean, and the change makes cards claim less, never more. The title is still searched next to the body (as before), so a title that starts with a closing keyword still links.
Daily mechanical release: folds the 63 changelog fragments into `## [0.2.8] - 2026-10-26` and bumps the core to `0.2.8`. Covered by the [standing approval for mechanical release PRs](AGENTS.md#standing-approval-mechanical-release-prs) (maintainer decision 2026-10-19 07:02 Asia/Shanghai). ## What changed (only the mechanical release files) - `CHANGELOG.md`: `changelog.mjs release 0.2.8 --date 2026-10-26` folded 63 fragments; `[Unreleased]` left empty. No hand edits. - `changelog.d/`: the 63 folded fragments removed, `README.md` untouched (64 entries in the directory before the fold, 63 of them fragments). - `core/package.json`, `core/package-lock.json`: `0.2.7` → `0.2.8`. - `patches/ds-bot/0007-version-and-tooling.patch`: its three version lines bumped by hand (no `git` binary here, so `ds-bot-patches.mjs generate` is not runnable on this box). Since v0.2.7: 88 commits on `main` (base `1e9f1844`, the `ThinkFlowLab#1183` merge commit). ## Ran at the tip (`1e9f1844`, Node 22.23.3, fresh tarball of `main`) - `changelog.mjs check` → 63 fragments well formed before the fold, 0 after; `release 0.2.8` wrote the section. - `check-release-version.mjs 0.2.8` → exit 0; `release-notes.mjs 0.2.8` → renders the new section, including the Delivery view entry (`ThinkFlowLab#1173`). - Diff of this commit: 67 files — the four mechanical files modified plus 63 fragment deletions. Nothing else. Not run: `ds-bot-patches.mjs generate`/`check` (no git), `npm ci` + `npm run harness` + `TZ=UTC npm run verify` (no dependency tree), smoke, typecheck, actionlint — CI's `tests-ok`, `ds-bot-patches` and `check-mojibake` jobs at the tip cover the build and the tests. No tag or release is created by this PR. Preflight: v0.2.8 is not released; the latest `Test` on `main` is green; 63 fragments existed when the run started. Tip SHA: ab5c7f0 Written-by: Release
Owner: Dev
Reviewer: Reviewer
Fixes #1173
What changed
A second view on the task dialog: Tasks stays the per-Bot board (#1058), Delivery is one read-only snapshot of the repository GitHub work, in five columns.
core/src/host/delivery-board.js(new) reads issues, pull requests and the day's workflow runs, lays them intoraw/ready/working/review/done-today, and caches each URL with its ETag. Before: there was no repository view at all; the only board wasstate.tasks.GET(get()refuses anything else by construction — there is no other request helper), the token is read host-side and never enters the payload, andread({ force })revalidates withIf-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.agent-workingsits in In progress,agent-readyin 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=closedcannot tell "closed unmerged" from a page that never reached it. A pull request card carries the newestVerdict: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 ascountedoftotalrather than pretending the capped list is complete.core/src/client/delivery-view.js(new) renders the board, showsas of <time>, and replaces it with one honest line when there is no GitHub connection.kanban.jsgains arole=tablistwith Tasks / Delivery, and the Delivery branch renders nobt-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.core/index.jsinstalls the module beforechannel;channel.jsanswersdelivery-board;authz.jsallows it to any signed-in member (it reads one repository, not an owner's Bots);client/index.jsexposesactions.deliveryBoard. i18n has the new copy in Chinese.installpasses a getter, not a value, andrt.deliveryBoardawaitsrt.loadSecrets()first. Before: the token was read once at install, whilesecrets.jsloads the file asynchronously, so a host withGITHUB_TOKENstored signed none of its requests (measured: 16/16 anonymous) and the anonymous limit failed a refresh halfway.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 testa verdict line wins over an Attestation that names an older shafails if the order is read back to front. Before:Attestation:was preferred, so a PASS naming the current tip could read as "no verdict".kanban.js'sboardRail,boardColumns,columnTree, the Tasks view output,shared/task-board.js(COLUMNS/COLUMN_OF/columnOf),tasks.jsandtools.js.git diffon those is empty except the additions above.Why
#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 (#1166).
Verification at the tip
Tip SHA: 48ef5dd
Branch rewritten: everything before this tip is obsolete —
bd04e9cd,9a033cef,632030ec,e09370d9,27abe2bd,38eaf366,ca393125,7f98a43b,707d1407and every conclusion written on them included. This PR is judged only on48ef5ddd6bea2e57d34b3dcccffd69874901b9b6, one commit onmain 604ffa3a. #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 thedelivery-boardchannel 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_HARNESSat the local DSH 0.2.0-rc.2 install):The patches were regenerated after the rebase by rebuilding
core/and re-diffing it againstds-bot/in this tree;checkrebuildscore/fromds-bot/+files/+ the series and compares, so a wrong hunk cannot pass it.Red-without-the-change, one knife at a time:
columnOfDeliveryplace a PR in Done today → the placement case reds.If-None-Matchheader → the 304 case reds (it fetches instead of reusing).setIntervalto the host module → the no-timer case reds.boardRailin the Delivery branch → the kanban case reds onbt-board-railcount.if (!snapshot)) → the honest-message case reds.token: tokenOf()) → only the token case reds (installed board sends no Authorization).at <sha>fallback inverdictOf→ only the verdict-without-attestation case reds.!row.merged_atinstead of!row.pull_request?.merged_at) → two cases red: the five-column list (a pull merged today appears twice) and the new one.row.head?.sha→ only the new case reds (''instead ofnull).snapshotFromGitHub→ only the new case reds: Done today reads[41, 14]instead of[41, 52, 14].Not run
The full
coresuite locally finished 1511/1520, and every red is environmental on this box, not this diff:jsdomis not installed in the DSH checkout (composer-label, header-effects, read-page),gitis absent socheck-arch-docscannot diff (cannot diff against HEAD— both subsystem docs are updated in this PR), theusage.sqlitefixture test needs a sqlite module this host lacks, and the three#896part tests are the knownTMPDIRguard (they pass withTMPDIR=/tmp; reported as #1059). CI's full run is the authority.plugins/social,plugins/tree,plugins/timelineare 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 as0 of 0— GitHub silently matches nothing whencreatedgets 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.