Repository navigation
fix(spec)!: action:icon and the action:group / action:menu members refuse confirmText beside a non-empty array params, as action:button does - #30624
Conversation
…ext beside a non-empty array params The fourth and fifth doors of the confirmText + params pair refusal, with action:button's predicate and message (declaresConfirmBesideParams, CONFIRM_BESIDE_PARAMS_REFUSAL). Both blocks forward confirmText and an array params (as actionParams) to the same runner, which opens the confirm and then the param dialog. Still accepted: no params, params: [], and an object params (an icon's static values; an api member's payload). Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
…escribe lines Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
…pe confirmText form Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
…nfirm-beside-params-icon-members Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 8 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4fdac8501027eb012d47a4cc0af01eb3f2bc5e66 && git checkout 4fdac8501027eb012d47a4cc0af01eb3f2bc5e66
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin aad1603cc2180b3eefa8cee41f5b895b8ee45909 9d69f747cd545a5e11690329ea16436a77d8a49a && git checkout -B drift-repro aad1603cc2180b3eefa8cee41f5b895b8ee45909 && git merge --no-ff 9d69f747cd545a5e11690329ea16436a77d8a49a
node scripts/docs-audit/affected-docs.mjs --json aad1603cc2180b3eefa8cee41f5b895b8ee45909
|
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Contract reviewServed-tier: Inputs read: card #30017 body and its four comments (ruling 6624208841 letter A, triage 6624670416, claim 6663933383, os-dev-report 6665968613); PR #30624 body, its five-file list and the net diff of ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
The narrowing against the published spec on Implemented-by: VERDICT: FAIL Generated by Claude Code |
…efusal as a step-18 D3 entry One SemanticMigration naming all four page action rows (action:button, action:icon, each action:group / action:menu member); the changeset's ADR-0087 marker becomes registered. The shared predicate module's docblock now counts the five doors that read it. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Contract reviewServed-tier: Re-review after FAIL 6666209629 on ① Derived judgments
② Semver level
③ Boundary flagsFindings of the previous record 6666209629, each against head
Dev flags, both reports:
④ Design judgment
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P 维护者速读
席位核对ACCEPT · head
Generated by Claude Code |
Requested by Sales · project thread
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
Fixes #30017
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: none — no
skills/**file teaches anaction:icon, or anaction:group/action:menumember, carryingconfirmTextbeside an arrayparams(git grepofskills/foraction:icon|action:group|action:menu: 0 hits). The one rule line about the pair (skills/objectstack-ui/rules/actions.mdL22, "A registered action is refused it beside a non-emptyparams(put the question ondescription)") stays true and names the remedy this refusal prescribes. The generatedcontent/docs/references/ui/component.mdxrows that render the threeconfirmTextdescribes are regenerated here.BREAKING accept-set narrowing at
ActionIconPropsSchemaand theaction:group/action:menumember rows (@objectstack/spec), served where a page's componentpropertiesare judged: the component-props gate (component-props-invalid,@objectstack/lint) at every CLI command and at the runtimepagesave door.维护者速读
action:icon,以及action:group/action:menu里的每个成员,同时写confirmText和非空数组params时,现在和action:button、已注册动作、内联动作一样被拒收,提示把这句话挪到description、删掉confirmText。params、params: []、对象形params(图标的静态值;type: 'api'成员的请求体,都不弹参数框)照常通过。已存页面照常加载,下次保存才被拒。回滚即 revert 本 PR。packages/spec/src/ui/component.zod.ts(ActionIconPropsSchema链尾与buildActionGroupMember/buildActionMenuMember链尾新增的.refine),packages/spec/src/ui/action-confirm-params-guard.test.ts末尾新的 describe 组,packages/spec/src/ui/component-report-items-action-members-typed.pin.test.ts改过的夹具。pnpm --filter @objectstack/spec exec vitest run src/ui/action-confirm-params-guard.test.ts,预期 29 个测试全过,其中新组 8 条(5 条拒收、3 条对照)。What changes
ActionIconPropsSchemagains.refine((data) => !declaresConfirmBesideParams(data), CONFIRM_BESIDE_PARAMS_REFUSAL)at the end of its chain, exactly asActionButtonPropsSchemacarries it. Theaction:groupandaction:menumembers each gain the same refine at the end of their builder's chain (buildActionGroupMember,buildActionMenuMember, the two consumers ofactionContainerMemberShape()), so the issue lands on the member, atactions.N.confirmText. No second predicate or message: both are imported frompackages/spec/src/ui/action-confirm-beside-params.ts, whose predicate and message are unchanged (the shared message needed no member-path variant: its remedy key,description, is declared on the icon and on both members); only its docblock now counts the five doors that read it.Array.isArray(params) && params.length > 0read refuses a non-empty array and leavesparams: []and an objectparamsalone: onaction:iconan object is the static parameter values, on a member it is atype: 'api'member's request payload (a non-apimember's objectparamsstays refused byactionContainerMemberParamsFitType, unchanged).confirmTextdescribes ofaction:iconand of the container member shape now append the sentenceaction:button's carries: refused beside a non-empty arrayparams, correct with noparams, besideparams: []and beside an objectparams(the member's wording names thetype: 'api'payload).content/docs/references/ui/component.mdxis regenerated from them (check:generated --fix, which proved onlycheck:docsstale).component-report-items-action-members-typed.pin.test.ts§1 "a member with every forwarded scalar" (action:menu) carriedconfirmTextbeside an arrayparams; itsparamsmoves to a new byte-identical case, "a member collecting params", which carries the question ondescription..changeset/30017-action-icon-members-confirm-beside-params-refused.md:@objectstack/specminor, both declaration lines, the ADR-0087 disposition marker (registered), the narrowing banner, before / now / unchanged / who, and the one-line fix naming the D3 entry.packages/spec/src/migrations/entries/semantic/18.ui-page-action-row-confirm-text-beside-params-refused.ts(added in the patch round, head9d69f747cd): oneSemanticMigrationnaming all four page action rows (properties.confirmTextbeside a non-empty arrayproperties.paramson anaction:button/action:icon, andconfirmTextbeside a non-empty arrayparamson eachaction:group/action:menumember), replacement ondescription, NOT mechanically convertible, acceptance asos validatereporting nocomponent-props-invalidat those paths. It also covers theaction:buttonrefusal PR fix(spec)!: anaction:buttonrefusesconfirmTextbeside a non-empty arrayparams, as the two action doors do #29869 shipped without an entry.ADR-0087 disposition
The changeset body carries the ADR-0087 marker comment with the disposition
adr-0087: registered ui-page-action-row-confirm-text-beside-params-refused(patch round, after contract review 6666209629: the refusal prescribes a hand rewrite, so ADR-0087 D3 owes an entry rather than an exemption).node scripts/check-adr-0087-registration.mjs --base origin/mainexits 0 and reads it asregistered, the id new in this diff. Nodocs/adr/**path is touched. The first head carriednot-required (no-migration-prescription); that marker is gone.Verification
All readings at head
0446795a12(the branch merged withorigin/main5b748dfede) unless a line says otherwise; the patch-round readings at head9d69f747cdare in the os-dev-report patch-round comment on the card; the implementation commits are0c6f39767c,73fb6b963e(regenerated reference),34eb15a15d(envelope pin).Census at the base (
origin/main2ffdb649)*.ts/*.tsx/*.js/*.mjs/*.cjs/*.mts(nodist/, no.d.ts): 213 files containconfirmText; every object literal carrying bothconfirmTextand aparamsthat is not an empty array or an object literal was listed with the nearest enclosingtype/actionTypeand the nearest enclosing array or call naming anaction:icon/action:group/action:menuliteral (the tuple-shaped fixtures). 48 such literals; 4 inside an action-block context, each read by hand:packages/spec/src/ui/component-report-items-action-members-typed.pin.test.tsL217: anaction:menumember (type: 'api') withconfirmTextbesideparams: [{ name: 'reason', … }]. The one carrier; a test fixture, repaired here (above).packages/lint/src/validate-action-copy-templates.test.tsL131: anaction:buttonfixture (theaction:groupliteral is a later array element); it feeds the copy-template rule, which does not parse these rows; the lint suite runs it green.packages/spec/src/ui/action.zod.tsL1156 andcomponent.zod.tsL4138: schema declarations, not carriers.*.json/*.yaml/*.yml/*.md/*.mdxnaming bothconfirmTextand one of the three blocks (CHANGELOG.md, generated references,json-schema/,api-surface,sdui.manifest.jsonexcluded):content/docs/frontend/layout.mdx,content/docs/protocol/objectui/actions.mdx,content/docs/ui/components/action.mdx,packages/spec/liveness/action.json; each read by hand — prose and key tables, no example carrying the pair.Before / after at the authoring door
validateComponentProps(@objectstack/lintsrc against this branch's specdist), one page per case:action:iconwithconfirmText+ arrayparamscomponent-props-invalid·error·…components[0].properties.confirmText· "confirmText: An action that declaresconfirmTextbeside a non-emptyparamsshows the u…"action:groupmember, same paircomponent-props-invalid·error·…components[0].properties.actions.0.confirmTextaction:menumember, same paircomponent-props-invalid·error·…components[0].properties.actions.0.confirmTextparams+description(the remedy)confirmText+params: []type: 'api'menu member,confirmText+ objectparamsaction:icon,confirmText, noparamsBefore: the ablation below is the base's behaviour for these three rows (the refine is the only change on them), and it parses the pair clean.
Pins (
packages/spec/src/ui/action-confirm-params-guard.test.ts, new top-level describe)action:icon— one issue,code: 'custom',path: ['confirmText'], messagetoBeaction:button's issue for the same pair, and containsTWO dialogs,`description`andparam-LESS;action:groupandaction:menumembers — one issue,code: 'custom',path: ['actions', 1, 'confirmText'](the second member), messagetoBeaction:button's; and each member on the template-envelopeconfirmTextform,[['custom', 'actions.1.confirmText']].action:iconand each container member acceptconfirmTextwith noparams, besideparams: [], beside an objectparams(type: 'api'on the members), and the remedy (arrayparams+description), each a fullsafeParsesuccess.Ablation (committed state,
node scripts/ablation-replace.mjs, test source read fromsrc/)three legs, each red then restored
ActionIconPropsSchema3eec6db7ac20→ff6c2420ddbbaction:iconrefusalgit diff HEADemptybuildActionGroupMembere77714c1e61dgit diff HEADemptybuildActionMenuMemberaeb719fd841fgit diff HEADemptyAfter the three legs, from the committed state: 29 / 29 passed. A first member run whose replacement text was a substring of its anchor was refused by the tool before running (replacement count 1 → 1), restored, and rerun with a distinct replacement; it is not counted above.
Tests
pnpm --filter @objectstack/spec test(merged head)pnpm --filter @objectstack/spec typecheck(merged head)pnpm --filter @objectstack/lint exec vitest run(head34eb15a15d, lint closure built)pnpm --filter @object-ui/types test(head34eb15a15d)@object-ui/componentsspec-symbol-action-renderer-props-11073.test.ts+src/renderers/action/(head34eb15a15d)pnpm --filter @objectstack/dogfood test(head34eb15a15d, closure built)npx eslint --no-inline-configon the three changed.tsfilesGates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives the same 102 families at34eb15a15dand at0446795a12. Exit codes are captured before any pipe.gate table, head 0446795 (102 families, exit codes)
node scripts/check-adr-0087-registration.mjs --base origin/mainnode scripts/check-adr-0087-registration.mjs --self-testnode scripts/check-adr-links.mjsnode scripts/check-adr-links.mjs --self-testnode scripts/check-changeset-no-major.mjs --base origin/mainnode scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-comment-mask-adoption.mjsnode scripts/check-comment-mask-adoption.mjs --self-testnode scripts/check-comment-mask-corpus.mjsnode scripts/check-dev-prereqs.mjs --self-testnode scripts/check-doc-route-spelling.mjs --advisorynode scripts/check-doc-route-spelling.mjs --self-testnode scripts/check-docs-section-name.mjsnode scripts/check-docs-section-name.mjs --self-testnode scripts/check-dts-emitted.mjs --self-testnode scripts/check-empty-changeset.mjs --base origin/mainnode scripts/check-empty-changeset.mjs --self-testnode scripts/check-issue-citations.mjsnode scripts/check-plugin-teardown-shape.mjsnode scripts/check-plugin-teardown-shape.mjs --self-testnode scripts/check-section-landing-index.mjsnode scripts/check-section-landing-index.mjs --self-testnode scripts/ci/assert-turbo-remote-cache.mjs --self-testnode scripts/ci/plan-test-core-shards.mjs --self-testnode scripts/ci/prune-turbo-cache.mjs --self-testnode scripts/docs-audit/check-affected-docs.mjsnode scripts/docs-audit/check-drift-comment.mjsnode scripts/pm/release-rehearsal-clone.mjs --self-testnode scripts/release-pending-publish.mjs --self-testpnpm --filter @objectstack/lint run check:doc-formula-expressionspnpm --filter @objectstack/lint run check:doc-security-posturepnpm --filter @objectstack/spec run check:api-surfacepnpm --filter @objectstack/spec run check:authorable-surfacepnpm --filter @objectstack/spec run check:browser-reachable-entriespnpm --filter @objectstack/spec run check:docspnpm --filter @objectstack/spec run check:dual-source-exportspnpm --filter @objectstack/spec run check:duration-unit-keyspnpm --filter @objectstack/spec run check:empty-statepnpm --filter @objectstack/spec run check:entry-nameabilitypnpm --filter @objectstack/spec run check:export-originspnpm --filter @objectstack/spec run check:exported-anypnpm --filter @objectstack/spec run check:generatedpnpm --filter @objectstack/spec run check:livenesspnpm --filter @objectstack/spec run check:llms-txtpnpm --filter @objectstack/spec run check:skill-examplespnpm --filter @objectstack/spec run check:skill-refspnpm --filter @objectstack/spec run check:strictness-ledgerpnpm --filter @objectstack/spec run check:variant-docspnpm --filter @objectstack/spec run check:yaml-examplespnpm check:changeset-gate-self-testspnpm check:ci-filter-paritypnpm check:closed-ceremony-textpnpm check:corpus-claim-driftpnpm check:cross-package-test-inputspnpm check:dispatcher-error-vocabularypnpm check:doc-anchorspnpm check:doc-authoringpnpm check:doc-frontmatterpnpm check:docs-audit-scopepnpm check:docs-redirectspnpm check:docs-single-h1pnpm check:docs-spec-enumerationspnpm check:docs-transcript-driftpnpm check:driver-memory-censuspnpm check:dts-closurepnpm check:dual-build-cjs-loadspnpm check:engine-double-contractpnpm check:gitlink-declaredpnpm check:issue-citationspnpm check:keyed-text-boundspnpm check:lean-entry-closurepnpm check:logger-receiver-detachpnpm check:merge-driverpnpm check:nul-bytespnpm check:objectql-double-limitpnpm check:org-identifierpnpm check:page-declaration-shapepnpm check:platform-object-tenancy-censuspnpm check:pm-prior-rulingspnpm check:published-filespnpm check:published-readme-linkspnpm check:query-options-erasurepnpm check:react-page-adapter-contractpnpm check:refd-timer-probepnpm check:registry-log-declaredpnpm check:rest-log-spy-declaredpnpm check:role-wordpnpm check:skill-identifier-livenesspnpm check:slot-lookuppnpm check:sourcemap-no-sources-contentpnpm check:spec-docblock-symbol-anchorspnpm check:spec-parsed-aliaspnpm check:system-context-censuspnpm check:test-source-aliaspnpm check:tier-file-adoptionpnpm check:type-check-coveragepnpm check:type-check-debtpnpm check:undeclared-dep-importspnpm check:vendor-version-stampspnpm check:watch-hint-literalpnpm check:where-matchernode scripts/pm/dispatch-gates.mjs --ranon this record: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero: all 102 lines carry an exit code). Also run:pnpm check:adr-0087-registration0,pnpm check:doc-authoring0,pnpm check:skill-frame-freshness0,pnpm check:dev-prereqs1 (see Acceptance notes).Acceptance notes
descriptionremedy on anaction:icon. With nolabel, an icon'sdescriptionis also its tooltip text, so moving the confirm sentence there changes the tooltip too. The changeset's remedy says so; the shared message is unchanged.check:dev-prereqs(local-only family) exits 1 in this worktree: 35ui/workspace packages have nodist/because no fullpnpm buildran here. It judges whether this checkout can boot a dev server, not this diff.🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P