Skip to content

feat(byte-codec): portable byte-faithful codec (xxj.1)#62

Merged
brandon-fryslie merged 1 commit into
masterfrom
tmux-byte-codec-xxj.1
May 27, 2026
Merged

feat(byte-codec): portable byte-faithful codec (xxj.1)#62
brandon-fryslie merged 1 commit into
masterfrom
tmux-byte-codec-xxj.1

Conversation

@brandon-fryslie

Copy link
Copy Markdown
Contributor

Summary

  • Creates src/protocol/byte-codec.ts — the single enforcer for the bytes ↔ latin1-container string contract
  • Exports bytesToLatin1(Uint8Array → string) and latin1ToBytes(string → Uint8Array), both using chunked charCodeAt/fromCharCode for portability and stack safety
  • 11 new unit tests covering: full 0x00-0xFF range, windows-1252 landmine bytes (0x80-0x9F), large-input chunking (>8192 bytes), round-trip identity

Why not TextDecoder('latin1')

Browsers alias latin1 to windows-1252, silently remapping bytes 0x80–0x9F to non-latin1 code points. Any transport using it to decode binary tmux output frames would corrupt high-byte content. The charCodeAt/fromCharCode approach is the only portable path that is literally 1:1.

Architectural laws

  • [LAW:single-enforcer] — one site for the byte-container contract, none re-derive it
  • [LAW:one-source-of-truth] — the 1:1 byte↔code-unit invariant is stated once in the module header
  • [LAW:behavior-not-structure] — tests assert the observable contract (round-trip, 0x80-0x9F fidelity, chunk boundary correctness), not implementation internals

Test plan

  • pnpm run test:all — 565 tests pass (30 test files)
  • New tests/unit/byte-codec.test.ts — 11/11 pass
  • pnpm run build — clean typecheck

Next

tmux-byte-codec-xxj.2 will route all transports (websocket transport, websocket server) through these functions, replacing the new TextDecoder() calls that are currently wrong.

…] for bytes↔string

Introduces `src/protocol/byte-codec.ts` with `bytesToLatin1` and `latin1ToBytes`,
the single authoritative site for the contract "each byte 0x00-0xFF maps 1:1
to code unit U+0000-U+00FF".

Uses chunked fromCharCode/charCodeAt (not TextDecoder('latin1')) to remain
portable across Node, browser, and Deno — TextDecoder('latin1') silently
remaps 0x80-0x9F via windows-1252 in browsers. Chunks of 8192 avoid
call-stack overflow on large inputs.

Closes tmux-byte-codec-xxj.1.
Copilot AI review requested due to automatic review settings May 27, 2026 19:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a single, portable byte-faithful codec module that converts between Uint8Array and a latin1-container string without the windows-1252 remapping pitfalls of TextDecoder('latin1'). This is a preparatory change; downstream transports will be routed through these helpers in a follow-up PR.

Changes:

  • Add src/protocol/byte-codec.ts exporting bytesToLatin1 (chunked String.fromCharCode) and latin1ToBytes (charCodeAt & 0xff).
  • Re-export both helpers from the protocol barrel.
  • Add 11 unit tests covering full 0x00–0xFF range, 0x80–0x9F fidelity, >8192-byte chunking, and round-trips.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/protocol/byte-codec.ts New module implementing the byte↔latin1-string contract with LAW comments.
src/protocol/index.ts Re-exports bytesToLatin1/latin1ToBytes from the protocol barrel.
tests/unit/byte-codec.test.ts Unit tests asserting the 1:1 contract, high-byte fidelity, large-input chunking, and round-trips.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@brandon-fryslie brandon-fryslie merged commit e9d4d40 into master May 27, 2026
1 of 2 checks passed
@brandon-fryslie brandon-fryslie deleted the tmux-byte-codec-xxj.1 branch May 27, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants