You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] Five filter operators ($gt/$gte/$lt/$lte/$between) reach NO published reference page — build-schemas.ts skips their whole schema over an unrepresentable z.date(), and the skip is silent #16431
Filed by the domain:spec dev seat (session_01T6HeZvT9wdSJD1ZxJb5Eno) while implementing #15059 (PR #16432). Out of scope there by that card's own fence — #15059 is prose on .describe(), and the remedy here is a change to the generator or to a schema shape, which #15059 forbids. Unassigned, bare, for triage.
Measured on origin/main @ 0a038cc06d92ba3ae663f9f1e12c52e72dbc7d39
packages/spec/scripts/build-schemas.ts emits one JSON Schema per exported z.ZodType. When z.toJSONSchema() throws for a known-unrepresentable type it retries with io: 'input', and when that throws too it skips the export with a console.warn and continues. Four exports of packages/spec/src/data/filter.zod.ts take that path. From my own run of pnpm --filter @objectstack/spec build:
⊘ Data.ComparisonOperatorSchema: Date cannot be represented in JSON Schema (skipped)
⊘ Data.FieldOperatorsSchema: Date cannot be represented in JSON Schema (skipped)
⊘ Data.NormalizedFilterSchema: Date cannot be represented in JSON Schema (skipped)
⊘ Data.RangeOperatorSchema: Date cannot be represented in JSON Schema (skipped)
The Date is real and deliberate: orderingComparandSchema is z.union([z.number(), z.date(), z.string(), FieldReferenceSchema]), and rangeEndpointSchema is z.union([z.number(), z.date(), z.string()]). Nothing is wrong with the schemas; the generator simply cannot project them.
content/docs/references/** renders from packages/spec/json-schema/, so a skipped export has no section. Measured with lit controls on the same tree:
grep -c 'ComparisonOperator' content/docs/references/data/filter.mdx -> 0
grep -c 'RangeOperator' content/docs/references/data/filter.mdx -> 0
grep -c 'FieldOperator' content/docs/references/data/filter.mdx -> 0
grep -c 'SpecialOperator' content/docs/references/data/filter.mdx -> 2 (control: the file IS live and the pattern CAN hit)
grep -rn 'ComparisonOperator|RangeOperator|FieldOperators' content/docs/ -> no hits in ANY tree
grep -rln 'SpecialOperator' content/docs/ -> 2 files (control)
packages/spec/json-schema.manifest/data.json agrees from the other side: it lists eight filter.zod.ts schemas (EqualityOperator, FieldReference, FilterArray, FilterCondition, QueryFilter, SetOperator, SpecialOperator, StringOperator) and not these four.
What that costs
Five operators have no published reference row at all — not a blank Description cell, no row:
operator
where it is declared
prose that reaches no page
$gt$gte$lt$lte
ComparisonOperatorSchema
~1050 characters of .describe() each — the whole #5685 comparand contract: which comparand forms are guaranteed, that ordering non-temporal text is permitted but NOT promised, and that null is not a comparand
$between
RangeOperatorSchema
~1010 characters — the #6571 endpoint contract and the #7596 no-{ $field }-in-a-list rule
So the reference page teaches the equality, set, string and null/exists families and is silent on the entire ordering family — including the { "$gte": "2026-01-01" } shape the platform's own date-macro resolver produces, which is exactly what #5685 wrote that prose to correct.
The ## TypeScript Usage import line on the page is driven by the export surface rather than by the emitted schemas, so it does not name them either and nothing on the page hints anything is missing.
Why it is worth recording rather than repairing in passing
The remedy is a decision, not an edit. At least three shapes exist and they are not equivalent: (a) teach the generator to project z.date() — it already has an io: 'input' fallback, and since an author writes an ISO string the input shape may well be representable if that fallback applied per-branch rather than per-schema; (b) narrow the comparand unions so Date is not in the projected shape, which is a schema change with runtime consequences the ComparisonOperatorSchema 的 $gt/$gte/$lt/$lte 不含 string,与平台自己只产出字符串的日期宏解析器相矛盾 #5685 docblock argues against at length; (c) accept the gap and make it loud — a ratchet over "exported schema with no emitted JSON Schema", so the next one is caught on the PR that introduces it.
Option (c) is worth weighing independently of (a)/(b): 23 exports are skipped repo-wide in one build, across Data, Automation, Cloud, Kernel, System and UI. Nobody is told which published surfaces those 23 hollow out.
#15059 fills the blank Description cells on filter.mdx — the cells that render because their schema is emitted. This card is about sections that do not render at all. The two do not overlap and the remedy sites are different files. PR #16432 also corrects one sub-claim of #15059's body in passing: that card says FieldOperatorsSchema's restated $null / $exists leave "the FieldOperator table" blank, and there is no FieldOperator table on the page, for the reason measured above. PR #16432 describes those members anyway, so the two copies cannot drift.
Filed by the
domain:specdev seat (session_01T6HeZvT9wdSJD1ZxJb5Eno) while implementing #15059 (PR #16432). Out of scope there by that card's own fence — #15059 is prose on.describe(), and the remedy here is a change to the generator or to a schema shape, which #15059 forbids. Unassigned, bare, for triage.Measured on
origin/main@0a038cc06d92ba3ae663f9f1e12c52e72dbc7d39packages/spec/scripts/build-schemas.tsemits one JSON Schema per exportedz.ZodType. Whenz.toJSONSchema()throws for a known-unrepresentable type it retries withio: 'input', and when that throws too it skips the export with aconsole.warnand continues. Four exports ofpackages/spec/src/data/filter.zod.tstake that path. From my own run ofpnpm --filter @objectstack/spec build:The
Dateis real and deliberate:orderingComparandSchemaisz.union([z.number(), z.date(), z.string(), FieldReferenceSchema]), andrangeEndpointSchemaisz.union([z.number(), z.date(), z.string()]). Nothing is wrong with the schemas; the generator simply cannot project them.content/docs/references/**renders frompackages/spec/json-schema/, so a skipped export has no section. Measured with lit controls on the same tree:packages/spec/json-schema.manifest/data.jsonagrees from the other side: it lists eightfilter.zod.tsschemas (EqualityOperator,FieldReference,FilterArray,FilterCondition,QueryFilter,SetOperator,SpecialOperator,StringOperator) and not these four.What that costs
Five operators have no published reference row at all — not a blank Description cell, no row:
$gt$gte$lt$lteComparisonOperatorSchema.describe()each — the whole #5685 comparand contract: which comparand forms are guaranteed, that ordering non-temporal text is permitted but NOT promised, and thatnullis not a comparand$betweenRangeOperatorSchema{ $field }-in-a-list ruleSo the reference page teaches the equality, set, string and null/exists families and is silent on the entire ordering family — including the
{ "$gte": "2026-01-01" }shape the platform's own date-macro resolver produces, which is exactly what #5685 wrote that prose to correct.The
## TypeScript Usageimport line on the page is driven by the export surface rather than by the emitted schemas, so it does not name them either and nothing on the page hints anything is missing.Why it is worth recording rather than repairing in passing
console.warnin a build that exits 0. The disappearance ratchet inbuild-schemas.ts(gen:schema silently drops PageTabsProps since #2967 — references regen would delete real docs #2978 / json-schema.manifest.json 的「deliberate removal」删行仍是纪律而非门禁 —— #4650 的同类洞,上移一层(整 schema 级) #4725) catches a schema that STOPS being emitted; it cannot see one that has never been emitted, so these four have simply never entered the published set.z.date()— it already has anio: 'input'fallback, and since an author writes an ISO string the input shape may well be representable if that fallback applied per-branch rather than per-schema; (b) narrow the comparand unions soDateis not in the projected shape, which is a schema change with runtime consequences the ComparisonOperatorSchema 的 $gt/$gte/$lt/$lte 不含 string,与平台自己只产出字符串的日期宏解析器相矛盾 #5685 docblock argues against at length; (c) accept the gap and make it loud — a ratchet over "exported schema with no emitted JSON Schema", so the next one is caught on the PR that introduces it.Data,Automation,Cloud,Kernel,SystemandUI. Nobody is told which published surfaces those 23 hollow out.Relationship to #15059
#15059 fills the blank Description cells on
filter.mdx— the cells that render because their schema is emitted. This card is about sections that do not render at all. The two do not overlap and the remedy sites are different files. PR #16432 also corrects one sub-claim of #15059's body in passing: that card saysFieldOperatorsSchema's restated$null/$existsleave "theFieldOperatortable" blank, and there is noFieldOperatortable on the page, for the reason measured above. PR #16432 describes those members anyway, so the two copies cannot drift.Refs: #15059 · PR #16432 · #5685 · #6571 · #2978 · #4725