Boiler Replacement, Vernon Hill School / WPS
- Bidders
- 4 (predicted 4.3)
- "You" bid
- $139K chance 17%
- Needed to win
- under $133K (−4%, chance 22%)
- 30% target
- $125K (−10%)
- Low bid band
- $74K to $171K median $115K
- Trained on
- 5,696 contracts to 2026-09-10
Trained only on contracts opened 2013 to 2024, then scored on every bid filed in 2025 and 2026: 7,728 bids, each bidder playing the customer in turn. Here is what it gets right, what a simple rule matches, and where it misses.
5,752 contracts 29,404 bids $14.8B in winning bids 2013 to 2026 MA, NJ, NY, OH, PA
The model is fitted on 4,394 contracts opened 2013 to 2024 and never sees a 2025 or 2026 result. The year-by-year check below refits before every test year.
For each test bid, the bidder's own number is its reference price, the number of bidders is predicted, and the model gives its chance of being lowest. The published tab says whether it was.
A flat base rate; one over the predicted number of bidders (no prices at all); one over the true number (which no one knows before opening); and the model itself told the true number.
Bids on one contract rise and fall together, so every range is worked out by redrawing whole contracts (1,000 times), not single bids.
Lower is better. Whiskers are 95% intervals. The two bars at the bottom know the true number of bidders, which nobody knows before bids open: they are the ceiling, not a rival.
| Method | Brier | AUC |
|---|---|---|
Base rate |
0.143 | 0.50 |
1 / predicted bidders |
0.133 | 0.70 |
Win-chance model |
0.133 | 0.70 |
1 / true bidders |
0.115 | 0.77 |
Win-chance model, bidders known |
0.115 | 0.77 |
In 5 of 10 deciles what it said falls inside the 95% interval of what happened; in 5 more it said too much. It runs a little high, worst at the ends: the lowest tenth was given 7.7% and won 3.6%; the highest tenth was given 35.9% and won 31.6%. Vertical bars are 95% intervals (bootstrap by contract).
| Decile | Bids | Said | Won | 95% interval |
|---|---|---|---|---|
| 1 | 773 | 7.7% | 3.6% | 2.8% to 4.3% |
| 2 | 773 | 8.4% | 7.0% | 6.1% to 8.2% |
| 3 | 773 | 10.2% | 7.6% | 6.3% to 9.5% |
| 4 | 772 | 11.8% | 10.6% | 9.1% to 12.4% |
| 5 | 773 | 15.3% | 12.7% | 10.8% to 14.7% |
| 6 | 773 | 18.8% | 18.4% | 16.5% to 20.5% |
| 7 | 772 | 21.9% | 22.8% | 20.8% to 25.0% |
| 8 | 773 | 25.1% | 26.9% | 24.6% to 29.2% |
| 9 | 773 | 29.6% | 29.8% | 27.4% to 32.4% |
| 10 | 773 | 35.9% | 31.6% | 29.3% to 34.5% |
Every test bidder's price moved from −30% to +20% and checked against the bids actually filed (assuming the others bid the same). The line is the model's average chance; the dots are how often the moved price really was lowest, with 95% intervals.
The whole-curve AUC is 0.81; ranking by the price move alone, with no model, already scores 0.78, because lower prices win more often. What the model adds is the level: how much a given cut is worth on this kind of job. On plumbing and HVAC, 10% above the price bid it runs 2 points high.
Refit before every test year from 2018, the model beat the base rate in 8 of 9 years, but beat the price-blind field-size model in only 3. Pooled over all 5,226 contracts: model 0.151, field-size model alone 0.148, base rate 0.159. That is the plainest statement of where the edge comes from today.
Brier at the price bid (lower is better) and AUC. A slice under 15 contracts is marked thin: read it as an anecdote.
| Trade | Contracts | Model | Base | Equal shot, real bidder count | AUC |
|---|---|---|---|---|---|
| Plumbing and HVAC | 291 | 0.194 | 0.203 | 0.160 | 0.61 |
| Plumbing | 95 | 0.214 | 0.223 | 0.174 | 0.55 |
| HVAC | 196 | 0.186 | 0.194 | 0.154 | 0.63 |
| All trades | 1,320 | 0.133 | 0.143 | 0.115 | 0.70 |
| State | Contracts | Model | Base | Equal shot, real bidder count | AUC |
|---|---|---|---|---|---|
| Massachusetts | 30 | 0.188 | 0.161 | 0.149 | 0.59 |
| New Jersey | 24 | 0.172 | 0.173 | 0.158 | 0.59 |
| New York | 168 | 0.197 | 0.215 | 0.155 | 0.68 |
| Ohio thin | 5 | 0.234 | 0.251 | 0.191 | 0.53 |
| Pennsylvania | 64 | 0.200 | 0.212 | 0.180 | 0.63 |
Median miss between the predicted and actual lowest competing bid on plumbing and HVAC test bids. In short: from your own number, the model's median ties a no-model rule (your number times the training years' typical ratio, 0.875), which misses by 16%. What the model adds is the band: 90% of actual low bids fell inside its 80% range (a little wide). With no number of your own, similar past jobs miss by 68%, so the app shows them for size and never prices from them.
1,015 test bids on 243 contracts. A public tab has no costs, so each bidder's cost is its bid divided by a markup. A win is a price under the lowest other bid filed. Money left on the table = second-lowest bid minus ours, on a win. No rule beat bidding the firm's own number at every markup with its 95% interval clear of zero, so the app does not move a firm's number for profit.
| Rule (cost = bid / 1.08) | Win rate | Profit | vs own number |
|---|---|---|---|
| Bid the number the firm actually bid | 23.9% | $37.19M | |
| Most profit within 5% of the firm's own number | 17.0% | $35.74M | −4% |
| Most profit on average (cap 35% over cost) | 6.0% | $24.34M | −35% |
| Highest price with a 20% chance | 14.5% | $37M | −1% |
| Highest price with a 30% chance | 25.4% | $27.29M | −27% |
| Highest price with a 40% chance | 26.2% | $30.69M | −17% |
| Rule (cost = bid / 1.12) | Win rate | Profit | vs own number |
|---|---|---|---|
| Bid the number the firm actually bid | 23.9% | $53.79M | |
| Most profit within 5% of the firm's own number | 17.6% | $49.41M | −8% |
| Most profit on average (cap 35% over cost) | 9.2% | $44.11M | −18% |
| Highest price with a 20% chance | 14.6% | $50.57M | −6% |
| Highest price with a 30% chance | 25.6% | $48.83M | −9% |
| Highest price with a 40% chance | 35.9% | $28.52M | −47% |
| Rule (cost = bid / 1.20) | Win rate | Profit | vs own number |
|---|---|---|---|
| Bid the number the firm actually bid | 23.9% | $83.68M | |
| Most profit within 5% of the firm's own number | 21.3% | $93.51M | +12% |
| Most profit on average (cap 35% over cost) | 18.6% | $91.44M | +9% |
| Highest price with a 20% chance | 15.9% | $75.67M | −10% |
| Highest price with a 30% chance | 25.7% | $91.77M | +10% |
| Highest price with a 40% chance | 38.8% | $79.13M | −5% |
The 12 most recent plumbing, HVAC or mechanical contracts opened in 2025 to 2026 with 3 or more responsive bids, newest first. Chosen by date alone; misses stay in. For each, the model was refitted on every contract opened before that day, and priced the bidder in the middle of the field ("you", a fixed rule) from its own number, with cost taken as its bid / 1.12.
Over only these contracts; a dozen openings is an illustration, not a score. The scores are the holdout sections above.
From a new building filing that names an owner and an architect but no GC yet, how often do the public histories put the GC that was later named first (top-1) or in the first three (top-3)? It is a ranked guess. Backtested in New York City, Chicago, Philadelphia; in the app it ranks open New York City filings today.
| City | Filings tested | Top pick right | In the top three | Busiest GC, top pick | Busiest GCs, top three |
|---|---|---|---|---|---|
| New York City | 4,648 | 21% (20% to 22%) | 35% (33% to 36%) | 4% | 10% |
| Chicago | 2,032 | 25% (23% to 27%) | 34% (32% to 36%) | 5% | 13% |
| Philadelphia | 2,272 | 12% (11% to 14%) | 18% (17% to 20%) | 3% | 6% |
Method. Score each GC by the share of earlier jobs with a known GC it built for this owner, this owner's signatory, this architect or engineer (license number) and this filing representative, plus its share of jobs in the borough and size band, nudged by how close the job is to its typical size. Weights tuned on the last fifth of the training period only. The test filings come after the training cutoff (2025-10-30 in New York City); the signals are the owner, the owner's signatory, the architect or engineer, the filing representative. Baseline: the GCs with the most jobs in the filing's borough and size band before the cutoff. Ranges are 95% Wilson score intervals.
What the New York City test does not show.
Generated 2026-11-02 by python scripts/gc_predict_report.py.
python scripts/backtest_report.py refits the model on the public warehouse (75 seconds) and writes backtest.json, which this page reads. Generated 2026-11-02T03:44:34+00:00; the app's live model is ptw-20261001T220731.