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

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-26475-skills-teach-queues
Oct 29, 2026
Merged

os-zhuang merged 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

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

1 participant