Skip to content

docs(plugin-gantt): state both reasons GanttConfigRestated keeps a member - #6589

Draft
os-support-ai wants to merge 2 commits into
mainfrom
claude/issue-6563-ganttconfigrestated-rationale
Draft

docs(plugin-gantt): state both reasons GanttConfigRestated keeps a member#6589
os-support-ai wants to merge 2 commits into
mainfrom
claude/issue-6563-ganttconfigrestated-rationale

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#6563

Comment-only. No declaration, type, or behaviour changed — GanttConfigRestated
still has exactly the same twelve members, and the diff is the docblock above it
plus an empty-frontmatter changeset.

Step 1 — the pin claim, verified by ablation rather than by reading

The card asked for this to be checked before anything else, and it holds.
parentField is a pin operand of ObjectGantt.configPin.test.ts three separate
ways. Measured by deleting the member and compiling — the mutation was confirmed
on disk first (anchored grep -c 1 → 0, blob hash e39b5b0799259398), and
the tree was restored afterwards and proven byte-identical to HEAD
(git diff HEAD empty, hash back to e39b5b07).

tsc -p tsconfig.test.json went from exit 0 to exit 2:

src/ObjectGantt.configPin.test.ts(125,11): error TS2322: Type 'true' is not assignable to type '"parentField"'.
src/ObjectGantt.configPin.test.ts(149,11): error TS2322: Type 'true' is not assignable to type 'never'.
src/ObjectGantt.configPin.test.ts(202,7): error TS2353: Object literal may only specify known properties, and 'parentField' does not exist in type 'GanttConfigRestated'.

Line 125 is the RESTATED census (StaleCensusEntry), line 149 is the pin's own
non-vacuity control #4 — which names the literal 'parentField' — and line 202 is
the cfg fixture. parentField is additionally a derived operand of Diverged,
which maps over keyof GanttConfigRestated.

One correction to the card: deleting parentField is not silent. It breaks
the build in three places, one of which names the key. The defect is still real,
but its shape is different and the docblock now says so — all three failures land
inside the pin test, which is the file a reader edits to turn a red build
green, and which advertises itself as a self-maintaining census. Follow those
three errors (drop the census entry, re-point the control at another key, drop the
fixture line) and you get a green tree with one member fewer under the pin.

Step 1 — the per-member JSDoc census

Re-measured on 6a7893d57, not the card's 0235ce7c1. Mechanical, by checking
whether the line above each member ends a JSDoc block:

memberown JSDoc hereprose on the flat face
parentFieldNOyes (block)
typeFieldyes (block)yes (1-line)
baselineStartFieldyes (1-line)yes (1-line)
baselineEndFieldNO — neighbour'syes (1-line)
groupByFieldyes (block)yes (1-line)
resourceViewyes (block)yes (1-line)
assigneeFieldNO — in resourceView'syes (1-line)
effortFieldNO — in resourceView'syes (1-line)
capacityyes (1-line)yes (1-line)
quickFiltersyes (block)yes (block)
autoZoomToFilteryes (block)yes (1-line)
timeSegmentsyes (block)yes (1-line)

Four of twelve are bare here, exactly as the card measured. Three borrow a
neighbour's prose; parentField borrows nothing.

Positive controls, because two columns contain a zero. My first census script
was wrong — it only recognised multi-line blocks and so reported false zeros for
baselineStartField and capacity; the table above is from the corrected query.
For "bare here", the same query on the same type returns non-zero for the other 8
members. For "0 of the twelve lack flat-face prose", the same query over all 310
optional members of objectql.ts also returns 0, so that file could not serve as
its own control — instead the query was re-run against a scratchpad copy of
that same file with exactly one JSDoc line removed, and it reported exactly
ObjectGanttSchema.typeField. The repo copy was never mutated.

Why the rationale was false, and more broadly than the card says

The docblock claimed the members are kept for ONE reason — their JSDoc is the only prose in this repo describing what this renderer DOES with each key. That
is false in two independent ways, and the second one reaches all twelve:

  1. Four members carry no JSDoc there at all.
  2. ObjectGanttSchema in @object-ui/types documents every one of the twelve
    with renderer-behaviour prose, so the JSDoc here is not the only prose for any
    member.

The dispatch framed (2) as objectui#6561 having weakened the documentation half
for parentField specifically. The commit timeline says something stronger — the
claim was already false for all twelve on the day it was written:

commitwhen (2026-08-26)what
75bd83d6d (objectui#6472)02:55declared the flat face with per-member JSDoc for all twelve
64e32e6c0 (objectui#6546)10:24wrote the "ONE reason … only prose" docblock — 7.5h later
f20dcf075 (objectui#6561)12:17expanded four of those pointers, parentField among them

So objectui#6561 did not weaken the claim; it made an already-false claim more
visible on the one key that had no local prose to fall back on.

Which shape was picked, and why

The card offered two. Option 1 (reword so both reasons are stated as reasons),
because the measurement rules option 2 out rather than leaving it a preference:
giving parentField a one-liner would not make the stated rationale true as
written. "Their JSDoc is the only prose in this repo" stays false afterwards — the
flat face still documents all twelve — and baselineEndField, assigneeField and
effortField are still bare, so the ONE-reason test still misfires on three
members and on any bare member added later.

Deliberately not done: adding duplicate prose for parentField here. The
authoritative consumer-visible prose landed on ObjectGanttSchema.parentField in
objectui#6561, and a second copy in a package-private type is the fork that
@object-ui/types' own docblock says the objectui#6051 lift existed to prevent.
The docblock points at it instead.

How the deletability test was checked, not asserted

The claim to check is that a reader applying the new test to parentField arrives
at "keep". The test the docblock now states is "delete a member here only when
its twin on GanttConfig goes with it"
, with reason 2 given as reaching every
member. Applying it mechanically to parentField: its twin is
GanttConfigSchema.parentField, which is present in the spec's shipped
view.zod-*.d.ts (verified in node_modules, parentField: z.ZodOptional<z.ZodString>
among the 19 keys), so the twin has not gone → keep. The old test — "does this
member carry its own JSDoc" — returns "deletable" on the same input, which is the
answer the ablation above proves wrong. The two tests are stated adjacently in the
docblock precisely so the wrong one cannot be applied by accident, and
parentField is named as the worked example.

Bounded in-place fix, declared

One correction beyond the card's literal subject, in the same docblock and the
same defect class (a stated keep-reason that measurement contradicts): the
neighbouring Two are NARROWINGS and load-bearing … which is precision the intersection would otherwise lose. ObjectGantt.configPin.test.ts already
records the opposite as a measured fact — "on current main they narrow
nothing"
— and its both still name THIS plugin's runtime vocabulary case pins
what those two members actually do. The correct form was therefore already
established by existing evidence rather than invented here. Leaving it would have
meant rewriting one paragraph to be accurate while the next asserted a keep-reason
this repo's own pin test disproves.

Also restated from measurement rather than carried forward: the origin count. The
old text said "nine of the ten arrive from the spec's GanttConfigSchema". Counted
against the shipped spec .d.ts, eleven of the twelve arrive from it and
timeSegments is objectui's own — the taxonomy had to be restated anyway once all
twelve are described as restatements.

Files touched

file+/-
packages/plugin-gantt/src/ObjectGantt.tsx+36 / -12 (comment lines only)
.changeset/gantt-restated-keep-rationale.md+13 / -0 (new)

Gates — union run on the final commit 8ceafdfaa, clean tree

Each exit code captured before any pipe; each verdict is the gate's own line.

gateexitverdict
pnpm --filter @object-ui/plugin-gantt run type-check0echoed tsc --noEmit && tsc -p tsconfig.test.json (not a zero-match)
vitest run packages/plugin-gantt/src/ObjectGantt.configPin.test.ts0Test Files 1 passed (1) / Tests 6 passed (6)
vitest run packages/plugin-gantt (full suite)0Test Files 50 passed (50) / Tests 420 passed (420)
check-changeset-presence.mjs0✅ … declares 1 changeset(s) — empty frontmatter, "the explicit exemption and a complete answer to this gate"
check-changeset-no-major.mjs0✅ No changeset declares a major bump.
check-changeset-fixed.mjs0✅ All workspace packages are in the changeset fixed group.
check-changeset-overwrite.mjs0✅ No pre-existing changeset was modified or deleted.
check-control-bytes.mjs0✅ check-control-bytes: OK (scanned 5444 tracked text file(s))
check-doc-fence-languages.mjs0✅ check:doc-fences — every TypeScript block in 223 document(s) …
eslint . in packages/plugin-gantt00 errors; edited file in the population at 0 errors

Tests were run from the repo root, not pnpm --filter <pkg> test (objectui#3378).
Dependency closure was built first (pnpm --filter '@object-ui/plugin-gantt^...' build,
exit 0) because tsconfig.test.json sets "paths": {} and resolves @object-ui/*
through built .d.ts; --listFiles confirms ObjectGantt.configPin.test.ts and
ObjectGantt.tsx are both in that program and that 41 files resolve from
packages/types/dist.

Lint narrowing, declared.eslint . was run for the affected package rather
than repo-wide. Population comes from eslint's own config (80 files selected under
packages/plugin-gantt), the count from --format json, and the invariance
argument is that eslint.config.js declares no projectService/parserOptions.project,
so there is no cross-file type program a comment edit could move. The edited file
carries 85 pre-existing warnings, none of them line-count-sensitive
(no-explicit-any ×73 and react-hooks rules; no max-len/max-lines) and none
inside the edited range 108–158. An earlier run with --no-inline-config reported
2 errors in demo/main.tsx; that flag is objectstack's lint spelling, not
objectui's, and the package's real lint script exits 0.

Note on the re-dispatch

The order described the branch as sitting at a stale base 6a7893d57.
origin/mainis6a7893d57, so the base was current, not stale;
git log origin/main..origin/<branch> was empty as required, and the branch was
re-cut from origin/main anyway. Nothing was discarded.

Generated by Claude Code


Generated by Claude Code

…mber
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
@os-support-aiClaude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT on the diff at 8ceafdfaa. ⏸ Landing held — CI has only 3 runs and all three are queued with no runner allocated. That is the merge-queue/Actions starvation recorded in #6588, not anything about this PR.

The ⛔ held, verified mechanically

Comment-only.ObjectGantt.tsx is +36/−12 and, parsing the patch, 0 non-comment lines added and 0 non-comment lines removed. No declaration, type or behaviour moved.

parentField survives:160 parentField?: string;, still read at :535, with 22 other member lines intact as a control. Deleting it was the outcome this card exists to prevent, and it was not performed.

The pin claim was verified by ablation, not by reading

The order forbade taking it from the card. Deleting parentField moves tsc -p tsconfig.test.json from exit 0 to exit 2 with three errors — the RESTATED census (:125), the pin's own non-vacuity control #4 which names the literal 'parentField' (:149), and the cfg fixture (:202) — and it is additionally a derived operand of Diverged, which maps over keyof GanttConfigRestated. Mutation proved on disk (anchored count 1→0, blob e39b5b0799259398), restore proved by byte identity rather than an exit code.

Why option 1, and why that is stronger than a preference

The card offered two shapes. Measurement rules the second one out rather than merely disfavouring it: giving parentField a one-liner would still not make "their JSDoc is the only prose in this repo" true, because ObjectGanttSchema in @object-ui/types documents all twelve members and baselineEndField / assigneeField / effortField would remain bare. An option that cannot be made true is not a choice.

It also declined to duplicate the prose, correctly: the authoritative consumer-visible copy landed on ObjectGanttSchema.parentField in #6561, and a second copy in a package-private type is exactly the fork the #6051 lift existed to prevent. Refusing to fix a documentation gap by re-creating the drift the repo already has a card about is the right instinct.

⭐ The control design is the best thing in this report

For the claim "0 of 12 members lack flat-face prose", the natural control is degenerate — the same query over all 310 optional members of objectql.ts also returns 0, so that file cannot control itself. Rather than report an uncontrolled zero, it built a synthetic positive: the same query against a scratchpad copy of the file with exactly one JSDoc line removed, which returned exactly ObjectGanttSchema.typeField. The repo copy was never mutated.

That is the correct answer to "what if there is no naturally-occurring positive" — manufacture one in a copy — and it is worth carrying forward as a pattern.

It also caught its own instrument error and said so: the first census script recognised only multi-line JSDoc and so reported false zeros for baselineStartField and capacity. The published table is from the corrected query.

Three corrections to this seat's order, all accepted

  1. "Stale base" was wrong. I called 6a7893d57 a stale base; origin/mainis6a7893d57. It ran the required emptiness check anyway.
  2. "Silently removes a pin operand" was wrong — and the replacement is better. Deletion is not silent: three assertions fail and tsc exits 2, with one error naming the key. But the defect survives in a sharper form: all three failures land inside the pin test, which advertises itself as a self-maintaining census and is precisely the file a reader edits to turn a red build green — so the three errors read as "update the census" rather than "you removed a guard". The reworded docblock states that shape. A correction that keeps the defect real instead of dissolving it is the useful kind.
  3. docs(types): expand the flat gantt face's four bare GanttConfig pointers #6561 did not weaken the rationale — it was false on arrival.75bd83d6d (feat(types,plugin-gantt): declare the flattened GanttConfig face ObjectGantt reads (#6051) #6472) gave all twelve members flat-face prose at 02:55; 64e32e6c0 (fix(plugin-gantt): pin every restated GanttConfig member against its twin #6546) wrote the "ONE reason … only prose" docblock at 10:24, 7.5 hours later. So that half was untrue for every member from the moment it was written; docs(types): expand the flat gantt face's four bare GanttConfig pointers #6561 only made it visible on the one key with no local prose to fall back on. My order said "weaker for that key specifically", which understated it.

The new test, checked rather than asserted

The docblock now reads "Delete a member here only when its twin on GanttConfig goes with it" (:147), with reason 2 given as reaching every member. Applied to parentField: its twin GanttConfigSchema.parentField is present in the spec's shipped .d.ts among the 19 keys → KEEP. The old test returns "deletable" on the same input, which the ablation proves wrong. Both are stated adjacently with parentField as the worked example, so the wrong one cannot be reached by accident.

The one in-place extension — correcting the neighbouring "Two are NARROWINGS and load-bearing" claim — is in scope and well-grounded: same docblock, same defect class, and ObjectGantt.configPin.test.ts already records the correct form as measured ("on current main they narrow nothing"), so it is transcribing existing evidence rather than introducing a judgement.


Generated by Claude Code

@os-support-aiClaude

Copy link
Copy Markdown
CollaboratorAuthor

Blocker, stated once: the two non-green checks here are cancelled, not failures, and they are not this PR's.

Skill Guide Path Check and Inert vi.mock Specifier Check both report steps: 0 — no step ever executed — and both ran exactly 15m01s before being cancelled (15:35:14→15:50:15). A job that never executed a step did not fail; it never started.

There is also a content argument that settles it independently of the timing: this PR is comment-only. Parsing its patch gives 0 non-comment lines added and 0 removed. A change that alters no code cannot break a skill-guide-path scan or a vi.mock specifier scan.

This is the repository-wide Actions runner starvation recorded in #6588 — nine such cancellations across this PR, #6587 and main itself, with zero genuine failure conclusions anywhere.

⛔ No push, no re-run, no change to this PR. ⛔ Not a case for weakening anything.

Holding, and landing once the checks can actually run.


Generated by Claude Code

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(plugin-gantt): GanttConfigRestated's “kept for ONE reason: their JSDoc” rationale does not hold for parentField, which has none

2 participants

@os-support-ai@claude