
An MVP includes whatever is required to answer one question, and nothing else. That sounds like a slogan until you write it down as a list, at which point it becomes the only artefact that matters: the cut list, the features deliberately not in version one, agreed before the first sprint rather than during the last one.
There is one exception to cutting, and it is the part most first versions get wrong. Cut features freely. Never cut the shape of the data. A feature left out can be added later at roughly the cost of building it. A field that every screen depends on, added later, costs far more than building it would have, because it has to be fitted around code that already exists.
We know the difference because we have got it wrong on shipped products. Across Al Amri Express, Tvam and DoraDori, there are three things we would decide earlier if we started again. None of the three was a missing feature. All three were the shape of the data, all three were cheap to decide in week one, and all three were expensive by month six.
This post is about what goes in version one and what does not. It deliberately carries no cost table and no timeline — what an MVP costs covers both, including how long a build takes and what moves the price.
Before any build, three questions. They take an afternoon in week one and they are expensive to answer in month six.
What is the one thing you are testing? Not what the product does. What your business is actually betting on, phrased so that a result can contradict it. "Will people order groceries online" is not it. "Will households in Muscat accept a substituted item rather than cancelling the order" is.
What result would make you stop? A question with no stopping condition is not a test, it is a plan to build the thing regardless. Writing the stopping condition down before launch is the only way it survives contact with sunk cost.
Is this codebase meant to survive? This one gets skipped most often and changes the most. An MVP meant to be thrown away and an MVP meant to become the product are different builds, and pretending the question is premature just means it gets answered by accident, in the architecture, by whoever is writing the code that week.
Those three answers shape every technical choice after them. That is why they come before the cut list rather than after it.
The cut list is a written document naming the features that are not in version one. It exists so the argument happens once, rather than every sprint.
It is agreed before the first sprint. A scope decided during the last sprint is not a cut list, it is a panic, and it cuts whatever is least finished rather than whatever matters least. The difference shows up months later, because panic-cutting removes the half-built thing, which is often the structural one.
The practical test for each item: does this change the answer to the question you are testing? An admin screen a human can do by hand for the first hundred orders does not. A second language does not, unless the question is about that market. Reporting beyond one CSV export does not. Anything with no answer attached to it does not, and that category is usually larger than anyone expects when they write it down.
What survives the test is small. That is the point, and it is why the list of what you are not building is the more useful document.
The cut list is not the only thing discovery produces, and it is not the first. The integration inventory comes before it: every system version one has to talk to, at the version you actually run rather than the version in the current documentation. That distinction is not pedantry. A vendor API that differs at your version from its published docs is the most common source of a mid-build surprise, and it is the reason we do not quote a fixed price before discovery. You cannot cut scope sensibly until you know which of the things on the list are yours to build and which are somebody else's to expose.
Here is the distinction that decides whether a cut is cheap or expensive.
A feature is a thing the system does. Leave it out and the cost of adding it later is roughly the cost of building it, plus a little integration. That is a real cost and a fair trade, and it is what a cut list is for.
The shape of the data is what the system can represent. Which level a number lives at. Whether a captured value carries how certain it is. Whether a flow exists for something the customer did not choose. Leave one of those out and adding it later is not building a feature, it is changing what every existing screen means — plus a backfill, plus a reconciliation proving the new history matches the old.
The trap is that both look identical on a requirements list. "Substitution handling" and "export to CSV" are both just rows. One is a feature. The other is the shape of an order.
Currency makes the point in one line. The Omani rial carries three decimal places, so money has to be stored in integer minor units with an exponent of three. Anything defaulting to two truncates silently — no error, no alert, just totals that drift and a reconciliation nobody can close. Deciding that in week one costs a conversation. Discovering it after launch means re-reading every stored amount with no record of which were already wrong.
Al Amri Express delivers groceries across Oman with its own operation rather than a marketplace of third-party riders, which made the customer app and the warehouse app one system: a promise made at checkout is kept or broken by whoever picks the order.
The customer app shipped first and the operations app followed, so each entered production against something stable. That sequencing was right. The thing we would change is substitution.
We designed the substitution flow after checkout rather than before it. Substitution is the only part of a grocery order the customer did not choose. It moves ratings more than delivery speed does. And deciding it late forces the question to be answered around code that already exists, rather than in the order model where it belongs.
Cash at the door compounds it: a shopper rejects one substituted item, not the whole order, so the door needs per-item accept and reject that reprices collection on the spot. That is not a screen you bolt on. It is a property of what an order is.
The same build got a harder structural call right, which is worth the contrast. Oman's addressing standard has no location-based postcode — the codes in circulation belong to post office boxes, and street names are only unique within a wilayat. So the pin drop is the primary key and the text is commentary, zones are polygons rather than code lookups, and the landmark a customer types is a field the rider reads verbatim. Had that been deferred as "addresses, v2", every order, zone and route in the system would have been built on an identifier that does not exist.
Tvam turns a birth date, time and place into an interactive Vedic chart. The calculation layer has to be exact: the ascendant travels the whole zodiac in a day, averaging a degree every four minutes, so minutes of clock error reorder houses.
We treated birth time as given. Plenty of users do not know theirs to the minute, and the app has no way to say so. A chart drawn from an approximate time looks exactly as confident as one drawn from a hospital record.
Starting again, we would carry an uncertainty flag on the birth event from capture, and let the interface show which parts of a chart hold steady across a plus-or-minus window and which do not. Retrofitting that touches every screen that reads a house — which is to say, all of them.
Note what this is not. It is not a missing feature. Nobody asked for an uncertainty indicator. It is a missing property of a captured value, and that is a different class of omission.
DoraDori is a garment ERP where the item hierarchy has three levels: a style, a colourway, and a variant of style, colour and size. Only the variant physically exists, so it is the only countable level.
The published item summary reports what is on hand. It does not say whether that stock is sellable, and in apparel sellable means a complete size run rather than a total. Stock can read healthy while the order cannot be filled, because the units left are sizes nobody ordered.
We would put size-run completeness into that read at the start. Because we did not, every consuming system works it out again, slightly differently, which is how two reports come to disagree while both are technically correct.
Three different domains, three different teams, one shape of mistake.

In each case the deferred decision was structural rather than functional, invisible on a feature list, cheap in week one, and expensive once code existed around it. In each case the cost of retrofitting scaled with how many things read the data, not with how big the change looked.
That is the rule the cut list needs. For every item you are about to cut, ask whether adding it later is building something new or changing what existing things mean. If it is the second, it is not a candidate for the cut list, however small it looks.
It sounds premature. It is the opposite: it is the question that decides how much of the above matters.
If the codebase is meant to be thrown away, you can be relaxed about the shape of the data, because nothing will be retrofitted into it. You are buying an answer, not an asset. Prototype quality is correct, and the structural rules in this post mostly do not apply.
If the codebase is meant to become the product, every shortcut in the data model is a debt with a multiplier attached, and the three examples above are what that debt looks like when it comes due. Most founders say throwaway and mean survive, which is the worst of both: prototype decisions carried into a product nobody planned to keep.
Answer it explicitly, in writing, in week one. It is the cheapest decision in the whole project and it silently prices several of the others.
There is a reliable tell for which answer you actually mean. Ask what happens to version one if the test comes back negative. If the honest reply is that you would adjust and carry on with the same codebase, it was never disposable, whatever the kickoff deck said — and the structural rules in this post apply in full. If the reply is that you would genuinely stop or start again, you have a prototype, and you should take the shortcuts deliberately and write down which ones you took, so that whoever revives the code later knows what they are inheriting.
Four properties, in the order they matter.
It is written down. An agreed-in-conversation cut list is not one. It reappears as a surprise in sprint four, usually from whoever was not in the room. The document does not need to be elaborate: one line per item, its reason, and a marker for whether it is structural. What it needs is to be the thing people point at, so that re-opening an item is visibly a change of decision rather than a clarification.
It names what is out, not what is in. A list of what is in reads like a promise and grows. A list of what is out reads like a decision and holds, because adding to it requires an argument.
Each item carries its reason. "Not in v1" is an instruction. "Not in v1 because it does not change whether households accept substitutions" is a decision somebody can disagree with on the record, which is the point.
Structural items are marked and excluded. Every item gets the test from earlier: adding this later, am I building something new or changing what existing things mean? The second category comes off the cut list and goes into version one, however minor it looks.
Not to be small. Small is a consequence, not a goal, and a version one that is small but answers nothing has achieved only a lower invoice.
Release 1 exists to produce a result that could have gone the other way. A launch that confirms what everyone already believed has cost you a build and taught you nothing you could not have got from a conversation. If every outcome you can imagine leads you to carry on building, you have not run a test, you have shipped an instalment. The stopping condition written in week one is what makes the difference, and it is the single item most likely to be quietly dropped between the kickoff and the launch.
The products in this post all passed that bar, and all three still carry a decision we would make differently. That is the honest shape of a first release: not a smaller product, but a narrower question, built on a data model wide enough to survive the answer.
Whatever answers one question, and nothing else. The useful artefact is the cut list: a written document naming the features deliberately not in version one, agreed before the first sprint rather than during the last one. The test for each item is whether it changes the answer to the question you are testing. Admin screens a human can do by hand, reporting beyond one export, and a second language usually fail that test. The exception is structural: anything that changes what the system can represent belongs in version one even when it looks small.
The shape of the data. A feature left out costs roughly what it would have cost to build, plus integration. A property of the data model left out costs far more, because adding it later changes what every existing screen means and usually needs a backfill and a reconciliation. Examples from our own builds: a flow for something the customer did not choose, how certain a captured value is, and which level of a hierarchy a number lives at. All three looked like features on a requirements list and were not.
Answer three questions first: what is the one thing you are testing, what result would make you stop, and is this codebase meant to survive. Then take each proposed feature and ask whether it changes the answer to the first question. If it does not, it is a candidate. Then apply the structural test: adding this later, would you be building something new or changing what existing things mean? If it is the second, take it off the cut list regardless of size.
Because it decides whether shortcuts in the data model are free or expensive. If the code is genuinely disposable, you are buying an answer rather than an asset, and prototype decisions are correct. If it will become the product, every structural shortcut carries a multiplier that comes due around month six. Most founders say throwaway and mean survive, which produces the worst outcome: prototype decisions carried into a product nobody planned to keep. Answer it in writing in week one.
A prototype answers a question without needing to survive contact with real users or real data. An MVP answers a question by being used. The practical consequence is the data model: a prototype can represent things loosely because nothing will be retrofitted into it, while an MVP that becomes the product cannot. If a prototype settles your question, build the prototype — it is cheaper and faster, and nothing in this post about structural decisions applies to it.
It becomes the backlog, but not automatically. The point of release 1 is a result that could have gone either way, so the first job after launch is to read the result against the stopping condition written in week one. Items on the cut list get re-tested against what you now know rather than promoted on schedule. In our experience the more valuable output is the opposite list: the structural decisions you deferred and now have to retrofit, which is what the three examples in this post are.
That is a separate question with its own answer, and it has its own post: see [what an MVP costs](https://zyneto.com/blog/mvp-development-cost) for the worked estimate, what moves the price, how long a build takes and the costs that fall outside it in year one. This post deliberately carries no cost table, because scoping decisions made to hit a number rather than to answer a question are how a cut list stops being a cut list.

Vikas has around fifteen years of experience building software and now builds generative AI systems at Zyneto. His work covers retrieval augmented generation, agentic AI, knowledge graphs, AI memory, and the evaluation and guardrails that decide whether any of it is safe to put in front of customers. He has shipped enterprise copilots, document AI, chatbots and predictive analytics for e-commerce, fintech and marketing teams, and works day to day in Python, JavaScript and SQL. He follows multimodal models, business process automation and enterprise AI security closely, and mentors engineers moving into AI. He writes about architecture, inference cost and the failure modes that only show up at production scale.
Share your details and we will talk soon.
Be the first to access expert strategies, actionable tips, and the trends actually shaping the digital world. No fluff - just practical insights delivered straight to your inbox.
Dive into our blog and stay ahead of the curve with expert perspectives, future-ready trends, and tech tips written for decision-makers and doers alike.