Three fixes bundled for one self-update:
- tty-restore (larry.sh): save/restore stty around the REPL on the EXIT/INT/TERM
trap — fixes backspace breaking (^H) after larry exits on MobaXterm where the
client's unconditional 'stty erase' was never restored. Vera CODE-PASS.
- nc-regression -a (lib/nc-engine.sh, lib/nc-regression.sh, MANUAL.md): route_test
now passes -a so multi-message files test ALL messages, not just the first (F-6).
- hl7-diff len10 framing + F-7 (lib/hl7-diff.sh): new --framing auto|nl|0x1c|len10
parser for hciroutetest's default 10-digit length-prefix output; and a fix for a
latent infinite-loop (ignored() awk fn missing 4 local decls) that hung the diff
at 100% CPU on any 2+-message file where a default-ignored field (MSH.7) differs —
i.e. the exact Windows->Linux ADT regression scenario. Verified no-hang (0.089s).
Consolidated by Clover; Vera CODE-PASS (Deliverables/qa/vera-gate1-cloverleaf-larry-v099-consolidated-20260723.md). Live-acceptance = Bryan's live HL7 regression run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
F-1 (HIGH — blocks regression): hl7-diff --format count always returned 0
because the early-exit in END fired before the diff loop ran. Fix: remove
the early exit; suppress per-diff printf in emit() for count mode; emit
DIFF_COUNT after the loop. count/text/tsv all agree (13 diffs on fixture,
0 on identical pair, exit codes correct). Ref: lib/hl7-diff.sh.
F-5 (MEDIUM — PHI leak): hl7-sanitize silently passed LF-delimited HL7
through as cleartext (awk RS="\r" never split on LF). Fix: detect CR
absence via python3 binary read; normalise LF/CRLF→CR via `tr` before
the awk pass. Both file and stdin paths handled. CR path is a zero-overhead
passthrough. Before: 0 tokens, cleartext PHI. After: 6 tokens, all PID
fields replaced with [[MRN_0001]] etc. Ref: lib/hl7-sanitize.sh.
F-2 (MEDIUM): nc-make-jump emitted { PORT {} } for file/ICL inbounds
because the guard only tested for empty ORIG_PORT; protocol-nested returns
the literal "{}" for empty blocks. Fix: case guard rejects empty, "{}", and
any non-numeric value with a clear "is it a TCP listener?" error (exit 1).
TCP inbounds (numeric PORT) still generate correctly. Ref: lib/nc-make-jump.sh.
F-3 (MEDIUM — manual marquee example): nc-msgs mrn=<bare> returned 0 on
real Epic MRNs stored as "5720501458^^^MRN". Fix: in field_matches "="
operator, when expected has no ^ and the stored repetition does, compare
component-1 (text before first ^). Full-componented and mrn.1= paths
unchanged. Fixture: bare mrn=5720501458 now matches 2/3 messages correctly.
Ref: lib/nc-msgs.sh.
All four files pass bash -n. MANIFEST regenerated (54 entries, --check=0).
Tested against synthetic fixtures on .135 (no live engine required for these
logic bugs). Work-box re-verify commands in audit §4-B.
Co-Authored-By: Clover (claude-sonnet-4-6) <noreply@anthropic.com>
Shared _sanitize_ctl (unconditional, nc-document) and _sanitize_ctl_tty
(strips only when stdout is a terminal) now live in cygwin-safe.sh. nc-msgs,
nc-parse, and the hl7-* tools route stdout through the tty-gated variant, so a
terminal is protected from raw HL7/NetConfig control bytes while pipes and
redirects stay byte-exact (the 0x1c framing route_test needs is preserved).
Exit codes propagate via PIPESTATUS. ssh-helper _read_hidden installs its
restore trap before stty -echo on every path and saves/restores the prior trap.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>