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. They have not been validated against verified instrument data, so treat the score as a triage signal, not proof.
- 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.