Commit 657e4b6
feat(upload): read shipboard CTD files into the core model (plan W1)
An uploaded cast can now be QC'd before it reaches a release. The design
principle that makes this cheap: every rule targets obs/sample, so projecting a
file into that shape runs the whole registry unchanged — no rule learns anything
about where the data came from.
FORMATS, and what each costs
.csv the CalCOFI cast file; maps through measurement_type.csv _source_column,
which already holds exactly those names.
.cnv Sea-Bird converted. Its `# name N =` header names every column, so there
is nothing to infer. PREFERRED.
.asc Sea-Bird ASCII. Same vocabulary, but see below.
.btl bottle summary: one Date header word over three data fields, several
tagged statistic rows per bottle.
.hex REFUSED, with the reason. It is raw A/D counts; converting it needs the
.xmlcon calibration file. A best-effort conversion would be invented
numbers presented as measurements, which in a QC tool is the worst
possible output.
THE TRAP IN .asc, measured not assumed
The header is fixed-width and adjacent names RUN TOGETHER —
`Sbeox0ML/LSbeox0Mm/Kg`. In 179 of 200 CalCOFI files a whitespace split gives the
wrong column count and silently mis-assigns every column after the collision.
Both names and numbers are right-aligned, so sbe_split_header() cuts the header at
the data rows' stop positions. When the result is not self-consistent it ERRORS
and asks for the .cnv rather than guessing. Measured across the archive: ~86% of
.asc and ~47% of .btl read cleanly; the rest say why.
MAPPING
Two vocabularies, one answer, both in reviewable registries rather than in code:
the CalCOFI names through measurement_type.csv, the Sea-Bird names through the new
metadata/sbe_name_map.csv. Unmapped columns are a RESULT, not an error — they are
where a format change announces itself. Raw voltages are unmapped deliberately
(which sensor a V0 is depends on the wiring), and FlECO-AFL is left unmapped
because the registry carries the fluorometer VOLTAGE, so mapping the converted
value would silently change units.
The projection applies the same two repairs the pipeline already knows — the -99 /
-9.99e-29 sentinels are deleted, and quality codes stored as "9.0" are stripped
textually (not via an integer cast, which would round an unexpected "9.5") —
because a new file is exactly where those arrive.
Also: qc_cast_profile's sibling qc_upload_con() makes the upload obs / sample /
obs_ctd_full in memory, so an uploaded cast (which IS full resolution) gets the
profile rules too rather than skipping them.
Verified end to end on a real .btl from the CalCOFI archive: all 16 rules ran,
5 correctly reporting skip because that bottle file carries no temperature_ave.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GEVWNQXLvWzz25oF8hqESd1 parent 704aa20 commit 657e4b6
13 files changed
Lines changed: 971 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| 58 | + | |
| 59 | + | |
58 | 60 | | |
59 | 61 | | |
60 | 62 | | |
| |||
142 | 144 | | |
143 | 145 | | |
144 | 146 | | |
| 147 | + | |
145 | 148 | | |
146 | 149 | | |
147 | 150 | | |
148 | 151 | | |
| 152 | + | |
149 | 153 | | |
150 | 154 | | |
151 | 155 | | |
152 | 156 | | |
153 | 157 | | |
154 | 158 | | |
155 | 159 | | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
156 | 164 | | |
157 | 165 | | |
158 | 166 | | |
| |||
162 | 170 | | |
163 | 171 | | |
164 | 172 | | |
| 173 | + | |
165 | 174 | | |
166 | 175 | | |
167 | 176 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
32 | 63 | | |
33 | 64 | | |
34 | 65 | | |
| |||
0 commit comments