Repository navigation
Conversation
parseRoomShare found the end of the envelope by counting braces without
tracking JSON string literals, so one { or } in a chat line's text ended the
object early and the whole envelope was dropped: the line never reached the
room. The scan now tracks strings and escapes, as the social plugin's own
envelope tail reader already does for the same shape (ThinkFlowLab#855).
Docs-not-needed: a parser fix inside a pure module; the marker contract and
every field bound are unchanged, and the module's own comment already says
ordinary chat never matches a marker.
|
Closing: our account has no write access to Owner: Delivery-1 |
…lowLab#2529) Fixes ThinkFlowLab#2447 Owner: Dev-3 Reviewer: Birfy Written-by: Dev-3 Risk tier: T3 (risk-gate: path core/src/shared/room-share.js) ## The defect `parseRoomShare` finds the end of a `FLYBOT-ROOM-SHARE` body by counting `{` and `}` from the first brace after the marker, and that scan never tracked JSON string literals. `encodeRoomShare` writes `text` with `JSON.stringify`, which leaves braces inside the string raw, so one unbalanced `{` or `}` in a message was counted as structure: the object looked finished too early, `JSON.parse` failed, and the whole envelope was dropped. A sent line therefore never arrived — the host routes a delivered share through `parseRoomShare` (`ingestRemoteRoomLine`, `applyInboundRoomShare`) and an unparsed envelope is not a room line at all — and a `join` that copied such a line into its history lost the whole join with it. On live `f36b3881` the loop is still the naive one at `core/src/shared/room-share.js:260-267`; the client's `envelopeTail` (`plugins/social/client.js`, ThinkFlowLab#855) already scanned past string literals for held-line display, so only the parser the host trusts was left behind. ## The change - The object-end scan skips a JSON string literal and its `\` escapes: a brace inside `text` is a message's own character, never structure, and a `\"` does not end the literal. A truncated body (no closing brace) is still refused, and `isRoomShareText`, every field bound, the op rules and the marker rule are untouched. - `core/test/room-share-braces.test.js` is the new suite: a line whose text opens a brace, one whose text closes a brace, a brace after an escaped quote (plus a `}` later in the same string), a join whose copied history carries braces, the plain/balanced controls, and a truncated envelope that must stay refused. Six cases, the first three red on the base tree. - `docs/subsystems/core-host.md` states how an envelope's body is found and why a brace in a chat line is text; `changelog.d/2447-room-share-braces.fixed.md` is the fragment. - `patches/ds-bot/files/src/shared/room-share.js` and `patches/ds-bot/files/test/room-share-braces.test.js` are generated from `core/`. `core/client.js` is unchanged: `src/client/` does not import this module. ## One issue, one in-flight line `ThinkFlowLab#2447` carries `needs-human` because Triage found the fix already in flight on another branch (comment `6640349586` on `ThinkFlowLab#2447`, 2026-11-04), and its note ends: "If that PR is abandoned, the issue can come back to `main` unchanged and be read as `agent-ready`." The carrier it named, `ThinkFlowLab#2448` (`delivery1/room-share-brace-scan` → `delivery/ai-centric-development-service`), was closed without merging at 2026-11-05T08:06:55Z (`merged_at` is null), so `main` is the only line now, and this is the only open PR that names `ThinkFlowLab#2447`. ## Red first On a clean tree at `f36b3881`, with only `core/test/room-share-braces.test.js` placed on it, `TZ=UTC node --import ./test/harness-resolve.mjs --test test/room-share-braces.test.js` exits 1: ``` not ok 1 - a line whose text opens a brace is read back, not dropped Expected values to be strictly equal: + actual undefined - expected 'line' not ok 2 - a line whose text closes a brace is read back, not dropped Expected values to be strictly equal: + actual undefined - expected 'line' not ok 3 - a brace right after an escaped quote is still inside the string Expected values to be strictly equal: + actual undefined - expected 'say "{" now' # tests 6 # pass 3 # fail 3 ``` Cases 4–6 (a join's copied history with braces, plain and balanced controls, a truncated envelope) pass before and after, so the fix cannot loosen the envelope's rejection of a genuinely broken body. With the fix the same file is 6 of 6. ## Measurements at the tip - Full `TZ=UTC ARCH_DOCS_BASE=f36b38814b96df0cbda79e6bc605178d678b10ac npm run verify` at this tip: exit 0. Core suite **2942 tests, 2942 pass, 0 fail**; `plugins/social` 577, `plugins/tree` 137, `plugins/timeline` 141, `plugins/workflow` 440, `.github/scripts` + `policy` 671, interop 37, live-e2e 26, all 0 fail. - Adjacent suites, `node --import ./test/harness-resolve.mjs --test test/room-ticket-seat.test.js test/remote-room.test.js test/group-bot-label.test.js test/text-boundary.test.js test/room-membership.test.js`: **163 tests, 163 pass, 0 fail**. - `node core/scripts/build-client.mjs --check`: exit 0. `node scripts/ds-bot-patches.mjs check`: `10 patches apply cleanly in order`, `core/ equals ds-bot/ + patches/ds-bot/`. `node scripts/ds-bot-patches.mjs canonical`: `patches/ds-bot/ is what generate writes (generate is a no-op)`. - `ARCH_DOCS_BASE=f36b38814b96df0cbda79e6bc605178d678b10ac npm run arch-docs`: `arch-docs: OK (6 changed file(s))`; oxlint 81 warnings, 0 errors; the four plugin lints 36 / 9 / 2 / 16 warnings, 0 errors. - `generate` ran once after the rebase onto `f36b3881` and left the tree unchanged; `git status --porcelain` reports zero tracked changes. - Rebased onto `f36b3881` (`ThinkFlowLab#2542` merged) because the base was three merges behind and `plugins (social)` had gone red on CI; the branch content is unchanged, so the diff is still `+142/−2` over 6 files. ## Files 6 files, +142/−2: - `core/test/room-share-braces.test.js` (+57/−0) - `core/src/shared/room-share.js` (+13/−1) - `patches/ds-bot/files/test/room-share-braces.test.js` (+57/−0) - `patches/ds-bot/files/src/shared/room-share.js` (+13/−1) - `docs/subsystems/core-host.md` (+1/−0) - `changelog.d/2447-room-share-braces.fixed.md` (+1/−0) ## Not run The smoke test, because no `index.js` or `src/host/` file changed, and the plugin suites, the pack check, typecheck and actionlint of CI's `package` job; CI runs those on this tip. ## Checkpoint <!-- flybot:checkpoint --> { "pr": 2529, "claim": "Dev-3", "issue": 2447, "summary": "The scan that finds the end of a room-share envelope counted braces without tracking JSON string literals, and encodeRoomShare writes a chat line's text with JSON.stringify, which leaves braces raw. One unbalanced brace in a message therefore ended the object early, JSON.parse failed, and the whole envelope was dropped: a sent line never arrived, and a join that copied such a line lost its history with it. The scan now skips a string literal and its backslash escapes, which is what the client's envelopeTail already did; a truncated body is still refused.", "files": ["core/src/shared/room-share.js", "core/test/room-share-braces.test.js", "docs/subsystems/core-host.md", "changelog.d/2447-room-share-braces.fixed.md", "patches/ds-bot/files/src/shared/room-share.js", "patches/ds-bot/files/test/room-share-braces.test.js"], "checks": { "ran": "TZ=UTC npm test in core/, plus node --import ./test/harness-resolve.mjs --test on the five adjacent suites, build-client --check, ds-bot-patches check and canonical", "result": "green", "at": "58c71182f03f2883299bd5fdbe72e95bbcf92532" }, "next": "none — ready for review" } <!-- /flybot:checkpoint -->
|
Correction to this closing record, so that "superseded" never reads as "done" (owner rule: a substitute that is still in flight must not be recorded as landed).
So for this PR only: item done, on main via #2529; this branch's own tip was never merged. If #2529 is ever reverted, this item is restored. This PR stays closed — no reopen, and the original close reason (our account cannot write |
Written-by: Delivery-1
Owner: Delivery-1
Fixes #2447
What changed
parseRoomShare(core/src/shared/room-share.js) found the end of an envelope by counting{and}, blind to JSON strings, so a single brace in a chat line'stextended the object early,JSON.parsefailed, and the whole envelope was dropped — the line never reached the room, and a join lost the history it copied. The scan now tracks string literals and\escapes, the same algorithmplugins/social/client.jsenvelopeTailalready uses for this shape after #855.Nothing else in the module moves: no field bound, no op rule, no marker rule, and
isRoomShareTextis untouched. A balanced pair keeps its current reading, and an envelope that really is truncated still answersundefined.Docs-not-needed: a parser fix inside a pure module; the marker contract and every field bound are unchanged, and the module's own comment already says ordinary chat never matches a marker.
Verification at
6d4657cfceda931b4e619e640970a78fcf6a5009Ran:
The 7 failures are two test files that cannot pass on this box (
test/workbench-client.test.js,test/project-runtime-setup.test.js—/workspacePTY/profile and native-composer refresh cases). They fail with the same names and the same count (32 tests / 25 pass / 7 fail) when the source change is reverted, and they failed the same way on the previous three delivery branches.Not run:
npm run buildas a whole (its second step,build-workbench.mjs, needs areactinstall this box does not have;core/client.jsis not in this diff), the two plugin suites and the smoke test (no host or plugin file in this diff).Files (4, +104 / −2)
core/src/shared/room-share.js—parseRoomSharetracks strings and escapescore/test/room-share-braces.test.js— new, 6 cases (3 red on base)patches/ds-bot/files/src/shared/room-share.js,patches/ds-bot/files/test/room-share-braces.test.js— generated fromcore/Base:
delivery/ai-centric-development-serviceat5e71a07e. Branch:HugoXK:delivery1/room-share-brace-scan.maintainer_can_modify: true.Checkpoint
{ "pr": 2448, "claim": "Delivery-1", "issue": 2447, "summary": "parseRoomShare found an envelope's end by counting braces, blind to JSON strings, so one unbalanced { or } in a chat line's text made JSON.parse fail and the whole envelope was dropped — the line never reached the room. The scan now tracks string literals and backslash escapes, as plugins/social/client.js envelopeTail already does. Field bounds, op rules and markers are unchanged; a balanced pair reads as before and a truncated envelope still answers undefined. Three of the six new cases fail on base 5e71a07e.", "files": ["core/src/shared/room-share.js", "core/test/room-share-braces.test.js", "patches/ds-bot/files/src/shared/room-share.js", "patches/ds-bot/files/test/room-share-braces.test.js"], "checks": { "ran": "cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test \"test/*.test.js\"; npm run lint; node scripts/ds-bot-patches.mjs check", "result": "green", "at": "6d4657cfceda931b4e619e640970a78fcf6a5009" }, "next": "none — ready for review" }