The most expensive fixes are the ones found in code
In the post about our process I described how our intake works: the product manager brings a brief with a problem, at the shaping session we look for a solution and cut the nonsense at the very start. Today — about what happens next, once the nonsense is cut and a solution seems to exist. About the first approximation of a feature. Before the code.
An observation from practice, not a revelation: the later you find a problem, the more it costs. Found in production — it costs nerves and hotfixes. Found in code — it costs a rewrite. Found on paper — it costs zero lines of code and one crossed-out paragraph. So for me the first approximation isn’t “sketching a work plan” — it’s a way to kill as many bad options as possible while they’re still free.
How many options died before the first commit
A live example — our duplicate detector in search. Here’s what didn’t survive to code.
The first version was “let’s make a separate audit tool; the agent calls it and gets a list of duplicates.” Beautiful on paper. Then we sat down and answered honestly: agents don’t call audit tools proactively; they work with what comes back in regular search. So the signal has to be embedded right into the search results, instead of building a separate door nobody will knock on. The option died in one evening.
Next came the temptation to widen the feature: since we’re finding duplicates, let’s also catch contradictions and gaps in the documentation. We ran the numbers — false positives would come by the wagonload, and nobody had confirmed demand for it. One signal that works well beats three that work “well, sometimes.” Crossed out.
Also on paper, we split the behavior by project: if you search within a project, documents from other projects don’t count as duplicates — the same name in different layers of the system is normal, not a mess. Search across the whole workspace — then they count. Had we discovered this in code, we’d have been redoing half the logic.
There was also a beautiful option with a document’s “semantic fingerprint”: run it through an LLM, get a summary, compare summaries. Cancelled at the planning stage — that’s essentially a hidden pre-”compilation” of knowledge, and our principle is that AI works with the base at the moment of the request. We chose a purely mathematical comparison, with no AI call at all. Along the way we discarded comparing “by the most similar chunk”: two independent documents with the same boilerplate intro would score high similarity, and the detector would cry wolf at the innocent.
And the cherry on top: before implementation we audited the existing code — and discovered the early version of the spec was built on wrong assumptions about how the system actually works. We revised the approach. Also on paper.
The connection graph went through the same story: at first we wanted the top level to show every document in the workspace as its own node; we estimated it — and realized it was unliftable (thousands of nodes, tens of thousands of tokens per response). The solution — make the top-level nodes projects, not documents: the top-level graph stays compact regardless of workspace size. We also dropped the idea of a separate graph database — the graph is computed on the fly over what already exists. All of it — before the code.
Where Meldoc fits in
Honestly: the thesis “paper is cheaper” isn’t a product feature, just experience. But the approach has a prerequisite without which it doesn’t work: the technical documentation has to exist. The first approximation needs something to check itself against — otherwise the “assumptions audit” turns into fortune-telling.
For us it looks like this: one call unfolds a document into its knowledge neighborhood — links in and out, hierarchy, semantic neighbors (Graphs in Meldoc covers the three layers in detail). You immediately see where the new feature will touch the system: which documents about the neighboring mechanisms exist, what will have to be taken into account. The concepts themselves I work through with Claude, with access to the base over MCP (MCP in Meldoc) — I sit there arguing with it about options, discarding, recording.
And an important side effect: the trail of decisions stays in the document. What was considered, what was discarded, why — it doesn’t drown in a chat; it lies next to the feature. Half a year later, when someone proposes “hey, let’s build an audit tool for duplicates,” you can simply show them the paragraph where that option already died.
Bad ideas will be born anyway — that’s normal. The only question is where they die: in a document over an evening, or in code over a sprint.