Repository navigation
docs(skills): the actions rule, its eval and the i18n skill teach an action's disabledReason - #26983
Conversation
…action's `disabledReason`
The `disabledReason` bullet beside `disabled` in objectstack-ui/rules/actions.md
(an I18nLabel, display-only, never a predicate; omitted keeps the console's
default, blank refused, the four near-miss spellings refused naming it, the
reason never in `description`), the key on the ReassignLead example's
`disabled` line, eval case 9 expecting it beside a `disabled` predicate, and
the objectstack-i18n group table row listing it under `_actions.{action_name}`.
Token ratchet: actions.md paid down first by 122 bytes of duplicate code
comments, then 2151 -> 2259 at the measurement; the eval 1789 -> 2009 at the
measurement (0 bytes of duplicate to cut); the i18n SKILL.md row stays.
Claude-Session: https://claude.ai/code/session_01ADHkmTQn7vTBdkhp6FF1Rs
Co-authored-by: Claude <noreply@anthropic.com>
…ontain string
Seat review round 2 on the same file: case 5's expected output says "no
deprecated source view" instead of the refused key, case 8's says a
`${…}` hole fails `os validate` instead of spelling the refused hole.
Every assertion and fact kept; the file is 2 bytes smaller, the row's
2009 ceiling is unchanged and its comment carries the new arithmetic.
Claude-Session: https://claude.ai/code/session_01ADHkmTQn7vTBdkhp6FF1Rs
Co-authored-by: Claude <noreply@anthropic.com>
席位核对ACCEPT ·
|
Contract reviewServed-tier: Director seat (summon #52, ledger objectstack#12708), summoned by the ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS Generated by Claude Code |
Requested by Steve · project thread
Fixes #26790
Clause-②: no
Metadata-protocol: none
维护者速读
skills/objectstack-ui/rules/actions.md在disabled旁加一条disabledReason(I18nLabel,只做显示:灰掉的按钮悬停标题与无障碍描述;不是谓词、不是门,拒绝仍由 hook 或权限做;不写则用控制台默认句 "Not available for this record";空串拒收,disabledMessage/disabledTooltip/disabledHint/disabledText四个近似拼法拒收并点名正键;理由不写进description),ReassignLead 示例在disabled行旁带上该键。eval 文件加第 9 题:要求disabledReason与disabled谓词并列,禁止理由落进description。skills/objectstack-i18n/SKILL.md分组表_actions.{action_name}行(同样适用于globalActions.{action_name})在confirmText/successMessage旁列出disabledReason。两行 token 棘轮按裁决 A 处理;@objectstack/skills补丁 changeset。disabledReasonbesidedisabled#26786 把ActionSchema.disabledReason加进协议,卡 skills(objectstack-ui, objectstack-i18n): the actions rule and the i18n skill do not teach an action's disabledReason (follow-up owed by #26619) #26790 是它欠下的Skills-docs:后续——AI 作者照技能写 action 时不知道这把键,要么留着通用默认句,要么把理由塞进description。skills/objectstack-ui/rules/actions.md(L20 新条目、L43–44 示例、删掉的两条重复代码注释)、skills/objectstack-ui/evals/views-apps-actions-pages.json(第 9 题)、scripts/check-skills-token-ratchet.mjs(两行:2151 → 2259、1789 → 2009,算式在注释里)。node scripts/check-skills-token-ratchet.mjs,预期rules/actions.md✓ 2259/2259、views-apps-actions-pages.json✓ 2009/2009、objectstack-i18n/SKILL.md✓ 5485/6333,总行82 authored bundle file(s) within their ceilings。skills/**受管面,Tier H)。What changes
Every key and sentence below is read off
packages/spec/src/ui/action.zod.tsonorigin/main4b8f8cdc(thedisabledReasondocblock L892–911, the blank refusal L913–919, the four aliases L954–955, the.describe()L1586) and the console rendererui/packages/components/src/renderers/action/disabled-reason.tsxL88 (the default sentence); nothing is invented.skills/objectstack-ui/rules/actions.md(the rule an AI author of actions reads):disabled:disabledReasonis an I18nLabel (a plain sentence or an inline locale map) a greyed action shows as its hover title and accessible description; display-only, never a predicate and never a gate (the hook or permission still refuses); omitted keeps the console's default "Not available for this record"; a blank one is refused;disabledMessage/disabledTooltip/disabledHint/disabledTextare refused naming the key; the reason goes here, not indescription;disabledReasonon the line afterdisabled, so the pair is shown once in code.// Greys out (stays visible) once the lead is converted:(home: thedisabledbullet, "shows but greys out … stay discoverable") and// success toast offers Undo; Ctrl+Z works too(home: theundoablebullet, "an Undo in the success toast (and Ctrl+Z)"). The example's keys are unchanged.skills/objectstack-ui/evals/views-apps-actions-pages.json: case 9 asks for an Approve action oncontractthat stays visible but greyed untillegal_review_statusisapproved, with the rep told why; expectsdisabled: P\record.legal_review_status != "approved"`besidedisabledReason: '…', display-only, the reason not indescription, omitted = the default, blank and near-miss spellings refused.must_containdisabled:/disabledReason;must_not_containdescription:/disabledMessage/disabledTooltip/visible:(hiding instead of greying). Nomust_not_containstring occurs in itsexpected_output; everymust_contain` string does. The file's cases share no sentence, so 0 bytes of duplicate were available to cut.skills/objectstack-i18n/SKILL.md: the_actions.{action_name}group-table row listsdisabledReason(the sentence a greyed action shows; absent keeps the console's default) betweensuccessMessageandparams.{param_name}; the row's closing clause already says the same keys hold underglobalActions.{action_name}, so that slot is covered by the same edit. The file had headroom, so its ratchet row does not move.scripts/check-skills-token-ratchet.mjs:rules/actions.md2151 → 2259 and the eval 1789 → 2009, each pinned AT the measurement with the arithmetic and the standing ruling quoted verbatim beside the sibling rows..changeset/26790-actions-disabled-reason-skills.md:@objectstack/skillspatch, both declaration lines at line start.Skills readings (
skills/**touched; before =origin/main4b8f8cdc, after = head; tokens = the ratchet'sceil(bytes/4), release-stamp line excluded):skills/objectstack-ui/rules/actions.mdlines / bytes / tokensskills/objectstack-ui/evals/views-apps-actions-pages.jsonlines / bytes / tokensskills/objectstack-i18n/SKILL.mdlines / bytes / tokensSKILL.mdlines / tokens (whole package, 11 files, ratchet table sum)Why
A record action greyed by
disabledcan now say why through a translatabledisabledReason(PR #26786, #26619 ruling A); the console's hover title and accessible description read it and "Not available for this record" stays the default when it is absent. An agent authoring an action from the published skill was not told the key exists and would leave the generic sentence in place or put the reason intodescription, the workaround the card names. The skills lane owes thisSkills-docs:follow-up becauseskills/**is Tier H and stayed out of the spec PR.Tests
node scripts/check-skills-token-ratchet.mjsat head:82 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted, exit 0;rules/actions.md✓ 2259 / 2259 (headroom 0),views-apps-actions-pages.json✓ 2009 / 2009 (headroom 0),objectstack-i18n/SKILL.md✓ 5485 / 6333 (headroom 848).node scripts/check-skills-token-ratchet.mjs --self-test:79 cases pass, exit 0.JSON.parse); case 9 has nomust_not_containstring in itsexpected_outputand everymust_containstring in it.Acceptance notes
check:skill-docs/check:skill-refs/check:skill-examplesreadSKILL.md,references/and the marked code fences). The ReassignLead fence carriesos:check, socheck:skill-examplescompiles the newdisabledReasonkey against the spec that now declares it.must_not_containstring (sourceView,${record.name}) insideexpected_output; round 2 (head 4092ea0) rewords both ("no deprecated source view", "a${…}hole failsos validate"), assertions unchanged, 8036 → 8034 bytes, same 2009-token ceiling. Per-case cross-check over all 9 cases: 0 failures (seat claim amendment 6456927584).examples/app-todo, whosecompleteaction declares nodisabledReason, so no example row was invented; the group-table row is the teaching.Verification
node scripts/pm/dispatch-gates.mjs --tier --repo objectstack-ai/objectstack:Model tier — MANDATORY(derived from the file surface:skills/**carries no one-line exemption, clause ① — the card isClause-②: no); changed lines 49 (+44 / −5, 5 files) vs the 3000 threshold.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat headd42ad5dc(the only commit) derived 63 commands. All 63 ran in the worktree after that commit, each asbash -c CMDwith stdin from /dev/null and its exit code captured before any pipe and recorded asCMD :: exit N: 63 of 63 exit 0 — 55 source-reading commands in one serial runner while the build held the lock, the 8 dist-reading ones (pnpm --filter @objectstack/lint run check:doc-formula-expressions,pnpm --filter @objectstack/spec run check:skill-docs,check:dts-closure,check:dual-build-cjs-loads,check:entry-guard,check:lean-entry-closure,check:published-files,check:sourcemap-no-sources-content) after it. Among the 55:node scripts/check-skills-token-ratchet.mjsand its--self-test,node scripts/check-empty-changeset.mjs --base origin/main,node scripts/check-adr-0087-registration.mjs --base origin/main,node scripts/check-changeset-no-major.mjs --base origin/main,pnpm check:pm-dispatch-gates,pnpm check:pm-governed-merges,pnpm check:pm-skill-id-lint,pnpm check:doc-authoring,pnpm check:ratchet-remedy-authority,pnpm check:skill-compatibility,pnpm check:skill-frame-sync,pnpm check:skill-identifier-liveness,pnpm check:nul-bytes.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RANFILE:63 derived famil(ies) accounted for — 63 run, 0 NOT-MEASURED (a DERIVED zero — all 63 recorded an exit code and none of them is 3), exit 0; no UNRUN family named on stderr.turbo run build --filter='./packages/**' --concurrency=2underscripts/pm/os-verify-lock.sh:VERDICT command-exit 0 · held the lock 408s (6m48s), 75 tasks, 0 cached.pnpm --filter @objectstack/spec run check:skill-examples(compiles the ReassignLeados:checkfence with its newdisabledReasonkey against the built spec) andpnpm --filter @objectstack/spec run check:skill-refs(9 generated files in sync with packages/spec).test/typecheckis owed; the edited gate script's own suite is its--self-test(79 cases);pnpm lintis CI's run.Human Minimum
packages/specholds no runtime logic. (No schema touched.)pnpm lintpasses (the repo-wide run is CI's; no source file edited).main, one pull request.packages/spectouched: n/a, not touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01ADHkmTQn7vTBdkhp6FF1Rs
Generated by Claude Code