Skip to content

ObjectGanttSchema still does not declare the gantt block face — declaring it enforces the spec's required trio and changes the CLI's refusal behaviour (severed from #6051) #6475

Description

@claude

Severed from objectui#6051 / PR #6472 by PM ruling (2026-08-26) so the decision is
recorded on its own card rather than bundled into a 27-key declaration PR. Filed
unassigned; triage grades it. The measurement below is complete — nothing needs
re-deriving to act on this.

What is proposed

Declare the gantt BLOCK face on ObjectGanttSchema, on both declaration faces:

// packages/types/src/objectql.ts
gantt?: GanttConfig;

// packages/types/src/zod/objectql.zod.ts
gantt: SpecGanttConfigSchema.extend(GanttConfigExtensionFields).optional(),

GanttConfigExtensionFields already exists in the mirror (PR #6472 added it as
the single field map the flat face is built from), so this is a two-line change
plus the pin entries.

Why it is a real undeclared read

getGanttConfig (packages/plugin-gantt/src/ObjectGantt.tsx) reads it:

// 2. Check schema.gantt (the block face, ObjectGridSchema style)
if (schema.gantt) { config = schema.gantt as GanttConfigEx; }

An AST enumeration of every top-level key read off the schema prop in
packages/plugin-gantt/src/** (non-test) on 854222c5e found 47 keys, of
which 28 were undeclared. PR #6472 declared 27. gantt is the 28th, and it is
the only one left undeclared — so the published type still does not teach the
block spelling, and an author writing { type: 'object-gantt', gantt: { … } } in
TypeScript gets no completion, no checking, and no error on a misspelt member.

Why it was severed rather than shipped — the accept-set change

This is the ONE key of the 28 whose VALUES get stricter, and the reason is not the
key itself:

  • gantt had no mirror entry at all, so a block rode through .passthrough()
    entirely unvalidated;
  • declaring it as GanttConfig means it is parsed, and GanttConfig derives from
    the spec's GanttConfigSchema, which requires startDateField,
    endDateField and titleField;
  • ObjectGanttSchema is a member of AnyComponentSchema, so this reaches
    safeValidateSchema and therefore the CLI's validate and check commands
    (packages/cli/src/commands/{validate,check}.ts).

Net effect: a gantt block missing one of those three moves from "accepted, then
warned about at runtime" to "refused at authoring/validate time."

The case FOR enforcing it (recorded so the next reader does not re-derive it)

  1. It is not a new contract. getGanttConfig's block branch already feeds
    the block to GanttConfigSchema.safeParse and logs
    [ObjectGantt] Invalid gantt configuration on failure. The flat branch returns
    before reaching that check. Declaring gantt as GanttConfig makes the
    declared face equal the face the renderer was already checking — declared = enforced restoration, not a widening of the rules.
  2. The spec already says so. GanttConfigSchema (rc.6, 19 keys) declares
    startDateField, endDateField and titleField required. Nothing here
    invents requiredness.
  3. Zero measured casualties in this repo. A scan of all 5095 tracked files
    for authored gantt: { … } blocks found no metadata block missing the
    trio. The apparent hits are i18n translation namespaces that happen to be named
    gantt (packages/i18n/src/locales/*.ts), prose, and as any test fixtures
    that never reach the zod mirror. The README's block example
    (packages/plugin-gantt/README.md:250) is a commented, elided one-liner, not a
    compilable example.
  4. It closes the last hole in the "one vocabulary, two faces" property PR
    feat(types,plugin-gantt): declare the flattened GanttConfig face ObjectGantt reads (#6051) #6472 established. That PR's derived pin
    (Exclude<DeclaredKeys<GanttConfig>, DeclaredKeys<ObjectGanttSchema>> must be
    never) proves every block-face key is declared at the top level; it does not
    and cannot prove the block key itself is declared.

The case AGAINST shipping it inside #6051 (the PM's ruling, recorded verbatim in substance)

  1. It changes a published CLI's refusal behaviour. Warning at runtime becoming
    refusal at build time is a real behaviour change for authors, whatever the spec
    says.
  2. The zero-casualty scan is in-repo only. 5095 tracked files measures this
    tree
    . Authored metadata living outside it is exactly the population an in-repo
    census cannot see — a blind spot that has produced false negatives on this seat
    before. Not a reason to doubt the number; a reason not to let it carry a
    published-surface decision by itself.
  3. Bundled, it would have been invisible. Nobody reading "declare the
    flattened GanttConfig face" would know they were also approving a CLI refusal
    change.

What a decision needs to cover

  • Ship as-is (block declared, spec requiredness enforced), or
  • ship with the requiredness relaxed on the objectui face — which forks the
    vocabulary from the spec and is not recommended, or
  • ship behind a deprecation period: declare gantt, keep the CLI's refusal
    behind a flag or a warning for one release, then enforce.

Whoever rules should also settle the out-of-tree question directly: is there
authored gantt block metadata outside this repository (examples, customer apps,
objectstack fixtures) that omits titleField?

Related: objectui#6051 / PR #6472 (declared the other 27), objectui#6469 (the flat
vs block PRECEDENCE question, separate), objectui#5903 / PR #6053 (the cast-read
sibling).

Generated by Claude Code


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions