A gate that could only subtract
- Symptom
No symptom. This one was caught while checking the design against the corpus before writing the filter, which is the only reason it is a paragraph here rather than a quarter of the library going quietly unreachable.
- Diagnosis
The design was the obvious one: exclude vendor documentation from the unrestricted retrieval pass, and admit it through the restricted pass when the question names a product.
Two facts, checked separately, killed it.
First, the tag the restricted pass filters on was present on no document and no chunk in the library. Not sparse, absent. So the exclusion would have removed a large block of chunks from the corpus and the admission path would have matched nothing, ever. Backfilling the tags fixes the arithmetic and not the design.
Second, and worse: I read the actual questions. Buyers write requirements to be vendor-neutral, so the product names live in the answer, not the question. Across a real returnable of several hundred rows the number of rows naming a product the company resells was zero, and the closest near-hit named the buyer’s own internal tooling, which would have opened the gate to the wrong vendor’s documentation entirely.
And none of it would have surfaced. The unrestricted pass always runs, so a restricted pass that matches nothing produces no error and no empty result, just a marginally worse answer, with no signal that a lane was closed.
- Decision
Move the admission signal from the question to the bid. Whether a bid proposes a given product is a fact about the bid, known before a single row is answered, and it is one human input that covers every row rather than several hundred failed inferences.
The field for it already existed on the bid, with a doc comment making exactly this argument, and nothing wrote to it. So the change had to include the control that populates it. Otherwise the filter keys off an empty field and the same silent failure recurs one level up, which is precisely how the tag ended up on nothing in the first place. Anything read as a gate needs a visible, intentional writer.
The question-text signal stayed, unioned with the bid’s stack rather than replacing it. On the rare row that does name a product it is correct, and as a bonus rather than the mechanism it is harmless.
The reusable part is not the fix, it’s the check. “Which existing records satisfy this predicate, and which real inputs trigger this branch” is two queries and a read of the input data, and it is the cheapest possible time to find out that a filter has no domain. Both answers here were zero.