Uh oh!
There was an error while loading. Please reload this page.
docs(spec): narrow the expression-bindable button row to the spelling its key reaches - #14321
Merged
os-zhuang merged 1 commit intoSep 2, 2026
Merged
Conversation
…ng its key reaches `EXPRESSION_BINDABLE_TEXT_KEYS_BY_COMPONENT` is keyed on the component type string exactly as authored, and `expressionBindableTextKeysFor` does an own-property lookup on it. The `button` row's evidence citation named `action/action-button.tsx`, which registers under `action:button` — a different key, with no row, answering the empty set. The citation therefore promised coverage the lookup cannot deliver. The machine face does not move: the map, the lookup and every export are unchanged, and `check:api-surface` is green against a fresh build. This is the protocol prose catching up with its own evidence table. - `button` row cites `form/button.tsx` alone. - New docblock section: the table is keyed on the authored type string, so namespace-prefixed spellings (`action:button`, `ui:button`, the `mcp:` family) answer the empty set BY CONSTRUCTION — and prefix-stripping is the wrong repair, since it would also grant rows to `element:button` and `page:card`, whose renderers read config out of the evaluated `properties` bag and never touch these keys at the node's top level. - `action:button` and `ui:button` recorded as deliberately out on the two measured grounds (zero corpus pull; the module's own admission rule), with the ordinary reopen path. - The test file carried the same retracted citation in a comment; corrected, and the namespaced spellings are now pinned to the empty set so a later prefix-stripping change cannot move the machine face in silence. - Reference page regenerated by `gen:docs`, never hand-edited. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 2, 2026
os-zhuang
marked this pull request as ready for review
September 2, 2026 02:30
os-zhuang
enabled auto-merge
September 2, 2026 02:30
Uh oh!
There was an error while loading. Please reload this page.
os-zhuang
deleted the
claude/issue-13672-bindable-keys-docblock-narrowing
branch
September 2, 2026 02:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#13672
Ruled outcome: option 3 — docblock narrowing (ruling comment 5479231731, director seat, maintainer verbatim, 2026-08-31). The machine face does not move.
What was wrong
EXPRESSION_BINDABLE_TEXT_KEYS_BY_COMPONENTis keyed on the component type string exactly as authored, andexpressionBindableTextKeysFordoes an own-property lookup on it. Thebuttonrow's evidence citation named two objectui renderers:but
action/action-button.tsxregisters underaction:button— a different key, with no row, answering the empty set. The citation promised coverage the lookup cannot deliver. The defect is a contradiction inside the protocol prose, not a fault in the lookup: precise own-property lookup on the authored string, with no row meaning the empty set, is the contract working as designed.What changed — prose only
buttonrow now citesform/button.tsxalone.action:button,ui:button, themcp:family) is a different key from the bare name and answers the empty set by construction, not by oversight. It also records why prefix-stripping is the wrong repair — it would in the same motion grant rows toelement:buttonandpage:card, whose renderers take config from the evaluatedpropertiesbag and never read these keys at the node's top level.action:buttonandui:buttonare recorded as deliberately out on the two measured grounds the ruling named: zero pull (objectui corpus census of 736 JSON documents / 2747 typed nodes — 5action:buttonnodes, 0 of them carrying an expression inlabel, and 0ui:-prefixed spellings of any kind), and this module's own admission rule that a row arrives with its own measurement while a type string with no row IS the empty set.action:buttonlabel adds a row here, carrying that row's own measurement.On the reasoning the ruling struck down: it rejected the semantic claim carried by the earlier triage recommendation, because
action/action-button.tsxrenders the author-writtenschema.labeldirectly. That reasoning appears nowhere in this diff, in any wording. The docblock records the affirmative measurement in its place — the read-back half is real, and only the pull is missing.The test file — a bounded in-place fix, declared with its evidence
packages/spec/src/ui/expression-bindable-text-keys.test.tscarried the same retracted citation in the comment above its carriage assertion (line 62: "form/button.tsx (and action/action-button.tsx) read schema.label"). Same defect class as item 1, correct form fixed by the ruling itself, no other claim on the file, same gate family — so it was corrected in the same motion rather than left standing as the surviving copy of a citation the docblock had just retracted. It was declared in the claim comment's file surface before the first edit, not discovered after the fact. Scan that bounded it, measured at the base commita39b02a6:git grep -n "action-button.tsx" a39b02a6 -- packages/spec/srcreturns exactly two hits — the docblock row (.zod.ts:58) and this comment (.test.ts:62). Both are in this diff, and nothing else in the spec sources carried the citation. Two further hits exist elsewhere underpackages/specand are deliberately untouched:liveness/action.json(evidence strings for unrelatedactionproperties) andCHANGELOG.md(shipped release history).The same file now pins that the machine face did not move.
action:buttonandui:buttonjoined the empty-set loop, so a later prefix-stripping "fix" cannot move the lookup in silence:expressionBindableTextKeysFor('button')still yields['label']— pin already present, unchanged.expressionBindableTextKeysFor('action:button')still yields[]— pin added.Clause-②: no
The path limb trips (
packages/spec/src/**); the content limb does not. No accept or reject behaviour changes and no public surface widens or narrows —check:api-surfaceis green against a fresh build, and the map, the lookup function and every export are byte-identical.needs:contract-reviewis hung on this PR and on the card for the path limb.content/docs/references/ui/expression-bindable-text-keys.mdxis the generated projection of this docblock, regenerated bypnpm --filter @objectstack/spec check:generated --fix(which proved it the only stale artifact of 15 and rangen:docsalone). Never hand-edited.A
patchchangeset is included because the prose is consumer-visible:packages/spec's publishedfilescarries bothdistandsrc/**/*.zod.ts, and the edited docblock is present indist/ui/index.d.ts.Verification — every reading below taken on head
2925aea7pnpm --filter '@objectstack/spec^...' buildthenpnpm --filter @objectstack/spec build34/34declaration files emittedpnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui/expression-bindable-text-keys.test.tsTest Files 1 passed (1)·Tests 9 passed (9)pnpm --filter @objectstack/spec typechecktsc --noEmit,check:scripts-typecheck,check:test-typecheck("OK — @objectstack/spec's test layer compiles under packages/spec/tsconfig.test.json")tsc --listFileson both projects.zod.tsfile is intsconfig.json's program and the.test.tsfile is intsconfig.test.json's — 1 hit each, so the green is not a green over files nothing readpnpm --filter @objectstack/spec check:generated15 of 15current after the regeneration;check:api-surfaceandcheck:docsboth greennode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths — it reads its own change set from the merge base)pnpm check:nul-bytespnpm lint(eslint . --no-inline-config)The 6 commands recorded as PREREQUISITE NOT MET rather than green or red, each on its own printed verdict line, all rooted in this container having only a partial workspace build:
check-dev-prereqs("the workspace is not built"),check-test-completeness(exit 3 — grades a savedturbo run testlog, and the family names it with no argument),check:doc-formula-expressionsandcheck:doc-security-posture(exit 3),check:dual-build-cjs-loads(exit 3 — "reads built output, and some package has no dist/"),check:type-check-debt(exit 3). None of them reads any of the four changed paths.check:skill-exampleswas initially in this group and was converted to a real green by building the@objectstack/client-reactclosure and re-running it: 259 marked examples across 3 surfaces type-check, including the 9 spec-source-TSDoc blocks that are this diff's own surface.scripts/pm/check-half-states.mjsinvoked bare timed out on proxy configuration; its real family commandpnpm check:pm-half-statesran green.Every gate exit code above was captured before any pipe (
cmd > log 2>&1; rc=$?), and each verdict is quoted from the gate's own output rather than from a bare$?.Not done, deliberately
Draft, base
main. Not flipped ready, no auto-merge, not enqueued.🤖 Generated with Claude Code
https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
Generated by Claude Code
Generated by Claude Code