earlyco.ai

A 2026 build by Max Abramsky · EarlyCo, Inc.

Scattered public records.
One traceable answer.

I built a precision-first entity-resolution engine over Florida public records. Give it a restaurant’s name and street address, and it returns exactly one cited answer, match, ambiguous or unresolved, about which licensed business, legal entity and licenses those are. It was built for credit teams that fund Florida restaurants.

business entity records in production1
1,001,760
source-record rows, each traced to the government feed it came from2
3,536,041
auto-matches correct on 250 blinded real restaurant rows3
215/215
false attachments on 50 adversarial rows: upstream-pick baseline, then the agent path4
35 → 0

Built March to September 2026. Collection is off; this page is the build record, drawn from commits, test reports and dated production snapshots.

One buyer, one output, and a test that could kill it.

In August I wrote the product down to one page and pointed every agent at it as the only product authority.5

The buyer
The head of credit or operations at a lender that already funds Florida restaurants, already pays a KYB vendor, and wires money within hours.
The output
A Florida resolution receipt: exactly one of match, ambiguous or unresolved, with the candidates, match reasons, license numbers, legal names, citations, the coverage of every feed searched, and duplicate-shell warnings.
Abstention
Ambiguous and unresolved are successful answers. They route to an exception queue, like a TIN mismatch, not to an automatic decline.
Not for sale
A risk score, a diligence book, an underwriting case file, MCP or a CLI as the product, an investigation agent, or national registry and watchlist data.
A production receipt. Tabs for Match, Ambiguous and Unresolved; the Match tab is open. One licensed-operation candidate with its name, address, legal name and two license identifiers blacked out. Why it surfaced: address_canonical and address_plus_name. Exact source coverage: 14 available, 0 degraded, 0 unavailable.
The receipt in production, captured August 24, 2026. Name, address and license numbers redacted. The two licenses on this match, one alcohol and one seated food, belonged to one restaurant: the shape in case 2 below.

The test I set

The plan was to ask one lender for its last 50 funded Florida restaurant files, run the receipt on each, and sort the results into three piles.

  1. Pile 1Silent wrong bind. The lender funded company A, but the food or alcohol license at that address belongs to company B.
  2. Pile 2Refuse. A famous name on the wrong block.
  3. Pile 3Split. Two plausible shells, so do not pick.

If pile 1 is empty, walk. That is a matcher, not a must-buy.

Product lock, August 20, 2026

From a government row to one cited answer.

Every ingested row becomes an observation tied to its source record and URL. Identifiers decide identity first; names and addresses decide only behind guards. When the evidence is close, the resolver says so instead of guessing.

System diagram: from government feeds to one cited answerSources feed a raw archive and then 3.5 million observations, each tied to its source. An identifier-authority layer sets what each ID may do. An offline batch merge with eight vetoes maintains the entity graph. The deterministic resolver tries seven tiers in order, refuses anything below 0.6 confidence and calls near ties within 0.05 ambiguous, then returns match, ambiguous or unresolved as a receipt with a citation on every field.1SourcesState licensing11 feeds, dailyCorporate registry2 daily, 1 weeklySecured-loan filingson demand, per case47 manual, 1 quarantinedeach with a written reason2Raw archiveRaw bytes, storedcontent-addressedby SHA-256Built August 17;not confirmed live3Observations3.5 million rowseach tied to a source record,its URL and an observed-attime4Identifier authorityEach source maps to theagency that issues its IDs.Each ID carries a policy:must linksupportingrelation onlyforbiddenUnknown issuer: corroborates,never drives a match.Person-held licenses arerelations, not identity.5Entity graph and batch merge, offlineEight vetoes, series-aware. Every merge records its run andprior state, so it can be reverted. Every decision is stored.The scheduled merge stays in dry run.6ResolverDeterministic. First hit wins.1 FEIN, exact2 State document number3 License number4 Phone, name-gated5 Canonical address6 Address plus name7 Name in county or ZIP8 Embedding search: offNothing below 0.6 resolves.Top two within 0.05:ambiguous.Weak name agreement ispinned at 0.7 and forcedto ambiguous. Chains refusename plus city.matchambiguousunresolvedExactly one answer.Ambiguous and unresolvedgo to an exception queue.7ReceiptEvery populated fieldcites its source type,URL, record ID andobserved-at time.Coverage for each of14 named feeds,searched or not,and how fresh.An optional as-of timereturns the recordas it stood then.Gated on every pull request: 48 resolver cases and 23 merge pairs. One false positive fails the build.System diagram: from government feeds to one cited answerSources feed a raw archive and then 3.5 million observations, each tied to its source. An identifier-authority layer sets what each ID may do. An offline batch merge with eight vetoes maintains the entity graph. The deterministic resolver tries seven tiers in order, refuses anything below 0.6 confidence and calls near ties within 0.05 ambiguous, then returns match, ambiguous or unresolved as a receipt with a citation on every field.1SourcesState licensing: 11 feeds, dailyCorporate registry: 2 daily, 1 weeklySecured-loan filings: on demand47 manual, 1 quarantinedeach with a written reason2Raw archiveRaw bytes, content-addressed by SHA-256Built August 17; not confirmed live3Observations3.5 million rows,each with a source record, URL and time4Identifier authorityEach ID carries a policy:Unknown issuer: corroborates, never drives.Person-held licenses are relations.must linksupportingrelation onlyforbidden5Entity graph and batch mergeEight vetoes, series-aware. Every mergerecords its run and prior state. Everydecision is stored. Scheduled runs: dry run.6ResolverDeterministic. First hit wins.1 FEIN, exact2 State document number3 License number4 Phone, name-gated5 Canonical address6 Address plus name7 Name in county or ZIP8 Embedding search: offNothing below 0.6 resolves.Top two within 0.05: ambiguous.Weak name agreement is pinned at 0.7and forced to ambiguous.matchambiguousunresolvedExactly one answer. Ambiguous and unresolvedgo to an exception queue.7ReceiptEvery populated field cites its source type,URL, record ID and observed-at time.Coverage for each of 14 named feeds.An optional as-of time returns the recordas it stood then.Gated on every pull request: 48 resolvercases and 23 merge pairs. One falsepositive fails the build.
  1. Sources

    Fourteen Florida state feeds were on schedules: 11 daily from the state licensing agency (food service, mobile food, inspections, ownership changes, alcohol, lodging and more) and 3 from the corporate registry. Statewide secured-loan (UCC) search ran per case. Everything else was manual with a written reason, and a CI test kept the ledger total, so no source could sit in limbo.

  2. Raw archive

    Florida’s extracts are rolling windows, not archives. Raw bytes are stored content-addressed by SHA-256, so an unchanged file costs one hash. Built August 17; not confirmed live before collection stopped.

  3. Observations

    About 3.5 million source-record rows. A July provenance gate brought registry coverage to 100%: every row traces to a source record with a URL and an observed-at time.

  4. Identifier authority

    Each source maps to the agency that issues its identifiers, and each identifier carries a link policy. An unmapped source can corroborate a match but never drive one. Declaring issuers made 487,277 already-ingested licenses usable as identity.

  5. Entity graph and batch merge

    Offline merging, separate from the lookup. Eight vetoes block a merge whatever the name score: a distinct current food license, alcohol license, state registration, FEIN, phone, suite, unit number or venue outlet. License conflicts count only within one series. Merges are reversible, and every accept, veto or deferral is stored as a decision.

  6. Resolver

    Seven deterministic tiers, first hit wins, from FEIN down to a name scoped to one county or ZIP. Embedding search is off and returns an error if requested. Relocation retries cap at 0.88, below the 0.9 auto floor, and last-resort renamed-occupant candidates cap at 0.55, so the credit path cannot resolve them.

  7. Receipt

    One decision, its candidates and reasons, and a citation on every populated field. Coverage lists each of 14 named feeds, searched or not, with freshness and the corpus timestamp. In the spec’s words: “A missing row in a degraded or unavailable feed must never become a clean result.”

63 managed sources in one ledger14 on schedules, 1 on demand, 47 manual with a written reason each, 1 quarantined.14 on schedules1 on demand47 manual, each with a written reason1 quarantined14on schedules47manual, each with a written reason1on demand1quarantined63 managed sources in one ledger14 on schedules, 1 on demand, 47 manual with a written reason each, 1 quarantined.14 on schedules1 on demand47 manual, each with a written reason1 quarantined14on schedules47manual1on demand1quarantined
The final source ledger: 63 managed sources, 14 of them on schedules.6 On August 10, 33 of 64 monitored source contracts were stale. That story is the second incident below.

Scale caveat. About 1 million entity records sat in production, but in May 859,147 of them, outside the restaurant and hospitality slice, had no canonical record. The receipt and every test on this page are about restaurants.

Watch the resolver decide.

Eight hard cases from the build record. Each shows the inputs, what a naive matcher would do, the checks that decide it, and the answer. Bracketed words stand in for real names. Licenses show only their state series: SEA seated food, NOS non-seating, MFD mobile food, BEV alcohol.

Case 1 of 8Merge decisionFound in production after the August 15 batch merge

Two grills inside one arena

Record A

Name
[venue] GRILL
Address
The arena’s street address, no unit (agrees)
Food license
SEA••••••• (conflicts)

Record B

Name
[venue] CLUB GRILL
Address
Same address, no unit (agrees)
Food license
SEA•••••••different number (conflicts)

A naive matcherThe August 15 job merged any pair at a shared address once name containment reached 0.7. These pairs scored 0.70 to 0.81.

Naive answer: Mergewrong

What this resolver checks

  1. AddressSame canonical addressAgrees
  2. Name containment0.70 to 0.81Above the old 0.7 bar
  3. Licenses in one seriesSEA and SEA, different numbersVeto fires

Kept separate

Two distinct active licenses in the same series at one address are two businesses, whatever the names say.

On the record. The August 15 run made 39 confirmed false merges of this class, all repaired in production the next morning. Two related vetoes followed: numbered carts at a theme-park venue (95 merge proposals in one dry run) and outlets that share a venue name.

Case 2 of 8Merge decisionFound in production forensics, August 16

One restaurant, two licenses

Record A

Name
[restaurant] (agrees)
Address
[street address] (agrees)
License
SEA•••••••seated food

Record B

Name
[restaurant] (agrees)
Address
[street address] (agrees)
License
BEV•••••••alcohol; also listed without the prefix

A naive matcherA blunt rule, “different identifiers block a merge”, splits one restaurant into two businesses.

Naive answer: Keep apartwrong

What this resolver checks

  1. Address and nameSame premises, same nameAgree
  2. License seriesSEA is food, BEV is alcoholNo conflict across series
  3. Prefix-dropped valueSame seven digits as the BEV licenseSame license

Merged

A seated-food license and an alcohol license are what one restaurant normally holds. A license conflict counts only within one series.

On the record. Forensics on the August 15 run found 52 false vetoes of exactly this shape. The repair left these pairs merged on purpose.

Case 3 of 8LookupBlinded customer test, July 16

Two food trucks at one commissary

Submitted

Trade name
[truck A] (conflicts)
Address
A commissary that dozens of trucks list (agrees)
License
Withheld as ground truth

Top candidate

Trade name
[truck C] (conflicts)
Address
Same commissary (agrees)
License
MFD•••••••a nearby number

A naive matcherMatches on the address and attaches the wrong truck.

Naive answer: Matchwrong

What this resolver checks

  1. Canonical addressThe commissaryAgrees with dozens of trucks
  2. Name at this address[truck A] against [truck C]Contradicts
  3. Mobile unit, address-only evidenceCandidate holds an MFD licenseNo auto-match

Sent to review

A shared address is the “same site, different operator” trap. A candidate with a mobile-food license can never auto-match on address evidence alone. An exact license, FEIN or state document number still can.

On the record. In the July run the name check caught both trucks and held them for review. After the structural guard shipped, about 10 commissary trucks in a later verification round were held by rule.

Case 4 of 8LookupFound in a live test, fixed July 7

A closed market read as open

Submitted

Name
[distinctive word] MARKETPLACE (conflicts)
Status
Closed
Location
ZIP code Z (agrees)

Candidate

Name
MARKETPLACE (conflicts)
Status
Open
Location
Same ZIP code (agrees)

A naive matcherThe scoped-name tier used token containment. The open record’s only word sat inside the submitted name, so containment was 1.0 and the row resolved at 0.89. A closed business read as open.

Naive answer: Match at 0.89wrong

What this resolver checks

  1. IdentifiersNone submittedFalls through to name
  2. Name within the ZIPContainment 1.0 on one shared wordWould resolve
  3. Distinctive anchor wordThe only shared word is genericNo attribution

Refused

Generic food and commerce words (market, marketplace, deli, eatery, bakery, grocery, lounge, pizzeria, taqueria, trattoria, catering) cannot carry an attribution alone. A recall guard keeps a restaurant matching its own “[name] RESTAURANT” record.

On the record. This was the one false-clean found in live testing. The next live run of 15 restaurants matched 15 of 15 with no false-cleans.

Case 5 of 8LookupPrecision fixture, run on every pull request

Right owner, wrong trade name

Submitted

Legal name
[owner] LLC (agrees)
Trade name
[cafe B] (conflicts)
Address
Site 1

Records at site 1

Legal name
[owner] LLC (agrees)
Trade name
[cafe A] (conflicts)
Also owned
[cafe B] at site 2

A naive matcherThe legal name agrees at the address, so it rescues the wrong trade name, or the owner match folds both cafes into one entity.

Naive answer: Matchwrong

What this resolver checks

  1. Legal name[owner] LLC owns both cafesAgrees, owner only
  2. Trade name at site 1[cafe A] operates here, not [cafe B]Conflicts
  3. Which object is the restaurantThe trade name drives restaurant identityNo match

Kept separate

Trade name, legal entity, food-license holder, alcohol-license holder, premises and predecessor are separate objects. An owner is not a restaurant, and sibling cafes stay apart.

On the record. The 48 resolver precision cases that run on every pull request cover this family: trade name as the primary name, a legal-name and trade-name conflict, and several trade names under one owner.

Case 6 of 8Merge decisionMerge dry run, August 17

Same license, new restaurant

Record A

Name
[franchise A], closed (conflicts)
Premises
Unit U (agrees)
Food license
SEA•••••••same number (agrees)

Record B

Name
[restaurant B] (conflicts)
Premises
Unit U (agrees)
Food license
SEA•••••••same number (agrees)

A naive matcherA shared license plus a shared address scores 1.0 and merges two businesses.

Naive answer: Mergewrong

What this resolver checks

  1. License valueSame SEA numberAgrees
  2. PremisesSame unitAgrees
  3. Name corroborationUnrelated namesRequired and missing

Sent to review

The schema keeps one current holder per license value, so any shared value is partly history. At one premises, a duplicate record and a hand-off to a new operator look identical. Without name evidence, a person decides.

On the record. In the first dry run, 310 of 469 shared-identifier merge proposals were confirmed hand-offs, and all 469 carried zero name evidence. The language-model verifier is told the license changed hands, so it cannot undo the guard.

Case 7 of 8Agent reviewAdversarial benchmark, July 20

A stale pick from upstream

Submitted

Restaurant
Name and street address
Upstream pick
The previous license holder at the address (conflicts)

Candidate slate

Pick
Previous holder, stale (conflicts)
Other 1
Current holder (agrees)
Other 2
Another real candidate

A naive matcherThe deterministic baseline keeps the upstream pick and attaches the predecessor.

Naive answer: Attach the pickwrong

What each path did

  1. Upstream pickPrevious license holder at this addressStale
  2. Deterministic baselineKeeps the pickFalse attachment
  3. Agent pathRejects the pick, selects the current holderCorrected

Matched, corrected

Across 50 adversarial rows the agent overturned 16 of 25 wrong or stale picks, abstained on all 10 rows whose true entity was withheld, and attached nothing wrongly.

On the record. It cost $0.22 a row, ran 237 times slower, and abstained on 5 rows that were already right. The cut that followed kept language models out of canonical identity.

Case 8 of 8LookupBlinded three-region test, July 15

Two stands, nearly the same license

Submitted

Name
[venue] stand [letter]
Address
The venue (agrees)
License
Withheld; truth is NOS•••••••

Top candidate

Name
A neighboring stand (conflicts)
Address
The venue (agrees)
License
NOS•••••••a few digits off, also listed bare (conflicts)

A naive matcherThe older full-book matcher auto-matched it. It was that matcher’s only false positive in 116 auto-matches.

Naive answer: Matchwrong

What this resolver checks

  1. AddressSame venueAgrees for both stands
  2. Top two candidatesScores within 0.05Near tie
  3. Ambiguity marginTwo different records within 0.05Ambiguous

Sent to review

When the top two different records sit within 0.05 of each other, the resolver will not pick one.

On the record. The row became a permanent same-site, different-operator regression test.

Measured on rows nobody had seen.

Blinded customer‑path test, July 15 to 17

Fresh restaurants were drawn from the state’s live food-license extracts at run time. Each upload row carried only what a lender collects: legal name, trade name, street, city and ZIP. License numbers were withheld and kept as ground truth. Rows went through the real product path, from sign-in and CSV upload to the full run, and the analysis used a read-only connection.3

Where 250 blinded rows wentRun 1: 150 rows, 132 auto-matched (all correct), 10 sent to review, 8 unresolved. Run 2: 100 rows, 83 auto-matched (all correct), 14 sent to review, 3 unresolved.Auto-matchedSent to reviewUnresolvedRun 1, July 15150 rows, 3 regions, 17 counties132 auto-matched10 sent to review8 unresolved132 auto-matched, all correct10 sent to review, 8 unresolvedRun 2, July 16100 rows, 9 counties83 auto-matched14 sent to review3 unresolved83 auto-matched, all correct14 sent to review, 3 unresolvedWhere 250 blinded rows wentRun 1: 150 rows, 132 auto-matched (all correct), 10 sent to review, 8 unresolved. Run 2: 100 rows, 83 auto-matched (all correct), 14 sent to review, 3 unresolved.Auto-matchedSent to reviewUnresolvedRun 1, July 15150 rows, all 132 auto-matches correct132 auto-matched10 sent to review8 unresolved132 auto-matched10 review8 unresolvedRun 2, July 16100 rows, all 83 auto-matches correct83 auto-matched14 sent to review3 unresolved83 auto-matched14 review3 unresolved
auto-matches correct
215 of 215
rows sent to review or left unresolved
35 of 250 (14%)
wrong in three re-runs after fixes: 83 of 83, 67 of 67, 72 of 72
0

Where the hard rows went. None auto-attached. Every wrong candidate sat in review: an inn’s food-service row matched to the property’s bed-and-breakfast lodging license, a venue stand matched to its neighbor with a near-identical license number, and two food trucks matched to a different truck at the same commissary. All three unresolved rows in run 2 were non-seating licenses, catering or kitchen-only, with a thin public footprint.

What this does not prove. No named person reviewed the books; that gate stayed at 0 of 150 rows, and the report says an automated workflow cannot honestly close it. Ground truth was the withheld license number. On the same three books an older full-book matcher had scored 115 of 116; its one false positive is case 8 above.

Deterministic baseline against an agent, July 20

50 real restaurant submissions, each with three real candidates and an upstream pick chosen to mislead: 20 wrong picks, 5 stale predecessors, 15 correct picks among close candidates, and 10 rows whose true entity was withheld to test abstention. The baseline keeps the upstream pick. It is not the production resolver, so its 30% is not the lookup’s score; it shows what accepting an upstream candidate costs.4

Adversarial benchmark, 50 rows eachDeterministic baseline: 15 correct, 35 false attachments, 30 percent accurate. Agent path: 26 correct targets, 10 correct abstentions, 14 over-abstentions, 0 false attachments, 72 percent accurate.Correct targetCorrect abstentionOver-abstentionFalse attachmentDeterministic baselinekeeps the upstream pick15 correct target1535 false attachment3530% accurate35 false attachmentsAgent pathGPT-5.4 via OpenRouter, 260 model calls26 correct target2610 correct abstention1014 over-abstention1472% accurate0 false attachmentsAdversarial benchmark, 50 rows eachDeterministic baseline: 15 correct, 35 false attachments, 30 percent accurate. Agent path: 26 correct targets, 10 correct abstentions, 14 over-abstentions, 0 false attachments, 72 percent accurate.Correct targetCorrect abstentionOver-abstentionFalse attachmentDeterministic baselinekeeps the upstream pick15 correct target1535 false attachment3530%35 falseAgent pathGPT-5.4 via OpenRouter, 260 model calls26 correct target2610 correct abstention1014 over-abstention1472%0 false
Benchmark results, deterministic baseline and agent path
50 adversarial rowsBaselineAgent path
Accuracy30.0%72.0%
Accuracy on rows with a true target37.5%65.0%
Wrong or stale picks recovered0 of 2516 of 25
Abstained when the truth was withheld0 of 1010 of 10
False attachments350
Precision on resolved rows0.301.00
Time for 50 rows4.5 s1,055.2 s
Model cost$0$11.07, or $0.22 a row

The agent bought precision with time and caution: 237 times slower, and it abstained on 14 of the 40 rows that had a true answer. The benchmark states its own limits: the slates were composed, not replayed from matcher logs, and it is not a blinded human baseline. The cut that followed kept models out of identity: “Do not let an LLM write canonical identity.”

Gates on every pull request

  • 48

    Resolver precision cases, 29 that must match and 19 that must not: co-tenants at one address, a shared FEIN, a shared state document, one phone across different names, weak-name near ties, generic names in one ZIP, and trade name against legal name. The test asserts zero false positives.

  • 23

    Labeled merge pairs, 10 merge and 13 must not, most negatives taken from real production dry runs. In the fixture’s words: “Zero false positives is a hard CI gate.”

  • 130

    Rows in a regression set run against production on demand rather than in CI: all 80 license-graded rows correct with 0 false positives, and all 8 abstention traps abstained. It mostly tests exact-license lookup, so the blinded run above is the real test.

Two failures, and what they changed.

Both were mine to own. Each write-up covers what happened, why, how it was found, the fix and how the fix was verified.

August 15 to 17, 2026

39 false merges, repaired in about 13 hours

A second matching step that hadn’t been through the same checks ran against production and merged distinct businesses at shared addresses: grills in one arena, stands at one venue. A read-only audit caught it the next morning, and by 10:37 the merges were repaired with decision records, merges had become reversible, and a precision gate guarded the path in CI.

Time from the production merge run, August 15 at 21:33 EDTMatcher rebuilt and merged: 12 h 40 min after the run; 39 false merges repaired in production: 13 h 4 min after the run; Every distinct-identifier pair adjudicated: 14 h 46 min after the run; Four more false-merge classes vetoed: 43 h 53 min after the run.0 h12 h24 h36 h48 hMatcher rebuilt and mergedvetoes, reversible merges, CI gateMatcher rebuilt and merged: 12 h 40 min after the run12 h 40 min39 false merges repaired in productionwith decision records39 false merges repaired in production: 13 h 4 min after the run13 h 4 minEvery distinct-identifier pair adjudicatedverdicts stored as decisionsEvery distinct-identifier pair adjudicated: 14 h 46 min after the run14 h 46 minFour more false-merge classes vetoedfound in dry runsFour more false-merge classes vetoed: 43 h 53 min after the run43 h 53 minTime from the production merge run, August 15 at 21:33 EDTMatcher rebuilt and merged: 12 h 40 min after the run; 39 false merges repaired in production: 13 h 4 min after the run; Every distinct-identifier pair adjudicated: 14 h 46 min after the run; Four more false-merge classes vetoed: 43 h 53 min after the run.0 h12 h24 h36 h48 hMatcher rebuilt and mergedMatcher rebuilt and merged: 12 h 40 min after the run12 h 40 min39 false merges repaired in production39 false merges repaired in production: 13 h 4 min after the run13 h 4 minEvery distinct-identifier pair adjudicatedEvery distinct-identifier pair adjudicated: 14 h 46 min after the run14 h 46 minFour more false-merge classes vetoedFour more false-merge classes vetoed: 43 h 53 min after the run43 h 53 min
Hours from the production run to each fix.
Read the write-up

June to August 2026

Every check green, no data

The state inspection feed delivered 2,728 observations for June against a median of 12,362, and nothing went red. Every gate checked structure, not volume. Twenty days of June were lost for good, because the state’s extracts are rolling windows.

Inspection observations by month, November 2025 to July 2026Monthly counts from the state food-inspection feed: Nov 10,274, Dec 12,359, Jan 12,365, Feb 12,206, Mar 15,032, Apr 12,369, May 8,915, Jun 2,728, Jul 12,284. June delivered 2,728 against a prior six-month median of 12,362, a ratio of 0.22. Nothing alerted.Median of the six months before June, 12,362Critical: below 50% of that median04K8K12K16KNov 2025: 10,274 observationsNovDec 2025: 12,359 observationsDecJan 2026: 12,365 observationsJanFeb 2026: 12,206 observationsFebMar 2026: 15,032 observationsMarApr 2026: 12,369 observationsAprMay 2026: 8,915 observationsMayJun 2026: 2,728 observationsJun2,728Jul 2026: 12,284 observationsJul20252026Inspection observations by month, November 2025 to July 2026Monthly counts from the state food-inspection feed: Nov 10,274, Dec 12,359, Jan 12,365, Feb 12,206, Mar 15,032, Apr 12,369, May 8,915, Jun 2,728, Jul 12,284. June delivered 2,728 against a prior six-month median of 12,362, a ratio of 0.22. Nothing alerted.Prior six-month median, 12,362Critical: below 50% of that median04K8K12K16KNov 2025: 10,274 observationsNovDec 2025: 12,359 observationsDecJan 2026: 12,365 observationsJanFeb 2026: 12,206 observationsFebMar 2026: 15,032 observationsMarApr 2026: 12,369 observationsAprMay 2026: 8,915 observationsMayJun 2026: 2,728 observationsJun2,728Jul 2026: 12,284 observationsJul20252026
Inspection observations by month.
Read the write-up

I stopped when the test said walk.

The engineering held up; the market case didn’t. I pitched lenders and insurance carriers, and none signed on, so I ran my own backtest to find out whether they were missing something.

A statewide loader for secured-loan (UCC) filings bound each debtor to a food- or alcohol-licensed business through the same fail-closed resolver. A read-only analysis raised flags from the past year of filings for 8 lenders, and a verifier checked them.

lenders in my own backtest
8
spot-checked flags that held up
10 of 10
flags a cheap per-borrower search would not have found
1 of 36

The flags held, but only 1 of 36 was something a lender couldn’t get from a cheap per-borrower UCC search. Meanwhile, keeping about 60 sources fresh as one person was a full-time job on its own; Every check green, no data shows what that upkeep looks like.

No buyer signed on, the signal was rarely unique, and that upkeep sat behind it. Under the kill test I had written in August, that meant walk. I closed the line on September 27, 2026.7

What else I cut

  • MCP. I built a 13-tool local MCP server and a hosted endpoint limited to three tools, which stayed dark behind a rollout flag. The MCP surfaces saw 17 production calls, so I cut them. The route now returns 410 Gone.
  • Sediment. I unmounted the book product, the autonomous diligence agent, the risk file and MCP, and each route now returns 410. On August 22 one pull request deleted the local MCP package and the other dead surfaces. The README calls what was left “sediment. Do not extend them.”
  • A rule for the agents. If a task would add an MCP, book-review, autonomous, diligence, risk-file or case-file surface and is not a deletion, stop and point at the product page.
One pull request, August 22, 2026149,893 lines removed and 5,528 added across 414 files.149,893 lines removed5,528 lines added149,893lines removed5,528lines addedOne pull request, August 22, 2026149,893 lines removed and 5,528 added across 414 files.149,893 lines removed5,528 lines added149,893lines removed5,528added
The cut, August 22, 2026: 414 files in one pull request.

I directed the agents that wrote it.

I founded EarlyCo. Claude Code and Codex wrote the code under my direction, with some Cursor early on, and a contract engineer helped set up the initial database in March. I scoped the work, wrote the product lock and the agent briefings, designed the evaluations and their ground truth, reviewed and merged through pull requests, approved production writes as bounded runs, and decided what shipped and what was cut.

commits on main, March 11 to September 2, 20268
2,110
merged as numbered pull requests
1,931
test files
767
SQL migrations
144
commits on main co-authored by Claude
675
dated Codex entries in the handoff ledger
132
Commits on main by month, 2026March 111, April 465, May 929, June 2, July 476, August 126, September 1.Mar 2026: 111 commits111MarApr 2026: 465 commits465AprMay 2026: 929 commits929MayJun 2026: 2 commits2JunJul 2026: 476 commits476JulAug 2026: 126 commits126AugSep 2026: 1 commits1SepCommits on main by month, 2026March 111, April 465, May 929, June 2, July 476, August 126, September 1.Mar 2026: 111 commits111MarApr 2026: 465 commits465AprMay 2026: 929 commits929MayJun 2026: 2 commits2JunJul 2026: 476 commits476JulAug 2026: 126 commits126AugSep 2026: 1 commits1Sep
Commits on main by month, 2026.

How the agents were kept honest

  • One product authority. Every agent briefing pointed at the product page as the only product authority, and the cut list carried its own rule for agents.
  • Gates before merge. Main required three status checks and rejected direct pushes. Every pull request ran the static checks and the unit and integration suites, precision gates included.
  • Dry run by default. Production write scripts for repair, rollback, re-linking and merging do nothing without an explicit apply flag. Production writes ran as bounded runs, verified by separate read-only runs.
  • Schedules on an allowlist. A workflow-hygiene test rejects any autonomous schedule that is not explicitly allowed.
  • Agent errors caught by design. The language-model cluster verifier counted a shared address as corroboration, so it “could re-merge exactly the pairs the guard protects.” Its prompt now states license hand-offs outright, so it cannot undo the code guard.

What I would do differently

  1. Run the sales test before building surfaces. I wrote “Do this before adding surfaces” in August, after most of them existed. Before that lock the product had pointed at vendor prospecting, insurance underwriting data, insurance books and lender credit.
  2. Keep one governed matcher. The worst incident came from a second matcher that hadn’t been through the same checks. Name containment should never decide identity on its own.
  3. Treat built and running as different states. A job counts once it runs on a schedule and something checks that it delivered.
  4. Keep raw bytes from the first ingest. State feeds are rolling windows. A gap that outlives the window is permanent.
  5. Scope every accuracy claim to its evidence. A July copy audit flagged “zero false-cleans” as true only of one dated 15-restaurant batch. Every number on this page carries its source and date for that reason.

Inspect saved records.

Before this case study, the site showed three questions answered from saved Florida public records. They still work, with the original fields, dated sources and what each record does not establish. They are fixed records, not live search.

  1. A restaurant buildout. The permit links to its master building permit and to a second plumbing permit.

    County records checked October 6, 2026; DBPR credential snapshot September 19, 2026

  2. The filing’s charter reference resolves to a separately captured LLC record.

    Sunbiz source captures: September 20, 2026 UTC

  3. The alcohol certificate refers explicitly to the land certificate. Both are historical records.

    Historic certificate rows checked against the county source on October 6, 2026

All saved examples

Notes and sources

Sources are documents and commits in EarlyCo’s private repository. Dates are commit dates unless stated. Pull request numbers refer to that repository.

  1. 1,001,760 entity records: the backend ship-ready sign-off report, section 3, counted July 3, 2026 (PR #1661). In May 2026, 859,147 entities outside the restaurant and hospitality slice had no canonical record (beta launch checklist, May 13). ↩
  2. 3,536,041 source-record rows, registered at 100% coverage by the provenance backfill: the ontology transformation report, July 9, 2026 (PR #1762). The July 3 sign-off had counted 3,521,089 observations. ↩
  3. Customer-path dogfood report, July 16, 2026 (PR #1947), and the three-region rollout report, July 15. Follow-up verification rounds: PR #1950. ↩
  4. Adversarial deterministic-versus-agent benchmark, 50 rows, committed July 20, 2026 (PR #1975). The deterministic baseline accepts the upstream candidate; it is not the production resolver. ↩
  5. Product lock dated August 20, 2026, committed August 22 (PR #2256) and edited August 23 (PR #2267). Quoted text is exact. ↩
  6. Source ledger: the ingestion control plane on main. Monitored contracts and staleness: ingestion live-health audit, August 10, 2026. ↩
  7. The 8-lender backtest is my own account. The loader and analysis were committed September 27, 2026 on a branch that was never merged, and the backtest outputs were never committed. ↩
  8. Counts from the main branch at its last commit, September 2, 2026 (PR #2280). Co-author counts come from commit trailers; most Codex commits carry none, so Codex work is counted from the handoff ledger instead. ↩