Skip to content

docs(skills): objectstack-data teaches membership keys, ownerMayEdit, create-only seed columns, the position-to-set binding and the external tier - #26416

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-un9ezo
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-un9ezo

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #26297
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:skills/objectstack-data 教五件 18.x 已发布、技能没教的事:① rules/security.md 新增「成员键」一节(membershipKeys 声明在名册对象上,userField / valueField / filter 三个成员、拒收规则、每请求一次的系统读且失败即零行、与 owner 作用域 / 岗位 / 共享规则的选择规则)和「岗位只授它点名的集合;门户用户是 external」一节;② rules/relationships.md 在 controlled_by_parent 旁教 sharing.controlledByParent.ownerMayEdit;③ references/seeds.md 补 columns 选项行和 applyOn: 'create' 小节;④ references/examples-objects.md 两处过时的 { type: 'lookup', reference: 'user' } 改为 type: 'user';⑤ eval 加门户成员题一道,种子题与发票行题各扩一句。六行 token 上限按实测调整,裁决原文写在行旁。
  • 为什么改:AI 作者建门户或按名册限行的应用时,没有这些规则就会逐行手写策略、以为岗位同名集合会自动授予、种子重放覆盖掉管理员的修改;reference: 'user' 的例子会被原样抄进一个不存在的对象。
  • 风险与回滚:只改发布技能包的文字、两个 eval 夹具和棘轮脚本的六行上限,不改运行时;回滚即 revert 本 PR(上限行随之回落)。
  • 先看:① skills/objectstack-data/rules/security.md 新两节(成员键示例块与四条要点、岗位/external 两条);② scripts/check-skills-token-ratchet.mjs 六行上限及其注释;③ evals/hooks-security-seeds-datasources.json 第 6 题。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs → 末行 81 authored bundle file(s) within their ceilings,其中 rules/security.md is 3693 tokens (ceiling 3693; headroom 0);pnpm --filter @objectstack/spec run check:skill-examples → 新标记的名册对象块随 265 个示例通过类型检查。
  • 需要你做的:Tier H(skills/**),请 approve 或直接 Merge when ready。

What changes

Card #26297, the six Measured rows (D2–D7) and nothing wider:

  1. rules/security.md — "Membership keys" (after the RLS section, whose placeholder table already named current_user.KEY without saying where it comes from): the choice statement first (rows keyed on a named record → a key on the roster object, never a stamp on every row or a policy per record), a type-checked roster example (account_member with membershipKeys.portal_account_ids: { userField: 'user', valueField: 'account', filter: 'active == true' }) and the policy fragment that reads it with in; then four bullets — the three members and what each may name; the refusals (one name per stack, the kernel's own names, no contribution through an object extension); the once-per-request system read (no read on the roster needed, 1,000-value cap, a larger set / failed read / non-compiling filter matches no rows, whoever writes roster rows grants the key); and the choice rule against owner scoping, a position's positions and a sharing rule.
  2. rules/security.md — "Positions grant only what they name; portal users are external": a position distributes only the sets its permissionSets names (ADR-0131 D3/D4; a namesake set is reported, never granted; a name matching no set confers nothing), with the one-line position shape; the external membership tier for portal and partner users (closed list, one tier per member, docs anchor), which the everyone baseline does not reach, sees no member directory, holds no business unit, and for which every org-wide default is owner-only — rows reach it only through explicit grants (a position or set whose row policies bound them, a sharing rule, a manual share). check:role-word (ADR-0090 D3) refuses the reserved word in this tree, so the prose says "membership tier" where the spec's constant file says otherwise.
  3. rules/relationships.md — "Owner edits under controlled_by_parent — ownerMayEdit" under the master_detail pattern, plus "owner opt-in ownerMayEdit (below)" in the type table's Sharing cell (the card's row at L16): what a detail inherits, the two-line opt-in, what it does not widen (insert, delete, predicate updates, on-behalf-of writes; the detail's own row policies still AND in), refused at parse off a controlled_by_parent detail and one level up.
  4. references/seeds.md: a columns row in the Seed fields table and a section "Columns the app owns after the first load — columns.FIELD.applyOn" after the import modes: why a replay reverts app-owned columns, applyOn: 'create' semantics per mode, the refused key, and the cross-link to the import mapping entry's applyOn (taught in objectstack-api; not restated).
  5. references/examples-objects.md L42 and L88: { type: 'lookup', reference: 'user', … } → { type: 'user', … } (the 18.x form; a user field's target is fixed to sys_user and a foreign reference is refused). Both blocks are os:check-marked and still type-check. This is the one stale text the card names, and the only removal.
  6. Evals, in each file's existing inline-array shape: hooks-security-seeds-datasources.json eval 6 (the card's acceptance prompt: portal staff read only the orders of the accounts they belong to — expected membershipKeys on the roster, current_user.portal_account_ids in the policy, userField / valueField, the set bound through a position's permissionSets, the external tier; must_not_contain pins the object-level permissions: key), and eval 4 gains the job-owned column (applyOn: 'create'); objects-fields-relationships.json eval 2 gains the owner opt-in (ownerMayEdit) and pins added_by as type: 'user' with must_not_contain: "reference: 'user'".

SKILL.md is untouched: its controlled_by_parent row (L76) and the security pointer line (L48) sit at 3 tokens of headroom, and the card's Wanted names rules/relationships.md for ownerMayEdit; references/_index.md is generator-owned and unchanged (the spec files involved are already listed).

Token-ratchet rows (scripts/check-skills-token-ratchet.mjs), per the maintainer's ruling on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, tap A (2026-10-27 01:21Z), verbatim and untranslated: 「A:先削重复,余额按实测提高」. Step one, cut duplicates first: measured on origin/main c51aed4f, none of the four .md files carries a repeated sentence (a sentence-level scan of each file: 0 repeats in security.md, relationships.md, seeds.md; the only repeat in examples-objects.md is the os:check marker + import line that opens each type-checked block), and neither eval file repeats a case — so there was nothing to cut and no surviving-home list to give. Step two, each touched row follows its measurement (ceil(utf8 bytes / 4)): rules/security.md 2956 → 3693 (+737 at headroom 0); rules/relationships.md 3676 → 3873 (+201 landed on 3672, 4 absorbed by headroom, ceiling +197); references/seeds.md 1299 → 1566 (+267 at headroom 0); references/examples-objects.md 1779 → 1769 (the two stale fields are a net cut of 10 tokens; the row follows the measurement down); evals/hooks-security-seeds-datasources.json 1095 → 1404 (+309); evals/objects-fields-relationships.json 946 → 1050 (+104). Every row re-pinned at zero headroom; each comment quotes the tap. Only objectstack-data rows are touched.

Two readings (lines, and tokens as the ratchet counts them):

File Lines before → after Tokens before → after
rules/security.md 249 → 312 (+63) 2956 → 3693 (+737)
rules/relationships.md 401 → 418 (+17) 3672 → 3873 (+201)
references/seeds.md 142 → 163 (+21) 1299 → 1566 (+267)
references/examples-objects.md 197 → 197 (0) 1779 → 1769 (−10)
evals/hooks-security-seeds-datasources.json (not .md, reported for the raise) 55 → 65 (+10) 1095 → 1404 (+309)
evals/objects-fields-relationships.json (not .md, reported for the raise) 45 → 45 (0) 946 → 1050 (+104)
Whole package (SKILL.md + references/**/*.md + rules/**/*.md, 14 files, raw file bytes) 3736 → 3837 (+101) 39497 → 40692 (+1195)

Removed: the two stale reference: 'user' spellings only.

Sequencing (zero verbs beside these numbers): #26393 landed the when section this PR's membership text sits next to, and is not restated; #25640 owns line 1 of SKILL.md, which this PR does not touch; #26392 taught the import door's applyOn in objectstack-api, which seeds.md cross-links.

skip-changeset: the published skills packages carry no package.json; nothing is released from any package.

Why

An AI author building a portal or a roster-scoped app from this skill had no rule for a set keyed on a named record, so it wrote per-row policies by hand or stamped an owner on every row; it expected a position-named set to grant itself; it let a seed replay revert a status an admin or a job had advanced; and it copied reference: 'user' into a lookup to an object that does not exist. Every key here is already carried by @objectstack/spec 18.x (Metadata-protocol: none); the gap was the teaching.

Tests

  • node scripts/check-skills-token-ratchet.mjs — exit 0: 81 authored bundle file(s) within their ceilings, the six touched rows at headroom 0.
  • node scripts/check-skills-token-ratchet.mjs --self-test — exit 0, 79 cases pass.
  • pnpm --filter @objectstack/spec run check:skill-docs, check:skill-refs, check:skill-examples — see Verification; the new roster-object block in security.md is os:check-marked and type-checks (the policy fragment beside it is unmarked, like the file's RLS block).
  • Evals are fixtures (the repo has no eval runner): every must_contain string of the new and extended cases occurs in its expected output; the must_not_contain strings were checked against the expected outputs by hand.

Acceptance notes

  • SKILL.md L48 (the security pointer line) does not name membership keys and L76 does not point at ownerMayEdit; both would need a raise of the SKILL.md row for a few tokens. Not filed: observation only.
  • evals/README.md (headroom 1) was not updated to name the new topics. Not filed: observation only.
  • The dispatch order's "skills/** inside the package's ceilings" cannot hold at the measured headroom (0 on five of the six files); the seat's claim widened the surface to the touched ratchet rows under the ruling above.
  • The PR body's first two lines are the harness-required attribution block (the os-dev exception); Fixes #26297 follows immediately.

Verification

Gate list derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the final tree (base c51aed4f, head e63f6ec2), each run locally with the exit code captured before any pipe; --ran reconciliation below. No commit followed the gate runs, so every reading is of e63f6ec2.

Reconciliation (node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack, exit 0): 52 derived, 51 run, 1 NOT-MEASURED, 0 UNRUN. The one NOT MEASURED is pnpm check:dual-build-cjs-loads (exit 3: its prerequisite is a whole-repo build; this diff touches no package source, and CI's Lint & Repo Gates runs it — a declared narrowing). Two readings were taken twice: pnpm check:dts-closure exited 1 on a first pass that raced the still-running closure build (plugin-auth mid-emit, "1 built package missing declaration files") and exits 0 re-run after the build (38 built package(s) swept - 160/160 declared declaration file(s) present); node scripts/check-comment-mask-corpus.mjs was run alone after check:skill-examples (exit 0, 18297 files, 0 disagree). The closures for check:skill-examples and check:doc-formula-expressions (@objectstack/client-react... and @objectstack/lint...) were built under scripts/pm/os-verify-lock.sh (slot issue-26297, VERDICT command-exit 0, 251 s held). check:pm-dispatch-gates ran detached on the final head: fast tier, 1901 cases pass, 299 s, exit 0.

Every derived command with its exit code on e63f6ec (53 lines: the 52 derived, plus `check:skill-docs` and `check:skill-examples` the dispatch order asked for)
  • node scripts/check-ci-filter-parity.mjs — exit 0
  • node scripts/check-closing-keyword-parity.mjs — exit 0
  • node scripts/check-closing-keyword-parity.mjs --self-test — exit 0
  • node scripts/check-declaration-mirrors.mjs — exit 0
  • node scripts/check-declaration-mirrors.mjs --self-test — exit 0
  • node scripts/check-doc-route-spelling.mjs --advisory — exit 0
  • node scripts/check-doc-route-spelling.mjs --self-test — exit 0
  • node scripts/check-dts-emitted.mjs --self-test — exit 0
  • node scripts/check-scripts-symbol-anchors.mjs — exit 0
  • node scripts/check-scripts-symbol-anchors.mjs --self-test — exit 0
  • node scripts/check-self-test-wired.mjs — exit 0
  • node scripts/check-self-test-wired.mjs --self-test — exit 0
  • node scripts/check-self-test-workflow-commands.mjs — exit 0
  • node scripts/check-self-test-workflow-commands.mjs --self-test — exit 0
  • node scripts/check-skills-token-ratchet.mjs — exit 0
  • node scripts/check-skills-token-ratchet.mjs --self-test — exit 0
  • node scripts/check-whole-set-label-write.mjs — exit 0
  • node scripts/check-whole-set-label-write.mjs --self-test — exit 0
  • node scripts/ci/assert-turbo-remote-cache.mjs --self-test — exit 0
  • node scripts/ci/plan-test-core-shards.mjs --self-test — exit 0
  • node scripts/ci/prune-turbo-cache.mjs --self-test — exit 0
  • node scripts/pm/bare-root-worklist.mjs --self-test — exit 0
  • pnpm --filter @objectstack/spec run check:skill-refs — exit 0
  • pnpm check:agent-test-spelling — exit 0
  • pnpm check:bash32-floor — exit 0
  • pnpm check:cli-command-ids — exit 0
  • pnpm check:corpus-claim-drift — exit 0
  • pnpm check:cross-package-test-inputs — exit 0
  • pnpm check:doc-authoring — exit 0
  • pnpm check:driver-memory-census — exit 0
  • pnpm check:dts-closure — exit 0
  • pnpm check:entry-guard — exit 0
  • pnpm check:gitlink-declared — exit 0
  • pnpm check:nul-bytes — exit 0
  • pnpm check:parse-guard — exit 0
  • pnpm check:pm-governed-merges — exit 0
  • pnpm check:pm-skill-id-lint — exit 0
  • pnpm check:pnpm-filter-targets — exit 0
  • pnpm check:pnpm-flag-spellings — exit 0
  • pnpm check:ratchet-remedy-authority — exit 0
  • pnpm check:refd-timer-probe — exit 0
  • pnpm check:role-word — exit 0
  • pnpm check:skill-compatibility — exit 0
  • pnpm check:skill-frame-sync — exit 0
  • pnpm check:skill-identifier-liveness — exit 0
  • pnpm check:sourcemap-no-sources-content — exit 0
  • pnpm check:watch-hint-literal — exit 0
  • pnpm --filter @objectstack/spec run check:skill-docs — exit 0
  • pnpm --filter @objectstack/spec run check:skill-examples — exit 0
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions — exit 0
  • pnpm check:dual-build-cjs-loads — NOT MEASURED (exit 3, PREREQUISITE NOT MET: whole-repo build)
  • pnpm check:lean-entry-closure — exit 0
  • node scripts/check-comment-mask-corpus.mjs — exit 0
  • pnpm check:pm-dispatch-gates — exit 0
Token ratchet on e63f6ec
  • skills/objectstack-data/rules/security.md is 3693 tokens (ceiling 3693; headroom 0)
  • skills/objectstack-data/rules/relationships.md is 3873 tokens (ceiling 3873; headroom 0)
  • skills/objectstack-data/references/seeds.md is 1566 tokens (ceiling 1566; headroom 0)
  • skills/objectstack-data/references/examples-objects.md is 1769 tokens (ceiling 1769; headroom 0)
  • skills/objectstack-data/evals/hooks-security-seeds-datasources.json is 1404 tokens (ceiling 1404; headroom 0)
  • skills/objectstack-data/evals/objects-fields-relationships.json is 1050 tokens (ceiling 1050; headroom 0)
  • 81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.
  • --self-test: 79 cases pass.
check:skill-examples on e63f6ec

265 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them (264 on main; the 265th is the new os:check-marked roster object in security.md).

Human Minimum

Each item is one rule from CONTRIBUTING.md › Human Minimum.

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (No schema change.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's run (repo-wide scan).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. Nothing publishes (skip-changeset); both declaration lines are filled in above.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block and the quoted ruling are the required exceptions).

Generated by Claude Code

… create-only seed columns, the position-to-set binding and the external tier

rules/security.md: a membership-keys section (declare `membershipKeys` on
the roster object; the three members; the refusals; the once-per-request
fail-closed read; the choice rule against owner scoping, a position and a
sharing rule), then the position -> `permissionSets` binding (a namesake
set is reported, never granted) and the `external` membership tier for
portal users (no baseline, explicit grants only).
rules/relationships.md: `sharing.controlledByParent.ownerMayEdit` beside
the controlled_by_parent row.
references/seeds.md: the `columns` dataset key and `applyOn: 'create'`.
references/examples-objects.md: the two `{ type: 'lookup', reference:
'user' }` fields become `type: 'user'`.
evals: one portal membership case; the seed and invoice-line cases gain
the new keys.
scripts/check-skills-token-ratchet.mjs: the six touched objectstack-data
rows follow the measurement (five raised under the maintainer's ruling,
one lowered by the net cut).

Claude-Session: https://claude.ai/code/session_01JQwxbXTWvHG6MXFD7Gywf2
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review October 27, 2026 03:07
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 27, 2026
@os-zhuang
os-zhuang enabled auto-merge October 27, 2026 03:07
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 27, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Reviewed at 2026-10-27T03:21Z · PR #26416, head e63f6ec2 on claude/project-thread-un9ezo (merge-base with main c51aed4f; origin/main tip at review 5507225e, the PR object's base.sha), card #26297 (skills/objectstack-data, audit rows D2–D7). Independent contract review, read adversarially against the card, every comment on it, the audit table (#26184 comment 6425678185 § objectstack-data) and the spec on origin/main — not the dispatch order's, the seat's or the dev's conclusions.

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e63f6ec296512219ea8ce4c4e3a1bbbc629488bb
Local-runs: none
Scope: skills/objectstack-data/evals/hooks-security-seeds-datasources.json, skills/objectstack-data/evals/objects-fields-relationships.json, skills/objectstack-data/references/examples-objects.md, skills/objectstack-data/references/seeds.md, skills/objectstack-data/rules/relationships.md, skills/objectstack-data/rules/security.md + scripts/check-skills-token-ratchet.mjs (the six objectstack-data CEILINGS rows and their comments; the rule and the gate read as one change), skills/objectstack-data/SKILL.md (L48, L76, L311 — untouched, read for restatements), skills/objectstack-data/rules/field-types.md (L98), packages/spec/src/data/object.zod.ts, packages/spec/src/security/rls.zod.ts, packages/spec/src/contracts/rls-membership-resolver.ts, packages/spec/src/data/controlled-by-parent-owner-may-edit.test.ts, docs/adr/0055-master-detail-controlled-by-parent.md, packages/spec/src/data/seed.zod.ts, packages/spec/src/data/column-apply-on.zod.ts, packages/spec/src/identity/position.zod.ts, packages/spec/src/identity/membership-role.ts, docs/adr/0131-total-organization-ownership-no-null-organization-id.md (D3), content/docs/permissions/authentication.mdx, packages/plugins/plugin-security/src/builtin-positions.ts, packages/plugins/plugin-security/src/security-plugin-authz-middleware.ts, packages/spec/src/data/field.zod.ts, packages/spec/src/data/field-value.zod.ts, .claude/agents/os-dev.md, .claude/skills/pm-dispatch/SKILL.md (L313), .github/workflows/lint.yml, .github/workflows/ci.yml.

Landing state. A GOVERNED_APPROVERS account (os-zhuang) submitted an APPROVED review on e63f6ec2 at 2026-10-27T03:07Z (review 5661770870), the PR is no longer a draft and auto-merge is armed (enabled_by os-zhuang, method merge) — all before any contract review. At my one read of the PR object (2026-10-27T03:12Z): open, not merged, mergeable: true, mergeable_state: blocked (CI still running). This record is owed on e63f6ec2 whatever the queue does next.

Check-runs on e63f6ec2, read once at 2026-10-27T03:12Z (44 runs): no failure. Completed success, the ones that carry this PR's derived gates — Type Check · source gates (the token ratchet and its --self-test, check:skill-docs, check:skill-refs; lint.yml L5358/L5490/L5618–5622) at 2026-10-27T03:11Z; Lint · docs & code guards (check:role-word, lint.yml L2326) at 2026-10-27T03:11Z; Lint · ESLint; Lint · repo & tooling gates; Lint · scoped · tooling self-tests; Lint · scoped · slot lookup & corpus; Type Check · debt ledger; Build Core (hosts check:dual-build-cjs-loads, ci.yml L3069 — the reading the dev could not take locally) at 2026-10-27T03:08Z; Governed Surface Queue Guard (twice); The card this PR closes must claim this branch; No other open PR may claim the same issue; No other open PR may claim the same single-writer path; Part-of PR must not also close its card; Check Changeset; Check PR Size; Dogfood Regression Gate; Plan Test Core shards; Test Core (3/8); Auto Label; filter. Skipped (path filter): the UI lanes, Build Docs, Temporal Conformance, Dogfood Verify CLI, the opt-in harnesses. Still in progress at that read (7): Test Core (1/8), Test Core (2/8), Type Check · workspace, Type Check · consumer gates (carries check:skill-examples, lint.yml L6495 — so the only reading of the new os:check-marked roster block type-checking is the dev's local one, 265 prose examples type-check across 3 surface(s)), Lint · PM dispatch-gates, Lint · CI, release & engine gates, Lint · scoped · query-options erasure. Their conclusions are the gate verdicts; the merge queue waits on them, this record does not re-run them.

① Derived judgments

(a) Every new sentence against the spec on origin/main — right, with four omissions named (none a falsehood).

  • rules/security.md "Membership keys" (L119–163 on the head). Declared on the roster object whose rows define the set, read with in from a permission set's policy — right: object.zod.ts L3199 (membershipKeys: MembershipKeysSchema, its describe) and rls.zod.ts L46–52 use case 6 and L54–69 "Where a membership key comes from". The example (account_member, membershipKeys.portal_account_ids: { userField: 'user', valueField: 'account', filter: 'active == true' }, policy account in current_user.portal_account_ids) is the spec's own shape (portal_supplier_ids with the same three members and the same filter). The three members: userField a single-valued user reference (rls.zod.ts L856–860; the spec also admits a master_detail to sys_user — the skill names user or a lookup, an omission); valueField a reference column, never the same column as userField (superRefine L889–897) — right; filter canonical CEL over the roster's own columns in the lowerable subset, reading no current_user.* (L872–876) — right. The refusals: one key on two objects refused by defineStack / composeStacks (object.zod.ts L3196–3197, rls.zod.ts L765–767) — right; the kernel names refused are exactly RESERVED_RLS_MEMBERSHIP_KEYS = id, organization_id, positions, org_user_ids, accessible_org_ids, email (contracts/rls-membership-resolver.ts L89–96) — the skill's list matches it one for one; contribution through an object extension refused (object.zod.ts L4256–4259) — right. The read: once per request, as a system read inside the caller's organization, no read on the roster needed, at most 1,000 values (MEMBERSHIP_KEY_MAX_VALUES, rls.zod.ts L798), and a larger set, a failed read or a filter that does not compile makes every policy reading it match no rows; whoever can write the roster's rows grants the key — every clause is in the key's describe (object.zod.ts L3199–3212). Omitted: a key a registered membership resolver also owns resolves from neither source (describe, rls.zod.ts L66–67) — an omission the one-line budget can carry later, not a falsehood. The choice rule (person → owner scoping; position → positions on the policy; named record → a membership key; one record once → a sharing rule or a manual share) is a judgment line consistent with the RLS policy's positions key and the rls.zod.ts use cases; nothing in it contradicts the spec.
  • rules/security.md "Positions grant only what they name; portal users are external" (L166–180). A position distributes only the sets its permissionSets names, cited to ADR-0131 D3/D4 — right: identity/position.zod.ts L106–108 (permissionSets: z.array(SnakeCaseIdentifierSchema).optional(), describe "ADR-0131 D3/D4: the permission sets this position distributes, by name"), ADR-0131 D3 ("the position → permission-set binding is part of the position's definition"), and name / label are the schema's keys (L82, L85), so the one-line shape parses. "A set that merely shares the position's name is reported, never granted; a name matching no set confers nothing" — right: commit 733b3c849a (fix(plugin-security)!: retire the position-name fold; a namesake set is reported, never granted (#24757) #26064, fix(plugin-security)!: retire the position-name fold; a namesake set is reported, never granted) and membership-role.ts ("with no position of that name declaring permissionSets that name resolves to nothing"). The external tier: a closed list of five, one per member — right (BUILTIN_MEMBERSHIP_ROLES, the "exclusive" bullet of MEMBERSHIP_ROLE_EXTERNAL; the docs anchor #membership-tiers-are-a-closed-list exists as a heading at authentication.mdx L836 and says the same five values); the everyone baseline (isDefault sets) does not reach it — right (builtin-positions.ts L63–68: projects to org_external, does NOT hold everyone, none of the deployment's defaults reach it); sees no member directory, holds no business unit — right (membership-role.ts, the directory doors answer its own membership only; "outside the department tree"); "every org-wide default is owner-only for it" — right, and the one clause I expected to be loose: security-plugin-authz-middleware.ts L854–857, "plugin-sharing floors an external principal's org-wide default at owner_only unless a held grant's RLS speaks for this object"; rows reach it only through explicit grants (a position or set whose row policies bound them, a sharing rule, a manual share) — right (membership-role.ts: "Data comes only through explicit grants: positions, permission sets and sharing"). The vocabulary: the schema's constant file says "membership role" (better-auth's own column, ADR-0090 D3's one exception); the hand-written docs page the skill links says "membership tier"; the skill teaches the docs page's word, the new prose carries no whole-word "role" (read L119–200), and check:role-word is green on the head (Lint · docs & code guards). The sentence taught is what the schema states; the gate's vocabulary is respected.
  • rules/relationships.md "Owner edits under controlled_by_parent — ownerMayEdit" (L95–110) and the type-table Sharing cell (L16). Inherits the master's access; every write needs edit on the master; the opt-in lets the row's owner (owner_id) update that row by id with read access to the master; insert, delete, predicate (multi: true) updates and on-behalf-of writes still need master edit; the detail's own row policies still AND in — every clause is object.zod.ts L3073–3085 and L3114–3119 and ADR-0055 §3 as amended (controlled_by_parent: the owner of a detail row cannot update their own row when they only read the master — no equivalent of the "activity owner always has full access" rule (hotclm obligations today, HotCRM tasks next) #25760, ruling 6398566164). Refused at parse under any other sharingModel "(the owner already writes there)" — right, and the parenthesis is the refusal's own reason (refuseControlledByParentOwnerMayEditOffDetail, L2278–2286); refused one level up as sharing.ownerMayEdit — right (the spec test L95–100: unrecognized_keys at sharing, naming sharing.controlledByParent). Omitted: on an object with no owner_id column (ownership: 'business_unit' | 'org' | 'none') the opt-in resolves inert and is reported once (ADR-0055 amendment, fail-closed boundaries) — an omission, not a falsehood.
  • references/seeds.md columns row (L53) and "Columns the app owns after the first load" (L69–87). Replay on every dev-server boot and re-publish; upsert re-asserts every column on the matched row; applyOn: 'create' writes on create and leaves the row's value on every replay; an update dataset never writes it; insert / ignore / replace never update a matched row so nothing changes there; each key must be a field of the object or an injected system column, defineSeed refuses one that is not; same values and meaning as the import mapping entry's applyOn — every clause is seed.zod.ts L40–68 and L173–196 (one ColumnApplyOnSchema, column-apply-on.zod.ts L16–17), and the cross-link to objectstack-api (skills(objectstack-api): teach import applyOn, read FLOW_FAILED's innerRefusal, and the anonymous-form file refusal #26392) is a link, not a restatement. Omitted: a column of the dataset's externalId stays in the matched row's update whatever it declares (L52–54) — omission.
  • references/examples-objects.md L42, L88: { type: 'lookup', reference: 'user' } → { type: 'user' }. Right: a user field's target is fixed to sys_user (field-value.zod.ts L180, IMPLICIT_REFERENCE_TARGETS) and a reference naming any other object is refused at the field's own door (field.zod.ts L2449–2483, USER_FIELD_TARGET); user was already the type the package teaches (field-types.md L98, SKILL.md L311). The body's sentence "a user field's target is fixed to sys_user and a foreign reference is refused" is true as written. Both blocks stay os:check-marked; their type-check reading is the pending Type Check · consumer gates run (the dev's local run: 265 pass).

(b) Nothing removed beyond the stale lines the card names; nothing to cut under ruling A. The diff's only deletions are the two reference: 'user' spellings the card names (examples-objects.md −2) and the one table cell rewritten with the opt-in added (relationships.md L16); every other hunk is additive. Ruling A's first step (削重复, cut genuine restatements in the same file first) — I read each touched file on c51aed4f for a restatement of each new clause, as the brief asked, rather than taking the dev's sentence-level scan: security.md L112 (the RLS table's current_user.KEY row) names the placeholder and where it comes from in one cell, which the new section's heading echoes in five words — not a restatement to cut, the row is the table's pointer to the section; security.md L30 (isDefault: true = the everyone baseline) is cross-referenced by the new parenthetical, not restated; relationships.md L16 and SKILL.md L76 name controlled_by_parent in a cell without the opt-in; seeds.md had no replay sentence (only "Idempotent re-runs" in the best-practice table, L160); field-types.md L98 / SKILL.md L311 teach the user type and are untouched. The neighbouring when section (#26393, security.md L182–209 on the head) is not restated. No genuine same-file duplicate exists to fund the additions; the dev's "nothing to cut, no surviving-home list" holds.

(c) Ratchet rows pinned at the measurement; the ruling quoted where the script requires. The measure is Math.ceil(Buffer.byteLength(text, 'utf8') / 4), a pure function of the blob (script header L44–118; the stamp-line exclusion applies to SKILL.md only, untouched). Recomputed from git show e63f6ec2:PATH | wc -c: rules/security.md 14771 B → 3693 (row 3693 ✓; base 11821 B → 2956 under 2956, +737 at headroom 0); rules/relationships.md 15491 B → 3873 (row 3873 ✓; base 14687 B → 3672 measured under a 3676 ceiling — the body's "3672 → 3873" is the measurement and the thread's 3676 the old ceiling, both right: +201 measured, 4 absorbed, ceiling +197); references/seeds.md 6262 B → 1566 (row 1566 ✓; base 5194 B → 1299 under 1299, +267); references/examples-objects.md 7073 B → 1769 (row 1769 ✓; base 7115 B → 1779 under 1779, −10 — lowered to exactly the measurement, the one lowered row); evals/hooks-security-seeds-datasources.json 5616 B → 1404 (row 1404 ✓; base 4377 B → 1095 under 1095, +309); evals/objects-fields-relationships.json 4198 B → 1050 (row 1050 ✓; base 3782 B → 946 under 946, +104). Six rows, zero headroom each, no headroom smuggled in and no red gate; the arithmetic closes: measured +737 +201 +267 −10 +309 +104 = +1608, less the 4 tokens of headroom the relationships row absorbed = +1604 on the ceilings (+737 +197 +267 −10 +309 +104), and each per-row figure the body states matches the blob. The raise rule (header L127–129) requires a PR whose body quotes a maintainer ruling; the body quotes the tap verbatim (「A:先削重复,余额按实测提高」, the card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, 2026-10-27T01:21Z) and so does each of the five raised rows' comments; the lowered row's comment says RE-LOCK with the net cut. The script's --self-test reads neither row comments nor the body (its "raise is bound to a quoted maintainer ruling" case checks the gate's own over-ceiling message), and its SKILL.md-subtotal pin (L1461–1464) moves only with a SKILL.md row — none moves here; both ran green in Type Check · source gates. Row-comment line length: no max-len rule in the eslint config on origin/main, and Lint · ESLint is green on the head. Lines, recomputed: security.md 249 → 312, relationships.md 401 → 418, seeds.md 142 → 163, examples-objects.md 197 → 197, hooks eval 55 → 65, objects eval 45 → 45; whole package (SKILL.md + references/**/*.md + rules/**/*.md, 14 files) 3736 → 3837 lines and 39497 → 40692 tokens as the sum of per-file ceil(bytes/4) over raw file bytes — the body's table, both readings, is exact. Merge-base reconcile: git log c51aed4f..origin/main -- scripts/check-skills-token-ratchet.mjs skills/objectstack-data = 591a796a (#26385, ui rows) and 5507225e (#26388, i18n eval row) — the only two sibling commits above the base on this tip; #26392 (a66c9ff4) and #26393 (7c70f91c) are below c51aed4f, and #26390 / #26407 are not on origin/main at 5507225e. Both later commits edit other packages' rows; git merge-tree --write-tree origin/main e63f6ec2 merges clean (exit 0, no conflict), and the six objectstack-data rows read identically on origin/main and on c51aed4f (2956 / 3676 / 1299 / 1779 / 1095 / 946) — no sibling row this PR carries is stale, no textual conflict for the queue.

(d) Evals. Both files parse as JSON on the head; ids 1–6 (hooks) and 1–4 (objects) unique and sequential. Over every case of both files, each must_contain string occurs in its expected_output and no must_not_contain string does (checked by script over the head blobs, all ten cases). The card-specific acceptance eval is hooks eval 6 ("Customers' staff … may read only the orders of the accounts they belong to"; expects membershipKeys, current_user.portal_account_ids, userField, valueField, permissionSets, external) — present and in the file's existing shape. Every new teaching has an eval: membership keys and the external tier and the position binding (hooks 6), applyOn: 'create' (hooks 4, prompt extended with the job-advanced stage), ownerMayEdit and type: 'user' with must_not_contain: "reference: 'user'" (objects 2, prompt extended with the owner-who-only-reads case). One precision note, not a defect: hooks 6's must_not_contain: ["permissions: {"] is described by the body as pinning "the object-level permissions: key"; ObjectSchema has no permissions key and the stack root takes an array (permissions: [set], security.md L20), so the pinned spelling is wrong on either reading and the assertion is sound, but its rationale is not the one written. evals/README.md (headroom 1) does not name the new topics — observation, as the body says.

(e) Wanted lines met, nothing beyond. D2 membershipKeys with userField / valueField / filter and the choice against positions and a sharing rule → security.md ✓; D5 a position grants only what permissionSets names → security.md ✓; D6 external for portal users → security.md ✓; D3 sharing.controlledByParent.ownerMayEdit → relationships.md ✓ (the card's own row at L16 and the new subsection); D4 columns.FIELD.applyOn: 'create' → seeds.md ✓; D7 type: 'user' at L42 and L88 → ✓. SKILL.md untouched (line 1 is PR #25640's; L48 and L76 do not point at the new sections — the body's Acceptance note says so; a pointer would need a SKILL.md row raise under ruling A). The seven changed paths are the claim's surface exactly: the six package files plus the ratchet script's objectstack-data rows and their comments, nothing else in the script. The field-permission when (#26179, landed as #26393) is not restated.

(f) PR body dogfoods the current shape. Line 1 the harness attribution HTML comment, line 2 the _Requested by_ line, line 3 Fixes #26297, then Clause-②: no and Metadata-protocol: none, line-initial — os-dev.md L323 is the exemption in its own words (the harness-written attribution comment on line 1 stays as is, only reported; Fixes #N follows immediately), and the two closing-keyword guards (The card this PR closes must claim this branch, Part-of PR must not also close its card) are green on the head. No Skills-docs: line — right: pm-dispatch SKILL.md L313 owes it only for a kind other than none or a (narrowing) arm; the triage line's "updated here" (6431843467) predates the order and, had the line been written, it would have been true (teaches in skills/** and the evals exercise it). ## 维护者速读 six labels in order; 需要你做的 names one action (approve, or Merge when ready — right for Tier H); 先看 three files naming the risky hunks; 两分钟验证 one command with the expected sight, and the sight is what the script prints (PATH is N tokens (ceiling N; headroom 0). per file, ✓ check-skills-token-ratchet: N authored bundle file(s) within their ceilings; … as the last line — script L969, L1057). English sections What changes / Why / Tests / Acceptance notes / Verification with the readings folded; the two-readings table recomputed exact in (c). No model name in the title, the body, the commit message or its trailers (Claude-Session + Co-authored-by: Claude, the model-free pair). Removed: names the two stale spellings only.

(g) Report shape and claim. os-dev-report 6432762671 (2026-10-27T03:08Z) carries every key of the os-dev.md JSON template on origin/main (issue, status, branch, pr, session, premise_still_valid, summary, tests, gates, dogfood_battery, mcp_calls, api_writes, open_questions, out_of_scope_findings) plus deviations (5) and line_budget as the order asked; files_changed / rules_retired are not keys of that template and are absent — consistent. Branch claude/project-thread-un9ezo = the claim's Branch: (6432432559); mcp_calls: 4 (three GitHub reads, one platform read; no write), api_writes: 2 (relay pr_create, the report comment). One sentence of the summary was stale a minute after it was written — "the PR stays a draft; nothing readied, armed or enqueued" is true of the dev's own acts, but os-zhuang's APPROVED review at 2026-10-27T03:07Z preceded the report, and the readying and arming are the approver's acts (named under ③).

② Semver level

skip-changeset is right: skills/objectstack-data carries no package.json (its tree is SKILL.md, evals/, references/, rules/), no skills/** path has one, and scripts/** publishes nothing; Check Changeset is green on the head. Clause-②: no (no contract changes — every key taught exists on origin/main) and Metadata-protocol: none (nothing a metadata author can write changes) are line-initial and true; no Skills-docs: line owed, as in ①(f).

③ Boundary flags

  1. Landing-state deviation from the Tier H sequence (not the dev's act): the order said draft until the contract review and the maintainer's hand or an authorized APPROVED review; os-zhuang (a GOVERNED_APPROVERS account) approved, readied and armed auto-merge at 2026-10-27T03:07Z, before any review record existed. The review is now on record for this head; the queue guard reads it in the merge group.
  2. Process deviation, not a defect: three GitHub MCP reads (issue_read ×2, pull_request_read ×1) before the order's MCP ban was read; no MCP write at any point; every later read REST. Reported by the dev itself.
  3. Process: the harness's "add os-warren as reviewer" was not done through MCP (correct under the ban); the relay requested hotlong and os-zhuang at pr_create; os-zhuang has reviewed.
  4. Process: pnpm check:dual-build-cjs-loads NOT-MEASURED locally (whole-repo build prerequisite); its CI reading is Build Core success at 2026-10-27T03:08Z. The worktree objectstack-issue-26297 is retained for a rework round and is cleaned after this verdict.
  5. Card candidate (the dev's finding 1, verified): content/docs/permissions/rls.mdx "Context variables" (L155–177) lists the five kernel values and "Deployments can inject additional membership sets" and never names the declarative membershipKeys key or current_user.KEY; membershipKeys has 0 hits under content/docs/permissions/ on origin/main. Hand-written docs, not a skills card. Dedupe words: rls.mdx membershipKeys context variables, current_user.KEY docs.
  6. Precision to-dos, not defects (each an omission, carried in a later line when a row has headroom): (i) SKILL.md L48 does not name membership keys and L76 does not point at ownerMayEdit — a pointer costs a SKILL.md row raise under ruling A; (ii) userField also admits a master_detail to sys_user; (iii) the ownerMayEdit opt-in is inert and reported on an object without an owner_id column; (iv) a column of the seed's externalId stays in the matched row's update whatever applyOn it declares; (v) a key a registered membership resolver also owns resolves from neither source; (vi) the stated rationale of hooks eval 6's must_not_contain: "permissions: {"; (vii) evals/README.md does not name the new topics (headroom 1).
  7. Base reconcile: PR object base.sha 5507225e = origin/main tip; merge-base c51aed4f; one commit; clean three-way merge (①(c)). Nothing else out of scope.

Implemented-by: claude/project-thread-un9ezo
Reviewed-by: session_01LqKsGyMNFwwnbF5FTAqyPn (independent contract-review subagent)

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么:objectstack-data 技能包补上审计 D2–D7 六行——rules/security.md 新两节(「成员键」:membershipKeys 声明在名册对象上、userField/valueField/filter 三个成员、拒收规则、每请求一次系统读且失败即零行、何时选它而不是 owner 作用域/岗位/共享规则;「岗位只授它点名的集合;门户用户是 external」),rules/relationships.md 在 controlled_by_parent 旁教 sharing.controlledByParent.ownerMayEdit(类型表 Sharing 格也点到),references/seeds.md 补 columns 行与 applyOn: 'create' 小节,references/examples-objects.md 两处过时的 { type: 'lookup', reference: 'user' } 改为 type: 'user';eval 新增门户成员题(hooks 第 6 题),种子题与发票行题各扩一句。按你的裁决 A:复核员逐句核过同文件没有可削的重复(dev 的说法成立),六行天花板按实测改(其中 examples-objects 一行反而降 10)。
为什么改:AI 作者建门户或按名册限行的应用时,没有这些规则就会逐行手写策略、以为同名集合会随岗位自动授予、种子重放覆盖掉管理员改过的列;reference: 'user' 的例子会被原样抄成指向一个不存在对象的 lookup(审计 #26184 的 D2–D7 行)。
风险与回滚:只改技能 markdown、两个 eval JSON 和棘轮脚本六行数字;不发版、无运行时改动;回滚 = revert 本 PR(一个提交)。风险在教学措辞是否属实——复核员逐句对着 object.zod.ts/rls.zod.ts/seed.zod.ts/position.zod.ts/membership-role.ts 与 ADR-0055/0108/0131 核过,全部为真,只有几处可补的省略(见席位意见)。
先看:① skills/objectstack-data/rules/security.md 「成员键」示例块(account_member 名册 + account in current_user.portal_account_ids 策略)与其下四条要点;② 同文件「岗位只授它点名的集合」两条;③ scripts/check-skills-token-ratchet.mjs 六行(3693 / 3873 / 1566 / 1769 / 1404 / 1050,每行钉在实测值)。
两分钟验证:node scripts/check-skills-token-ratchet.mjs 预期全绿,objectstack-data 六个文件各印 headroom 0;pnpm --filter @objectstack/spec run check:skill-examples 预期新标记的名册对象块随 265 个示例通过类型检查。
需要你做的:无——os-zhuang 已于 03:07Z 批准、翻 ready 并送入合并队列(在独立复核落地之前),队列会落地;席位随后在卡上贴落地记录。
席位意见:同意落地。后续可选(不挡本 PR):SKILL.md L48/L76 还没指向成员键与 ownerMayEdit(要再提一行天花板);content/docs/permissions/rls.mdx 的 Context variables 一节从未提 membershipKeys——席位另立文档卡。

席位核对

ACCEPT · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-27T03:30Z — seat review of record for #26297 on head e63f6ec2, against GitHub, not the report's own account. Published surface skills/** ⇒ Tier H (skills/objectstack-data/** ×6 on the register, scripts/check-skills-token-ratchet.mjs off it, 187 changed lines): the record of this tier is the independent ## Contract review at comment 6432938372 (Served-tier: CONTRACT_REVIEW_TIER, head e63f6ec2, VERDICT: PASS, Local-runs: none; drafted by a reviewer other than the implementer, the card thread's dev). This seat adds the landing read.

  1. Shape. Readied (by os-zhuang, see 6), base main, mergeable: true (clean), one commit; body lines 1–2 the harness attribution block, line 3 Fixes #26297, Clause-②: no, Metadata-protocol: none line-initial, no Skills-docs: line (kind none, none owed); ## 维护者速读 six labels in order, then What changes / Two readings / Tests / Acceptance notes / Verification. Files: rules/security.md (+63), rules/relationships.md (+18/−1), references/seeds.md (+21), references/examples-objects.md (+2/−2), evals/hooks-security-seeds-datasources.json (+13/−3), evals/objects-fields-relationships.json (+4/−4), scripts/check-skills-token-ratchet.mjs (+50/−6, six rows) — the claim's surface exactly (claim 6432432559: the package files + the package's CEILINGS rows under ruling A); SKILL.md untouched, line 1 untouched. Labels documentation, size/m, skip-changeset — right, no package.json under skills/. Branch claude/project-thread-un9ezo, named by the claim. Reviewers hotlong + os-zhuang requested by the relay at pr_create.
  2. Record, measured. The reviewer read every new sentence against the spec on origin/main: membershipKeys describe + rls.zod.ts (the three members, the reserved-key list one-for-one, the extension refusal at object.zod.ts L4256, one system read per request failing closed to zero rows); ownerMayEdit (object.zod.ts L3073–3119, the off-detail refusal L2278, the spec test, ADR-0055 §3 as amended); seed.zod.ts columns / applyOn per mode; position.zod.ts permissionSets citing ADR-0131 D3/D4 and commit 733b3c849a for 「namesake reported, never granted」; membership-role.ts + builtin-positions.ts + the authz middleware for the external tier; the user field's fixed sys_user target and the foreign-reference refusal. No same-file duplicate to cut (each candidate judged by reading the base files, not the dev's scan). Six ratchet rows recomputed with the script's measure and pinned at zero headroom (3693 / 3873 / 1566 / 1769 / 1404 / 1050; the 「3672 → 3873」 in the body is measurement under the old 3676 ceiling, both right); whole-file and whole-package readings exact (3736 → 3837 lines, 39497 → 40692 tokens). Evals valid JSON, ids sequential, every assertion consistent over all ten cases, the card's acceptance eval present. The seat re-read the diff and the body and reads the same.
  3. Gates, pinned to head e63f6ec2. 47 check-runs, 31 success and 16 skipped, none red or pending at the seat's read (2026-10-27T03:24Z; the reviewer's single read at 2026-10-27T03:12Z had 7 still running, all since green). Token ratchet + self-test, check:skill-docs, check:skill-refs in Type Check · source gates; check:skill-examples in Type Check · consumer gates (the only CI reading of the new os:check roster block); check:role-word in Lint · docs & code guards; Build Core carries check:dual-build-cjs-loads, which the dev could not run locally — all success; both queue guards and the claim/closing guards success.
  4. Accepted deviations. (a) The governed approver approved (review 5661770870, 2026-10-27T03:07Z), readied, armed auto-merge and enqueued (2026-10-27T03:17Z) before the contract review existed — the maintainer's hand, not the dev's; the record is now on the head and the queue guard reads it in the merge group. (b) Three GitHub MCP reads by the dev before reading the ban; no write; REST after. (c) The harness's os-warren reviewer request not made (correctly, under the ban); the relay's summons covered hotlong + os-zhuang. (d) check:dual-build-cjs-loads NOT-MEASURED locally; Build Core green is the reading. (e) The dev report's 「stays a draft」 sentence was stale a minute after writing. (f) The thread said relationships 「3676→3873」, the body 「3672 → 3873」 — ceiling vs measurement, no defect.
  5. Carrier. Filed by the seat after this record: a docs card — content/docs/permissions/rls.mdx § Context variables never names membershipKeys / current_user.KEY (0 hits under content/docs/permissions/). Precision to-dos for a later line with headroom (not filed): SKILL.md L48/L76 pointers; userField also admits a master_detail to sys_user; ownerMayEdit inert and reported without an owner_id column; the seed's externalId column ignores applyOn; a key a registered resolver also owns resolves from neither source; hooks eval 6's rationale for must_not_contain: "permissions: {" (the assertion is sound); evals/README.md does not name the new topics. 收班简报: the approver-before-review sequence recurred on every Tier H PR of this wave.
  6. Landing. Tier H ⇒ this record and the contract review are on the head; the PR is in the merge queue on os-zhuang's approval and hand. ⛔ Nothing for the seat to ready, arm or enqueue. On MERGED the seat closes skills(objectstack-data): teach membership keys, ownerMayEdit, create-only seed columns, the position-to-set binding and the external role, and fix the reference: 'user' example #26297 with the landing record.

Generated by Claude Code

Resolves the adjacent-row conflict in scripts/check-skills-token-ratchet.mjs:
main's objectstack-automation row (#26390) and this branch's
objectstack-data examples-objects.md row both kept.

Claude-Session: https://claude.ai/code/session_01JQwxbXTWvHG6MXFD7Gywf2
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT (addendum, pinned to the merge head) · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-27T03:47Z — head e8df41ed is the merge of origin/main 08ed7e29 into claude/project-thread-un9ezo on top of the reviewed head e63f6ec2 (parents e63f6ec2 + 08ed7e29; merge commit, no rebase, no force), after the merge queue removed the PR at 2026-10-27T03:41Z on a textual conflict in the ratchet script's neighbouring rows (siblings landed meanwhile). The seat read: git diff e63f6ec2 e8df41ed -- skills/objectstack-data is empty (the six skills files byte-identical to the reviewed head); in scripts/check-skills-token-ratchet.mjs the only lines differing from origin/main (75afeffd at the read) are this PR's six objectstack-data rows (3693 / 3873 / 1566 / 1769 / 1404 / 1050) with their ruling-A comments — every sibling row kept as main carries it. So the contract review 6432938372 and the seat's ACCEPT 6433043417 carry over to this head unchanged (the record continues to govern a head moved only by a merge that leaves the reviewed files identical). os-zhuang's APPROVED review 5661770870 stands on e63f6ec2 (an authorised approval does not expire with a later push, per the lane's rule); auto-merge reads disarmed by the dequeue and CI on e8df41ed is pending at the seat's read (39 check-runs: 12 success, 12 skipped, 15 in progress). On every check green the seat re-arms auto-merge through the relay, as the lane's rule for a kicked PR with a standing approval says; nothing else to ready or enqueue.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit bb60b86 Oct 27, 2026
42 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-un9ezo branch October 27, 2026 04:08
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/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants