ADR-011. A product is admitted, not merely added

Status: accepted, 7 September 2026. Still in force.

Context

Adding a product is the most expensive decision in this repository. It brings a contract nobody here wrote, dozens of operations to classify, and pages that are published on Galaxy for good.

Every measurement needed to judge that decision already existed, and none of them answered it. mise run report says a product is classified. mise run parser:coverage says what the parser cannot read. mise run docs:quality says whether the page can be understood. Asked “is it safe to add RDB?”, the only available answer was “the tests pass”.

That is not an answer. The tests also pass on a product whose parser ignores half the constructs, whose pages nobody has read, and half of whose operations come out UNKNOWN.

Decision

mise run admission chains the stages in the order in which they inform each other, and returns a verdict with an exit code: 0 admitted, 1 error, 2 refused. It runs in mise run check, over every product in the index: adding a refused product to products.txt turns the gate red.

Not every stage blocks, and that is deliberate. A gate that refused on every measurement would refuse both shipped products, so nobody would run it, and it would measure nothing. The blocking stages are the ones whose failure produces a wrong module:

stage

blocks

why

OpenAPI syntactic coverage

no

a construct being present is work to decide, not a defect

semantic constraints

yes

a constraint found and silenced gives a module that accepts what the API refuses (ADR-008)

clearable fields

no

a known, documented, sized limit (ADR-008, issue #114)

Day-2 classification

yes

an operation no rule settles is indistinguishable from a forgotten one (ADR-001)

write completeness

yes

a managing module that vanishes silently is indistinguishable from a forgotten one

comparison strategies

yes

a managed parameter with no strategy is compared strictly with nobody having decided it (ADR-009)

documentary coverage

yes

a page is published for good (ADR-005)

The non-blocking stages print a number. That number is the price of admission, and printing it is the point: a product enters with its price known, not with its price hidden.

Consequences

Excluded with a reason is not missing. The first version of the write completeness stage refused instance_server_user_data, which the generator does not write because the contract describes no body field for SetServerUserData: the module would not know what to send. The reason is carried and published. A gate that confuses the two punishes exactly the behaviour this repository asks for, and it found that out on a shipped product the first time it ran.

Both current products are admitted. Their price is the response codes the parser does not read, two for Instance and one for the Load Balancer, and forty clearable fields between them. The first version of this record said “two unhandled OpenAPI constructs each”: the parser coverage report filed oneOf: [T, null], which the parser translates, under the same “unhandled” line as a real union of shapes, and the gate charged the Load Balancer for it. Issue #120 separated the two counts, and the corrected price is the one above.

The gate reuses the other measurements rather than recomputing them. Reading their printed output would make a second reader of the same calculation, and the two would diverge at the first formatting change; parser_coverage was split into a function that measures and one that prints, for that reason.

The clearable-field count of this record was an undercount. The parser carried nullability only on a scalar written type: [T, "null"]: behind a $ref to a protobuf wrapper, and on type: [array | object, "null"], the fact was dropped. The contracts declare 55 clearable body fields written by a module, and the measurement said forty until the parser carried them all.

What this record does not decide

Whether a product is worth adding at all. That is a judgement about users, and no gate makes it.