Health check no longer opens the camera — it just confirms the server
is running. This prevents blocking when the camera is in use by a
concurrent request or the background startup test.
Co-authored-by: Cursor <cursoragent@cursor.com>
Server starts accepting requests immediately instead of blocking on
the camera test. If the camera lock is held by a previous process,
the server is still reachable and will attempt live camera access
on each request independently.
Co-authored-by: Cursor <cursoragent@cursor.com>
Every request now opens the camera, grabs fresh frames, conditions them
with SHA-256, and returns. No pool, no background harvester, no buffered
data. Camera not available = immediate error.
- Delete src/entropy/pool/ (ring buffer, harvester, subscriber channels)
- Add src/entropy/live.rs (extract_entropy, fill_entropy, stream_entropy)
- Health endpoint now tests live camera reachability instead of pool stats
- /stream opens a dedicated camera session per connection
- Remove rand/rand_chacha dependencies (only used by removed CSPRNG)
- Include monotonic nonce + timestamp in SHA-256 conditioning to guarantee
unique output even on rapid back-to-back calls
Co-authored-by: Cursor <cursoragent@cursor.com>
LaunchAgent now uses launch-wrapper.sh which does git pull + cargo build
before exec-ing the binary, so every restart picks up the latest code.
Eliminates the drift where a rebuilt binary doesn't take effect until
the old process is manually killed.
New scripts:
- launch-wrapper.sh: auto-pull, rebuild, exec (used by LaunchAgent)
- upgrade.sh: manual pull, rebuild, restart LaunchAgent
Tests (12 total, all passing):
- Pool camera-only invariants: empty pool returns error (no CSPRNG
fallback), push/pull round-trip matches exactly, pool empty after
drain (no synthetic fill), extract_entropy and fill_entropy fail
without camera data, partial pull is all-or-nothing, stats track
only camera bytes.
- Conditioning tests: deterministic output, varies with frame index,
correct SHA-256 output size, 8:1 ratio, LSB masking to 0-3 range.
Refactored pool.rs into pool/mod.rs + pool/tests.rs to stay under
400-line file limit.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Remove CSPRNG fallback: pool now returns errors when camera entropy
is insufficient instead of silently falling back to ChaCha20.
Random data is only from camera input or not at all.
- Fix throughput display: show Mbps/KB/s for smaller frame sizes,
Gbps/MB/s for larger ones (actual frame size varies by pixel format).
- Add RESEARCH.md note about pixel format impact on throughput.
- Complete README API table with all endpoints (dice, password, coin,
8ball, cameras, docs, MCP).
- Add docker-compose device mapping for Linux camera access with
explanatory comments about macOS limitation.
- Add macOS LaunchAgent scripts (install/uninstall/plist template).
- Polish run-mac.sh with build step and clearer output.
- Fix dead code warnings on library utility functions.
- Add /logs/ to .gitignore for LaunchAgent log output.
- Fix skill.md: remove stale CSPRNG fallback references.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Simplify build process by removing dummy source step
- Fix binary name from camera-trng to camera-qrng
- Copy skill.md to fix include_str! error
- Remove /dev/video0 device requirement from docker-compose
- Allows container to run with CSPRNG fallback when no camera available
Co-authored-by: Cursor <cursoragent@cursor.com>
Sync Matomo and PostHog snippets with main site for consistency. Updated PostHog loader to latest version with expanded method stubs and defaults config.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Replace all Mutex::lock().unwrap() with lock_or_recover() that recovers
from poisoned mutexes instead of panicking (cascading failure prevention)
- Wrap harvester loop in catch_unwind with a supervisor thread that
automatically restarts on panic (requires panic=unwind in release profile)
- Add exponential backoff with jitter for camera reconnection (2s base,
60s cap) instead of fixed 10s intervals
- Enforce frame deadline: frames exceeding FRAME_TIMEOUT are treated as
errors rather than just logged
- Add graceful shutdown via SIGINT/SIGTERM with axum's
with_graceful_shutdown
- Track harvester restart count via AtomicU64 for diagnostics
- Extract docs/MCP handlers into src/docs_handlers.rs to keep main.rs
under 400 lines
- Change release profile from panic=abort to panic=unwind so
catch_unwind actually works in production
- Add tokio signal feature for shutdown handling
Co-authored-by: Cursor <cursoragent@cursor.com>
20 is the recommended minimum for 2026. The API and UI still
accept shorter lengths if explicitly requested.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the full dropdown nav with three simple links: Portfolio
(colinknapp.com), TRNG (/), and Tools (/tools). Removed all
unused dropdown CSS from both pages.
Co-authored-by: Cursor <cursoragent@cursor.com>
Dice output now always shows "Sum: X of Possible: Y" where Y is
sides * count, on both the main page and standalone /tools page.
Co-authored-by: Cursor <cursoragent@cursor.com>
The /tools page now has the same chrome as the main page:
- Skip-to-content link
- Full navigation bar with all dropdown menus
- Accessibility notice in footer
- Footer CTA with shimmer border and contact modal
- Matomo + PostHog analytics scripts
- Same max-width (800px) and font/color variables
Co-authored-by: Cursor <cursoragent@cursor.com>
The checkbox was crammed into the controls flex row alongside the
length/charset/generate button, causing layout issues at narrower
widths. Now sits on its own line between controls and output box
on both the main page and standalone /tools page.
Co-authored-by: Cursor <cursoragent@cursor.com>
Dedicated tools-only page at /tools with dice, password generator,
coin flip, and 8 ball - each with its own click-to-copy output box.
Clean, lightweight page without API docs/MCP/contact form clutter.
Linked from the main page's QTRNG Tools section.
Co-authored-by: Cursor <cursoragent@cursor.com>
New QTRNG tool: Quantum 8 Ball with all 20 classic Magic 8 Ball
responses, selected via rejection sampling on quantum camera noise.
Includes /8ball API endpoint, sentiment classification (positive/
neutral/negative), and a fun dark-orb UI with shake animation and
color-coded answers. Both output boxes (random bytes + tools) now
support click-to-copy with a toast notification.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Removed /raw route from server
- Removed get_raw function and RawQuery struct
- Removed extract_raw_lsb import
- Removed all /raw references from skill.md documentation
- Replaced url_template placeholders with concrete example URLs in MCP JSON
- Users can no longer access raw sensor data
Security: Raw sensor data access completely removed to prevent potential
information leakage from camera sensor patterns.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Enhanced /.well-known/mcp.json to extract hostname from request headers (SNI/Host)
- Added self-referencing URLs that work with localhost, domains, and reverse proxies
- Documented all 5 API endpoints (random, raw, stream, cameras, health) as MCP tools
- Added /docs endpoint serving HTML documentation from skill.md
- Added /docs/skill.md for raw markdown access
- Added /docs/mcp.json as alias to /.well-known/mcp.json
- Created skill.md with comprehensive API documentation
- Markdown to HTML conversion happens at build time
Co-authored-by: Cursor <cursoragent@cursor.com>