Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .changeset/value-domain-note-settings-door-repointed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
"@objectstack/spec": patch
---

docs(spec): the `field.valueDomain` liveness note stops claiming the settings door is "unchanged until then"

The `valueDomain` row of the published `liveness/field.json` ledger ended on a sentence written
while the re-point was still in the future:

> The settings door (`service-settings/value-domains.ts`) re-points onto the shared predicate in
> its own follow-up card and is unchanged until then.

Both halves of the 2026-09-02 ruling have since landed — the settings half (#15434) and the engine
half (#15316) — and the engine half rewrote this note wholesale while carrying that sentence
forward verbatim. "Unchanged until then" therefore described a state that no longer existed: the
door it names had already re-pointed, one commit earlier.

The sentence now says what is true of that door, read off its source rather than off a PR title:
its second copy of all three definitions is deleted, `firstRejectedDomainMember` asks
`isValueDomainMember` — the same call `record-validator.ts` makes — and what remains on that side
is the door's own business (which declarations it agrees to enforce, how a multi-value carrier is
walked, the fragments the env-override log line needs). A re-added local table reddens
`value-domains.shared-predicate.pin.test.ts`.

Ledger-note text only. The row's `status` is untouched — it tracks the engine write path, and
`liveness/state-counts.md` is derived by `gen:liveness-counts` from the row states, none of which
move here (`check:liveness` reports the counts file current).
2 changes: 1 addition & 1 deletion packages/spec/liveness/field.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
"status": "live",
"verifiedAt": "2026-09-04",
"evidence": "packages/objectql/src/validation/record-validator.ts#validateOne (the write-path seam, beside `maxLength`'s: `if (def.valueDomain !== undefined && VALUE_DOMAIN_FIELD_TYPES.has(t) && !isValueDomainMember(def.valueDomain, s)) return fail('value_domain', { valueDomain: def.valueDomain }, ...)` \u2014 a non-member WRITTEN to a `text` field declaring a domain is refused with the ADR-0114 code `value_domain` and `constraint.valueDomain`); packages/spec/src/data/field.zod.ts#VALUE_DOMAIN_FIELD_TYPES (the parse-time applicability door: the key is accepted on `text` only and refused with a located `custom` issue at [valueDomain] on every other type — the same superRefine mechanism `maxLength` / `minLength` use); packages/spec/src/shared/value-domain.zod.ts#isValueDomainMember (the ONE membership predicate the write path will call — shared with the settings door)",
"note": "The write path enforces it since 2026-09-04 (#15161, the engine half of the maintainer ruling 2026-09-02 option A on #14168; the spec half declared the slot, the closed vocabulary, the shared predicate, the ADR-0114 catalog member and its four-locale templates). WRITTEN VALUE ONLY, the `min`/`max`/`maxLength` transition-gate class: a stored value outside a domain declared later is never re-read and survives unrelated edits, and an absent/empty value is the field's `required` handling, not this check \u2014 both pinned in packages/objectql/src/validation/record-validator.value-domain.test.ts, together with the per-domain matrix (iso_3166_alpha2 admits CH and refuses ZZ; iana_time_zone admits UTC and refuses Mars/Olympus; iso_4217_currency admits CHF and refuses chf). The applicability door is one constant read by both seams \u2014 the schema refuses the key outside VALUE_DOMAIN_FIELD_TYPES at parse and the validator judges exactly that set, so the two cannot drift into two opinions (the #11875 discipline; the subset relation to BOUNDED_STRING_FIELD_TYPES, which the enforcement branch rides on, is pinned in the same file). The settings door (`service-settings/value-domains.ts`) re-points onto the shared predicate in its own follow-up card and is unchanged until then."
"note": "The write path enforces it since 2026-09-04 (#15161, the engine half of the maintainer ruling 2026-09-02 option A on #14168; the spec half declared the slot, the closed vocabulary, the shared predicate, the ADR-0114 catalog member and its four-locale templates). WRITTEN VALUE ONLY, the `min`/`max`/`maxLength` transition-gate class: a stored value outside a domain declared later is never re-read and survives unrelated edits, and an absent/empty value is the field's `required` handling, not this check \u2014 both pinned in packages/objectql/src/validation/record-validator.value-domain.test.ts, together with the per-domain matrix (iso_3166_alpha2 admits CH and refuses ZZ; iana_time_zone admits UTC and refuses Mars/Olympus; iso_4217_currency admits CHF and refuses chf). The applicability door is one constant read by both seams \u2014 the schema refuses the key outside VALUE_DOMAIN_FIELD_TYPES at parse and the validator judges exactly that set, so the two cannot drift into two opinions (the #11875 discipline; the subset relation to BOUNDED_STRING_FIELD_TYPES, which the enforcement branch rides on, is pinned in the same file). The settings door (`service-settings/value-domains.ts`) has re-pointed onto that same predicate (#15434, the services half of the same ruling): its second copy of all three definitions is deleted and `firstRejectedDomainMember` asks `isValueDomainMember`, so a value Settings admits is the value a field admits and vice versa; what is left on that side is the door's own business (which declarations it agrees to enforce, how a multi-value carrier is walked, the fragments the env-override log line needs), and a re-added local table reddens packages/services/service-settings/src/value-domains.shared-predicate.pin.test.ts."
},
"rows": {
"status": "live",
Expand Down
Loading