Research-Stack/4-Infrastructure/shim/waveprobe_rgflow_teleport.py
Brandon Schneider ac4e23dc9b Expand devcontainer with full Python stack, add MCP servers (Notion/AWS), strengthen Lean theorems
- .devcontainer/Dockerfile: add PostgreSQL client libs, OpenSSL/libffi headers, gfortran/BLAS for scipy, rclone; install full Python dependency set (boto3, psycopg2-binary, fastapi, uvicorn, notion-client, httpx, pytest, numpy, scipy, etc.) in uv-managed venv; add rclone S3 gateway init script as ENTRYPOINT
- .devcontainer/devcontainer.json: switch from build to pre-built image (localhost/research
2026-05-19 01:52:14 -05:00

263 lines
9.4 KiB
Python
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.

#!/usr/bin/env python3
# PTOS: LAYER=STORE / DOMAIN=COMPUTE / CONDITION=EXPERIMENTAL / STAGE=ACTIVE / SOURCE=CODE
"""
waveprobe_rgflow_teleport.py — Waveform teleport shim.
Reads a WAV file (or a raw PCM array), calls the Lean WaveformTeleport
module via subprocess, and emits a JSON TeleportReceipt.
Shim boundary (per AGENTS.md §7.1):
ALLOWED: WAV parsing, SHA-256 hashing, JSON serialisation, subprocess spawn
FORBIDDEN: RG decimation logic, beta-residual computation, sigma_q arithmetic
— all of that lives in WaveformTeleport.lean.
Usage:
python3 4-Infrastructure/shim/waveprobe_rgflow_teleport.py \
--wav 2-Search-Space/simulations/matter-frequencies/wav-files/caffeine_fade_96k.wav \
--out /tmp/caffeine_teleport_receipt.json
python3 4-Infrastructure/shim/waveprobe_rgflow_teleport.py \
--wav <path> --max-depth 32 --out <receipt.json>
Environment:
LEAN_BIN path to SemanticsCli binary
default: 0-Core-Formalism/lean/Semantics/.lake/build/bin/SemanticsCli
"""
from __future__ import annotations
import argparse
import hashlib
import json
import struct
import sys
import wave
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
# ── repo root ────────────────────────────────────────────────────────────────
REPO_ROOT = Path(__file__).resolve().parents[2]
LEAN_BIN_DEFAULT = (
REPO_ROOT
/ "0-Core-Formalism/lean/Semantics/.lake/build/bin/SemanticsCli"
)
CLAIM_BOUNDARY = "waveform-teleport-rg-attractor-only"
# ── WAV helpers (shim-only: read bytes, hash bytes) ──────────────────────────
def _sha256_hex(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def _sha256_words(data: bytes) -> list[int]:
"""Return the SHA-256 digest as 8 × uint32 words (big-endian)."""
digest = hashlib.sha256(data).digest()
return list(struct.unpack(">8I", digest))
def _read_wav(path: Path) -> tuple[list[int], int, int]:
"""
Read a WAV file and return (samples_q16_16, sample_rate, n_samples).
Samples are normalised to Q16_16 (UInt32):
PCM int16 → Q16_16 by sign-extending and shifting left 16 bits
PCM float → Q16_16 via f * 65536 (clamped)
Only the first channel is used; stereo is downmixed to mono.
"""
with wave.open(str(path), "rb") as wf:
n_channels = wf.getnchannels()
sample_width = wf.getsampwidth() # bytes per sample
sample_rate = wf.getframerate()
n_frames = wf.getnframes()
raw = wf.readframes(n_frames)
samples_q: list[int] = []
if sample_width == 2: # PCM int16
fmt = f"<{n_frames * n_channels}h"
pcm = struct.unpack(fmt, raw)
for i in range(0, len(pcm), n_channels):
# int16 → Q16_16: treat as signed, shift to 16.16 space
# value in [-32768, 32767] → Q16_16 by (v + 32768) * 2 to [0, 131070]
# Then encode as UInt32: (v << 16) with sign handling
v = pcm[i]
# Encode: Q16_16 one = 0x00010000 = 65536
# map int16 range [-32768..32767] → [0x80000000..0x7FFF0000]
q = (v * 65536) & 0xFFFFFFFF
samples_q.append(q)
elif sample_width == 3: # PCM int24
n_total = n_frames * n_channels
for i in range(0, n_total * 3, n_channels * 3):
# read 3 bytes as little-endian int24
b0, b1, b2 = raw[i], raw[i + 1], raw[i + 2]
v24 = b0 | (b1 << 8) | (b2 << 16)
if v24 & 0x800000:
v24 -= 0x1000000 # sign extend
# scale to int16 range then Q16_16
v16 = v24 >> 8
q = (v16 * 65536) & 0xFFFFFFFF
samples_q.append(q)
else:
raise ValueError(
f"Unsupported sample width {sample_width} bytes in {path.name}. "
"Only 16-bit and 24-bit PCM WAV are supported."
)
return samples_q, sample_rate, len(samples_q)
# ── Lean shim call ────────────────────────────────────────────────────────────
def _call_lean_teleport(
samples_q: list[int],
sha256_words: list[int],
sample_hz_q16: int,
max_depth: int,
lean_bin: Path,
) -> dict[str, Any]:
"""
Marshal the waveform data to JSON, call SemanticsCli with the
waveform-teleport command, and return the parsed receipt dict.
If the Lean binary is not present, return a stub receipt with a clear
software-witness-only marker.
"""
payload = {
"command": "waveform_teleport",
"samples_q16": samples_q,
"sha256_words": sha256_words,
"sample_hz_q16": sample_hz_q16,
"max_depth": max_depth,
}
if not lean_bin.exists():
# Software-witness fallback: no Lean binary available.
# Return a stub so the shim can still emit a receipt.
return {
"lean_witness": False,
"stub": True,
"reason": f"Lean binary not found at {lean_bin}",
"attractor_id": None,
"rg_depth": None,
"sigma_q": None,
"beta_residual": None,
"token_lawful": False,
"roundtrip_ok": False,
}
import subprocess # noqa: PLC0415 — only imported when binary is present
result = subprocess.run(
[str(lean_bin), "waveform-teleport"],
input=json.dumps(payload),
capture_output=True,
text=True,
timeout=120,
)
if result.returncode != 0:
raise RuntimeError(
f"SemanticsCli waveform-teleport failed:\n{result.stderr}"
)
return json.loads(result.stdout)
# ── receipt assembly ──────────────────────────────────────────────────────────
def build_receipt(
wav_path: Path,
max_depth: int = 32,
lean_bin: Path = LEAN_BIN_DEFAULT,
) -> dict[str, Any]:
"""
Main shim entry point.
1. Read WAV → Q16_16 samples + SHA-256
2. Call Lean teleport logic
3. Assemble and return TeleportReceipt JSON
"""
raw_bytes = wav_path.read_bytes()
sha256_hex = _sha256_hex(raw_bytes)
sha256_words = _sha256_words(raw_bytes)
samples_q, sample_rate, n_samples = _read_wav(wav_path)
# sample_rate in Q16_16: Hz * 65536 (fits in UInt32 for rates ≤ 32767 Hz)
sample_hz_q16 = (sample_rate * 65536) & 0xFFFFFFFF
lean_result = _call_lean_teleport(
samples_q = samples_q,
sha256_words = sha256_words,
sample_hz_q16 = sample_hz_q16,
max_depth = max_depth,
lean_bin = lean_bin,
)
receipt: dict[str, Any] = {
"schema": "waveprobe_rgflow_teleport_receipt_v1",
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
"source_path": str(wav_path),
"source_sha256": sha256_hex,
"n_samples": n_samples,
"sample_rate_hz": sample_rate,
"max_depth": max_depth,
"lean_witness": lean_result.get("lean_witness", False),
"attractor_id": lean_result.get("attractor_id"),
"rg_depth": lean_result.get("rg_depth"),
"sigma_q": lean_result.get("sigma_q"),
"beta_residual": lean_result.get("beta_residual"),
"token_lawful": lean_result.get("token_lawful", False),
"roundtrip_ok": lean_result.get("roundtrip_ok", False),
"claim_boundary": CLAIM_BOUNDARY,
}
# receipt_hash: SHA-256 of the stable preimage (excludes generated_at_utc)
preimage = {k: v for k, v in receipt.items() if k != "generated_at_utc"}
receipt["receipt_hash"] = _sha256_hex(
json.dumps(preimage, sort_keys=True).encode()
)
return receipt
# ── CLI ───────────────────────────────────────────────────────────────────────
def main() -> None:
parser = argparse.ArgumentParser(
description="Waveform teleport shim — extract RG attractor, emit receipt."
)
parser.add_argument("--wav", required=True, type=Path,
help="Input WAV file")
parser.add_argument("--out", required=False, type=Path, default=None,
help="Output receipt JSON path (default: stdout)")
parser.add_argument("--max-depth", type=int, default=32,
help="Max RG decimation depth (default: 32)")
parser.add_argument("--lean-bin", type=Path, default=LEAN_BIN_DEFAULT,
help="Path to SemanticsCli binary")
args = parser.parse_args()
if not args.wav.exists():
print(f"[ERROR] WAV not found: {args.wav}", file=sys.stderr)
sys.exit(1)
receipt = build_receipt(
wav_path = args.wav,
max_depth = args.max_depth,
lean_bin = args.lean_bin,
)
out_json = json.dumps(receipt, indent=2)
if args.out:
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(out_json)
print(f"[OK] Receipt written to {args.out}")
else:
print(out_json)
if __name__ == "__main__":
main()