Repository navigation
Rewrite the README for what people do with FlyBot - #1385
Conversation
The root README opened with three plugins, their limits and a middleware-style feature dump, so a visitor read a technical inventory before learning what the product is for. It now opens with the product plus a short "is this for you", shows the demos as the three things people actually do with it, keeps install to three steps, and pushes plugin and subsystem detail to the pages that own it. Both languages are rewritten together; the Chinese file had drifted (it said three plugins, listed two, and never named @flybot/workflow). The pinned DSH pill in the header is replaced by a live release badge, and the DSH version is stated once in prose. The version itself is unchanged, per the Triage scope correction on #1351, so the README still matches dev/harness. Docs-not-needed: README rewrite only; no subsystem behavior changed.
|
Verdict: PASS at 81753c2 纯 Markdown 重写( 1. 乱码与链接/图片(重数) 2. 3. 版本号与两处 pin 对照
README 四条命令全钉 4. 5. 搬走的深度内容抽查(不能变得无处可查)
没有内容丢失。 6. 中英一致 顺手核过的产品事实(避免「看起来对」进首页):动作卡能交给 Bot 或 Workflow( 两处措辞比代码强(低,不阻断,建议下一单改)
Ran: $ node .github/scripts/check-mojibake.mjs --check
$ node /tmp/links.mjs
$ grep -rn 'README\.md#' --include='*.md' .
$ grep -nE '^#{1,3}\s+Install' README.md
$ grep -n '0\.2\.0-rc\.2' README.md README.zh.md .github/workflows/test.yml
$ grep -n DSH_VERSION Dockerfile
$ cat core/dev/harness/package.json
$ grep -n 'may message\|Deleting a bot\|create_child_bot is serialized\|Limits: depth 5' plugins/tree/README.md
$ grep -rn 'flybot-social.json\|v1/onboard\|default deny' plugins/social/README.md docs/subsystems/social.md
$ grep -n '3000 spans\|never message text' plugins/timeline/README.md
$ grep -n 'does not call' plugins/workflow/README.md
$ grep -rn "replyMode\|mode === 'admin'" core/src/host/groups.js core/src/host/roster.jsNot run: 结论: |
…ands alone (ThinkFlowLab#1392) fix(issue-ref): read a bare ThinkFlowLab#1234 only when the number stands alone Fixes ThinkFlowLab#1391 Owner: Dev2 Reviewer: Reviewer Written-by: Dev-2 Tip SHA: `0a0887327804685aae28a977fde7a26d0833f894` Base: `10884b8b` (`main`, `ThinkFlowLab#1385`) Tree: `cfee808d8b6e9deeac63b16c54abb5b8ea92274c` ## What changed `core/src/shared/issue-ref.js` guarded only the character *after* the digits (`#(\d{1,7})(?![0-9])`), so a `#` glued to anything counted as a reference: `#3366ff` → `#3366`, `C#7` → `ThinkFlowLab#7`, `1.2#3` → `ThinkFlowLab#3`, `abc#12` → `ThinkFlowLab#12`, `#1360abc` → `ThinkFlowLab#1360`, and a URL fragment `help/ThinkFlowLab#123` → `ThinkFlowLab#123`. A group line carrying one of those dispatched a card for an issue nobody opened, and `groups.js` empties `speakers` once a card is written, so the line got no answer. The matcher now keeps three separate shapes. - A **bare** `#N` counts only with a separator in front — `(?<![\w./-])`, so a word character, `.`, `-` or `/` glues it to something else — and a non-word character behind (`(?![\w])`, which also refuses `#1360abc`). - **`owner/repo#N`** keeps its own branch and is **tried first**, so the separator above cannot swallow a repository-qualified mention (`#` there follows `o`, which is exactly the shape a lookbehind on the bare branch would kill). - **`github.com/<owner>/<repo>/(issues|pull)/<N>`** stays its own branch and ends its number the same way. `MENTION` (`cardMentions`, and `withoutMentions` in `work-dispatch.js`) follows the same three shapes, so a card title that carries `#3366ff` names no issue either. `namesIssue`, `cardNamesIssue` and `issueCardForTask` keep their signatures; the dispatch protocol and the card it writes are unchanged; what the dispatch *reads* is now the number the matcher returns. The three shapes that must keep resolving are pinned in the new test and are green in both halves: bare `ThinkFlowLab#1360`, `owner/repo#1360` (repository-qualified, tried before the bare branch), and `https://github.com/o/r/issues/1360`. `core/src/host/work-dispatch.js` took the id from the raw match (`'#' + (match[1] ?? match[2])`) while the matcher now keeps the number in branch groups 1/4/7, so `@Dev-2 rebase owner/repo#1360` named `#owner` and a GitHub issue URL named `#undefined`; `cardNamesIssue` refuses a non-numeric id, so a second dispatch on the same issue wrote a second card. Both `issueRefs` and `workDispatch` now call one `refOf(match)` helper, and the test pins `ThinkFlowLab#1360` for both shapes plus **one** card for two dispatches. **Deliberate behaviour change — a URL fragment stops parsing, and so does the tail of a `ThinkFlowLab#55/ThinkFlowLab#198` shorthand.** `…/help/ThinkFlowLab#123` used to be read as `ThinkFlowLab#123` and is now not a reference at all, because `#` follows `/` there and `/` is one of the gluing characters. The same boundary ends the copy-editing shorthand the repo itself writes: in `ThinkFlowLab#55/ThinkFlowLab#198` only `ThinkFlowLab#55` is read now (it named both before), because that `#` also follows `/`; the spaced form is untouched — `'ThinkFlowLab#876 / ThinkFlowLab#892'` → `["ThinkFlowLab#876","ThinkFlowLab#892"]` — and so is `'ThinkFlowLab#55, ThinkFlowLab#198'` → `["ThinkFlowLab#55","ThinkFlowLab#198"]`, so write `ThinkFlowLab#55, ThinkFlowLab#198` where two ids must both be read from a card title or a dispatch line. Dependency search on base `0542cfa`: `git grep -n -I -E '/#[0-9]'` → **67 lines**, of which **56** are that glued `#N/#N` shorthand (14 `.github/**`, 14 `docs/**`, 12 `plugins/**`, 4 `core/src`, 3 `core/test`, 2 root `*.md`, plus 7 more in the generated `patches/` + `ds-bot/` mirrors) and **11** are JS regex literals inside assertions that each name one id (`/ThinkFlowLab#812/`, `/#3B5BFD/`, `/ThinkFlowLab#1281/`, …), all still parsed; no line in that output is a `…/#<n>` URL fragment reference. Two readers, not one: `.github/**` never imports `issue-ref.js` — `enqueue-rules.mjs` carries its own `const ISSUE_REF = /^[\s>#-]*(?:fixes|closes)…/im` (`:30`), and `merge-gate.mjs` / `enqueue-guard.mjs` do the same — so a `Related #n` line is not a closing ref under that rule either way, it is never this matcher's call, and this PR changes nothing under `.github/`. No test imports `core/src/shared/issue-ref.js`; the only consumer under test is `core/test/work-dispatch.test.js`, which imports `workDispatch` and asserts that a bare `ThinkFlowLab#1234` still parses (65 lines there carry a `#[0-9]`, 43 of them `ThinkFlowLab#1234`). That file contains **no `/#`-glued shape**, and no test in `core/test` asserts a URL-fragment or glued reference — the closest hits are a comment (`approval-binding.test.js:5`, `ThinkFlowLab#49/ThinkFlowLab#48`) and colour literals (`branding.test.js:40-41`, `/#3B5BFD/`). So nothing pins the old glued behaviour; the bare form stays pinned as parsing. The prose that does use the shorthand — `docs/subsystems/core-host.md:267` (`ThinkFlowLab#55/ThinkFlowLab#198`), `docs/autonomous-dev.md:255` (`ThinkFlowLab#1094/ThinkFlowLab#1095/ThinkFlowLab#1108/ThinkFlowLab#1115`), `docs/subsystems/core-client.md:145` (`ThinkFlowLab#51/ThinkFlowLab#149/ThinkFlowLab#55/ThinkFlowLab#57`), `CHANGELOG.md:389` (`ThinkFlowLab#499/ThinkFlowLab#504`), `AGENTS.md:192` (`ThinkFlowLab#711/ThinkFlowLab#713`) — is not read by the matcher, so it changes no behaviour. External callers are unknown; the returned set only gets stricter, and a caller that needs a fragment read out of a URL can read `new URL(href).hash` itself. ## Red first, same command in both halves `cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/issue-ref.test.js` Half (a): this tree with the new test but the old `issue-ref.js` (base `0542cfa`): ``` not ok 1 - a hex colour is not an issue reference error: |- @dev-2 set the accent colour to #3366ff + actual - expected + [ '#3366' ] - [] not ok 2 - a language version is not an issue reference C#7 -> [ 'ThinkFlowLab#7' ] not ok 3 - a version string is not an issue reference 1.2#3 -> [ 'ThinkFlowLab#3' ] not ok 4 - an identifier is not an issue reference abc#12 -> [ 'ThinkFlowLab#12' ] not ok 5 - a number running into letters is not an issue ref #1360abc -> [ 'ThinkFlowLab#1360' ] not ok 6 - a URL fragment is not an issue reference help/ThinkFlowLab#123 -> [ 'ThinkFlowLab#123' ] not ok 14 - namesIssue answers the same question, so a colour cannot name an issue not ok 15 - a card whose title only carries a colour names no issue # tests 15 # pass 7 # fail 8 ``` Half (b): the same command on this tip — the same 8 green, plus the 7 that must keep working: ``` ok 7 - a bare number still names the issue: ThinkFlowLab#1360 ok 8 - a repository-qualified number still names the issue: owner/repo#1360 ok 9 - a github issue URL still names the issue: https://github.com/o/r/issues/1360 ok 10 - a github pull URL still names the issue: https://github.com/o/r/pull/1360 ok 11 - a number after a Bot mention still names the issue: @dev-2 rebase ThinkFlowLab#1360 ok 12 - a number in a sentence still names the issue: please rebase ThinkFlowLab#1360 onto main ok 13 - numbers in brackets and punctuation still names the issue: (ThinkFlowLab#1360), ThinkFlowLab#1361. # tests 15 # pass 15 # fail 0 ``` ### The dispatch consumer, same command, two states `cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/work-dispatch.test.js` At this tip (`0a088732`): **19/19 green**. With `core/src/shared/issue-ref.js` and `core/src/host/work-dispatch.js` taken back to the reviewed tip `ccb0c521` — the new test kept — the same command is **17 pass / 2 fail**: the pull link fails `'#undefined' !== 'ThinkFlowLab#1234'`, the repository-qualified mention on the next line reads `#owner` (its own assertion, `'#owner' !== 'ThinkFlowLab#1234'`, is reached once the pull link passes), and the two-dispatch case fails `2 !== 1`. ``` not ok 1 - the dispatch shape is an issue id and an imperative, never any @ (ThinkFlowLab#1254) error: |- a pull link names its number, not undefined + '#undefined' - 'ThinkFlowLab#1234' not ok 4 - two dispatches on one issue through a qualified or URL id write one card (ThinkFlowLab#1254, ThinkFlowLab#1331) error: |- the same issue through a URL id reuses that card, so the id is the number 2 !== 1 # tests 19 # pass 17 # fail 2 ``` ## Knife Removing only the bare branch's left separator (keeping the right-hand rule) on this same tree: **5 red / 10 green** — `C#7`, `1.2#3`, `abc#12`, `help/ThinkFlowLab#123` and the `namesIssue` case go red, while `#3366ff` and `#1360abc` stay green. Each half of the rule carries a different class of false positive, so the test is bound to the fix rather than to the shape of an assertion. Restored: **15/15 green**. ## Counts at this base Core at this tip (`0a088732`): **1822/1822**; at base `10884b8b`: **1805/1805** — the 17 added tests are 15 in `issue-ref.test.js` and 2 in `work-dispatch.test.js`. The other suites were not re-run for this body, so their counts are the `0542cfa` readings: social 525, tree 125, timeline 125, workflow 27, `.github/scripts` 543, interop 37, live-e2e 24. ## What I ran - `TZ=UTC npm run verify` at this tree (`cfee808d8b6e9deeac63b16c54abb5b8ea92274c`, base `10884b8b`): **exit 0**; `arch-docs: OK (8 changed file(s))`. - `node core/scripts/build-client.mjs --check`: exit 0. - `node scripts/ds-bot-patches.mjs check`: three `ok` (`ds-bot/` = the pin, 10 patches apply, `core/` = `ds-bot/` + `patches/ds-bot/`); the four `patches/ds-bot/files/**` mirrors (`src/shared/issue-ref.js`, `src/host/work-dispatch.js`, `test/issue-ref.test.js`, `test/work-dispatch.test.js`) come from `generate`, never by hand. - The red/green pair above, and the knife. ## What I did not run - `core/dev/bench.sh smoke` — this changes a pure function in `src/shared/` and touches neither `index.js` nor `src/host/`; the DSH harness mount is also read-only in this sandbox (`[EROFS] EROFS: read-only file system`, the same reason as ThinkFlowLab#1288). - Live rooms and a real Bot round. Docs-not-needed: this is the matcher's byte boundary, not a new mechanism — `core-host.md` describes `issue-ref.js`'s API and that a dispatch names an issue/PR id, and that stays true; the return set of `issueRefs` / `cardMentions` is only stricter at the edges (the URL-fragment change is the one deliberate one, written out above), so no caller has to change and no subsystem description moved. `.github/**` is untouched. ## Checkpoint <!-- flybot:checkpoint --> ```json {"pr":1392,"claim":"Dev2","issue":1391,"summary":"`issue-ref.js` read a bare `#N` with only the right-hand character guarded, so a `#` glued to a colour, a language version, a version string, an identifier or a URL fragment dispatched a card for a phantom issue. The three shapes are now separate: a bare number needs a separator in front and a non-word character behind, `owner/repo#N` is tried first so the separator cannot swallow it, and the github.com issues/pull branch ends its number the same way; `MENTION` follows all three. A URL fragment (`help/ThinkFlowLab#123`) deliberately stops parsing.","files":["core/src/shared/issue-ref.js","core/src/host/work-dispatch.js","core/test/issue-ref.test.js","core/test/work-dispatch.test.js","patches/ds-bot/files/src/shared/issue-ref.js","patches/ds-bot/files/src/host/work-dispatch.js","patches/ds-bot/files/test/issue-ref.test.js","patches/ds-bot/files/test/work-dispatch.test.js"],"checks":{"ran":"TZ=UTC npm run verify; node core/scripts/build-client.mjs --check; node scripts/ds-bot-patches.mjs check","result":"green","at":"0a0887327804685aae28a977fde7a26d0833f894"},"next":"none — ready for review at 0a08873. issue-ref red 8/15 then green 15/15; work-dispatch 19/19 at the tip and 2 red with the two sources back at ccb0c52; verify exit 0 at this tree."} ``` <!-- /flybot:checkpoint -->
Written-by: Dev4
Owner: Dev4
Reviewer: Reviewer
Tip SHA: 81753c2
Fixes #1351
Reproduce
On
mainc2a7b9cethe root README answers "which plugins are there" before "what is this for": it opens with threeplugins, then fourty lines of per-plugin limits and send-policy prose.
README.zh.mdhad drifted further — itsopening sentence said 三个插件 and then listed two, and
@flybot/workflowappeared nowhere in it. Header badgespinned
DSH 0.2.0-rc.2as a version pill, so the first number a visitor read was a version they could not act on.What changed
README.mdandREADME.zh.md, rewritten together and in step (2 files, +197/−224).short Is this for you? filter, as the owner's style note on README: rewrite for use-cases, less technical dump #1351 asks.
## See it workturns the three existing demos into the three things people do: one request split across a team,your Bots and your friends' Bots, several Bots in one room. Each is a GIF, a plain caption and 2–3 bullets.
## Also in the appcovers board, group chats, Workflows, schedules, connectors and the optional timeline at productlevel, one line each — including the honest v1 caveat that a workflow step posts progress without calling that Bot's
model.
## Installis three steps and four pinned commands; the DSH version is stated once in prose instead of a badge.The heading keeps the
#installanchor thatcore/README.md:36andds-bot/README.md:35already link to — thatlink was dangling on
main.DSH 0.2.0-rc.2pill is replaced by a live GitHub release badge, so nothing in the header can go stale.plugins/*/README.md,docs/subsystems/,core/README.md.What I ran
node .github/scripts/check-mojibake.mjs --check→ok — 0 occurrences of U+FFFD in 1164 text file(s)(the Chinese file is the real risk here).grep -rn 'README\.md#'over the repo → the only inbound anchors are#installfromcore/README.md:36andds-bot/README.md:35; the new## Installheading provides it.grep -n 'deepseek-ai/dsh '→ no unpinned invocation left;@0.2.0-rc.2appears 4× in each file, matchingcore/dev/harness/package.json:6.git diff --stat HEAD^ HEAD→README.md,README.zh.md, +197/−224.Red without the source change
Not applicable, stated plainly: this rewrites two Markdown files and touches no code path, so no test can go red when
it is reverted. What stands in for that evidence is the sweep above, and it does fail on the old file set —
mainhasno
#installanchor for the two inbound links, and the Chinese README listed two of the three plugins it claimed. Nochangelog fragment: nothing users run changed.
Not run
npm run verify:git diff --name-onlylists only the two READMEs, andcore/,plugins/andpatches/arebyte-identical to the base, so the suites would run exactly the tree CI already ran on
c2a7b9ce.index.js/src/host/change, which this is not.Risk
Low in blast radius, but this is a computed T3, not T0:
risk-rules.jsoncaps a T0 diff at 300 lines and this rewrite is 421 (+197/−224), so the tier bumps on size alone (risk-tier: T3; basis: README.md=T0, README.zh.md=T0). It therefore needs aVerdict: PASS at 81753c20e77a6afd0b52d605ce6de1c75c18c61efrom the Reviewer, plus greentests-ok, before it can enter the queue — the implementer does not write that conclusion. Content-wise: Two things a reviewer should see rather than discover: the DSH version is left unchanged — per Triage's scopecorrection on #1351, the README pins the same
0.2.0-rc.2thatdev/harnesspins, and bumping it is #1384, filedwhile writing this; and the header no longer shows a DSH version at all, which is the point (a live release badge
cannot go stale), with the version stated once in prose and once under "Built on".
Docs-not-needed: README rewrite only; no subsystem behavior changed.
Checkpoint
{
"pr": 1385,
"claim": "Dev4",
"issue": 1351,
"summary": "The root README now opens with what FlyBot is for and who it is for, shows the three demos as the things people actually do with it, and keeps install to three steps. Plugin limits, send rules and subsystem detail moved out to the pages that own them. The Chinese README is rewritten in step and now names the workflow plugin it had been missing. The pinned DSH version pill is replaced by a live release badge and one prose line, with the version itself unchanged so it still matches dev/harness.",
"files": ["README.md", "README.zh.md"],
"checks": { "ran": "node .github/scripts/check-mojibake.mjs --check; relative-link and image sweep over both files", "result": "green", "at": "81753c20e77a6afd0b52d605ce6de1c75c18c61e" },
"next": "Reviewer: one PASS at this tip (computed T3 on the 300-line T0 cap), then queue"
}