The code was written. Nothing called it.
Threading headers parsed correctly by a helper the parser never invoked. Four tests written afterwards found it in seconds, which is the argument for the tests.
Threading an email reply is a small problem with a fiddly middle. A reply carries `In-Reply-To` pointing at a `Message-ID` you set on the way out, and `References` carrying the whole ancestry. Providers disagree about where they put those: a snake-case top-level field, a camel-case one, an object of headers, or an array of name and value pairs. Header names are case-insensitive and nobody agrees on casing. Long headers are folded across lines by every mail transfer agent in the path.
So the helper handles all of it, and the helper was correct.
function threadingHeader(data: Record<string, unknown>, name: string) {
const flat = text(data[name.replace(/-/g, "_")]) ?? text(data[camel(name)]);
if (flat) return flat;
const headers = data["headers"];
if (isObject(headers)) {
for (const [key, value] of Object.entries(headers)) {
if (key.toLowerCase() === name) return text(value);
}
return undefined;
}
if (Array.isArray(headers)) { /* ... name/value pairs ... */ }
return undefined;
}It was never called. The edit that was supposed to add it to the parser's return object silently did not apply, and the function sat in the file being exported to nobody.
The build was clean. An unused function is not an error, and the parser still returned a valid object with every field it had before. Nothing anywhere was red.
What that failure looks like in production
This is the part worth dwelling on, because it explains why the tests were worth writing. A reply arrives. The webhook accepts it, verifies the signature, parses it, stores it. Every step succeeds. The message simply appears as a new conversation instead of an answer to an existing one.
No error, no log line, no failed request. The only evidence is a thread list with two entries where there should be one, which requires somebody to already know what the right answer was.
× threading headers > reads a headers array, which is what Resend sends
× threading headers > reads a headers object
× threading headers > ignores the casing a provider chose
× threading headers > survives a References header folded across lines
Tests 4 failed | 51 passed (55)Four tests, written after the code and before believing the code. They failed immediately, which is the entire return on writing them.
The same shape, twice in a week
The second one was a repository. A migration added six columns to the emails table for threading and attachments. The types were updated, the sender passed the new values, the service built them correctly, the routes accepted them. The `INSERT` was never given them.
await executor.insert(emails).values({
id: record.id,
// ...
idempotencyKey: record.idempotencyKey,
metadata: record.metadata ?? null
// threadId, messageId, inReplyTo, bodyText, bodyHtml, attachments:
// all present in the type, none of them written.
});Drizzle does not require every column, so this is valid. The type accepted the extra fields on the way in and quietly dropped them on the way to SQL. Everything above it was correct and the feature was completely inert.
It took about four seconds to find, once something actually ran the path: compose a message, then read the row back by its `Message-ID` and get nothing.
Why typechecking cannot see this
Both defects have the same shape. A correct producer, a correct consumer, and no edge between them. A typechecker verifies each node; it has no opinion about whether a node is reachable, and a function nobody calls is as well-typed as one everybody does.
Coverage would have caught the first, which is a decent argument for coverage on parsers. Nothing catches the second except running it. The only reliable move is to exercise the whole path against real infrastructure and read what landed, rather than what the tests say landed.