Commit Graph

4 Commits

Author SHA1 Message Date
Indiana
58c30b7273 feat: possession presentation layer — glitchy text + degraded audio
First sub-project of the "make contact feel real" arc (spec:
docs/superpowers/specs/2026-07-23-possession-presentation-design.md).
Direct Contact replies now feel like a spirit fighting through static to
hold the channel rather than a plain chat bubble:

- backend/app/possession.py: compute_stability(rarity, magnitude, rng) —
  a 0.05-0.98 score per reply (rarer entity + stronger triggering anomaly =
  cleaner signal), rng injectable for a later quantum-RNG source.
- ws.py sends stability on reply_start; audio synthesis for that reply gets
  noise/bitcrush scaled by instability (1 - stability) via a new
  instability param on synthesize_spirit_voice — effects.py itself is
  untouched, only the params fed into it.
- frontend/src/lib/possession.ts: renderPossessedText — pure, deterministic
  (tick-seeded, no Math.random) text corruption with self-correcting
  glitch bursts, wired into Transcript.tsx's streaming reply display.

Stored transcript/reply text is unaffected — this is presentation only.
78/78 backend, 137/137 frontend tests passing.
2026-07-23 05:48:02 +00:00
Indiana
6399039589 fix: resolve real visitor IP via CF-Connecting-IP for per-IP limiting
websocket.client.host is always the Cloudflare Tunnel machine's LAN IP for
every internet-facing connection (the tunnel runs on a separate machine and
terminates TLS there), which collapsed per-IP rate limiting into a single
shared bucket for all remote visitors — the exact gap flagged in review.

Cloudflare's edge sets CF-Connecting-IP itself, overwriting any
client-supplied value, so it's safe to trust when present. Falls back to
the raw socket peer for direct LAN/local access.
2026-07-22 23:59:35 +00:00
Indiana
83575f9bb3 feat: add per-IP rate limiting to WS LLM triggers
Per-account limits alone don't stop one account script-hitting
Ollama from many source IPs. Adds matching per-IP limiters
alongside the existing per-account ones for fragment/question/
summon triggers, per spec's dual per-account-and-per-IP requirement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
2026-07-21 03:45:58 +00:00
Indiana
b9110f45de feat: spirit engine — seance WS, entity minting/Codex, Piper TTS voices, wire telemetry
- WS /ws/session: modes, summon, anomaly fragments, streaming direct contact,
  passive wire-ghost ambient loop, per-user rate limits, event transcript
- entities: anomaly-signature fingerprinting, LLM minting + procedural
  fallback, Codex matching with contact counts and sightings
- tts: 8 local Piper voices (EN/ES), per-entity voice profiles, numpy
  effects chain (pitch/rate/bitcrush/echo/static)
- llm: streaming client, submit_stream in bounded queue, SpiritService
  with offline fallbacks for every channel
- routes: public /api/codex, /api/codex/{id}, /api/stats; /audio static mount
- models: Entity, EntitySighting, Event, ContactSession(entity_id, language)
2026-07-20 20:13:28 +00:00