Anomaly Upload Validator · Specification artifact
Data Dictionary
Every field, its source schema, and how it maps across vendor, platform, and client.
This page is rendered from that DOCX. Same document, same words.
Anomaly Upload Validator , Data Dictionary
Internal Tool · v3.1.4 · September 2026
About this revision
Updated 2026-09-17 from v2.1 to v2.7, then extended 2026-09-18 to v3.1.4. Three kinds of change in the first pass:
1. Output schema. The D/E/F columns were split (v2.5). Asset now carries the blade letter; turbine and asset serial numbers are separate fields.
2. Sanitization. Generic labels were inconsistent across the previous revision (four competing forms, some producing ungrammatical sentences). The whole document now uses one scheme, defined below.
3. Verification flags. Items marked [verify] could not be confirmed from the change log alone and need checking against a current export before this document is treated as authoritative. They are listed together in "Open verification items" at the end.
The tool's own version header and its working file advance together: v2.x / v8.x through v2.7.1, v3.x / v9.x since. This document describes v3.1.4 (working file v9.1.4).
The second pass, on 2026-09-18, carried the document from v2.7 to v3.1.4. That range is four defect fixes: the header misrenderings below (v2.7.1); a date fault that shifted CSV dates back a day west of UTC and made every dated row fail its own YYYY-MM-DD check in every timezone (v3.0); two output columns that wrote an empty cell under a correct header because the export looked them up by header text rather than canonical name (v3.1); and the export's column-width list, one entry short since the v2.5 split and so shifting every width from column E onward onto its right-hand neighbour (v3.1.1 through v3.1.4).
Generic labels used in this document
This is an internal tool operating between three commercial systems. Their names, and the contents of the conversion tables between them, are withheld. The structure is not.
| Label | Means |
|---|---|
| Input Source | The inspection platform the raw dataset is exported from. Column A of the Conversions tab. |
| Platform A | The platform the dataset is being loaded into. Column B of the Conversions tab. |
| Platform B | The manufacturer's system the report is ultimately delivered in. Column C of the Conversions tab. |
Conversion runs Input Source, then Platform A, then Platform B. All three classify the same physical damage differently, which is the problem this tool exists to solve.
Overview
This data dictionary defines every field the Anomaly Upload Validator processes, from the raw Input Source export columns through to the derived conversion columns in the exported XLSX. It covers field names, source column mappings, data types, classification, validation rules, and conversion output targets.
Field Classification Key
| Classification | Meaning |
|---|---|
| Required | Must be present and non-empty in every data row. Missing or invalid values raise an Error. |
| Conditional | Optional. No flag raised if absent or empty. Format validated only when populated. |
| Check Internally | Required in principle but may exist in internal records. Empty gives a Check Internally flag, not an Error, and is excluded from the compliance score. |
| Raw | Source columns used only as inputs to derivation formulas. Not directly validated. |
| Derived | Computed by the tool from raw source columns. Written to the output XLSX as lookup formulas. |
Column Alias Map
The tool normalizes the following column name variants before validation. Applied silently at ingestion.
| Raw Column Name | Normalized To | Notes |
|---|---|---|
Date | Inspection Date | Input Source uses 'Date'; Platform A requires 'Inspection Date' |
Blade Chamber | BladeChamber | Space removed to match the Platform A column spec |
Chord (%) | Chord(%) | Parenthetical formatting normalized |
Turbine Serial Number | Serial Number | Input Source full label mapped to the Platform A short label. [verify] This alias predates the v2.5 D/E/F split and may now be ambiguous, since two serial-number fields exist. |
Links | Source Images | Input Source uses 'Links'; Platform A expects 'Source Images' |
Since v2.3 the alias map is a fallback rather than the primary mechanism. Columns are matched by content as well as by name: see "Column matching" below.
Column matching
Added v2.3. Input files vary in column order, column names, and sheet structure, so a fixed-layout assumption failed on any file that did not match the canonical structure exactly.
The matcher runs two passes. First a header-alias match, priority-ordered so that a more specific alias wins over a general one. Second a data-shape fingerprint, comparing each candidate column's values against the expected shape of the field. Where alias matches are ambiguous, the closer shape match wins. Where shape scores tie, the column with more distinct values wins, which resolves the case of two identically named columns holding different things at different levels of the record.
The header row is detected automatically and is not assumed to be row 1: up to 25 rows of metadata preamble above the header are scanned and skipped. A collapsible confirmation panel shows which input column was bound to each canonical field.
Field Reference
All fields listed in the order they appear in the Damages Report output tab.
Output column letters confirmed 2026-09-17 against a current export header row. All previously flagged letters are resolved. The layout below is the real one, and it differs from the v2.1 document in more than position: four fields moved, two were removed, and one is new.
| Field Name | Col | Source Column(s) | Type | Classification | Format / Validation Rule |
|---|---|---|---|---|---|
ID | A | ID | String | Required | Any non-empty value |
Site | B | Site | String | Required | Any non-empty value |
Turbine | C | Turbine | String | Required | Any non-empty value |
Asset | D | Blade / Asset (extracted) | String | Required | Single letter A to C. Changed at v2.5: carries the BLADE LETTER, not a turbine identifier. Extracted from a dedicated Blade column, a Blade Position column, a full label, or a bare letter. |
Turbine Serial Number | E | Asset (input column) | String | Conditional | New at v2.5. Carries the value previously written to the output Asset column. |
Asset Serial Number | F | Serial Number (input column) | String | Conditional | New at v2.5. Carries the value previously written to the output Serial Number column. |
Severity | G | Severity | Integer | Required | Must be exactly 1, 2, 3, 4, or 5 |
Critical | H | Critical | String | Required. See D-5, open. | "Yes" or "No", case-insensitive |
Propagation Type | I | Propagation Type | String | Conditional | Preserved unchanged |
Date | J | Date / Inspection Date (alias) | Date | Required | Must match YYYY-MM-DD exactly. The output header is Date, not Inspection Date. |
OpSeverity | K | OpSeverity | String | Conditional | Preserved unchanged |
Monitoring Recommendation | L | Monitoring Recommendation | String | Conditional | Preserved unchanged |
Damage Location | M | Damage Location | String | Required. See D-5, open. | "Internal" or "External", case-insensitive |
Component | N | Component | String | Raw | Base of the component concatenation |
Material | O | Material / Element | String | Raw | Carries the effective suffix for both formats: Material for Format A, Element for Format B. The header stays Material either way. |
Input Source Component | P | Derived | String | Derived | Concatenation of N and O. Lookup key for Q and R. |
Platform A Element | Q | Derived | String | Derived | Lookup on P, column 2 |
Platform B Element | R | Derived | String | Derived | Lookup on P, column 3 |
Type | S | Type / Anomaly Type | String | Raw | Carries the damage base for both formats: Type for Format A, Anomaly Type for Format B. The header stays Type either way. |
Subtype | T | Subtype | String | Raw | Optional. Appended to the base if non-empty. |
Input Source Damage Type | U | Derived | String | Derived | Concatenation of S and T. Lookup key for V and W. |
Platform A Anomaly Type | V | Derived | String | Derived | Lookup on U, column 2 |
Platform B Anomaly Type | W | Derived | String | Derived | Lookup on U, column 3 |
Blade Side | X | Blade Side | String | Required | Code 1 / Value 1 / Code 2 / Value 2 / Code 3 / Value 3 / Code 4 / Value 4 |
Platform A Blade Side | Y | Derived | String | Derived | Direct lookup on X, column 2 |
Platform B Blade Side | Z | Derived | String | Derived | Direct lookup on X, column 3 |
Blade Chamber | AA | Blade Chamber | String | Conditional | Any value, no format rule. The output header is Blade Chamber with a space, not BladeChamber. |
Distance (m) | AB | Distance (m) | Decimal | Required | Numeric, float noise cleaned to 4dp |
Length (m) | AC | Length (m) | Decimal | Required | Numeric, float noise cleaned to 4dp |
Width (m) | AD | Width (m) | Decimal | Required | Numeric, float noise cleaned to 4dp |
Chord (%) | AE | Chord (%) | Decimal | Conditional | Numeric if present, float noise cleaned to 4dp |
Action | AF | Action | String | Conditional | Preserved unchanged |
Rule | AG | Rule | String | Conditional | Preserved unchanged |
Coordinates | AH | Coordinates | String | Check Internally | At least 3 [x,y] pairs. Empty gives a Check Internally flag. |
Source Image Reference | AI | Source Image Reference | String | Required | Identifier, not a URL. No hyperlink attached. |
Links | AJ | Links | String | Required | URL value. Hyperlink attached since v2.6. |
Source Images | AK | Source Images | String | Required | URL value. Hyperlink attached since v2.6. |
Source Image Expiration Date | AL | Derived or passed through. [verify] | Date | [verify] | Not documented anywhere. Present in the current export, absent from the v2.1 dictionary and from the change log. See open items. |
Tasks | AM | Tasks | String | Conditional | Preserved unchanged |
Output header names were misrendered in four of eight derived columns. FIXED in v2.7.1.
Corrected in v2.7.1 (working file v8.9.1) on 2026-09-17, verified against a live export, and carried forward unchanged since. All four headers now render both company names correctly. Retained as a record of the defect and of what it showed about the "preserved intentionally" note, not as a description of current behaviour.
The defect as it stood through v2.7: two separate name errors, neither applied consistently.
| Col | Header through v2.7 | Error |
|---|---|---|
| P | Source-system name, lower-cased mid-word | Casing |
| Q | Platform A name, two letters transposed | Transposition |
| R | Platform B name | Correct |
| U | Source-system name, lower-cased mid-word | Casing |
| V | Platform A name | Correct |
| W | Platform B name | Correct |
| Y | Platform A name, two letters transposed | Transposition |
| Z | Platform B name | Correct |
Four of the eight derived columns carried a wrong rendering of a company name. Two different companies, two different kinds of error, and the same name appeared correct in one column and wrong in another.
This settled how the typo item should be read. The v2.1 limitation log records the misspelling as preserved intentionally, which implied a downstream consumer matching on that exact string. A deliberately preserved convention would have been consistent. Four of eight, with one name spelled both ways in the same sheet, was accumulated copy error rather than convention.
Consequences worth stating plainly:
- A consumer matching these columns by header string had to match two spellings of one name to catch all three of its columns. Exports produced before v2.7.1 still carry the old headers, so that remains true when reading one of them.
- Correcting all four was a single normalization, not a schema negotiation. Nothing depended on a misrendered form.
- The question for Engineering was not "may I fix the spelling" but "what matched on those strings when they were preserved, and does it still". Answered in the closure below.
- Only the transposition was ever tracked, as LIM-07. The casing error was never recorded anywhere and was found during this revision. Both were corrected together in v2.7.1.
LIM-07: CLOSED, 2026-09-18. Closed by the v2.7.1 correction, verified against the header row of a live export read from the raw file rather than from a summary.
It is closed as copy error, not convention. The v2.1 log recorded the misspelling as preserved intentionally, which implied a downstream consumer matching on that exact string. Nothing did. Before the correction the tool was searched for all four misrendered strings: every occurrence was on the output side, and the input-side column matcher — both its alias map and its field signatures — contained neither spelling. No ingestion path depended on a misrendered form, so none was made tolerant of one, and files exported before the change ingest exactly as they did before. The question this document put to Engineering, "what matched on those strings when they were preserved, and does it still", is answered: nothing did, and nothing does.
The casing error takes no entry of its own. It was found and fixed within the same change, so it was never an open item.
Scope note: the v2.1 limitation log that holds the LIM-07 entry is not part of this sanitized document set. This records the closure; if that log is maintained separately it still shows LIM-07 open and needs the same update.
Sanitized note: these headers appear in this document under generic labels, so neither error surfaces here. Both are recorded because they describe every export produced up to v2.7.1, which anyone opening an older file will still see.
What changed against the v2.1 document, beyond position
Bladeis gone as an output column.Assetin column D represents it fully. This closes the open question from the v2.5 entry.Recommendationis gone. It was listed in the v2.1 dictionary and does not appear in the current export.LinksandSource Imagesare both present as separate columns. The v2.1 alias map saidLinksnormalizes toSource Images. The export carries both, so that alias entry describes ingestion only, not the output layout.- Four fields moved forward. Propagation Type, OpSeverity and Monitoring Recommendation now sit at I, K and L, between Critical and Damage Location, rather than near the end.
Datemoved to J. Source Image Expiration Dateis new and undocumented.
Note on the pass-through fields. Propagation Type, OpSeverity, Monitoring Recommendation and Tasks were defined in this document at v2.1 and were correct. What was wrong was the tool: the matcher held no field signatures for them, so it never bound the input column and the export wrote a header with nothing beneath it. Signatures were added at v2.4. The definitions did not change.
Derived Fields
Computed by the tool from raw source columns. Written as lookup formulas in the output XLSX.
Column references confirmed 2026-09-17. The change log's references to a Material slot at N and a Type slot at R, and this document's previous references to O, T and W, were all pre-v2.5 values. The v2.5 insertion shifted every one of them by exactly one position, which is why the two sets never reconciled. The values below are post-v2.5 and match the current export.
| Field | Col | Formula |
|---|---|---|
Input Source Component | P | IF(LEN(O2)>0, N2&" - "&O2, N2) |
Platform A Element | Q | IFERROR(VLOOKUP(P2, Conversions!A:C, 2, FALSE), "MANUAL REVIEW: "&P2) |
Platform B Element | R | IFERROR(VLOOKUP(P2, Conversions!A:C, 3, FALSE), "MANUAL REVIEW: "&P2) |
Input Source Damage Type | U | IF(LEN(T2)>0, S2&" - "&T2, S2) |
Platform A Anomaly Type | V | IFERROR(VLOOKUP(U2, Conversions!A:C, 2, FALSE), "MANUAL REVIEW: "&U2) |
Platform B Anomaly Type | W | IFERROR(VLOOKUP(U2, Conversions!A:C, 3, FALSE), "MANUAL REVIEW: "&U2) |
Platform A Blade Side | Y | IFERROR(VLOOKUP(X2, Conversions!A:C, 2, FALSE), "MANUAL REVIEW: "&X2) |
Platform B Blade Side | Z | IFERROR(VLOOKUP(X2, Conversions!A:C, 3, FALSE), "MANUAL REVIEW: "&X2) |
Row 2 shown as the example row. LEN() is used rather than ISBLANK() because ISBLANK() returns FALSE for an empty-string cell, which produced a trailing separator on the derived value. Fixed at v2.1.
Derivation rule, added v2.4. Any raw input value the export needs is read from the untouched input row, never from the working row. The row object is mutated during derivation, so reading a value back from it after processing returns the already-transformed value and concatenates it a second time.
Format handling, added v2.4. The formulas reference the output slots rather than the raw input columns, so one formula path serves both input formats. The output Material slot carries the effective suffix, Material for Format A and Element for Format B. The output Type slot carries the damage base, Type for Format A and Anomaly Type for Format B.
Dataset Format Variations
Two distinct Input Source export formats are handled. Format is detected automatically.
| Field | Format A | Format B | Detection Logic |
|---|---|---|---|
| Element source | Component + Material | Component + Element | Check whether a Material column exists |
| Element formula | Component & " - " & Material | Component & " - " & Element | LEN(Material)>0 uses Material, else Element |
| Damage Type source | Type + Subtype | Anomaly Type + Subtype | Check whether a Type column exists |
| Damage Type formula | Type & " - " & Subtype | Anomaly Type & " - " & Subtype | LEN(Type)>0 uses Type, else Anomaly Type |
| Blade field | Empty, extracted from Asset | "Blade A", letter extracted | Accepts a full label, a bare letter, a Blade column, or a Blade Position column |
Provenance note. Format B support was built against illustrative reconstructed examples and was first confirmed against a genuine Input Source export later. Treat any Format B behavior not exercised by a real file as unverified.
Conversion Lookup Tables
The three lookup tables live in the Conversions tab of the exported XLSX. Columns are A (Input Source) then B (Platform A) then C (Platform B).
What is published here and what is not. The structure of the conversion problem is described below. The tables themselves are not, because the category names, code values and the mappings between them are the commercial property of the platforms and the manufacturers involved. The redaction is deliberate and is marked where it applies rather than left as a silent gap.
Structure, which is publishable:
- Three separate taxonomies are in play, and none of them classifies damage the same way.
- The mapping between them is uneven in both directions: some source categories collapse together downstream, others split apart.
- Severity is an ordinal scale.
- Some source categories have no clean target at all. These are held for manual review rather than guessed at, which is why conversion is a decision with exceptions rather than a lookup.
Illustrative shape only, with invented values:
[input category A] -> [platform A category 2] -> [platform B code X]
[input category B] -> [platform A category 2] -> [platform B code X]
[input category C] -> (no clean target) -> held for manual review
Element / Component Conversions
Lookup key: Input Source Component.
[Table withheld. See the redaction note above.]
Anomaly Type Conversions
Lookup key: Input Source Damage Type.
[Table withheld. See the redaction note above.]
Blade Side Conversions
Lookup key: Blade Side, a direct lookup with no concatenation.
[Table withheld. See the redaction note above.]
Table currency
The tool currently uses the original key set. A reconciled union table built from the conversion tables of genuine delivered files is staged but not wired in, pending confirmation of four conflicting mappings where the same source value resolves to different targets in files of different dates.
Reconciliation rule. The tables reconcile by union, not intersection. A key absent from one client's table is a key that client's data has never needed. Absent does not mean retired, and pruning on that basis would silently drop valid mappings.
Validation Status Reference
| Status | Trigger | Compliance Score | Export Gate |
|---|---|---|---|
| Error | Required field missing or format invalid | Counts against score | Does not block export |
| Manual Review | Concatenated value not found in the conversion table | Counts against score | Blocks export until resolved |
| Check Internally | Field empty where the value may exist in internal records | Excluded from score | Does not block export |
| Warning | Conditional field format invalid | Counts against score | Does not block export |
Manual Review flags can be resolved in bulk from within the tool rather than row by row (added v2.2). The export button stays disabled until every Manual Review flag is cleared.
Compliance Score Formula
Score = ROUND( cleanRows / (totalRows - checkInternallyRows) * 100, 0 )
cleanRows counts rows with no issues of any kind. Check Internally rows are excluded from the denominator.
Known Limitations
- Lookup row ranges in the Damages Report are calculated at export time. Rows added beyond those ranges require the formula references to be updated by hand.
- Only the first sheet of an input XLSX is processed.
- Cross-field conditional validation is not implemented, for example requiring BladeChamber when Damage Location is Internal.
- Duplicate anomaly ID detection is not implemented.
- Manual Review resolutions are held in browser memory only and are not persisted across sessions. Bulk resolution (v2.2) reduced the cost of redoing them but did not remove it.
- Image links expire. The signed URLs carried in the Source Images column are time-limited by the source system, typically around a 30 day window. After expiry the link resolves to a not-found error. This is an upstream constraint rather than a tool defect, and the tool does not currently warn about it: a file processed outside the window will export links that silently fail when clicked.
- One client's conversion model is severity-aware, using severity inside the lookup key together with size-threshold rules. The flat three-column lookup cannot represent it, and that client is out of scope for automated conversion until the model question is decided.
Open verification items
Resolved 2026-09-17 by a current export header row: all output column letters, every derived-field formula reference, the classification of Asset and the two serial-number fields, and whether Blade survives as its own column. It does not.
Three items remain.
1. Source Image Expiration Date, column AL. Present in the current export, absent from the v2.1 dictionary and absent from the change log across all six versions. Either it predates v2.1 and was never documented, or it shipped without a change-log entry. Needs classification, a source, and a format rule. The change log lists an expiry warning at ingest as a deferred idea, so a column already emitting the expiry date is worth reconciling against that.
2. The Turbine Serial Number to Serial Number alias. Predates the v2.5 split and now sits against two serial-number fields. Confirm which it feeds.
3. Classification of Critical and Damage Location. Open as D-5. Both currently Required, both empty in some client files and absent as columns in others, both therefore penalising the compliance score for data the client never supplies. Reclassification to Check Internally is under consideration.
Anomaly Upload Validator · Internal Use Only · v3.1.4 · September 2026