Pressure Is a Measurement, Not a Number: Designing Unit-Safe Tire Pressure Data with Context, Provenance, and Uncertainty
Design exercise: The architecture, schemas, events, examples, and tests in this article are illustrative. They do not describe a live KMJ Tire production system, customer product, incident, migration, or operational result. Values are teaching examples, not vehicle recommendations. Drivers should use the pressure specified for their vehicle and tire application.
Tire pressure looks like one of the easiest fields in a software system. A developer might begin with pressure: 35, add a label that says PSI, and move on. That innocent integer hides nearly every problem that makes physical measurements difficult: units, temperature, time, location, instrument behaviour, rounding, source authority, human transcription, and uncertainty.
Calgary makes those hidden dimensions easy to notice. A vehicle can sit through a cold dawn, cross Deerfoot Trail after sunrise, warm its tires through motion, then park during a chinook. The pressure did not become dishonest. The conditions changed. A data model that stores only 35 cannot distinguish a genuine loss from expected thermal response, a warm reading from a cold baseline, or a dashboard estimate from a handheld gauge.
This tutorial treats pressure as an evidence-bearing observation. We will design a unit-safe schema, preserve raw readings, attach provenance, express uncertainty, validate without pretending to know the vehicle specification, and test conversions at numerical boundaries. For driver-facing fundamentals, KMJ Tire's Be Tire Smart guide provides practical background; the focus here is what developers and operations teams can learn from the same physical reality.
1. Begin with the quantity, not the database column
A pressure observation is not merely a scalar. At minimum, it answers: what magnitude was observed, in which unit, when, under what thermal condition, at which wheel position, using what instrument, and by whom or what process? It should also identify whether the value was typed, imported, calculated, or directly captured.
Consider two records:
{ "pressure": 35 }
{ "pressure": 241.3 }
Those values might describe almost the same physical quantity if the first is pounds per square inch and the second is kilopascals. They might instead be severe data-entry errors. A bare numeric type cannot decide. The semantic type must travel with the magnitude.
The same principle applies outside automotive software. Temperature without a scale, money without a currency, and distance without a unit are incomplete quantities. Pressure adds a second complication: gauge pressure is relative to ambient atmospheric pressure, whereas absolute pressure uses a different zero. Most everyday tire readings use gauge pressure. A robust schema says so rather than leaving the reference implicit.
The design target is therefore an observation object, not a FLOAT named pressure. The object can still serialize efficiently and index well. Rich semantics do not require a bloated platform; they require deliberate boundaries.
2. Separate specified targets from observed readings
A common modelling error stores the vehicle's specified value and a measured value in the same field. Those numbers play different roles. One is a target drawn from an authoritative source for a particular application; the other is evidence gathered at a moment in time.
type PressureTarget = {
magnitude: DecimalString;
unit: "psi" | "kPa";
axle: "front" | "rear";
source: TargetSource;
effectiveFor: ApplicationIdentity;
};
type PressureObservation = {
rawMagnitude: DecimalString;
rawUnit: "psi" | "kPa";
measuredAt: string;
wheelPosition: WheelPosition;
thermalState: ThermalState;
provenance: MeasurementProvenance;
uncertainty: Uncertainty;
};
Never infer the target from a tire sidewall maximum. The sidewall contains important information, but it is not a universal replacement for the vehicle-specific pressure specification. KMJ Tire's sidewall information explainer helps distinguish markings and their meanings.
Keeping target and observation separate also protects audit logic. A later correction to reference data should not rewrite what an instrument displayed last Tuesday. Conversely, correcting a transposed observed value should not silently change the target. Different entities deserve different histories, authorization rules, and retention policies.
3. Choose canonical storage without erasing the original
Systems often standardize on one canonical unit for comparison. Kilopascals are convenient in SI-oriented platforms; PSI may be familiar to many North American users. Either can work if conversion is explicit and the original reading remains available.
An effective pattern stores three related values:
- the raw magnitude exactly as entered or reported;
- the raw unit attached to that magnitude;
- a derived canonical magnitude created by a versioned converter.
{
"raw": { "value": "35.0", "unit": "psi" },
"canonical": {
"value": "241.316505",
"unit": "kPa",
"conversionAlgorithm": "pressure-convert@1.0.0"
}
}
Why keep both? Suppose a user later disputes a display. The raw pair shows what entered the boundary; the canonical value shows what the software computed. If conversion policy changes, engineers can re-derive normalized values without inventing a new raw history.
Canonical storage is not permission to present six decimals as meaningful. Precision used for computation differs from resolution communicated by an instrument. Preserve sufficient internal precision, record display resolution separately, and round only at well-defined presentation or interchange boundaries.
4. Make conversion exact before deciding how to round
The relevant relationship is:
1 psi = 6.894757293168 kPa
1 kPa = 0.145037737730 psi
Binary floating-point cannot represent most decimal values exactly. That fact does not make floating-point unusable, but it makes casual equality checks and repeated round trips dangerous. A decimal library or scaled integer is often easier to reason about for business records.
import Decimal from "decimal.js";
const KPA_PER_PSI = new Decimal("6.894757293168");
function psiToKPa(psi: Decimal): Decimal {
return psi.mul(KPA_PER_PSI);
}
function kPaToPsi(kPa: Decimal): Decimal {
return kPa.div(KPA_PER_PSI);
}
Conversion and rounding must be separate functions. psiToKPa(35) produces an internal mathematical result; formatKPaForGauge(...) applies a policy based on destination resolution. If the source gauge reports whole PSI, showing a converted result to three decimal places creates false precision.
Document the rounding mode. Half-even, half-up, truncation, and floor differ at boundaries. A test suite should name the chosen behaviour. Otherwise a mobile client and a backend service can disagree while each appears locally reasonable.
5. Treat significant digits as provenance
The text 35, 35.0, and 35.00 may parse to the same numeric magnitude, yet they communicate different resolutions. JSON numeric values erase trailing zeros, so preserving the input as a decimal string is useful when those distinctions matter.
Instrument metadata should say more directly what the source can resolve:
{
"instrument": {
"kind": "handheld_digital_gauge",
"displayIncrement": { "value": "0.5", "unit": "psi" },
"identifier": "illustrative-device-A"
}
}
This example identifier is fictional and deliberately generic. In a real design, identifiers might map to a calibration registry, a device fleet, or an anonymous class depending on privacy and operational needs.
Resolution is not accuracy. A display that changes in 0.1 PSI increments does not automatically measure within ±0.1 PSI. Accuracy may vary over range, temperature, battery state, age, and calibration history. The schema should avoid deriving uncertainty solely from the last displayed digit.
Capturing significant-digit context also improves exports. A CSV pipeline that turns 35.0 into 35 has changed evidence, even if its arithmetic value is unchanged. Raw strings, parsed decimals, and normalized quantities each serve distinct purposes.
6. Model cold, warm, and unknown as evidence states
“Cold pressure” is a measurement condition, not a magical attribute of the tire. A useful system records why the condition was classified cold, warm, or unknown instead of trusting an unexplained boolean.
type ThermalState =
| { kind: "cold"; basis: "user_attested" | "policy_evaluated"; notes?: string }
| { kind: "warm"; basis: "recent_driving" | "sun_exposure" | "unknown_heating" }
| { kind: "unknown"; reason: string };
An observation after travel on Stoney Trail should not be compared naively with an early-morning baseline. Motion flexes the tire and generates heat. Sun loading can affect one side differently from the other. A garage can be warmer than the outdoor air. The model needs enough context to prevent invalid comparisons, but it should not fabricate unavailable sensor data.
Unknown is a legitimate state. Forcing a user to choose cold or warm encourages false certainty. A tri-state or evidence-based union lets downstream policy say, “comparison withheld because thermal context is unknown,” which is more honest than producing a precise-looking variance.
Operational instructions should still point people to the vehicle's specified method and values. Software can organize evidence; it should not improvise a specification.
7. Temperature belongs beside pressure, with its own provenance
Attaching temperatureC: -15 looks helpful until someone asks what that temperature represents. Was it outdoor air from a weather service, garage air, tread surface, inner liner, or a sensor inside the assembly? Each has different relevance.
{
"temperatureContext": [
{
"kind": "ambient_air",
"value": "-15.0",
"unit": "degC",
"observedAt": "2026-01-12T14:05:00Z",
"source": "illustrative-local-sensor",
"uncertainty": { "plusMinus": "0.8", "unit": "degC" }
}
]
}
The timestamp matters. A weather reading an hour away is context, not a co-measurement. Geographic resolution matters too; Calgary conditions can differ across the city, and a chinook can make rapid changes especially noticeable. Do not label remote ambient data as tire temperature.
If direct tire-temperature instrumentation is unavailable, say so. Nullable fields must mean “not observed,” not zero. Zero degrees Celsius is a real observation; null expresses absence. A temperatureSource field without a temperature is also suspect and should fail structural validation.
8. Resist simplistic temperature correction
Developers may be tempted to normalize every reading to a standard temperature with a single rule of thumb. That shortcut risks overstating what the available data supports. Gas behaviour provides useful intuition, but a mounted tire is not a rigid, perfectly sealed laboratory vessel. Its volume changes, the gas may contain moisture, sensor temperature may lag, and driving introduces heat through deformation.
A design can include an optional educational estimate while clearly labelling assumptions:
type TemperatureEstimate = {
kind: "idealized_estimate";
model: "constant-volume-ideal-gas";
inputObservationId: string;
referenceTemperatureK: DecimalString;
result: PressureQuantity;
warnings: string[];
};
Such a result must never overwrite an observation. It belongs in a derived-data envelope with a model name and version. The UI should avoid presenting it as “what the gauge would definitely read.”
An honest warning might state that the estimate ignores volume variation and transient heating. That sentence protects meaning better than adding more decimal places. It also guides operations teams: model output can support investigation, while a properly conditioned measurement remains the stronger basis for comparison.
9. Use gauge pressure and absolute pressure deliberately
Everyday tire gauges generally report pressure above local atmospheric pressure. Thermodynamic formulas, however, typically require absolute pressure and absolute temperature. Mixing these frames creates subtle errors.
type PressureReference = "gauge" | "absolute";
type PressureQuantity = {
value: DecimalString;
unit: "psi" | "kPa";
reference: PressureReference;
};
Converting gauge to absolute pressure requires an atmospheric-pressure observation or assumption. Calgary's elevation means a sea-level default can be materially misleading for a careful model. Local weather also changes atmospheric pressure. Therefore, a derived absolute value needs the ambient source, time, location granularity, and uncertainty recorded alongside it.
P_absolute = P_gauge + P_atmospheric
Never add a hard-coded atmosphere and discard the fact that it was assumed. If the application does not need thermodynamic modelling, staying entirely in gauge pressure is simpler and safer. Rich schemas should enable justified analysis, not create complexity for its own sake.
10. Design provenance as a first-class object
Provenance answers how a value entered the system. A compact discriminated union prevents an unhelpful free-text field from becoming the only evidence.
type MeasurementProvenance =
| { mode: "manual_entry"; actorId: string; enteredAt: string }
| { mode: "device_import"; deviceId: string; protocol: string; receivedAt: string }
| { mode: "vehicle_display_transcription"; actorId: string; displayUnit: "psi" | "kPa" }
| { mode: "derived"; algorithm: string; inputs: string[] };
Manual entry is not inferior by definition, but it has characteristic risks: transposition, wrong wheel position, and unit selection errors. Device import avoids some transcription problems while adding firmware, pairing, and identity questions. A vehicle display transcription differs from direct sensor telemetry and should remain distinguishable.
Provenance also helps resolve contradictory observations. If two readings at nearly the same time differ, investigators can compare instrument class, resolution, and capture path before deciding anything changed physically.
A privacy-aware implementation avoids collecting unnecessary personal information. Stable actor IDs can be scoped, pseudonymous, or role-based. Evidence quality does not require publishing a person's identity.
11. Represent instrument calibration without claiming perfection
Calibration records belong to instruments, not individual observations, although an observation may reference the applicable calibration state. A simple model includes the calibration date, method, reference standard, result, validity window, and any adjustment.
{
"calibrationRef": "cal-example-2026-0042",
"statusAtMeasurement": "within_declared_window",
"declaredAccuracy": {
"model": "plus_minus_fixed",
"value": "1.0",
"unit": "psi"
}
}
These are illustrative fields and values. “Within declared window” does not mean error-free. It means a policy condition was met according to stored evidence. If calibration status is unknown, record unknown rather than manufacturing confidence.
Instrument drift can be modelled as a separate concern. A sequence of checks against a reference may reveal a pattern, but the analysis should preserve each original check and the method used. Retrospective adjustment of historical measurements, if ever justified, belongs in derived records with explicit lineage.
12. Express uncertainty as a range and a reason
Uncertainty is often reduced to ±1, but a responsible model says where that interval came from. Was it a manufacturer accuracy statement, calibration result, resolution-based estimate, repeated-measurement variation, or conservative policy default?
type Uncertainty = {
interval: { lower: DecimalString; upper: DecimalString; unit: "psi" | "kPa" };
confidence?: { level: DecimalString; interpretation: "coverage_probability" };
basis: "instrument_spec" | "calibration" | "repeatability" | "policy_default";
components?: UncertaintyComponent[];
};
Do not combine components by simple addition unless the policy intentionally uses a worst-case bound. Independent random components are often combined differently from systematic effects. The appropriate method depends on the measurement discipline and purpose.
For many practical applications, a clearly labelled conservative interval is better than an elaborate but unsupported probability distribution. The key is to stop pretending the displayed magnitude is exact.
Intervals also change comparison semantics. If an observation interval overlaps a target tolerance band, the system may classify it as indeterminate rather than confidently high or low. That third outcome reduces false alarms at boundaries.
13. Give wheel position a stable vocabulary
Free-form labels such as front driver become ambiguous across left-hand and right-hand traffic conventions, trailers, dual-wheel arrangements, and localization. Define a vocabulary suited to the supported vehicle classes.
type WheelPosition =
| "front_left"
| "front_right"
| "rear_left"
| "rear_right"
| "spare"
| { kind: "other"; axleIndex: number; side: "left" | "right"; ordinal: number };
The observation should also reference an application identity or inspection session, not just a vehicle globally. Wheel positions can change during rotation, seasonal swaps, or fleet maintenance. Historical records need to remain attached to what was actually observed at that time.
KMJ Tire's guide to seasonal tire changes offers the driver context behind this lifecycle. For software, the important lesson is that location and identity are time-bounded relationships.
14. Validate syntax, semantics, and policy in separate layers
One validator should not attempt every decision. Split the work:
- Syntax validation checks required fields, enum membership, timestamps, and decimal format.
- Semantic validation checks compatible units, sensible references, and relationships among fields.
- Policy evaluation determines whether the observation can be compared with a particular target under defined conditions.
function validateObservationShape(input: unknown): Result<PressureObservation>;
function validateMeasurementSemantics(obs: PressureObservation): Issue[];
function evaluateAgainstTarget(obs: PressureObservation, target: PressureTarget): Evaluation;
A magnitude below zero gauge pressure may be rejected for the intended use, while an absolute pressure at or below zero is physically invalid. An impossible timestamp is a syntax issue. A warm observation compared to a cold target is a policy mismatch. Keeping categories separate makes errors actionable.
Do not embed a universal “correct PSI” range in generic validation. Suitable values vary by vehicle and application. Validation can impose broad data-integrity bounds to catch unit mistakes, but those bounds must be labelled as ingestion safeguards, not service recommendations.
15. Catch unit mistakes with dimensional boundaries
The most valuable validation often occurs where data crosses a boundary. If an API accepts {value: 240, unit: "psi"}, it should flag the entry as implausible for the supported domain rather than quietly store it. Yet the error should say “possible unit mismatch” instead of inventing the intended value.
if (unit === "psi" && value.greaterThan(150)) {
issues.push({ code: "POSSIBLE_UNIT_MISMATCH", severity: "error" });
}
The threshold above is illustrative, not a recommended tire value or a universal physical limit. Domain bounds need documented rationale, supported application scope, and versioning.
A safer API can expose constructors:
const observed = Pressure.psi("35.0");
const normalized = observed.to("kPa");
Compile-time brands or dedicated quantity libraries prevent adding pressure to temperature and reduce accidental comparison of bare numbers. Runtime validation remains necessary because network payloads and database rows do not inherit TypeScript guarantees.
16. Preserve immutable observations and append corrections
Auditability improves when accepted observations are immutable. If someone later discovers that a reading was assigned to the wrong wheel, append a correction event instead of overwriting history.
{
"eventType": "observation_corrected",
"eventId": "evt-example-88",
"correctsObservationId": "obs-example-52",
"reasonCode": "wheel_position_transposed",
"replacement": { "wheelPosition": "rear_right" },
"recordedAt": "2026-01-12T15:20:00Z"
}
An effective read model resolves the current interpretation while retaining the chain. Consumers that need raw evidence can inspect the original; everyday views can show the corrected state and a visible correction marker.
Event sourcing is not mandatory. A conventional relational schema can provide the same principle using an observations table plus amendments. The essential property is that history does not disappear silently.
17. Build an append-only measurement ledger
A relational design might use these tables:
| Table | Responsibility |
|---|---|
pressure_observation |
immutable raw magnitude, unit, time, wheel, thermal state |
measurement_provenance |
capture mode and instrument reference |
temperature_context |
zero or more contextual temperatures |
observation_derivation |
canonical conversions and model outputs |
observation_amendment |
corrections with reasons and timestamps |
pressure_target |
versioned vehicle/application reference values |
Foreign keys enforce lineage. Check constraints restrict units and decimal formats. Application validation handles richer rules that a database constraint cannot express cleanly.
Partitioning should follow actual query and retention needs, not fashion. Time-series volume may justify partitioning by observation time, while a small service can use ordinary indexed tables. Keep high-cardinality device or actor fields out of metric labels even if they remain useful in the database.
18. Version conversions, validators, and target sources
Derived values are reproducible only if the algorithm and inputs are identifiable. Store versions for conversion constants, rounding policies, validation rule sets, and reference-data imports.
{
"ruleSet": "pressure-observation-validation@2.1.0",
"conversion": "psi-kpa-decimal@1.0.0",
"targetSourceVersion": "illustrative-reference-snapshot-7"
}
Again, these names are fictional design examples. Their purpose is to show the shape of audit evidence.
Versioning does not mean every code deployment needs a new data version. Change the semantic version when behaviour affecting stored or displayed meaning changes. A performance improvement with identical results can remain implementation detail.
When reprocessing historical records, store a new derivation rather than replacing the old one. Analysts can then compare outputs and explain why dashboards changed.
19. Design the API around explicit quantities
A request payload should make omission difficult:
{
"schemaVersion": "1.0",
"measurement": { "value": "238", "unit": "kPa", "reference": "gauge" },
"wheelPosition": "front_left",
"measuredAt": "2026-02-05T14:10:00Z",
"thermalState": { "kind": "unknown", "reason": "driving history unavailable" },
"provenance": { "mode": "manual_entry", "actorId": "role-technician-example" }
}
Return structured issues rather than a single generic message:
{
"issues": [
{
"code": "THERMAL_CONTEXT_UNKNOWN",
"path": "/thermalState",
"severity": "warning",
"effect": "target comparison withheld"
}
]
}
Idempotency keys protect imports from retry duplication. Request IDs support tracing. Neither should leak into the meaning of the physical observation.
20. Keep presentation rounding out of the domain model
Different audiences may need different displays. A technician-oriented view might show source resolution and uncertainty; a simple driver view might show the instrument-reported value with its unit and condition. Both should be generated from the same observation, not separate mutated copies.
function formatPressure(q: PressureQuantity, policy: DisplayPolicy): string {
const converted = convert(q, policy.unit);
const rounded = round(converted, policy.increment, policy.roundingMode);
return `${rounded} ${policy.unit}`;
}
Locale is another boundary. Decimal separators and unit typography vary. Store machine-readable decimals in a locale-neutral format; localize only at presentation.
Avoid converting, rounding, converting back, and storing the result. That loop accumulates drift. Always derive alternative displays from the preserved raw or high-precision canonical value.
21. Test conversion with properties, not just examples
Example-based tests are necessary but insufficient. Property-based testing can explore many values and boundary cases.
fc.assert(fc.property(validPsiDecimal(), psi => {
const kPa = psiToKPa(psi);
const roundTrip = kPaToPsi(kPa);
expect(roundTrip.minus(psi).abs().lte("0.000000001")).toBe(true);
}));
Useful properties include:
- conversion preserves ordering for positive quantities;
- converting zero yields zero within the same reference frame;
- a round trip remains within the defined computational tolerance;
- formatting never implies finer resolution than policy permits;
- parsing a formatted value has a bounded, documented loss;
- unit tags survive serialization and deserialization.
Generate decimal strings, not only IEEE doubles. Include values near rounding midpoints, leading zeros, trailing zeros, maximum accepted input, and values just outside domain bounds.
22. Write table-driven tests for rounding policy
Rounding behaviour deserves a visible fixture:
| Input kPa | Increment | Mode | Expected display |
|---|---|---|---|
| 241.316505 | 1 kPa | half-even | 241 kPa |
| 241.500000 | 1 kPa | half-even | 242 kPa |
| 242.500000 | 1 kPa | half-even | 242 kPa |
| 241.316505 | 0.5 kPa | half-up | 241.5 kPa |
All figures are illustrative. The fixture specifies software behaviour, not a pressure recommendation.
Tests should also confirm the raw record remains unchanged after formatting. A formatter that mutates the quantity is a serious defect because a second display request could compound rounding.
Snapshot tests can help with documents, but arithmetic deserves explicit assertions. Snapshots may hide a changed conversion constant in a large diff; a focused numerical test tells reviewers exactly which contract moved.
23. Exercise invalid and adversarial payloads
Validation tests should cover more than empty fields. Try scientific notation if unsupported, Unicode lookalikes in units, arrays where strings belong, extreme exponent values, NaN, infinity, negative zero, and timestamps far outside the accepted window.
"35 psi" -> reject: magnitude and unit must be separate
"035.0" -> accept or normalize according to documented parser policy
"35,0" -> reject at API boundary; locale parsing belongs in the UI
"NaN" -> reject: non-finite
"241" + psi -> flag possible unit mismatch under illustrative bounds
Do not echo hostile payloads unsafely into logs or HTML. Structured issue codes provide enough debugging value without creating injection paths.
Fuzz tests can target parsers and converters. Database constraints should be exercised in integration tests so invalid rows cannot bypass application code through a maintenance script.
24. Test thermal-context policy as a state machine
Comparison eligibility depends on conditions. A state table is clearer than nested booleans:
| Observation state | Target state | Comparison result |
|---|---|---|
| cold with evidence | cold specification | eligible |
| warm after recent driving | cold specification | withheld |
| unknown | cold specification | indeterminate |
| cold, stale timestamp | cold specification | policy-dependent |
The word eligible does not mean the pressure is suitable; it means the comparison method has compatible context. A separate evaluator handles the numerical relation and uncertainty overlap.
Model time explicitly. An observation might be structurally valid but too old for a current decision. Staleness thresholds belong to versioned policy and should vary by use case rather than being buried in a database trigger.
25. Observe the pipeline without turning measurements into metrics labels
Operational telemetry should report pipeline health: ingestion counts, validation failures by bounded code, conversion latency, duplicate retries, and derivation errors. It should not place vehicle IDs, device IDs, raw values, or free-text notes into metric labels.
Cardinality-safe metrics might include:
pressure_ingest_total{unit="psi",result="accepted"}
pressure_validation_total{code="THERMAL_CONTEXT_UNKNOWN"}
pressure_conversion_duration_seconds{algorithm="v1"}
Logs can carry a correlation identifier, while sensitive details stay in controlled data stores. Traces should show boundary stages without exposing unnecessary measurement contents.
An alert on a rise in possible-unit-mismatch errors can reveal an integration problem. It should not automatically rewrite data. Operators need samples, provenance, and recent deployment context before choosing a response.
26. Handle offline capture and clock uncertainty
A mobile measurement workflow may operate where connectivity is unreliable, including highway stops west on Highway 1. Offline records need both event time and receipt time. Device clocks can be wrong, so timestamps deserve uncertainty too.
type TimeEvidence = {
observedAt: string;
receivedAt: string;
clockSource: "network_synced" | "device_local" | "unknown";
estimatedClockErrorSeconds?: number;
};
Ordering by receipt time alone can scramble the physical sequence. Ordering by device time alone may trust a bad clock. Preserve both and let downstream logic surface ambiguity.
Offline idempotency identifiers should be generated locally with collision-resistant values. The server can acknowledge the accepted observation ID, allowing the client to reconcile without creating duplicates.
27. Protect lineage during CSV import and export
CSV remains common in operations, but it has weak types. A safe export includes separate columns for magnitude, unit, reference, time, wheel position, and provenance mode. Include schema version and converter version either per row or in a manifest.
Spreadsheet software may turn identifiers into numbers, dates into locale-specific strings, or decimal text into floating-point. Quoting fields is not enough to guarantee preservation. Provide checksums or row counts, validate after import, and retain the source file as evidence when policy permits.
An import preview should summarize proposed interpretations: “1,204 rows parsed as kPa; 12 possible unit mismatches; 8 missing thermal states.” Those counts are hypothetical examples, not operational results. The importer should require an explicit mapping rather than guessing from a column called pressure.
28. Use uncertainty-aware comparisons
Suppose an illustrative target band is represented as [T_low, T_high], and an observation as [O_low, O_high] after accounting for declared uncertainty. Classification can be interval-based:
if O_high < T_low => definitely below under this model
if O_low > T_high => definitely above under this model
otherwise => overlapping or indeterminate
This method avoids a sharp decision based on a central value that differs by less than the measurement uncertainty. It also exposes why a result is indeterminate.
Target uncertainty and source authority may need treatment too. A transcribed target with unknown provenance should not receive the same confidence as a verified application record. Keep numerical interval logic separate from authority ranking so each can be reviewed.
29. Explain the result instead of emitting a colour
A red, amber, or green badge compresses too much meaning. A useful evaluation response includes the observation, unit, thermal eligibility, source, uncertainty, target provenance, and rule version.
{
"classification": "indeterminate",
"reasons": ["observation_interval_overlaps_target_band"],
"comparisonEligibility": "eligible",
"ruleSet": "illustrative-pressure-eval@1.2.0"
}
For a driver, plain language matters more than the data structure. The interface can say that the reading is too close to the boundary for this instrument and context to support a confident classification. It can advise checking the vehicle specification and obtaining a properly conditioned reading.
30. Connect software evidence to responsible service boundaries
Pressure data may point to a need for inspection, but software should not diagnose a cause from one number. A change could relate to measurement conditions, a valve issue, a puncture, temperature, or another factor requiring physical examination. KMJ Tire provides tire services and oil changes; mechanical concerns outside that scope should be assessed by an appropriate qualified provider.
Relevant driver resources include tire repair guidance, an explanation of wheel balancing, and information about winter tires in Calgary. Developers can treat these links as domain education, not as machine-readable specifications.
Other useful context lives in KMJ Tire's guides to all-weather tires, load indexes, buying tires in Calgary, and local service areas. The schema must never scrape prose pages and pretend it discovered a vehicle-specific target.
31. A compact end-to-end reference flow
The complete design exercise can be summarized as a sequence:
- Accept a raw decimal string plus explicit unit and reference.
- Attach wheel position, observation time, and thermal evidence.
- Record capture provenance and instrument identity class.
- Validate structure without guessing missing values.
- Preserve the immutable raw observation.
- Derive a canonical quantity with a versioned converter.
- Attach uncertainty using a documented basis.
- Select a separately versioned target from an authoritative application source.
- Evaluate eligibility before comparing intervals.
- Return an explainable classification and retain lineage.
Every arrow should be inspectable. A failed conversion must not create a partially normalized record. A missing target must produce “not evaluated,” not a default number. A corrected wheel position must append evidence rather than erase the earlier assignment.
32. Review checklist for implementation teams
Before approving a pressure-data design, ask:
- Can any numeric value exist without a unit?
- Is gauge versus absolute reference explicit?
- Are target specifications separate from observations?
- Does the system preserve the exact entered magnitude?
- Are conversion constants and rounding modes versioned?
- Can warm, cold, and unknown conditions be distinguished with evidence?
- Is every temperature labelled by what it measures and where it came from?
- Does provenance distinguish manual, displayed, imported, and derived values?
- Can uncertainty be traced to a basis?
- Are corrections append-only and visible?
- Do tests include properties, boundaries, malformed payloads, and round trips?
- Can an operator explain a classification without reading source code?
- Are fictional examples clearly separated from real operational claims?
If several answers are no, adding another dashboard will not repair the underlying semantics.
33. Closing principle: store evidence, derive conclusions
The durable lesson is simple: pressure is a measurement, not a number. A magnitude becomes useful only when its unit, reference, time, thermal state, location, provenance, and uncertainty travel with it. Those dimensions let developers preserve truth even when downstream policies evolve.
Calgary's temperature swings make the lesson vivid, but the architecture applies anywhere physical quantities cross software boundaries. Store raw evidence immutably. Normalize through explicit, versioned functions. Round at presentation boundaries. Treat unknown context as unknown. Keep targets authoritative and separate. Make each conclusion reproducible.
That discipline does more than prevent PSI/kPa mistakes. It creates a system that can admit what it knows, what it inferred, and what remains uncertain—the essential qualities of trustworthy measurement software.
34. Walk through one illustrative observation
Imagine a fictional import containing 35.0 psi, recorded at the front-left position. The operator states that the vehicle had been stationary for several hours, while an independent ambient sensor reports minus ten degrees Celsius near the same time. The handheld gauge resolves half a PSI and has a documented uncertainty interval wider than its display increment. None of those details establishes the vehicle's specified target; they only describe the observation.
At ingestion, the parser retains 35.0 as text, validates that PSI is an allowed gauge-pressure unit, and converts the magnitude to a high-precision decimal. The provenance object identifies manual entry and references the illustrative instrument. A policy evaluator accepts the thermal claim as user-attested evidence but does not upgrade it to direct tire-temperature knowledge. The canonical converter derives kPa without rounding the stored result. A presentation view may later show a sensible resolution, while the immutable raw pair remains unchanged.
Suppose a second fictional reading arrives as 241 kPa from a different instrument. The system must not conclude that both gauges agreed exactly. Conversion shows similar central magnitudes, but each observation has its own resolution, uncertainty, timestamp, and source. An interval comparison can describe consistency under the stated model. It cannot prove either instrument was correct.
Now suppose the first wheel label was transposed. An amendment records the corrected position, reason, actor, and time. The raw reading is not deleted. A current-state query resolves the amendment, and an audit query can reconstruct both interpretations. This small example demonstrates why unit safety, provenance, thermal context, and immutability reinforce one another.
35. Decide what the system must refuse to infer
Good measurement software has explicit non-goals. It should refuse to guess a missing unit from magnitude alone, invent a cold classification from outdoor weather, treat a sidewall marking as the vehicle target, convert an unknown pressure reference, or diagnose a physical cause from a trend. These refusals are product features because they keep uncertainty visible.
The interface can still help users recover. It may ask them to select the unit shown by the source, explain why recent driving affects comparison, or direct them to authoritative vehicle information. Validation messages should describe the missing evidence without supplying a fabricated answer.
For operations teams, refusal states need bounded reason codes and measurable rates. A growing number of unknown units might indicate an upstream mapping regression. A rise in missing timestamps might reveal an exporter change. The pipeline can detect those patterns while leaving the questionable observations unnormalized.
Finally, every automated conclusion needs an escape hatch for human review. That does not mean a reviewer may overwrite physics or erase lineage. It means the system can attach a reasoned disposition, cite additional evidence, and preserve who made the decision. Trust grows when a platform records uncertainty and correction honestly, not when it forces every case into a confident category.












