Skip to content

host: the steward's long-message view keeps 1000 characters, not its 1500-character budget, when the text is dense in astral characters #2552

Closed

Description

@HugoXK

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.

Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 033a673560cc461c8eb0c9a870d5a912
Branch: dev/5-steward-shorten-chars
Base: 940815a
At: 2026-11-06T00:07:16Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.

Written-by: FlyBot Lead

What happens

shorten() in core/src/host/steward.js claims to cut a long message on a 1500-character budget, and #2546/#2548 moved the test of that budget to code points (fits()), but the two cut points still mix two units:

const head = codePointEnd(text, Math.ceil((STEWARD_LINE_MAX * 2) / 3))
const tail = codePointStart(text, text.length - (STEWARD_LINE_MAX - head))

codePointEnd() returns a UTF-16 index (it only steps back off a surrogate pair), so head is an index, yet STEWARD_LINE_MAX - head subtracts it from a character budget and then subtracts that from text.length, also an index. slice() therefore cuts at the right place, but the budget arithmetic is off whenever the message holds astral characters: the view keeps fewer characters than 1500 and the marker overstates what was left out.

Measured with a probe built only on stewardRequest. steward.js is blob fca6229d27f0 on both 3d81d8b47f0b and the newer 940815ab184e, so the readings hold on both:

message (1500-character budget) characters kept marker says
'a'.repeat(1600) 1500 100
'🚀'.repeat(1800) 1500 300
'🚀'.repeat(800) + 'a'.repeat(800) (1600 chars) 1000 600
'🚀'.repeat(500) + 'a'.repeat(1100) (1600 chars) 1000 600
1500 characters exactly 1500 0 (fits)

A message dense in astral characters (🚀, most emoji, CJK extension B) loses a third of the view the budget allows, and such a message is exactly a long pasted report.

Not a regression from #2548: before it, the same two lines were on UTF-16 units and the view was 1000/750 characters. This is the half of #2546/#2548 that did not move.

Reproduction

No source change, live main:

import { stewardRequest } from './core/src/host/steward.js'
const body = '🚀'.repeat(800) + 'a'.repeat(800) // 1600 code points
const [line] = stewardRequest({ lines: [{ who: 'user', text: body }], midTurn: false, checkpoints: [], group: null }).split('\n\n')
console.log([...line].length, line.includes('characters left out'))
// today: 1000 characters kept, marker reports 600 left out

Expected

For a message over the 1500-character budget, the view keeps 1500 characters: the head is the first 1000 code points, the tail is the last 500 code points, and the marker reports characters − 1500 left out (100 for a 1600-character message). A message at or under 1500 characters is returned untouched.

Scope

  • core/src/host/steward.js: shorten() takes both cut points from the code-point count (head = UTF-16 index of the 1000th code point, tail = index of the 500th code point from the end), so an index is never subtracted from a character budget. fits(), linesFor(), STEWARD_TOKENS, STEWARD_LINE_MAX and the marker wording stay as they are.
  • core/test/steward.test.js: assertions added to the existing case at :120 ('a long message shortened for the steward cuts on characters, never inside one', whose :123 comment already states the rule), not a new file — '🚀'.repeat(800) + 'a'.repeat(800) through stewardRequest keeps 1500 characters and a marker of 100; red on today's tree (1000/600).
  • patches/ds-bot/0001-core-fixes.patch regenerated by node scripts/ds-bot-patches.mjs generate — both core/src/host/steward.js and core/test/steward.test.js live in that patch, so canonical fails without it; one changelog.d/ fragment.
  • Not the client bundle, not core/client.js; no plugin or docs change needed.

Duplicate check

Searched steward.js (blob fca6229d27f0, unchanged on 3d81d8b4 and 940815ab) for STEWARD_LINE_MAX, codePointEnd, shorten( and the closed issue list for "steward shorten": the only hits are #2546 (closed, merged) and #2548 (closed, merged), which fixed the fits() test but left these two lines; no open issue covers the remaining half. Tier: T2 (core/src/host/**).

Activity

  1. HugoXK commented on Nov 6, 2026

    @HugoXK
    ContributorAuthor

    Release

    Written-by: FlyBot Lead
    Released: 033a673560cc461c8eb0c9a870d5a912
    Reason: merged and issue closed
    At: 2026-11-06T02:13:30Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions