20 Commits

Author SHA1 Message Date
jaxperro 7e579aca98 sync_tape: batch acks into one ssh call + make ack failures non-fatal
Per-file 'flyctl ssh console' acks ride WireGuard; travel networks throttle
it past the 120s timeout, and the raised TimeoutExpired killed whole
backlog runs mid-flight (52/64 files, twice). The delete invariant is
one-directional — the box may delete ONLY what the Mac acked — so a
MISSING ack is always safe. Batch at end, best-effort, log and continue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 11:00:52 -04:00
jaxperro 678d7de948 sync_tape: never bless a timed-out sftp partial — fall through to the base64 fallback
A TimeoutExpired get leaves a size>0 partial that the exists-check treated
as success, so the console fallback never ran for timeouts; the caller's
parquet read then failed (no magic bytes), deleted the file, and the next
run repeated the identical loop — 8 hours of tape-head stall overnight
2026-07-23. Partials from timeouts are now removed and the fallback runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 09:35:26 -04:00
jaxperro 790ef42c40 docs: the 2026-07-22 lessons — resolution-timing survivorship (round 3)
FINDINGS: full round-3 section (mechanism, the 81%-vs-26% audit, how the
paper harness caught it, corrected verdicts, three standing rules) +
scorecard updates (surge dead, sub5c dead 0/38, oracle revived at E>=0.07)
+ correction banner on the 07-20 tape-era section. HANDOFF: queue +
snapshot reflect the kill, surgebot's instrument role, scorer law, Friday's
combined agenda. research/README: SCORER LAW + independent-instrument rule
+ full current layout. recorder/README: sync transport fallback. README:
/surge dashboard + research row truth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 17:39:47 -04:00
jaxperro 3b4475b0e2 sync_tape: base64-over-console fallback + sane sftp timeout
flyctl sftp flaked again (900s timeouts, magic-byte-less partial parquets)
and 14h of tape queued behind it — the research nightly waits on tape
freshness by design, so everything downstream stalled too. Port ingest.py's
proven console fallback: sftp gets 240s, then base64 over ssh console
(600s); the manifest row-count verify remains the integrity gate and
partials are cleaned on both paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 11:52:05 -04:00
jaxperro 8edccda58a docs: stage-0 coherence pass across README/HANDOFF/recorder/research
- README: recorder row + architecture diagram reflect fold->parquet->
  15-min mirror (and research/ joins the diagram); cheat-sheet gains a
  'sync the tape now' row
- HANDOFF: snapshot dated 2026-07-21, launchd roster (tape-sync +
  research-nightly wait behavior), #15 back in the open queue, tape ops
  line in quick-reference
- recorder/README: ops block (sync_tape + fold health, deploy gap note),
  storage economics (/mo, mirror as Stage-1 feedstock)
- research/README: nightly.sh wait-for-fresh-tape semantics
- live/tape_sharps.json: refreshed 4-day chain-validated screen (the
  smoke run had briefly left a chain-less version)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 13:07:31 -04:00
jaxperro 5c8ee5961b stage-0 warehouse: recorder folds its own tape to parquet; Mac mirrors every 15 min
The nightly Mac-coupled bulk ingest was the fragile link (today: Mac slept
through 08:00, the pipeline started 09:31, and the sftp bulk pull wedged in
timeout cascades holding the db lock — digest blocked behind it). Stage 0
moves the fold onto the box and reduces the Mac to an incremental mirror:

- recorder/fold.py (sidecar, capture stays PID 1): closed gz segments ->
  zstd parquet /data/parquet/<fam>/date=*/segment.parquet, row-parity
  verified, manifest-logged, THEN gz deleted. Deletion invariant STRONGER:
  raw needs a verified parquet; parquet needs a Mac ACK before the disk
  guard may prune it. duckdb capped 384MB; VM 256MB -> 1GB.
- recorder/sync_tape.py (com.jaxperro.tape-sync every 15 min + daily.sh):
  manifest-driven incremental sftp pull, per-file row verify, append into
  rtds.duckdb NATIVE tables (views-over-parquet rejected: sim's per-asset
  point queries would crawl), segment-keyed idempotence shared with the
  legacy ingest.py (kept as fallback), ack back to the box.
- recorder/bootstrap_parquet.py: pre-fold history exported to the mirror,
  parity OK (13.84M trades + 3.07M aux). live/parquet/ is now the complete
  durable layer Stage 1 (MotherDuck/ClickHouse) would consume.
- research/tape.py connect(): brief retry — the 15-min sync holds the
  write lock for seconds.

First run: backlog folded in <60s on the box, 36/36 files mirrored+
verified, rtds.duckdb 13.8M -> 18.2M trades, tape age 24h+ -> ~15-45 min.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 12:46:54 -04:00
jaxperro 6f6bd81cb1 fix tape ingest data loss + daily digest send
ingest: sftp needs stdin=DEVNULL under launchd (no tty) — without it, empty/partial files decoded to 0 lines and the missing integrity guard MARKED+DELETED them (36 segments lost). Guard: a >200B gz that yields 0 lines is a failed fetch, left on box to retry.
digest: retry+backoff moved INTO _post so the digest send (not just the start ping) survives the post-wake DNS gap; ingest ping gets the same.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 13:19:59 -04:00
jaxperro 7086569024 ingest: sftp timeout 900s, fallback timeout contained, both-transports-failed skips instead of crashing the backlog (#11 hardening)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 17:12:45 -04:00
jaxperro ab56b2aa4b reconcile_entries cadence 5m→30m (closes #12); tape transport sftp-first with base64 fallback (closes #11)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 16:46:28 -04:00
jaxperro 2744b67587 chain-balance gates in reconcile_exits + retry queue — ghosts dropped, sells clamped to chain (closes #7); tape ingest pings the daily channel at start + finish
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 16:34:52 -04:00
jaxperro ea69aec127 docs: recorder README (full-firehose design, preservation policy, ops) + README/HANDOFF sync
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 16:07:39 -04:00
jaxperro b8c0734c5a recorder: never delete un-ingested tape — warn from 80%, single-oldest drop only at 95% as loud last resort (user directive); volume 10→25GB
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 16:00:20 -04:00
jaxperro 77b2457523 recorder: FULL firehose — activity/* (trades + orders_matched), comments, crypto_prices; aux segment family + ingest branch (probed: rfq/prices dead)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 15:55:10 -04:00
jaxperro 5e375f6d88 recorder: dual-socket capture + cross-socket dedupe + 15s stale guard — single socket measured 92.9% minute coverage; the twin covers per-connection silences
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 15:37:52 -04:00
jaxperro baa4182343 audit hardening: book fully serialized, chain-gated sweep, boot-id single-writer guard, TLS on user-ws, atomic valuebot state, hot-path throttle, newest-kept seen_tx, daily lock, ingest txn, AIcAIc pin
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 14:07:43 -04:00
jaxperro 006d79ac18 ingest: 900s per-segment timeout — busy-hour tape outgrew 300s over ssh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 13:43:06 -04:00
jaxperro 38c2d51366 ingest: resolve flyctl absolutely — launchd's minimal PATH broke the first nightly run
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:18:56 -04:00
jaxperro 315990cd90 recorder: reset freshness clock on reconnect (insta-close loop bug) + 45s stale guard — cuts per-flap tape loss
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 09:06:45 -04:00
jaxperro ddf1e97a54 recorder: nightly tape ingest into live/rtds.duckdb (own DB — never contends with the bet cache lock)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 13:02:41 -04:00
jaxperro 3a3e366de5 recorder: RTDS tape silo — hour-rotated gzip segments on a Fly volume
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 12:53:54 -04:00