Skip to content

docs(skills): objectstack-data, -automation and -platform teach ownership queues and assignment rules (ADR-0142 phase 2) with one eval each - #27426

Draft
objectstack-fleet[bot] wants to merge 3 commits into
mainfrom
claude/issue-26475-skills-teach-queues
Draft

objectstack-fleet[bot] wants to merge 3 commits into
mainfrom
claude/issue-26475-skills-teach-queues

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #26475
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:三个对外发布的 skill 开始教「所有权队列 + 分派规则」(ADR-0142 第二阶段,PR feat!: ownership queues and assignment rules (ADR-0142 phase 2) #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 feat!: ownership queues and assignment rules (ADR-0142 phase 2) #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).

`pnpm --filter @objectstack/spec check:skill-examples` — green, then the reverse leg (exit 0 / exit 1)

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.

`node scripts/check-skills-token-ratchet.mjs` — exit 0
✓ 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.
Derived families — `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `a0193e39`, 46 commands, exit codes captured before any pipe

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-tests.

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.

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 skills(os-dev, pm-dispatch): a seat-driven PR is not assigned to the seat's account at the draft open; it reaches a human only after ACCEPT + contract PASS, as a review request to os-zhuang/hotlong when Tier H #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

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

objectstack-fleet Bot and others added 3 commits October 29, 2026 05:27
…d assignment rules (WIP)

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg
…rules, paid by tightening existing model answers

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tooling labels Oct 29, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-justin · session_01QSeKYmhU5KEj1nukYhp1Tg

Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 rate_limit: the account's ceiling-tier quota is exhausted, 2026-10-29T07:03Z) · head a0193e3

The dispatching seat holds no claim and no record on this head and will not review it below tier (contract-review.md 〈复核归属与资格〉: 「派发席达档调用被配额拒(HTTP 429)⇒ ⛔ 不降档审;PR 落交接行、留等复核标记,交分诊席」). The maintainer's words this session: 「没有fable了,用 opus 完成开发,然后等分诊契约复审」. needs:contract-review hangs on this PR in the same stroke.

For the reviewer (inputs, not conclusions): the card is #26475 (Tier H skills/**, ADR-0142 phase 2 skills leg of PR #26337); dispatch order constraints were net ≤ +0 tokens per file, no ceiling raise without a ruling id, key names quoted off packages/spec/src/automation/assignment-rule.zod.ts, security/queue.zod.ts, contracts/ownership-queue-service.ts; the dev report is 6489653060 on the card. Check-runs on this head at the hand-off: 41, 27 success, 14 skipped, 0 failed, 0 in progress. After a PASS, the seat writes its ## 席位核对 ACCEPT on this head and makes the hand-off to GOVERNED_APPROVERS (pr_request_reviewers + needs-user-decision on the PR); nobody is asked before that.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

Contract-review-claim: session_01AavokzJ5DndAwitDXvKy4U · head a0193e3957d521450d28b1d5733424af915703d6 · 2026-10-29T07:54Z

Triage seat, taking the hand-off and needs:contract-review on this head (#27062 (a)). The review runs at CONTRACT_REVIEW_TIER. If the lane claims or posts a record on this head first, triage withdraws.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a0193e3957d521450d28b1d5733424af915703d6
Local-runs: none
Scope: skills/objectstack-automation/SKILL.md, skills/objectstack-automation/evals/flows-triggers-approvals.json, skills/objectstack-data/SKILL.md, skills/objectstack-data/evals/hooks-security-seeds-datasources.json, skills/objectstack-data/rules/security.md, skills/objectstack-platform/SKILL.md, skills/objectstack-platform/evals/config-plugins-ops.json + packages/spec/src/security/queue.zod.ts, packages/spec/src/automation/assignment-rule.zod.ts, packages/spec/src/shared/expression.zod.ts, packages/spec/src/stack.zod.ts, packages/spec/src/data/injected-system-columns.ts, packages/spec/src/security/sharing.zod.ts, packages/spec/src/automation/approval.zod.ts, packages/spec/src/security/rls.zod.ts, packages/spec/src/contracts/ownership-queue-service.ts, packages/spec/src/kernel/platform-capabilities.ts, packages/spec/src/security/index.ts, packages/spec/src/automation/index.ts, packages/spec/src/index.ts, packages/spec/package.json, packages/objectql/src/assignment-rules.ts, packages/objectql/src/plugin.ts, packages/objectql/src/registry.ts, packages/objectql/src/concurrent-update-error.ts, packages/plugins/plugin-security/src/ownership-queue-gate.ts, packages/plugins/plugin-sharing/src/sharing-plugin.ts, packages/plugins/plugin-approvals/src/approval-service.ts, docs/adr/0142-ownership-queue-membership-claim-and-assignment-rules.md, skills/objectstack-automation/references/state-machines-and-approvals.md, skills/objectstack-data/rules/naming.md, skills/objectstack-data/rules/field-types.md, skills/objectstack-data/rules/indexing.md, skills/objectstack-data/references/seeds.md, skills/objectstack-platform/references/operations.md, skills/objectstack-platform/references/bootstrap.md, content/docs/automation/queues-and-assignment-rules.mdx, content/docs/permissions/sharing-rules.mdx, scripts/check-skills-token-ratchet.mjs, .changeset/26475-skills-teach-queues-assignment-rules.md, AGENTS.md

① Derived judgments

Inputs read in full: card #26475 body + 4 comments (triage grade 6434161625, unblock 6487363775, claim 6488140412, os-dev-report 6489653060), PR #27426 body, file list (8 files), both PR comments (hand-off 07:04Z, triage claim 07:54Z), the 46 check-runs on the head, and the net diff vs main (merge-base 45c9be5f).

  • Accept-set changes: none — right. The diff touches skills/** and one .changeset/*.md only. No schema, key, export, runtime or content/docs/** file moves; git show prr-27426: of every cited spec/runtime file equals origin/main's reading (the PR merged 45c9be5f before its head).
  • Public surface: @objectstack/skills catalog content — right. packages/skills (name @objectstack/skills, 18.2.0) ships skills/** through sync-catalog.mjs; new prose, two new os:check blocks and three new eval cases publish in the next patch. No frontmatter (description/tags) edit, so content/docs/ai/skills-reference.mdx is not regenerated — right, that file is another lane's.
  • Governed surface: skills/** is Tier H — right. The PR stops at a draft awaiting the maintainer's APPROVE; needs:contract-review hangs; no assignee (maintainer ruling on skills(os-dev, pm-dispatch): a seat-driven PR is not assigned to the seat's account at the draft open; it reaches a human only after ACCEPT + contract PASS, as a review request to os-zhuang/hotlong when Tier H #27363). This record is the contract-tier reading; the maintainer's word remains the landing condition.
  • Check-runs on a0193e39: 46, all completed; 28 success, 18 skipped, 0 failure, 0 pending — the gate verdicts. Green: Lint & Repo Gates (carries check:skills-token-ratchet, check:skill-top-level-keys, check:skill-identifier-liveness, check:skill-docs, check:skill-refs), TypeScript Type Check (all six lanes), Test Core (plan + 2 shards + aggregate), Build Core, Check Changeset, Governed Surface Queue Guard, PR-body guards, Check PR Size, Dogfood Regression Gate (aggregate). Skipped are path-filtered UI/docs lanes, live-DB conformance, opt-in harnesses and the schedule gate — expected for a diff with no ui/**, content/docs/** or package source. Right.
  • Token arithmetic read off the tree (wc -c, ceil(bytes/4), stamp line 20 bytes = 5 units excluded on the three SKILL.md): automation 6449 (main 6457), data 6106 (6120), platform 6006 (6014), security.md 3681 (3687), automation evals 2732 (2734), data evals 1573 (1573), platform evals 1689 (1690) — every file at or under its main count, matching the PR's table exactly; scripts/check-skills-token-ratchet.mjs is not in the diff, so no ceiling moved. Right. The dispatch order's "net ≤ +0 per file, no ceiling raise without a ruling id" is met.
  • Key names quoted off the tree — right, every one: QueueSchema name/label/members[].type: 'position'/members[].value (queue.zod.ts: DeclaredQueueMemberSchema is z.literal('position')); AssignmentRuleSchema name/object/entries[].{name, criteria?, assignTo{type:'queue'|'user', value}, strategy?: 'round_robin'|'least_loaded', load?} with the three refinements (strategy only on a queue target; load required with least_loaded, refused otherwise); stack keys queues (L839) / assignmentRules (L848); QUEUE_COLUMN = 'queue' injected exactly where owner_id is (queue = owner, ownership === undefined || 'user'); ShareRecipientType includes 'queue'; ApproverType includes 'queue' (D6 comment: resolved at node entry, empty → nobody, onEmptyApprovers decides); rls.zod.ts L56–58 names queues among the kernel-resolved keys (ADR-0142 D3). defineQueue is exported only from ./security (security/index.ts L26) and defineAssignmentRule only from ./automation (automation/index.ts L19); src/index.ts exports neither — the examples' subpath imports are the only correct spelling. Right.

② Semver level

.changeset/26475-skills-teach-queues-assignment-rules.md: '@objectstack/skills': patch, body carries Clause-②: no and Metadata-protocol: none; the PR body carries the same two lines. AGENTS.md's rule (kind none ⇒ patch; Clause-②: yes|no plus at most one arm) is met: the diff publishes new catalog prose from a released package and changes nothing an author can write — no key, value, type, export or default moves. Clause-②: no is right and patch is right; skip-changeset would have been wrong (the package publishes). Check Changeset green on the head.

③ Boundary flags

open_questions: [] in the dev report — none to answer. Seven declared deviations and two out-of-scope findings, each judged:

  1. .claude/agents/os-dev.md says pr_create carries assignees: [LOGIN]; the order forbade it. Process, not this tree; the PR correctly carries no assignee under the maintainer's 2026-10-29 ruling on skills(os-dev, pm-dispatch): a seat-driven PR is not assigned to the seat's account at the draft open; it reaches a human only after ACCEPT + contract PASS, as a review request to os-zhuang/hotlong when Tier H #27363. Escalated: the file is the .claude/** lane's to reconcile with the ruling — not a finding on this PR.
  2. Partial rebuild (spec + client-react closure, not full pnpm build); check:dual-build-cjs-loads NOT MEASURED locally. Answered by the head's check-runs: Build Core, Test Core, TypeScript Type Check and Lint & Repo Gates all success. Closed.
  3. Eval model answers and prompts tightened as payment. Judged against the fixtures: every pre-existing case's must_contain tokens are still present in its expected_output on the head (parsed and checked for all 29 cases across the three files); the tightenings drop restatements and parentheticals, not facts (e.g. automation eval 10 keeps the lock-read, the non-participant refusal, approvalsVisibleToReaders and the 404 rule; platform eval 2 keeps "record events are not kernel hooks… a data hook"). Payable text under the ruling's "deleted word / removed duplicate" reading. Accepted.
  4. skills/objectstack-data/evals/README.md not updated (ceiling 143, headroom 1). Harmless; the README is an index, the new case is discoverable by id. Accepted.
  5. Pre-existing must_not_contain self-contradictions in skills/objectstack-platform/evals/config-plugins-ops.json evals 1/2/4/7 left as written. Verified on origin/main byte-for-byte (the same six strings: tableName; data:beforeInsert, onInstall; @objectstack/adapter-; role:, admin_full_access) — not introduced here, and the new eval 9 is clean. Should-fix outside this PR; escalated: the domain:skills seat files the card the dev named ("noted, not filed") — it is the defect class changeset 26515-automation-eval-fixtures.md already repaired for the automation skill.
  6. No frontmatter edit, so the automation description does not name assignment rules. Accepted for this PR (the regenerated skills-reference.mdx is another lane's file). Should-fix follow-up: a one-line description addition so the family is routed by the skill picker, coordinated with the docs lane.
  7. test:repo not run locally. Test Core success on the head. Closed.

Out-of-scope finding 2 (PM fold-home hypothesis partly falsified) is reporting, not a defect; no action.

④ Design judgment

Each hits file read against the card's prompt ("teach ownership queues and assignment rules … with eval prompts; the queue approver type"), ADR-0142 D1–D7 and the spec/runtime on the head.

skills/objectstack-data/SKILL.md — § Ownership queues. Holds. "Every ownership: 'user' object carries a platform-injected queue column beside owner_id" — injected-system-columns.ts L240–252 (queue = owner). "An object declaring its own queue field is refused" — registry.ts#objectQueueColumnRefusal (422 ObjectQueueColumnRefusedError, prescription: rename or leave the user tier). "Sits in a queue when owner_id is empty and queue names it: members read and edit it (rows widen, verbs never — no delete)" — ADR-0142 D3 verbatim semantics (disjunct in buildReadFilter/update arm/checkEdit, never the delete paths). "Declared members are positions only; an organization adds users and teams through sys_queue_member" — DeclaredQueueMemberSchema refusal text. The defineQueue example parses (name snake_case, label, members[]) and is type-checked by check:skill-examples (Lint & Repo Gates green; the PR's reverse leg shows the block is live). Claim as a by-id { owner_id: <self> } update admitted to a member on an unowned record, loser 409 CONCURRENT_UPDATE — D4 + ownership-queue-gate.ts#CLAIM_REFUSAL + concurrent-update-error.ts ("The record was taken"). Release = owner writes owner_id: null, record sits in its home queue again — D4 + RELEASE_REFUSAL. Move = writing another queue is a transfer (allowTransfer or modifyAllRecords) — D3/D4 + MOVE_REFUSAL. The refused alternatives (assigned_to picklist, counter field, owner-picking hook) are exactly ADR-0142 D8's STOPGAP list. Folds verified at their homes: rules/naming.md L7–13 (table), rules/field-types.md L9 ("49 available"), L44–45 (password/secret), L98 (user), L110–118 (embedded), rules/indexing.md L26–33 (retired type/partial), L40–80 (unique scope, bare true, FIELD rule). No fact lost. No finding.

skills/objectstack-data/rules/security.md. Holds. current_user.queues row cites ADR-0142 D3 and rls.zod.ts names queues kernel-resolved — right; plugin-security/src/kernel-queue-membership.ts is the producer. The sharedWith: { type: 'queue', value } sentence ("shares the rule's rows, parks none — only the record's queue column does that") is ADR-0142 D7's closing sentence and matches content/docs/permissions/sharing-rules.mdx L189. Tightened paragraphs (permissionSets refusal, Layer-0 blockquote, viewAllRecords, secret, renaming) keep every fact. Should-fix (wording, not blocking): the placeholder row reads "the ownership queues the caller sits in" — the skill's own § Ownership queues defines sits in for records; a caller is a member of a queue. One word (belongs to), zero token cost.

skills/objectstack-automation/SKILL.md — § Assignment rules. Holds. "Routes each inserted row of an ownership: 'user' object whose owner_id and queue are both still empty — once, after every beforeInsert hook, never on update, never refusing the insert (ADR-0142 D5)" — AssignmentRuleSchema TSDoc and D5 word for word. "Entries ordered; the first whose criteria (CEL over record.*) match decides" — AssignmentRuleEntrySchema; a bare string is CEL shorthand (EvaluatedExpressionInputSchema L269–272), so criteria: 'record.priority == "urgent"' and load: 'record.status != "closed"' are valid input. The example's two entries exercise both arms the refinements allow: queue target without strategy (parks) and least_loaded with load; the comment "load only with least_loaded" is the refinement's own rule. "strategy is for a queue target only" — refinement 1. The queue approver pointer resolves: references/state-machines-and-approvals.md L236 ### Approver Types, L247 the queue row ("at node entry; an empty queue adds nobody") — approval-service.ts L2473/L2522–2532 implements exactly that. Folds: item 5 → requires table L343 (messaging … skipped: true); item 4's stdlib/brace rule kept in the surviving item 4; item 3's dispatch sentence kept in the node table L89 and the rewritten item 3; When-to-Use bullets → one paragraph that now names the family; Blueprint table → one paragraph with the same four facts. Should-fix (prose, not blocking): "The third automation family" has no antecedent in the file (When to Use names six things); "Another automation family" or dropping the ordinal reads cleaner. No must-fix.

skills/objectstack-platform/SKILL.md — the queues/assignmentRules paragraph. Holds against the code: the boot refusal is objectql/src/plugin.ts#assertOwnershipQueueServicePresent at kernel:ready → describeMissingOwnershipQueueService (probes the ownership-queue service, "never the job queue's queue"), and plugin-sharing/src/sharing-plugin.ts L707 registers it. The paragraph sits after the key enumeration, outside what check-skill-top-level-keys parses (green). Folds verified: references/operations.md L61 ## Ports & networking (anchor #ports--networking), references/bootstrap.md L100 ### Programmatic Bootstrap (Without CLI) (anchor #programmatic-bootstrap-without-cli), objectstack-data/references/seeds.md L59 ### Import modes with the five-mode table (anchor #import-modes). Should-fix (precision, not blocking): "(sharing in requires): a stack declaring either without it is refused at boot" lets "it" read as the token. sharing is on PLATFORM_ALWAYS_ON_CAPABILITIES (platform-capabilities.ts L357), so under default os serve the service is mounted whether or not requires names it; the refusal fires where the SERVICE is absent (--preset minimal, a programmatic boot without @objectstack/plugin-sharing). Declaring sharing is still right under the skill's own "Declaring is a demand" rule (an absent provider becomes a hard error instead of best-effort), so nothing an AI writes from this sentence is refused or silently wrong — hence should-fix: say "the service @objectstack/plugin-sharing registers — demand it with sharing in requires; a composition without it is refused at boot".

skills/objectstack-data/evals/hooks-security-seeds-datasources.json — eval 8. Holds. The model answer's defineQueue({ name: 'inside_sales', label, members: [{ type: 'position', value: 'inside_sales_rep' }] }) parses; a queue-target entry with no strategy parks (D5); the claim and 409 CONCURRENT_UPDATE are D4. expected_output contains all four must_contain strings and neither must_not_contain string (checked). The prompt ("two reps must never own the same lead") is answered by the one-owner precondition. Evals 1–7 keep every must_contain token. No finding.

skills/objectstack-automation/evals/flows-triggers-approvals.json — eval 12. Holds. defineAssignmentRule({ … entries: [{ name: 'all', assignTo: { type: 'queue', value: 'support_team' }, strategy: 'round_robin' }] }) passes every refinement (round_robin takes no load); "evaluated once per insert on a still-ownerless row, never on update" is D5; the queue approver sentence is D6 and the ApproverType comment. This is the first eval exercising the queue approver type the card asked for. All four must_contain present, neither must_not_contain present. Evals 1–11 keep every token. No finding.

skills/objectstack-platform/evals/config-plugins-ops.json — eval 9. Holds. Two collections, 'sharing' in requires, "queue is the job queue" (the contract header's own distinction). Self-consistent. The pre-existing contradictions in evals 1/2/4/7 are on main unchanged and carried in ③ item 5. No finding on the new case.

Nothing in the seven hits files contradicts the spec, the ADR, the runtime or content/docs/automation/queues-and-assignment-rules.mdx on main; the three new os:check/model-answer shapes are the shapes the schemas accept. Three should-fixes, no must-fix.

Implemented-by: claude/issue-26475-skills-teach-queues
Reviewed-by: session_01AavokzJ5DndAwitDXvKy4U

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-justin · session_01QSeKYmhU5KEj1nukYhp1Tg

维护者速读

  • 改了什么:三份对外发布的 skill 开始教「归属队列(ownership queue)与分配规则(assignment rule)」:objectstack-data 加一节(平台注入的 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,拒收手写替代(assigned_to 下拉、插入钩子设 owner、轮询计数字段)。
  • 为什么改:ADR-0142 第二阶段的平台能力已落地(PR feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337),但 AI 写 CRM 类应用时从 skills 里学不到它,只会手写轮询分配;这是该 PR 欠下的 Skills-docs: 腿([Decision] pm-dispatch: which PRs owe a Skills-docs: line (the #26184 audit Part B rule draft) — protocol-kind only, protocol-kind plus narrowing, or not adopted #26369 裁决 B)。
  • 风险与回滚:只改 skills/** 七个文件的散文、两个 os:check 示例与三条 eval;每个文件 token 数都不高于 main(净 −14 / −6 / −8 / −8 / 0 / −2 / −1),新内容靠删重复付账,天花板未动;@objectstack/skills patch。回滚 = revert 本 PR。
  • 先看:skills/objectstack-automation/SKILL.md 的 ## Assignment rules 节,skills/objectstack-data/SKILL.md 的 ### Ownership queues 节。
  • 两分钟验证:pnpm --filter @objectstack/spec check:skill-examples(两个新示例参与类型检查;dev 的反向腿把 strategy 改成 strategie 即红);node scripts/check-skills-token-ratchet.mjs 全绿。
  • 需要你做的:批准本 PR(Tier H,skills/**)。契约复核 PASS 在案:分诊记录 6491424419,Head-sha a0193e3957d521450d28b1d5733424af915703d6;无 must-fix。复核列了 3 条不阻塞的措辞 should-fix(见核对第 5 项):直接批即按现状落地;回一个「改」,席位起一轮返工、交分诊 delta 复核后再请您批。
  • 席位意见:ACCEPT。开发在 fable 额度用尽前完成;契约复核按规则交分诊在 CONTRACT_REVIEW_TIER 达档完成,复核逐键对照了 spec、ADR-0142 与运行时代码。

席位核对

  1. 形态:8 个文件 +269/−236(505 ≤ 3000);head a0193e39(含 merge 45c9be5f);draft,作者 objectstack-fleet[bot](经中继),assignees []、requested_reviewers [] —— 交棒之前无人被请;mergeable_state: clean。
  2. 前提实测:复核在 head 上逐键核对:QueueSchema(members[].type 只许 position)、AssignmentRuleSchema 三条 refinement、stack 键 queues / assignmentRules、注入列 queue、ShareRecipientType 与 ApproverType 含 queue、defineQueue 只从 ./security、defineAssignmentRule 只从 ./automation 导出 —— 示例的子路径 import 是唯一正确拼法;卡上第 5 项(content/docs/permissions/sharing-rules.mdx)已在 main(PR feat(console): ownership queues in the Console — two-source queue pickers, Claim on a queued record, an In-a-queue list filter, and the authoring guide (ADR-0142) #27264)。
  3. 门禁 check-runs(head a0193e3):46 个全部完成,28 success、18 skipped、0 失败;check-expected-skips.mjs --pr 27426(roster 取自 origin/main)→ exit 0,18 个 skip 皆在名册。
  4. 接受的偏差:eval 文件靠收紧既有标准答案与提示词付账(复核解析全部 29 条用例,每条 must_contain 仍在其 expected_output 中);只重建了 spec 与 client-react 闭包,check:dual-build-cjs-loads 本地未测(CI 的 Build Core / Lint & Repo Gates 绿);未改 frontmatter(会重生成另一车道的 skills-reference.mdx);skills/objectstack-data/evals/README.md 余量 1 未写入新用例。
  5. 范围外去向 + Skills-docs::filed skills(objectstack-platform): four eval cases in config-plugins-ops.json refuse strings their own expected answer contains, so a verbatim ideal answer grades as wrong #27455(平台 eval 1/2/4/7 拒收字串出现在自身标准答案里,main 上已复现,复核亦确认,排本 PR 之后串行)。复核 should-fix(不阻塞,未建):① rules/security.md 占位行「the ownership queues the caller sits in」宜作 belongs to;② automation「The third automation family」无先行词;③ platform 段「a stack declaring either without it is refused at boot」的 it 宜指明是 @objectstack/plugin-sharing 注册的服务(sharing 在平台常开能力里,拒绝只发生在服务缺席时)。automation 的 frontmatter description 未点名 assignment rules —— 与 docs 车道协调的后续,本席记于 Acceptance notes、不立卡。Skills-docs: updated here。
  6. 落地条款:Tier H(check-governed-merges --pr 27426:skills/**,人工合并即审核记录);契约复核 PASS 6491424419 钉现 head;本笔交棒 = 中继 pr_request_reviewers 请 os-zhuang、hotlong(作者非审批人,请全员)+ PR 挂 needs-user-decision、摘 needs:contract-review;获授权批准后席位 ready → 入队;⛔ 席位不批准、不合并。

ACCEPT · head a0193e3957d521450d28b1d5733424af915703d6 · 2026-10-29T08:10Z

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation needs-user-decision size/l tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills(data,automation,platform): teach ownership queues and assignment rules (ADR-0142 phase 2, PR #26337) with eval prompts

0 participants