Record incident WA-2026-10-27 in docs/whatsapp.md section 13: the symptom (a
std::length_error core dump during --whatsapp-link after the QR refreshed), the
root cause (an overflowable `pos + len > size` bounds check plus an unguarded
dispatch loop), the fix (commit f16c5c6), and the standing rule for all code
that parses untrusted bytes: overflow-safe bounds checks, no unchecked
allocation from an attacker-controlled count, and no exception escaping a
top-level loop. The goal is C++ that a hostile peer can never crash.
Prevention is enforced, not just written: tests/whatsapp_test.cpp gains a
test_hostile section that feeds the parsers the exact shapes that crashed (a
4GB length field, an oversized protobuf varint, truncated frames, 2000 random
inputs) and fails if std::length_error is ever thrown again. Runs under
build/whatsapp_test / whatsapp.unit / make test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A protobuf/binary length field could be read as a huge value, and the
`pos + len > size` bounds check overflowed size_t and slipped past, so
vector::assign threw std::length_error. Node dispatch (pairing, etc.) was
not wrapped in a catch, so this aborted the whole process (core dump) during
--whatsapp-link after the QR refreshed.
- ProtoReader::next and the binary Decoder now use overflow-safe length
checks (len > remaining) and the decoder reads 4-byte lengths unsigned and
rejects anything larger than the frame; read_bytes rejects negatives.
- WaClient::dispatch wraps all node routing in try/catch: a bad node is
logged and skipped instead of crashing the client.
Verified: build/whatsapp_test 16/16, make lint clean, and a live
--whatsapp-link run survives the QR-refresh window with no abort.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Native WhatsApp Web multi-device client in C++ (src/whatsapp/, namespace
detz::wa), built on OpenSSL plus a vendored public-domain ed25519 ref10
(third_party/ed25519, zlib) for XEdDSA and the nayuki QR generator
(third_party/qrcodegen, MIT); no new runtime dependency.
- WaCrypto, WaBinary, WaProto, WaNoise, WaSignal, WaDevice, WaSocket,
WaClient, WaStore, WaQr, WaWizard.
- Verified offline against golden vectors captured from the real Baileys
client (tests/whatsapp_data, from jfelipesjc/wa-go, MIT): HKDF/PBKDF2 RFC
vectors, XEdDSA roundtrips, codec battery 19/19, ClientPayload byte-exact,
the Noise handshake, and a 4-exchange Signal session byte-exact. Unit test
build/whatsapp_test (16/16), run_all step whatsapp.unit.
- Verified live against web.whatsapp.com: `detz --whatsapp-link` connects,
completes the Noise handshake, receives pair-device, renders a scannable QR
in the terminal, and persists the device to the vault (whatsapp/<profile>.db).
Also --whatsapp-status / --whatsapp-unlink.
- Agent tools whatsapp_send and whatsapp_contacts (detz-only, in DetzTools).
- Pairing completion after the phone scans, and the message send path
(usync + prekey fetch + Signal encrypt + send node), are ported faithfully
from whatsmeow but unverified in-tree (no linked account in development).
send_image and own-device fan-out are not wired yet. See docs/whatsapp.md.
Also in this snapshot: the terminal-screenshot tool (src/termshot/,
terminal_screenshot, docs/termshot.md, research/terminal-screenshot-rendering)
and a concurrent session's in-progress llm/muse failover changes carried along
in the shared files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
No native Python WhatsApp library exists (neonize is whatsmeow over
ctypes, yowsup is dead) and no browser is needed. Spec for detz::wa:
native C++ transpiled from wa-go (MIT, golden vectors) with whatsmeow as
referee, libcurl WebSocket plus OpenSSL, no new dependencies, build vs
deep-research table, caps, tests, phases, and a whatsapp-mcp shortcut.
Research archive: research/whatsapp-automation (70 sources, 3
conclusions). Nothing built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Feed panes in the multiplexer (vpane_* control commands, main-vertical layout, header row),
src/orch (board, panel, formatter, transport, CAP adapter), Agent observer and cancel flag,
supervision (idle warn/cancel, user close cancels, soft then hard stop), CAP answers collected
through the spill path. Research archived under background-work-limits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
make test builds and runs 32 steps; not green: misc.diff and mplex.e2e fail on real module bugs.
test_main.cpp replaced by util_config_test.cpp; stale *.mk and store_test rule removed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the grr client of tai.py: client, SSE stream, session, store, router, shell, views,
chat, panes, file viewer and the unix control socket; GrrTui::run is the --tui entry.
Verified against tai.py --tui on a real grr server over a pty: 236 steps, screen text and
per-cell styles identical except clocks, spinner frames and server-made ids.
docs/tui.md holds the symbol table and gaps, docs/wiring/tui.md the integrator hooks.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Full port of the Store (17 tables, FTS5, per-profile slices, sessions, turn state,
bots, settings, MCP registry), DebugLog, SETTINGS_CATALOG and boot_settings,
ShellSession (as ShellContext), Conversation persistence, Repl/Boot, and the
PlexerController family with FlowValidator/PlexerFlow. Verified by replaying 643
operations through tai.py and the C++ code (results, tables, FTS, schema, files
identical) and by restarting the REPL under per-pane shells and checking the vault.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>