Split out of #16159 by the round that closes it. That card's last row (VALIDATION_FAILED, PR pending) carried this question in its body — "whether they should converge is a question this card does not answer" — and closing the card would leave the question with no home. ⛔ Observation, not a runtime defect: nothing on main is wrong today. No assignee, no pm:queue; triage grades it.
The two spellings, measured on origin/main ac76425f0
One package, two exported constants, two different wire codes for what both call a validation refusal:
| producer |
constant |
wire code |
packages/objectql/src/secret-fields.ts:103 |
EMPTY_CREDENTIAL_REFUSAL_CODE |
VALIDATION_ERROR |
packages/objectql/src/validation/record-validator.ts |
VALIDATION_FAILED_CODE (the #16159 conversion) |
VALIDATION_FAILED |
Both are registered in ERROR_CODE_LEDGER. VALIDATION_FAILED is listed under @objectstack/objectql's own owner key; the ledger's prose distinguishes them repeatedly, and several of its comments say a given code is explicitly "Not a VALIDATION_ERROR synonym" — so the ledger already treats the two as carrying different meanings, in its own words, at least in the places where somebody wrote that sentence down.
Why this is a card rather than a shrug
The #16159 conversion made both spellings importable, which is the point at which the divergence stops being an implementation detail and becomes a published choice a consumer has to read. A consumer catching a refusal from this one package now has two constants to choose between and no published sentence saying which applies when.
⚠️ The conversion did not decide it, deliberately: the constant holds text byte-identical to the literal it replaced, so the decision is exactly as open as it was, and a pin test in that PR asserts the two are still two so that a future ruling has to argue for itself rather than arrive as a side effect of an unrelated edit.
What a ruling would cost, so triage can grade it
⛔ A convergence is a breaking rename of a registered wire code, in either direction, not a tidy-up:
- both codes are in
ERROR_CODE_LEDGER and are therefore in the population check:error-code-provenance reconciles;
VALIDATION_FAILED is re-authored as an inline literal at 148 non-test sites across 33 files in this repo — most of them independent producers minting their own house-code envelope rather than consumers of the engine class, but four of them are genuine recognizers (packages/types/src/validation-failure.ts, packages/rest/src/error-response.ts twice, packages/plugins/plugin-auth/src/objectql-adapter.ts);
scripts/check-changeset-no-major.mjs makes the **BREAKING** banner and the ADR-0087 disposition mandatory carriers for an accept-set change, so the ruling arrives with paperwork attached.
Three readings this card is asking for, ⛔ not a recommendation
- Leave them. They may genuinely name different refusals — an empty credential write is not a field-validation failure — in which case the fix is a published sentence saying so, not a rename.
- Converge on one, with the breaking-rename paperwork and a migration note.
- Rename neither but document the boundary in the ledger and in
content/docs/kernel/contracts/data-engine.mdx, which is the page that already teaches catching engine refusals by code.
Refs: #16159 · packages/spec/src/api/error-code-ledger.zod.ts · packages/objectql/src/secret-fields.ts · packages/objectql/src/validation/record-validator.ts
Generated by Claude Code
Split out of #16159 by the round that closes it. That card's last row (
VALIDATION_FAILED, PR pending) carried this question in its body — "whether they should converge is a question this card does not answer" — and closing the card would leave the question with no home. ⛔ Observation, not a runtime defect: nothing onmainis wrong today. No assignee, nopm:queue; triage grades it.The two spellings, measured on
origin/mainac76425f0One package, two exported constants, two different wire codes for what both call a validation refusal:
packages/objectql/src/secret-fields.ts:103EMPTY_CREDENTIAL_REFUSAL_CODEVALIDATION_ERRORpackages/objectql/src/validation/record-validator.tsVALIDATION_FAILED_CODE(the #16159 conversion)VALIDATION_FAILEDBoth are registered in
ERROR_CODE_LEDGER.VALIDATION_FAILEDis listed under@objectstack/objectql's own owner key; the ledger's prose distinguishes them repeatedly, and several of its comments say a given code is explicitly "Not a VALIDATION_ERROR synonym" — so the ledger already treats the two as carrying different meanings, in its own words, at least in the places where somebody wrote that sentence down.Why this is a card rather than a shrug
The #16159 conversion made both spellings importable, which is the point at which the divergence stops being an implementation detail and becomes a published choice a consumer has to read. A consumer catching a refusal from this one package now has two constants to choose between and no published sentence saying which applies when.
What a ruling would cost, so triage can grade it
⛔ A convergence is a breaking rename of a registered wire code, in either direction, not a tidy-up:
ERROR_CODE_LEDGERand are therefore in the populationcheck:error-code-provenancereconciles;VALIDATION_FAILEDis re-authored as an inline literal at 148 non-test sites across 33 files in this repo — most of them independent producers minting their own house-code envelope rather than consumers of the engine class, but four of them are genuine recognizers (packages/types/src/validation-failure.ts,packages/rest/src/error-response.tstwice,packages/plugins/plugin-auth/src/objectql-adapter.ts);scripts/check-changeset-no-major.mjsmakes the**BREAKING**banner and the ADR-0087 disposition mandatory carriers for an accept-set change, so the ruling arrives with paperwork attached.Three readings this card is asking for, ⛔ not a recommendation
content/docs/kernel/contracts/data-engine.mdx, which is the page that already teaches catching engine refusals bycode.Refs: #16159 ·
packages/spec/src/api/error-code-ledger.zod.ts·packages/objectql/src/secret-fields.ts·packages/objectql/src/validation/record-validator.tsGenerated by Claude Code