From 14b3c15cd5e33fae7cfa7175dbe61eac6e62f3d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 15:26:29 +0000 Subject: [PATCH 1/2] docs(plugin-gantt): state both reasons GanttConfigRestated keeps a member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docblock said the restated members are kept for ONE reason — their JSDoc being the only prose in this repo for what the renderer does with each key. Measured on main, that is false twice over: four of the twelve carry no JSDoc here at all (parentField, baselineEndField, assigneeField, effortField), and since #6472 the flattened face ObjectGanttSchema in @object-ui/types documents all twelve, so the prose is not unique either. The reason that actually reaches every member is already in the same docblock, stated as a mechanism rather than as a reason: naming the local half gives ObjectGantt.configPin.test.ts two independent operands. For parentField it is the only reason, so a reader applying the ONE-reason test literally concludes that member is deletable. State both reasons as reasons, name parentField as the worked example, and correct the neighbouring NARROWINGS claim that the pin test already measures as false. Comment-only; no declaration changed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q --- packages/plugin-gantt/src/ObjectGantt.tsx | 48 +++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/plugin-gantt/src/ObjectGantt.tsx b/packages/plugin-gantt/src/ObjectGantt.tsx index e39b5b07c4..3e4c5b838b 100644 --- a/packages/plugin-gantt/src/ObjectGantt.tsx +++ b/packages/plugin-gantt/src/ObjectGantt.tsx @@ -110,18 +110,42 @@ type GanttConfigEx = GanttConfig & GanttConfigRestated; * measured against the shipped `GanttConfig` on `main` (objectui#6471; the card * counted eleven before objectui#6051/#6472 landed part of the lift). * - * Ten are RESTATEMENTS: `GanttConfig` already declares them (nine of the ten - * arrive from the spec's `GanttConfigSchema`, which declares 19 keys), and the - * type written here is mutually assignable with the twin. They are kept, not - * deleted, for ONE reason — their JSDoc is the only prose in this repo describing - * what this renderer DOES with each key. The spec emits no per-member docs - * (`z.input` carries none), so deleting the members - * deletes the documentation, and JSDoc cannot be attached to a member a type - * merely inherits. + * All twelve RESTATE a key `GanttConfig` already declares — eleven arrive from + * the spec's `GanttConfigSchema` (19 keys), `timeSegments` is objectui's own — + * and every one is mutually assignable with its twin. That includes + * `quickFilters` and `timeSegments`, which objectui#6471 called load-bearing + * NARROWINGS: measured on `main` they narrow nothing. What those two still do is + * NAME this plugin's runtime types (`QuickFilterDef[]` / + * {@link ShiftSegmentsConfig}), so a spec bump that moves either side surfaces as + * a decision. `ObjectGantt.configPin.test.ts` holds that measurement — read it + * there rather than re-deriving it here. * - * Two are NARROWINGS and load-bearing: `quickFilters` and `timeSegments` pin the - * plugin's own runtime types (`QuickFilterDef[]` / {@link ShiftSegmentsConfig}), - * which is precision the intersection would otherwise lose. + * ## Why a member is kept rather than deleted — TWO reasons, either sufficient + * + * 1. PROSE, where there is any. The spec emits no per-member docs + * (`z.input` carries none) and JSDoc cannot be + * attached to a member a type merely inherits, so for most members the + * docblock below is the fullest description of what this renderer DOES with + * the key. It does NOT reach every member: four are bare here — + * `parentField`, `baselineEndField`, `assigneeField`, `effortField` — the last + * three covered by a neighbour's docblock, `parentField` by nothing. Nor is + * this prose unique any more: since objectui#6472 the flattened face + * (`ObjectGanttSchema` in `@object-ui/types`) documents all twelve, and + * objectui#6561 expanded `parentField`'s entry there. + * + * 2. PIN OPERAND — this reason reaches EVERY member, and for `parentField` it is + * the only one. The pin below is derived over `keyof GanttConfigRestated`: a + * member that exists is compared against its twin, and a member that is + * deleted simply stops being compared. + * + * ⛔ So the test for whether a member may be deleted is NOT "does it carry its + * own JSDoc". Applied to `parentField` that test answers "deletable", and it is + * wrong. Deleting `parentField` is not silent — it fails three assertions in + * `ObjectGantt.configPin.test.ts`: the `RESTATED` census, the non-vacuity control + * that names it, and the fixture. But all three fail INSIDE the pin, which is the + * file a reader edits to turn a red build green; follow those errors and the tree + * goes green with one member fewer under the pin. Delete a member here only when + * its twin on `GanttConfig` goes with it. * * ⚠️ NAMED rather than inlined into the intersection above, and that is the * whole mechanism: inside `GanttConfigEx` there is nothing left to compare, @@ -129,7 +153,7 @@ type GanttConfigEx = GanttConfig & GanttConfigRestated; * therefore assignable to `GanttConfig[K]` by construction — an assertion written * against `GanttConfigEx` passes no matter how far the two declarations drift. * Naming the local half is what gives `ObjectGantt.configPin.test.ts` two - * independent operands, so a spec bump that re-types one of the ten breaks the + * independent operands, so a spec bump that re-types one of the twelve breaks the * build at the pin instead of silently intersecting the old type back in. */ export type GanttConfigRestated = { From 8ceafdfaa920b575f5f7430efdfb094fa20f5716 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 15:33:03 +0000 Subject: [PATCH 2/2] chore: declare the docblock change as releasing nothing Empty-frontmatter changeset: check-changeset-presence.mjs flags any source file of a released package, and this one is comment-only. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q --- .changeset/gantt-restated-keep-rationale.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/gantt-restated-keep-rationale.md diff --git a/.changeset/gantt-restated-keep-rationale.md b/.changeset/gantt-restated-keep-rationale.md new file mode 100644 index 0000000000..671cfb83ba --- /dev/null +++ b/.changeset/gantt-restated-keep-rationale.md @@ -0,0 +1,13 @@ +--- +--- + +Comment-only change in `@object-ui/plugin-gantt`: no published behaviour, no +declaration and no type changes. `GanttConfigRestated`'s docblock in +`ObjectGantt.tsx` said its members are kept for ONE reason — their JSDoc being +the only prose in this repo for what the renderer does with each key. Measured +on `main` that was false in two ways: four of the twelve members carry no JSDoc +there (`parentField`, `baselineEndField`, `assigneeField`, `effortField`), and +`ObjectGanttSchema` in `@object-ui/types` has documented all twelve since +objectui#6472. The docblock now states both keep-reasons — the prose, and being +an operand of `ObjectGantt.configPin.test.ts` — so the deletability test a +reader applies to `parentField` arrives at "keep".