GTM Engineering
Your 400 Custom Fields Are Debt an LLM Will Expose
Every custom field was a workaround for a question the CRM could not answer. An LLM answers those questions from the raw record. The fields are now debt, and the debt is coming due.
· 12 min read
I pulled the field usage report on an Opportunity object with 412 custom fields. 71 of them had a non-null value on more than a quarter of records. The rest were populated on a handful of rows, or on none. Every one of those 341 dead fields was created on purpose, by someone solving a real problem, in a meeting where adding a field felt like the answer. The field was never the answer. It was a workaround for a question the CRM could not answer on its own, frozen into schema and left there forever.
Here is the shift that turns those fields from harmless clutter into debt that is coming due. The reason you built a “Deal_Complexity__c” picklist was that no query could tell you how complex a deal was, so you made a human classify it into a field. An LLM reads the raw opportunity, the emails, the notes, the line items, and answers “how complex is this deal” on demand, from the source, without a field, without a human, and without the drift. The moment inference is cheap, a derived field stops being infrastructure and becomes a stale cache of a question you can now ask live. Stale caches are debt. This one has 341 rows.
Watch the object collapse before you read the argument. Four hundred and twelve custom fields dissolve to the 71 facts that carry weight, then to the handful still worth storing, and finally to a single generative layer that answers every question the other 341 fields were pretending to answer. The pile that vanishes is not lost information. It is cached answers a model now computes live.
Two kinds of fields, and only one is debt
Not every field is debt, so start by splitting them. There are fields that hold facts a human or system observed and cannot be re-derived: the amount, the close date, the signed contract URL, the product on the line item. Those are the source of truth. Delete them and you have lost information forever. Keep every one.
Then there are derived fields: values someone computed or classified from other fields to answer a question. Deal complexity, health score, “is this strategic,” segment when segment is really just a bucket of employee count and revenue, “engagement level,” priority tier. Every one of these is a cached answer to a question, and the cache goes stale the moment the underlying facts change and nobody re-runs the classification. These are the debt. An LLM re-derives them live, from the facts, every time you ask.
The three costs of a derived field nobody prices
A derived field looks free after it is created. It is not. It carries three costs that compound, and none of them show up on a report until an LLM makes the cheaper alternative obvious.
The first is the fill cost. A required derived field is a tax on every rep, every record, forever. The required-fields tax is real: reps face 47 required fields and honestly fill 6, so the other 41 get garbage that makes the field worse than empty. The second is the drift cost. A field classified as “high complexity” in March is still “high complexity” in July even though the deal simplified, because nobody re-runs the classification. The field lies quietly. The third is the schema cost. Every field is a thing to secure, document, migrate, and reason about; 400 fields is a data model no human holds in their head, so nobody dares delete any of it, and it grows.
View as table
| Item | Value |
|---|---|
| Core facts (amt, date) | 98% |
| Used derived fields | 34% |
| Rarely-filled fields | 8% |
| Effectively dead | 2% |
The migration: from stored field to computed view
The move is to stop storing derived answers and start computing them. The derived field becomes a query or an inference that runs when someone asks, over the facts, so it is never stale and never a fill tax. Here is the shape, drawn.
Some derived fields collapse into plain SQL, because they were deterministic all along and someone just stored the answer to save a join. Segment is the classic one: it is almost always a function of employee count and revenue that got frozen into a picklist reps now edit by hand.
-- "Segment" was never a fact. It is a function of two facts.
-- Compute it in a view; stop storing and maintaining a field.
SELECT
id,
CASE
WHEN employees >= 1000 OR annual_revenue >= 100000000 THEN 'Enterprise'
WHEN employees >= 100 OR annual_revenue >= 10000000 THEN 'Mid-Market'
ELSE 'SMB'
END AS segment
FROM account;
The moment segment is a view, it cannot drift, cannot be fat-fingered, and costs a rep nothing. Every account that crosses 1,000 employees is Enterprise the instant the fact updates, with no field to re-classify. That is one field retired and one source of drift eliminated, from a five-line view.
The judgment fields, the ones that needed a human to read something, become an inference call instead of a stored value. Deal complexity was a picklist a rep set from a gut read; now it is a function of the facts.
{
"field_retired": "Deal_Complexity__c",
"computed_from": ["line_item_count", "product_mix", "legal_redlines", "stakeholder_count", "custom_terms_flag"],
"method": "llm_classify",
"output": { "complexity": "high", "confidence": 0.82,
"reason": "9 line items across 3 product families, 2 rounds of legal redlines, non-standard payment terms." },
"recompute": "on_demand"
}
The difference that matters: the reason field. A stored picklist tells you “high” and nothing about why or when. The computed version tells you why, from the current facts, every time you read it. It never lies, because it is never cached.
Not everything should be inferred
The counter-discipline matters, or you replace stale fields with expensive hallucinations. Deterministic derivations belong in SQL, not an LLM: segment, days-in-stage, coverage ratio, anything that is arithmetic on facts. Reach for inference only where the answer genuinely required reading unstructured content a human would have had to read. And a fact never becomes an inference: you do not “infer” the contract amount, you store it, because it is ground truth and getting it wrong is unforgivable.
The sort is not a matter of taste; each field has a right home and a real per-read cost. Deterministic derivations run for effectively zero in a view. Judgment fields cost a model call, and a call is cheap enough that the math almost never favors storing the answer. A Claygent research run in Clay costs about 1 to 6 credits depending on depth (Clay pricing, 2026), and a credit starts around 5 cents, so a classification lands in the low single-digit cents. Set that against the rep-minutes a required picklist burns on every record forever and the stored field loses on cost, not only on freshness.
| Derived field | What it really is | Right home | Per-read cost |
|---|---|---|---|
| Segment | Employee count crossed a threshold | SQL view (CASE) | ~0, deterministic |
| Days in stage | Arithmetic on two timestamps | SQL view | ~0, deterministic |
| Coverage ratio | Pipeline divided by quota | SQL view | ~0, deterministic |
| Deal complexity | A human read the deal and judged | LLM classify | cents per call (Clay, 2026) |
| Health / risk | A human read usage and signals | LLM classify | cents per call |
| ”Is this strategic” | A human read context and judged | LLM classify | cents per call |
The comparison that ends the argument
Stored derived field versus computed answer. Same question, two implementations.
| Stored derived field | Computed answer | |
|---|---|---|
| Freshness | Stale the moment facts change | Recomputed from facts on read |
| Fill cost | A rep enters it on every record | Zero: nobody fills it |
| Drift | Silent, unmeasured, permanent | Impossible, there is nothing to drift |
| Auditability | "High." No why, no when | Reason and confidence, every read |
| Schema weight | One more field to secure and migrate | One line in a view or one prompt |
| Cost | Rep minutes, hidden, recurring | Cents of compute, visible, on demand |
The migration math
A 412-field object does not shrink by deleting fields on a Friday. It shrinks by classifying, then computing, then deprecating in order. Here is the split I find and what happens to each pile.
| Pile | Count | Disposition |
|---|---|---|
| Core facts | 71 | Keep. Source of truth, cannot re-derive. |
| Deterministic derived | ~90 | Move to SQL views. Retire the field. |
| Judgment derived | ~60 | Move to on-demand inference. Retire the field. |
| Dead or near-dead | ~190 | Deprecate and delete after a usage-report grace period. |
That is roughly 340 fields headed for retirement against 71 that stay, which matches the population report at the top: only the facts were ever carrying weight. The rest was cached answers and abandoned experiments.
The platforms are already leaning this way, even if they will not say it in these words. Salesforce is pushing Agentforce as a consumption layer that reads records and answers questions on the fly rather than demanding a field for every attribute, and HubSpot shipped Breeze AI credits (HubSpot, 2025) to do inference over the CRM instead of storing more of it. Both moves point at the same conclusion the field audit reaches from the other side: the value moved from what you store to what you can compute over what you store. The vendors monetizing inference are betting the derived-field pile shrinks, and they are the ones who watched a billion of these fields get created.
Here’s how I’d build it: the field-debt paydown
Do not big-bang this. You will break a report someone depends on and lose the room. Pay the debt down field by field, cheapest and highest-drift first, with a proof at each step.
- 1
Pull the field population report
For every custom field, get percent populated and last-modified distribution. This is your debt ledger. Anything under 10% populated is a candidate for deletion, not migration.
- 2
Sort every field into fact, deterministic, or judgment
Facts stay. Deterministic derivations go to SQL. Judgment fields go to inference. This sort is the whole strategy; do it before you write any code.
- 3
Collapse the easy deterministic fields into views
Start with segment, tier, days-in-stage: anything that is arithmetic on facts. Ship the view, prove it matches the field on live data, then deprecate the field. One win the whole team can see.
- 4
Replace one judgment field with on-demand inference
Pick the highest-drift judgment field, deal complexity or health, and compute it from facts with a reason and confidence attached. Run it in shadow mode against the stored field first to earn trust.
- 5
Deprecate on a grace period, never delete cold
Rename the field, watch the usage report for anything still reading it, and delete only after a clean window. A field with zero reads for a quarter is safe to remove. This protects the report you did not know existed.
The shadow-mode discipline here is the same one I use for shadow-mode scoring: compute the new answer alongside the old field, compare, and only cut over when they agree or when the new one is demonstrably better. You do not earn the right to delete a field by arguing. You earn it by showing the computed answer was right and the stored one had drifted.
The 400 fields were never the problem. They were the best answer available when the CRM could not answer questions on its own. It can now, and the debt comes due the day someone points an LLM at your raw records and asks the questions your fields were pretending to answer. Get ahead of that day with one report this week: pull field population, sort the piles, and collapse your first deterministic field, segment is the easy one, into a five-line view. That single retired field is the proof you need to earn the next fifty.
Keep reading
One email. Every week.
One email a week: a system I built or broke, with the config, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.
The newsletter opens soon.
Connect a provider in src/config.ts