Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,46 @@ New entries are written as one fragment file per change in [changelog.d/](change

## [Unreleased]

## [0.2.19] - 2026-11-01

### Changed

- Project board: a role-pool entry in the team block reads `@id` beside its rank instead of a Dossier control — `project-team` answers rows keyed by the Project's own Bots, so the old pool click opened a dossier the host never sent; the Chief and my-agent rows keep theirs ([#1892](https://github.com/ThinkFlowLab/FlyBot/issues/1892)).

### Fixed

- The Project memory box now counts its 600-character bound in characters rather than UTF-16 units, so a note of 600 emoji — 1,200 units — is saved instead of refused as *A Project memory entry is at most 600 characters*, and 601 characters is still refused in both writers ([#1886](https://github.com/ThinkFlowLab/FlyBot/issues/1886)).
- The Project settings memory box warns about its bound before the click: a `N/600` counter under the field counts code points like the host, a 601st code point turns the counter and the Save button into their over-limit state, and an empty or whitespace-only box disables Save, so neither state calls `project-memory-write` or writes anything ([#1887](https://github.com/ThinkFlowLab/FlyBot/issues/1887)).
- CI now runs `node scripts/ds-bot-patches.mjs canonical`, which fails when `generate` would rewrite `patches/ds-bot/`: `check` proves the committed series applies and reproduces `core/`, not that it is the split the generator writes, so a drifted series landed green between #1883 and #1889. `npm run verify` runs the same gate. ([#1890](https://github.com/ThinkFlowLab/FlyBot/issues/1890))
- Host character limits count code points, so a character outside the BMP costs one instead of two ([#1895](https://github.com/ThinkFlowLab/FlyBot/issues/1895)): a memory entry at 300, a `MEMORY.md` at 4,000 and its size note, a scheduled task's name at 120, a Bot-to-Bot message at 20,000, and the Project memory entry at 600 in both writers now measure what a reader counts, and a refusal prints that code-point number.
- The Project board's wait label now carries seconds under a minute, so a card that waited 40 seconds reads `40s` instead of `0m`; the three duration metrics (PR merge time, issue close time, task completion) use the same label, and a span over zero never floors to `0s`. Unknown and negative spans still render nothing. ([#1896](https://github.com/ThinkFlowLab/FlyBot/issues/1896))
- An incident entry's `trigger`, `wrong` and `right` are bounded at 600 characters counted as code points, not UTF-16 units ([#1899](https://github.com/ThinkFlowLab/FlyBot/issues/1899)): 300 emoji no longer fill the 600 budget, a 600-character emoji entry is stored rather than refused as 1,200 units, and an entry already on disk that is over 600 UTF-16 units but within 600 characters loads again through the same check on the read path.
- Project board: the five-second refresh no longer re-reads the team dossier — `project-team` is read once when the board opens and handed back to each poll, so an open board stops re-reading persona and memory files (about 192 KB a minute) for an answer only an edit changes; a dossier that fails to read now leaves the rows, the done group and the tasks on screen with an empty team block instead of showing "No Project yet" ([#1900](https://github.com/ThinkFlowLab/FlyBot/issues/1900)).
- The task board's typed question and answer (2,000) and its handoff, evidence and lease bounds (300, 200, 200) now count characters rather than UTF-16 units ([#1901](https://github.com/ThinkFlowLab/FlyBot/issues/1901)), so a 2,000-character emoji question is accepted instead of refused as 4,000.
- `read_own_chat` now says what a cap left out instead of reading as the whole chat: a search that fills its 20 hits ends with `N more not shown; search with narrower words, or read around one of these anchors.`, and a bare read of a part with more than 12 messages is headed `newest 12 of 15, oldest first`. The caps stay; exactly at the cap nothing is added. ([#1906](https://github.com/ThinkFlowLab/FlyBot/issues/1906))
- A clipped or excerpted line no longer ends on half of an emoji ([#1907](https://github.com/ThinkFlowLab/FlyBot/issues/1907)): the host cuts `read_own_chat`, checkpoint and handoff lines, the memory review input and the error sentences on a code point boundary, so what a client receives is the whole character instead of a replacement character.
- Project board: a refused `project-team` read at open is no answer yet, not an empty team — the next five-second poll asks again, the block fills when the answer lands, and it stays frozen for the rest of the open; before this the refusal was normalised to `{ rows: [] }` and served by every later poll ([#1910](https://github.com/ThinkFlowLab/FlyBot/issues/1910)).
- A decision or a meeting archive no longer stores half of an emoji ([#1912](https://github.com/ThinkFlowLab/FlyBot/issues/1912)): the host's one `cut` helper stops a bounded prefix before the surrogate pair it would split, and every archive writer now uses it instead of `slice(0, max)` — `decisions.jsonl`, `decisions/<date>-<slug>.md`, and the claim line, diagnostics report, activity-feed label and browser text beside them — so the stored record round-trips through UTF-8 as the whole character instead of U+FFFD.
- The Project board's Dossier panel now re-reads the team dossier when it opens, so a memory head written
after the board opened is one click away instead of stale until the board is closed and reopened. A
refused refresh keeps the rows the panel already had, and the five-second poll still does not read the
dossier.
- Eight more places stopped storing or showing half of an emoji ([#1916](https://github.com/ThinkFlowLab/FlyBot/issues/1916)): the claim cue's fallback reference, the task lead's name in a member's prompt, a failed group Session's error text, `read_own_chat`'s query and anchor, an open page's address and title, a diagnostics browser-log line, and a friend's Bot name now cut on a code point boundary. The rule itself moved to `core/src/shared/text-boundary.js`, so the shared label code and the host's `cut` use one implementation instead of two.
- The memory review now keeps whole characters in what it shows the model and writes to the log ([#1918](https://github.com/ThinkFlowLab/FlyBot/issues/1918)): the two bounds in `core/src/host/memory.js` — the 800-unit context line and the 3,000-unit two-ended user line — go through the shared boundary rule, so a cut that lands inside an emoji steps back instead of leaving half a pair, and the tail it keeps is never longer than the budget it had. The exported `clip` in `core/src/host/text.js` also makes its reason optional: a two-argument call now reads `… (cut)` instead of the literal `… (cut; undefined)`, while a call that passes a reason keeps `… (cut; <reason>)` byte for byte.
- The diagnostics report's stack summary stopped showing half of an emoji ([#1919](https://github.com/ThinkFlowLab/FlyBot/issues/1919)): the `<details><summary>Stack: …` line now cuts the message on a code point boundary, so the character the 80-unit bound would split is left out of the summary entirely and the line shows a whole-character prefix instead of ending in U+FFFD.
- A friend's Bot name no longer shows half of an emoji ([#1923](https://github.com/ThinkFlowLab/FlyBot/issues/1923)): the published name stored from the roster, the group member line, the room label `othersInRoom` returns and the envelope's name, handle, ownerName and roster fields now cut on a code point boundary, so such a value that straddles its 60 (or 40) cap keeps the whole character instead of U+FFFD. The envelope's message body and its fitTransport shrink loop are untouched.
- A room-share envelope keeps whole characters in the text it copies to another owner's FlyBot ([#1928](https://github.com/ThinkFlowLab/FlyBot/issues/1928)): the history line a join copies (bounded at 2,000 units on both the host that builds the envelope and the guest that copies it) and a line fitted to Bot Social's 4,000-character transport limit now stop before a character that straddles their bound instead of leaving half of it, so a guest no longer reads U+FFFD where the sender typed an emoji — a family emoji fitted to the transport reproduces the old break. The 18,000-unit bound on a line envelope's body goes through the same rule for consistency; it is not reachable on its own because the transport fit already shortens the body to 4,000.
- The host's own bounded lines no longer end in half of an emoji ([#1930](https://github.com/ThinkFlowLab/FlyBot/issues/1930)): the busy acknowledgment's 600-unit task text and 1,500-unit message text, `cleanName`'s 60-unit peer name (the one that lands in `fenceUntrusted`'s `from="…"` attribute), the `list_bots` group line's 100-unit notice and 120-unit job line, the group answer echo at 300 and a rework card's note at 200 now cut on a code point boundary, so a value whose cap falls inside a surrogate pair keeps the whole character instead of U+FFFD. Every cap is unchanged.
- A join to a shared room keeps the group notice even when the room's Bot roster has to shrink to fit ([#1932](https://github.com/ThinkFlowLab/FlyBot/issues/1932)): the roster used to be trimmed after the notice, and the notice was cut by the whole envelope's overflow, so a room with enough Bots emptied it and a guest never heard an edited or cleared notice — an explicit clear (an empty notice) was dropped along with it. The roster now gives its rows first, the notice is cut only by what is left over once the roster cannot give more, and a present empty notice arrives as the clear it is. No limit changes: a join still fits Bot Social's 4,000-character transport.
- A joined room's notice and the pane line copied from another owner's FlyBot keep whole characters ([#1933](https://github.com/ThinkFlowLab/FlyBot/issues/1933); [#1928](https://github.com/ThinkFlowLab/FlyBot/issues/1928) covered the envelopes, and these are the two host-side readers it left on a raw code-unit cut): the guest bounds the notice it stores at its own 2,000 units and the history line it draws at the same 2,000-unit bound it already stores, both by backing up to a code point boundary, so a text whose 2,000th unit is half of a surrogate pair no longer leaves that half in the notice or in the pane — it reads as U+FFFD no more. The pane used to be shown the sender's raw `entry.text`, longer than the line the guest's own log kept; it now draws exactly the bounded prefix the log holds.
- A peer name that arrives with half of a surrogate pair — a string JSON accepts but is not well formed — is now made well formed before it is cleaned, so the message header a person reads (`[Message from …]`), the `from="…"` attribute of an untrusted-message fence and the recorded `senderName` carry the replacement character instead of a lone half that would not survive a UTF-8 round trip. The same repair now happens when a shared room's envelope is parsed: the notice, a roster entry's name and owner name and a copied chat line are handed on well formed, so the room's standing prompt and the guest's copy of a line no longer carry a broken character. The 60-character name bound, the notice's 2,000-character bound and their code point boundaries are unchanged ([#1937](https://github.com/ThinkFlowLab/FlyBot/issues/1937)).
- The notice the host edits in a group's settings now reaches the friends' Bots already in the room ([#1939](https://github.com/ThinkFlowLab/FlyBot/issues/1939)): editing or clearing it pushes one room-share `join` with the same roster and only the notice changed, and a settings save that leaves the notice alone sends nothing.
- A peer's display name is now made well formed before it is cleaned: when a roster name, an owner or lead label, an inviter name or a face seat arrives with half of a surrogate pair — a string JSON accepts but that is not well formed — the label carries the replacement character instead of a lone half that shows as an empty box and does not survive a UTF-8 round trip. The 60-character name bound and its code-point boundaries are unchanged, so a name that is already well formed comes back exactly as it was ([#1940](https://github.com/ThinkFlowLab/FlyBot/issues/1940)).
- A line that arrives from another home with half of a surrogate pair in its body now has the body made well formed before it is used: the stored room line, the line the pane draws and the text handed to the Bot that was called all carry the replacement character instead of a lone half that would not survive a UTF-8 round trip. The line is still accepted and still calls that Bot — a broken character never silences a peer's message — and a body that is already well formed, including one with a real emoji, is passed through exactly as it arrived ([#1943](https://github.com/ThinkFlowLab/FlyBot/issues/1943)).
- A group's notice and name are now cut on a code point instead of a UTF-16 unit ([#1945](https://github.com/ThinkFlowLab/FlyBot/issues/1945)): a 2000-unit notice or a 60-unit name that ended in a whole emoji used to store a lone surrogate, which every encoder downstream turned into U+FFFD; the bound now drops the straddling character whole, the way every other cut in the host already did.
- A room whose roster had to shrink to fit one share envelope no longer drops the host's cleared notice ([#1946](https://github.com/ThinkFlowLab/FlyBot/issues/1946)): the roster now gives while the envelope overflows with the notice field in place, so an explicit empty notice — the host clearing it — reaches the guest as empty instead of disappearing and reading as "change nothing".
- A line that a remote seat writes into a room of this home is now made well formed before it is used: the stored room line, the line the pane draws and the text handed to the Bot the line calls all carry the replacement character instead of half of a surrogate pair that would not survive a UTF-8 round trip. The line is still accepted and still calls that Bot, and a body that is already well formed — a real emoji included — is passed through exactly as it arrived ([#1950](https://github.com/ThinkFlowLab/FlyBot/issues/1950)).

## [0.2.18] - 2026-10-31

### Added
Expand Down
1 change: 0 additions & 1 deletion changelog.d/1886-memory-code-points.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1887-memory-counter.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1890-generate-canonical-gate.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1892-pool-no-dossier.changed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1895-host-limits-code-points.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1896-waited-label-seconds.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1899-experience-text-code-points.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1900-team-dossier-off-the-poll.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1901-task-text-code-points.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1906-own-chat-left-out.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1907-host-cut-code-points.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1910-team-read-retry.fixed.md

This file was deleted.

1 change: 0 additions & 1 deletion changelog.d/1912-archive-cut-boundary.fixed.md

This file was deleted.

4 changes: 0 additions & 4 deletions changelog.d/1913-dossier-refresh-on-open.fixed.md

This file was deleted.

Loading
Loading