A mapper that copies a named subset of fields drops every field added later, silently
A context object was built by explicitly mapping a chosen list of fields from the stored record; a field added afterwards was never added to that list, so every consumer read it as the empty default and treated the absence as a legitimate value rather than a missing mapping.
Resurfaces when
- a field is always empty regardless of the data
- adding a field to a stored record or model
- building an application object from a database document
- the same value is correct in one place and empty in another
- an endpoint returns a plausible-looking default
- a newly added field shows up empty in the app even though the record holds a value
- a mapper that copies a fixed list of fields from the stored record
The lesson’s retrieval contract, weighted three times heavier than its body. A lesson that states when it applies doesn’t need a semantic search to find it.
The lesson
Explicit field mapping is the right default — it stops storage internals leaking into application objects — but it converts 'new field' into 'silently absent field' unless someone remembers the mapper. The absence is undetectable downstream because it arrives as a plausible empty value: an empty array, a zero, a null that the consumer's own fallback quietly absorbs. Where the same information is also read directly from storage elsewhere, the two paths disagree and only the mapped one is wrong, which makes the bug look conditional on where you observe it.
The failure that taught it
An endpoint consistently returned an empty list for a field, regardless of the record's actual contents. The context builder mapped a fixed set of fields from the stored document and this one was not among them, so the endpoint's fallback returned empty every time. Server-side logic that consulted the same information was unaffected, because it re-read it from storage directly rather than from the mapped object — so the same data was correct in one place and empty in another.
How to apply it
When adding a field to a stored record, grep for the mappers that build application objects from it and add it there in the same change; a field that exists in storage and never surfaces is nearly always an unmapped one. When a value is always empty, check the mapper before the query. Where two code paths read the same information by different routes, note it — a disagreement between them localises the bug immediately.
Where this claim comes from
- Lessonhigh confidence
A mapper that copies a named subset of fields drops every field added later, silently
- Distillationmechanism stated
Written from the mechanism, not the incident — which is what lets it transfer to code sharing nothing with the original.
- Scar2 occurrences
2 separate failures, recorded independently at the time. A clustering pass found they shared one cause.
- Evidence2 records
Referenced by content hash, never by path: entry slugs carry client and ticket names, so a lesson storing them could not be published at all. Resolving a hash needs a map that never leaves the machine. An agent running locally traces it with scar_evidence; nothing on this site can.
What happened when it was used
- 8
- retrieved
- 0
- acted on
- 0
- held up
- 0
- did not hold up
Retrieved but never acted on — a demotion, not a neutral result. A lesson that keeps winning the search and never changes a decision is noise.