Skip to content

Warn about the Project memory bound before Save - #1889

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-p258-memory-counter
Oct 31, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-p258-memory-counter

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1887

Owner: Dev2
Written-by: Dev-2
Reviewer: Reviewer
Claim-Id: ec566cc5f28a4f5f94653f4649e80818
Base: e4fe937
Verified commit: 5af1964
Tree: af8cc4ca1264a6e8a4fd02144de0943b51b3aad4
Diff: 14 files, +12763/−33098. 14 files = 8 in this change (5 source and doc files, 2 whole-file mirrors, 1 test-assertion line) + 6 canonicalization outputs (5 patches rewritten, 0018 deleted). This change's 8 files are +240/−59: the panel, core/client.js,
core/test/project-board-panels.test.js and its patches/ds-bot/files/ mirror, the doc, the changelog
and the #978 patch-count assertion; the other 6 are the patch series the generator re-canonicalizes
below, 0008 carrying both)

What changed

The Project settings memory box gave the reader no notice of the host's 600 bound before the click:
#bt-project-note carried no counter, and Save memory stayed enabled on an empty field, so the
first news of the bound was the host's refusal after it. As the audit correction says, an empty Save
did not store anything — #1847 refuses at the door; the defect was the silence, and the click the
panel let a reader make.

core/src/client/project-board.js:

  • MEMORY_TEXT_MAX = 600 beside the panel, with memoryLength = (value) => [...text(value)].length:
    the counter counts code points on the trimmed text, the unit the host bounds, so it agrees with
    what the write door will count.
  • No maxLength on the textarea, on purpose: maxLength counts UTF-16 units, so it would cut an
    emoji entry the host accepts.
  • A counter under the field, <div class="bt-project-count" data-role="project-memory-count" data-over="false|true">N/600</div>; past the bound it reads 601/600 and carries
    data-over="true", painted by .bt-project-count[data-over="true"].
  • Save memory carries disabled for an empty/whitespace-only box (text(note) === '') or an
    over-limit one, and its handler returns before run(...) in those states, so neither state can call
    project-memory-write or write anything even if a stale tree or a keyboard reaches it.
  • The host's own refusal text still renders through hostText when a race reaches the endpoint, which
    is what the two #1847 panel assertions now pin: the client and the host disagreeing about the bound
    (an emoji entry the client counts at the bound, refused by a host that still counted UTF-16 units).

Tests: core/test/project-board-panels.test.js gains the #1887 case (empty, whitespace, 601, 600
code points, no endpoint call, no write) and its press-Save cases now type an entry the panel allows
first, since a disabled Save is the new contract.

Docs: one sentence in docs/subsystems/core-client.md naming the counter, the code-point unit and the
empty-text rule. changelog.d/1887-memory-counter.fixed.md with this issue's link.

Why this diff also rewrites the patch series

main after #1883 is not canonical: 0018-project-dossier.patch stores a client.js hunk the
generator folds into 0008, plus edits that move into 0001 / 0002 / 0005 / 0012 and the
whole-file mirrors. Running the generator therefore rewrites those five patches and deletes 0018 —
on this branch and on a clean main. Reproduced on e4fe9379b547ed8a739e240df0cf5a4315ee3a10 with nothing of #1887 in the tree:

$ git worktree add --detach /tmp/wt e4fe9379 && cd /tmp/wt
$ node scripts/ds-bot-patches.mjs generate
 M patches/ds-bot/0001-core-fixes.patch
 M patches/ds-bot/0002-flybot-api-host.patch
 M patches/ds-bot/0005-social-seams.patch
 M patches/ds-bot/0008-client-bundle.patch
 M patches/ds-bot/0012-room-membership.patch
 D patches/ds-bot/0018-project-dossier.patch
   core/ sha before and after: 10a278b946a942a6bb28c2cdd546e06f42fa118a

Nothing was hand-edited: on this tip the core/ tree is exactly what the generator reproduces, so the
rewritten patches are output, not a merge decision.

HEAD:core                                  a6f773203cf3ce45d1244b444c56fa32dc09404c
generate → git add -A; git write-tree → :core
                                           a6f773203cf3ce45d1244b444c56fa32dc09404c
git diff --stat HEAD -- core/              (empty)
$ node scripts/ds-bot-patches.mjs check
ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

The regenerated series stores 10 patches where main stores 11, so .github/scripts/ds-bot-patches.test.mjs (#978) now expects 10 and names 0018 in its existing fold-away comment. This is not a loosened assertion: on clean e4fe9379, with nothing of #1887 on the tree, generate already stores 10 — it rewrites 0001/0002/0005/0008/0012 and deletes 0018 — while core/ keeps the same subtree sha 10a278b946a942a6bb28c2cdd546e06f42fa118a before and after. 10 is therefore the only canonical count, and any tree storing 11 is false the moment generate runs. The root cause is #1890: main is not generate-canonical, and CI never runs generate, so this drift cannot be seen there. A second generate leaves git status --porcelain empty.

Conflict resolution

Rebased with git rebase --onto e4fe9379 818b71ea; three content conflicts, all resolved without
dropping a case:

  • core/test/project-board-panels.test.js and its patches/ds-bot/files/ mirror — both sides kept.
    Show each Project Bot's dossier on the project board #1883's dossier cases are byte-identical to e4fe9379's version and come first; this change's
    #1887 case and its two rewritten #1847 cases follow. 15 cases in the file (9 pre-existing, 3
    dossier, 2 #1847, 1 #1887).
  • core/client.js — not merged by hand. The base copy was taken and
    node core/scripts/build-client.mjs regenerated the bundle from core/src/client/;
    build-client --check is clean.

Red first

Run on e4fe9379b547ed8a739e240df0cf5a4315ee3a10 with only the source reverted (git checkout e4fe9379 -- core/src/client/project-board.js):

not ok 1 - #1887: the memory box counts code points and disables Save before the click
  error: |-
    an empty memory box disables Save
    + actual - expected
    + undefined
    - true
# tests 1
# pass 0
# fail 1

Exactly the shape the issue names: an empty box leaves Save enabled today, and there is no counter to
read at 601 or 600. With the fix the same case is # pass 1.

Verification at the tip

Ran: at 5af196449b8214d689661746628f7d6453ecdf65 (tree af8cc4ca1264a6e8a4fd02144de0943b51b3aad4) on the committed tree, git status --porcelain empty before and after:

$ TZ=UTC ARCH_DOCS_BASE=e4fe9379b547ed8a739e240df0cf5a4315ee3a10 npm run verify
$ node core/scripts/build-client.mjs --check
$ node scripts/ds-bot-patches.mjs check
  • core: 2286/2286, including project-board-panels.test.js 15/15 and
    project-assistant.test.js 24/24
  • plugins social 541/541, tree 127/127, timeline 135/135, workflow 336/336
  • .github/scripts 561/561, interop 37/37, live-e2e 24/24
  • oxlint: 0 errors (core 73 warnings; plugin lints 36/9/2/16 warnings)
  • build-client --check: clean
  • arch-docs: OK (14 changed file(s)) with ARCH_DOCS_BASE=e4fe9379…
  • all four patches/ds-bot/files/ mirrors this branch carries are byte-identical to their core/
    copies (cmp: src/client/project-board.js, test/project-board-panels.test.js,
    src/host/project-assistant.js, test/project-assistant.test.js)

Not run: the smoke bench (no index.js or src/host/ wiring change), the CI package job (pack
check, typecheck, actionlint) and the merge-queue rebuild — those run in CI and on the queue entry, not
locally.

Ordering

This commit's parent is live main e4fe9379b547ed8a739e240df0cf5a4315ee3a10, so the branch is parallel to #1888 (Dev-1's #1886),
not stacked on it: nothing of #1886 is in this commit, and this file no longer carries its case. If
#1888 lands first, this branch rebases onto that main and both sides' cases in
project-board-panels.test.js are kept the same way — nothing dropped either way.

Checkpoint

{
  "pr": 1889,
  "claim": "Dev2",
  "issue": 1887,
  "summary": "The Project settings memory box gave no notice of the 600 bound before the click: no counter, and Save stayed enabled on an empty field. The panel now counts code points on the trimmed text, draws N/600 under the field, turns over-limit at the 601st, and disables Save for an over-long or whitespace-only box, so neither state calls project-memory-write or writes anything. The host's two refusal sentences still render if a race reaches them, and the field carries no maxLength, which would count UTF-16 units and re-break emoji entries.",
  "files": [
    "core/src/client/project-board.js",
    "core/client.js",
    "core/test/project-board-panels.test.js",
    "docs/subsystems/core-client.md",
    "changelog.d/1887-memory-counter.fixed.md",
    "patches/ds-bot/0008-client-bundle.patch",
    "patches/ds-bot/files/src/client/project-board.js",
    "patches/ds-bot/files/test/project-board-panels.test.js",
    ".github/scripts/ds-bot-patches.test.mjs"
  ],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=e4fe9379 npm run verify", "result": "green", "at": "5af196449b8214d689661746628f7d6453ecdf65" },
  "next": "none — ready for review"
}

Reviewer-metadata (Written-by: Reviewer): set Reviewer: Reviewer in place of the Reviewer: Birfy line and left the Dev2 checkpoint as written; no source change. 2026-10-31T04:33Z

@HugoXK
HugoXK force-pushed the dev/2-p258-memory-counter branch from e7471e3 to 4791fbb Compare October 31, 2026 03:23
@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: 4791fbb716c64145adbf3500fd4971f7304b85ce (tree 0571b139652c6aa8c17dee90a92bd7ed063ee8fc), base 575accc63bc42b3becd2003601126d2409b417fb.

@Birfy review request: PR #1889 at 4791fbb — for #1887 the memory box now counts code points on the trimmed text (N/600 under the field, over-limit at the 601st) and disables Save memory for an empty/whitespace-only or over-long box, with the handler returning before run(...) so neither state reaches project-memory-write; no maxLength, which would count UTF-16 units and re-break emoji entries. Host untouched; the two #1847 panel cases are rewritten to type an allowed entry first and still pin the host's Chinese refusal through a real race.

Stacked on #1888 (818b71ea, still open) because both touch core/test/project-board-panels.test.js: this branch keeps #1886's case untouched and adds #1887's — 13 cases in the file, no #1886 assertion removed or weakened. The 17-file diff against main therefore carries #1888's nine files until it merges; this change alone is 8 files +1217/−2337.

Red first (clean base 575accc6 with only the new test in place): # tests 1 / # pass 0 / # fail 1

not ok 1 - #1887: the memory box counts code points and disables Save before the click
  error: |-
    an empty memory box disables Save
    + actual - expected
    + undefined
    - true

At this tip: panels 13/13, core 2281/2281, social 541, tree 127, timeline 135, workflow 336, .github/scripts 561, interop 37, live-e2e 24; npm run verify exit 0, oxlint 0 errors (core 73 warnings; plugins 36/9/2/16), build-client --check clean, arch-docs: OK (17 changed file(s)) with ARCH_DOCS_BASE=575accc6.

Generator idempotence and mirrors on this tree: node scripts/ds-bot-patches.mjs generate then git status --porcelain empty; four mirrors byte-identical by cmp (src/client/project-board.js, test/project-board-panels.test.js, src/host/project-assistant.js, test/project-assistant.test.js); patch chain:

ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

patches/ds-bot/0008-client-bundle.patch moves +983/−2283 although core/client.js is only +22/−1: the patch is the generator's diff of the long-line bundle against the fixed ds-bot/ tree, so one insertion re-chunks every hunk coordinate below it — the line counts move, the content is equivalent, and the idempotent generate plus check's third line are what prove nothing was swallowed.

enqueue-guard is red only because no Verifier report names this tip; every other check at 4791fbb7 is success.

Owner: FlyBot Lead
Written-by: FlyBot Lead

@HugoXK
HugoXK force-pushed the dev/2-p258-memory-counter branch from 4791fbb to 481990e Compare October 31, 2026 03:34
@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: 481990ee91379ce876262825ad302fd8cb36e638 (tree 0571b139652c6aa8c17dee90a92bd7ed063ee8fc), base 575accc63bc42b3becd2003601126d2409b417fb.

@Birfy review request: PR #1889 at 481990e — for #1887 the memory box now counts code points on the trimmed text (N/600 under the field, over-limit at the 601st) and disables Save memory for an empty/whitespace-only or over-long box, with the handler returning before run(...), so neither state reaches project-memory-write; no maxLength, which would count UTF-16 units and re-break emoji. Host untouched; the two #1847 panel cases are rewritten to type an allowed entry first and still pin the host's Chinese refusal through a real race.

Structure: this head's parent is 818b71ea (the head of #1888), so the two PRs are stacked, not parallel, and this commit holds only #1887's own change: 8 files +1217/−2337. The 17-file diff against main splits as 9 files that exist only in the parent commit (store.js, constants.js, project-assistant.js, its test and mirror, 0002-flybot-api-host.patch, docs/subsystems/core-host.md, changelog.d/1886-…), 2 shared (core/test/project-board-panels.test.js and its patches/ds-bot/files/ mirror, both sides' cases kept), and 6 that belong to this change alone. Once #1888 merges, the same head shows only this change's files.

Red first (clean base 575accc6 with only the new test in place): # tests 1 / # pass 0 / # fail 1

not ok 1 - #1887: the memory box counts code points and disables Save before the click
  error: |-
    an empty memory box disables Save
    + actual - expected
    + undefined
    - true

At this tip: panels 13/13 (with #1886's case present and untouched), core 2281/2281, social 541, tree 127, timeline 135, workflow 336, .github/scripts 561, interop 37, live-e2e 24; npm run verify exit 0, oxlint 0 errors (core 73 warnings; plugins 36/9/2/16), build-client --check clean, arch-docs: OK (17 changed file(s)) with ARCH_DOCS_BASE=575accc6.

Generator idempotence and mirrors on this tree: node scripts/ds-bot-patches.mjs generate then git status --porcelain empty; four mirrors byte-identical by cmp (src/client/project-board.js, test/project-board-panels.test.js, src/host/project-assistant.js, test/project-assistant.test.js); patch chain:

ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

patches/ds-bot/0008-client-bundle.patch moves +983/−2283 although core/client.js is only +22/−1: the patch is the generator's diff of the long-line bundle against the fixed ds-bot/ tree, so one insertion re-chunks every hunk coordinate below it — the line counts move, the content is equivalent, and the idempotent generate plus check's third line are what prove nothing was swallowed.

enqueue-guard is red only because no Verifier report names this tip; every other check at 481990ee is success.

Owner: FlyBot Lead
Written-by: FlyBot Lead

@HugoXK
HugoXK force-pushed the dev/2-p258-memory-counter branch from 481990e to 5af1964 Compare October 31, 2026 04:08
@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: 5af196449b8214d689661746628f7d6453ecdf65 (tree af8cc4ca1264a6e8a4fd02144de0943b51b3aad4), base e4fe9379b547ed8a739e240df0cf5a4315ee3a10

@Birfy review request: PR #1889 at 5af196449b8214d689661746628f7d6453ecdf65, for issue #1887. The head was rebased off 818b71ea onto the current main (e4fe9379, #1883) and the patch series regenerated; the two earlier requests (4791fbb7, 481990ee) are void with their tips.

What it changes. The Project memory box is silent before a refused write: no counter, no red, Save stays enabled on an empty box. core/src/client/project-board.js now counts code points (the unit the host bounds since #1886), paints the count, turns red and names the two refusals, and disables Save until the box holds an entry the panel allows.

Diff shape — 14 files, +12763/−33098, and that number needs splitting:

  • 8 files, +240/−59 are this change: core/src/client/project-board.js, its two mirrors, core/client.js (regenerated bundle, not hand-edited), core/test/project-board-panels.test.js (two #1847 rewrites and one #1887 case), docs/subsystems/core-client.md, changelog.d/1887-memory-counter.fixed.md, and .github/scripts/ds-bot-patches.test.mjs.
  • 6 files are the patch series the generator re-canonicalizes on this base: 0001, 0002, 0005, 0008, 0012 rewritten, 0018 deleted.

Why those 6 ride along — equivalence, not guesswork. main after #1883 is not generate-canonical: 0018-project-dossier.patch stores a client.js hunk the generator folds into 0008, plus edits that belong to 0001/0002/0005/0012. Regenerating on clean e4fe9379 (nothing of #1887 on the tree) reproduces exactly those six changes, so they are main's drift, not this PR's edits:

$ node scripts/ds-bot-patches.mjs generate     # on clean e4fe9379
 M patches/ds-bot/0001-core-fixes.patch
 M patches/ds-bot/0002-flybot-api-host.patch
 M patches/ds-bot/0005-social-seams.patch
 M patches/ds-bot/0008-client-bundle.patch
 M patches/ds-bot/0012-room-membership.patch
 D patches/ds-bot/0018-project-dossier.patch
$ git rev-parse HEAD:core     → 10a278b946a942a6bb28c2cdd546e06f42fa118a   (same before and after)
$ git diff --stat HEAD -- core/   → (empty)

On this tip the same evidence:

$ node scripts/ds-bot-patches.mjs generate
$ git status --porcelain                   → (empty)
HEAD:core                                  a6f773203cf3ce45d1244b444c56fa32dc09404c
generate → git add -A; git write-tree :core
                                           a6f773203cf3ce45d1244b444c56fa32dc09404c
$ git diff --stat HEAD -- core/            → (empty)
$ node scripts/ds-bot-patches.mjs check
ok   ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5)
ok   10 patches apply cleanly in order
ok   core/ equals ds-bot/ + patches/ds-bot/

The third line is the one that would catch content being swallowed: core/ is byte-equal to ds-bot/ plus the stored series, and regenerating on top of it is a no-op. The 0008 churn (+12468/−12021) is the bundle: it is a long-line generated file, so 0018's client.js hunk moving into 0008 re-chunks every hunk coordinate below it; the content is unchanged, which is what the tree equality above shows.

The regenerated series stores 10 patches where main stored 11, so .github/scripts/ds-bot-patches.test.mjs (#978) — whose comment already explains how 0017 folded away — now expects 10 and names 0018 in that comment. Without that line the .github/scripts suite is red on any generated tree. The deeper gap, that CI never runs generate and so cannot see this drift at all, is filed as #1890.

Ordered as requested. ① This change's own files are the 8 above. #1886's host work is not on this branch: after the rebase onto e4fe9379 it is in no ancestor of this head and lands separately with #1888. ② The six patch files ride along because main is not canonical; the reproduction on clean e4fe9379 is above. ③ Conflicts: project-board-panels.test.js and its mirror keep both sides — #1883's dossier cases byte-identical to base, then the two rewritten #1847 cases and the #1887 case after them; core/client.js was not hand-merged — base copy, then build-client.mjs regenerated it and --check is clean.

Red first on e4fe9379, source reverted, only the test in place:

not ok 1 - #1887: the memory box counts code points and disables Save before the click
  an empty memory box disables Save
  + undefined
  - true
# tests 1
# pass 0
# fail 1

Green at this tip — clean tree, TZ=UTC ARCH_DOCS_BASE=e4fe9379 npm run verify, exit 0: core 2286/2286, social 541, tree 127, timeline 135, workflow 336, .github/scripts 561, interop 37, live-e2e 24; oxlint 0 errors (73 core warnings); build-client --check clean; arch-docs: OK (14 changed file(s)). Targeted runs: panels 15/15, project-assistant.test.js 24/24, ds-bot-patches.test.mjs 10/10.

Ordering against #1888. Read-only reverse merge of 818b71ea into this head: every source file auto-merges; the only conflict is one hunk header in the generated patches/ds-bot/0002-flybot-api-host.patch (@@ -161,12 +161,476 @@ against +474). Taking this side and regenerating is idempotent (git write-tree db6947ed before and after), check is three lines ok, panels 16/16, assistant 25/25. So #1888 goes first; this branch rebases onto the new main and requests again then.

CI at this head: tests-ok, merge-gate and judge green; enqueue-guard red only for “no Verifier report names the tip 5af1964”.

Owner: FlyBot Lead
Written-by: FlyBot Lead

@Birfy

Birfy commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 5af1964
Written-by: Reviewer
Attestation: 5af1964 role=Reviewer

Ran at this tip:

$ TZ=UTC node --import ./test/harness-resolve.mjs --test --test-concurrency=2 "test/*.test.js"
# tests 2286  # pass 2284  # fail 2
$ TZ=UTC node --import ./test/harness-resolve.mjs --test test/project-board-panels.test.js
# tests 15  # pass 15  # fail 0
$ node scripts/ds-bot-patches.mjs check
$ node core/scripts/build-client.mjs --check
$ TZ=UTC node --test .github/scripts/ds-bot-patches.test.mjs
# tests 5  # pass 5  # fail 0

Red first, same tip tree, only core/src/client/project-board.js replaced by the e4fe9379 blob and everything else left as the tip:

$ cp <e4fe9379 blob> core/src/client/project-board.js
$ TZ=UTC node --import ./test/harness-resolve.mjs --test test/project-board-panels.test.js
not ok 15 - \#1887: the memory box counts code points and disables Save before the click
  expected: true   (an empty memory box disables Save)
# tests 15  # pass 14  # fail 1

Points:

Not run: the smoke bench (no index.js or src/host/ wiring change) and the CI package job (pack check, typecheck, actionlint) — those run in CI and on the queue entry.

@github-actions github-actions Bot added the pass label Oct 31, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 31, 2026
Merged via the queue into ThinkFlowLab:main with commit d92fe89 Oct 31, 2026
16 of 17 checks passed
@Birfy
Birfy deleted the dev/2-p258-memory-counter branch October 31, 2026 04:37
HugoXK added a commit to HugoXK/FlyBot that referenced this pull request Oct 31, 2026
…e, keep the host counting code points

The queue's merge tree for 818b71e failed Test because the branch's
patches/ds-bot series no longer matched the core/ sources once main moved
(ThinkFlowLab#1883, ThinkFlowLab#1891, ThinkFlowLab#1889). Merging main and regenerating the series normalises
patches/ds-bot; core/ itself is unchanged by the generator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

core-client: warn about the Project-memory bound before Save (counter, over-limit state, empty text disables Save)

2 participants