diff --git a/README.md b/README.md index c3fb131..8b3848e 100644 --- a/README.md +++ b/README.md @@ -369,3 +369,45 @@ Public `status` is one of: `matched` · `no_match` · `not_configured` · `inval ## License [MIT](LICENSE) — free to use and modify. + + +## Source-reviewed architecture overview + +```mermaid +%% Source-reviewed overview; 2026-10-03; commit 2671ccab1802f330083f122561e7ab6c2718dd9f +%% Solid edges: core flow. Dashed edges: optional or separately invoked services. +%%{init: {"theme":"base","securityLevel":"loose","fontFamily":"Arial, sans-serif","themeVariables":{"background":"#0b1220","primaryColor":"#17283d","primaryTextColor":"#edf4ff","primaryBorderColor":"#71c4ec","lineColor":"#9fadc1","secondaryColor":"#213548","tertiaryColor":"#17283d","edgeLabelBackground":"#0b1220","clusterBkg":"#101d2e","clusterBorder":"#456783","fontSize":"17px"},"flowchart":{"htmlLabels":true,"curve":"linear","nodeSpacing":35,"rankSpacing":50}}}%% +flowchart TD + I["Microphone / file input"] + W["CLI + Flask entry points"] + N["Validate + normalize audio"] + D["Matcher + fallback dispatch"] + L["Local hashes + fingerprint index"] + P["Optional remote providers"] + F["CLI FFT diagnostic"] + R["Status / result presentation"] + ART["External album-art URLs"] + I --> W + R -. optional album art .-> ART + W --> N + N --> D + N -.->|CLI diagnostic before matching| F + D -->|configured index| L + D -.->|configured audio/fingerprint request| P + L --> R + P -.->|provider response| R + N -->|invalid audio status| R + click ART "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/display.py" "Open source" + click I "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/main.py" "Open source" + click W "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/app.py" "Open source" + click N "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/recorder.py" "Open source" + click D "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click L "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fingerprint.py" "Open source" + click P "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click F "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fft_analyze.py" "Open source" + click R "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/static/app.js" "Open source" + classDef core fill:#17283d,stroke:#71c4ec,stroke-width:1.6px,color:#edf4ff; + class I,W,N,D,L,P,F,R,ART core; +``` + +See the [architecture case study](docs/architecture/README.md), [coverage](docs/architecture/coverage.md), and [publication evidence and rendered previews](docs/architecture/publication.md). diff --git a/TODO.md b/TODO.md index 355c210..ba1f16d 100644 --- a/TODO.md +++ b/TODO.md @@ -286,3 +286,8 @@ Record evidence here as work lands: | 2026-07-31 | Matcher correctness slice | Provider adapters now return stable `error_code` values with diagnostic detail; mocked RapidAPI, AudD, and AcoustID success/no-match/HTTP/timeout/malformed-output tests and temporary-WAV cleanup tests were added. | 36 pytest tests passed; branch coverage is 59%; real provider behavior and credentialed smoke tests remain open | | 2026-07-31 | Polishing roadmap | Added an ordered eight-task execution roadmap covering benchmark evidence, audio validation, web ownership, production security, test depth, CI/repository hygiene, documentation reconciliation, and distinctiveness evaluation. | Roadmap recorded; complete one main task at a time | | 2026-07-31 | CI quality-gate slice | `.github/workflows/ci.yml` runs pytest on every push and pull request across Python 3.10–3.12, enforces 50% branch coverage on Python 3.12, and uploads `coverage.xml`. | Workflow structure verified; later PR #4 evidence supersedes the pending remote/Codecov note | + + +## Architecture documentation publication — 2026-10-04 + +Goal: publish source-linked architecture documentation and diagram previews. Scope: README, this backlog and docs/architecture artifacts. Source snapshot: 2671ccab1802f330083f122561e7ab6c2718dd9f; no runtime, dependency, data or deployment changes. Acceptance: pinned inventory/source-map/embedding checks, ten intended negative cases, renderer checks, bounded Jev review, documentation-only commit and remotely verified PR. Jev remains advisory; pre-existing workspace changes are excluded. diff --git a/docs/architecture/README.md b/docs/architecture/README.md new file mode 100644 index 0000000..0e10078 --- /dev/null +++ b/docs/architecture/README.md @@ -0,0 +1,104 @@ +# Audio Recognition: architecture case study + +CLI and Flask inputs share a bounded audio contract and configurable recognition backends. + +Source snapshot: `2671ccab1802f330083f122561e7ab6c2718dd9f`. Reviewed on **2026-10-03**. This describes the selected committed source, excluding unrelated uncommitted work in the canonical checkout. It is not a runtime, provider, deployment or security certification. + +## Overview + +```mermaid +%% Source-reviewed overview; 2026-10-03; commit 2671ccab1802f330083f122561e7ab6c2718dd9f +%% Solid edges: core flow. Dashed edges: optional or separately invoked services. +%%{init: {"theme":"base","securityLevel":"loose","fontFamily":"Arial, sans-serif","themeVariables":{"background":"#0b1220","primaryColor":"#17283d","primaryTextColor":"#edf4ff","primaryBorderColor":"#71c4ec","lineColor":"#9fadc1","secondaryColor":"#213548","tertiaryColor":"#17283d","edgeLabelBackground":"#0b1220","clusterBkg":"#101d2e","clusterBorder":"#456783","fontSize":"17px"},"flowchart":{"htmlLabels":true,"curve":"linear","nodeSpacing":35,"rankSpacing":50}}}%% +flowchart TD + I["Microphone / file input"] + W["CLI + Flask entry points"] + N["Validate + normalize audio"] + D["Matcher + fallback dispatch"] + L["Local hashes + fingerprint index"] + P["Optional remote providers"] + F["CLI FFT diagnostic"] + R["Status / result presentation"] + ART["External album-art URLs"] + I --> W + R -. optional album art .-> ART + W --> N + N --> D + N -.->|CLI diagnostic before matching| F + D -->|configured index| L + D -.->|configured audio/fingerprint request| P + L --> R + P -.->|provider response| R + N -->|invalid audio status| R + click ART "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/display.py" "Open source" + click I "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/main.py" "Open source" + click W "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/app.py" "Open source" + click N "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/recorder.py" "Open source" + click D "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click L "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fingerprint.py" "Open source" + click P "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click F "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fft_analyze.py" "Open source" + click R "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/static/app.js" "Open source" + classDef core fill:#17283d,stroke:#71c4ec,stroke-width:1.6px,color:#edf4ff; + class I,W,N,D,L,P,F,R,ART core; +``` + +[Editable Mermaid](overview.mmd). Solid edges show the core flow; dashed edges show optional or separately invoked paths. Diagram connections summarize control/data flow rather than a complete import graph. + +## Main flow + +A user records or uploads audio through the CLI or Flask interface. The shared recorder validates duration and encoding, then normalizes samples. The dispatcher attempts RapidAPI, AcoustID, AudD, then the local matcher, skipping missing configuration and stopping on success or a terminal result: remote provider adapters send audio or derived fingerprints when enabled, while the local backend searches constellation hashes against a configured index. Results become stable public statuses and CLI or browser output. The CLI runs FFT diagnostics before matching and stops on diagnostic failure; the web route omits FFT. + +## Engineering decision + +Use one audio contract and one result contract across CLI, browser and recognition backends. This keeps validation and recovery behavior consistent while allowing provider fallback. The tradeoff is dependence on provider catalogs or a locally prepared fingerprint index rather than guaranteed recognition. + +## Source map + +| Component | Review path | +| --- | --- | +| Microphone / file input | [main.py](../../main.py) | +| CLI + Flask entry points | [web/app.py](../../web/app.py) | +| Validate + normalize audio | [shazam_project/recorder.py](../../shazam_project/recorder.py) | +| Matcher + fallback dispatch | [shazam_project/matcher.py](../../shazam_project/matcher.py) | +| Local hashes + fingerprint index | [shazam_project/fingerprint.py](../../shazam_project/fingerprint.py) | +| Optional remote providers | [shazam_project/matcher.py](../../shazam_project/matcher.py) | +| CLI FFT diagnostic | [shazam_project/fft_analyze.py](../../shazam_project/fft_analyze.py) | +| External album-art URLs | [shazam_project/display.py](../../shazam_project/display.py) | +| Status / result presentation | [web/static/app.js](../../web/static/app.js) | + +## Boundaries and limitations + +- The local matcher needs an index; remote providers need credentials and may receive the submitted audio when invoked. This differs from Launchpad browser-local audio processing. +- FFT output is diagnostic, not the recognition algorithm. Browser history is session-only; product accounts and persistent history are not implemented. +- No recognition accuracy, latency benchmark, credentialed provider result or public deployment was verified here. + +## GitDiagram provenance + +GitDiagram draft dated 2026-09-19 and the existing detailed Mermaid/PNG are retained. The reviewed overview emphasizes shared normalization, provider transmission and diagnostic boundaries. + +[GitDiagram reference](https://gitdiagram.com/icecold009/Audio-Recognition) · [Repository](https://github.com/icecold009/Audio-Recognition) + +The compact overview is a source-reviewed adaptation authored for this snapshot and rendered locally, not an unmodified GitDiagram export. Existing detailed assets remain at [Mermaid](audio-recognition.mmd) and [PNG](audio-recognition.png). + +## Interview explanation + +> The interesting part is the shared audio and result contracts, not an FFT picture. CLI and Flask normalize inputs consistently, and the matcher isolates local fingerprinting from optional provider adapters. Real accuracy still needs a lawful corpus and measured evaluation. + +## Verification and refresh + +Documentation-only acceptance: validate every relative source link and commit-specific diagram link, render Mermaid, inspect the dark PNG for readability, inspect the complete diff, and obtain a bounded Jev diff review. The repository proposal contains no new binary images; separately delivered PNG previews are independently checked because Jev reviews text. Results and Jev coverage are recorded in this task’s delivery report rather than treated as application test evidence. + +After an architecture change, inspect the new source, update this snapshot identifier, regenerate the overview from Mermaid, and recheck links and image appearance. Keep planned integrations explicitly separate from implemented paths. + +## Review status + +Integration is pending warning resolution. Earlier Jev uncertainty has not been accepted or waived. The proposed repository changes are text only, including embedded Mermaid; PNG previews are separate delivery outputs. Source claims describe this committed snapshot. The coverage register accounts for tracked paths and does not prove every execution path or deployed behavior. + +## Detailed coverage + +See [the subsystem diagram and complete tracked-file register](coverage.md) and [editable detail Mermaid](detail.mmd). This supplement records recovery, optional services, delivery boundaries and original-checkout drift beyond the overview. + +[Documentation verification record](verification.md). + +Source clarification: the CLI invokes FFT diagnostics before matching and stops on a diagnostic error. The web match route does not invoke FFT. When artwork is returned, the CLI display and browser can request its external image URL separately from recognition. diff --git a/docs/architecture/coverage.md b/docs/architecture/coverage.md new file mode 100644 index 0000000..e79e8ab --- /dev/null +++ b/docs/architecture/coverage.md @@ -0,0 +1,168 @@ +# Subsystem coverage register + +Snapshot: `2671ccab1802f330083f122561e7ab6c2718dd9f`. The overview is intentionally compact; this detail layer accounts for the selected Git-tracked tree. Inventory coverage is not proof of every behavior, dynamic dependency, ignored file or deployed system. Nodes group modules rather than reproducing every function. Credentials, local datasets and generated dependencies are excluded. + +```mermaid +flowchart TB + %% Solid arrows: runtime/data dependency; dotted arrows: optional, build or local-only boundary. + UI["CLI microphone/PCM and browser capture/upload"] + API["Flask validation, quotas and status/health routes"] + CONVERT["Bounded FFmpeg normalization and temp cleanup"] + DIAG["CLI FFT diagnostic before matching"] + FP["Local constellation fingerprints and index"] + MATCH["Dispatcher: RapidAPI, AcoustID, AudD, then local"] + CONFIG["Runtime configuration and provider policy"] + QUOTA["Atomic Supabase quota schema; in-memory mode"] + TOOLS["Fingerprint index construction and benchmarks"] + RUN["Gunicorn/container and deployment definitions"] + NORM["Shared validated AudioClip normalization"] + REMOTE["RapidAPI / AudD audio; AcoustID fingerprints"] + RESULT["Matched/no-match/not-configured/invalid/error results"] + SUPPORT["Supporting tests, assets, documentation and delivery config"] + ART["External album-art URLs"] + UI --> API + UI -. optional album art .-> ART + UI --> NORM + API --> CONVERT + CONVERT --> NORM + NORM --> MATCH + CONFIG --> API + CONFIG --> MATCH + API --> QUOTA + TOOLS --> FP + RUN -. configured entry .-> API + UI -. CLI diagnostic before matching .-> DIAG + MATCH -. local backend .-> FP + MATCH -. configured remotes .-> REMOTE + MATCH --> RESULT + RESULT --> UI + SUPPORT -. supports .-> UI +``` + +## Flow and boundary notes + +- The CLI captures PCM/WAV; the web upload path normalizes supported formats with bounded FFmpeg execution and temporary-file cleanup. Both paths reach the shared AudioClip normalization and matcher contract. The CLI always performs FFT diagnostics before matching and returns on diagnostic failure. The web match route skips FFT; FFT is not itself the song-identification algorithm. +- The dispatcher attempts RapidAPI, AcoustID, AudD, then the local matcher, skipping unavailable configuration and stopping on a match or other terminal result. It is not local-first. RapidAPI/AudD can receive audio; AcoustID receives derived fpcalc fingerprints. The local backend uses its constellation index. These are separate privacy and network boundaries. +- Status, health and readiness routes differ from recognition success. Quota enforcement can use memory or the atomic Supabase schema. Container/render configuration describes packaging, not verified hosting; benchmark/index scripts are offline tooling. + +## Original checkout differences + +Pre-existing changed paths at audit: `M supabase/config.toml`, `M web/templates/index.html`. This documentation targets the commit above; these unrelated changes remain in the original checkout. + +## File accounting + +69 tracked paths, each assigned exactly once below. Supporting items remain explicit without becoming runtime services. Root dependency/build/CI files and otherwise unassigned support files are in DELIVERY; that bucket must be inspected for misclassified runtime modules. + +### UI: CLI microphone/PCM and browser capture/upload (7) + +- `main.py` +- `shazam_project/display.py` +- `shazam_project/recorder.py` +- `web/static/app.js` +- `web/static/style.css` +- `web/static/typography.css` +- `web/templates/index.html` + +### API: Flask validation, quotas and status/health routes (1) + +- `web/app.py` + +### CONVERT: Bounded FFmpeg normalization and temp cleanup (0) + +External or cross-cutting concept; source is shared with other nodes. + +### DIAG: CLI FFT diagnostic before matching (1) + +- `shazam_project/fft_analyze.py` + +### FP: Local constellation fingerprints and index (1) + +- `shazam_project/fingerprint.py` + +### MATCH: Dispatcher: RapidAPI, AcoustID, AudD, then local (1) + +- `shazam_project/matcher.py` + +### CONFIG: Runtime configuration and provider policy (2) + +- `shazam_project/__init__.py` +- `shazam_project/config.py` + +### QUOTA: Atomic Supabase quota schema; in-memory mode (3) + +- `supabase/.gitignore` +- `supabase/config.toml` +- `supabase/migrations/20260801145213_production_rate_limits.sql` + +### TOOLS: Fingerprint index construction and benchmarks (7) + +- `evaluation/sources.example.csv` +- `scripts/__init__.py` +- `scripts/benchmark.py` +- `scripts/build_fingerprint_index.py` +- `scripts/evaluation.py` +- `scripts/record_benchmark.py` +- `scripts/update_readme.py` + +### RUN: Gunicorn/container and deployment definitions (4) + +- `Dockerfile` +- `compose.yaml` +- `gunicorn.conf.py` +- `render.yaml` +### TEST (16) + +- `tests/__init__.py` +- `tests/conftest.py` +- `tests/test_audio_pipeline.py` +- `tests/test_benchmark.py` +- `tests/test_ci_hardening.py` +- `tests/test_config.py` +- `tests/test_core.py` +- `tests/test_deployment.py` +- `tests/test_display.py` +- `tests/test_fingerprint.py` +- `tests/test_providers.py` +- `tests/test_rate_limits.py` +- `tests/test_recorder.py` +- `tests/test_reproducible_benchmark.py` +- `tests/test_web.py` +- `tests/test_web_pipeline.py` + +### DOC (17) + +- `LICENSE` +- `README.md` +- `TODO.md` +- `docs/01-product-requirements.md` +- `docs/02-technical-requirements.md` +- `docs/03-app-flow.md` +- `docs/04-ui-ux-design-brief.md` +- `docs/05-backend-schema.md` +- `docs/architecture/audio-recognition.mmd` +- `docs/architecture/audio-recognition.png` +- `docs/screenshots/fft-output.png` +- `evaluation/README.md` +- `showcase/audio-recognition/case-study.md` +- `showcase/audio-recognition/diy-shazam-showcase.pptx` +- `showcase/audio-recognition/evidence-checklist.md` +- `showcase/audio-recognition/presentation-outline.md` +- `showcase/audio-recognition/presentation-script.md` + +### ASSET (0) + +None in this snapshot. + +### DELIVERY (9) + +- `.dockerignore` +- `.env.example` +- `.gitattributes` +- `.github/container_smoke_wsgi.py` +- `.github/workflows/ci.yml` +- `.gitignore` +- `pyproject.toml` +- `requirements-dev.txt` +- `requirements.txt` + +Source clarification: the CLI invokes FFT diagnostics before matching and stops on a diagnostic error. The web match route does not invoke FFT. When artwork is returned, the CLI display and browser can request its external image URL separately from recognition. diff --git a/docs/architecture/detail.mmd b/docs/architecture/detail.mmd new file mode 100644 index 0000000..6d0ed7b --- /dev/null +++ b/docs/architecture/detail.mmd @@ -0,0 +1,34 @@ +flowchart TB + %% Solid arrows: runtime/data dependency; dotted arrows: optional, build or local-only boundary. + UI["CLI microphone/PCM and browser capture/upload"] + API["Flask validation, quotas and status/health routes"] + CONVERT["Bounded FFmpeg normalization and temp cleanup"] + DIAG["CLI FFT diagnostic before matching"] + FP["Local constellation fingerprints and index"] + MATCH["Dispatcher: RapidAPI, AcoustID, AudD, then local"] + CONFIG["Runtime configuration and provider policy"] + QUOTA["Atomic Supabase quota schema; in-memory mode"] + TOOLS["Fingerprint index construction and benchmarks"] + RUN["Gunicorn/container and deployment definitions"] + NORM["Shared validated AudioClip normalization"] + REMOTE["RapidAPI / AudD audio; AcoustID fingerprints"] + RESULT["Matched/no-match/not-configured/invalid/error results"] + SUPPORT["Supporting tests, assets, documentation and delivery config"] + ART["External album-art URLs"] + UI --> API + UI -. optional album art .-> ART + UI --> NORM + API --> CONVERT + CONVERT --> NORM + NORM --> MATCH + CONFIG --> API + CONFIG --> MATCH + API --> QUOTA + TOOLS --> FP + RUN -. configured entry .-> API + UI -. CLI diagnostic before matching .-> DIAG + MATCH -. local backend .-> FP + MATCH -. configured remotes .-> REMOTE + MATCH --> RESULT + RESULT --> UI + SUPPORT -. supports .-> UI diff --git a/docs/architecture/detail.png b/docs/architecture/detail.png new file mode 100644 index 0000000..717108e Binary files /dev/null and b/docs/architecture/detail.png differ diff --git a/docs/architecture/overview.mmd b/docs/architecture/overview.mmd new file mode 100644 index 0000000..b678dc7 --- /dev/null +++ b/docs/architecture/overview.mmd @@ -0,0 +1,34 @@ +%% Source-reviewed overview; 2026-10-03; commit 2671ccab1802f330083f122561e7ab6c2718dd9f +%% Solid edges: core flow. Dashed edges: optional or separately invoked services. +%%{init: {"theme":"base","securityLevel":"loose","fontFamily":"Arial, sans-serif","themeVariables":{"background":"#0b1220","primaryColor":"#17283d","primaryTextColor":"#edf4ff","primaryBorderColor":"#71c4ec","lineColor":"#9fadc1","secondaryColor":"#213548","tertiaryColor":"#17283d","edgeLabelBackground":"#0b1220","clusterBkg":"#101d2e","clusterBorder":"#456783","fontSize":"17px"},"flowchart":{"htmlLabels":true,"curve":"linear","nodeSpacing":35,"rankSpacing":50}}}%% +flowchart TD + I["Microphone / file input"] + W["CLI + Flask entry points"] + N["Validate + normalize audio"] + D["Matcher + fallback dispatch"] + L["Local hashes + fingerprint index"] + P["Optional remote providers"] + F["CLI FFT diagnostic"] + R["Status / result presentation"] + ART["External album-art URLs"] + I --> W + R -. optional album art .-> ART + W --> N + N --> D + N -.->|CLI diagnostic before matching| F + D -->|configured index| L + D -.->|configured audio/fingerprint request| P + L --> R + P -.->|provider response| R + N -->|invalid audio status| R + click ART "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/display.py" "Open source" + click I "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/main.py" "Open source" + click W "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/app.py" "Open source" + click N "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/recorder.py" "Open source" + click D "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click L "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fingerprint.py" "Open source" + click P "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/matcher.py" "Open source" + click F "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/shazam_project/fft_analyze.py" "Open source" + click R "https://github.com/icecold009/Audio-Recognition/blob/2671ccab1802f330083f122561e7ab6c2718dd9f/web/static/app.js" "Open source" + classDef core fill:#17283d,stroke:#71c4ec,stroke-width:1.6px,color:#edf4ff; + class I,W,N,D,L,P,F,R,ART core; diff --git a/docs/architecture/overview.png b/docs/architecture/overview.png new file mode 100644 index 0000000..a0f9ec9 Binary files /dev/null and b/docs/architecture/overview.png differ diff --git a/docs/architecture/publication.md b/docs/architecture/publication.md new file mode 100644 index 0000000..e9ce212 --- /dev/null +++ b/docs/architecture/publication.md @@ -0,0 +1,11 @@ +# Publication evidence + +Source snapshot: `2671ccab1802f330083f122561e7ab6c2718dd9f`. Publication parent: `b2ef7b1e7461a5fe56858e5773303632cbfc8bce`; target branch: `main`. The diagrams describe this pinned source snapshot, not all later application changes. + +![Overview](overview.png) + +![Subsystem detail](detail.png) + +Editable Mermaid, full tracked inventory, source maps and a read-only checker are included. Current structural checks and source snapshot boundaries are separate from app runtime, hosted/provider and deployment proof. PNG previews are verified by rendering and byte hashes rather than Jev binary review. + +The user authorized feature-branch commits, push and PR publication on 2026-10-04. Original unrelated edits and local application commits are preserved and excluded from these documentation commits. No merge or deployment is authorized. Observed Jev model: jev-1.13.0. 9 text files were covered by a complete-diff call, without text exclusions or truncation. All observed outcomes were no_clear_issue, but every gate remains resolve_findings_or_human_review. Exact typed results and non-empty usage are saved in [review.json](review.json). This generated receipt records the preceding source/documentation review; no green approval is claimed. diff --git a/docs/architecture/review.json b/docs/architecture/review.json new file mode 100644 index 0000000..bf967ec --- /dev/null +++ b/docs/architecture/review.json @@ -0,0 +1,43 @@ +{ + "date": "2026-10-04", + "sourceSnapshot": "2671ccab1802f330083f122561e7ab6c2718dd9f", + "publicationParent": "b2ef7b1e7461a5fe56858e5773303632cbfc8bce", + "scope": "Actual documentation publication patch before this generated receipt; PNGs independently rendered and inspected", + "coveredTextFiles": [ + "README.md", + "TODO.md", + "docs/architecture/README.md", + "docs/architecture/coverage.md", + "docs/architecture/detail.mmd", + "docs/architecture/overview.mmd", + "docs/architecture/publication.md", + "docs/architecture/verification.md", + "docs/architecture/verify.mjs" + ], + "excludedTextFiles": [], + "binaryPreviews": [ + "overview.png", + "detail.png" + ], + "reviews": [ + { + "model": "jev-1.13.0", + "gate": "resolve_findings_or_human_review", + "outcome": "no_clear_issue", + "confidence": 0.46, + "riskSignals": { + "correctness": 0.37, + "security": 0.13, + "regression": 0.09, + "test_gap": 0.47, + "context_gap": 0.52 + }, + "usage": { + "input_tokens": 16260, + "output_tokens": 499 + } + } + ], + "approvalClaim": false, + "mainMergeAuthorized": false +} diff --git a/docs/architecture/verification.md b/docs/architecture/verification.md new file mode 100644 index 0000000..0f6c3f8 --- /dev/null +++ b/docs/architecture/verification.md @@ -0,0 +1,107 @@ +# Documentation verification record + +Snapshot: `2671ccab1802f330083f122561e7ab6c2718dd9f`. Checks observed on 2026-10-03 in this isolated feature-branch copy. + +| Acceptance check | Observed evidence | +| --- | --- | +| Source and diagram links | 21 case-study/diagram references resolve; 8 root-embedded diagram click targets checked. | +| Root diagram fidelity | Embedded Mermaid equals overview.mmd after adapting relative source URLs to the root README location. | +| Tracked-file accounting | 69 snapshot paths assigned exactly once; no missing or duplicate paths. | +| Detail graph structure | 10 functional groups have diagram nodes; no dangling endpoints. | +| Preview rendering | Overview and detail Mermaid rendered successfully; separate output PNG previews inspected previously. No new PNG is proposed for this repository. | +| Previously truncated source | 11 contiguous redacted fragments cover all lines of 4 previously truncated files; each was sent in a successful Jev helper call. | +| Application behavior | Application runtime was not exercised in this documentation task. | + +These checks verify documentation structure and recorded review coverage. Inventory accounting does not establish every execution path, source conformance or hosted behavior. Fragment reviews retain their individual uncertainty; successful transmission is not approval. Jev thresholds remain unchanged. Integration remains pending unresolved warnings. No application code, dependency, schema, deployment or user data is changed. + +## Reproduce structural checks + +With Node.js and Git installed, run from the repository root: + +```sh +node docs/architecture/verify.mjs --self-test +``` + +The checker reads the explicitly pinned source snapshot, not the current HEAD, so a later documentation commit does not invalidate inventory accounting. It checks source paths, snapshot pinning, inventory equality, graph endpoints, Mermaid embed consistency and documentation links. Seven base structural failure cases cover inventory, paths, embeds, links and snapshot identity. The current checker has 10 intended-failure cases in total, including source-map checks; each must fail at its intended check. No files are changed by the checker. Node is an optional documentation-checking tool; this adds no application dependency. + +This checker does not parse the full Mermaid language, verify arrow semantics, access hosted services or prove all application behavior. Rendering was checked separately. A passing structural check does not replace source-conformance review. + +## Bounded source-claim review + +On 2026-10-04, jev-1.13.0 evaluated four critical source-behavior claims against selected implementation files or exact contiguous source fragments from this snapshot. Observed call usage: 7761 input tokens and 179 output tokens. All four typed results selected supported. + +| Claim | Typed result | Confidence | +| --- | --- | ---: | +| match_audio attempts RapidAPI, AcoustID, AudD, then the local matcher in that order. | supported | 1 | +| The dispatcher normalizes input, skips missing configuration, and stops after a matched response or another terminal status. | supported | 0.91 | +| The local matcher calls match_local_index and does not make a network request in match_audio_local. | supported | 1 | +| FFT analysis is a separate diagnostic/visualization module rather than the matching dispatcher. | supported | 1 | + +Source evidence: [shazam_project/matcher.py](../../shazam_project/matcher.py), [shazam_project/fingerprint.py](../../shazam_project/fingerprint.py), [shazam_project/fft_analyze.py](../../shazam_project/fft_analyze.py). Long-file fragments were reviewed with their original source path, commit and line ranges; this is bounded evidence, not a claim that every source file was supplied in one call. + +These semantic checks supplement the structural checker. They cover only the four claims listed, not every diagram arrow or execution path, and do not replace the complete-diff or plan approval gates. Integration remains blocked while those required gates are unresolved. + +## Complete diagram relationship source map + +Observed 2026-10-04: all **27 diagram arrows** have selected source ranges at pinned commit 2671ccab1802f330083f122561e7ab6c2718dd9f. Latest judgments support 26 arrows; W-to-N remains insufficient. Fourteen bounded calls used jev-1.13.0 with 47985 input/1318 output tokens, including historical additional-context and alternative-label judgments. Each call used at most six redacted excerpts, at most 10,000 characters each. Narrow judgments are separate from whole-diff approval and runtime/hosting evidence. + +The FFT labels were corrected: CLI main.py calls analyze_audio before match_audio and exits on diagnostic error, while the web route omits FFT. Both diagrams now show the additional optional artwork network boundary. No runtime, provider, quota schema, dependency or original checkout was changed. + +### Entry-helper disagreement + +The latest original W-to-N judgment is insufficient despite selected source showing main.py calls load_audio_file/record_microphone, web/app.py calls load_audio_file, and both recorder helpers return normalize_audio results. An alternative direct-helper wording received contradicted; it was not adopted. The typed responses provide no textual rationale, so no specific defect can be attributed to them. The original relationship is retained with this disagreement disclosed, rather than counted as Jev-supported. Direct static checks of pinned source are recorded separately; they do not manufacture a Jev approval. Integration remains held. + +### Source keys + +- [S1](../../main.py) +- [S2](../../web/static/app.js) +- [S3](../../web/app.py) +- [S4](../../shazam_project/recorder.py) +- [S5](../../shazam_project/matcher.py) +- [S6](../../shazam_project/display.py) +- [S7](../../shazam_project/config.py) +- [S8](../../scripts/build_fingerprint_index.py) +- [S9](../../shazam_project/fingerprint.py) +- [S10](../../Dockerfile) +- [S11](../../tests/test_web_pipeline.py) +- [S12](../../tests/test_display.py) + +O/D mean overview/detail. S ranges are inclusive pinned Git lines. The checker validates exactly one mapping per arrow and source range bounds. Ten intended-failure fixtures include a missing mapping, unknown source key and invalid range; these structural checks do not judge semantics. + +| Arrow | Source ranges | Latest typed judgment (confidence) | +| --- | --- | --- | +| O I --> W | S1:27-50, S2:550-583 | supported (0.97) | +| O W --> N | S1:27-50, S3:453-483, S4:81-127, S4:147-203, S4:205-258 | insufficient (0.46) | +| O N --> D | S1:62-72, S3:569-593, S5:184-215 | supported (0.96) | +| O N -.-> F | S1:51-72, S3:569-593 | supported (0.92) | +| O D --> L | S5:199-244, S5:447-457 | supported (0.99) | +| O D -.-> P | S5:78-98, S5:246-307, S5:364-395 | supported (0.96) | +| O L --> R | S5:447-457, S1:64-72, S6:11-45 | supported (0.96) | +| O P -.-> R | S5:209-244, S3:584-594, S2:584-619 | supported (0.97) | +| O N --> R | S1:43-50, S3:497-503, S5:184-198 | supported (0.99) | +| D UI --> API | S2:550-583, S3:546-569 | supported (1) | +| D UI --> NORM | S1:27-42, S4:193-203, S4:243-258 | supported (0.94) | +| D API --> CONVERT | S3:453-495, S4:299-363 | supported (1) | +| D CONVERT --> NORM | S3:474-483, S4:193-203 | supported (0.8) | +| D NORM --> MATCH | S5:184-215 | supported (0.99) | +| D CONFIG --> API | S3:568-578, S7:26-59 | supported (0.95) | +| D CONFIG --> MATCH | S5:78-90, S5:246-254, S5:364-374, S5:447-457 | supported (1) | +| D API --> QUOTA | S3:364-390, S3:410-436, S3:546-589 | supported (0.99) | +| D TOOLS --> FP | S8:10-27, S8:45-67, S9:154-189 | supported (0.99) | +| D RUN .-> API | S10:1-45, S3:24-32 | supported (0.99) | +| D UI .-> DIAG | S1:51-72, S3:569-593 | supported (0.93) | +| D MATCH .-> FP | S5:447-457, S9:201-239 | supported (1) | +| D MATCH .-> REMOTE | S5:199-215, S5:78-98, S5:291-307, S5:364-395 | supported (0.9) | +| D MATCH --> RESULT | S5:184-244 | supported (0.85) | +| D RESULT --> UI | S1:64-72, S6:11-45, S2:584-619 | supported (0.99) | +| D SUPPORT .-> UI | S11:1-80, S12:1-42 | supported (0.88) | +| O R .-> ART | S6:46-50, S2:619-633 | supported (0.92) | +| D UI .-> ART | S6:46-50, S2:619-633 | supported (0.82) | + +## Specific source-concern diagnosis + +A subsequent bounded diagnostic on 2026-10-04 used jev-1.13.0 with 5693 input/147 output tokens and redacted pinned source. The three separately judged call chains (CLI file, CLI microphone and web upload to shared normalization) each returned yes probability 0.96. No listed concrete contradiction was selected (confidence 0.99). This supports those individual facts, not a new whole-arrow or complete-diff approval. Earlier insufficient judgments remain disclosed above; the full-review gates and integration condition are unchanged. + +## Focused local execution evidence + +On 2026-10-04, all 44 existing tests in [test_recorder.py](../../tests/test_recorder.py), [test_audio_pipeline.py](../../tests/test_audio_pipeline.py) and [test_web_pipeline.py](../../tests/test_web_pipeline.py) passed against this pinned source. A disposable Python environment supplied pytest 8.4.2, NumPy 2.5.3, SciPy 1.18.1 and Flask 3.1.3. The workspace harness blocked socket connections, disabled dotenv loading, removed credential environment variables and used workspace fixture/cache paths. Microphone and provider boundaries were mocked. Earlier fixture setup errors were caused by an inaccessible system temp folder and resolved by changing only the harness paths. This is focused local input/normalization/upload evidence, not full-suite, device, FFmpeg-installation, dependency-lock, live provider, quota database, deployment or Jev gate clearance. diff --git a/docs/architecture/verify.mjs b/docs/architecture/verify.mjs new file mode 100644 index 0000000..1b10695 --- /dev/null +++ b/docs/architecture/verify.mjs @@ -0,0 +1,86 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; +import {execFileSync} from 'node:child_process'; +const dir=path.dirname(fileURLToPath(import.meta.url)),repo=path.resolve(dir,'../..'); +const remoteRepository='icecold009/Audio-Recognition'; +const read=f=>fs.readFileSync(path.join(repo,f),'utf8').replace(/\r\n/g,'\n'); +const fail=message=>{throw new Error(message);}; +const graphBlock=s=>s.match(/```mermaid\n([\s\S]*?)\n```/)?.[1]?.trim(); +function validate(c){ + const snapshot=c.coverage.match(/Snapshot: `([a-f0-9]{40})`/)?.[1]; + if(snapshot!==c.snapshot)fail('Snapshot mismatch'); + const listed=[...c.coverage.split('## File accounting')[1]?.matchAll(/^- `([^`]+)`$/gm)??[]].map(m=>m[1]); + if(new Set(listed).size!==listed.length)fail('Duplicate inventory path'); + if(JSON.stringify([...listed].sort())!==JSON.stringify([...c.paths].sort()))fail('Missing or extra inventory path'); + for(const f of listed)if(!c.exists(f))fail('Snapshot file missing: '+f); + if(graphBlock(c.caseStudy)!==c.overview.trim())fail('Case-study Mermaid differs from overview'); + const rootBlock=c.rootReadme.split('## Source-reviewed architecture overview')[1]; + if(!rootBlock||graphBlock(rootBlock)!==c.overview.trim().replaceAll('"../../','"'))fail('Root Mermaid differs from overview'); + if(graphBlock(c.coverage)!==c.detail.trim())fail('Coverage Mermaid differs from detail'); + let links=0,edges=0; + for(const [file,text] of [['docs/architecture/overview.mmd',c.overview],['docs/architecture/detail.mmd',c.detail]]){ + const nodes=[...text.matchAll(/^\s+(\w+)\[/gm)].map(m=>m[1]); + if(new Set(nodes).size!==nodes.length)fail('Duplicate diagram node'); + for(const m of text.matchAll(/^\s+(\w+)\s+(?:-->|<-->|-\.(?:->|[^\n]*?\.->))(?:\|[^|]*\|)?\s*(\w+)/gm)){ + if(!nodes.includes(m[1])||!nodes.includes(m[2]))fail('Dangling diagram endpoint');edges++; + } + for(const m of text.matchAll(/click \w+ "([^\"]+)"/g)){ + const target=m[1],remote=target.match(/^https:\/\/github\.com\/([^/]+\/[^/]+)\/(?:blob|tree)\/([^/]+)\/(.+)$/); + if(remote){if(remote[1]!==remoteRepository||remote[2]!==c.snapshot||!c.exists(decodeURIComponent(remote[3])))fail('Unpinned or missing source target');} + else if(/^https?:/.test(target))fail('Unrecognized diagram source URL'); + else if(!c.exists(path.relative(repo,path.resolve(repo,path.dirname(file),decodeURIComponent(target)))))fail('Missing diagram link'); + links++; + } + } + for(const [file,text] of [['docs/architecture/README.md',c.caseStudy],['docs/architecture/coverage.md',c.coverage],['docs/architecture/verification.md',c.verification]]){ + for(const m of text.matchAll(/\]\(([^)]+)\)/g)){ + if(/^https?:|^#/.test(m[1]))continue; + const local=path.relative(repo,path.resolve(repo,path.dirname(file),decodeURIComponent(m[1]))); + if(!c.exists(local))fail('Missing documentation link');links++; + } + } + const key=s=>s.match(/^\s*(\w+)/)?.[1]+(s.includes('<-->')?'<-->':'->')+s.match(/(\w+)\s*$/)?.[1]; + const expected=[...c.overview.split('\n').filter(s=>/^\s+\w+\s+(?:-->|<-->|-\.)/.test(s)).map(s=>'O:'+key(s)),...c.detail.split('\n').filter(s=>/^\s+\w+\s+(?:-->|<-->|-\.)/.test(s)).map(s=>'D:'+key(s))].sort(); + const sources=new Map([...c.verification.matchAll(/^- \[(S\d+)\]\(\.\.\/\.\.\/([^)]+)\)$/gm)].map(m=>[m[1],m[2]])); + const rows=[...c.verification.matchAll(/^\| ([OD]) ([^|]+) \| ([^|]+) \|/gm)]; + if(JSON.stringify(rows.map(m=>m[1]+':'+key(m[2])).sort())!==JSON.stringify(expected))fail('Source map misses or duplicates an arrow'); + for(const row of rows){ + const ranges=[...row[3].matchAll(/\b(S\d+):(\d+)-(\d+)/g)]; + if(!ranges.length)fail('Missing source range'); + for(const range of ranges){ + const file=sources.get(range[1]);if(!file||!c.paths.includes(file))fail('Unknown source key'); + if(/(?:^|\/)(?:\.env|secrets|credentials)(?:\.|\/|$)|\.(?:pem|key|db|sqlite)$/i.test(file))fail('Sensitive source range refused'); + if(Number(range[2])<1||Number(range[3])c.sourceLines(file))fail('Invalid source range'); + } + } + return {snapshot,inventoryPaths:listed.length,links,edges,sourceMappedArrows:rows.length}; +} +try{ + const coverage=read('docs/architecture/coverage.md'),snapshot=coverage.match(/Snapshot: `([a-f0-9]{40})`/)?.[1]; + if(!snapshot)fail('Missing full snapshot commit'); + const paths=execFileSync('git',['-c',`safe.directory=${repo.replaceAll('\\','/')}`,'-C',repo,'ls-tree','-rz','--name-only',snapshot],{encoding:'utf8',stdio:['ignore','pipe','pipe']}).split('\0').filter(Boolean); + const exists=f=>{const full=path.resolve(repo,f);return full.startsWith(repo+path.sep)&&fs.existsSync(full);}; + const lineCache=new Map(); + const sourceLines=file=>{if(!lineCache.has(file)){const content=execFileSync('git',['-c',`safe.directory=${repo}`,'-C',repo,'show',`${snapshot}:${file}`],{encoding:'utf8',maxBuffer:2*1024*1024,stdio:['ignore','pipe','pipe']});lineCache.set(file,content.split(/\r?\n/).length);}return lineCache.get(file);}; + const c={snapshot,paths,coverage,overview:read('docs/architecture/overview.mmd'),detail:read('docs/architecture/detail.mmd'),caseStudy:read('docs/architecture/README.md'),rootReadme:read('README.md'),verification:read('docs/architecture/verification.md'),exists,sourceLines}; + const result=validate(c); + let negativeChecks=0; + if(process.argv.includes('--self-test')){ + const brokenDetail=c.detail+'\n SUPPORT --> MISSING_NODE\n'; + const mutants=[ + [{...c,paths:c.paths.slice(1)},'Missing or extra inventory path'], + [{...c,coverage:c.coverage+'\n- `'+c.paths[0]+'`\n'},'Duplicate inventory path'], + [{...c,exists:f=>f!==c.paths[0]&&exists(f)},'Snapshot file missing:'], + [{...c,detail:brokenDetail,coverage:c.coverage.replace(graphBlock(c.coverage),brokenDetail.trim())},'Dangling diagram endpoint'], + [{...c,rootReadme:c.rootReadme.replace('## Source-reviewed architecture overview','## Removed architecture overview')},'Root Mermaid differs from overview'], + [{...c,caseStudy:c.caseStudy+'\n[broken](missing-documentation-link.invalid)\n'},'Missing documentation link'], + [{...c,coverage:c.coverage.replace(c.snapshot,'0'.repeat(40))},'Snapshot mismatch'], + [{...c,verification:c.verification.replace(/^\| O I --> W \|[^\n]+\n/m,'')},'Source map misses or duplicates an arrow'], + [{...c,verification:c.verification.replace(/S\d+:(\d+)-/,'S999:$1-')},'Unknown source key'], + [{...c,verification:c.verification.replace(/S\d+:\d+-/,'S1:0-')},'Invalid source range'], + ]; + for(const [m,expected] of mutants){let reason='';try{validate(m);}catch(error){reason=error.message;}if(!reason.startsWith(expected))fail('Negative fixture did not fail at its intended check: '+expected);negativeChecks++;} + } + console.log(JSON.stringify({...result,negativeChecks,scope:'read-only documentation structure; not semantic, runtime, hosted or renderer proof'})); +}catch(error){console.error('Architecture verification failed: '+error.message);process.exitCode=1;}