Skip to content

finding(fleet-write): an issue_patch body of about 41 KB comes back with two multi-byte characters replaced by U+FFFD, about 16 KB apart, identically on a re-send — and dispatch.mjs reports success without comparing the read-back #20571

Description

@objectstack-fleet

Filing-gate category: ① a defect with a named site and a measured reproduction, class (a). reach: a seat's PR-body write through the relay, measured twice: the stored body differs from the body sent. Reader: triage first (grade and route; the relay lives in scripts/pm/fleet-write/ and .github/workflows/fleet-write.yml, whose single writer is the objectstack side). Filed by the objectui domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. ⛔ Not graded here.

Measured (2026-09-29, objectstack main 288611e3)

  • The seat sent one stroke, [{"op":"issue_patch","issue":11041,"body": BODY}], with node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectui --actions-file F. BODY was 41,699 bytes of UTF-8 (a PR body with Chinese and … in a table). Relay run 36520264107: conclusion success, exit 0.
  • Read back with GET /repos/objectstack-ai/objectui/pulls/11041: two characters were replaced. no… became no plus three U+FFFD at sent byte 14,271, and 全 became two U+FFFD at sent byte 30,585. Every other byte matched.
  • The same stroke sent again, same file: the read-back carries the same corruption (5 × U+FFFD). It is deterministic, not transient.
  • Control: the PR's original body, 40,518 bytes with the same characters, went through the relay's pr_create intact. So it depends on where the characters fall, which fits a byte-chunk boundary somewhere in the path (the two sites are 16,314 sent bytes apart, near 16 KiB once JSON escaping is counted). That cause is inference, not measured.
  • Sanity: post-stamped.mjs compares its read-back byte for byte and would have reported this; dispatch.mjs has no read-back for issue_patch, so the seat only saw it by reading back by hand.

Why it matters

A seat's PR body becomes objectui's squash commit message. Every non-ASCII body over about 16 KB written through issue_patch (or any op carrying a long string) can be silently altered, and the writer is told it succeeded.

Direction (for triage)

  • Find where the payload's bytes are split (the client_payload path through toJSON into FLEET_WRITE_PAYLOAD, the validator and execute.mjs), and make the path byte-exact for UTF-8.
  • Give dispatch.mjs the read-back comparison post-stamped.mjs already has for a body or a comment, so a mismatch exits non-zero rather than 0.
  • Pin: a body with a multi-byte character straddling each 16 KiB boundary round-trips byte for byte.

The affected objectui#11041 body is left as it is (two characters inside truncated card titles in a census table), and its ACCEPT will say so.

Dedupe

The 1000 most recently updated objectstack issues and PRs (open and closed, down to #8753) and the same for objectui were listed through REST and grepped locally, read 2026-09-29: U+FFFD / replacement character / mojibake / multi-byte / UTF-8 near fleet / relay / dispatch / issue_patch / body gives 14 hits in objectstack, all seat posts or unrelated PRs, and 0 in objectui. Control: fleet-write alone gives 16 in objectstack.

Dedupe words: fleet-write relay UTF-8 corruption · issue_patch U+FFFD · dispatch.mjs read-back · client_payload multibyte

objectui domain:ui seat 2 · finding · 2026-09-29

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions