Commit Graph

17 Commits

Author SHA1 Message Date
Indiana
30c0da1eaf Merge Workstream F: unlocks/inventory UI + sigil designer + listening tool 2026-07-24 09:39:19 +00:00
Indiana
98864976b1 Merge Workstream E: ritual mini-game + judgment UI + consequences
Resolved conflict in types.ts: dropped the duplicate EntityTraits
definition (D and E both added it identically) and combined both
workstreams' new ServerFrame variants (tell/ritual_complete from D,
judgment_result from E). 223/223 frontend tests pass, tsc clean.
2026-07-24 09:39:08 +00:00
Indiana
e4a834620f feat: Ghost Log HUD + evil meter + tells (Workstream D)
App-shell HUD (mounted in App.tsx alongside HauntingLayer, visible on
every screen) that shows ambient idle status until a séance is active,
then streams `tell` WS frames as terminal-style log lines with a
"hacker witch" crescent-arc evil-meter gauge (occult sigils/runes fused
with Transcript.tsx's monospace log vocabulary).

- lib/evilMeter.ts: pure function computing a malevolent<->benevolent
  belief from the accumulated tell history — starts wide/uncertain,
  narrows geometrically and shifts per tell (deterministic hash of the
  tell text, since tells never leak ground truth), and snaps to
  definitive certainty on a successful ritual_complete's
  revealed.alignment. Fully unit tested (narrowing, ordering,
  determinism, ritual override, idle/empty history).
- lib/ghostLogBus.ts: tiny typed event bus (mirrors lib/haunting.ts's
  HauntBus) so the app-shell-level GhostLog can react to live séance
  frames — SeanceProvider is only mounted inside the séance route, so a
  shell-level sibling can't read its context directly.
- state/seance.tsx: publish entity/tell/ritual_complete onto the bus,
  and session_end on provider teardown so the HUD falls back to idle
  when the seeker leaves the séance page.
- lib/types.ts: add the `tell` and `ritual_complete` server frames from
  the Character Depth spec's Contract section (only what this
  workstream consumes).
- components/GhostLog.tsx/.css: the HUD itself, plus i18n keys in
  en.json/es.json.

168/168 frontend tests pass (137 pre-existing + 20 evilMeter + 11
GhostLog); tsc -b and the i18n coverage pretest are clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 16:28:33 +00:00
Indiana
ebe6a4b0b8 feat(frontend): unlocks/inventory UI, sigil designer, listening-tool EVP threshold
Workstream F of the character-depth/ghost-log spec.

- InventoryPanel.tsx: essence balance, owned unlocks/items (terminal
  listing + Codex-style rarity-glow borders on items), and a buy flow
  for a small fixed unlock catalog (currently just "listening_tool",
  the only key the contract names) with afford/can't-afford button
  states. Prices are fetched from a best-guess /api/inventory/catalog
  endpoint and fall back to a flagged "(est.)" price sourced from the
  spec's own worked example when that endpoint isn't available yet —
  the contract doesn't define a price-list REST shape.

- SigilDesigner.tsx + lib/sigil.ts: constrained geometric builder —
  points snap to 24 fixed clock-face slots around a circle, capped at
  12 to match the backend's payload limit, connected in placement
  order. Five hand-drawn stroke-only rune glyphs (eye/crescent/key/
  spiral/thorn) overlay the center. Point-cap enforcement, rune
  selection and payload-shape building are pure functions in
  lib/sigil.ts, unit-tested directly. Saves via POST
  /api/inventory/sigils (path inferred; payload shape matches the
  contract exactly: {"points": [[x,y],...], "rune": str}). Art
  direction: the builder itself reads like a plotting/debug tool
  (crosshair cursor, monospace coordinate HUD) while the rendered
  lines + rune glow violet, consistent with GhostGlyph's conventions.

- lib/evp.ts: new evpThresholdDb(hasListeningTool) pure function and
  EvpListener.start() now accepts { hasListeningTool } to lower the
  EVP anomaly threshold (8dB -> 4dB) when the unlock is owned — wired
  from useAuth().user.unlocks in SeancePage's EvpPanel, a real
  gameplay effect on which faint signals register as anomalies.

- api.ts User type gains unlocks/essence per the contract's /auth/me
  extension; new InventoryPage.tsx mounts both components behind auth
  at /inventory, linked from the séance nav.

166/166 tests pass (137 pre-existing + 29 new), i18n coverage check
clean, tsc -b clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 16:26:18 +00:00
Indiana
a52a781880 feat(frontend): ritual mini-game, judgment UI, and consequences (Workstream E)
Implements the Character Depth / Ghost Log spec's Workstream E:

- RitualPanel.tsx: a 4-step "focus the channel" hold-to-charge sequence
  (align/breathe/trace/lock), sending ritual_step frames as the seeker
  progresses. Success reveals the entity's true hidden traits; failure
  reveals nothing. Sequencing/timing logic lives in the pure, unit-tested
  lib/ritual.ts rather than inline in the component.
- JudgmentPanel.tsx: Trust/Banish/Cross Over/Test verdict buttons with
  rune-style SVG icons, sending the judgment frame and rendering a
  distinct treatment per judgment_result consequence — reward,
  escalation (also spikes the ambient haunting), withdrawal, resisted,
  neutral, and a calm glyph-fade farewell for crossed_over (deliberately
  not the reward treatment, since it's a goodbye).
- lib/haunting.ts: IdleEscalator gains forceEscalate()/forcedUntil so a
  judgment's "escalation" consequence can spike the ambient haunting
  immediately instead of waiting on the 90s idle clock; exports a
  sharedIdleEscalator singleton and a forceEscalate() free function.
  HauntingLayer now paces itself off that shared instance instead of a
  private one, so the forced spike actually reaches the running layer.
- state/seance.tsx: new ritual/judgmentResult state, a local_ritual_start
  action, and reducer cases for the ritual_complete/judgment_result server
  frames; SeanceContext exported for component testing; startRitual/
  sendRitualStep/sendJudgment added to the provider API.
- lib/types.ts: EntityTraits/JudgmentVerdict/JudgmentConsequence types and
  the new client/server WS frames, per the spec's Contract section.
- i18n: seance.ritual.* / seance.judgment.* keys in en.json and es.json.

Fast-forwarded this worktree's branch onto master first — it had been
created from a stale ancestor commit predating the frontend scaffold
entirely, with zero commits of its own ahead of that point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:29:29 +00:00
Indiana
6d8c6f2496 rename: The Armory -> The Reliquary; extend spec with essence + cross-over
Renaming: "Armory" read too militaristic for a séance app. Landed on "The
Reliquary" (not "The Threshold" — that name was already taken by the
landing-page back-link).

Spec addendum: added a visible essence currency (earned per summon, spent
on unlocks — distinct from the hidden favor score) and a fourth judgment
verdict, cross_over, for compassionately helping a genuinely benevolent
"stuck" spirit move on rather than just trusting or banishing it. Updates
workstreams B/C/E/F accordingly before any of them are dispatched.
2026-07-23 11:06:07 +00:00
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
761d6171b5 fix: actually strip stale SESSION_SECRET mentions from README
The gap-g-readme merge commit (57a8914) staged this fix but never
re-staged it after editing, so the merge landed with the pre-fix content —
the working tree had the correction but git didn't. No functional change,
just closing the gap between what was intended and what was committed.
2026-07-23 03:32:21 +00:00
Indiana
b56f5b8108 Merge gap-e-sdr-tests: SpectrumAnomalyDetector unit test coverage 2026-07-23 00:33:28 +00:00
Indiana
9c34fdc67f Merge gap-f-i18n-ci: run i18n coverage check via npm pretest 2026-07-23 00:33:28 +00:00
Indiana
2b83c7cb7d test: add coverage for SpectrumAnomalyDetector
Pure rolling-floor/spike-detection logic in sdr.ts had zero tests,
unlike its EVP/EMF detector siblings. No production code changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
2026-07-21 03:45:52 +00:00
Indiana
f0ee7dbdab refactor: use TelemetryReadout and EntityCard components
Both were built and tested but never wired in — SeancePage.tsx was
reimplementing the same markup inline. Removes the duplication.
2026-07-21 03:45:11 +00:00
Indiana
34314c324d chore: enforce i18n key coverage via npm test
coverage-check.mjs existed but nothing ran it automatically.
Wired in as a pretest hook so a coverage regression now fails
the test run instead of silently passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
2026-07-21 03:42:44 +00:00
Indiana
0756e677b9 Add EMF field mode, Armory shop/waitlist, and ambient haunting layer
Three self-contained features, verified complete and cross-wired
end-to-end (audited: backend 54/54 tests, frontend 110/110 tests,
tsc --noEmit clean, i18n coverage script clean):

- EMF mode: DeviceMotion/DeviceOrientation-based field-meter sensing,
  a fifth séance channel alongside Wire/EVP/Radio/Ouija, with its own
  fragment prompt persona and full frontend gauge UI.
- Armory (shop/waitlist): pre-order capture page for the future
  Ultimate Quantum Box hardware line, rate-limited public endpoint,
  explicitly no payment collection.
- Haunting layer: ambient possession effects (dread-bed audio, title
  glitching, idle-paced whispers/manifests), respects
  prefers-reduced-motion, mounted once at the app root.

Plus WebUSB robustness fixes in lib/sdr.ts (Terratec vendor ID,
explicit selectConfiguration, isSecureContext gate).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
2026-07-21 02:28:14 +00:00
Indiana
c372427ced feat: matrix/graph data views, wire-generated anomalies, http cookie fix
- auth: session cookie Secure only over https — plain-http LAN access was
  silently dropping the cookie, killing WS auth ('connection unstable')
- wire ghost: server-side spike detection on jitter baseline (3σ + 2.5×mean,
  20KB/s floor, 20s throttle) — wire anomalies now flood every session with
  zero hardware, pushed to clients as {type:'anomaly'} frames
- telemetry cadence 3-5s for live graphs; ambient whispers unchanged
- frontend: MATRIX view (data-rain interleaved with live utterances/anomaly/
  telemetry strings), GRAPHS view (scrolling jitter/variance/dns lines +
  anomaly markers + counters), BOARD/MATRIX/GRAPHS switcher
- connection banner: 'connecting' is now neutral 'tuning the veil…', only
  unstable/closed warns
- db: recreated quantumancy(+_test) as UTF8 (was SQL_ASCII — crashed on
  non-ASCII spirit text); README quickstart updated
- i18n: seance.views.* EN/ES
2026-07-21 00:02:41 +00:00
Indiana
6edbbbbc2a feat: complete Quantumancy web app — full frontend + docs
Frontend (React 18 + TS + Vite):
- Landing: glitching hero, live /api/stats veil ticker, mode cards, featured spirits
- Séance: three.js shader ghost (hue/form per entity, mood + audio-reactive),
  Ouija planchette board spelling utterances, transcript with TTS replay,
  entity dossier, direct contact streaming, passive/active listening
- Modes: Wire Ghost telemetry panel, EVP mic anomaly detection, WebUSB
  RTL-SDR sweep + waterfall (hardware pass pending), Ouija/Direct Contact
- Codex: public registry + entity dossiers, rarity tiers, i18n EN/ES complete
- State: VeilSocket (reconnect/backoff), seance reducer, auth context
- 72 vitest tests green; served by FastAPI at :7777

Docs: README + as-built plans 3-7
2026-07-20 21:11:49 +00:00
Indiana
6bcdf83c4d feat: scaffold React frontend with login/register UI 2026-07-20 17:42:44 +00:00