Designing an Explainable Tire-and-Wheel Fitment Constraint Solver
Design exercise, not a production system: KMJ Tire has not built or deployed the solver described here. There was no incident, outage, migration, or production rollout behind this article. Every record, identifier, dimension, tolerance, query result, and performance figure below is illustrative.
A fitment decision looks simple only when its hidden assumptions remain hidden. A driver asks whether a tire and wheel combination can be used on a vehicle. A database appears to contain the vehicle, tire, and wheel. The tempting implementation is a chain of equality checks followed by a green or red badge. That implementation fails as soon as the question becomes precise: compatible for which axle, under which load, using which wheel width, with what evidence, according to which edition of the data, and with what treatment of uncertainty?
This article develops a design for an explainable constraint solver. It is aimed at developers and operations teams who need to reason about typed measurements, source provenance, conflicting records, rule versions, and human-readable audit trails. It does not attempt to replace inspection, manufacturer documentation, or professional judgment. Tire work involves physical condition as well as database facts. A record cannot see corrosion, damage, interference, an altered vehicle, or an incorrectly labelled component.
Calgary provides useful edge cases. Deep winter, chinook temperature swings, road salt, gravel, Deerfoot speeds, Stoney Trail commutes, and Highway 1 travel west of the city all expose weak assumptions. Those conditions do not change dimensional arithmetic, but they change which questions matter and how conservative an unresolved result should be. Drivers wanting a practical introduction can start with being tire smart, while developers can treat the rest of this article as a model-building exercise.
Start With a Decision Contract, Not a Catalogue Join
The first design artifact should be a decision contract. It defines the question the solver is allowed to answer. “Does it fit?” is not a contract. A more useful request includes a vehicle configuration, axle position, operating context, candidate tire, candidate wheel, evidence cutoff, and policy version. The response must distinguish compatible, incompatible, conditionally compatible, and unknown.
Those four outcomes matter. A binary result pressures the application to convert missing evidence into either approval or rejection. Both are misleading. Unknown means the available sources cannot support a decision. Conditional means the combination may satisfy the encoded rules if named conditions are verified, such as a wheel-width range or a load requirement. Incompatible means at least one hard constraint has a supported contradiction. Compatible means all required constraints passed under the specified policy and evidence snapshot.
The contract should also say what the solver does not know. It cannot infer physical clearance from nominal dimensions alone. It cannot certify a modified suspension or nonstandard body hardware. It cannot determine component condition from a catalogue entry. It should direct mechanical concerns beyond tire service to an appropriate qualified provider. KMJ Tire performs tire services and oil changes; this hypothetical software design must never turn a data result into a claim that KMJ performs unrelated mechanical work.
A request can be represented as:
type FitmentRequest = {
vehicleConfigId: VehicleConfigId;
axle: "front" | "rear" | "all";
tireId: TireSpecId;
wheelId: WheelSpecId;
evidenceAsOf: string;
policyVersion: PolicyVersion;
context: "urban" | "highway" | "winter" | "mixed";
};
The context field does not magically alter engineering limits. It selects which warnings and unresolved conditions deserve emphasis. A Highway 1 example may elevate sustained-load evidence. A Calgary winter example may foreground cold-pressure education and seasonal suitability without treating weather as proof of dimensional compatibility. Readers can review sidewall information to see why a compact label still requires careful interpretation.
Make Every Dimension a Type With a Unit
Plain numbers are dangerous in fitment software. 17, 7.5, and 114.3 could represent diameter, width, or a bolt-circle measurement. A solver should reject arithmetic between unrelated dimensions at compile time where possible and at validation time everywhere else.
Use branded types or value objects:
type Millimetres = number & { readonly __unit: "mm" };
type Inches = number & { readonly __unit: "in" };
type Kilograms = number & { readonly __unit: "kg" };
type Psi = number & { readonly __unit: "psi" };
type Count = number & { readonly __unit: "count" };
type WheelDiameter = { value: Inches };
type WheelWidth = { value: Inches };
type SectionWidth = { value: Millimetres };
type Offset = { value: Millimetres };
type BoltPattern = { holes: Count; circle: Millimetres };
The type is more than a wrapper. It owns parsing, permitted precision, normalization, and display. An offset can be negative, zero, or positive. A count must be integral. A bolt circle needs a tolerance policy that is distinct from display rounding. A tire size parser should preserve its raw input and emit a structured interpretation rather than overwriting the source string.
Conversions belong at controlled boundaries. Internally, one canonical unit per dimension reduces ambiguity. The raw value and declared unit remain attached to the evidence record, while the normalized value is derived and reproducible. If the source says 7.5 inches, storing only a rounded millimetre value discards information about origin and precision.
Typed dimensions also prevent a subtle failure: comparing descriptive identifiers as measurements. A nominal wheel diameter label is not permission to assume every bead-seat geometry with a similar text value is interchangeable. The model should encode category and standard family alongside the number. Domain types force those distinctions into code review instead of leaving them in comments.
Separate Observations, Assertions, and Derived Facts
A robust data model distinguishes three kinds of truth claims.
- Observation: what a source literally supplied, including its format and timestamp.
- Assertion: the normalized claim attributed to that source.
- Derived fact: a value computed from one or more assertions by a named algorithm.
Suppose a source provides a load index. The observation contains the original text. The assertion states the parsed index and standard table edition. A derived fact may map that index to a load capacity, provided the rule identifies the table version. The result is not “just data”; it is a conclusion with lineage.
{
"observationId": "obs-demo-104",
"sourceId": "source-example-A",
"capturedAt": "2026-08-30T16:00:00Z",
"raw": { "loadIndex": "99" },
"assertions": [
{
"path": "tire.serviceDescription.loadIndex",
"value": 99,
"parserVersion": "illustrative-parser-2"
}
]
}
This separation prevents normalization from erasing evidence. If parsing rules improve, the system can replay observations and compare old and new assertions. If two sources disagree, both assertions remain visible. The solver does not silently choose whichever record arrived last.
Load capability deserves special care because a symbol needs a referenced mapping and an operating interpretation. The practical overview of tire load index is useful background. In software, the mapping table should be immutable, versioned, and covered by fixtures. A number without its standard context is incomplete evidence.
Model Compatibility as a Graph, Then Evaluate Rules
A compatibility graph is a useful organizing structure, but it should not become a giant table of unexplained yes/no edges. Nodes represent vehicle configurations, axle configurations, tire specifications, wheel specifications, standards, source documents, and policy versions. Edges represent typed claims such as requires, permits, measured-by, supersedes, and derived-from.
An edge can carry validity dates, source provenance, confidence, and conditions. For example, a vehicle-to-wheel edge may permit a diameter only when paired with an acceptable tire envelope. That is different from unconditional wheel compatibility. A tire-to-wheel-width relation may be a range, not an enumerated list.
The graph narrows candidates and exposes lineage. The rule evaluator still performs dimensional and logical checks. This hybrid avoids two extremes: encoding every possible combination in advance or recalculating everything from unstructured records during every request.
Conceptually:
VehicleConfig --requires--> AxleRequirement
AxleRequirement --constrains--> LoadCapability
TireSpec --declares--> LoadIndex
LoadIndex --mapped-by--> StandardTableVersion
TireSpec --permits--> WheelWidthInterval
WheelSpec --has--> WheelWidth
Every assertion --supported-by--> SourceRevision
Graph traversal should be deterministic. A query plan identifies required nodes, permitted source classes, version boundaries, and ordering rules. Determinism is essential for auditability: the same request against the same immutable snapshot should yield the same result and explanation.
Express Hard Constraints and Advisory Policies Differently
Not every rule has the same force. A hard constraint represents a contradiction that blocks compatibility under the selected policy. An advisory rule adds context or requests verification. Mixing them creates either unsafe approvals or noisy rejections.
A rule definition can include:
type RuleDefinition = {
id: string;
version: number;
severity: "hard" | "conditional" | "advisory";
inputs: string[];
evaluate: (facts: FactSet) => RuleResult;
explanationTemplateId: string;
citationsRequired: number;
};
Examples of hard checks might include incompatible rim diameter categories, insufficient supported load capability, or a bolt-pattern mismatch where both records are authoritative and exact. Conditional checks include missing offset evidence or an acceptable wheel width that depends on a specific tire specification. Advisories can discuss seasonal context, pressure maintenance, or the need for a physical interference check.
Wheel balancing is related to service quality but is not dimensional proof. A combination can be dimensionally plausible and still require correct installation and balancing. The distinction is explained for drivers on the wheel balancing service page. In the solver, balancing belongs in an operational note, not in a compatibility equation.
Each rule must declare its required inputs. If an input is absent, the result is not_evaluated, not pass. Aggregation then asks whether every mandatory rule produced a supported pass. This single distinction prevents missing offset or load evidence from becoming accidental approval.
Treat Ranges, Tolerances, and Rounding as Policy
Fitment data contains intervals. Wheel width compatibility, dimensional envelopes, and measurement tolerances cannot be safely reduced to string equality. A generic interval type needs inclusive and exclusive boundaries, unit identity, and source precision.
type Interval<T> = {
lower: T;
upper: T;
lowerInclusive: boolean;
upperInclusive: boolean;
sourcePrecision?: string;
};
Tolerance must never be smuggled into a floating-point comparison. approximatelyEqual(a, b) is meaningless unless the tolerance comes from a named rule and applies to that exact dimension. Display rounding should happen after evaluation. A visible value of 114.3 must not imply that values within an arbitrary fraction are compatible.
An illustrative calculation shows the principle. Assume a hypothetical wheel-width interval of 6.5 through 8.0 inches, inclusive, and an illustrative candidate value of 7.5 inches. The width check passes because 6.5 ≤ 7.5 ≤ 8.0. That says nothing about diameter, offset, load, fastener geometry, physical clearance, or component condition. The explanation must enumerate what the calculation did and did not establish.
Store decimal quantities with explicit scale or rational representation when exactness matters. Binary floating point can create edge behavior around interval boundaries. A decimal library or scaled integer is often simpler to audit. The chosen representation belongs in the architecture decision record and in fixtures for lower and upper boundaries.
Give Provenance First-Class Schema Space
Provenance is not a footnote attached after a decision. It is a core input. Every assertion should identify source, source revision, capture method, capture time, applicable market, parser version, and any transformation chain. The schema must also represent withdrawal and supersession without mutating history.
create table assertion (
assertion_id text primary key,
subject_id text not null,
predicate text not null,
normalized_value jsonb not null,
source_revision_id text not null,
valid_from timestamptz,
valid_to timestamptz,
parser_version text not null,
recorded_at timestamptz not null,
retracted_at timestamptz
);
Source hierarchy should be explicit and scoped. A policy may prefer a manufacturer document for one predicate while allowing a validated catalogue for another. “Source A always wins” is usually too crude. Freshness is also predicate-specific. A newer secondary record should not automatically defeat an older primary specification that remains valid.
The solver should emit citations at rule-result level. A final explanation saying “sources checked” is insufficient. An operator needs to see which assertion supported the load result, which supported wheel width, and which contradiction caused rejection.
Represent Uncertainty Without Fake Precision
Uncertainty arises from missing fields, ambiguous parsing, source disagreement, market applicability, and stale revisions. A single confidence percentage can conceal those differences. Prefer structured uncertainty reasons.
type Uncertainty =
| { kind: "missing"; field: string }
| { kind: "ambiguous_parse"; alternatives: unknown[] }
| { kind: "source_conflict"; assertionIds: string[] }
| { kind: "scope_unknown"; expectedMarket: string }
| { kind: "stale_by_policy"; ageDays: number };
The aggregator maps uncertainty to outcomes through policy. Missing mandatory evidence yields unknown. A low-impact advisory field may permit a compatible result with a note. A source conflict on a hard dimension produces unknown until resolved; it should not be converted to a majority vote.
Confidence scores are acceptable for triage, search ranking, or review queues, but they should not substitute for hard evidence. If used, show their components and never display them as engineering certainty. “82% compatible” invites a user to interpret probability where the software may only mean data completeness.
Calgary weather adds another uncertainty lesson. A chinook can move temperatures quickly, changing measured pressure. That observation supports maintenance guidance, not a revision to the vehicle’s required fitment. Seasonal information, including winter tire guidance, should be linked as context while dimensional rules remain anchored in their proper evidence.
Resolve Conflicts Through Reviewable Precedence
Conflict handling needs an algorithm and a queue. When two active assertions disagree, the system should classify the conflict before applying precedence:
- equivalent values expressed in different units;
- rounding-only differences within an authorized representation rule;
- market or trim scope mismatch;
- revision supersession;
- direct substantive contradiction;
- parser disagreement over the same raw observation.
Unit-equivalent values can be normalized automatically. Scoped records can coexist when their predicates include the missing scope. A superseded revision may be excluded for new decisions while remaining in historical audits. A substantive contradiction should remain unresolved unless policy identifies a valid authority for that predicate.
The review interface must show both raw observations, normalization steps, source metadata, and the proposed resolution. A reviewer action creates a new resolution record rather than deleting the losing assertion.
{
"resolutionId": "resolution-demo-7",
"conflictIds": ["assertion-A", "assertion-B"],
"disposition": "scoped-separately",
"rationaleCode": "market-difference",
"effectivePolicyVersion": "fitment-policy-demo-3",
"reviewedBy": "illustrative-review-role"
}
This is deliberately boring. Conflict resolution should produce durable evidence, not clever guesswork. When the system cannot resolve a disagreement, unknown is the correct answer.
Version Rules, Data, and Decisions Independently
Three clocks affect reproducibility: source-data time, rule-release time, and decision time. They should not be collapsed into one “updated at” field.
Data revisions describe when assertions were recorded and when they applied. Rule versions describe executable policy. Decisions identify the exact data snapshot and rule bundle used. A later rule release does not silently rewrite yesterday’s audit record.
Semantic versioning can help, but meaning must be domain-specific. A patch might improve explanation text without changing outcomes. A minor version might add an advisory. A major version might change a hard constraint or precedence rule. Automated comparison should run a fixture corpus before activation and report outcome changes.
Activation deserves its own entity:
type PolicyActivation = {
policyVersion: string;
activatedAt: string;
evidenceSnapshotId: string;
approvedFixtureRunId: string;
};
Rollback should select an earlier immutable policy bundle rather than rewriting the current one. Historical replay uses the original bundle. Counterfactual replay can ask what an old request would produce under a new bundle, but it must label that result as simulated.
Compile Requests Into Observable Query Plans
A fitment request can touch many relations. Letting an object-relational mapper lazily fetch them creates unpredictable behavior and incomplete explanations. Compile each request into a query plan based on rule input declarations.
The plan can contain these phases:
- Resolve the vehicle configuration and axle scope.
- Load candidate tire and wheel assertions from the chosen evidence snapshot.
- Fetch mappings required by the active rule bundle.
- Detect conflicts among assertions used by mandatory predicates.
- Evaluate cheap exact constraints before expensive graph traversals.
- Construct explanations from rule results and cited evidence.
- Persist the decision envelope atomically.
The planner should expose diagnostics: planned predicates, records read, conflict count, rules skipped, cache keys, and snapshot identifier. These are operational measurements, not customer claims.
Caching is safe only when the key includes every decision dependency. A cache key based solely on vehicle and tire IDs will return stale or cross-policy decisions. Include wheel, axle, market, policy version, evidence snapshot, and relevant context. Derived lookup tables can be cached by immutable revision hash.
An illustrative query budget might target a small bounded number of database round trips, but no invented performance benchmark should be presented as reality. Measure actual behavior in the environment where the design is implemented. Optimization before lineage correctness merely makes unexplained mistakes arrive faster.
Build Explanations From Rule Results, Not Marketing Copy
An explanation should be generated from structured rule output. Free-form summaries alone drift away from evidence. Each rule result needs status, normalized inputs, comparison, citations, conditions, and a plain-language sentence.
type RuleResult = {
ruleId: string;
ruleVersion: number;
status: "pass" | "fail" | "unknown" | "not_evaluated";
inputs: Record<string, unknown>;
evidenceIds: string[];
explanation: string;
unresolved?: Uncertainty[];
};
A good final explanation is layered. The headline gives the outcome. The next layer lists decisive checks. A technical layer shows normalized comparisons and source revisions. A boundary layer lists what the solver did not assess physically.
For an illustrative compatible result, it might say the wheel diameter category matched, the candidate width fell inside the tire specification’s supported interval, and the supported load capability met the encoded axle requirement. It would then state that physical clearance, current component condition, modifications, and installation quality still require verification.
For a rejection, identify the first decisive contradiction but retain other evaluated results. “Rejected because bolt-pattern assertions differ” is useful. “Does not fit” is not. For unknown, say precisely which evidence is missing or conflicting and what source could resolve it.
Preserve a Complete Decision Envelope
The durable audit object is a decision envelope, not a status string. It captures request, outcome, rule bundle, evidence snapshot, individual rule results, generated explanation, software build, and trace identifier.
{
"decisionId": "decision-illustrative-301",
"outcome": "unknown",
"policyVersion": "fitment-policy-demo-3",
"evidenceSnapshotId": "snapshot-demo-88",
"decisiveRules": ["bolt-pattern-match-v2"],
"unresolved": [
{ "kind": "source_conflict", "assertionIds": ["a17", "a18"] }
],
"softwareBuild": "example-build-hash",
"createdAt": "2026-08-30T16:15:00Z"
}
Audit records should be append-only and access-controlled. Personally identifying request data should be minimized or separated from technical evidence. Retention policy must distinguish operational traces from durable safety evidence. Logs are not automatically an audit system; they may be sampled, rotated, redacted, or reordered.
The decision envelope also supports replay. A replay engine loads the recorded snapshot and policy, repeats evaluation, and compares normalized rule results. Any mismatch is a reproducibility defect worth investigating.
Design Test Fixtures Around Boundaries and Contradictions
Example-based tests should be fixtures with explicit provenance and expected explanations. Avoid building tests from unverified customer stories. Synthetic cases are safer and more controllable when clearly labelled.
The fixture matrix should cover:
- exact lower and upper interval boundaries;
- one unit below and above each boundary;
- negative, zero, and positive offsets;
- different bolt counts with similar circle values;
- equal values represented in different units;
- missing load mapping;
- conflicting primary and secondary assertions;
- superseded source revisions;
- ambiguous trim selection;
- staggered axle requirements;
- parser changes that alter normalized output;
- an advisory failure alongside hard-rule passes;
- unknown caused by unavailable mandatory evidence.
Property-based tests add broad coverage. Useful properties include unit-conversion round trips, monotonic interval containment, deterministic evaluation against immutable snapshots, and explanation citations that reference only evidence present in the decision envelope.
Metamorphic tests are especially valuable. If only display formatting changes, the outcome must remain unchanged. If a supporting assertion is retracted, affected decisions should no longer replay as supported. If a hard requirement increases beyond candidate capability in an illustrative fixture, a pass cannot remain a pass.
Golden explanation snapshots should focus on structure and decisive facts rather than fragile punctuation. Test that an unknown result names the missing predicate and that a failure cites the contradictory evidence. Human reviewers can then assess clarity without turning prose into an unchangeable API.
Add Mutation, Fuzz, and Differential Testing
Constraint solvers often look correct because happy-path fixtures mirror their implementation. Mutation testing deliberately changes comparisons and logical operators. If replacing >= with > does not fail a boundary test, the suite has a gap.
Fuzz parsers with whitespace, localized decimal separators, unexpected suffixes, Unicode lookalikes, overlong strings, negative values, and mixed units. A parser should reject invalid input explicitly rather than coercing it into a plausible number. Preserve the failing raw observation for debugging while ensuring it cannot enter evaluation as trusted data.
Differential testing compares the new evaluator with a slower reference model or independently implemented rule set. Differences do not prove which implementation is correct, but they locate cases needing review. Keep the comparison corpus synthetic or properly licensed.
Chaos testing can target dependencies: missing mapping tables, delayed source ingestion, partially available graph stores, and cache corruption. The desired behavior is graceful unknown or controlled failure, never fabricated compatibility. A circuit breaker should distinguish service unavailability from a valid negative result.
Measure Quality Without Turning Metrics Into Truth
Useful operational metrics include outcome distribution, unknown-reason frequency, conflict backlog age, rule evaluation errors, replay mismatches, parser rejection counts, and explanation completeness. These indicators help maintain the system; they do not prove real-world compatibility.
Track metrics by policy and evidence snapshot. A sudden fall in unknown results after a deployment might mean improved data, or it might reveal that missing inputs are now treated as passes. Outcome shifts require fixture comparison and sample audit.
Latency should be decomposed by phase: entity resolution, evidence retrieval, conflict detection, rule evaluation, explanation construction, and persistence. A total percentile alone cannot identify the failing layer. Cardinality labels require discipline so source and rule identifiers do not overwhelm monitoring storage.
Service-level objectives should describe software availability and bounded response time, not safety certainty. A highly available solver can still be wrong. Pair reliability measures with audit-quality measures such as the share of decisive rules carrying required citations and the rate of deterministic replay.
All numeric thresholds in a real implementation must come from observed workloads and accepted operational policy. The figures in this design exercise are examples, not KMJ production metrics.
Secure the Ingestion and Evaluation Boundary
Source data is untrusted input even when it comes from a respected provider. Validate schemas, enforce size limits, verify signatures where available, and isolate parsers. Store raw artifacts immutably, but do not render unescaped source strings in explanations.
Rule bundles are executable policy and deserve supply-chain controls. Sign releases, pin dependencies, review changes, and restrict activation rights. A compromised explanation template can mislead users even if the underlying result is correct. Templates should use escaped structured fields rather than arbitrary markup.
Authorization should separate source ingestion, conflict resolution, policy activation, and audit access. One role should not be able to introduce a new assertion and quietly approve the conflict it creates. Every privileged change needs an immutable event with rationale.
Privacy belongs in the model. Most compatibility evaluation should not require a person’s name, address, or journey history. Keep technical requests pseudonymous where possible. Calgary route examples are contextual illustrations, not a reason to retain location traces.
Plan Human Review as Part of the Architecture
Human review is not an embarrassing fallback. It is an explicit state transition. A review item should contain the unresolved predicate, competing evidence, effect on outcome, and suggested next source to consult. It should avoid presenting a guessed resolution.
Prioritize queues by decision impact and evidence quality. A conflict on an advisory description is different from missing evidence for a hard load requirement. Age alone should not dictate resolution. The interface should make it easy to abstain and request better evidence.
Review actions need reason codes plus optional notes. Free text alone is hard to analyze; reason codes alone cannot capture nuance. The system records the reviewer role, applicable policy, evidence viewed, and timestamp. Any new assertion passes through the same validation path as automated ingestion.
Physical verification is a separate activity. Software can prepare a checklist, but it cannot inspect the vehicle through a database. For Calgary drivers evaluating seasonal changes, the practical process described under seasonal tire changes can complement data review. If a physical concern points to unrelated mechanical systems, refer it to an appropriately qualified provider rather than implying tire-service scope covers it.
Roll Out With Shadow Decisions and Explicit Stops
If this design were implemented, a safe rollout would begin with offline fixtures, historical synthetic replays, and shadow decisions that do not control customer-facing outcomes. The team would compare explanations with authoritative source material and document disagreement categories.
Promotion stages might include:
- schema validation and parser tests;
- deterministic rule evaluation on synthetic fixtures;
- expert review of sampled explanations;
- shadow execution alongside an established manual process;
- narrow decision support with mandatory human confirmation;
- broader use only after defined evidence and audit standards are met.
Stop conditions include unexplained outcome drift, missing citations on decisive rules, nondeterministic replay, unresolved data corruption, or a policy bundle whose fixture diff was not reviewed. Rollback selects the previous signed bundle and evidence snapshot.
No stage should be described as deployment at KMJ. This is an architecture exercise. There are no KMJ rollout statistics, production adoption numbers, or incident results to report.
Use Calgary Context Without Encoding Geography as Proof
Local context improves explanations when used honestly. Winter temperatures affect pressure maintenance. Chinooks create large day-night changes. Gravel season can reveal damage that a catalogue cannot observe. Deerfoot and Stoney Trail make sustained-speed preparation relevant. Highway 1 west adds changing weather and distance from services.
None of those facts can prove a wheel clears a particular vehicle. The solver should attach contextual guidance only after evaluating dimensional evidence. It must not infer compatibility from common local use or popularity.
Season category also deserves separate modelling. A tire can satisfy dimensional constraints while being a poor choice for the intended conditions. Represent dimensionally_compatible and context_suitability as different result families. The latter can link to education about all-weather tires in Calgary or all-season tires, but it should not overwrite fitment evidence.
A transparent interface might display: “Dimensional checks passed under the selected evidence snapshot; winter-context guidance remains separate.” That wording teaches users that fitment is multidimensional without pretending software has inspected the actual vehicle.
Define Failure Modes Before Writing the Happy Path
Architecture reviews should begin with failure modes. Consider these examples:
- a parser interprets a diameter token using the wrong unit;
- a cache omits policy version from its key;
- two market-specific vehicle configurations collapse into one identifier;
- a source revision is overwritten rather than superseded;
- a missing rule input returns false and is mistaken for a supported rejection;
- a rounded display value is fed back into evaluation;
- graph traversal crosses outside the evidence snapshot;
- explanation text cites a record unused by the decisive rule;
- a rule bundle activates without completing fixture comparison;
- an unavailable database returns an empty set that looks like “no conflicts.”
For each failure, define detection, containment, recovery, and audit evidence. An empty result must not be ambiguous: distinguish “searched successfully and found none” from “search did not complete.” A typed result such as Complete<T> | Unavailable | Partial<T> makes this visible.
Retries require idempotency. Repeating a request under the same decision identifier should not create conflicting envelopes. If a retry uses a newer snapshot, it is a new decision with lineage to the earlier request.
Choose Storage Around Access Patterns and Evidence Needs
A relational database fits strongly typed assertions, revisions, policies, and decision envelopes. A graph projection can accelerate compatibility traversal while the relational store remains the evidence authority. Maintaining two stores adds synchronization risk, so projections should be rebuildable from immutable events.
Event sourcing is attractive for provenance but increases implementation complexity. A simpler append-only assertion and resolution model may provide enough history. The correct choice depends on update volume, replay needs, and team experience—not architectural fashion.
Indexes should follow query plans: subject and predicate, source revision, validity interval, snapshot membership, conflict status, and decision replay keys. JSON fields are useful for heterogeneous normalized values, but critical dimensions still deserve typed generated columns or validated domain tables.
Data migrations must preserve old replay. If a schema changes, maintain an adapter capable of reading historical envelopes or migrate them with a verifiable transformation log. Never claim reproducibility while deleting the interpretation needed to reproduce old decisions.
Create a Minimal Vertical Slice
A sensible prototype solves one narrow, well-evidenced subset. It might accept a synthetic vehicle requirement, tire record, and wheel record; evaluate diameter category, width interval, load capability, and bolt pattern; then produce a cited explanation. Offset and physical-clearance questions can remain explicitly unknown.
The slice should include:
- immutable raw observations;
- normalized assertions with parser versions;
- one signed policy bundle;
- a small fixture corpus with boundary cases;
- structured rule results;
- an append-only decision envelope;
- replay that proves determinism;
- a review queue for one conflict type.
Avoid adding recommendation ranking, inventory, commerce, or personalized route analysis. Those features introduce unrelated correctness and privacy questions. The first milestone is not a colourful interface; it is an explanation whose every decisive statement can be traced to evidence.
For readers moving from system design back to practical tire purchasing, buying tires in Calgary provides consumer context. The software lesson is similar: ask precise questions, preserve assumptions, and avoid treating a single dimension as the entire decision.
Review the Solver With an Audit Checklist
Before any real use, reviewers should be able to answer all of the following:
- Are dimensions represented with explicit units and categories?
- Can every normalized assertion be traced to an immutable raw observation?
- Are source scope, market, revision, and validity dates represented?
- Does missing mandatory evidence produce unknown rather than pass?
- Are conflict precedence rules predicate-specific and versioned?
- Can the same snapshot and policy reproduce the same rule results?
- Does every decisive rule cite the evidence it used?
- Are physical inspection limits visible in the response?
- Are policy activation and rollback auditable?
- Do boundary fixtures fail when comparison operators are mutated?
- Are cache keys complete for all decision dependencies?
- Can partial dependency failure be distinguished from an empty result?
- Are synthetic examples clearly labelled?
- Are unrelated mechanical concerns directed to qualified providers?
An audit should sample both easy passes and uncomfortable unknowns. A system that almost never returns unknown may be hiding absence. Reviewers should challenge the explanation, recreate comparisons independently, and verify that the evidence snapshot contains exactly what the result claims.
What an Explainable Result Ultimately Promises
An explainable solver does not promise universal certainty. It promises disciplined reasoning within a declared boundary. It tells the user which request was evaluated, which sources were considered, which rules ran, what comparisons were made, why the outcome was selected, and what remains unresolved.
That promise requires more engineering than a catalogue join. Typed dimensions prevent unit confusion. A compatibility graph organizes relationships. Predicate-specific rules distinguish hard constraints from advice. Provenance retains origin and revision. Structured uncertainty prevents missing evidence from masquerading as approval. Versioned policies make history reproducible. Fixtures attack boundaries, while decision envelopes make explanations auditable.
The most trustworthy output may be unknown. In a tire-and-wheel domain, refusing to guess is a feature. Software should narrow the question, expose evidence, and prepare a qualified person to verify the remaining conditions. It should never claim to have inspected metal, rubber, fasteners, or clearance through a screen.
This entire architecture remains a design exercise. KMJ has not built or deployed it, and none of the illustrative records or measurements describe a live internal system. The practical takeaway for developers is straightforward: model uncertainty as carefully as compatibility, and make every green result explain itself.
Top comments (0)