Repository navigation
Commit 501bfc6
docs(skills): objectstack-data, -automation and -platform teach ownership queues and assignment rules (ADR-0142 phase 2) with one eval each (#27426)
Fixes #26475
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:三个对外发布的 skill 开始教「所有权队列 + 分派规则」(ADR-0142 第二阶段,PR #26337
落地的能力):`objectstack-data` 新增小节 *Ownership queues*(保留列 `queue`、可编译的
`defineQueue` 示例、claim / release / move 各一句)与 `rules/security.md` 的
`queue` 共享收件人和 `current_user.queues` 占位符;`objectstack-automation` 新增小节
*Assignment rules*(可编译的 `defineAssignmentRule` 示例:`criteria` /
`assignTo: { type: 'queue' }` / `strategy` / `load`,外加 `queue`
审批人指针);`objectstack-platform` 给 `queues` / `assignmentRules` 两个键各一句并点明需
`sharing` 能力;三个 skill 各加一条 eval。
- **为什么改**:能力已进 spec 与文档,但 skills 不教,AI 从 skills 写 CRM
类应用时只能手搓——`assigned_to` 下拉、轮询计数字段、钩子挑 owner;平台已经付出的 ADR-0142 用不上。本 PR 是
PR #26337 欠下的 `Skills-docs` 后续。
- **风险与回滚**:只改 `skills/**` 与一条 `@objectstack/skills` patch changeset;不动
spec、运行时、`content/docs/**`、ratchet 脚本。每个文件 token 数不升(新文字靠折叠同 skill
`rules/**` / `references/**` 已有的重复句付账,eval
靠精简既有示范答案的措辞)。风险在折叠处:若某句被我误判为重复,读者要多开一个 rules 文件。回滚 = revert 本 PR。
- **先看**(按风险):① `skills/objectstack-automation/SKILL.md` —— 新节
*Assignment rules* 与 Valid-but-silently-wrong 条目 3/4/5 的折叠;②
`skills/objectstack-data/SKILL.md` —— 新节 *Ownership queues* 与 Common
Patterns 三处折叠(Naming / Field Type Selection / 索引引言);③ 三个 `evals/*.json`
—— 新 case 的断言,以及既有示范答案精简后是否失真。
- **两分钟验证**:`node scripts/check-skills-token-ratchet.mjs` —— 预期末行「84
authored bundle file(s) within their ceilings」,七个目标文件 headroom
0–17;`pnpm --filter @objectstack/spec check:skill-examples`(先 `pnpm
--filter '@objectstack/client-react...' build`)—— 预期「274 prose examples
type-check」,含两个新 `os:check` 块。
- **需要你做的**:Tier H(`skills/**`)—— 授权账号 APPROVE 一次,席位落地;无其它动作。
## What changes
Teach what PR #26337 (ADR-0142 phase 2) merged, quoting key names off
the tree: `packages/spec/src/security/queue.zod.ts` (`QueueSchema`:
`name`, `label`, `members[].type: 'position'`, `members[].value`),
`packages/spec/src/automation/assignment-rule.zod.ts`
(`AssignmentRuleSchema`: `name`, `object`, `entries[]` with `criteria`,
`assignTo: { type: 'queue' | 'user', value }`, `strategy: 'round_robin'
| 'least_loaded'`, `load`), the stack keys `queues` / `assignmentRules`
(`stack.zod.ts` L839/L848), the injected `queue` column
(`injected-system-columns.ts` `QUEUE_COLUMN`), the `queue` sharing
recipient (`sharing.zod.ts` `ShareRecipientType`) and the `queue`
approver type (`approval.zod.ts` `ApproverType`). `defineQueue` and
`defineAssignmentRule` are subpath exports
(`@objectstack/spec/security`, `@objectstack/spec/automation`), not root
exports — the examples import them that way.
| File | Added | Paid by (folded sentence → its home) |
|:--|:--|:--|
| `skills/objectstack-data/SKILL.md` | `### Ownership queues — park a
record for a team to claim` under *Security & Access Control*: the
injected `queue` column, a compiled `defineQueue` example, claim /
release / move one sentence each, the hand-rolled alternatives refused |
*Naming Rules Summary* table → `rules/naming.md` L9–12 (one line kept);
*Field Type Selection* category list → `rules/field-types.md` (L9 count,
L44–45 `password` / `secret`, L98 `user`, L116–117 embedded; the two
credential traps and the `user` / `formula` notes kept inline); the two
index blockquotes (retired `type` / `partial`; unique scope and bare
`unique: true`) → `rules/indexing.md` L26–33, L46–75 (one blockquote
kept) |
| `skills/objectstack-data/rules/security.md` | the `queue` sharing
recipient (`sharedWith: { type: 'queue', value }` shares the rule's
rows, parks none) in the *Choose by what the rows are keyed on* bullet;
the `current_user.queues` placeholder row (`rls.zod.ts` L57–58) |
`permissionSets:` refusal bullet, the Layer-0 "both keys are
load-bearing" blockquote, *Renaming or removing a shipped access item*,
the `secret` paragraph (facts also in `rules/field-types.md` L45) and
the `viewAllRecords` bullet — each tightened in place, every fact kept |
| `skills/objectstack-automation/SKILL.md` | `## Assignment rules —
route a new record to a queue or a person` before *Triggers*: when a
rule runs, a compiled `defineAssignmentRule` example (parked entry;
`least_loaded` + `load`; `round_robin` noted), `strategy` only on a
queue target, the `queue` approver pointer to
`references/state-machines-and-approvals.md` § Approver Types, the
hand-rolled alternatives refused; *When to Use* names the family |
Valid-but-silently-wrong item 5 (notify `skipped: true`) → the
`requires` table's `messaging` row (same file); item 4 → the CEL note at
the top and item 1's brace rule; item 3's two opening paragraphs → the
`script` node-table row; *CRM Automation Blueprint* table → one
paragraph; *When to Use* bullets → one paragraph (the frontmatter
`description` holds them); the `readonly` / `runAs: 'system'` blockquote
tightened (objectstack-data SKILL.md *Conditional Field Rules* states
the same rule); the fault-edge blockquote, the filter-operand bullet,
the Flow Variables example, *Elevate the write*, the system-sweep note,
the Triggers intro and the integrations tail tightened in place |
| `skills/objectstack-platform/SKILL.md` | one paragraph after the key
enumeration: what `queues` and `assignmentRules` declare, their
`define*` factories and subpaths, and that both need the ownership-queue
service `@objectstack/plugin-sharing` registers (`sharing` in
`requires`) or the boot is refused
(`describeMissingOwnershipQueueService`) | the intro paragraph → the
frontmatter `description`; *Port resolution* →
`references/operations.md` § Ports & networking; the `DriverPlugin`
fenced snippet → `references/bootstrap.md` § Programmatic Bootstrap (the
`SqlDriver` line kept inline); the seed `mode` table →
`objectstack-data/references/seeds.md` § Import modes;
`manifest.engines.protocol` tightened |
| `skills/objectstack-data/evals/hooks-security-seeds-datasources.json`
| eval 8: ownerless web-form leads a team holds until a rep claims one;
`must_contain` `defineQueue` / `type: 'position'` / `type: 'queue'` /
`CONCURRENT_UPDATE`, `must_not_contain` `assigned_to` / `beforeInsert` |
evals 1–7: model answers and three prompts tightened (words removed,
every `must_contain` token and fact kept) |
| `skills/objectstack-automation/evals/flows-triggers-approvals.json` |
eval 12: round-robin routing into a queue plus a `queue` approver;
`must_contain` `defineAssignmentRule` / `strategy: 'round_robin'` /
`type: 'queue'` / `type: 'approval'`, `must_not_contain` `assigned_to` /
`record-after-create` | evals 1–11: model answers and seven prompts
tightened |
| `skills/objectstack-platform/evals/config-plugins-ops.json` | eval 9:
a stack declaring `queues:` and `assignmentRules:` with `'sharing'` in
`requires`; `must_not_contain` `assigned_to` / `beforeInsert` | evals
1–8: model answers and five prompts tightened |
| `.changeset/26475-skills-teach-queues-assignment-rules.md` |
`'@objectstack/skills': patch`, both declaration lines | — |
Token table (`ceil(utf8 bytes / 4)`, the ratchet's convention; stamp
line excluded on SKILL.md; `main` = origin/main `45c9be5f`, `now` =
`a0193e39`):
| File | main | now | ceiling | net |
|:--|--:|--:|--:|--:|
| `skills/objectstack-data/SKILL.md` | 6120 | 6106 | 6123 | −14 |
| `skills/objectstack-data/rules/security.md` | 3687 | 3681 | 3687 | −6
|
| `skills/objectstack-automation/SKILL.md` | 6457 | 6449 | 6457 | −8 |
| `skills/objectstack-platform/SKILL.md` | 6014 | 6006 | 6014 | −8 |
| `skills/objectstack-data/evals/hooks-security-seeds-datasources.json`
| 1573 | 1573 | 1573 | 0 |
| `skills/objectstack-automation/evals/flows-triggers-approvals.json` |
2734 | 2732 | 2734 | −2 |
| `skills/objectstack-platform/evals/config-plugins-ops.json` | 1690 |
1689 | 1690 | −1 |
No ceiling moves. No re-wrap counted as payment: every freed token is a
deleted word, a removed duplicate or a dropped fence. Frontmatter is
untouched on all three skills (a `description` / `tags` edit regenerates
`content/docs/ai/skills-reference.mdx`, another lane's file);
`check:skill-docs` and `check:skill-refs` report in sync.
## Tests
Final head `a0193e39` (origin/main `45c9be5f` merged in before the PR;
it moved `packages/spec/src/ui/component.zod.ts`, so `@objectstack/spec`
was rebuilt under the verify lock, VERDICT command-exit 0, before the
readings below).
<details><summary>`pnpm --filter @objectstack/spec check:skill-examples`
— green, then the reverse leg (exit 0 / exit 1)</summary>
Green on `a0193e39`: `✅ 274 prose examples type-check across 3
surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on
all of them` (240 skills+docs, 11 spec TSDoc, 23 client SDK).
Prerequisite: `pnpm --filter '@objectstack/client-react...' build` under
the lock (VERDICT command-exit 0, 6m42s) — the gate refuses with exit 3
while `packages/client-react/dist` is unbuilt.
Reverse leg, both new blocks mutated through
`scripts/ablation-replace.mjs` (anchor count 1 → 0, replacement 0 → 1,
blob changed; `--hold` on the data file, wrap mode on the automation
file), on-disk counts during the run `strategie-count=1 team-count=1`:
```
skills/objectstack-automation/SKILL.md:311:7
error TS2561: Object literal may only specify known properties, but 'strategie' does not exist in type '{ name: string; assignTo: { type: "user" | "queue"; value: string; }; criteria?: … strategy?: "round_robin" | … Did you mean to write 'strategy'?
skills/objectstack-data/SKILL.md:421:15
error TS2322: Type '"team"' is not assignable to type '"position"'.
GATE_EXIT=1
```
Restore proven per path: `blob after restore == blob at HEAD` (data
`3513dbc6…`, automation `b77e9446…`), `git diff HEAD` empty on both,
tree clean.
</details>
<details><summary>`node scripts/check-skills-token-ratchet.mjs` — exit
0</summary>
```
✓ skills/objectstack-automation/SKILL.md is 6449 tokens (ceiling 6457; headroom 8)
✓ skills/objectstack-automation/evals/flows-triggers-approvals.json is 2732 tokens (ceiling 2734; headroom 2)
✓ skills/objectstack-data/SKILL.md is 6106 tokens (ceiling 6123; headroom 17)
✓ skills/objectstack-data/evals/hooks-security-seeds-datasources.json is 1573 tokens (ceiling 1573; headroom 0)
✓ skills/objectstack-data/rules/security.md is 3681 tokens (ceiling 3687; headroom 6)
✓ skills/objectstack-platform/SKILL.md is 6006 tokens (ceiling 6014; headroom 8)
✓ skills/objectstack-platform/evals/config-plugins-ops.json is 1689 tokens (ceiling 1690; headroom 1)
✓ check-skills-token-ratchet: 84 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.
```
</details>
<details><summary>Derived families — `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` at `a0193e39`, 46
commands, exit codes captured before any pipe</summary>
45 × exit 0: `check:skills-token-ratchet` (+ self-test),
`check:skill-top-level-keys` (`enumerates all 52 authorable top-level
keys`), `check:skill-identifier-liveness` (`Leg 1: 487 citation(s) over
70 published file(s)`), `check:skill-compatibility`,
`check:skill-frame-sync`, `check:skill-docs`, `check:doc-authoring`,
`check:corpus-claim-drift`, `check:closed-ceremony-text`,
`check:role-word`, `check:nul-bytes`, `check:pm-skill-id-lint`,
`check:pm-governed-merges`, `check:published-files`,
`check:adr-0087-registration --base origin/main`,
`check:changeset-no-major`, `check:empty-changeset`,
`check:changeset-gate-self-tests`, `check:closing-keyword-parity`,
`check:comment-mask-corpus`, `check:doc-route-spelling --advisory`,
`check:cross-package-test-inputs`, `check:driver-memory-census`,
`check:dts-closure`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content`, `check:watch-hint-literal`,
`check:gitlink-declared`, `check:merge-driver`,
`check:refd-timer-probe`, `check:ci-filter-parity`,
`check:agent-test-spelling`, `check:pm-changeset-deadline-census`,
`@objectstack/lint check:doc-formula-expressions`, and the derived
`--self-test`s.
1 × exit 3, NOT MEASURED locally: `pnpm check:dual-build-cjs-loads` —
`PREREQUISITE NOT MET — this gate reads built output, and some package
has no dist/` (33 packages; wants a full `pnpm build`, a farm-wide run
that belongs to CI; this diff touches no package source).
Also run: `pnpm --filter @objectstack/skills build` — `✓ sync-catalog
self-test: 9 cases pass` · `95 file(s) across 11 skill(s) copied from
skills/** into dist/skills and read back byte-identical`;
`check:skill-refs` — `9 generated files in sync`.
</details>
No package test suite is owed: the diff touches `skills/**` and
`.changeset/` only (`@objectstack/skills` ships the catalog by
`sync-catalog.mjs`, run above); clause ① is empty. `test:repo` and the
full farm are CI's.
## Acceptance notes
- **Conflict named.** `.claude/agents/os-dev.md` says `pr_create`
carries `assignees: [LOGIN]`; the dispatch order says omit it under the
maintainer's 2026-10-29 ruling on #27363 (a seat-driven draft is
assigned to nobody until the seat's review). This PR follows the order
and carries no assignee; the file still says otherwise.
- **PM hypothesis 1 (fold homes) partly falsified.**
`skills/objectstack-platform/references/*` hold the `DriverPlugin`
construction, port resolution and the barrel pattern, but NOT the Hono
two-package table, the "no `@objectstack/adapter-*`" line, the
`basePath` caveat or the driver selection table — those stayed.
`skills/objectstack-automation/references/*` hold none of the
Valid-but-silently-wrong prose, so every automation fold is intra-file
(duplicates of the node table, the CEL note and the `requires` table) or
a tightening. The data folds are as hypothesised: `rules/naming.md`,
`rules/field-types.md` (all 49 types present, checked by name) and
`rules/indexing.md` hold the folded text.
- **Hypothesis 2 confirmed** — see the reverse leg. **Hypothesis 3
confirmed**: no eval executor exists; each new case's `expected_output`
was checked programmatically to contain every `must_contain` token and
none of the `must_not_contain` ones.
- **Out of scope, class a (reproducible), noted not filed — pre-existing
eval self-contradictions in
`skills/objectstack-platform/evals/config-plugins-ops.json` on
origin/main**: the model answer of eval 1 contains `tableName`, eval 2
contains `data:beforeInsert` and `onInstall`, eval 4 contains
`@objectstack/adapter-`, eval 7 contains `role:` and `admin_full_access`
— each a string the same eval's `must_not_contain` forbids, so a
verbatim ideal answer grades wrong (the defect class the landed
changeset `26515-automation-eval-fixtures.md` fixed for the automation
skill). Repro: parse the file and test each `must_not_contain` string
against its own `expected_output`. reach: named producer — the shipped
eval fixture is the producer, the skills catalog grader the consumer.
Left as written here (my tightening of those answers kept the wording);
carrier: the `domain:skills` seat. Dedupe words: platform eval
must_not_contain self-contradiction tableName onInstall.
- **Beyond the minimum**: `rules/security.md` also gains the
`current_user.queues` placeholder row (the RLS placeholder table listed
six reserved keys and the kernel-name list already named `queues`).
Nothing from the minimum teaching was cut.
- `skills/objectstack-data/evals/README.md` (ceiling 143, headroom 1)
was not updated to mention queues: one word exceeds it, and the ruling
allows no raise.
- No `Skills-docs:` line: kind `none`, no `(narrowing)` arm.
## Verification
```bash
node scripts/check-skills-token-ratchet.mjs # 84 files within ceilings; the seven target files as tabled above
node scripts/check-skill-top-level-keys.mjs # 52 keys enumerated; the new paragraph sits outside the key paragraph
node scripts/check-skill-identifier-liveness.mjs # Leg 1 487 citations OK (the new `current_user.queues` row included)
pnpm --filter '@objectstack/client-react...' build && pnpm --filter @objectstack/spec check:skill-examples # 274 blocks, the two new os:check blocks included
```
Reading the teaching: `skills/objectstack-data/SKILL.md` § Ownership
queues; `skills/objectstack-automation/SKILL.md` § Assignment rules;
`skills/objectstack-platform/SKILL.md` the paragraph after the key
enumeration; the three new eval cases (ids 8 / 12 / 9).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg)_
---------
Co-authored-by: objectstack-fleet[bot] <objectstack-fleet[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>1 parent a33fce2 commit 501bfc6
8 files changed
Lines changed: 269 additions & 236 deletions
File tree
- .changeset
- skills
- objectstack-automation
- evals
- objectstack-data
- evals
- rules
- objectstack-platform
- evals
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
30 | 28 | | |
31 | 29 | | |
32 | 30 | | |
| |||
122 | 120 | | |
123 | 121 | | |
124 | 122 | | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
| 123 | + | |
| 124 | + | |
133 | 125 | | |
134 | 126 | | |
135 | 127 | | |
| |||
138 | 130 | | |
139 | 131 | | |
140 | 132 | | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
148 | 138 | | |
149 | 139 | | |
150 | 140 | | |
151 | 141 | | |
152 | 142 | | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
170 | 156 | | |
171 | 157 | | |
172 | 158 | | |
| |||
180 | 166 | | |
181 | 167 | | |
182 | 168 | | |
183 | | - | |
184 | | - | |
185 | | - | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
186 | 172 | | |
187 | 173 | | |
188 | 174 | | |
| |||
202 | 188 | | |
203 | 189 | | |
204 | 190 | | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
211 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
212 | 196 | | |
213 | 197 | | |
214 | 198 | | |
| |||
258 | 242 | | |
259 | 243 | | |
260 | 244 | | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
268 | 249 | | |
269 | 250 | | |
270 | 251 | | |
| |||
298 | 279 | | |
299 | 280 | | |
300 | 281 | | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
312 | 285 | | |
313 | 286 | | |
314 | 287 | | |
315 | 288 | | |
316 | 289 | | |
317 | 290 | | |
318 | 291 | | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
319 | 324 | | |
320 | 325 | | |
321 | | - | |
322 | | - | |
323 | | - | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
324 | 329 | | |
325 | 330 | | |
326 | 331 | | |
| |||
405 | 410 | | |
406 | 411 | | |
407 | 412 | | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
412 | | - | |
413 | | - | |
414 | | - | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
415 | 420 | | |
416 | 421 | | |
417 | 422 | | |
418 | 423 | | |
419 | 424 | | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
427 | 429 | | |
428 | 430 | | |
429 | 431 | | |
| |||
0 commit comments