Skip to content

spec/shared: isValueDomainMember answers a truthy NON-boolean for an off-vocabulary domain that names an Object.prototype member #15315

Description

@claude

Observation-class finding, measured while re-pointing packages/core's time-zone probe onto this predicate (#15134). ⛔ Not reachable from that card's call site and not fixed there: packages/spec is another lane's surface, and core passes a TS-checked literal.

What was measured

packages/spec/src/shared/value-domain.zod.ts:175

export function isValueDomainMember(domain: ValueDomain, value: string): boolean {
  return DOMAIN_MEMBERSHIP[domain](value);
}

DOMAIN_MEMBERSHIP is an object literal, so it inherits Object.prototype. Measured against the BUILT artifact (packages/spec/dist/shared/index.mjs) on Node v22.22.2:

domain argument result typeof
iana_time_zone (in vocabulary) true for UTC boolean
toString [object Object] string — TRUTHY
constructor the DOMAIN_MEMBERSHIP object object — TRUTHY
__proto__ throws TypeError
nope throws TypeError

So an off-vocabulary domain does one of two different wrong things, and one of them is a membership FALSE POSITIVE from a function whose whole job is to refuse non-members.

Why it is worth recording rather than shrugging at

In-repo this is unreachable: the parameter is typed ValueDomain, every call site names a member, and the core call site added in #15134 passes a string literal. The exposure is that isValueDomainMember is published on @objectstack/spec/shared (it is in packages/spec/api-surface/shared.json), so a plain-JS consumer — or any caller handing it a domain string read from metadata rather than written in source — reaches it with no type checking at all. A validation predicate that returns a truthy string for an unknown domain fails OPEN.

The existing pin does not cover this: packages/spec/src/shared/value-domain.test.ts:169 asserts typeof isValueDomainMember(domain, ...) is boolean, but iterates ValueDomainSchema.options only — i.e. exactly the domains that behave.

Suggested shape

A null-prototype record (Object.assign(Object.create(null), {...})) or an explicit Object.prototype.hasOwnProperty.call(DOMAIN_MEMBERSHIP, domain) guard returning false, plus a pin over a few off-vocabulary domain strings including toString and constructor. ⛔ Not a hard call about behaviour, but it IS a choice between false and a thrown refusal for an unknown domain, so it wants an owner rather than a drive-by.

Not a defect reachable from any current in-repo call site. Filed unassigned and unlabelled for triage.

Generated by Claude Code


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions