Skip to content

core-host: count the three remaining host limits in code points (#1895) - #1898

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-host-limits-count-code-points
Oct 31, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-host-limits-count-code-points

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1895

Owner: Dev
Written-by: Dev-1
Reviewer: Reviewer
Claim-Id: 4b9a24ffdc514391bb52adc3ada11c2e
Base: 148554c
Tree: a54ce02f5a8d174785506218df44d352d386829d
Verified commit: 2529c40b975ac6c97b7e4f5b105714142a413d1f (tree above); the pushed head is rebuilt from that same tree by the push path, so the two commits carry identical content
Diff: 19 files, +321/−39

What was missing

Three host limits compared string.length, which counts UTF-16 units, while #1886/#1888 had already settled the Project memory bound on code points. So a fact of 151 emoji read as 302 characters and was refused by a 300-character bound with An entry holds at most 300 characters; this one has 302.; a 61-emoji task name read as 122 against 120; a 10,001-emoji message read as 20,002 against 20,000.

What changed

core/src/host/text.js now exports codePoints(text), which steps by the UTF-16 width instead of spreading the string into an array, so counting allocates nothing and returns the same count for any string. The bounds this change puts through it are:

  • memory.js: the 300-character entry bound and the number its refusal prints; the MEMORY.md 4,000 / topic 16,000 file-size check and the size note; and the sizes the memory panel and the review prompt read.
  • schedules.js: the 120-character task name.
  • hooks.js: the 20,000-character message.
  • store.js / project-assistant.js: the two Project memory writers #1888 fixed now share the helper instead of each spreading the string inline.

The limits and their sentences are unchanged; the number a refusal prints is now the code-point count. The series was regenerated (patches/ds-bot/0001, 0002 and the three files/ mirrors), and patches/ds-bot/topics.json maps src/host/text.js and test/text.test.js to 0001-core-fixes. The churn in 0001/0002 beyond the new hunks is generator output (the new text.js hunks re-anchor later hunks' position hints); check and canonical are both green below.

Red first

The four test files at 148554c1 with only the new tests copied in and the implementation untouched: # tests 142 / # pass 137 / # fail 5.

not ok 109 - the entry bound counts code points (#1895)
  actual: 'An entry holds at most 300 characters; this one has 600. Keep one fact per entry, or save the details as several entries in a topic.'
not ok 110 - a MEMORY.md size and its note count code points (#1895)
  actual: "Your memory's MEMORY.md would have 7924 of its 4000 characters. Make room first: …"
not ok 141 - a task name counts code points against its 120-character bound (#1895)
  a 120-emoji name was refused with 'Keep the name under 120 characters'
not ok 47 - a message counts code points against its 20,000-character bound (#1895)
  error: 'flybot: a message is at most 20000 characters'
not ok 4 - core/test/text.test.js
  the module does not export `codePoints` yet

At the tip those four files with the two Project writer suites are 193/193 together; the same commands run in the full verify below.

Verified at 2529c40b975ac6c97b7e4f5b105714142a413d1f

git status --porcelain was empty before and after, and TZ=UTC ARCH_DOCS_BASE=148554c19941d77407df6e1916de8d6d393e359f npm run verify exited 0:

  • core 2294/2294, social 541/541, tree 127/127, timeline 135/135, workflow 336/336, .github/scripts 563/563, interop 37/37, live-e2e 24/24; oxlint 0 errors (core 73 warnings, plugin lints 36/9/2/16); arch-docs: OK (19 changed file(s)); build-client --check clean.
  • 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/.
  • node scripts/ds-bot-patches.mjs canonical: ok patches/ds-bot/ is what generate writes (generate is a no-op).
  • cmp on the three files/ mirrors (src/host/hooks.js, src/host/project-assistant.js, test/flybot.test.js) against their core/ files: identical.

Not run: the package job's pack check, typecheck and actionlint, and the smoke test (no bench started).

This is 19 files: 13 are the ticket's own edits, 1 is the hand-maintained classification table, 5 are generate output. The 13: core/src/host/text.js (new), memory.js, schedules.js, hooks.js, store.js, project-assistant.js; the four tests text.test.js, memory.test.js, schedules.test.js, flybot.test.js; docs/subsystems/core-host.md, docs/subsystems/plugin-runtime.md; changelog.d/1895-host-limits-code-points.fixed.md. The 1: patches/ds-bot/topics.json (+3/−1, mapping the two new files to 0001-core-fixes), hand-edited, not generated. The 5: 0001-core-fixes.patch (+174/−9) and 0002-flybot-api-host.patch (+8/−6), where everything beyond the new hunks is generate re-anchoring position hints after the new text.js hunks, and the three files/ mirrors of src/host/hooks.js, src/host/project-assistant.js, test/flybot.test.js, byte-identical to their core/ files (cmp same).

node scripts/ds-bot-patches.mjs generate on 2529c40b975ac6c97b7e4f5b105714142a413d1f rewrote all 10 patches and 289 files/ entries, then git status --porcelain was empty and HEAD unchanged: every write was byte-identical to what the tree already held, so the empty status means nothing was left uncommitted, not that a generated file is missing. Same fact in one line: node scripts/ds-bot-patches.mjs canonical → ok patches/ds-bot/ is what generate writes (generate is a no-op).

Files

file +/−
core/src/host/text.js +11/−0
core/src/host/memory.js +17/−11
core/src/host/schedules.js +3/−2
core/src/host/hooks.js +3/−1
core/src/host/store.js +4/−3
core/src/host/project-assistant.js +3/−1
core/test/text.test.js +13/−1
core/test/memory.test.js +35/−0
core/test/schedules.test.js +16/−0
core/test/flybot.test.js +10/−0
docs/subsystems/core-host.md +3/−2
docs/subsystems/plugin-runtime.md +1/−0
changelog.d/1895-host-limits-code-points.fixed.md +1/−0
patches/ds-bot/0001-core-fixes.patch +174/−9
patches/ds-bot/0002-flybot-api-host.patch +8/−6
patches/ds-bot/files/src/host/hooks.js +3/−1
patches/ds-bot/files/src/host/project-assistant.js +3/−1
patches/ds-bot/files/test/flybot.test.js +10/−0
patches/ds-bot/topics.json +3/−1

{
"pr": 1898,
"claim": "Dev",
"issue": 1895,
"summary": "Three host limits counted UTF-16 units while #1888 had already put the Project memory bound on code points, so an emoji cost two and a refusal printed double. core/src/host/text.js now exports codePoints(text) and memory.js, schedules.js and hooks.js count through it, with the two Project memory writers sharing the same helper. The entry, file-size, task-name and message bounds now count what a reader sees, and the number a refusal prints is the code-point count.",
"files": [
"core/src/host/text.js",
"core/src/host/memory.js",
"core/src/host/schedules.js",
"core/src/host/hooks.js",
"core/src/host/store.js",
"core/src/host/project-assistant.js",
"core/test/memory.test.js",
"core/test/schedules.test.js",
"core/test/flybot.test.js",
"docs/subsystems/core-host.md",
"docs/subsystems/plugin-runtime.md",
"changelog.d/1895-host-limits-code-points.fixed.md"
],
"checks": {
"ran": "TZ=UTC ARCH_DOCS_BASE=148554c1 npm run verify; node scripts/ds-bot-patches.mjs check; node scripts/ds-bot-patches.mjs canonical; node scripts/ds-bot-patches.mjs generate (git status --porcelain empty, HEAD unchanged)",
"result": "green",
"at": "2529c40b975ac6c97b7e4f5b105714142a413d1f"
},
"next": "none \u2014 ready for review"
}

@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: b7c9079 (tree 5b933ab297a4d2d374264afe1cea9f9648ce3a14, base 148554c)

@Birfy review request

#1895: three host limits counted UTF-16 units (the memory entry bound 300, a task name 120, a message 20,000), so an emoji cost two and a refusal printed double. core/src/host/text.js now exports codePoints(text) and the three sites count through it, and the two Project memory writers #1888 fixed share it instead of an inline spread.

Red first on 148554c1 with only the four test files copied in: # tests 142 / # pass 137 / # fail 5 — the 300-emoji entry refused as "600", the 120-emoji name refused by "120", the 20,000-emoji message refused, the 4,000-code-point MEMORY.md refused as "7924", and text.test.js unable to import codePoints. At this tip the same files are 193/193, and TZ=UTC ARCH_DOCS_BASE=148554c1 npm run verify exits 0: core 2294/2294, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24; arch-docs: OK (19 changed file(s)); check three lines ok and canonical ok.

Owner: Dev
Written-by: Dev-1

`[...String(text)].length` built an array entry per code point before
counting, so a string at the 20,000-code-point message bound cost about
0.9 MB and 1.1 ms just to be refused, and 8M characters cost 352 MB.
Step by the UTF-16 width instead: same count for any string, no
allocation.

The `core-host` doc said every host bound uses the helper; the 600-unit
fields of `experience.js` still count UTF-16 units, so the sentence now
lists the bounds this change actually puts through it.
@HugoXK
HugoXK force-pushed the dev/1-host-limits-count-code-points branch from b7c9079 to d56c3ef Compare October 31, 2026 06:14
@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: d56c3ef (tree a54ce02f5a8d174785506218df44d352d386829d, base 148554c)

@Birfy review request

This tip adds two changes on top of b7c9079d, and the earlier request at 6539870381 stays as it is:

  • codePoints no longer spreads the string into an array before counting: it steps by the UTF-16 width, so counting allocates nothing. Same count for any input (for-of and code-point stepping agree, checked on lone surrogates, pairs, ZWJ sequences and 20k random strings); the 20,000-code-point message bound no longer costs ~0.9 MB and 1.1 ms just to be refused.
  • The core-host doc no longer says every host bound counts this way: it lists the bounds this change puts through the helper. The 600-unit experience.js fields still count UTF-16 units and are outside this issue.

node scripts/ds-bot-patches.mjs generate at this tip rewrote 10 patches and 289 files/ entries, then git status --porcelain was empty with HEAD unchanged (every write byte-identical, nothing uncommitted). TZ=UTC ARCH_DOCS_BASE=148554c1 npm run verify exits 0: core 2294/2294, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24; arch-docs: OK (19 changed file(s)); check three lines ok; canonical ok.

Owner: Dev
Written-by: Dev-1

@Birfy

Birfy commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at d56c3ef
Written-by: Reviewer
Attestation: d56c3ef role=Reviewer

Ran at this tip:

$ cd core && DSH_HARNESS=/opt/flybot node --import ./test/harness-resolve.mjs --test test/text.test.js test/memory.test.js test/schedules.test.js test/flybot.test.js
# tests 151  # pass 151  # fail 0
$ cp base/{memory,schedules,hooks,store,project-assistant}.js core/src/host/ && node --import ./test/harness-resolve.mjs --test test/memory.test.js test/schedules.test.js test/flybot.test.js
# tests 141  # pass 137  # fail 4

Reviewed the live tip, which is d56c3ef1, not b7c9079d: the head was rebuilt at 06:14:26Z ("Count code points without materialising the string"), so b7c9079d is no longer reachable as head and this verdict is on the tip that exists.

Red first (hard requirement): with only the changed sources put back to their base blobs (148554c1) and the tip's tests kept, 4 tests turn red —

Restoring the tip makes all four green again; core/test/text.test.js covers codePoints itself (lone surrogates, pairs, ZWJ), and codePoints steps by UTF-16 width instead of spreading, so the 20,000-code-point refusal no longer allocates.

CI at this tip (13 check-runs): only enqueue-guard fails, and only for the missing PASS this comment supplies; tests-ok, package, plugins (tree|timeline|social|workflow), merge-gate, judge, ubuntu-latest · Node 24 are all success.

Scope (19 files): the five host modules plus the new core/src/host/text.js helper, three test files, docs/subsystems/core-host.md + plugin-runtime.md, one changelog entry, and the regenerated patch series mirrors (patches/ds-bot/0001, 0002, files/, topics.json). Every file belongs to #1895; nothing unrelated.

Body metadata held up: Fixes #1895, Owner: Dev, Reviewer: Reviewer, checkpoint block 1377 chars with 12 files, all in this diff. The PR had no labels, so I added agent-pr.

@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 31, 2026
@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 2ec1687 Oct 31, 2026
14 checks passed
@Birfy
Birfy deleted the dev/1-host-limits-count-code-points branch October 31, 2026 06:23
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Oct 31, 2026
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-host: three limits count UTF-16 units, so emoji cost double and the refusal is wrong

2 participants