- handle_pps(): flag the first post-PPS character; _read_byte_clk() re-measures
the CLK period there and accounts the measurement's 16 edges. The Alcor
reader upclocks 4.0 -> 4.8 MHz at PPS (FI/DI still 512/32), so the ATR
measurement was stale: 64 vs 53.33 samples/ETU, no post-PPS APDU framed.
- _wait_clk_rising(): project to the n-th edge (skip to target - half a
period, take one edge) instead of "skip n-2 cycles + 2 edges", which lost
~1 edge per call on fractional periods and slid the samples ~0.5 ETU early
by the parity bit. xiaomi 7698 -> 2, 4gmodem 7218 -> 0, S21p_sim2 394 -> 0
CHKSUM lines (previously misread as dirty-wire noise).
- CONCAT gate: EMBEDDED_CLA excludes the structural 0x4x/0x5x classes (payload
false hit on the Alcor secured packet); mirrored in tools/vs_reader.py and
covered by a new vector in tests/test_gsmtap.py.
- tools/capture_baseline.sh: add the alcor_reader_sample fixture; baseline
regenerated (APDU counts and RESULT: OK unchanged everywhere, 0 CONCAT).
- 75/75 unit tests. README/AGENTS updated.
Residual CONCAT mis-frames (4gmodem/A55_sim2/S21p_sim2) traced to a silent
5-byte drop at an invalid-INS T=0 header (0x0f 00 a4 08 04). Drop only the
stray leading byte and re-frame the remaining four via _replay so the real
command (00 a4 08 04 02 2f 00 -> 61 1c) is recovered.
- _note_discard()/_consume_first(): every consumed-but-unemitted byte is
now logged; idle 0x00/0xFF discards are rate-limited, real data always
gets an ANN_WARN annotation.
- All read-until-SW loops log skipped non-SW bytes.
- All traces: CONCAT 0; BAD_FCS/GARBAGE 0; test_8/test_7 RESULT OK;
47/47 unit tests; baseline byte-identical.
History rewritten to a single root commit so no example trace is stored
in the repo (fixtures are local-only, gitignored). README keeps only
generic <trace>.sr placeholders; AGENTS.md retains the fixture names.