Skip to content

skills(ui): optimization flight — date macros/relationships pointed at their anchors, searchableFields and timeSegments cut, dashboards consolidated, retired widget keys removed (net −2,585 tokens) - #14338

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-14298-skills-ui-optimization
Sep 2, 2026
Merged

os-zhuang merged 5 commits into
mainfrom
claude/issue-14298-skills-ui-optimization

Conversation

@os-litant

@os-litant os-litant commented Sep 2, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #14298

Governed surface (skills/**) ⇒ this PR stays draft; needs:contract-review is on both carriers because falsehoods 1–2 are contract-semantics corrections. Head sha for every gate figure below: 684415c3.

Review round 1 — one FAIL, fixed

In-seat contract review flagged the UI-D-08 retitle ### Cube Rules (enforced) as asserting enforcement that does not exist. Correct, and the evidence is stronger than the review cited — re-verified at source:

  • granularities: z.array(TimeUpdateInterval).optional() (packages/spec/src/data/analytics.zod.ts:147), and that file contains zero .refine( / superRefine occurrences, so nothing requires it on a time dimension.
  • Cube sql: z.string().describe('Base SQL statement or Table Name') (:216) — the describe string itself admits raw SQL; nothing rejects it at parse time, and no gate script under scripts/ or packages/*/scripts/ references cube.sql.

There is no gate or schema refinement to cite, so the word is dropped, not defended: the heading is now ### Cube Rules. The two body items are unchanged — they are prescriptions with a stated mechanism (cube.sql.trim() read as the object name), not claims of enforcement. Shipping an unbacked "(enforced)" would have been the same defect class this flight exists to remove.

Open questions ruled by the seat: Q1 → C (UI-E-04 deprecated objectName/viewType, filed by the seat as its own card — nothing done here); Q2 → A (the two CJK trigger phrases stay).

Per-file token delta (ratchet convention, ceil(utf8 bytes / 4))

file before after delta ceiling
skills/objectstack-ui/SKILL.md 25,441 22,856 −2,585 25,445 (headroom 4 → 2,589)
package total 36,542 33,957 −2,585 —
whole shipped bundle 187,854 185,269 −2,585 —

Generated package members untouched and unchanged: contracts/react-blocks.contract.json 5,352 · references/react-blocks.md 3,153 · references/_index.md 1,205. evals/** untouched (1,102 + 289). The ceiling is left at 25,445: the ratchet header says a ceiling "may be LOWERED by any PR that shrinks its file … always legitimate and encouraged", but the card's flight constraint forbids touching the ratchet script, so the 2,589 tokens of new headroom are deliberately NOT claimed here — a follow-up may lower the row to the measurement.

Against the card's target. The card targets ≈ −9,170, of which −5,352 is UI-B-04's duplicated generated JSON — explicitly DEFERRED to #14296 item 3 and not mine. The in-file target was −4,199 prose against +385 of additions; landed −2,585. The gap is itemised below rather than smoothed over: the three funded additions cost +838 against the estimated +385 (the filterBindings and widget-options constructs are each roughly double their estimate), and UI-D-01 returned −387 against an estimated −900. Every number below is a measured byte delta.

Per-item: 落点 | before | after

Deletions and merges

id 落点 before after
UI-C-01 ## Date Macros — Filter Placeholders (whole section + ## Context Tokens) 1,288 tok 265 tok (−1,023)
UI-D-02 ### Shift segmentation — timeSegments 581 tok 0 (−581)
UI-C-04 master-detail inlineEdit ladder + line-item grid behaviours 643 tok 193 tok (−450)
UI-D-01 ### Toolbar Search (searchableFields) 1,381 tok 994 tok (−387)
UI-D-05 the options.drillDown renderer note 235 tok 0 (−235)
UI-C-02 action ctx org-isolation + positions narration 371 tok 154 tok (−217)
UI-B-06 ## When to Use This Skill 136 tok 0 (−136)
UI-D-06 the "Removed in v17" compareTo blockquote 106 tok 0 (−106)
UI-D-08 ### Cube Best Practices (5 items) 159 tok 74 tok (−85), retitled ### Cube Rules — see Review round 1
UI-D-04 the metadata fence rationale 145 tok 75 tok (−70)
UI-D-03 "Why this model" (build-independent / collision-free / responsive-correct) 79 tok 22 tok (−57)
UI-C-03 the visibleWhen/readonlyWhen/requiredWhen table 149 tok 103 tok (−46)
UI-D-07 the removed-inline-query history 86 tok 68 tok (−18)
UI-B-05 the 4th Tailwind className restatement 67 tok 52 tok (−15)
UI-B-03 the dateGranularity bucket table under ### Drilldown 273 tok 273 tok (0 — moved under its own heading; reorder is free)

The three funded additions

id what landed cost named payers actual
UI-F-01 + UI-F-03 ### Dashboard filters — globalFilters + per-widget filterBindings: the broadcast rule, name (defaults to field; name it for the vocabulary, not the column), scope: 'widget' + targetWidgets, re-target, false opt-out, the absent-default incl. dateRange.field ?? 'created_at', plus a 2-widget example +371 UI-D-05 (−235) + UI-D-06 (−106) −341, so +30 over
UI-F-02 ### Widget options — the five declared keys (dateGranularity / sortBy / sortOrder / limit / stageOrder), with the top-N spelling that had no documented form +357 UI-D-08 (−85) + UI-D-03 (−57) −142, so +215 over
UI-E-01 os:check marks on the four highest-traffic examples (+ UI-E-03's inlined action) +110 UI-E-02 (−18) +92 over

The three additions cost +838 against −501 of named payers. They are nonetheless fully paid in the same file: the flight's total deletions are −3,423, so SKILL.md ends 2,585 tokens smaller and the ratchet is green with 2,589 tokens of headroom. Flagging the per-item overrun rather than re-cutting the payer list to fit, because the card's funding lines are its ruling and I would rather show them broken than silently re-derive them.

Falsehoods

# 落点 before after
1 canonical dashboard widget actionType: 'url', actionUrl: '/objects/opportunity?filter=open' line deleted. dashboard.zod.ts:382-384 retires all three via retiredKey(...) = z.never(); prescription :309-320 "a dashboard widget has NO action button, and never had one".
2 ### Server-side date bucketing "Date bucketing lives on the dataset dimension, not the widget." "The dataset dimension carries the default; a widget's options.dateGranularity overrides it for that widget only." (dashboard.zod.ts:217-225)
3 frontmatter "the React renderer implementation (lives in packages/client-react, not metadata)" clause deleted. packages/client-react is "React hooks for ObjectStack Client SDK"; the renderer is @object-ui/react-runtime, in objectui.
4 (new) the Tokens-in-filters blockquote on the canonical dashboard {current_user.id} {current_user_id}. current_user.id is the RLS expression root, not a filter token — spec/src/data/context-tokens.zod.ts:44,49 names this exact near-miss and :85 lists the real token. Found inside a span this flight was already rewriting, same defect class as 1–2, mechanically fixed against the spec; taken under the bounded-in-place rule.

Also deleted, never ported (card ruling): this package's claim that "unknown placeholders silently pass through as literal strings". It is false and the file contradicted itself 37 lines earlier. packages/core/src/utils/filter-tokens.ts:378 throws UnknownFilterTokenError, and the module header at :44 is titled "An unknown token throws".

Deliberate deviations from the routed plan

  1. UI-C-01 keeps its ## heading. The ruling says delete :1659-1768. Two in-file links (:1074, :1507) target #date-macros--filter-placeholders; deleting the heading breaks both, so the heading survives carrying the pointer. Also kept: two rules objectstack-query does not own — a filter token is presentation scope, not security; and AppContextSelector ids resolve in navigation recordId/params only, never in a filter. Both were their last mention in the package.
  2. UI-C-02 keeps ctx.session.positions in compact form. The routed anchor does not carry it (see follow-ups). Kept with the "not an authorization input" guard; the org-isolation half is deleted and pointed.
  3. UI-G-03 translates 1 of 3 CJK lines, not 3 — label: '打印总表(A3)' → 'Print Summary Sheet (A3)'. The two at :755-756 are non-English user phrasings the router matches on; translating a phrase whose only job is to match untranslated input destroys it. Seat ruled A: they stay.
  4. The ratchet ceiling is not lowered — see the token table.

Not implemented (and why)

premise_false

None. git diff --stat a59f78d origin/main -- skills/objectstack-ui is empty, so every audit span was byte-identical at the branch point. Two PM mechanical assumptions were refined rather than confirmed — below.

PM mechanical assumptions — measured

  1. Confirmed. skills/objectstack-ui/** byte-identical between a59f78d and origin/main. (origin/main had already moved past the dispatch's d63c8a25 to 909a4417, which does not touch skills/; the branch is cut from 909a4417.)
  2. Refined — the predicted file is the wrong one. check:skill-docs does run in CI and the frontmatter edit does force a regeneration, but skills/README.md came back green on its own (✓ skills/README.md) — it does not embed the description. The out-of-date artifact was content/docs/ai/skills-reference.mdx. Regenerated with the one generator the card names; the diff is 2 lines, both the frontmatter's own text.
  3. Confirmed for tsc; the parse half not measured. Reverse-verified against a committed tree: re-injecting actionType/actionUrl on the widget turns check:skill-examples red with two error TS2322: Type 'string' is not assignable to type 'undefined' — one per retired key, z.never() surfacing as undefined in the input type. Mutation proven on disk before measuring (injected-text grep count 1; blob 4a5d1e25 → 6b5d8296), restore proven the same way (git diff HEAD empty, blob back to 4a5d1e25, injected count 0) — neither leg read from an editor's exit code. This gate exercises tsc only, so the Zod parse failure is asserted from the schema source, not measured here.
  4. Confirmed, with one restructure. Marked count 259 → 263, "every marked block parsed, so tsc ran the SEMANTIC pass on all of them". Two needed more than a marker: the record-detail page carried UI-E-03's unresolvable relative import (replaced with an inlined 4-line defineAction), and the defineDataset block was a fragment — it now imports defineDataset + type DashboardWidget and binds the trailing widget literal to a typed const.
  5. Not exercised — no finding's premise was false.

follow-up for objectstack-query

rules/filters.md is the anchor and is strong: it already carries the fixed tokens, the parameterised form, both session tokens, both resolvers, the calendar-DAY *_end trap, and — decisively — "Unknown tokens are rejected, not ignored". These TRUE rows from the deleted objectstack-ui text are not in it and were not ported:

  1. Both {token} and ${token} spellings are accepted — spec/src/data/date-macros.zod.ts:200,207 and context-tokens.zod.ts:101. rules/filters.md shows only the bare form.
  2. Two more near-misses: {user_id} (a valid titleFormat field interpolation elsewhere) and {organization_id} (the real column name). Query names {current_user} and {this_quarter_start} only.
  3. A token embedded in a larger string is not substituted ('user-{current_user_id}'). Query states only the converse; filter-tokens.ts:44 states this half directly — "Values that merely CONTAIN braces are left untouched."
  4. isDateMacroToken(tok) from @objectstack/spec/data as the author-time type check.
  5. The build rule's name, filter-token-unknown, and why it exists: an unresolved token reaches SQL as a literal, matches nothing, and the widget renders 0 — indistinguishable from a genuine zero.

follow-up for objectstack-data

references/data-hooks.md carries the org-isolation half completely — UI-C-02's deletion is safely routed there. It does not document ctx.session.positions at all; :368 says only that ctx.session has "No role list — session.roles was retired in 17.0.0". So the ADR-0090 D3 spelling and the "not an authorization input" guard have no anchor to point at, and a compact form was kept here rather than deleted into a gap.

Gates — all 42 families, all at head 684415c3

⚠️ Correcting a stale figure this PR body previously carried. It claimed 16 families. That derivation ran at 0f937dcc, when the changeset was SKILL.md alone; the next commit added content/docs/ai/skills-reference.mdx and scripts/skill-identifier-liveness-ledger.json, and I did not re-derive. Re-derived at the current head, node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack names 42 — the 26 extra are the docs family the .mdx pulls in. All 42 have now been run; every one of the 26 that had never been run passes. The earlier "16" was wrong and is retracted here rather than quietly overwritten.

41 of 42 exit 0. Each exit code captured by redirecting before any pipe. The full list, in the order the harvester prints it:

check-ci-filter-parity · check-cross-package-test-inputs · check-doc-frontmatter · check-doc-route-spelling · check-docs-section-name · check-section-landing-index · check-shard-attestation · check-skills-token-ratchet · doc-formula-expressions · doc-security-posture · check:docs · check:empty-state · check:liveness · check:skill-docs · check:skill-examples · check:strictness-ledger · check:variant-docs · check:yaml-examples · agent-test-spelling · bash32-floor · cli-command-ids · corpus-claim-drift · cross-package-test-inputs · doc-anchors · doc-authoring · docs-audit-scope · docs-redirects · docs-single-h1 · entry-guard · merge-driver · parse-guard · pm-governed-merges · pnpm-filter-targets · published-readme-links · react-page-adapter-contract · role-word · skill-compatibility · skill-frame-sync · skill-identifier-liveness · vendor-version-stamps · watch-hint-literal — all exit 0.

Named verdict lines for the two the review asked for:

  • node scripts/check-skills-token-ratchet.mjs → exit 0, "skills/objectstack-ui/SKILL.md is 22856 tokens (ceiling 25445; headroom 2589)" · "38 authored bundle file(s) within their ceilings".
  • pnpm --filter @objectstack/spec check:skill-examples → exit 0, "✅ 263 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them".

The 42nd, node scripts/check-test-completeness.mjs, exits 3 = NOT MEASURED by its own verdict text ("Nothing was measured… It is not a red, and there is nothing here to fix") — it needs a saved turbo run test log. Recorded as NOT MEASURED: not a pass, not a red.

Heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-14298. Prerequisite builds re-run at this head, not assumed: @objectstack/spec and the @objectstack/client-react / @objectstack/client dependency closure — without the latter check:skill-examples refuses to run rather than reporting green ("packages/client-react/dist holds no .d.ts declarations… a FALSE GREEN on exactly the change it exists to catch").

Repo-wide pnpm lint (eslint over the whole tree) was NOT run — it is CI's own step, in this derivation's unnarrowable "always runs" tail. A plain omission, not a measured narrowing; I claim none of the three evidence items a narrowing would need.

Two consequences outside SKILL.md

Both generator/tool output, neither hand-written, each the mechanical consequence of a funded edit:

  • content/docs/ai/skills-reference.mdx — gen:skill-docs, forced by the frontmatter edit (assumption 2). Not content/docs/releases/.
  • scripts/skill-identifier-liveness-ledger.json — check-skill-identifier-liveness.mjs --update, pruning dayStart and showMidnight. Both existed only to excuse the timeSegments block this flight deleted, and each ledger note independently records the implementation living in objectui plugin-gantt — the same measurement UI-D-02 rests on. --update never adds an exemption.

Changeset

skip-changeset applies and is on the PR. Checked against the repo's own rule: the exemption means "this PR declares no release of its own", and no package publishes skills/, content/docs/ or scripts/. The Check Changeset job reads labels live; the label cannot be applied before the PR exists, so it was applied immediately after creation and read back.


🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

os-litant and others added 4 commits September 2, 2026 01:59
…e/drilldown trims, filterBindings + widget options funded

UI-C-01  delete the date-macro + context-token block; keep the heading (two
         in-file anchors resolve to it) and point at objectstack-query
         rules/filters.md. Two UI-owned rules stay: presentation-scope-not-
         security, and AppContextSelector ids never resolving in a filter.
UI-C-02  drop the org-isolation narration; keep the blessed-name pointer at
         objectstack-data's hooks reference. `ctx.session.positions` stays in
         compact form -- the anchor does not carry it (see PR follow-up list).
UI-D-08  Cube Best Practices -> the two enforced facts.
UI-D-05  delete the renderer note that ends by telling the reader to ignore it.
UI-D-06  delete the v17 `compareTo` removal narration.
UI-B-03  move the dateGranularity bucket table out of `### Drilldown` and under
         its own heading (reorder only).
UI-G-02  falsehood 2: the dataset dimension is the DEFAULT; options.dateGranularity
         overrides it per widget (dashboard.zod.ts:217-225).
UI-E-02  falsehood 1: delete the retired `actionType`/`actionUrl` pair from the
         canonical dashboard widget (dashboard.zod.ts:382-384, retiredKey =
         z.never()).
falsehood 4 (found in span, same defect class): `{current_user.id}` ->
         `{current_user_id}`; `current_user.id` is the RLS expression root, not
         a filter token (spec/src/data/context-tokens.zod.ts:44,49,85).
UI-F-01/F-03  ADD the globalFilters/filterBindings construct (paid by D-05+D-06).
UI-F-02  ADD the five declared widget `options` keys (paid by D-08+D-03-to-come).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…etired, relationships/conditional-rules pointed at objectstack-data

UI-D-01  keep the two tables and the `userActions: { search: false }` example;
         delete the two verbatim `os validate` diagnostics, the empty-array
         essay (folded into the row that already existed) and the related-title
         prose (reduced to its objectstack-data pointer).
UI-D-02  delete the `timeSegments` block -- self-declared NOT part of
         GanttConfigSchema, zero implementation in this repo (every hit is in
         objectui plugin-gantt), and 10 of the package's 13 CJK lines.
UI-C-04  the inlineEdit ladder and the modelled grid behaviours point at
         objectstack-data rules/relationships.md, which carries them verbatim.
         Kept the three UI-authored facts the anchor does NOT carry: the ghost
         row, `autofill: false`, and the form's `taxRateField`.
UI-C-03  delete the visibleWhen/readonlyWhen/requiredWhen table; keep the
         routing line, the row-by-row inline-grid note and the retired
         `conditionalRequired` guard.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…our highest-traffic examples gated

UI-A-01  add `*.page.ts` / `*.report.ts` / `*.dataset.ts` to the trigger list --
         `*.page.ts` is the corpus's most-authored kind (29 definitions) and had
         no filename trigger at all.
UI-A-02  falsehood 3: drop "the React renderer implementation (lives in
         packages/client-react)". That package is React hooks for the client SDK
         (package.json description; src/index.tsx exports hooks + provider). The
         renderer is @object-ui/react-runtime, in objectui.
UI-A-03  wizards: a stepped form over ONE object is this skill's `formViews`
         `type: 'wizard'`; only step-branching flows route to automation.
UI-D-07  keep the requirement, drop the removal history.
UI-D-03  delete the "Why this model" justification.
UI-D-04  reduce the metadata-fence rationale to the two facts the table lacks
         (live-not-a-screenshot; data-not-code).
UI-B-06  delete "When to Use This Skill" -- it restated the frontmatter.
UI-B-05  the Tailwind rule now states the rule once and points at ADR-0065.
UI-G-03  translate the CJK example label. The two remaining CJK lines are
         non-English USER PHRASINGS the router matches on -- see the PR body.
UI-E-03  inline a minimal defineAction so the record-detail page block stands
         alone (the relative import could never resolve in the gate build dir).
UI-E-01  mark four highest-traffic examples `os:check`: structured definePage,
         the Dashboard literal, defineDataset, the react source tier.

Gate: pnpm --filter @objectstack/spec check:skill-examples -- 259 -> 263 marked
blocks, "every marked block parsed, so tsc ran the SEMANTIC pass on all of them".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…nd the timeSegments deletion

Two mechanical consequences, neither hand-written:

- `content/docs/ai/skills-reference.mdx` — `pnpm --filter @objectstack/spec
  gen:skill-docs`. The dispatch predicted `skills/README.md` would be the file
  the drift gate demands; it is not. README came back green on its own (it does
  not embed the description); the out-of-date artifact is the reference page.
  Both are outputs of the one generator the card names.
- `scripts/skill-identifier-liveness-ledger.json` — `node
  scripts/check-skill-identifier-liveness.mjs --update`, pruning the now-stale
  `dayStart` / `showMidnight` exemptions. Both existed only to excuse the
  `timeSegments` block this flight deleted, and each ledger note independently
  records that the implementation lives in objectui plugin-gantt -- the same
  measurement UI-D-02 rests on. `--update` never ADDS an exemption.

Gates: check:skill-docs 0 (both artifacts ✓); check:skill-identifier-liveness 0
("Leg 1: 498 citations over 48 published files ... 3 ledgered exemptions").

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation labels Sep 2, 2026
@os-litant os-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate needs:contract-review and removed documentation Improvements or additions to documentation labels Sep 2, 2026 — with Claude
…ding

In-seat contract review is right: my UI-D-08 retitle asserted enforcement that
does not exist, which is the same defect class this flight exists to remove.
Re-verified against the source, and the evidence is stronger than the review
cited:

- `granularities: z.array(TimeUpdateInterval).optional()`
  (packages/spec/src/data/analytics.zod.ts:147) — optional, and the file
  contains ZERO `.refine(` / `superRefine` occurrences, so nothing requires it
  on a `time` dimension.
- Cube `sql: z.string().describe('Base SQL statement or Table Name')` (:216).
  The describe string itself admits raw SQL; nothing rejects it at parse time,
  and no gate script under scripts/ or packages/*/scripts/ references
  `cube.sql`.

So there is no gate or schema refinement to cite, and the word is dropped rather
than defended. The two body items are unchanged: they are prescriptions with a
stated mechanism (`cube.sql.trim()` read as the object name), not claims of
enforcement.

Gates at this head: node scripts/check-skills-token-ratchet.mjs exit 0 --
SKILL.md 22856 tokens (ceiling 25445, headroom 2589); pnpm --filter
@objectstack/spec check:skill-examples exit 0 -- "263 prose examples type-check
across 3 surface(s)".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 2, 2026
@os-litant os-litant changed the title skills(ui): optimization flight — date macros/relationships pointed at their anchors, searchableFields and timeSegments cut, dashboards consolidated, retired widget keys removed (net −2,583 tokens) skills(ui): optimization flight — date macros/relationships pointed at their anchors, searchableFields and timeSegments cut, dashboards consolidated, retired widget keys removed (net −2,585 tokens) Sep 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 2, 2026 06:18
@os-zhuang
os-zhuang enabled auto-merge September 2, 2026 06:18
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 2, 2026
Merged via the queue into main with commit 54a1125 Sep 2, 2026
45 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14298-skills-ui-optimization branch September 2, 2026 06:41
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 size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants