top of page

The FY27 Recompete Cliff: Which Federal Contracts Will Change Hands?

Between October 1, 2026 and September 30, 2027, 16,281 federal contracts of $5M or more reach the end of their current period of performance. When that work is bought again, some incumbents keep it and some lose it. Capture teams, and the incumbents themselves, spend real money guessing which is which.


I built Fed-Spend, a federal-contract intelligence platform, and it already ships a hand-weighted "incumbent vulnerability" score. So this project asks an uncomfortable question of my own product: does that score actually predict who loses the recompete? And if not, what does?


The short version: a calibrated model trained on seven years of public award data predicts a change of vendor far better than the heuristic (0.754 vs 0.585 AUC on a year it never saw). Most of the signal is in how the last award was bought, not in the algorithm.


Metric

Value

Contracts of $5M+ ending Oct 2026 to Sep 2027

16,281

Lifetime obligations on those contracts

$1,027.2B

Labeled recompetes, FY2019-FY2025

6,883

Held-out AUC, FY2025 (model / my old heuristic)

0.754 / 0.585

Changed hands, model's top 10% (base rate 50%)

88%



The question


  • Predict: six months before a contract ends, how likely is the follow-on to go to a different vendor?

  • Explain: which award patterns separate retained incumbents from displaced ones?

  • Compare: how does that stack up against the heuristic Fed-Spend ships today, graded on the same labels?

  • Operate: rank every FY27 expiring contract, with reasons, and keep the list current every week.


The data


  • USAspending.gov bulk award downloads: 554,649 prime contracts signed FY2012-FY2026, pulled through the public download API (async jobs, polled to completion) and reconciled to the award count endpoint, plus two years of award modifications to catch contracts signed before FY2012 that are still running (61 FY27 contracts, $176.1B, mostly Energy laboratories, Defense, and NASA). Public domain.

  • Fed-Spend API: the GAO bid protest docket and Fed-Spend's live recompete radar, pulled with a key that lives in Infisical and never touches disk.

  • DuckDB: typed, deduplicated, and rolled up to 46,843 parent vendors, so a subsidiary winning the follow-on counts as the same incumbent.


Building ground truth that did not exist


Federal data never says "award B replaced award A." Without that link there is nothing to predict, so the first real job was a follow-on matcher:


  • Vendor-blind by design. Candidates come from the same office with a matching product or industry code, a start date in a window around the predecessor's end, and a similar size. The match is scored on description similarity (TF-IDF), timing, and size. The vendor is never an input, and a unit test proves it; otherwise the label would simply learn "same vendor means retained."

  • Four rounds of blind hand audits. Each round drew 100 matched pairs, 50 retained and 50 changed, with vendor names hidden, and graded them as the same requirement, related, or wrong. Each round changed the rules: excluding orders under the same parent vehicle, requiring informative descriptions, penalizing place-of-performance conflicts for services, and dropping construction.

  • Final audit: 66% clearly the same requirement, 17% related, 17% wrong. Wrong matches cluster in the "changed" class (28% vs 6%), so change rates lean high and measured accuracy is, if anything, understated. Full audit log.


No time travel


  • Point-in-time features. Everything is computed as of 180 days before the contract ended: competition, offers, vehicle type, set-aside, incumbent share of the office, office and incumbent recompete history: 38 features in all.

  • Already-decided contracts are dropped. If the follow-on was awarded before that date, the outcome was knowable, so the row leaves training.

  • Temporal split. Train on contracts ending FY2019-FY2023, calibrate on FY2024, test once on FY2025.

  • Leakage check. Removing every feature derived from past labels leaves AUC unchanged (0.756), so the result is not riding on a leak.


Results


FY2025 test set, 1,126 recompetes

AUC

Top 10% hit rate

Calibration error

Fed-Spend heuristic, as shipped

0.585

53%

0.151

Logistic regression baseline

0.743

80%

0.059

LightGBM, calibrated (shipped)

0.754

88%

0.053


  • The model beats the heuristic by 0.169 AUC (95% bootstrap CI 0.131 to 0.207). Of the 10% of contracts it flags most strongly, 88% changed hands against a 50% base rate.

  • It does not meaningfully beat logistic regression (+0.012, CI includes zero). The honest reading: the features carry the signal, and the heuristic's problem is its weights, not its lack of machine learning.

  • Calibrated probabilities. Isotonic calibration on FY2024 brings expected calibration error to 0.053, so a 70% means roughly 70%.

  • Where it is weaker: AUC is 0.786 inside DoD, 0.693 for small-business incumbents, and 0.604 for other agencies. On high-confidence labels only, it rises to 0.793.


Calibration curve for the FY2025 held-out test set, predicted versus observed vendor change rate
Predicted vs observed change rate, FY2025 held-out year.

What predicts a change of vendor


Pattern at the last award, FY2019-FY2025

Changed hands

Competed / sole-source

59% / 26%

Order under a multiple-award / single-award vehicle

68% / 42%

Two or more offers / one offer

63-66% / 37%

Incumbent holds under 20% / 20%+ of the office's spend

54% / 25%

Incumbent is a small business / is not

58% / 45%


The pattern is intuitive once it is measured: work that was competed, split across a multiple-award vehicle, and drew several offers is contestable. A sole-source incumbent holding a large share of the office's spend usually keeps it. The change rate also drifted up, from 44% in FY2019 to 55% in FY2024.


SHAP feature importance for the incumbent-loss model
Mean absolute SHAP value by feature (model inputs as named in the code).

The FY27 watchlist


Every expiring contract gets a calibrated probability, a band (top 5%, elevated, typical, low), and its top three reasons in plain language. Summed, the probabilities imply about 8,299 vendor changes in FY27. The top 5% band holds 815 contracts and $14.3B. Open GAO protests appear next to each contract as context, not as a model input, because the docket only reflects protests that are live now.


Streamlit watchlist app showing ranked FY27 expiring contracts with change probability and reasons
The watchlist app: filter by agency, band, or dollar size, or look up any PIID.

Watchlist app agency view with expiring dollars and expected vendor changes by agency
Agency view: where the expiring dollars and the expected vendor changes sit.

Built to run, not just to demo


  • Weekly refresh. A GitHub Actions job runs every Monday: it pulls new and modified awards, refreshes the Fed-Spend radar, rescores the watchlist with the exact model that was evaluated, and commits the new data. Retraining is a reviewed change, never automatic.

  • n8n digest and watchdog. The job posts a week-over-week digest (contracts new to the top 5%, the biggest risk moves, and top-band contracts ending within 90 days) to an authenticated n8n webhook that emails it. A Tuesday watchdog alerts if a week passes with no digest.

  • Governance. A model card mapped to the NIST AI Risk Management Framework (Map, Measure, Manage, Govern), a datasheet, subgroup metrics, and known gaps.

  • Secrets stay out of the repo. Keys are pulled from Infisical into the process at runtime locally and read from GitHub Actions secrets in CI.


What I would do with it


  1. Replace the hand-weighted score. For Fed-Spend, the takeaway is direct: swap the heuristic for the calibrated model, and show the reasons next to the number.

  2. Capture teams: start with the contestable profile. Competed, multiple-award, several offers, and an incumbent with a small share of the office. Those recompetes changed hands about two times in three.

  3. Incumbents: read the band as an early warning. A top-5% contract 12 months out is a signal to invest in the relationship and the proposal now, not in the final quarter.

  4. Treat small agencies with care. The model is weakest outside DoD; use it there as a sort order, not a verdict.


Tools


  • Python 3.12, pandas, and uv with a Makefile for a reproducible pipeline

  • DuckDB SQL for typing, deduplication, vendor rollup, candidate generation, and point-in-time features

  • scikit-learn and LightGBM for TF-IDF matching, logistic regression, gradient boosting, and isotonic calibration

  • SHAP for global importance and per-contract reasons

  • Streamlit and Plotly for the watchlist app; matplotlib for the figures

  • GitHub Actions, n8n, and Infisical for the weekly refresh, digest email, watchdog, and secrets

  • USAspending API and the Fed-Spend API for the data


Reproduce it


Everything runs from one repository: github.com/jasonpellerin-aisolutionist/federal-recompete-cliff. Clone it, run make download, make build, make label, make features, make train, and make score, and every number in this post is recomputed from public data. The docs folder holds the methodology, label audit, and model card.


Limits: labels are inferred from award data, not recorded, and 17% of audited matches were wrong. Only 7,332 of 59,888 ended contracts received a confident label, so scores apply best to contracts like those. The model sees award patterns, not performance ratings, pricing, or proposals. A score describes a pattern, not a judgment about any incumbent.


Data: USAspending.gov (public domain) and the GAO bid protest docket via Fed-Spend. This project is independent and not affiliated with any federal agency.

Comments


bottom of page