AWRA OpsHub Search

Two Relations, and One Is Always Empty

A request for quotation here has two different routes to the quotes that came back. One of them is the live one. The other belongs to an earlier design that was replaced, was never removed, and returns an empty list for every request that has ever existed.

Procurement Insights AWRA OpsHub Team 10 min read

Software accumulates. A first design gets built, gets used, gets found wanting, and gets replaced by a better one. The better one ships. The first one, very often, stays exactly where it was — because deleting it is a decision and leaving it is not.

We found one of ours on 26 August 2026, in procurement, and it is worth writing up not because anything is broken but because of the specific way this kind of leftover eventually costs somebody a day.

Two answers to one question

Ask a [request for quotation](/glossary/request-for-quotation) what quotes came back against it, and there are two ways to ask. Both look equally official from the inside. One returns the quotes. The other returns nothing, always, for every request in every workspace, and has done since the day it was written.

The empty one is the remains of a simpler idea: a vendor's response as a single line — who quoted, how much in total, how long delivery would take, what discounts and extra costs applied. Reasonable, compact, and inadequate the moment anybody wanted to compare quotes line by line, apply tax properly, hold a currency, or keep a snapshot of the terms as they stood.

So it was replaced by a full quote document — numbered, dated, itemised, taxed, with its own currency and status. That is what the product uses, and it is what the vendor portal writes when a supplier responds.

The replacement was built. The original was left. Both are still reachable, and only one of them has ever contained anything.

Why nothing is wrong today

Worth being precise, because this is not a defect you can trip over. No screen in the product asks the empty question. Every list of quotes against a request, every comparison, every conversion of a quote into a purchase order goes through the live route.

A buyer using the system sees their quotes, compares them, and raises an order. Nothing is missing, nothing is slow, and no figure is wrong. The leftover is invisible from every direction a user can look from.

Why it is still worth removing

Because the next person to touch this area will find two plausible routes and no signal about which one is real. That person may be a developer adding a feature, an integrator building against the interface, or a report author asking for quotes per request.

And here is the specific cruelty of an abandoned structure over an abandoned function: an empty result is a valid result. A route that no longer exists announces itself immediately — the code fails and somebody fixes it in a minute. A route that exists and returns nothing looks exactly like a request with no quotes yet.

A removed route is used by mistake

It fails at once

The error names the thing. The cost is a minute and it is paid by the person who made the mistake, immediately, at the keyboard.

An empty route is used by mistake

It succeeds and returns nothing

The result looks like a request nobody quoted. The cost is paid later, by somebody investigating why the report shows no quotes, and it is paid in hours.

The second is the more expensive outcome and it is what a leftover data structure produces every time.

2
routes from a request to its quotes
1
that anything writes to
0
screens affected by the other one

The general pattern, and how to spot it

Superseded structure is one of the commonest forms of debt in any system past its second year, and it is nearly always invisible in the product. It shows up in three places, all of which are outside the screens.

  • In an integration. Somebody building against your system picks the route whose name matches what they want. If two names match, they have a coin flip, and the wrong side of it produces silence rather than an error.
  • In a report. A definition written against the wrong structure produces a report that runs, returns nothing, and gets described as "the data must not be there yet".
  • In a migration. Moving to a new system, somebody exports the quotes. If they export from the abandoned structure they get an empty file and no warning that it was the wrong one.

That third one is where this class of leftover has done real damage in the industry, because it is discovered after the old system has been switched off.

What we are doing about ours

The empty route and the structure behind it are scheduled for removal rather than documentation, because a note explaining which of two routes is real is a worse fix than having one route. Until then it is recorded in our internal register and stated here, which is the same thing we would want from anybody whose data we were building against.

Three questions worth asking before you integrate with anything

Are there any structures in here that are no longer written to?

What you will hear

Usually a pause, then an honest yes.

How to read it

Every system past a couple of years has some. A vendor who can name theirs has looked; one who says none has almost certainly not. The answer you want is a list, not a denial.

If I ask for something and get an empty result, how do I tell "none yet" from "wrong place"?

What you will hear

A description of the data model.

How to read it

The most useful question on this list for anybody writing an integration. An empty result is ambiguous by nature and the only cure is knowing which routes are live before you start.

What did this area look like two versions ago?

What you will hear

A story.

How to read it

Listen for a replacement that shipped without a removal. That is where the leftovers are, and the person telling you the story usually knows exactly where the bodies are buried without having thought of them as a risk.

The short version

Replacing a design is the easy half. Removing what it replaced is the half that gets deferred, because nothing breaks when you skip it — and an abandoned structure is worse than an abandoned function precisely because nothing breaks. It answers, politely, with nothing, and an empty answer is indistinguishable from a true one. If you are integrating with any system, ask what in it is no longer written to before you ask anything else.

Quotes against a request, precisely

What AWRA OpsHub does today

  • Vendor quotes as full documents — numbered, dated, itemised, taxed, with their own currency and a status — stored against the request they answer.
  • A supplier portal where a vendor responds to a request directly, so the quote arrives as a record rather than as an email somebody keys in.
  • Conversion of an approved quote into a purchase order, carrying the lines across rather than rekeying them.
  • A snapshot of the financial and country terms as they stood when the quote was made, so a later change to a tax rate cannot rewrite a historic document.

More we can add to your workspace

  • Removal of the superseded quote structure and the route to it, so a request has exactly one answer to what came back against it.
  • A marker on the interface showing which routes are current, so an integrator can tell a live structure from a retired one without asking.
  • A warning when a report definition is written against a structure nothing writes to, which would turn a silent empty result into a question.

Where we point you to a specialist

  • We would rather remove a superseded structure than document it. A note explaining which of two routes is the real one leaves both in place and adds a thing to read; the fix is to have one route.
  • We will keep publishing structural debt of this kind even where it changes nothing a customer can see. Anybody building against our data deserves to know which parts of it are live, and finding out during a migration is the worst possible time.
  • Deciding whether a quote is the best one is a buyer's judgement about price, delivery, terms and history. We hold the documents and the comparison; we would decline to rank suppliers on your behalf.

Removal of the superseded structure and a currency marker on the interface are scoped work we can quote on.

What we would build

Two, and the first one is subtraction

Most engineering is addition. This is the other kind, and it is the kind that gets deferred indefinitely unless somebody writes it down.

Remove the superseded route

One structure, one relation, one answer to "what came back against this request". The work is small and the value is entirely in what stops being possible to get wrong.

Mark which routes are current

A published list of what is live and what is retired, so an integrator or a report author chooses correctly on the first attempt rather than after an empty result.

How it works: you describe the requirement, we return a written scope, timeline and cost, and once agreed it is built into your environment and maintained as part of the product. If you are planning an integration against procurement data, ask us for the current-routes list before you start — that one costs nothing.

Talk to us about procurement data

Ask what is no longer written to

Of any system you are about to build against, integrate with, or migrate away from. It is a question vendors are rarely asked and can usually answer, and the answer is worth more than most of the documentation.

Talk to us about procurement

Help Center

Need a quick answer while you read?

Run inventory, procurement, assets, sales, and field work with approved AWRA guidance for setup, migration, integrations, security, pricing, and support.

Search all approved AWRA public help articles.

Open Help Center