Repository navigation
Commit 13aea18
docs(skills): objectstack-ui action examples and the SKILL.md action rows follow the ActionSchema refinements (#22184)
Fixes #22176
Clause-②: no
The published objectstack-ui skill taught action shapes that
`ActionSchema` refuses; `defineAction` is `ActionSchema.parse`, so
copying either `rules/actions.md` example threw at module load, and two
`SKILL.md` rows taught the same refused shape in prose (a `modal` that
executes a `body`). This PR changes the two example blocks (plus the one
eval sentence that quoted the first) so both parse, and rewords the two
`SKILL.md` rows so each states a shape the schema accepts — the smallest
prose change that leaves no sentence beside a block, or in a table,
false. Draft on a Tier H surface (`skills/**`): it lands on an
authorized APPROVED review or the maintainer's hand; no seat readies it.
## What changed (one rule file, one eval sentence, two `SKILL.md` rows)
1. **"Modal-typed action (collect params, then execute server body)"** —
the block authored `type: 'modal'` + `target` + `params` + `body`. The
schema's refinement refuses a `body` on any non-script action ("a
non-script action dispatches on `target` and silently ignores its body.
To collect `params` and then run the body, use `type: 'script'`"). The
lesson is the body, so the block is now `type: 'script'`, the heading
moves with it ("Script-typed action"), and the `target` line goes (a
script with an inline `body` has nothing for `target` to name).
`params`, `body`, `locations: ['list_toolbar']` and the `ctx` section
under it are unchanged. The eval sentence that described the bulk action
as `type: 'modal'` beside a `body` now says `type: 'script'`; its
`must_contain` list is untouched.
2. **`opensInNewTab` + `newTabUrl` example** — the block authored `type:
'url'` with no `target`; the first refinement requires `target` for
`url`. The block is now `type: 'script'` + `target: 'open_invoice_pdf'`
(see the re-route below); `opensInNewTab`, `newTabUrl` and `locations`
are unchanged.
3. One comment deleted from block 1 (`// Field-backed params resolve
label/type/options from object metadata:`) — it restates the "Action
Parameter Patterns" paragraph in the same file and pays the token
ratchet for the added `target` line (the file sat 4 bytes under its
ceiling).
4. **`SKILL.md`, two rows (patch round, same family).** The Action Types
table row for `modal` read "Open a dialog (typically collecting
`params`, then executing `body`)" and the CRM blueprint row sent
parameterized bulk mutations to `modal` — the shape the refinement
refuses and this PR removes from `rules/actions.md`. The table row now
reads "Open the page named by `target`; a `body` runs only on `script`"
— the schema's own words (`target` is "the modal/page name to open"; the
refinement message says "keep `type: 'modal'` with `target` naming the
page") and what the renderer does (objectui's modal executor opens
`action.target` as the dialog schema). The blueprint row now sends
parameterized bulk mutations to `script`, the lesson of the
"Script-typed action" block. The required-field column, the column
widths and every other row are unchanged; no eval states the shape
(`modal` and `dialog` have zero hits under `evals/`).
## Positive control (measured, both legs)
A one-off node probe parses the two fenced blocks AS WRITTEN ON DISK
against the built `packages/spec/dist/ui/index.mjs` (build-input-hash
`e5e882202edc406c`, built under the verify lock on this tree, rebuilt
and re-measured on the patch-round head):
| block | before (`959c209d56`) | after (`eb522522f2`; re-measured
byte-identical on `28a140bb45`) |
|---|---|---|
| `AddToCampaignAction` | `safeParse.success: false`, issue path `body`,
`defineAction` throws | `success: true`, no issues, no throw |
| `OpenInvoicePdfAction` | `safeParse.success: false`, issue path
`target`, `defineAction` throws | `success: true`, no issues, no throw |
Before-leg messages, verbatim: "`body` only runs for `type: 'script'` —
a non-script action dispatches on `target` and silently ignores its
body. To collect `params` and then run the body, use `type: 'script'`;
to open a page/modal, drop the `body` and keep `type: 'modal'` with
`target` naming the page." and "Action 'target' is required when type is
'url', 'flow', 'modal', 'api', or 'form'."
## Dispatch assumption 3 — measured, falsified, re-routed
The order assumed the second block's repair is "keep `type: 'url'`, add
`target`". Measured on the sibling renderer (objectui checkout
`9990f9e`):
- `ActionRunner.builtinExecutors.url` goes to `executeUrl`, which reads
`action.target || action.redirect` and navigates; it never consults
`opensInNewTab` or `newTabUrl`
(`packages/core/src/actions/ActionRunner.ts`).
- `newTabUrl` is read in exactly one place — the console server-action
wrapper, behind `action.opensInNewTab && newTabUrl`
(`packages/app-shell/src/utils/consoleServerAction.ts`), and that
wrapper is bound as the `script` handler (`useConsoleActionRuntime.tsx`
and `RecordDetailView.tsx`: `script: serverActionHandler`). The spec's
own refinement comment on the `newTabUrl` pair says the same: no other
path reads the key at all.
- Every producer and pin pairs the key with `type: 'script'`: the spec's
legal-pair pin in `action-newtaburl-pair.test.ts` (`type: 'script',
target: 'ssoOpen', opensInNewTab: true, newTabUrl: …`), the
doubled-redirect pin, and all objectui `consoleServerAction` tests.
`content/docs/ui/actions.mdx` and
`content/docs/protocol/objectui/actions.mdx` both say "for an async
handler that redirects, use `opensInNewTab`" and give a `type: 'url'`
action the `openIn` control instead.
So `type: 'url'` + any `target` would parse and teach a dead pair: the
renderer would navigate to `target` and `newTabUrl` would never fire
(the schema text itself routes a `url` action's new tab through
`openIn`, which is the previous subsection's lesson). Per the ruling
intent — spec declaration first, and no wrong sentence on the shipped
surface — the block takes the spec's pinned legal pair: `type: 'script'`
+ `target` naming the registered handler, with an inline comment that
the handler is the POST half and is skipped while `newTabUrl` is set. No
second URL is invented; `newTabUrl` keeps the one URL. The alternative
the order suggested (keep `url`, add `target:
'/api/v1/invoice/${ctx.recordId}/pdf'`) would make the example parse but
contradict the prose above it and the renderer; if the maintainer
prefers it anyway, say so on this PR and it is a one-line change.
## `skills/**` readings (base `959c209d56` → `28a140bb45`)
- `rules/actions.md`: 208 → 207 lines; 2107 → 2104 tokens (ceiling 2108;
headroom 1 → 4); 8428 → 8414 bytes.
- `evals/views-apps-actions-pages.json`: 65 → 65 lines; 1502 → 1502
tokens (ceiling 1505); 6005 → 6006 bytes.
- `SKILL.md`: 308 → 308 lines; 3843 → 3844 tokens (ceiling 3856;
headroom 13 → 12); 15372 → 15373 bytes — one byte of growth, paid inside
the file's headroom.
- Whole package: all `skills/*/SKILL.md` 4408 → 4408 lines (210279 →
210280 bytes); `skills/objectstack-ui/**` 2232 → 2231 lines, 124058 →
124046 bytes; ratcheted bundle 144047 → 144045 tokens; whole shipped
tree 154833 → 154831 tokens.
- Growth in `rules/actions.md` paid by content deletion (the restated
comment); the one byte in `SKILL.md` paid inside its headroom. Nothing
re-wrapped.
## Verification (tree `28a140bb45`, worktree clean)
- `check:skill-examples` (the control): exit 0 on `28a140bb45` after
building `@objectstack/client` and `@objectstack/client-react` under the
lock — 262 marked examples across 3 surfaces type-check, the
"Script-typed action" block among them (`SKILL.md` carries no marked
block). On `eb522522f2` the first run had refused with PREREQUISITE NOT
MET (exit 3, no built declarations, nothing measured) and passed after
the same build.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 24 families on this tree: the first
round's 23 plus `pnpm --filter @objectstack/spec run check:skill-docs`,
brought in by `SKILL.md` entering the changeset (its generator reads
only the frontmatter; it reports "Skill docs in sync"). All 24 ran on
`28a140bb45` with exit codes captured before any pipe, all 0; the
`--ran` reconciliation reads "24 derived, 24 run, 0 NOT-MEASURED, 0
UNRUN". Families: check-ci-filter-parity; check-closing-keyword-parity
(+ self-test); check-comment-mask-corpus; check-doc-route-spelling
(advisory + self-test); check-skills-token-ratchet (+ self-test); lint
check:doc-formula-expressions; spec check:skill-docs;
check:agent-test-spelling; check:corpus-claim-drift;
check:cross-package-test-inputs; check:doc-authoring;
check:driver-memory-census; check:gitlink-declared; check:nul-bytes;
check:pm-governed-merges; check:refd-timer-probe; check:role-word;
check:skill-compatibility; check:skill-frame-sync;
check:skill-identifier-liveness; check:watch-hint-literal.
- Token ratchet on `28a140bb45`: "skills/objectstack-ui/SKILL.md is 3844
tokens (ceiling 3856; headroom 12)" and "54 authored bundle file(s)
within their ceilings".
- NOT MEASURED locally (CI-owned): the artifact-roster families,
whole-root scans, the type-check lanes and the Test Core shards. No
package source changed, so no package `test`/`typecheck` is owed.
- Changeset: none — `skills/**` publishes nothing from a released
package (`skip-changeset`).
## Acceptance notes
- The `SKILL.md` same-family finding reported on the first round (the
`modal` table row and the blueprint row) is folded into this PR in the
patch round on the seat's revised file surface; it is item 4 above.
- The `opensInNewTab` block carries no `os:check` marker, so
`check:skill-examples` does not see it; a marker would add a type check
only (the refinement that refused it is invisible to tsc either way).
Not added (scope).
- "`input` (the modal params)" in the `ctx` section is left as is: the
params dialog is still a modal for a script action with `params`.
## 维护者速读(草稿)
**改了什么** — 发布的 objectstack-ui skill 里有三处教 AI 写 schema 会拒收的 action 写法。①
`rules/actions.md` 的"收集参数再执行服务端 body"示例由 `type: 'modal'` 改为 `type:
'script'`,标题同步,去掉多余的 `target`;② 同文件新标签页 `newTabUrl` 示例由 `type: 'url'` 改为
`type: 'script'` 并补上 schema 要求的 `target`;③ `SKILL.md` 两行:Action Types 表里
`modal` 一行原写"打开对话框(通常收集 `params` 再执行 `body`)",改为"打开 `target`
命名的页面;`body` 只在 `script` 上运行",蓝图表里"参数化批量变更用 `modal`"改为用
`script`。另删一句与下文重复的注释以抵消 token 棘轮;评测文件里描述该示例的一句话同步改为 `script`。
**为什么改** — spec 声明优先:`ActionSchema` 的两条 refinement 明确拒绝这两种写法(非 `script`
带 `body`、`url` 缺 `target`),错误信息本身就给出了修法;渲染端只在 `script` 路径读取
`newTabUrl`,保留 `type: 'url'` 只会让示例"能过校验但不起作用"。`SKILL.md`
的两行与示例是同一个错误,同一次审批一并收口。北极星优先级 4:发布面上写给 AI 看的错句是产品缺陷。
**风险与代价(含回滚)** — 只改文档与评测文字(三个文件),不改代码、不改 spec,不发包、无 changeset。`SKILL.md`
净增 1 字节,在该文件棘轮余量内。风险在于第二处示例的改法与派发单建议(保留 `url` 加
`target`)不同,正文已给出实测依据;若维护者更倾向原建议,改回是一行。回滚 = revert 本 PR。
**席位意见** — (留空)
**你要做的** — 审阅本 PR 并 APPROVE(或在评论里指明第二处改用「保留 `url` 加 `target`」),由席位落地。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CXydFDyiQwNbGFkmwrcRQq)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5d1d1ac commit 13aea18
3 files changed
Lines changed: 7 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
212 | | - | |
| 212 | + | |
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
| |||
249 | 249 | | |
250 | 250 | | |
251 | 251 | | |
252 | | - | |
| 252 | + | |
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
86 | | - | |
| 85 | + | |
87 | 86 | | |
88 | 87 | | |
89 | | - | |
90 | 88 | | |
91 | 89 | | |
92 | 90 | | |
| |||
178 | 176 | | |
179 | 177 | | |
180 | 178 | | |
181 | | - | |
| 179 | + | |
| 180 | + | |
182 | 181 | | |
183 | 182 | | |
184 | 183 | | |
| |||
0 commit comments