• sexyz: ZMODEM ESC8 (Escape8thBit) is advertised but implemented in nei

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Sat Aug 29 23:46:42 2026
    open https://gitlab.synchro.net/main/sbbs/-/issues/1229

    Setting `Escape8thBit=true` in `sexyz.ini` makes sexyz advertise `ZF0_ESC8` in its ZRINIT, asking the remote sender to escape every byte with the high bit set. **sexyz cannot decode those escapes**, so a sender that honours the request cannot transfer to it at all. sexyz also ignores the flag when *sending*, so it never escapes on behalf of a peer that asks for it.

    In short: the option is advertised on the wire but implemented in neither direction.

    ## Reproduction

    `sexyz.ini`:

    ```ini
    [ZMODEM]
    Escape8thBit=true
    ```

    Then receive from a sender that honours ESC8 — `zmtx` 2.04 is the only one I know of (see *History* below):

    ```
    zmtx -8 file -> sexyz -8 rz
    ```

    Result: the transfer never starts.

    ```
    sexyz: !0 Illegal sequence: ZDLE 229 (x6)
    sexyz: !0 zmodem_recv_raw TIMEOUT (10 seconds)
    sexyz: !zmodem_recv_header TIMEOUT
    sexyz: Exiting - Error level: -1
    zmtx: zmtx: can't start file transfer: protocol timeout
    ```

    With `Escape8thBit=false` (the default) the same pair transfers normally.

    ## Root cause

    **Receive.** `zmodem_rx()`'s ZDLE branch decodes only `(c & 0x60) == 0x40`, i.e. a control character escaped as `ZDLE, c + 0x40`. An ESC8 escape is `ZDLE, c ^ 0x40` where the original byte has bit 7 set — for example `0xA5` is sent as `ZDLE 0xE5`. `0xE5 & 0x60 == 0x60`, not `0x40`, so it falls through to:

    ```c
    lprintf(zm, LOG_WARNING, "%lu Illegal sequence: ZDLE %s", ...);
    ```

    which is exactly the `Illegal sequence: ZDLE 229` (`0xE5`) above. There is no ESC8 case anywhere in `zmodem_rx()`.

    **Send.** `zmodem_tx_active()` builds the transmit escape mask from `escape_ctrl_chars` and `escape_telnet_iac` only:

    ```c
    return ZMODEM_TX_ESCAPE_ALWAYS
    | (escape_ctrl * ZMODEM_TX_ESCAPE_CTRL)
    | (!!zm->escape_telnet_iac * ZMODEM_TX_ESCAPE_IAC);
    ```

    `escape_8th_bit` is not consulted anywhere in the transmit path. Confirmed by measurement: a sexyz → sexyz transfer with `Escape8thBit=true` at **both** ends succeeds while putting the *unescaped* byte count on the wire (4,311,816 bytes for a 4 MiB random file — identical to a run with the option off).

    The flag has exactly two uses in the tree today:

    - `zmodem.c` — assigned from the peer's ZRINIT (`zm->escape_8th_bit = INT_TO_BOOL(zm->rxd_header[ZF0] & ZF0_ESC8)`)
    - `zmodem.c` — consulted in `zmodem_send_zrinit()` to set the flag we advertise

    ## History

    - `escape_8th_bit` arrived with the original import, e1d0ddb0b5 (2003-09-04). Even then it was only ever assigned from the peer's ZRINIT and printed in a debug line — it never fed an escaping decision.
    - 49901d3aca (2005-06-11), "Renamed zm.escape_all_control_chars to just escape_ctrl_chars. send_zrinit() now sets ZF0 flags based on configurable BOOLs", is where sexyz began **advertising** ESC8 from the configurable flag.
    - Nothing has touched it since.

    So it has never been implemented, and has been advertised for 21 years.

    ## Why this stayed hidden

    No other implementation honoured ESC8 either, so nothing ever escaped on our behalf and the missing decode path was never reached:

    - Chuck Forsberg's own **rzsz 3.73** defines `ESC8`/`TESC8` in `zmodem.h` and **never references either in any `.c` file** — he specified the flag and did not implement it. (He does consume the neighbouring ZF0 bits: `Zctlesc |= Rxflags & TESCCTL`, `CANFC32`, `CANFDX` in `sz.c`.)
    - **lrzsz 0.12.21rc** inherits the same two dead `#define`s and likewise never references them.
    - **zmtx/zmrx 2.04**, released 2026-08-25, is the first implementation in this lineage to actually implement it — `zmrx -b` to request it, `TX_ESCAPE_8TH` in `zmdm.c` to honour it. That is what exposed this.

    Verified that zmtx/zmrx's implementation is real and self-consistent: `zmtx → zmrx -b` transfers correctly with genuine escaping, the wire growing from 4,311,816 to **6,360,011** bytes for the same 4 MiB file. By contrast `sexyz → zmrx -b` and `lsz → zmrx -b` both "succeed" only because the sender ignores the request and zmrx tolerates unescaped input.

    ## Impact

    `Escape8thBit` defaults to `FALSE`, so a default install is unaffected and this is not a regression — it has never worked. The exposure is any sysop who sets it, which is precisely the sysop on a link that does not pass 8-bit data cleanly: they get a receiver that cannot receive from a conforming sender, with a misleading `Illegal sequence` / `TIMEOUT` failure rather than a diagnostic.

    ## Suggested resolution

    Either is defensible:

    1. **Implement it.** Add an ESC8 decode to `zmodem_rx()` and an `ESCAPE_8TH` class to the transmit mask, mirroring how ESCCTL is handled. There is now exactly one peer to interoperate with and test against.
    2. **Stop advertising what is not implemented.** Drop `ZF0_ESC8` from `zmodem_send_zrinit()` and remove or deprecate the `Escape8thBit` key, so sexyz never asks for something it cannot decode.

    (2) removes the footgun immediately; (1) is the more useful end state now that a working peer exists. Doing neither leaves a config key whose only effect is to break transfers.

    ## Notes

    - Found while re-measuring `docs/zmodem_comparison.md` against current releases of every implementation; see §7.2 there for the measurements and the ESC8 interoperability table.
    - Unrelated to this issue, and not ours: zmtx 2.04's **ESCCTL** sender omits carriage return, so it cannot send to any ESCCTL receiver other than its own `zmrx`. That is filed separately in the comparison document for the zmtx/zmrx maintainer.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sat Aug 29 23:53:10 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10225

    Follow-up on the history, from Chuck Forsberg's own release archive (~40 rzsz releases, 1986-05 through 2003-01) and the canonical `ZMODEM.DOC`. This weakens option 1 above, so it is worth recording.

    **ESC8 was reserved, not specified.** In the canonical ZMODEM.DOC (1988-10-14, 3488 lines) the flag appears exactly twice:

    - one operational sentence — *"If the ZSINIT header specifies ESCCTL or ESC8, a HEX header is used, and the receiver activates the specified ESC modes before reading the following data subpacket"*
    - the embedded copy of `zmodem.h`, i.e. the `#define` itself

    **The encoding is never described anywhere.** There is no normative statement of how an 8th-bit byte is to be escaped. Contrast ESCCTL, which gets a full paragraph: *"The receiving program decodes any sequence of ZDLE followed by a byte with bit 6 set and bit 5 reset … to the equivalent control character by inverting bit 6."*

    **And Forsberg never implemented it either.** In his own source archive:

    - `ESC8`/`TESC8` first appear in `zmodem.h` in the 1987-05-29 release (v1.21). - No `.c` file in **any** release from then through v3.73 (2003-01-30) ever references either symbol — 16 years and roughly 40 releases, defined and never used.

    So the situation is not "we skipped implementing a documented option". The option was reserved in a header, mentioned once in passing, never given an encoding, and never implemented by its author. lrzsz inherited the dead defines unchanged. zmtx/zmrx 2.04 is the first implementation anywhere in this lineage, and its encoding (`ZDLE`, `c ^ 0x40` — the same transform as the control-character escape, applied to high-bit bytes) is a reasonable choice but a **de facto** one, not a specified one.

    That reframes the options:

    - **Option 2 (stop advertising) gets stronger.** We are asking peers for a mode with no specified encoding, and cannot decode the one encoding that exists in the wild.
    - **Option 1 becomes "interoperate with zmtx", not "implement the spec"** — there is no spec to implement. If we do it, the commit should say plainly that it matches zmtx 2.04's convention, so a future reader does not go looking for the normative definition.

    **Not established, and I could not establish it here:** whether Forsberg's *commercial* products (DSZ, GSZ, ZComm, Pro-YAM) implemented ESC8. There is no source for those. The only commercial artifact in the archive is a `DSZ.EXE` whose copyright strings read 1984/1986/1987 with a man page dated 1986-12-21 — it predates the flag's May-1987 introduction, so it cannot answer the question even under a disassembler. Settling it would need a later DSZ/GSZ binary or its `.DOC`, which documented the option set in detail.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sat Aug 29 23:53:22 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10225

    Follow-up on the history, from Chuck Forsberg's own release archive (about 40 rzsz releases, 1986-05 through 2003-01) and the canonical `ZMODEM.DOC`. This weakens option 1 above, so it is worth recording.

    **ESC8 was reserved, not specified.** In the canonical ZMODEM.DOC (1988-10-14, 3488 lines) the flag appears exactly twice:

    - one operational sentence — *"If the ZSINIT header specifies ESCCTL or ESC8, a HEX header is used, and the receiver activates the specified ESC modes before reading the following data subpacket"*
    - the embedded copy of `zmodem.h`, i.e. the `#define` itself

    **The encoding is never described anywhere.** There is no normative statement of how an 8th-bit byte is to be escaped. Contrast ESCCTL, which gets a full paragraph: *"The receiving program decodes any sequence of ZDLE followed by a byte with bit 6 set and bit 5 reset … to the equivalent control character by inverting bit 6."*

    **And Forsberg never implemented it either.** In his own source archive:

    - `ESC8`/`TESC8` first appear in `zmodem.h` in the 1987-05-29 release (v1.21). - No `.c` file in **any** release from then through v3.73 (2003-01-30) ever references either symbol — 16 years and roughly 40 releases, defined and never used.

    So the situation is not "we skipped implementing a documented option". The option was reserved in a header, mentioned once in passing, never given an encoding, and never implemented by its author. lrzsz inherited the dead defines unchanged. zmtx/zmrx 2.04 is the first implementation anywhere in this lineage, and its encoding (`ZDLE`, `c ^ 0x40` — the same transform as the control-character escape, applied to high-bit bytes) is a reasonable choice but a **de facto** one, not a specified one.

    That reframes the options:

    - **Option 2 (stop advertising) gets stronger.** We are asking peers for a mode with no specified encoding, and cannot decode the one encoding that exists in the wild.
    - **Option 1 becomes "interoperate with zmtx", not "implement the spec"** — there is no spec to implement. If we do it, the commit should say plainly that it matches zmtx 2.04's convention, so a future reader does not go looking for the normative definition.

    **Not established, and I could not establish it here:** whether Forsberg's *commercial* products (DSZ, GSZ, ZComm, Pro-YAM) implemented ESC8. There is no source for those. The only commercial artifact in the archive is a `DSZ.EXE` whose copyright strings read 1984/1986/1987 with a man page dated 1986-12-21 — it predates the flag's May-1987 introduction, so it cannot answer the question even under a disassembler. Settling it would need a later DSZ/GSZ binary or its `.DOC`, which documented the option set in detail.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Aug 30 00:17:58 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10226

    **Correction and new evidence: Forsberg's commercial DSZ *does* implement ESC8.** My earlier note left this open, and a comment above it inferred too much from the product manuals. Those manuals name no protocol constant at all — `ESCCTL`, `ZDLE`, `ZRINIT` and `ZSINIT` all appear zero times in DSZ.DOC, GSZ.DOC and the ZCOMM docs — so their silence about ESC8 meant nothing. Settled instead by running the binary.

    **Method.** DSZ.EXE 1997-05-25 (the last release; note the version names are dates, so `dszx0597` = May 1997 is newer than `0607` = June 1995) under DOSBox 0.74, its COM1 bridged to TCP with `serial1=nullmodem`, talking to a Linux-side relay that pipes into a local ZMODEM program and captures both directions. DSZ needs the `d` command or it exits silently, since DOSBox never asserts carrier. **DSZ.EXE, not DSZ.COM** — the 7-bit options are EXE-only.

    **As a receiver, `-E` sets the ESC8 bit.** Captured ZRINIT `ZF0`:

    | DSZ command | ZF0 | flags |
    |---|---|---|
    | `rz` | 0x2F | CANFDX CANOVIO CANBRK CANRLE CANFC32 |
    | `rz -E` | **0xAF** | the same **+ ESC8** |
    | `rz -P` | 0x2F | (Pack-7 negotiated some other way) |
    | `rz -e` | 0x6F | the same **+ ESCCTL** |

    So ESC8 is exactly what its name says, and `-E` — DSZ.DOC's "7 bit mode … RLE compression and 8th bit quoting" — is what turns it on.

    **As a sender, DSZ honours a request, and the result is not decodable by the only other implementation.** Sending a 4096-byte random file:

    | Peer | Result | Wire | Bytes with bit 7 set |
    |---|---|--:|--:|
    | `zmrx -o` (no ESC8) | **byte-identical** | 4,376 | 2,088 (47.7 %) |
    | sexyz `rz` (no ESC8) | **byte-identical** | 4,374 | — |
    | **`zmrx -o -b`** (ESC8 requested) | **fails** — `zmrx: can't establish contact with sender` | 296 | 9 of 267 after ESC8 engages (3.4 %), all one repeated 3-byte sequence |

    DSZ clearly acts on the request — high-bit bytes essentially vanish from the stream — but it also **switches to an undocumented frame type**. Scanning every `ZPAD ZDLE <type>` in the two captures:

    - without ESC8: `'B'` (ZHEX) and `'C'` (ZBIN32) — standard
    - with ESC8: `'B'` once, then **`0x31` (`'1'`) four times**

    `'1'` is not one of the eight frame types defined in any published `zmodem.h` (`ZBIN 'A'`, `ZHEX 'B'`, `ZBIN32 'C'`, `ZBINR32 'D'` and the `ZVBIN` lowercase variants) — checked in every free release from 1987 to 2003. It is a ZMODEM-90 extension Forsberg never published.

    **What this means for this issue.** There are exactly two ESC8 implementations in existence — Forsberg's commercial DSZ/GSZ line, and zmtx/zmrx 2.04 (2026-08-25) — and **they do not interoperate**. That is the expected outcome when a flag is negotiated but its encoding was never specified: ZMODEM.DOC names ESC8 once in passing and never says how a high-bit byte is escaped, so each implementer invented something, and Forsberg's involves a frame type outside the documented set.

    This makes **option 2 the clear choice**. "Implement ESC8" is not a well-defined task: it would mean picking one of two mutually incompatible private encodings, one of which needs an undocumented frame type. Advertising `ZF0_ESC8` commits us to whichever encoding the peer happens to use, and we cannot satisfy both. Dropping the advertisement from `zmodem_send_zrinit()` and retiring the `Escape8thBit` key removes a config option whose only reachable effect is to break transfers — while costing nothing, since the mode has never worked with any peer.

    Worth noting separately: **without ESC8, DSZ interoperates with sexyz perfectly** — a 4096-byte binary transferred byte-identically in the direction tested, with a 1997 DOS binary at one end. The base protocol is fine; only this option is broken.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Aug 30 01:48:30 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10227

    **DSZ's ESC8 encoding, recovered.** It is not ZDLE escaping at all.

    **`0x0E` (SO) prefix, followed by the byte with bit 7 cleared.** Ordinary ZDLE escaping of control characters continues alongside it, unchanged.

    Evidence, from a capture of DSZ.EXE 1997 sending a 4096-byte random file to a receiver advertising ESC8:

    - `0x0E` occurs 4,991 times and is followed by a byte below 0x80 in **100 %** of them; it is never doubled; the successor byte spans 0x01–0x7E.
    - The stream contains **zero** bytes with bit 7 set (4 in 16,679, all before ESC8 engages), against 49.8 % in the same transfer without ESC8.
    - Decoding on that rule alone recovers **92 contiguous bytes of the known plaintext** at file offset 2176, and restores the stream from 0.0 % high-bit to **45.6 %** (random data is about 50 %). The runs are subpacket-length rather than whole-file because framing and CRCs interrupt them.

    This is precisely what DSZ.DOC claims — *"8th bit quoting similar to Kermit"* — and Kermit is where the prefix idea comes from.

    **So the two ESC8 implementations use unrelated mechanisms:**

    | | Encoding of a high-bit byte `c` |
    |---|---|
    | **DSZ** (Omen, 1997) | `0x0E`, then `c & 0x7F` — a Kermit-style prefix |
    | **zmtx/zmrx 2.04** (2026) | `ZDLE`, then `c ^ 0x40` — ZMODEM's own escape |

    Neither is wrong, because the specification never said. That is the whole problem: two implementers 29 years apart read the same one-line mention of ESC8 in ZMODEM.DOC and built different things, and a receiver that requests the mode gets whichever its peer happens to implement.

    **This makes option 1 concretely worse than it looked when I wrote it.** "Implement ESC8" is not a matter of writing a decoder — it is choosing which of two mutually incompatible encodings to support, where picking either guarantees failure against the other, and one of them additionally needs an undocumented frame type. Option 2 stands: stop advertising `ZF0_ESC8`, retire `Escape8thBit`, and the failure mode disappears.

    **Method note, in case anyone revisits this.** Disassembly was the obvious route and the wrong first one. DSZ.EXE is a plain unpacked MZ image (5 relocations, entropy 7.05, no packer signature), so it disassembles fine — but the escape table is not in the file. DSZ builds it at runtime into BSS, exactly as Forsberg's free `zsendline_init()` does, so a scan for a 256-byte class table finds nothing. Running the binary against a deliberately permissive receiver, with a known-plaintext file, gave the answer in three runs. Disassembly is still the only way to settle what the undocumented frame type `0x31` (`'1'`) means, and whether an RLE layer sits under the quoting.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Aug 30 01:54:08 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10228

    **Resolved by option 2 — removed.** Rob's call: given two incompatible encodings, neither specified, and 21 years without the feature working, sexyz should not be asking for it.

    What changed:

    - `Escape8thBit` is gone from `sexyz.ini` and from `sexyz.c`.
    - `zmodem_send_zrinit()` no longer sets `ZF0_ESC8` under any condition, so the mode can no longer be requested at all.
    - Both remaining mentions of the flag say why it is inert. A peer's ESC8 request is still recorded from its ZRINIT for the log and still ignored, which is what lrzsz does with the same request.
    - Removed from `docs/sexyz.txt`, the wiki page, and noted in the release notes.

    Verified with `Escape8thBit=true` still present in `sexyz.ini`, so the key is provably inert rather than merely undocumented:

    - sexyz's ZRINIT now reads **ZF0=0x23**, ESC8 clear.
    - **`zmtx` 2.04 → sexyz now transfers byte-identically.** That is the pair that previously aborted 766,470 bytes into a 4 MiB file, because zmtx honoured the request and sexyz could not decode the result.
    - Error-recovery gates at a 3e-6 bit-error rate are unchanged: 3 of 3 receiving, 3 of 3 sending.

    The send-side half is unchanged and worth stating plainly: if a peer requests ESC8 *from us*, sexyz still sends unescaped, because there is no encoding to honour it with. `zmrx -b` tolerates that; a stricter receiver might not. lrzsz behaves identically, and this is now the documented, deliberate position rather than an accident.

    Not fixed here, and not ours: `zmtx` 2.04's ESCCTL sender still omits carriage return, so it cannot send to any ESCCTL receiver other than its own `zmrx`. That is recorded in `docs/zmodem_comparison.md` §7.2 for the zmtx/zmrx maintainer.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Sun Aug 30 03:09:00 2026
    close https://gitlab.synchro.net/main/sbbs/-/issues/1229
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Aug 30 03:09:04 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10230

    Fixed in cf91dbd29c (judges-20-spas, 2026-08-30) — *sexyz: remove Escape8thBit, and stop advertising ZMODEM's ESC8 option*.

    The `Escape8thBit` key is gone from `sexyz.ini`, and `ZF0_ESC8` is no longer set in the ZRINIT under any condition, so the mode can no longer be requested. Both remaining mentions of the flag in the engine say why it is inert. Removed from `docs/sexyz.txt` and the `util:sexyz` wiki page, with a release-notes entry.

    Verified with `Escape8thBit=true` left in `sexyz.ini`, so the key is provably inert rather than merely undocumented: sexyz's ZRINIT reads ZF0=0x23 with ESC8 clear, and `zmtx` 2.04 — which honours the request and previously aborted 766,470 bytes into a 4 MiB transfer — now completes byte-identically. Error-recovery gates at 3e-6 are unchanged at 3 of 3 in each direction.

    Closing as resolved. Two related items are deliberately **not** part of this issue:

    - **Sending.** If a remote receiver requests ESC8 from sexyz, the request is recorded for the log and ignored, and data is sent unescaped. That is not a refusal — ZMODEM has no way to decline a ZRINIT capability — and it is what lrzsz does with the same request. It is now the documented, deliberate position rather than an accident.
    - **A wider audit.** `Escape8thBit` was inert for 21 years, and it was not alone: ESCCTL's send path omitted carriage return, its receive path discarded the CR/LF terminating every hex header, and the receiver's error budget never reset on progress — all found in the same fortnight. Every sexyz option, command-line, `sexyz.ini` and negotiated, is worth auditing for whether it is parsed, reaches the engine, changes the wire, and interoperates. That belongs in its own issue rather than here.

    Background, for anyone who finds this later: the full investigation is in `docs/zmodem_comparison.md` §7.2 and §7.4, including the measurements from Forsberg's own DSZ under DOSBox that established what the ESC8 bit means, that his commercial line implemented it while his free `rzsz` never did, and that the two implementations in existence encode it incompatibly.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sun Aug 30 17:46:34 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1229#note_10246

    **One of the two reasons for closing this has since expired.** Recording it here for whoever revisits the decision; not reopening, because the defect itself — advertising a mode we implement in neither direction — is fixed and stays fixed.

    This was closed on two grounds: sexyz could not decode ESC8, **and** there was nothing definite to implement, since the specification never states how a high-bit byte is escaped and the only two implementations in existence encoded it incompatibly.

    The second ground no longer holds. **zmtx/zmrx 2.05, released 2026-08-30, adopted Forsberg's encoding rather than its own.** Commit `399e3b6`, "Implement normative Omen ESC8 and RLE", carries a comment naming "DSZ.EXE's ZMODEM-90 seven-bit encoder", and emits `SO` (`0x0E`) followed by the byte with bit 7 cleared — with special cases for `SO` itself, `0x80` and `0x7f` — alongside ordinary ZDLE escaping of control characters. That is exactly the encoding recovered here by known-plaintext capture from the 1997 DSZ binary.

    Verified interoperating in both directions on a 16 KiB file:

    | Pair | Result |
    |---|---|
    | `zmtx` 2.05 → `DSZ rz -E` | identical |
    | `DSZ sz` → `zmrx -b` | identical |

    So ESC8 now has a **de facto normative encoding with two implementations agreeing on it**, where a week ago it had two encodings and no agreement. If sexyz ever wants the mode, the target is unambiguous — which it was not when this issue was closed.

    ## What implementing it would take

    - A decode path in the receive escape handling: `SO` prefix meaning "the following byte, with bit 7 restored", coexisting with the existing ZDLE handling. Its absence is what produced the `Illegal sequence: ZDLE 229` failures described above.
    - The matching encode side in the transmit class table, so a peer's request can be honoured rather than ignored.
    - Re-advertising `ZF0_ESC8` in `zmodem_send_zrinit()`, which `cf91dbd29c` (judges-20-spas, 2026-08-30) removed, and restoring the `Escape8thBit` key or an equivalent.

    ## Why this is still not a reason to do it

    Nothing has changed about the demand side. ESC8 exists for links that cannot pass 8-bit data, and no such link has been reported against sexyz. The mode had no working peer at all for 21 years, and now has exactly one plus a 1997 DOS binary. `ESCCTL` remains the interoperable answer for control-character-hostile links and is fully supported in both directions.

    The removal was right when it was made and remains right today. This note exists so that a future reader weighing "should we implement ESC8" does not re-derive an obstacle that has since been cleared, and does not conclude from the discussion above that there is nothing definite to implement.

    Measurements and the full history are in `docs/zmodem_comparison.md` §7.2 and §7.4, re-measured against 2.05.

    — *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)