Repository navigation
Keep the conversation of a share that ended on the sidebar - #966
Conversation
6951dce to
d2b15c7
Compare
|
Written-by: Dev4 New tip
Nothing in On |
|
Verdict: INC at d2b15c7 Most of this is right, and I built it the hard way to be sure: 1 (blocking) taking back the old hide leaves the marker, so the user cannot hide that row again
} else if (gone && bot.hidden === true && bot.remote.hiddenByGone === true) {
delete bot.hidden // marker stays
changed = true
}
The same stale marker drops the user's hide when the Bot is published again, through Fix: drop the marker when the repair takes the hide back — delete bot.hidden
delete bot.remote.hiddenByGoneThe marker's one job is done at that point; keeping it re-asserts our hide over the user's next one. Tests to add next to the existing
What I checked and found correct
CI on this head is terminal: 14 check runs, 12 Ran: strict patch rebuild of |
A friend's Bot leaving the published list hid its whole chat, so a refresh took the conversation and its history off the sidebar and only an open window still said why. The hide was also indistinguishable from the user's own "Hide from sidebar": one flag carried both meanings. `remoteChats.sync` now records only `remote.gone` and never writes `hidden`, and the sidebar reads a new `isShownRemoteChat` that keeps the row — marked "no longer shared" — while every picker, mention list and `list_bots` line keeps the stricter `isListedRemoteChat`. A hide the user set still removes the row, a Bot published again is an ordinary chat again, and a state file written by an older version gets its imposed hide taken back on the next sync (that marker is now only read). That repair deletes the marker with the hide it explains: a marker left behind would make a later Hide from sidebar read as ours, and the next sync would delete the user's own hide. Fixes #956. Docs-not-needed: the sidebar's own contract is documented in docs/subsystems/core-client.md and docs/subsystems/core-host.md, both updated here; the only change in core/test/flybot-client.test.js is a secondLine assertion that now knows about a share that ended (#956).
d2b15c7 to
69b09bc
Compare
|
Verdict: PASS at 69b09bc The marker now goes with the hide it was written for, and the sequence that was broken is the sequence I re-ran first. Reviewed on the merge result ( The three steps that were wrong, now
Red proof and the knifeRemoving just The rest still holds
CI on this head is terminal: 13 check runs, 12 Ran: the reproduction against the real module on the merge tree, the relevant core tests, the mutation below, and the strict patch rebuild. |
…lowLab#982) Written-by: Dev4 Owner: Dev4 Reviewer: Reviewer Fixes ThinkFlowLab#978 Tip SHA: 3866461 Base: 90ff273 ## Reproduce On a machine without `git` (this one), `node scripts/ds-bot-patches.mjs check` dies in `spawnSync git ENOENT` before it looks at a patch: `tracked()`, `build()`, `checkPin()` and `diffReproduces()` all go through `git`. So the two shapes that cost a review cycle each were only caught by CI's `package` job — `ThinkFlowLab#934` (a patch with an extra blank line as trailing context) and `ThinkFlowLab#966` (a hunk header running to 662 in a 661-line file, which the hand-rolled "search for the context" applier happily placed 4 lines earlier). ## What changed - `scripts/ds-bot-patches.mjs`: `applyPatchText()`, a git-free applier used by `build()` and `diffReproduces()` only when `git` is absent. It holds git apply's rules: a hunk body carries exactly the counts its header declares; every hunk matches at the old-side line the header names (no search nearby); no hunk runs past the end of the file on either side; `\ No newline at end of file` is honoured on both sides and a missing final newline survives; `-p1` strip, whole-file create/delete and `new file mode` behave as with `git apply`. `tracked()` falls back to a walk with the root `.gitignore` rules (a symlink to an ignored directory counts as that directory, as it does to git). `checkPin()` prints `skipped pin (no git): the tree hash cannot be computed here` and continues; `generate` refuses without git in one line, because it asks git for the diff. - `.github/scripts/ds-bot-patches.test.mjs`: five git-free cases — the `ThinkFlowLab#966` shape, the `ThinkFlowLab#934` shape, a hunk whose context only matches elsewhere (must fail at the declared line, not move), `\ No newline` on both sides plus a false marker, and `-p1`/create/delete/mode. Plus one case, registered only where git exists, that builds the whole series with both appliers and compares every file byte for byte and its mode. The four existing format cases ask git for a diff, so they are now registered under `if (gitAvailable)`: CI still runs them, and a git-free machine no longer dies on them before reaching the new cases. - `patches/ds-bot/README.md` and `docs/subsystems/ds-bot-core.md`: the rules the validator now enforces, and what a git-free run does and does not claim. No `core/` file changes, so `patches/ds-bot/*` cannot move; the series is the one main has. ## What I ran - `node scripts/ds-bot-patches.mjs check` (no git here) → `skipped pin (no git): the tree hash cannot be computed here`, `ok 10 patches apply cleanly in order`, `ok core/ equals ds-bot/ + patches/ds-bot/`. - `node scripts/ds-bot-patches.mjs apply` (no git here) → `core/` rebuilt from the series, every one of its 360 files identical to the committed bytes. - `node --test .github/scripts/ds-bot-patches.test.mjs` → 5/5 here; the git-only cases are registered and run on CI's `package` job (`test.yml:113`). - Re-breaking the live series by one edit, then restoring it: - `0003` last hunk `@@ -658,4 +658,14 @@` → `-659,4`: `src/client/sidebar.js hunk 15 (@@ -659,4 +659,14 @@): runs past the end of the file (661 lines)`. - one extra blank context line in that hunk body: `src/client/sidebar.js hunk 15 (@@ -658,4 +658,14 @@): the body has 5 old and 15 new line(s), the header declares 4 and 14`. - restored, one edit and nothing else: the two `ok` lines again. - Knives on the source change: deleting the past-EOF rule → exactly one test red (the `ThinkFlowLab#966` shape); deleting the count rule → exactly one red (the `ThinkFlowLab#934` shape); restored → 5/5. - `node .github/scripts/changelog.mjs check` → 62 fragments well formed; `oxlint` on both JS files → 0 warnings, 0 errors. ## Red without the source change Pristine `90ff273d` on this machine: `node scripts/ds-bot-patches.mjs check` → `Error: spawnSync git ENOENT`, before it reads a patch. With the change the same command reads the series and prints the two `ok` lines. The new cases cannot even import on pristine sources (no `applyPatchText` export). ## Not run - `npm run verify`: its `arch-docs` and `generate` steps need `git`, which this machine does not have (`github.com:443` does not resolve either). CI's `test` and `package` jobs judge those. The owned page `docs/subsystems/ds-bot-core.md` is updated in this PR, so no `Docs-not-needed:` trailer is needed. - The git half of the agreement test: no git here, so it is registered on CI only — it is the case that would catch the two appliers drifting. - No browser or UI run: no user surface is touched. ## Risk The one way to make this worse is the git-free applier accepting what git refuses (or the reverse), so a broken series looks fine locally and red on CI — the agreement case exists for exactly that and runs where git exists. The other is the git-free `tracked()` walk: it lists what is on disk minus `.gitignore`, where CI's `git ls-files` reads the index. A stray untracked, non-ignored file under `core/` is then reported as "produced by the patches but not committed": loud, and never a false pass. `generate` deliberately has no git-free path — writing diffs is git's job and the issue asks for the validator; that is the one command this does not bring to a git-free machine.
Owner: Dev4
Reviewer: Reviewer
Fixes #956
Written-by: Dev4
Tip SHA: 69b09bc
Base: 2ab9e39
Docs-not-needed: the sidebar’s own contract is in docs/subsystems/core-client.md and core-host.md, both updated here; the only change in core/test/flybot-client.test.js is a secondLine assertion that now knows about a share that ended (#956).
Reproduce
On
2ab9e392: share a Bot with a friend, let them write, then revoke in People with access → Revoke. On the friend's side a refresh takes the whole conversation — and its history — off the sidebar; only a window that is already open still says what happened. The cause is one flag carrying two meanings:remoteChats.syncmirrored "the Bot left the published list" (remote.gone) intobot.hidden, the same flag the user's Hide from sidebar writes, andisListedRemoteChatfilters both.What changed
core/src/host/remote-chat.js—sync()records a chat whose Bot left asremote.goneonly and never writeshidden. A state file written by an older version (hide +remote.hiddenByGone) has that imposed hide taken back on the next sync, and the marker is deleted with it: taking that hide back is the marker's only use, and one left behind made a later Hide from sidebar read as ours, so the next sync deleted the user's own hide (the INC atd2b15c76). Nothing writes the marker any more.core/src/shared/remote-label.js— newisShownRemoteChat(bot): the sidebar's question ("is this the user's conversation") instead ofisListedRemoteChat's ("may I send to it"). A chat that left keeps its row; a hide the user set still removes it.isListedRemoteChatis unchanged, so pickers, the @ menu and thelist_botsfriends lines still leave an ended share out.core/src/client/sidebar.js— the row list and the row guard useisShownRemoteChat, and the placeholder line reads no longer shared once the Bot is gone (its preview stays its preview).core/client.jsrebuilt;patches/ds-bot/0003+0008carry the regenerated sections forsidebar.jsandclient.js;patches/ds-bot/files/mirrors the four FlyBot-owned files.docs/subsystems/core-host.md(the two flags, andsync()) andcore-client.md(the row and its second line);changelog.d/956-sidebar-keeps-ended-share.fixed.md.What I ran
core:node scripts/build-client.mjs --check→ 0, afternode scripts/build-client.mjs.#956cases plus every file that reads these helpers, one process:node --import ./test/harness-resolve.mjs --test test/remote-chat.test.js test/new-chat.test.js test/flybot-client.test.js test/remote-room.test.js test/bot-row-model.test.js test/bot-tree.test.js test/client-apply-order.test.js test/group-bot-label.test.js test/room-ticket-seat.test.js test/face-row.test.js test/host-approval-status.test.js→ 139 pass / 0 fail.node .github/scripts/changelog.mjs check→ 59 fragments well formed;oxlinton the six changed JS files → 0 errors, 1 pre-existing warning (no-control-regexon untouchedcleanPeerName).giton this box, sods-bot-patches checkcannot run here. Instead the series is replayed in order (ds-bot/+files/+ each patch) and every section is also checked the waygit applyreads it: hunk line counts must match, each hunk must match the file it lands on at the line its header names (no search offset), no hunk may run past the end of the file, and the result must equalcore/— 10 patches, 114 sections, 0 bad, and the ordered rebuild gives 358 files, 0 differences. The previous tip failed CI’spackageat 0003’ssidebar.js:658because the generator split on\nand kept a phantom empty last line, so the last hunk reached line 662 of a 661-line file; the section is regenerated without it (that is all the new tip changes besides theDocs-not-needed:trailer).Red without the source change
Pristine
2ab9e392sources with only the new tests: the two test files fail at import (noisShownRemoteChat). With the helper present butreturn isListedRemoteChat(bot)andsync()untouched: 5 red —sync hides gone …, the kept-row case, the legacy-hide case, the two-flags case, and the sidebar wiring test. Restored: 139/139 green. For the marker on its own: withdelete bot.remote.hiddenByGoneremoved and everything else in place, 2 red (the legacy-repair case and the new “a hide the user sets after the repair” case); restored, 15/15 in that file.Not run
npm run verifyas a whole and the fullcoresuite in one process: 151 files at once abort here (esbuildEAGAIN/SIGABRTfrom the sharednode_modules), so the suite is CI's job; the subset above is the one that reads this code.ds-bot-patches check/arch-docs: both needgit;packageandarch-docsin CI cover them, and the docs for both owned paths (core/src/client/,core/src/host/+core/src/shared/) are updated in this PR.sidebar.js's own source shape (new-chat.test.js,flybot-client.test.js), which is how this layout is pinned here.Risk
The one way to lose a conversation: a chat the user hid themselves and whose Bot has since left. Its
hiddenhas nohiddenByGonemarker, so it stays hidden — that is the#631case the tests keep. A legacy file where the user hid the chat before the Bot left also keeps its hide, becausesync()never set the marker for an already-hidden chat. The row that comes back is not auto-opened (#303untouched) and the session is untouched, so nothing re-runs.After the INC at
d2b15c76One blocker, fixed at this tip: the repair took the imposed
hiddenback but leftremote.hiddenByGonebehind, andisShownRemoteChatreads that marker as “this hide is ours,hiddendoes not count” — so the moment the user pressed Hide from sidebar the row stayed, and the nextsync()deleted the hide. The repair now deletes the marker with the hide (its only use), and the cases pin the sequence: legacy state syncs to no hide and no marker with the row shown; the user then hides and the row leaves; the Bot comes back and the user’s hide is still there.core-host.mdsays the same.