Skip to content
Kiran
← Work

Asset recovery · the first model I put in front of a business decision

Vehicle Recovery Optimisation & Reporting Automation

A recovered vehicle is a depreciating asset with several possible disposal routes, each with a different expected price, a different time to sale, and a different cost to get there. Choosing the route by convention leaves money on the table in a way that is invisible unless you compute the counterfactual. The modelling is not hard; the part that took the time was making the recommendation arrive somewhere a person would act on it, which is why half this project is reporting infrastructure.

Reconstructed

The earliest work on this site, reconstructed from the résumé. The design reasoning is my own account.

Outcome figures are attested; anything used to make the scale legible is illustrative.

2016–2019mldata

What I owned

Designed and built the recovery model and the reporting pipeline it depends on: the feature layer, the per-channel price and time estimates, the net-proceeds ranking, and the ETL and reporting automation that made the recommendation arrive before the decision.

Vehicle recovery profits
+30%attestedVehicle recovery profits
Batch runtime
−25%attestedBatch runtime
Analyst time saved
5+ hrs/weekattestedAnalyst time saved
Built onInformaticaSQLQlikView

The problem

What was actually wrong

When a vehicle is recovered, it can be disposed of through several channels. Each has a different expected sale price for a given vehicle, a different time to sale, and different transport and preparation costs. Time matters twice over, because the asset depreciates while the decision is being made.

The existing process routed vehicles by standing convention (largely by location and channel availability), which is a reasonable default and a poor decision. The loss is invisible without computing what the alternative route would have returned.

The second problem was that the analysis existed before the model did, in the sense that analysts could have worked this out per vehicle and never had time to. Batch reporting ran long enough that the numbers arrived after the disposal decision had been made.

Before this existed

Disposal routing by location and channel convention, with reporting that arrived after the decision.

Constraints

The conditions the design had to hold under

Constraints are the interesting part of an architecture. Without them any diagram looks reasonable.

The asset depreciates during the decision
A recommendation that arrives two days late has a measurably lower ceiling than the same recommendation on day one.
Channel capacity is finite
The best channel for every vehicle individually is not available for every vehicle simultaneously.
The counterfactual is never observed
Only the chosen route's outcome is ever seen. The route not taken has no realised price, ever.

My role

Designed and built the recovery model and the reporting pipeline it depends on: the feature layer, the per-channel price and time estimates, the net-proceeds ranking, and the ETL and reporting automation that made the recommendation arrive before the decision.

Designed

  • Per-channel expected price and time-to-sale estimates rather than a single 'best channel' classifier, so the ranking can respond to capacity
  • Net proceeds as the ranking quantity: price less transport, preparation and holding cost over the expected time to sale
  • The reporting pipeline schedule, so the recommendation lands ahead of the disposal decision rather than after it

Built

  • The recovery model and its feature layer
  • The Informatica ETL and SQL workflow optimisation behind it
  • Automated reporting that replaced a recurring manual analyst task

Led

  • Worked with the operations team on what the recommendation had to look like to be actionable, which changed the output more than any modelling decision did

Architecture

How it is put together

A scheduled pipeline that estimates per-channel outcomes for each recovered vehicle and ranks disposal routes by expected net proceeds, delivered into the reporting layer the operations team already worked from.

The same architecture, in prose

Recovery events and vehicle attributes arrive from the group's operational systems.

The ETL layer consolidates vehicle, location, condition and channel-availability data on a scheduled cycle.

The feature layer builds vehicle characteristics, location, condition grade and current channel capacity.

Per-channel models estimate the expected sale price and the expected time to sale for this specific vehicle through each available route.

The net-proceeds calculation subtracts transport, preparation and holding cost over the expected time to sale.

The ranker orders the available routes and produces a recommendation with the margin over the default route stated explicitly.

Recommendations are delivered into the operational reporting layer ahead of the disposal decision.

Realised sale outcomes flow back as labels for the chosen route only; the counterfactual is never observed.

Every path, written out (2)· the walkthroughs above, as text

One vehicle, routed

A recovered vehicle enters the cycle and leaves it as a ranked recommendation with the margin over the default route stated.

  1. 01

    The vehicle appears

    A recovery event lands with vehicle attributes, location and an assessed condition grade.

    Everything downstream is an estimate conditioned on these four things.

    Fails by: Condition grading is subjective, so two assessors can put the same vehicle in different grades and the estimate moves with them.

  2. 02

    The period is consolidated

    Vehicle, location, channel and capacity data are pulled together on the schedule.

    The schedule is the product constraint, not an implementation detail.

    Fails by: A batch overrun pushes the recommendation past the decision point.

  3. 03

    Features are built per channel

    One feature row per vehicle per available channel, including that channel's current capacity.

    Capacity has to be a feature rather than a filter applied afterwards, or the ranking recommends full routes.

    Fails by: Stale capacity produces a recommendation that cannot be executed.

  4. 04

    Expected price, per route

    Each channel gets its own price estimate for this specific vehicle.

    Per-channel estimates degrade sensibly when a channel is unavailable; a best-channel classifier does not.

    Fails by: Thin history for an uncommon vehicle-and-channel pair.

  5. 05

    Expected days to sale, per route

    How long this vehicle is likely to sit in each channel.

    Holding cost and depreciation both scale with time, so the fastest route is sometimes the most valuable one.

    Fails by: Seasonal throughput swings outside the training window.

  6. 06

    Cost is subtracted

    Transport, preparation and holding cost over the expected time to sale come off the expected price.

    Ranking on price alone systematically favours distant, slow channels whose costs are real and unmodelled.

    Fails by: Cost tables are maintained separately and on a different cadence, so the subtraction can be right against a stale table.

  7. 07

    Routes are ordered

    The available routes are ranked and the margin over the default route is stated explicitly.

    The margin is what turns a recommendation into something an operator will override convention for.

    Fails by: A marginal uplift presented with the same confidence as a large one.

  8. 08

    It reaches the decision

    The recommendation appears in the reporting layer the operations team already works from.

    The analysis existed before the delivery did. Delivery is what made it a decision rather than a document.

    Fails by: It lands in a report nobody opens before deciding.

The route not taken

The recommendation is followed, the outcome is recorded, and the models learn from a world they selected.

  1. 01

    The ranking recommends a route

    One channel is placed first with an uplift over the default.

    This is the system working exactly as designed.

  2. 02

    The recommendation is followed

    Operations disposes of the vehicle through the recommended channel.

    Adoption is the goal, and adoption is also what causes the next step.

  3. 03

    Only one outcome exists

    The realised sale price and time are recorded for the chosen route. The other routes produced nothing, because they were never taken.

    There is no counterfactual to observe. The label set is exactly the set of decisions the model already endorsed.

    Fails by: This is the failure. Feedback is structurally censored, and nothing in the pipeline reports it as missing data.

  4. 04

    The models retrain on their own choices

    Each cycle narrows the training distribution toward routes the system already prefers, and confidence in them rises.

    Nothing breaks and no metric degrades, which is what makes it hard to catch.

    Fails by: The correction is deliberate exploration: route against the recommendation occasionally, accept a known cost per vehicle, and keep the alternatives observable.

What changes as load grows· the scale stages, as text

One disposal cycle

attested

a scheduled batch, scored before the decision point

ETL consolidates the period, features are built per vehicle per channel, both models score every available route, net proceeds are computed against the cost tables, and the ranking lands in the reporting layer before anyone decides. The whole cycle is bounded by the decision deadline, not by accuracy.

Gives first: The batch window. Runtime optimisation was worth more here than model improvement, because a recommendation that arrives after the decision is worth exactly nothing.

More channels, more combinations

illustrative

each new disposal route multiplies the scored space

Scoring is per vehicle per channel, so adding a route adds a full pass rather than a column. The per-channel design is what makes this survivable: a new channel is a new model, not a retrained classifier over a changed label set, but thin history for uncommon vehicle-and-channel pairs means the newest routes are the least trustworthy exactly when someone wants to try them.

Gives first: Training data per channel, not compute. A channel cannot be ranked honestly until it has been chosen enough times to be observed.

Years of accumulated feedback

illustrative

labels only ever arrive for routes that were taken

The dataset narrows as the system succeeds. Every cycle the recommendation is followed, the alternatives go unobserved, so the models are retrained on an increasingly self-selected slice and grow confident about a world they helped create. Nothing in the pipeline gets slower; the estimates just get quietly less correctable.

Gives first: Counterfactual coverage. The fix is to route against the recommendation occasionally on purpose, pay a known cost per vehicle to keep the alternatives observable, which is a business decision rather than an engineering one.

Decisions

The calls I would defend

Each one with the alternatives I rejected, what the choice cost, and how it turned out.

Decision

The ranking quantity is expected price less transport, preparation and holding cost over the expected time to sale.

Context

Expected price is the number everyone reaches for and it systematically favours distant, slow channels whose costs are real and were not being modelled.

Alternatives, and why not

  • Rank by expected sale priceRecommends the channel with the best headline price regardless of what it costs to get the vehicle there or what it costs to wait.
  • Rank by speedThe mirror-image error. Fastest disposal is not the same as best disposal.

Rationale

The business outcome is net recovery. Anything else is a proxy that diverges from it precisely where the decision is hardest.

What it cost

Depends on cost tables maintained outside the model, on a different cadence. That coupling was a persistent source of small errors.

Outcome

30% improvement in vehicle recovery profits.

What broke

Failures, and what they changed

Every one of these is a thing that went wrong in a system I own. They are here because the architecture is largely a record of them.

The recommendations were right and could not be executed

What happened
For a stretch of cycles the top-ranked route was frequently one the operations team could not use, because the channel was already at capacity by the time they read the recommendation.
Root cause
Channel capacity was a feature, correctly, but it was consolidated on the ETL schedule like everything else, so it described capacity at batch time rather than at decision time. For fast-moving channels those are different numbers.
What I did
Capacity was pulled on a shorter cycle than the rest of the feature set, and the ranking began stating the capacity headroom it had assumed alongside the recommendation, with its timestamp.
What changed in the architecture
Feature freshness stopped being uniform. Inputs that decay on the scale of the batch window are refreshed separately from inputs that do not, and anything the ranking depends on that can go stale is shown to the operator rather than only used.
What it taught me
A feature and a constraint are not the same thing, even when they enter the model the same way. Capacity was modelled as evidence about the world and it was actually a gate on whether the answer could be acted on, and things in that second category need their own freshness budget.

The models got more confident as the evidence got narrower

What happened
Over successive retraining cycles the estimates for the recommended routes tightened while the estimates for everything else stopped improving. Nothing in the monitoring flagged it; every headline metric looked better.
Root cause
Labels only ever arrive for the route that was taken. As adoption rose, the training distribution converged on the system's own past recommendations, so it was validating itself against a world it had selected.
What I did
Reported estimate quality per channel separately, weighted by how recently and how often each channel had actually been observed, rather than reporting a single aggregate that the dominant routes controlled.
What changed in the architecture
The retraining path is treated as censored by default. Per-channel observation counts sit next to per-channel error, so a channel with excellent apparent accuracy and almost no recent observations reads as unknown rather than as good.
What it taught me
A recommender that is followed stops receiving the data that would tell it it is wrong. The only real fix is to pay for exploration: route against the recommendation sometimes, on purpose, and treat the cost as the price of a correctable model. That is a commercial decision, and it has to be argued for as one rather than smuggled in as a technical default.

Impact

What changed, and how it is known

Every figure carries its basis. Nothing here is rounded up, and nothing modelled is presented as a result.

+30%attested
Vehicle recovery profits
−25%attested
Batch runtimeInformatica ETL and SQL workflow optimisation
5+ hrs/weekattested
Analyst time savedReporting automation
Business
Disposal routing moved from convention to expected net proceeds, improving recovery profits 30%.
Engineering
A pipeline whose schedule was treated as a product requirement rather than an operational detail.

Leadership and hindsight

What I influenced, and what I would change

What I would do differently

  • The counterfactual problem was real and I did not address it. The model was trained on the routes it recommended, so channels it under-rated accumulated progressively less evidence. I would build in deliberate exploration now. I recognised the shape of this problem properly only years later, on a gold set that had recorded a model's own predictions as truth.
  • Cost tables lived outside the model and moved on their own cadence. That coupling produced small persistent errors that were tedious to trace.

Stack

What it is built on, and why that

A technology list without reasons is a list of things I have heard of.

Informatica
The ETL consolidation layerThe group's standard integration platform.
SQL
Feature computation and reporting workloadsThe data lived in the warehouse and the runtime constraint was there too.
QlikView
The operational reporting the recommendations were delivered throughIt was where the operations team already worked, which was the entire point.

3 more sections are written and hidden: constraints, leadership, stack.