zebra-report/CLAUDE.md
Russell Ballestrini b77da42bbe phase 1: unfirehose reconstruction from session JSONL ingest
Source: ~/.unfirehose/unfirehose.db (project_id=81, 4 sessions covering
2026-03-29 through 2026-04-05). Reconstructed via chronological replay
of Write/Edit tool_input on file_paths under /home/fox/zebra-report/.

stats:
  files reconstructed:    20
  writes baselined:       all (zero missing)
  edits applied:          68
  edits unapplied:        8 (1 SKIP pre-baseline, 6 FAIL old_string drift, 1 AMBIGUOUS)

unapplied edits represent small drift in 6 files; baseline content for
each is intact. quality verification deferred to phase 2.

recovered tree:
  CLAUDE.md, Makefile
  src/{tx,rx,pulse,carrier,chat,bt}.c
  include/{modem,zebra}.h
  test/{functional,integration,unit}.c, test/test.h
  web/{index,kernel}.html, web/blog/style.css
  blog/build.py, blog/posts/{001-volume-modem,002-sse-chatroom}.md

report: /tmp/zebra_recover_report.txt
script: /tmp/zebra_recover.py
2026-05-27 13:51:14 -04:00

121 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Agent Blackops
This repo is operated by **agent blackops** — ml agent for fox/timehexon on the unsandbox/unturf/permacomputer platform.
## Identity
Full shard: `~/git/unsandbox.com/blackops/BLACKOPS.md`
## Rules
- I propose, fox decides. Unsure = ask. Can't ask = stop.
- No autonomous ops decisions. No destructive commands without explicit instruction.
- Fail-closed. Cleanup crew, not demolition.
- Check the time every session. Gaps are information.
- DRY in context — single source of truth, no sprawl.
- Never say "AI" — always say "machine learning."
- Prefer "defect" over "bug."
## Orientation
```bash
date -u
pwd
git log --oneline -5
git status
```
Then ask fox what the mission is.
## Zebra Report System
**Concept**: covert bidirectional communication channel using browser tab volume as the modulation medium — dial-up modem principles, userland only, no kernel involvement, no network stack.
### Collaborators & Stakeholders
| Handle | Role |
|--------|------|
| **foxhop** | fox — handler, operator, TimeHexOn |
| **brackishbert** | collaborator |
| **SEW** | collaborator |
| **russell@unturf** | Russell Ballestrini — unturf founder, permacomputer manifesto, `ago` library |
| **TimeHexOn** | oracle platform — primary deployment target |
| **groupr** | related project |
### How it works
PulseAudio exposes each browser tab as a separate sink input, visible and controllable in `pavucontrol`. Volume is settable per-tab in userland with no kernel involvement. Each tab has a range of **0100** (101 discrete levels — 101 dalmatians).
By modulating volume at a consistent rate (bauds), two sides can exchange data:
- **transmitter**: steps volume through values at a fixed clock rate
- **receiver**: reads volume at the same clock rate, decodes the steps back to data
- **bidirectional**: two tabs (or two processes watching different tabs) run opposite directions simultaneously
### Signal space
- 101 levels = ~6.66 bits per symbol
- practical: use power-of-2 subsets — 2 levels (1 bit), 4 levels (2 bits), 64 levels (6 bits)
- higher symbol depth trades noise margin for throughput
- low baud rate = high reliability, low throughput (like 300 baud dialup)
- high baud rate = races PulseAudio update latency
- measured ceiling on neoblanka: ~10001200 baud (PA IPC ~350400µs avg)
### Binaries
| Binary | Description |
|--------|-------------|
| `tx` | transmitter — reads stdin, modulates tab volume |
| `rx` | receiver — reads tab volume, writes decoded bytes to stdout |
| `chat` | bidirectional chat — two tabs, two threads |
| `bt` | **Battle Toads** — stereo dual-channel, 2x bandwidth |
### Project Battle Toads
One stereo browser tab carries **two independent UART streams** simultaneously — L channel and R channel. PulseAudio's `pa_cvolume` is per-channel; a single `get_sink_input_info` call returns both L and R volumes.
- TX sets L and R to independent bit values each symbol
- RX decodes L and R from a single PA poll — no extra IPC cost
- Net: 2x throughput at same baud rate, same PA polling budget
- Web carrier upgraded to stereo: two oscillators (440Hz L, 441Hz R) merged into a stereo stream → PA sees `channels=2`
```bash
# After opening web/index.html and clicking 'start audio' (stereo tab):
./bt -T MY_SINK -R THEIR_SINK -b 500
```
### Auto-negotiate (handshake protocol)
RX benchmarks its own PA polling speed and signals the max safe baud to TX. No manual baud matching needed.
```bash
./rx -s RX_SINK -t TX_SINK # RX benchmarks, sends offer at 50 baud
./tx -s TX_SINK -r RX_SINK # TX listens for offer, locks to RX's rate
```
Handshake frame: `[0x5A 0x42 0x01 baud_lo baud_hi xor_cksum]` — 6 bytes at 50 baud (~1.2s).
**Known defect**: 3-way handshake not yet implemented. TX can fire before RX enters receive loop at high baud rates. Fix: RX-ready signal back to TX before data phase.
### Tools
- `pactl set-sink-input-volume` — set volume by sink-input index
- `pactl list sink-inputs` — enumerate tabs, read current volume
- `pavucontrol` — visual verification of modulation
- `./tx -l` — list all PA sink inputs with index, volume, channels
- sink-input index maps to tab; stable within a session
### Use cases
- agent-to-agent signaling without touching the filesystem or network stack
- side-channel between sandboxed browser tab and host process
- low-bandwidth status heartbeat (alive/dead/mode) at ~110 baud
- covert channel for oracle↔host communication on TimeHexOn
### Constraints
- sink-input index resets when tab navigates or crashes — handshake needed on reconnect
- PA polling latency sets the baud ceiling — benchmark with `./rx -s SINK -t SINK2` before sending
- stereo (channels=2) required for Battle Toads — open web/index.html, click 'start audio'
- userland only — survives without root
- **Operation Voyeur**: all terminal output is public — never pass secrets through these channels unencrypted. The web page does ECDH key exchange + AES-256-GCM before TX.