Skip to content

spec(ui): UserActionsConfigSchema adopts group / hideFields / rowColor (ruled A on objectui#5435) - #11458

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11195-user-actions-three-keys
Aug 23, 2026
Merged

spec(ui): UserActionsConfigSchema adopts group / hideFields / rowColor (ruled A on objectui#5435)#11458
os-steve merged 1 commit into
mainfrom
claude/issue-11195-user-actions-three-keys

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#11195

Held for contract review (clause ②) — accept-set widening on a contract schema; needs:contract-review hangs on the card. Draft on purpose; the landing decision is the review's.

What

UserActionsConfigSchema (packages/spec/src/ui/view.zod.ts:853, a strictObject) gains three boolean keys, implementing the ruling recorded on objectui#5435 (maintainer, 2026-08-22, decision-inbox digest, verbatim: 「接受所有」 — Option A):

  • group — default true
  • hideFields — default false
  • rowColor — default false

objectui's normalize-list-view.ts fold maps legacy showGroup / showHideFields / showColor onto exactly these keys, and ListView.tsx honours all three — so before this change the fold's own output was rejected by name at the save gate. The fold-map's own comment calls the three "pending promotion into UserActionsConfigSchema upstream"; this is that promotion, spelled exactly as the fold emits it. No shape or naming fork was forced — the stop-and-report clause on the card was not triggered.

Defaults asymmetry is load-bearing

Copied from the renderer's reads, not chosen here: ListView.tsx computes showGroup as ua?.group !== false (absent = shown) but showHideFields / showColor as === true (absent = hidden). Pinned in view.test.ts with a dedicated test naming those reads; normalising the three to one default would silently flip a toolbar affordance on every view that never wrote the key.

The name collisions, and what the batch20 guard reads on the pair

Both pre-existing spellings stay untouched; each pair is toggle-vs-config, documented on the describes and in the schema docblock:

  • userActions.rowColor (boolean toggle, NEW) vs the list view's own rowColor (RowColorConfigSchema — the colour rules the toggle exposes) and the component-registry rowColor (config, component.zod.ts).
  • userActions.hideFields (boolean toggle, NEW) vs the record-details component's hideFields (string[] of field names to omit, component.zod.ts).

object-strictness-batch20.test.ts readings on the pair, post-adoption:

  • The prose vocabulary enumeration is updated (it had gone false).
  • The no-overlap claim is now re-checked mechanically, not assumed: a new test reads UserActionsConfigSchema.shape (11 keys), asserts the three adopted keys are present, asserts zero overlap with the object block's five verbs (create/import/edit/delete/exportCsv), and asserts the object block still refuses group/hideFields/rowColor by name — the operative half of "disjoint": the wrong-layer write stays a loud rejection, never a silent second meaning.
  • The existing control still holds: object-level userActions: { sort: false } still rejects naming VIEW.

Acceptance criterion (executed on the built dist at 51de14c)

ListViewSchema.safeParse({name:'my_view',label:'My View',columns:[{field:'name'}],
userActions:{group:false,hideFields:true,rowColor:true}}).success === true ✅ observed: true
object-block control rejectOnObject({userActions:{sort:false}}) red, names VIEW ✅ observed: red + VIEW
per-key probes group/hideFields/rowColor through ListViewSchema ✅ all accepted, zero unrecognized_keys
object-side probes group/hideFields/rowColor ✅ all refused by name
defaults on parse of empty object: group=true, hideFields=false, rowColor=false ✅

Bounded in-place fix (declared)

packages/spec/src/data/object.zod.ts guidance comment (the wrong-layer guard's own rationale, lines 1726-1731): its enumeration of the view vocabulary went stale the same way the batch20 comment did — same defect class as pin 1 of the card, comment-only, mechanical (the shape is the evidence), no gate family added. Claim-surface supplement posted on the issue in the same round. No guidance/alias entries were added for the three new keys on the object block — that would be a behavioural extension outside this card; flagged in the report instead.

Verification (all at 51de14c, clean tree; exit codes captured before any pipe)

  • pnpm --filter @objectstack/spec build — VERDICT command-exit 0
  • pnpm --filter @objectstack/spec test — 419 files / 11157 tests passed, VERDICT command-exit 0
  • pnpm --filter @objectstack/spec typecheck — VERDICT command-exit 0 (incl. check:test-typecheck OK line)
  • pnpm --filter @objectstack/spec check:generated — 1 of 14 stale (check:docs); regenerated via --fix; re-run green. Build had already refreshed authorable-surface/ui.json + authorable-defaults/ui.json; generated diff carries exactly the three keys + defaults.
  • Derived families (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, changeset from merge base 5a916c4): 26 derived gate commands run locally, all exit 0 — nul-bytes, changeset-gate-self-tests, objectui-changeset, adr-0087-registration, merge-driver, doc-anchors, doc-authoring, docs-audit-scope, docs-redirects, published-readme-links, quick-reference-counts, role-word, published-files, slot-lookup, spec-parsed-alias, test-source-alias, type-source-resolution, cross-package-test-inputs, engine-double-contract, where-matcher, spec empty-state / liveness / strictness-ledger / variant-docs, lint doc-formula-expressions / doc-security-posture.
  • Declared narrowingcheck:type-check-debt --re-measure (needs the full workspace build closure; exceeds the local foreground cap cold) was NOT run locally; CI runs it. Receipt: population = the 26 ledger entries inside scripts/check-type-check-coverage.mjs itself; @objectstack/spec is not among them (it is COVERED via its own typecheck, run green above); all TS changes in this diff live in packages/spec; ledger packages see the change only through spec's built d.ts, where the delta is purely additive, and UserActionsConfig is referenced by 0 files outside packages/spec (repo grep over ts/tsx/mts excluding node_modules/dist). An additive extension of a type no ledger entry names cannot raise any entry's tsc error count.

Changeset

minor for @objectstack/spec (accept-set widening; not breaking, so no ADR-0087 disposition marker is required and check:adr-0087-registration passes).

Downstream

Unblocks objectui#5435 (fold/renderer test alignment — their seat's follow-up; that card stays open and is additionally held on objectui's spec pin bump, currently at 17.1.0 per objectui#5716). No objectui files touched here.


Generated by Claude Code

#11195)
The three toolbar affordances ListView already honours become authorable:
objectui's normalize-list-view fold maps legacy showGroup/showHideFields/
showColor onto exactly these userActions keys, so the fold's own output now
passes the save gate (ruled Option A on objectui#5435).
Defaults copy the renderer's reads and the asymmetry is load-bearing:
group defaults ON (ua?.group !== false), hideFields/rowColor default OFF
(=== true). Cross-surface name collisions (component hideFields: string[],
view-level rowColor: RowColorConfig) are documented on the describes; the
object-block userActions vocabulary stays disjoint, now re-checked
mechanically in object-strictness-batch20.test.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9cDbY2NBiVJWYx3BpWfH2
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/objects.mdx(via userActions (symbol))
  • content/docs/protocol/objectui/index.mdx(via userActions (symbol))

3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v14.mdx(via userActions (symbol))
  • content/docs/releases/v16.mdx(via userActions (symbol))
  • content/docs/releases/v17.mdx(via userActions (symbol))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 changed file(s) yielded no anchor (packages/spec/authorable-defaults/ui.json, packages/spec/authorable-surface/ui.json) — pages documenting those are invisible to this run
  • the SDK route bridge reached 45 of 222 client-bound route-ledger rows — the other 177 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run: node scripts/docs-audit/affected-docs.mjs --bridge-coverage

Coarse fallback — 126 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 8542bd457765444626023db6ffeb6f8105f7f83epackageMentionDocs.

Which tree this was computed on

This run read content/docs from e2932d5af98fff6b35e525ca3b99e6dfd4c06805 — the merge of head 51de14c509e29254339d5c75bbcde08dfc71523c into base 8542bd457765444626023db6ffeb6f8105f7f83e, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e2932d5af98fff6b35e525ca3b99e6dfd4c06805 && git checkout e2932d5af98fff6b35e525ca3b99e6dfd4c06805
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8542bd457765444626023db6ffeb6f8105f7f83e 51de14c509e29254339d5c75bbcde08dfc71523c && git checkout -B drift-repro 8542bd457765444626023db6ffeb6f8105f7f83e && git merge --no-ff 51de14c509e29254339d5c75bbcde08dfc71523c
node scripts/docs-audit/affected-docs.mjs --json 8542bd457765444626023db6ffeb6f8105f7f83e

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8542bd457765444626023db6ffeb6f8105f7f83e → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@os-steve
os-steve marked this pull request as ready for review August 23, 2026 20:38
@os-steve
os-steve added this pull request to the merge queueAug 23, 2026
Merged via the queue into main with commit b372318Aug 23, 2026
39 checks passed
@os-steve
os-steve deleted the claude/issue-11195-user-actions-three-keys branch August 23, 2026 21:17
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:dataprotocol:uisize/mteststooling

Projects

None yet

2 participants

@os-steve@claude