Spec debt starts before tech debt: catch missing rules
Spec debt grows when teams skip rules for auth, billing, and odd cases. Learn how to track decisions before code turns guesses into behavior.

Why missing rules become product behavior
Spec debt is the pile of product rules nobody wrote down while the work still felt obvious. A team agrees on a feature in broad terms, but the small decisions stay fuzzy. Then development starts, and engineers still need exact answers.
Code can't ship with blanks. If the spec doesn't say what happens after a failed login, an expired trial, or a payment retry, someone has to decide. That choice becomes the product. Users don't see a missing note in a doc. They see a locked account, a dead end, or a charge.
That's why missing rules turn into product behavior so fast. The app has to decide who gets access, when access ends, what counts as abuse, and what happens when billing fails. Even a reasonable engineering guess can drift away from what the business intended.
A bug and an unanswered product decision are different problems. A bug breaks a known rule. An unanswered decision leaves no rule to follow. The software can behave exactly as coded and still produce the wrong outcome.
Support and QA usually find these gaps first because they work where vague ideas meet real cases. QA asks, "What should happen if a user signs up, never verifies their email, and tries again with the same address?" Support gets the message that says, "I paid late. Why did you lock my account right away?" Those aren't random edge cases. They expose rules nobody wrote down.
Teams often call the cleanup tech debt once the rework begins. The problem started earlier. It started when auth rules, billing rules, or exception handling lived in someone's head, a chat thread, or nowhere at all.
A short note written before development can prevent hours of rework later. It also protects something that's harder to win back: trust.
Where gaps show up first
Spec debt usually appears first in flows that change access, money, or account state. These are the moments when the product has to make a decision. If the spec says nothing, the app still does something, and that guess becomes product behavior.
Signup is a common weak spot. Teams often define the happy path and skip the simple questions around it. Can one person create two accounts with the same email through Google login and password login? What happens if someone starts signup, leaves, and comes back two days later? Password reset has the same problem. If a reset link expires, does the user get a clear next step or a dead end?
Login rules get messy when roles change. A founder invites a teammate and later makes that person an admin. Who can remove the original owner? What happens if the owner leaves the company? If two admins try to change roles at the same time, which action wins? These cases sound rare until they happen on a real account.
Billing gaps appear even faster because money creates sharp edges. Trials need plain rules. Does the trial end at midnight in the user's time zone or in yours? If a customer upgrades during the trial, do they lose unused days? After a failed renewal, do they lose access at once, keep working during a grace period, or move into a limited mode?
The quiet gaps often sit in empty and broken states. A user opens a dashboard with no data. What should they see, and what can they do next? Someone deletes a record that another screen still expects. Does the app show an error, hide the missing item, or recover cleanly? Duplicate actions create the same trouble. A double click on "Pay" or "Invite" can create two charges or two invites if the rules don't say how to prevent it.
A simple test helps: if a screen can be empty, expired, deleted, retried, or paid late, write the behavior down before anyone builds it.
How to track rules before engineers start
Start with actions, not screens. Most product confusion hides in moments where something changes: a user logs in, a card gets charged, a role changes, or a record gets deleted. If an action changes access, money, or data, write it down.
For each action, write one plain sentence that says what should happen. It should be specific enough that two engineers would build the same thing. "If a trial user cancels before the trial ends, keep access until the trial end date" is clear. "Cancel the trial gracefully" leaves room for guesswork.
A short rule log usually works better than a long spec. Keep it in one place, whether that's a doc, spreadsheet, or ticket template. For each rule, record the trigger, the expected result, what happens if the action fails or returns partial data, who owns the open question, and whether the team resolved it before planning.
Failure cases deserve more attention than teams expect. When billing fails, do you retry, warn the user, or pause access? When a login code arrives late, can the user request another one right away, or do you slow the flow for a minute? Small gaps like these become product behavior by accident.
Open questions also need owners, not comments. If nobody owns "What happens after three failed payments?" that question stays fuzzy until a sprint is already underway and someone makes a fast call. That's usually the most expensive time to decide.
Review unresolved rules before sprint planning. If the list is short, the team can move. If it is full of open questions around auth or billing, stop and close them first. One hour of review can save days of rebuilds, support tickets, and awkward customer messages.
Auth rules to settle early
Auth rules look small on paper, but users hit them every day. If you leave them vague, the app still makes a choice.
Start with unverified users. Many teams say "sign up first" and leave it there. Decide whether someone with an unverified email can read public data, create a draft, start a trial, join a workspace, or invite another person. Loose rules here often create strange half states where a user can set up part of an account but can't finish the one task that matters.
Session expiry needs the same level of detail. If a session ends while someone is filling out a long form, uploading a file, or paying for a plan, what happens next? The product should warn them, save their work when possible, and tell them what to do next. Surprise logouts feel careless.
Lockouts and recovery need exact rules too. After how many failed login attempts do you slow someone down or lock the account? How long does the lock last? Can they still reset their password during that time? If support steps in, what proof do they need before they restore access?
Role changes are another source of confusion. In many products, "admin" means different things to different people. Write down who can invite a teammate, who can remove one, who can suspend or restore an account, and whether a removed user can return with their history intact.
Access by support or admins deserves extra care. If someone can enter another user's account, say when that's allowed, what they can change, and what the system records. A visible audit trail is usually the safer choice because it turns special access into a rule instead of a quiet exception.
Billing rules that save rework
Billing is where spec debt gets expensive fast. If the product team leaves payment rules undefined, the app still has to do something. That default behavior often becomes the real policy, and support has to explain it later.
Pick one clear moment when a trial starts. It might begin at signup, after email confirmation, on first login, or when someone creates a workspace. The end needs the same detail: exact date, exact time, and time zone. If you skip that, two users can sign up on the same day and still see different trial lengths.
Failed charges need a plain rule as well. Decide whether users keep full access, move into read only mode, or lose access after a grace period. Write down how many retry attempts you make and how far apart they are. A failed annual renewal should never surprise a customer with a locked account unless the team agreed to that rule on purpose.
Upgrades and downgrades also create avoidable mess. When someone upgrades in the middle of a billing cycle, do you charge the difference right away or add it to the next invoice? When they downgrade, does the lower price start now or at renewal? Proration sounds like a finance detail, but it changes what users think they bought.
Seat changes need the same care. If a company drops from 20 seats to 10 while 14 people still have access, the product needs a written rule. You can block the change, or you can allow 14 active users until the next cycle. Either approach can work if the team chooses it early and explains it clearly.
Permissions around billing matter more than many teams expect. Decide which roles can update a card, change the billing email, view invoices, or cancel a plan. In a small company, the person paying the bill is often not the person using the product every day.
Refunds and grace periods should be simple enough that support can apply them without guessing. Write down when support can issue a refund, whether it can be partial, and how many days count as a grace window. One short policy note can prevent long email threads and a pile of manual fixes.
Edge cases that break trust
Small edge cases often do more damage than obvious bugs. Users can forgive a slow page once. They don't forgive feeling locked out, billed twice, or treated differently on two devices.
This is where spec debt gets personal. If the product team leaves the rules open, the code still picks a behavior. It just might pick the wrong one.
Take identity first. If one person signs up with Google and later uses the same email with a password, the product needs a rule. Does it merge those identities, block the second signup, or ask the user to confirm? If you don't decide, users end up thinking the app lost their account.
Multi workspace products have their own trouble. If one user belongs to two workspaces, what follows them and what stays separate? Session state, notifications, billing access, and saved settings can bleed into each other if the boundaries aren't clear.
Drafts and failed actions deserve written behavior too. If someone saves half a form and their network drops, what does the app keep? A draft, a warning, and a clear recovery path feel fair. Silent data loss doesn't.
Time rules also matter more than teams expect. A renewal at 11:30 PM in New York and one at 12:30 AM in London can hit the same backend moment but feel like different calendar days to users. Pick one rule and stick to it. Use the account billing time zone or UTC, but don't mix browser time with server time.
Teams rarely lose trust because of one huge outage. They lose it in small moments where the product feels unfair, random, or forgetful.
A simple example: trial, login, and failed payment
Mia starts a 14 day trial in a mobile app on Monday. Two days later, she opens the product on her work laptop and signs in with Google. Before she verifies her email, a coworker invites her into the company workspace. On day 14, the first renewal charge fails. Support then gives her a short extension.
If the rules are clear, this flow is routine. If they aren't, spec debt shows up before anyone writes code.
The first gap is identity. Does the trial belong to Mia as a person, to the device where she started it, or to the workspace she joined later? If nobody wrote that down, desktop login can create a second account, merge into the wrong one, or hide the original trial.
The next gap sits in auth. Can an invited user enter a shared workspace before email verification, or must they verify first? Each answer changes access. One version lets Mia see team data right away. Another blocks her completely. A third lets her in but blocks certain actions.
Then billing takes over. When the renewal charge fails, what happens that same day? Some products cut access at once. Some keep read only access for a few days. Some allow full use during a retry window. If the product manager, finance lead, and engineer all assume different answers, the user feels that mismatch fast.
Support adds one more branch. A three day extension sounds simple, but it isn't. Does support extend product access, move the billing date, pause collection emails, or all three? If only access changes, Mia may keep working while the system still tries to charge her on the old schedule.
One flow touches identity, permissions, payment state, and support actions. Missing rules don't stay missing for long. They turn into whatever the first person in the chain guessed was right.
Mistakes teams make when they decide too late
Most teams don't create bad product rules on purpose. They write the happy path, ship fast, and leave the hard parts for later. Then the code still needs an answer, so someone picks one.
Signup is a common example. The spec says a user creates an account, starts a trial, adds a card, and upgrades. It says nothing about duplicate emails, expired trials, shared cards, failed renewals, or what happens when someone uses Google login after signing up with a password. Those missing rules don't stay blank.
Vague words make this worse. Terms like "usually," "if needed," or "for some users" feel harmless in a draft. Under deadline pressure, they push the real decision onto engineers, support, or whoever touches the issue last. Two people read the same line and build two different policies.
Spread makes things worse too. One rule sits in the spec, another lives in chat, a billing exception hides in a ticket, and a support workaround stays in the inbox. After a few weeks, nobody knows which version is current. Engineers follow the ticket they saw. Support repeats what worked last time. Product assumes everyone shares the same understanding.
Release pressure makes the problem more obvious. When launch gets close, engineers stop asking open questions and make the safest guess they can. The guess may be reasonable, but it still becomes product policy without product approval. Later the team calls it tech debt, even though the real issue started before code.
Support can also create a shadow spec. A customer complains, support grants a refund or extends a trial, and the exception solves the moment. If nobody writes that rule down, the next customer gets a different answer. Trust falls fast when auth or billing depends on who replied.
A simple habit prevents a lot of this: when someone makes an exception, update the written rule that same day. If the team can't state the rule in one clear sentence, they haven't decided it yet.
A short check before handoff
A handoff isn't ready when the team still answers basic rule questions with "it depends." That's how spec debt slips into code. Once the app ships, guesses stop looking like guesses and start looking like policy.
A quick review usually catches the problem. Ask the product manager, designer, engineer, and QA the same question: "What happens next?" Use one normal path and one blocked path. If their answers differ, the rule is still loose.
A solid handoff usually passes four checks:
- The team can explain each action and the next state in one clear sentence.
- Every blocked action shows a message the user can understand and act on.
- Every money flow has an owner, a time, and a fallback.
- QA can write a test from the rule alone, without asking what the team meant.
Money flows need extra care because small gaps create expensive messes. Decide who owns each step, when access changes, and what happens if the payment provider is late or fails. Then cover the less exciting cases too: retries, duplicate charges, reversals, refunds, grace periods, and expiry.
Blocked actions deserve the same detail. "Access denied" isn't enough. Say why the action failed, whether the user can fix it, and what the product does next. A clear message cuts support tickets. A vague one turns a simple rule into a complaint.
QA is usually the best final filter. If QA has to ask, "Did you mean block login or block only premium features?" the rule still lives in people's heads instead of on the page. Fix that before handoff.
Next steps for a lean rule tracking habit
Most teams don't need a huge spec file. They need a short rule list that answers the questions engineers would otherwise answer in code.
Start with auth and billing before you map every screen. Those two areas create expensive mistakes fast. If login fails, a session expires, a card is declined, or a refund is partial, the product still needs a clear rule.
Keep the habit small enough that people actually use it. One shared document is enough if the team reviews it every week, turns repeated support fixes into written policy, and removes stale notes before the list gets bloated. A good test is simple: can someone scan it in five minutes and see what is still undefined?
Support tickets are one of the best inputs. When the team answers the same customer question three times, the product usually already has a rule. Nobody wrote it down. Write it once, then use it in product decisions, QA checks, and future support replies.
You don't need to solve every edge case on day one. Start with the rules that affect access, money, trust, and support load. That's where guesses do the most damage.
If your team keeps finding the same gaps late, an outside review can save time. Oleg Sotnikov at oleg.is does this kind of work with startups and smaller companies, reviewing product rules, auth flows, billing paths, and the operating decisions that often get left vague before development starts.
Done well, this habit is boring in the best way: fewer surprises, fewer support patches, and fewer product decisions hidden inside code.
Frequently Asked Questions
What is spec debt?
Spec debt means your team started building before it wrote down enough product rules. The code still needs answers, so engineers make reasonable choices and those choices turn into real product behavior.
How is spec debt different from tech debt?
Tech debt usually comes from code and architecture choices. Spec debt starts earlier, when the team never decided what the product should do in messy cases like failed payments, expired sessions, or duplicate signups.
Where does spec debt show up first?
It usually shows up in flows that change access, money, or account state. Signup, login, trials, renewals, role changes, refunds, and deleted records tend to expose gaps first.
Which rules should we write down first?
Start with anything that can lock someone out, charge money, change permissions, or lose data. If a screen can end up empty, expired, retried, deleted, or paid late, write that behavior before development starts.
What is the simplest way to track missing rules?
Keep one short rule log in a place the whole team uses. For each action, write the trigger, the expected result, what happens on failure, and who owns any open question.
Which auth decisions matter most before handoff?
Settle email verification, session expiry, lockouts, password recovery, role changes, and support access early. Users hit auth every day, so vague rules there create confusion fast.
What billing rules save the most rework?
Choose the exact trial start and end, the time zone, what happens after a failed charge, and how upgrades, downgrades, seats, and refunds work. Support should be able to explain every billing outcome in one plain sentence.
Why do small edge cases hurt trust so much?
Users lose trust when the product feels unfair or random. Double charges, surprise lockouts, missing drafts, and account merge mistakes feel personal because people expect the app to remember what they did.
How can I tell if a spec is ready for engineering?
Ask product, design, engineering, and QA the same question: what happens next? If they give different answers for a normal path or a blocked path, the handoff still has gaps.
What should we do if the team keeps missing the same rule gaps?
Turn repeated support exceptions into written rules on the same day. If your team keeps finding the same gaps late, an outside review from someone like Oleg Sotnikov can help you tighten auth flows, billing rules, and handoff decisions before code locks them in.