Metcor take-home: Igor Diev

Notes before reading

  1. Inconsistencies in the data. A few quotes are inconsistent and lower the final scores. To make proper rules and reduce noise, I excluded them from the training dataset, but not from the final scoring. They are worth checking manually: Data inconsistencies.
  2. The 150 jobs with real quotes were split once at random into two datasets:
    • Training dataset: 100 jobs used to write the rules and check them while building.
    • Hold-out (test) dataset: 50 jobs never looked at while building. The finished system was frozen and scored on them once.
  3. The frozen system was then run on all 849 jobs without a quote. Its answers are in predictions.json.

A1. Types of job

QuestionWhich types of job did you find and how many of each?

I found 10 types of job. Each type can include supporting lines, such as waste removal, surface reinstatement or traffic cones, which are part of the job rather than separate jobs.

Across all 999 jobs, the types split like this:

Type of jobJobs
Manhole cover replacement416
Channel drain repair155
Gully repair112
Dig and pipe work72
Tanker: pump out and dispose of waste64
Drainage crew: jetting, CCTV, liner63
Civils visit, labour only44
Small civils repair (gully pot, chamber, bespoke cover)40
Single engineer: plumbing, pumps21
Manhole cover re-set (rebed)12
Total999

For the 150 labelled jobs the type comes from the estimator's quote; for the other 849 from my system.

A2. Mislabelled classes

QuestionOur Engineers label the jobs, are there classes of jobs you can identify that are mislabeled?

Outright wrong labels are rare: I found 3. But about a quarter of the jobs labelled "Other" (73 of 267) clearly belong to a real class of work, so "Other" hides a large share of ordinary cover, channel and gully jobs.

This is what the 73 "Other" jobs really are:

Real workJobs
Manhole cover replacement36
Channel drain repair18
Gully repair10
Manhole cover re-set9
Total73

The engineers knew what they were looking at: in 61 of the 73 the text names the object plainly ("broken manhole cover", "new gully lid", "missing aco grate").

Part of the cause is the form itself. Manhole, Gully and Channel types exist only under the Civils category. 30 of the 73 jobs were raised on a Drainage form, where "Other" was the only choice; 8 of those come from engineers who only ever use Drainage forms. The other 43 were raised on a Civils form, where the right type was available.

The 3 outright wrong labels all say "Defective Manhole" for something that is not a drainage manhole:

Counts use the estimator's quotes for the 150 labelled jobs and my system for the other 849.

A3. Attributes that drive the price and the quote

QuestionThere are key "attributes" of jobs that drive a different price or a different quote, can you identify them and reason about them?

Within each type of job (A1), three groups of attributes change the quote: the part being fixed, extra lines added on top, and multipliers that scale everything.

1. The part being fixed

For a cover, three attributes pick the line from the rate card:

Cover attributeValuesPrice, low → high
Size600x450, 600x600, 675x675, 750+£160 → £520
Load classlight (A15/B125), heavy (C250/D400)£185 → £330 (600x600)
Stylestandard, chequer plate, recessed£330 → £410

Gullies, channels and pipe work have fewer choices, because the rate card offers one type of grate and one type of channel:

Type of jobAttributeValuesPrice, low → high
GullyPot brokengrate only, grate + new pot£210 → £395
ChannelSump replacedno, yes£0 → £240
Dig and pipeHow the pipe is fixedpatch liner, new pipe£290 (liner) → £38 per 3 m of pipe + £22 per fitting + excavator £210 a day

Tanker, drainage crew, visit, small civils repair and plumbing have no part to choose; they are priced by crew time and waste.

2. Extra lines added on top

These depend on where the job is and what it leaves behind:

AttributeValuesPrice, low → high
Surfaceblock paving, concrete, asphalt£0 → £660 (asphalt, median)
Waste typegeneral, contaminated or grease£0 → £852 (median)
Job sizeunder 3 days, 3+ days or 8+ m of channel£95 (general waste) → £320 (skip)

3. Multipliers

These scale the lines already chosen:

AttributeValuesPrice, low → high
Number of covers1, 2–3, 4+£1,870 → £8,466 (median quote)
Channel lengthmetres£205 per metre
Out of hoursday, night or weekend+36–39% on every crew line
Not a driver: priority. The median quote is £2,083–2,468 at every level from P0 (same day) to P3 (one month).

B. A classifier that labels a job only when it is very sure

QuestionWe would like a classifier with few false positives: one that labels a job only when it is very sure. How would you build it? Show a proof of concept, and tell us how many jobs it labels and how often it is right.

I built an MVP classifier that works on these principles:

  1. Code prepares the input. It turns each job's forms into clean text: empty forms and exact copies are dropped, every filled field and the free text are kept. No decisions are made at this stage.
  2. An LLM does the reading and the judgement. Claude Sonnet gets the text with a long prompt: 61 quoting rules, the rate card, three worked examples and the rules for confidence. It returns the type of job, the quote lines with quantities, and how sure it is. Code then checks every line against the rate card and adds up the prices.
  3. Three levels of confidence, set in the rules before any results were seen:
    • Green: the rules give one answer from what the form states.
    • Yellow: the form leaves a gap and the model makes an educated guess, for example no cover size given, so a standard 600x600 is assumed.
    • Red: the form contradicts itself or doesn't say what work is needed, or a channel run is over 10 m, where the estimator's practice is unclear.
  4. It labels only green jobs and leaves the rest to the estimator: 298 of the 849 unlabelled jobs (35%).

On the green jobs it labelled, the classifier was right this often:

MeasureHold-out (17 green of 50)Training (40 green of 97)
Manhole job: yes / no17 of 1740 of 40
Type of job17 of 1738 of 40
Exact label, including the cover kind14 of 1736 of 40
Main quote lines, F10.830.92
Other quote lines, F10.790.85

The 3 hold-out misses are all the wrong cover kind on a correctly typed manhole job. 3 of the 100 training jobs are the worked examples in the prompt and are not scored.

Proof of concept: predictions.json (all 849 jobs, field confidence), quote_run.py, quote_rules.md.

Also tested: Haiku, Sonnet and Opus; with and without site photos (see D2).

What could improve it

Several ways to improve quality were not tested in this MVP:

  1. Other models, especially for reading the photos.
  2. Splitting the single prompt into a workflow of small steps, with a large model producing the final result once the small steps finish.
  3. Clearer rules on diagnosis versus work, night versus day, and how many metres of channel to replace. These rules can't be learned from the data alone; they are worth learning from the estimators and adding to the system.

C. Predicting quotes and their line items

QuestionAre you able to predict quotes and their line items? How would you measure accuracy?

Yes, I can predict the quotes: my system writes a full quote for every job, with rate-card lines and quantities (predictions.json). However, some limits in the data leave a relatively large gap to the prices in the real quotes.

Some of the gap comes from inconsistencies in the data. For example, one real quote (J0222) charges 150 loads of waste removal for half a day of work on one cover: £16,039 instead of about £1,884. This one quote is 19% of the system's money error on the training dataset (example 1).

Some comes from rules the forms don't reveal. For example, night work adds 36–39% to every crew line, but it is hard to tell from the form when it applies: of the 12 night quotes in the training dataset, only 3 forms mention out-of-hours work, while 3 other forms do mention it and were priced by day.

How I measure accuracy

A quote is compared with the estimator's real quote in four steps, from coarse to fine:

StepWhat is comparedMeasure
1. Manhole jobyes or noshare right
2. Main linesthe part: cover, gully, channel, pipe linesF1 on lines
3. Other lineslabour, materials, waste, services, hireF1 on lines
4. Moneythe quote totalmean and median absolute error (£)

F1 on lines: precision is the share of the system's lines that are in the real quote, recall is the share of real lines it found. Quantities count in step 4, through the money.

Results on the jobs the system is sure about (green)

These are the jobs the classifier in B labels:

StepHold-out (17)Training (40)
1. Manhole job right17 of 1740 of 40
2. Main lines, F10.830.92
3. Other lines, F10.790.85
4. Mean absolute error£571£440
4. Median absolute error£306£246

Results on all jobs

Including the yellow and red jobs, the gap grows:

StepHold-out (50)Training (97)
1. Manhole job right49 of 5095 of 97
2. Main lines, F10.750.78
3. Other lines, F10.690.78
4. Mean absolute error£1,379£764
4. Median absolute error£744£351

A few large errors dominate: on the hold-out the 3 largest make up 46% of all money error. The hold-out quotes are also larger on average (£3,662 vs £2,767).

Where it falls short

D1. Summary

QuestionSummarise your work in short bullet points.

D2. Choices and their effect

QuestionWhich choices did you make, and what difference did they make?

  1. Code where no judgement is needed, the LLM where it is. I started with code that read the form fields: deterministic and consistent. But key facts often sit in free text (the size in the description, the surface in "Part required"), so the final system leaves the reading and the rules to the LLM. Code turns the forms into text, checks every line against the rate card and adds up the prices. On the training dataset this moved main lines F1 from 0.51 to 0.78, other lines from 0.61 to 0.78, and the mean price error from £1,904 to £764.
  2. Haiku, Sonnet and Opus. The three models were tested to see the trade-off between price and performance. On the same prompt in an earlier step they differed by 1–3 jobs out of 100, while the cost differed up to 27 times. The final system uses Sonnet, at half the price of Opus. Sonnet and Opus were not compared on the final rules.
  3. Clean data first. I excluded the four quotes with clear inconsistencies from the training dataset when writing the rules; they still count when the system is scored. Early versions were built on a "golden" subset of 36 training jobs with clean, unambiguous forms. A rule was kept only if the estimator follows it in most similar quotes, so one-off exceptions did not become rules. On the hold-out, never seen while building, main lines held up (F1 0.75 against 0.78 on the training dataset); other lines dropped more (0.69 against 0.78).
  4. Photos as input. Adding the site photos fixed 2 training jobs and broke 3, for about 50% more cost. The final system doesn't use images, which saves tokens without losing accuracy.

D3. How the AI's output was checked

QuestionHow did you check the AI's output? Where is your approach strong, and where is it weak?

  1. Objective comparison on the hold-out. The main check is a deterministic comparison with the estimator's real quotes on the hold-out dataset: 50 jobs never seen while building, scored once with the system frozen. This is the closest to a scientific test of whether the system works.
  2. Asking the AI for examples. While building, I checked the AI's reasoning by asking it for concrete examples, and found dozens of judgement mistakes. For example, two labelled quotes give a light cover where the engineer's form asks for a heavy one (example 2, example 3). I saw this as a serious inconsistency and an important signal; the AI treated it as minor, because only a few quotes had it.
  3. The weak part. With more time, I would spend it checking the data visually, to spot nuances the AI misses: AI is weaker on real-world scenes. Both I and the AI lack domain knowledge in drainage and civils work, and that is a limit of this approach.

D4. Files

QuestionI'll review several submissions, so please give me one starting page (an index.html or similar) that links to everything you want me to see.

This page is the starting point. Everything it refers to:

FileWhat it is
predictions.jsonanswers for the 849 unlabelled jobs: manhole yes/no, type, quote lines with quantities, confidence, what the estimator should check
code/quote_run.pysends each job's forms to the model with the rules and the rate card
code/build_predictions.pyturns the model's answers into predictions.json
code/holdout_eval.pyscores the frozen system on the hold-out
rules/quote_rules.mdthe 61 quoting rules
rules/examples.mdthe three worked examples in the prompt
Data inconsistenciesthree examples shown in full: form, quote and photos
code.zipeverything above, to run locally next to the job pack

Data inconsistencies

A few real quotes don't agree with their own forms or with the rest of the data. They lower the system's scores: with clean data the scores would be higher.

1. J0222: 150 loads of waste for half a day of work on one cover

The quote prices one cover fitted by a two-person crew in half a day, yet charges 150 loads of waste removal: £14,250, eight times the rest of the quote (£1,789). Every other quote with this line has 1 load; the largest jobs use one or two skips instead. This one quote is 19% of the system's money error on the training dataset.

Engineer's form

Category / typeCivils / Defective Manhole
Request / priorityQuoted Works / P2 Moderate (1 week)
Description of exact locationentrance to site on right hand side
Any potential access issuesno
Can chamber opening be measuredYes
Chamber opening length (mm)860mm
Chamber opening width (mm)700mm
Manhole frame depth (mm)100mm
Manufacturer gradeD400 - HGVs
Is heavier grade requiredNo
Surface typeConcrete
Part requiredcivil team to attend site to try and break free chamber 2nd stage interceptor lid hydraulic lifters breaker

Estimator's quote: £16,039

CodeDescriptionQtyUnit priceTotal
LAB-CIV-HCivils gang (2 operatives + van), in hours, half day1 half day£640£640
SRV-UTILBuried utility plans (search before breaking ground)1 each£85£85
WST-GENWaste removal from site (spoil, broken frames, packaging)150 load£95£14,250
MAT-MORTRapid-set bedding mortar, tub8 tub£68£544
CVR-750-HCover & frame, solid top, 750 x 750 or larger, heavy duty (D400)1 each£520£520

Photos

J0222 site photo J0222 site photo J0222 site photo J0222 site photo

2. J0189: a light cover where the form asks for a heavy one

The cover is in a car park, the grade is D400, and the engineer recommends "a D400 rated lid and frame". The quote gives a light-duty cover (A15/B125).

Engineer's form

Category / typeCivils / Defective Manhole
Request / priorityReactive / P0 Danger (same day)
Description of exact locationcar park (second chamber in rear [place] area )
Any potential access issuesno
Can chamber opening be measuredYes
Chamber opening length (mm)480mm circle
Chamber opening width (mm)480mm
Manhole frame depth (mm)NA
Manufacturer gradeD400 - HGVs
Is heavier grade requiredNo
Surface typeTarmac
Additional notescircle cast [place] manhole chamber lid completely shattered in car park on site [place] have currently used a circle plastic chamber lid from rear [place] to cover exposed chamber in car park plastic lid is to be refitted to correct chamber in rear [place] after new cover and frame fitted on car park car park chamber left with barriers around but needs doing assap due to blocking off Tennant car spaces please note when arrived on site only rememisense that the original chamber lid was cast [place] it is suspected the original lid was not the correct rate and has shattered from cars driving over it due to being in a car park it is recommended to replace this with a D400 rated lid and frame when repair works are carried out please collect cones and barriers and return to depot again it is vital to refit plastic chamber lid to the correct chamber in yhe rear [place] Issue Type NA
Part requiredcivil [place] support to sort out

Estimator's quote: £1,818

CodeDescriptionQtyUnit priceTotal
LAB-CIV-HCivils gang (2 operatives + van), in hours, half day1 half day£640£640
SRV-UTILBuried utility plans (search before breaking ground)1 each£85£85
WST-GENWaste removal from site (spoil, broken frames, packaging)1 load£95£95
MAT-MORTRapid-set bedding mortar, tub2 tub£68£136
MAT-CONCRapid flowable concrete, 25 kg bag1 bag£24£24
MAT-ASPHCold-lay rapid asphalt repair kit2 kit£260£520
MAT-PRIMPrimer for asphalt repair kit1 kit£38£38
MAT-BANDThermoplastic overbanding tape (seals joint round frame)1 roll£95£95
CVR-600-LCover & frame, solid top, 600 x 600, light duty (A15/B125)1 each£185£185

Photos

J0189 site photo J0189 site photo

3. J0381: a light cover where the form asks for a heavier grade

The cover is by a loading bay, the grade is C250, and the form says "Is heavier grade required: Yes". The quote gives a light-duty cover (A15/B125).

Engineer's form

Category / typeCivils / Defective Manhole
Request / priorityPPM / P2 Moderate (1 week)
Description of exact locationsee highlighted plans for exact location manhole chamber not actually on site plans to the right side of [business] unit loading bay/doors
Can chamber opening be measuredNo
Manhole cover length (mm)x
Manhole cover width (mm)x
Manufacturer gradeC250 - Light Goods Vehicle
Is heavier grade requiredYes
Surface typeTarmac
Additional notesI've lost my tape measure so unable to get precise measurements manhole chamber approx 450mm diameter Issue Type tarmac all crumbled away and foul water manhole covers is loose.
Part requiredframe and cover replacement

Estimator's quote: £1,887

CodeDescriptionQtyUnit priceTotal
LAB-CIV-HCivils gang (2 operatives + van), in hours, half day1 half day£640£640
SRV-UTILBuried utility plans (search before breaking ground)1 each£85£85
SUN-CARRCarriage / delivery of materials or plant1 each£45£45
WST-GENWaste removal from site (spoil, broken frames, packaging)1 load£95£95
MAT-MORTRapid-set bedding mortar, tub2 tub£68£136
MAT-CONCRapid flowable concrete, 25 kg bag2 bag£24£48
MAT-ASPHCold-lay rapid asphalt repair kit2 kit£260£520
MAT-PRIMPrimer for asphalt repair kit1 kit£38£38
MAT-BANDThermoplastic overbanding tape (seals joint round frame)1 roll£95£95
CVR-600-LCover & frame, solid top, 600 x 600, light duty (A15/B125)1 each£185£185

Photos

J0381 site photo J0381 site photo J0381 site photo J0381 site photo