Skip to content

docs(spec): the DashboardWidgetOptionsSchema doc comment says a misspelled options key compiles and parses, and a wrong value is the type error - #21275

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-21210-widget-options-docblock
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-21210-widget-options-docblock

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #21210
Clause-②: no

What changed

packages/spec/src/ui/dashboard.zod.ts: the DashboardWidgetOptionsSchema doc comment said that a misspelled widget options key (sortDirection, granularity) "is now an author-time type error". That is false. The bag ends in .passthrough(), so such a key compiles and parses. The paragraph now says three things:

  • A wrong VALUE for a declared key (sortOrder: 'sideways') is the author-time type error and the parse error.
  • A misspelled KEY compiles and parses like any other extra key, and it changes nothing.
  • The unconsumed-widget-option warning from os validate, os build and os lint names the misspelled key. It is a warning, so none of the three commands fails on it.

.changeset/21210-widget-options-docblock.md is '@objectstack/spec': patch with Clause-②: no. The comment ships to npm in two places. It is in src/**/*.zod.ts. After the build it is also in the published dist/ui/index.d.ts and dist/ui/index.d.mts, where the new sentence is measured. The schema's shape does not change.

The measurements behind each clause (HEAD 9c765bf4f5)

  1. Type error. tsc --noEmit ran against the BUILT spec, with TypeScript 6.0.3, strict and NodeNext. --listFiles shows 33 files under packages/spec/dist and 0 under packages/spec/src. Each case is written twice: once as a DashboardWidgetOptions annotation, and once inside defineStack({ dashboards }).
    • { sortBy: 'total_amount', sortDirection: 'desc' } compiles clean.
    • { granularity: 'month' } compiles clean.
    • { sortBy: 'total_amount', sortOrder: 'sideways' } is TS2322 at both sites: Type '"sideways"' is not assignable to type '"asc" | "desc" | undefined'.
    • The control, { dateGranularity: 'month', sortBy: 'total_amount', sortOrder: 'desc', limit: 10 }, compiles clean.
    • tsc exits 2, and both errors come from the wrong-value file.
  2. Doors. A probe project ran through the built CLI. It is a defineStack with one object, one dataset and one dashboard. The dashboard has a control widget with only declared keys, a widget with sortDirection and a widget with granularity.
    • os validate exits 0 with 2 warnings. --json reports rule: unconsumed-widget-option and severity: warning at dashboards[0].widgets[1].options and dashboards[0].widgets[2].options.
    • os build exits 0 with the same 2 warnings, and names the rule.
    • os lint exits 0 with Warnings (2), and names the rule.
    • The control widget draws no finding.
    • Wrong-value control: the same probe with sortOrder: 'sideways' makes os validate exit 1 with dashboards.0.widgets.0.options.sortOrder: Invalid value 'sideways'. Expected one of: asc, desc.
    • The level and the three commands match the rule's registration in packages/lint/src/authoring-rules.ts (tier: 'advisory', commands: ALL).

Census of the same claim

git grep -i "author-time type error" over packages/spec/src, content/docs and skills:

  • packages/spec/src/ui/dashboard.zod.ts is corrected in this PR.
  • content/docs/ui/dashboards.mdx is already correct on main. It says a misspelled key parses and the warning names it.
  • skills/objectstack-ui/rules/dashboards.md has the claim at this branch's base 30c530e5c0. PR docs(skills): the dashboards rule stops teaching unread widget options extras #21205 already corrected it on main (f148852752; git merge-base --is-ancestor f148852752 origin/main exits 0). No separate Tier H PR is needed, and this PR does not touch skills/**.
  • content/docs/references/** has 0 hits. build-docs does not lift a schema-level doc comment into the reference page. It lifts only the module header and the .describe() text. check:docs is green after the edit with no regenerated diff, so no reference page changes in this PR.

Verification (HEAD 9c765bf4f5)

  • pnpm --filter @objectstack/spec build: exit 0 (lock verdict command-exit 0).
  • pnpm --filter @objectstack/spec check:generated: all 15 generated artifacts are up to date, read against the dist that build produced.
  • pnpm --filter @objectstack/spec typecheck: exit 0.
  • pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2: 597 files and 17465 tests passed, 1 todo.
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths) derives 79 families. All 79 ran and exited 0. The --ran reconcile reads 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET, because 9 packages had no dist/). After those packages were built, it exited 0.
  • eslint was narrowed to the one changed .ts file. --print-config resolves that file, so it is in the linted population, with 5 rules. --format json reports 1 file, 0 errors and 0 warnings. The config enables no type-aware linting (no parserOptions.project, no projectService), so a comment edit in this file cannot change any other file's result. The repo-wide pnpm lint is left to CI.

Acceptance notes

  • os validate prints the warning text without the rule code in its human output. os build and os lint print unconsumed-widget-option, and os validate --json carries it. The doc comment uses the code as the warning's name, and all three commands carry that code in their machine output. Noted here, not filed.
  • The card says the sentence lifts into the generated reference page. The measurement shows it does not (see the census).

Generated by Claude Code

claude added 2 commits October 1, 2026 23:44
…sspelled options key compiles and parses

The bag ends in .passthrough(), so an undeclared key such as sortDirection
or granularity is admitted by both z.input and the parser. A wrong value for
a declared key is the type error; the misspelled key is named by the
unconsumed-widget-option warning at the authoring doors.

Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d
Co-authored-by: Claude <noreply@anthropic.com>
… add the patch changeset

Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:ui tooling labels Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/ui/dashboard.zod.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/ui/dashboard.zod.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 137 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2791138cbfe89bbc6d72b22e3974ef009a0f3a2e → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 9c765bf4f5d084e008250e9efd6936ebd6beb489
Local-runs: none
Reviewed-at: 2026-10-02T00:38Z

Inputs: card #21210 (body and all 3 comments: triage 5936320498, claim 5942799387, dev report 5943270346), PR #21275 (body, 2-file list, net diff origin/main...9c765bf4f5), and the check-runs on that head. Base of the branch is 30c530e5c0; origin/main at the read is 2791138cbf. Isolated review: the dispatch order and the dispatching seat's conclusions were not read.

① Derived judgments

  1. Accept set: unchanged — RIGHT. The diff is 7 replaced lines inside the /** */ block above export const DashboardWidgetOptionsSchema (packages/spec/src/ui/dashboard.zod.ts :242-254) plus one new .changeset file. The schema body — lazySchema wrapping z.object({ dateGranularity, sortBy, sortOrder, limit, stageOrder }).passthrough().describe(...) — is byte-identical to origin/main. No key added, removed, renamed or tightened; no .strict(), no retiredKey(); DashboardWidgetOptions, the schema's z.input type (:1731), unchanged. Spec property liveness: success.
  2. Public surface: text only — RIGHT. @objectstack/spec publishes src/**/*.zod.ts (package files), and tsc emits the JSDoc onto the exported declaration in dist/ui/index.d.ts / index.d.mts (exports['./ui']), so the new sentences ship to npm; the declaration's type does not move. No generated artifact changes in the diff (no api-surface/, json-schema/, liveness/ or content/docs/references/** hunk); check:generated and check:api-surface sit in Lint & Repo Gates (lint.yml :5511, :5622, :6588) and that job's conclusion is their verdict.
  3. Sentence 1 — TRUE. "a wrong VALUE for one (sortOrder: 'sideways') is an author-time type error and a parse error": sortOrder: z.enum(['asc', 'desc']).optional() (main :281) types as 'asc' | 'desc' | undefined under z.input, and the enum refuses the value at parse. The generalisation holds for the two enum-typed keys (sortOrder, dateGranularity); limit: 0 is a parse error only (z.number().int().positive() types as number), and a sortBy naming nothing the widget selects is caught by the gating validateWidgetBindings rule rather than by the type. The sentence anchors on its named example and every wrong value still surfaces at the authoring door, so no teaching trap of the class the card fixes — a note, not a defect.
  4. Sentence 2 — TRUE. "A misspelled KEY is neither: the bag is open, so sortDirection or granularity compiles and parses like any other extra and changes nothing": .passthrough() closes the object at main :308 (Zod ^4.6.5, where it is the loose form), so z.input admits unknown keys — the generated reference page renders the type as the five declared keys intersected with an open Record of string keys (content/docs/references/ui/dashboard.mdx :82, :187) — and the parser keeps them. "Changes nothing": checkDashboardWidgetOptions (packages/sdui-parser/src/dashboard-widget-options.ts) defines CONSUMED_WIDGET_OPTION_KEYS as the full read set of the dataset-bound render path, and neither spelling is in it.
  5. Sentence 3 — TRUE at the commands' default contract. "the unconsumed-widget-option warning os validate, os build and os lint raise for a key the dataset-bound path does not read — a warning, so none of the three fails on it": packages/lint/src/authoring-rules.ts :747-765 registers validateDashboardWidgetOptions with tier: 'advisory' and commands: ALL (the three authoring commands; validate.ts, compile.ts and lint.ts each consume the registry), and the adapter (validate-dashboard-widget-options.ts) forwards the check's own severity: 'warning' and code: 'unconsumed-widget-option' unchanged (dashboard-widget-options.ts :168, :184). The check skips dataset-less and legacy component widgets (:152-154), which is exactly "the dataset-bound path". Exit codes: os validate and os lint promote warnings only under the opt-in --strict flag ("Treat warnings as errors"; lint.ts :1052 failing = errors.length + (strict ? warnings.length : 0)), and os build has no warning promotion at all (--strict-body is unrelated). Noted, not required: the sentence could say "(without --strict)"; the promotion is the author's flag, not the rule's level.
  6. The retained framing sentence ("the four that are NOT presentation-only: they change the SQL the dataset query compiles to") is unchanged from main and not re-judged.
  7. Changeset body — each sentence TRUE. "no longer says ... author-time type error" (the diff); ".passthrough() ... compiles and parses like any other extra key, and it changes nothing at render time" (items 4); "A wrong value for a declared key, such as sortOrder: 'sideways', is the type error and the parse error" (item 3); "os validate, os build and os lint name the misspelled key with the unconsumed-widget-option warning, which does not fail any of the three commands" (item 5; the check's message names the offending key on every face); "Only the comment changed. The schema's shape is the same." (item 1).
  8. No reference page to regenerate — the dev is RIGHT, the card's "lifts into the generated reference page" is wrong. build-docs.ts renders each ## Schema section through renderSchemaSection from the JSON-schema description (scripts/lib/schema-section.ts :397), i.e. the .describe() string, and takes the page description from the FILE-header docblock (scripts/lib/page-description.ts). The ## DashboardWidgetOptions section on main (dashboard.mdx :300-313) carries only "Widget configuration — declared query keys + open renderer extras" and the five property describes. git grep "author-time type error" origin/main -- content returns 0 hits, so the false sentence never reached a page and the corrected one does not either. check:docs is in Lint & Repo Gates; Build Docs: skipped is by design (its filter is apps/docs/** and content/**, neither touched).
  9. Sibling text is consistent. content/docs/ui/dashboards.mdx :137-143 already states the open bag and names the warning; skills/objectstack-ui/rules/dashboards.md was corrected on main by f148852752 (PR docs(skills): the dashboards rule stops teaching unread widget options extras #21205, an ancestor of origin/main). The branch base 30c530e5c0 predates that commit, but the PR touches no skills/** path, so the merge carries main's text and no governed surface is in the file list (Governed Surface Queue Guard: success).
  10. Observation, carrier none: the // note at dashboard.zod.ts :312-315 says "build-docs lifts JSDoc onto the reference page"; item 8 shows it lifts the file header and .describe() text, not a schema-level or property-level JSDoc on this page. Pre-existing, outside this diff, not a defect in the sense of PD chore: version packages #10 — left for the seat.

② Semver level

  • Changeset .changeset/21210-widget-options-docblock.md: '@objectstack/spec': patch, body ends Clause-②: no. PR body: Clause-②: no. The two agree.
  • RIGHT. The diff publishes text from a released package (src/**/*.zod.ts and the .d.ts JSDoc ship in @objectstack/spec@17.5.0's successor), so skip-changeset would be wrong (Post-Task Checklist step 3: that label is for a diff that publishes nothing). No accept-set widening or narrowing, so no minor, no (widening)/(narrowing) arm, no ADR-0087 disposition owed. Check Changeset: success.
    Clause-②: no

(correct for a comment-only edit under an unchanged schema)

③ Boundary flags

  • open_questions: none declared.
  • Deviation 1 (no regenerated reference page) — ANSWERED, correct; ① item 8.
  • Deviation 2 (skills/** hit already on main, no separate Tier H PR) — ANSWERED, correct; ① item 9.
  • Deviation 3 (zero label writes) — ANSWERED, acceptable. The PR carries the labeler's documentation, size/s, tooling, protocol:ui; needs:contract-review was never hung on it. This record on the current head is the PASS it would have waited for, so there is nothing to strip.
  • Deviation 4 (attribution) — ANSWERED, correct. Both commits end with the model-free pair Claude-Session: + Co-authored-by: Claude, and the PR body ends with the session-URL footer — the form AGENTS.md prescribes for commits and PR bodies; the user's instructions outrank the harness reminder.
  • OOS-1 (os validate's text face prints the warning without its rule code) — CONFIRMED on main: validate.ts :841 pushes ${f.where}: ${f.message} for each advisory, while os build prints rule: ${f.rule} at ${f.path} (utils/format.ts :1712) and os lint prints ${issue.rule} at ${issue.path} (lint.ts :1118); os validate --json carries the advisory objects with rule. The check's message names the offending key on every face, so the comment's sentence holds. Classification "none of a, b, c" is accepted: a face asymmetry, not a defect, contract violation or authoring trap. The seat may file a domain:cli parity card if it wants the three faces to agree; not a condition of this verdict.
  • Docs Drift Check bot (5943254996): the changed file yielded no anchor — informational, ① items 8-9 are the hand re-read it asks for.

Check-runs on 9c765bf4f5d084e008250e9efd6936ebd6beb489

Read at the final poll: 33 check-runs — 23 success, 3 skipped, 0 other conclusions, 7 still running.

  • success: Auto Label, Build Core, Check Changeset, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Dogfood Regression Gate (1/3), Dogfood Regression Gate (2/3), Dogfood Regression Gate (3/3), Dogfood Verify CLI, Flag docs affected by code changes, Governed Surface Queue Guard, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Spec property liveness, Temporal Conformance (live PG + MySQL), Test Core (2/6), The card this PR closes must claim this branch, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, filter.
  • skipped (path-filtered by design on this diff: Build Docs watches apps/docs/** and content/**; Console Pin Gate and Packed-tarball smoke (opt-in) are not triggered by a spec comment edit): Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in).
  • still running at the final read (a running gate is not reported as passed): Lint & Repo Gates, Test Core (1/6), Test Core (3/6), Test Core (4/6), Test Core (5/6), Test Core (6/6), Type Check · workspace.

The derived gate families this diff implies — check:generated, check:docs, check:api-surface (all in Lint & Repo Gates), the four type-check lanes, Check Changeset, Spec property liveness and Governed Surface Queue Guard — are judged by the conclusions above; nothing was run locally. The verdict below is the contract-review verdict on the diff (①-③). The seven runs named as still running are NOT reported as passed: the landing waits for them to conclude green, and the seat confirms that from the head's check-runs before queueing.

Implemented-by: claude/issue-21210-widget-options-docblock
Reviewed-by: session_01UtnxvdiN376GF3sgXwAw4d

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 00:47
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 00:47
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit c7396f1 Oct 2, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-21210-widget-options-docblock branch October 2, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/s tooling

Projects

None yet

2 participants