Dated, short lessons from real FlyBot work. Agents read this before coding. Humans promote durable rules into docs/code-standards.md and CONTRIBUTING.md.
- Before a change: skim every open lesson below. Treat them as hard constraints until promoted or retired.
- When something bites again: add or bump a lesson the same day. Date it (
YYYY-MM-DD). Keep the body to a few lines: trigger → wrong move → right move. - Seen N×: each recurrence increments
Seen. First write-up isSeen 1×. - Promote after ≥3 days: if a lesson is still true and has been seen (or stayed relevant) for at least three calendar days, move the durable rule into
docs/code-standards.md(and a one-line pointer in CONTRIBUTING if humans need it). Leave a short “Promoted → …” stub here, or delete the lesson once the standard covers it. - Do not paste proprietary process text from other products. Write FlyBot-specific facts only.
- Security lessons stay hot: fence / display-name / claim-honesty themes stay in LESSONS until the matching tests and standards land, even after promote.
- Seen: 4× (#864, #876, #887; #907 re-uploaded an old copy of its branch twice, at
d6e143a8andb8b582bd) - Trigger: branching from a local
main, or anymainnot fetched in this run, and opening a pull request from it. - Wrong: reading the green pull request page as "the branch is fine"; the ghost files in the diff are the tell, and the branch quietly restores an old
main. #887 removed the 84 test lines #869 had just merged, with every check green. #907 dropped #909's whole fix from both old tips (noverifiedAuthor, nonot-inviterrefusal) while its page stayed green. - Right:
git diff origin/main...HEAD --statmust list only your files. Anything else means a stale base: delete the branch and start again from the fetched tip. See AGENTS.md step 2.
- Seen: 1× (#759)
- Trigger: deciding a pull request can merge from its own page.
- Wrong: 9/9 green on the head read as mergeable; the entry was kicked out of the queue twice and went red on
mainatcore/test/follow-through.test.js:264. - Right: read the queue entry — the pull request merged onto the current
main. A red entry naming files you did not touch is the stale base above, not bad luck.
- Seen: recurring; the team's highest incident rate, so no single issue to point at.
- Trigger: a Bot judging a tip that already carries a
Verdict:. - Wrong: posting a second
Verdict:at the same SHA to "settle" the first, or editing the first when the answer changed. - Right: one
Verdict:per tip. A new commit voids the old one; a correction readsCorrection from <Bot>: …and carries noVerdict:.
- Seen: 1× (the commit on
maincarries the pull request title and body, nothing else) - Trigger: excusing an owned-path change with a trailer in a branch commit only.
- Wrong: green on the pull request and on the queue entry, then
arch-docsfails on the push tomain, where the branch commits no longer exist. - Right: write the trailer in the pull request body as well (
check-arch-docs.mjsreadsgit log <base>..HEAD).
- Seen: 2× (from PR #2 review → issue #9; #98 non-face room ingest)
- Trigger: Remote message or file body, or a peer display name / handle, reaches model-visible text.
- Wrong: One-shot
replaceAll('</untrusted-…>', ''); put peer-controlled names in trusted headers outside the fence. - Right: Neutralize markers until stable (or escape
</ rejectuntrusted-fragments); share one helper with the client parser. Sanitize remote strings (strip controls/newlines, cap length); fence where possible. Negative tests required (see #9 acceptance). - Promote path: After ≥3 days and green tests → harden as a rule in docs/code-standards.md.
- Seen: 3× (#94, #99, #177) — all caught on packaging only. Dated 2026-10-15, so ≥3 days: promote the merge-gate rule into docs/code-standards.md.
- Trigger: any edit to
core/after the lastds-bot-patches generate, or before acheck-arch-docsrun. - Wrong: trusting an earlier green
check/arch-docs;check-arch-docsdiffs the base...HEAD and answers "0 changed" on uncommitted work. - Right: final
core/edit →npm run buildincore/whensrc/client/changed →node scripts/ds-bot-patches.mjs generate(repo root) → commit →ARCH_DOCS_BASE=upstream/main npm run verify. New files undercore/land whole inpatches/ds-bot/files/(notopics.jsonrow). - Promote path: after ≥3 days → docs/code-standards.md (merge gate section).
- Seen: 1× (#217, #222)
- Trigger: merging a green PR into
main. - Wrong:
gh pr merge <n> --squash, reading! The merge strategy for main is set by the merge queueas a failure, then retrying or looking for a--merge-queueflag. - Right:
gh pr merge <n> --auto --squash --match-head-commit <sha>enqueues it; the queue runsTestonmerge_groupand squash-merges. Wait for MERGED (the merge starts thepushrun onmain). See merge plumbing. - Promote path: after ≥3 days → docs/code-standards.md (merge gate section).
- Seen: 1× (#342: #228's
join_invitemock returned abotfield the server never sends; #334 broke the real shape and stayed green) - Trigger: a plugin test mocks a Bot Social tool answer.
- Wrong: invent a convenient field, or use a home-level
inviterwhere the server sends the invited Bot, so the test passes while the real answer takes another path. - Right: copy the answer from the server source or a read-only call, name the Bot Social commit in a comment, and keep one test on exactly that shape (
#342inplugins/social/test/social.test.js). - Promote path: after ≥3 days → docs/code-standards.md.
- Seen: 1× (PR #2 review / agent claim patterns)
- Trigger: Agent or PR claims “fixed”, “tested”, “secure”, or “ready to merge”.
- Wrong: Imply full validation when only part of the suite ran; omit tip SHA; treat author narrative as evidence.
- Right: Name the tip SHA. List commands run and their results. List not run explicitly. PASS only from the reviewer (the owner's reviewer Bot, self-PASS counts) at that tip. No “faster/safer” without a new Verifier PASS.
- Promote path: After ≥3 days → docs/code-standards.md.