Audio forensics meets AI-assisted development.
Losselot started as a tool to detect fake lossless audio files. It evolved into something more: a living experiment in how AI and humans can build software together, with every decision tracked and queryable.
Two things at once:
-
An Audio Forensics Tool - Detect if your FLAC/WAV files are actually transcoded from MP3s. Uses spectral analysis, binary metadata parsing, and lo-fi detection to expose the truth.
-
A Living Museum - Every algorithm choice, every rejected approach, every "why did we do it this way?" is captured in a queryable decision graph. Watch the project evolve in real-time.
Explore the Live Site | Browse the Decision Graph
git clone https://github.com/notactuallytreyanastasio/losselot.git
cd losselot
cargo build --release
./target/release/losselot serve examples/ --port 3000Open localhost:3000 - you'll see the interactive analysis UI.
No test files? Generate them:
cd examples && ./generate_test_files.sh| Platform | Download |
|---|---|
| Mac (Apple Silicon) | Download |
| Mac (Intel) | Download |
| Windows | Download |
| Linux (AppImage) | Download |
| Linux (CLI) | Download |
| Verdict | Score | Meaning |
|---|---|---|
| CLEAN | 0-34 | Genuine lossless - natural frequency content |
| SUSPECT | 35-64 | Something's off - investigate further |
| TRANSCODE | 65-100 | Fake lossless - clear compression damage |
Audio Analysis Deep Dive
Lossy codecs remove high frequencies to save space. The "scars" are permanent:
| Source | Typical Cutoff |
|---|---|
| 128kbps MP3 | ~16kHz |
| 192kbps MP3 | ~18kHz |
| 320kbps MP3 | ~20kHz |
| True Lossless | ~22kHz |
For MP3 files, we read encoder metadata (LAME headers). A "320kbps" file with a 16kHz lowpass was definitely transcoded from 128kbps - the encoder honestly reports what it kept.
Not all high-frequency rolloff is compression damage. Tape recordings have natural rolloff.
The difference:
- MP3: Brick-wall cutoff at fixed frequency
- Tape: Gradual rolloff that varies with dynamics
We use Cross-Frequency Coherence (CFCC) to distinguish them.
Multiple encoder signatures = multiple lossy passes = cumulative damage. We detect LAME, FFmpeg, Fraunhofer, and chains between them.
Spectral:
severe_hf_damage- Major frequency losshf_cutoff_detected- Clear lossy cutoff founddead_ultrasonic_band- No content above 20kHz
Re-encoding:
multi_encoder_sigs- Multiple encoders detectedencoding_chain(LAME → FFmpeg)- Specific chain identifiedlame_reencoded_x2- Re-encoded through LAME twice
FLAC, WAV, AIFF, MP3, M4A, AAC, OGG, Opus, ALAC
Decision Graph & Memory System
Claude (and LLMs generally) lose context. Sessions end, memory compacts, decisions evaporate. Six months later, no one remembers why we chose CFCC over temporal variance analysis.
Every decision is tracked in a queryable graph that persists forever:
# See all decisions ever made
./target/release/losselot db nodes
# See how they connect
./target/release/losselot db edges
# Full graph as JSON
./target/release/losselot db graph| Type | Purpose |
|---|---|
| Goal | High-level objectives |
| Decision | Choice points with options |
| Option | Approaches considered |
| Action | What was implemented |
| Outcome | What happened |
| Observation | Technical insights |
Every node can have a confidence score (0-100):
# Add with confidence
./target/release/losselot db add-node -t decision "Use CFCC" -c 85- 70-100: High confidence - proven approach
- 40-69: Medium - reasonable, some uncertainty
- 0-39: Low - experimental
Link decisions to specific code changes:
./target/release/losselot db add-node -t action "Implemented feature" -c 90 --commit abc123The demo UI shows clickable commit badges that link to GitHub.
- Queryable history: "Why didn't we use temporal variance?" → search the graph
- Rejected approaches preserved: What didn't work is as valuable as what did
- Code-decision traceability: Every commit linked to its reasoning
- Survives context loss: The graph outlives any session
Browse it here - 75+ nodes, chains grouped by topic, confidence badges, commit links.
Claude Integration & CLAUDE.md
The project includes a CLAUDE.md file that tells Claude:
- Always start by reading the decision graph - recover context
- Log everything - observations, decisions, actions, outcomes
- Link commits to decisions - full traceability
- Sync the graph before deploying - keep the live site current
# Decision Graph Commands
make obs T="Found interesting pattern" C=80 # Observation
make decision T="Choose approach" C=70 # Decision point
make action T="Implemented fix" C=95 # Implementation
make outcome T="Tests pass" C=90 # Result
make link FROM=1 TO=2 REASON="because" # Connect nodes
make sync-graph # Export to live site
# Web Viewer Commands (React + TypeScript + Vite)
make web # Sync graph data and start dev server
make web-dev # Start dev server at http://localhost:3001
make web-build # Build production bundle
make web-typecheck # Run TypeScript type checking
make web-test # Run web testsNote: All commands should be run via make targets. This is the primary entrypoint for Claude skills and automation.
The frontend has TypeScript types mirroring the Rust backend:
DecisionNode,DecisionEdge,GraphData(graph.ts)AnalysisResult,BinaryAnalysis,SpectralAnalysis(analysis.ts)
Tests run in CI alongside Rust tests.
This isn't documentation written after the fact. It's a real-time record of how software gets built - captured as decisions happen, not reconstructed from memory later.
Command Line Reference
# Analyze files
./losselot ~/Music/ # Folder
./losselot file.flac # Single file
./losselot -o report.html ~/Music/ # Custom output
# Web UI
./losselot serve ~/Music/ --port 3000
# Quick scan (no spectral)
./losselot --no-spectral ~/Music/
# Decision graph
./losselot db nodes # List nodes
./losselot db edges # List edges
./losselot db graph # Full JSON
./losselot db add-node -t TYPE "Title" [-c CONF] [--commit HASH]
./losselot db add-edge FROM TO [-t TYPE] [-r REASON]Exit codes: 0=clean, 1=suspect, 2=transcode
Build from Source
# Requires Rust (rustup.rs)
git clone https://github.com/notactuallytreyanastasio/losselot.git
cd losselot
cargo build --releasecargo test # Rust tests
cd docs && npm test # TypeScript testscd examples && ./generate_test_files.shCreates files demonstrating:
- Clean 320kbps and V0 VBR encodes
- 128kbps → 320kbps transcodes
- Multiple re-encoding passes
- Mixed encoder chains
Losselot started as "does this FLAC actually contain lossless audio?" and evolved into "can we build software in a way where every decision is preserved, queryable, and linked to code?"
The audio forensics works great. But the real experiment is whether decision graphs can solve the "why did we do it this way?" problem that plagues every long-running project.
MIT - Do whatever you want with it.
