Exports
What can you hand to someone else, and what is actually in it?Reading the mode from the URL…
MonitorExports
demoThis build is a demo. The catalog and detections are a fixed sample.Scopereading…Sound is used for one thing: a short tone when a long scan finishes while this tab is in the background. The A/B listening check plays audio either way, because there the sound is the evidence.Reading the mode from the URL…
The service streams the file. It is not rebuilt here: the stream carries the detection row as the database names it — a superset of the 22 columns the sample builds — and stamps the scope and the row count into x-choon-scope and x-choon-row-count, so the count travels with the file rather than staying on the screen that produced it.
This link sends no filter, so the file is the whole scope — the route takes claim_status, decision_state, review_state, ownership and search, and none of them is wired to a control here. The header the file carries says what it was counted over either way, which is the half that has to be right.
An empty field means the console does not have the value. The em dash is a screen convention and does not travel into a file, where a parser would read it as a value. Two claim columns travel: claim_status is empty where reconciliation has never seen the row, and claim_status_resolved says not_reconciled — collapsing them would make a never-adjudicated detection look adjudicated on somebody else’s desktop.
Two write routes, and they produce different objects. Recording an export request writes a row stamped with the scope query and the versions in force — the row exists whether or not the file is ever fetched, which is what makes an export auditable. Building an evidence pack produces an actual artifact and points its detections at it.
POST /api/monitor/exports writes a row in state running carrying the scope query and the model and catalog version in force. It does not produce the file: the CSV is served synchronously from /api/monitor/export.csv, and the two are separate objects on purpose — the row is the record that somebody asked, which survives the file being deleted.
POST /api/monitor/exports/evidence-pack builds the L4 artifact §13.11 calls “the object that converts a demo into a contract”: pack.json, detections.csv, a server-rendered plot per detection, the per-window points and the audit trail. With no scope query it covers every detection in the tenant.
Drop an evidence pack here and this checks every digest inside it, then checks the signature against the key this deployment publishes. Nothing is stored. The file is read, checked, and the answer returned.
Reading the published key…
Neither route contacts a platform. This service holds no rights-platform credential, every write lands in Postgres or in $AUDIO_BUCKET, and notified_at remains a column nothing writes. Nothing here files a claim or sends a notice.
No actor is sent. actor_from() reads X-Choon-Actor and falls back to the literal string unauthenticated; this app has no identity, so it sends no header and the export row records that fallback. An invented name on an evidence artifact would be worse than an honest blank.
Reading the export history…
One pack per scope query, and the L4 forensic export §14.5 specifies is what each detection contributes to it. How complete a pack would be is a count with its base, not a yes or a no — a detection whose per-window points were never written contributes an absence, and the pack ships the absence rather than an empty axis.
The per-detection breakdown is not read on this surface.
It needs the detection rows, and this page reads only GET /api/monitor/exports. Each detection states its own pack availability on its evidence page, beside the fields it is counting — the same lib/evidence-pack.ts reading in both places, so the two cannot disagree about what a pack is. Open one from the queue.
Nothing can be scheduled from this console.
monitor_exports records an export request with its scope query and the versions in force, and carries no cadence column; no route accepts one. The one cadence in the schema, monitor_sources.cadence_cron, schedules SCANS rather than reports — reading it as a report schedule would be inventing a capability out of a neighbouring column. §1 is why it matters: the RIAA deliverable is due within three days and must be “generated without manual intervention”, so a human pressing a button is not the shipping form of this.
§13.15 gives the anchor customer’s format two screens the sitemap does not have — /reports/coverage for the ISRC metadata report and /reports/streams for the per-detection CSV. Neither is in this build.
The confidence integer 0–99 the RIAA format requires is not in this file.
It is the single exemption to §6.6’s ban on printed confidence — the export carries the integer, the interface carries the band — and this CSV carries the band instead, because the mapping is server-side (scripts/riaa_stream_analyzer.py’s _conf_to_0_99) and a second mapping written in the browser would be a second opinion about a number a signed declaration is attached to.