Finding from the axis-① .describe() sweep (describe claims vs measured acceptance face — the #6762 class). Recorded unassigned; suggest domain:spec-surface for routing.
Anchor
packages/spec/src/ui/view.zod.ts, GroupingConfigSchema:
export const GroupingConfigSchema = lazySchema(() => strictObject({
surface: 'this grouping configuration',
history: VIEW_HISTORY,
}, {
fields: z.array(GroupingFieldSchema).min(1).describe('Fields to group by (supports up to 3 levels)'),
}).describe('Record grouping configuration'));
Described claim
"Fields to group by (supports up to 3 levels)" — a fixed-count support envelope (house rule E17: any fixed count is a candidate by itself; counts drift).
Measured acceptance face
Probed on origin/main @ 2f3e79351 (tsx safeParse matrix, sources extracted via git archive; controls on both sides so a broken harness can't read as "no mismatch"):
control-reject 0 levels : rejected [too_small]
control-reject unknown key : rejected [unrecognized_keys]
1 grouping levels -> ACCEPTED
3 grouping levels -> ACCEPTED
4 grouping levels -> ACCEPTED
5 grouping levels -> ACCEPTED
10 grouping levels -> ACCEPTED
50 grouping levels -> ACCEPTED
The gate is .min(1) with no upper bound — the "3" exists only in the sentence.
Nothing downstream enforces it either, measured on the same checkout:
packages/lint/src has no grouping-level rule (the only grouping hits are validate-react-page-props.ts nested-key plumbing and org-axis prose).
- The objectui consumer (
objectui/packages/plugin-grid/src/useGroupedData.ts, buildLevel) recurses over all configured fields — if (depth >= fields.length) return [] is the only stop; no slice, no depth cap.
Why it matters for an authoring reader (ADR-0033)
The sentence is rendered verbatim in the published reference (content/docs/references/ui/view.mdx, the GroupingConfig.fields row). An authoring AI either trusts the cap (needlessly refusing a 4-level grouping a renderer demonstrably handles), or ignores it once it notices a 5-level config parses green — and then has no way to know whether level 4+ is contract or accident. Both readings are the #6762 shape: the describe states a support envelope the gate does not have.
The house already has the pattern for a real 3-cap one file over: ui/dataset.zod.ts include claims "max 3 hops" and enforces it — .refine((p) => p.split('.').length <= 3, { message: 'include path exceeds the 3-hop limit (ADR-0071)' }). GroupingConfigSchema has the claim without the refine.
Suggested shape, if triage wants it fixed
Decide which side is true and make the other match:
- if 3 is the intended contract, add
.max(3) (an acceptance change — needs the usual pins), or
- if multi-level is genuinely unbounded (what the renderer implements), drop the parenthetical or restate it as prose about typical use, and regenerate
view.mdx.
Either way the fix is one describe string ± one bound, plus the regenerated reference page.
Refs
#6762 (class specimen: describe narrower than the measured gate), ADR-0071 (the enforced 3-hop precedent), ADR-0033 (AI-first authoring readers).
Finding from the axis-①
.describe()sweep (describe claims vs measured acceptance face — the #6762 class). Recorded unassigned; suggestdomain:spec-surfacefor routing.Anchor
packages/spec/src/ui/view.zod.ts,GroupingConfigSchema:Described claim
"Fields to group by (supports up to 3 levels)" — a fixed-count support envelope (house rule E17: any fixed count is a candidate by itself; counts drift).
Measured acceptance face
Probed on
origin/main@2f3e79351(tsxsafeParsematrix, sources extracted viagit archive; controls on both sides so a broken harness can't read as "no mismatch"):The gate is
.min(1)with no upper bound — the "3" exists only in the sentence.Nothing downstream enforces it either, measured on the same checkout:
packages/lint/srchas no grouping-level rule (the onlygroupinghits arevalidate-react-page-props.tsnested-key plumbing and org-axis prose).objectui/packages/plugin-grid/src/useGroupedData.ts,buildLevel) recurses over all configured fields —if (depth >= fields.length) return []is the only stop; noslice, no depth cap.Why it matters for an authoring reader (ADR-0033)
The sentence is rendered verbatim in the published reference (
content/docs/references/ui/view.mdx, theGroupingConfig.fieldsrow). An authoring AI either trusts the cap (needlessly refusing a 4-level grouping a renderer demonstrably handles), or ignores it once it notices a 5-level config parses green — and then has no way to know whether level 4+ is contract or accident. Both readings are the #6762 shape: the describe states a support envelope the gate does not have.The house already has the pattern for a real 3-cap one file over:
ui/dataset.zod.tsincludeclaims "max 3 hops" and enforces it —.refine((p) => p.split('.').length <= 3, { message: 'include path exceeds the 3-hop limit (ADR-0071)' }).GroupingConfigSchemahas the claim without the refine.Suggested shape, if triage wants it fixed
Decide which side is true and make the other match:
.max(3)(an acceptance change — needs the usual pins), orview.mdx.Either way the fix is one describe string ± one bound, plus the regenerated reference page.
Refs
#6762 (class specimen: describe narrower than the measured gate), ADR-0071 (the enforced 3-hop precedent), ADR-0033 (AI-first authoring readers).