07 / 14 · audits
Spectrum Provenance Audit
Flags reflectance curves that look interpolated, smoothed, or synthesized rather than measured.
The problem
Spectral collections routinely mix real measurements with resampled, model-fitted, and emulated curves, and the provenance metadata often does not say which is which. Detecting synthetic images is a mature field; the same question for reflectance curves has had no tooling at all. Build on a spectrum that was never measured and every downstream number inherits that fiction silently.
The method
The audit runs six physically motivated detectors on the canonical 38-sample grid. A DCT high-frequency energy ratio catches curves missing the small noise floor real spectrophotometry always carries; third-difference statistics catch analytic or spline-generated smoothness; vanishing second differences catch linear interpolation from a coarser grid; a distinct-value ratio catches values sitting on a coarse quantization lattice; runs of identical band-edge samples catch flat-clamped extrapolation; and samples pinned at exactly 0 or 1 catch range clipping. Each detector reports a severity from 0 to 1 with a written evidence string, and the measured-likeness score starts at 1 and subtracts the weighted severities. The framing borrows from synthetic-image detection, where frequency-domain generator fingerprints and color-statistics detectors are established, and applies that question to reflectance curves.
What it promises
- Evidence, not a bare verdict: every flagged artifact carries a named code, a severity from 0 to 1, and a human-readable evidence string, alongside the raw metrics they were computed from.
- A measured-likeness score from 0 (strongly synthetic) to 1 (consistent with a real measurement), version-stamped: every response carries engine_version and dataset_snapshot.
- The calibration caveat ships inside every response as a machine-readable field, so a downstream agent cannot silently drop it.
- Fails loudly: fewer than 8 samples is an error, and tristimulus inputs are refused because a color has no unique spectrum.
Calling it
{
"tool": "audit_spectrum_provenance",
"arguments": {
"inputs": [
{
"space": "record",
"id": "syn-0000-blue-pigment"
},
{
"space": "spd",
"values": [
0.062,
0.064,
0.071,
0.083,
0.102,
0.131,
0.169,
0.214,
0.266,
0.318,
0.365,
0.401,
0.423,
0.431,
0.428,
0.416
],
"wavelengths_nm": [
400,
420,
440,
460,
480,
500,
520,
540,
560,
580,
600,
620,
640,
660,
680,
700
]
}
]
}
} Clone the repo, run cd mcp && npm install && npm run build, then register with: claude mcp add maryslab -- node <repo>/mcp/dist/server.js
Known limits
- Thresholds are calibrated on synthetic negatives (curves we degraded by known interpolation and smoothing) plus smooth analytic positives, so the score is a triage signal, not proof.
- Run against 1,752 published USGS spectra, the score does not separate them from an analytic model: median 0.678 against 0.667, with the noise-floor flag firing on 1,630 of them. This is not our resampling — the same spectra score lower at native spectrometer resolution — but the library publishing processed data. Use the instrument to rank a corpus, never to judge a single record. TR-13 reports this in full.
- Inputs off the canonical 38-sample grid are resampled before auditing, so the verdict describes the resampled curve, not your raw file.
- The score measures the absence of six known artifacts, not intent: a synthesized curve with realistic noise added can pass.