Skip to content

id(web): world presenter still mis-measures ⬛/⭕, narrow-base skin tones, composed Hangul jamo and long graphemes — #1431's folded-in classes survived its fix, and the 16-unit symbol cap has no Rust twin #1581

Closed

Description

@dezren39

Summary

The web world presenter (pkgs/id/web/src/world-surface.ts) still diverges from the Rust validator for four grapheme classes. CLOSED #1431 fixed emoji-modifier and tag sequences (PR #1542), but two classes that were folded into #1431 as evidence (comment 6446198995) were not touched by that fix, and two further classes in the same function were found this run. In every case a screen the Rust side validates and the SSH presenter renders (world_presentation.rs:219 parse, :350 render_ansi, both measuring with UnicodeWidthStr::width under unicode-width 0.2.2, pinned in pkgs/id/Cargo.lock) is either refused whole by the web presenter — renderWorldSurface returns false, so world.ts:175-176 falls back to dumping the raw frame text — or, worse, accepted at the wrong column count, producing a misaligned grid.

Verified on main 601af5a (2026-10-27, lane-B creator run)

Method: TS probe on the laptop driving the verbatim world-surface.ts (sha256 3ee9823c identical both sides; Bun 1.4.2, minimal DOM stub, renderWorldSurface called directly) against a Rust probe crate on the laptop using the pinned unicode-width =0.2.2 + unicode-segmentation (the exact crates world_presentation.rs uses). Controls behaved: x Rust 1 / TS renders at 1; U+1F600 Rust 2 / renders at 2, refused at 1; the #1542 controls U+1F44D U+1F3FD and the England tag flag render at 2.

1. ⬛ U+2B1B and ⭕ U+2B55 — wide in Rust, missing from WIDE_RANGES

2. Narrow base + skin-tone modifier — ☝🏻 U+261D U+1F3FB

3. Composed Hangul jamo clusters — U+1100 U+1161 (LV) and U+1100 U+1161 U+11A8 (LVT)

4. One grapheme longer than 16 UTF-16 units, and a lone spacing mark

  • e + 17× U+0301 (combining acute): Rust 1 grapheme, width 1. TS refuses at columns=1 — pinned to the cell.symbol.length > 16 check (world-surface.ts, cell validation in renderWorldSurface): the same grapheme at UTF-16 length 15 and 16 renders, at 17 and 18 it is refused. The Rust validator imposes no symbol-length limit — only exactly-one-grapheme and width 1–2 — so the cap is a TS-only rule that rejects Rust-valid cells.
  • Lone U+0903 (Devanagari spacing combining mark, category Mc): Rust width 1; TS width 0 via the /^\p{M}$/u rule (world-surface.ts:133,142), so the cell is refused at both column counts. (Inside a cluster after a base consonant both sides agree at the base's width; only the standalone mark diverges.)

Why it matters

The presenter is the web half of a two-presenter contract: the same validated ScreenSurface must render on SSH and web. Every divergence either drops the whole screen to a raw-text dump (classes 1–4, at the correct column count) or silently misaligns it (classes 1–2, at the wrong count — a guest that disagrees with the Rust validator, or a future Rust change, would pass the web check it should fail). ⬛/⭕ are ordinary emoji a world program can plausibly draw as tiles; decomposed Hangul and accented Latin are ordinary text.

Acceptance criteria

Notes

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  5. 37 remaining items

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 31, 2026
  7. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 31, 2026
  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · claimed

  10. added a commit that references this issue on Oct 31, 2026
  11. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

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

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions