Problem
The same defect has now occurred four times in Schema::ANNOTATION_VOCABULARY:
| Key |
Consequence while absent |
x-openregister-processing |
per-schema AVG read-logging could never be enabled |
x-openregister-contextchat |
the ContextChat per-schema opt-in could never take effect |
x-openregister-shareable |
schemas never surfaced as a shareable type |
x-openregister-agent-context |
every Hermiq agent leaf fleet-wide resolved an EMPTY context (#2164) |
Each was fixed by adding one string, and each fix left a comment in the list explaining the trap. The comments have not stopped it recurring, because nothing mechanically connects "a key is READ somewhere" to "the key is in the vocabulary".
The failure mode is uniformly invisible: setConfiguration() drops the unknown key, the schema saves with HTTP 200, no validation error reaches the caller, and the only signal is a log line. The capability is then 100% inert while looking healthy — the orphaned-capability pattern gate-52 exists to catch.
Proposed fix
A test that derives the expected vocabulary from usage rather than restating it:
- Grep the codebase (and ideally consuming apps' known keys) for
x-openregister-[a-z-]+ literals read via getConfiguration() / annotation constants.
- Assert every such key is present in
ANNOTATION_VOCABULARY.
- Assert the converse too — a key in the vocabulary that no engine reads is a phantom (exactly what
x-openregister-seed was, and it is already asserted absent for that reason).
Cross-app keys make step 1 imperfect from inside OpenRegister alone, so an explicit registry of externally-read keys (with the owning app named) may be the pragmatic form.
Alternative worth considering
Make an unknown x-openregister-* key a 400 to the caller rather than a warn-and-drop. A silently discarded annotation is indistinguishable from a stored one at the API boundary, which is what makes every instance of this bug survive review.
Raised while fixing #2164 (PR #2167).
Problem
The same defect has now occurred four times in
Schema::ANNOTATION_VOCABULARY:x-openregister-processingx-openregister-contextchatx-openregister-shareablex-openregister-agent-contextEach was fixed by adding one string, and each fix left a comment in the list explaining the trap. The comments have not stopped it recurring, because nothing mechanically connects "a key is READ somewhere" to "the key is in the vocabulary".
The failure mode is uniformly invisible:
setConfiguration()drops the unknown key, the schema saves with HTTP 200, no validation error reaches the caller, and the only signal is a log line. The capability is then 100% inert while looking healthy — the orphaned-capability pattern gate-52 exists to catch.Proposed fix
A test that derives the expected vocabulary from usage rather than restating it:
x-openregister-[a-z-]+literals read viagetConfiguration()/ annotation constants.ANNOTATION_VOCABULARY.x-openregister-seedwas, and it is already asserted absent for that reason).Cross-app keys make step 1 imperfect from inside OpenRegister alone, so an explicit registry of externally-read keys (with the owning app named) may be the pragmatic form.
Alternative worth considering
Make an unknown
x-openregister-*key a 400 to the caller rather than a warn-and-drop. A silently discarded annotation is indistinguishable from a stored one at the API boundary, which is what makes every instance of this bug survive review.Raised while fixing #2164 (PR #2167).