Skip to content

docs(skills): stop teaching objectui as a separate repo, list it in the catalog index, repair dead anchors, author sharingModel in object examples - #31152

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-4ejvqq
Nov 7, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-4ejvqq

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Irene · project thread

Fixes #31114

Clause-②: no
Metadata-protocol: none

dispatch-gates --tier reads a MANDATORY model tier for skills/** (clause ① of the model-tiering ruling). The maintainer's standing order in this project (2026-11-03) waives it, and this card ran on the project's default model. The dispatching seat runs the contract review.

维护者速读

  • 改了什么:objectui 技能 README、page-builder.md 和目录 README 不再把 ObjectUI 说成独立仓库,改指本仓库 ui/ 与目录 README 的固定版本 experimental_sync 安装;build-skill-docs.ts 按“有 SKILL.md 且非 metadata.internal”收录技能,生成的索引与文档页补上 objectui;修三处死锚点;bootstrap.md 版本改为 18.3.0;relationships.md、lifecycle.md、datasources.md 的完整对象示例补 sharingModel;indexing.md 的租户列改为注入的 organization_id;objectstack-query 补 $empty;升级技能注明 objectstack-pm-dispatch 已不在 18 目录中。
  • 为什么改:UI 合入本仓库和几次“原样搬移”重构后,这些地方仍在教过时或会被拒的写法(skills: stale teaching after the ui merge and the moved-verbatim refactors — objectui as a separate repo, three dead SKILL.md anchors, bootstrap.md pins 18.1.0, examples omit sharingModel, retired plugin-ai eval, $empty untaught #31114):缺 sharingModel 的对象发布会被 security-owd-unset 拒绝;索引写未声明的 tenant_id 会被字段引用检查拒绝。
  • 风险与回滚:只改技能文字、eval、一个生成脚本及其生成产物;所有文件都在 token 上限内,未上调任何上限:七个文件(objectui/README.md、relationships.md、indexing.md、plugin-lifecycle.md、service-registry.md、objectstack-query/SKILL.md、objectstack-upgrade/SKILL.md)的增长落在既有余量内,其余靠同文件删除重复内容支付,见下文;发 @objectstack/skills patch;回滚即 revert。
  • 先看:packages/spec/scripts/build-skill-docs.ts 的收录谓词,和 skills/objectstack-data/rules/relationships.md 的 sharingModel 示例。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs 与 pnpm --filter @objectstack/spec check:skill-docs,预期都退出 0。
  • 需要你做的:skills/** 属 Tier H(人合),需要 os-zhuang 或 hotlong 的一次 approval,之后席位落地。

What changes

Every item was re-read on main before editing (the card was measured on aa3e21cc; this branch is on 9f61e06e).

1. ObjectUI is not a separate repository

Code site: the UI lives at ui/ in this repository since #25752, and packages/skills ships the objectui skill since #25832.

  • skills/README.md § Related repositories → § Related code: ui/ in this repository (link to tree/main/ui), in place of the archived objectstack-ai/objectui link.
  • skills/objectui/README.md: the skills.sh badge for objectstack-ai/objectui is removed. The install section now says the skill ships in @objectstack/skills, shows the two pinned commands the catalog README teaches (pnpm add -D "@objectstack/skills@…" + npx skills@1.7.2 experimental_sync --agent claude-code --copy -y), and links the catalog README for other package managers and agents. That link is an absolute objectstack/blob/main/skills/README.md URL: ui/scripts/check-doc-links.mjs (L732, diskRoot: '../skills/objectui') refuses a relative href that leaves the bundle, because the skill ships to customer projects as one directory. The "CLI auto-detects your agent" sentence is removed, because it is false under experimental_sync --agent. The repository link now points at ui/.
  • skills/objectui/guides/page-builder.md: the plugin-gantt README link now goes to objectstack/tree/main/ui/packages/plugin-gantt, a directory page that renders the README. That URL is 3 bytes shorter, so it fits the ceiling.

2. The catalog index lists objectui

Code site: packages/spec/scripts/build-skill-docs.ts. The startsWith('objectstack-') filter is replaced by "carries a SKILL.md and is not metadata.internal". The predicate is a copy of isMarkedInternal in packages/create-objectstack/src/template-consistency.test.ts L608, spelled the same way. DISPLAY gains { name: 'objectui', label: 'ObjectUI' }. Two parser changes were needed:

  • objectui's frontmatter description: is a plain one-line scalar, not a folded > block, and the parser read only the folded block.
  • objectui spells its clauses "Use for" / "Do NOT use". The split now matches Use (when|for) and is case-insensitive on Do not use. The first match wins, so the ten existing entries render byte-identically. The only change in the regenerated output is the added row and card, plus the count (10 → 11).

Regenerated with pnpm --filter @objectstack/spec gen:skill-docs and committed as generated: the index block of skills/README.md and content/docs/ai/skills-reference.mdx. The DECLARED_WATCH_HINTS population is unchanged: skills/*/SKILL.md already covered objectui/SKILL.md. Cross-seat note: packages/spec/scripts belongs to domain:spec, and per the triage it rides along here with no spec seat online. @objectstack/spec does not publish scripts/ (its files list), so the changeset is @objectstack/skills only.

3. Three dead anchors

  • skills/objectstack-data/references/data-hooks.md L961: the "Project hooks pattern" line pointed at ../SKILL.md#lifecycle-hooks. The data SKILL.md has no hooks section any more, and its Quick Reference row (L46) routes to this very file. The line is deleted (seat ruling). The fix is the deletion; the home is this file.
  • skills/objectstack-platform/rules/plugin-lifecycle.md L259 now points at ../references/plugin-development.md#complete-plugin-example. That section (L164) is the AuditPlugin example the sentence describes: a service registered in init(), kernel:ready / metadata:reloaded hooks, cleanup in destroy().
  • skills/objectstack-platform/rules/service-registry.md L147-149 now points at ../references/plugin-development.md#well-known-plugin-names--services, and the hand-written "13 rows" is dropped per Hand-written inventory counts in live docs, skills and READMEs drift silently: delete the number, keep the names or point at the source (cross-lane sweep) #27522. Card premise corrected: the card said that heading exists nowhere. It exists at references/plugin-development.md L280, with 12 rows, not 13.

4. bootstrap.md pins the current version

skills/objectstack-platform/references/bootstrap.md: all five pins in the starting package.json (L147-153, not only the two the card named) are now 18.3.0. That is the version in packages/skills/package.json, packages/spec, packages/runtime, packages/cli, plugin-hono-server, and every SKILL.md metadata.version. The edit is the same byte length.

5. Complete object examples author sharingModel

Code site: packages/lint/src/validate-security-posture.ts L843-877. A non-system object with no sharingModel is security-owd-unset (error). The object counts as system when isSystemObject (L280) says so: isSystem: true or a sys_ name.

  • rules/relationships.md: sharingModel: 'private' on account, contact, invoice, project, employee, project_assignment and category. sharingModel: 'controlled_by_parent' on the two master_detail children, invoice_line_item and invoice_line (the lint hint's prescription for master-detail children, consistent with the file's § Owner edits and its Relationship Types "Sharing: Inherits parent"). The ❌ counter-example (invoice_line_item with a lookup) is a complete create call, and it stays as it is: it is kept as a labelled counter-example under § Incorrect vs Correct, a shape the page tells the reader not to write.
  • rules/lifecycle.md: sharingModel: 'private' on api_call_log, import_ticket and consent_log. sys_automation_run is a system object (sys_ prefix, isSystemObject), so it is exempt and unchanged.
  • rules/datasources.md: sharingModel: 'public_read' on ext_customer. The binding has no external.writable: true, so it is read-only (validate-external-owner-sharing.ts L190), and the lint's prescription for an unprovable owner anchor is READ_ONLY_EXTERNAL_WAY_OUT (L136): 'public_read', because on 'private' a member reads no row.
  • No edit, measured: references/bootstrap.md and references/plugin-development.md hold no complete example. Each mentions ObjectSchema.create({ … }) only in prose, so the card's 1/0 counts are the prose mentions. bootstrap.md names the scaffolder's note.object.ts as the shape to copy, and that file authors sharingModel: 'private' (packages/create-objectstack/src/templates/blank/src/objects/note.object.ts L54).

6. System columns: what was confirmed

  • examples-objects.md: card premise wrong, measured, no edit (seat ruling B). An explicit created_at / created_by declaration is neither refused nor merely shadowed. applySystemFields lets the author's declaration win and forces only readonly: true / system: true over it (packages/metadata-core/src/audit-field-governance.ts, module note L10-15 and applyAuditFieldGovernance L121; label, group and even type stay the author's). And packages/spec/src/data/field-group-layout.ts L18-21 leaves audit fields out of a grouped layout unless the author explicitly groups them. So created_at: { …, group: 'system' } is the supported way to show them in that example's System section. The serial wait on docs(skills): guard nullable validation operands, teach hook body, list mailbox / package-registry, drop os generate agent #31127 is moot: the file is untouched.
  • rules/indexing.md § Multi-Tenant Queries: fixed. The injected tenant column is organization_id, governed by systemFields.tenant (packages/spec/src/data/object.zod.ts L3309: "the column is always provisioned; the multi-tenant flag governs only its index"). On a multi-tenant host the registry adds the single-column index itself (packages/objectql/src/registry.ts TENANT_SCOPE_INDEX L1692, provisionTenantScopeIndex L1694). An index naming an undeclared tenant_id is refused: indexes[].fields[] existence is judged against the authored fields plus the injected columns (packages/lint/src/validate-object-field-refs.ts, INDEX_POSITION L320). The example now indexes ['organization_id', 'status', 'created_at'], with one paragraph on systemFields.tenant and the automatic index. The paragraph scopes the composite to non-unique indexes, because the neighbouring § unique scopes says "do NOT list organization_id yourself" for unique: 'organization'.

7. plugin-ai eval: card premise wrong, measured, no edit

skills/objectui/evals/project-setup.json L20 lists @object-ui/plugin-ai under must_not_contain (the same at aa3e21cc). The fixture already penalises an answer that names the retired package, so there is nothing to replace (seat ruling A).

8. $empty is taught: confirmed

$empty is in FILTER_OPERATORS (packages/spec/src/data/filter.zod.ts L3377), declared on both operator schemas (L1829, L1905), and is the lowering target of is_empty / is_not_empty (L2760-2763). Its semantics are the ruled per-type table EMPTY_PREDICATE_DESCRIPTION (L1796).

  • rules/filters.md Operator Reference: one row, $empty → "IS NULL, '' or [] by type".
  • SKILL.md § Null & Existence Operators: the row, an example (false = has content), and two sentences: the view operators lower to it, and a face that judges by declared type refuses it on a column it holds no declaration for (the built-in id), so use $null there.
  • $regex / $options stay out.

9. Upgrade roster

skills/objectstack-upgrade/SKILL.md: the prose before the skills remove block says objectstack-pm-dispatch is not in the 18 catalog and that only an older install has it (#17311). The prose carries the note, not the command, so the command stays copy-pasteable. The roster also gains objectui (seat review S2): a 17.x project installed it from objectstack-ai/objectui, so it has a github-sourced skills-lock.json entry that the sync skips, like the objectstack-* ones.

Token readings (node scripts/check-skills-token-ratchet.mjs, exit 0)

File main This branch Ceiling
skills/objectui/README.md 728 733 735 (inside headroom)
skills/objectui/guides/page-builder.md 3410 3409 3411
skills/objectstack-data/references/data-hooks.md 10011 9987 10011
skills/objectstack-data/rules/relationships.md 3870 3873 3873 (inside headroom)
skills/objectstack-data/rules/lifecycle.md 1590 1588 1590
skills/objectstack-data/rules/datasources.md 908 908 911
skills/objectstack-data/rules/indexing.md 2200 2284 3241 (inside headroom)
skills/objectstack-platform/references/bootstrap.md 1350 1350 1351
skills/objectstack-platform/rules/plugin-lifecycle.md 1775 1787 2408 (inside headroom)
skills/objectstack-platform/rules/service-registry.md 1754 1764 2331 (inside headroom)
skills/objectstack-query/SKILL.md 4234 4329 5547 (inside headroom)
skills/objectstack-query/rules/filters.md 2482 2477 2482
skills/objectstack-upgrade/SKILL.md 6160 6182 6188 (inside headroom)

skills/README.md is outside every skill directory and is not ratcheted. No ceiling is raised, so the ruling path was not used. No line was re-wrapped. Every deletion, with the facts it held and where each survives:

  • objectui/README.md: the skills.sh badge (a pointer to the archived repo's listing; no surviving home needed). The "CLI auto-detects your agent… (e.g. .claude/skills/objectui/…) See skills.sh/docs" sentence. Facts: auto-detection is false under the taught --agent install; the landing directory and the other agents are in the catalog README (§ install: "the skills land as real files in .claude/skills/", "Name your own runtime after --agent"), which the new text links.
  • data-hooks.md: the dead "Project hooks pattern" reference line (item 3). Its home is this file, which the data SKILL.md Quick Reference routes to.
  • relationships.md:
    • § ✅ Correct — Junction Object Pattern: the post_tag block is replaced by "The junction object pattern above.", mirroring the master_detail Correct entry. Facts: a junction is an explicit object with two lookups, both required: true. Home: § Many-to-Many: Junction Object (project_assignment, same shape, plus its unique pair index).
    • The // Contact can exist without account comment on required: false. Homes: the example's own // Child: Contact (independent lifecycle) and the Relationship Types row lookup | Independent | Optional by default.
  • lifecycle.md:
    • The intro's "— and, at its end, the save notice a hook hands the saver." Home: § Save Notice, and the data SKILL.md Quick Reference row.
    • // must: after === maxAge on the ConsentLog archive line. It was the page's only statement of the equality that object.zod.ts L1067 enforces at parse, so the follow-up commit restates it at its home (seat review S1). The § Validation Rules counter-example's comment now reads // ❌ archive.after must equal retention.maxAge, in place of "❌ Archive window detached from the hot window".
  • datasources.md: ", not only on a federated object" in the columnName bullet. Home: the same bullet's "on ANY object" and "everywhere".
  • query/rules/filters.md:
    • "; $null: false is IS NOT NULL" in § Prefer $null. Home: the Operator Reference $null row (IS NULL / IS NOT NULL) and SKILL.md's Null table.
    • The // Records created in the last 7 days (compute date in application code) comment. Its first half did not match the code below it (a fixed new Date('2025-01-01')), and its second half is the section's lead sentence ("For ad-hoc queries in application code, compute the date yourself").

Link walk

/mnt/project-files/card-31114/linkwalk.py (project folder) walks every skills/**/*.md outside code fences and inline code. It checks that relative links resolve to a file, that #anchors match a GitHub heading slug or an <a id> in the target, and that github.com/objectstack-ai/objectstack/(tree|blob)/main/<path> links name a path that exists in the checkout.

  • main (98583cd6): 243 links, 3 broken (exactly item 3's three).
  • This branch: 248 links, 0 broken.
  • The repo's own ui/scripts/check-doc-links.mjs (in pnpm --dir ui exec vitest run scripts/, a derived gate) also covers skills/objectui and is green.

Eval cases

  • objectstack-data/evals/objects-fields-relationships.json case 8 (new, item 5): project + owned milestone. Must contain ObjectSchema.create, sharingModel: 'private', sharingModel: 'controlled_by_parent', master_detail, deleteBehavior: 'cascade'; must not contain many_to_many, deleteBehavior: 'set_null'.
  • objectstack-data/evals/objects-fields-relationships.json case 9 (new, item 6): a multi-tenant index for an organization's open tickets. Must contain indexes, organization_id; must_not_contain is empty, because a careful answer warns against tenant_id by name, as the case's own expected_output does (seat review N1).
  • objectstack-data/evals/hooks-security-seeds-datasources.json case 11 (new, item 5; renumbered from 10 when docs(skills): guard nullable validation operands, teach hook body, list mailbox / package-registry, drop os generate agent #31127's case 10 landed on main): a read-only external ext_supplier. Must contain ObjectSchema.create, remoteName, sharingModel: 'public_read'; must not contain columnName:.
  • objectstack-query/evals/filters-pagination-search.json case 7 (new, item 8): tasks with no notes, where a blank string counts as none. Must contain $empty: true; must_not_contain is empty, because an answer that warns against the retired $regex / $options by name must not fail (seat review N1).
  • Item 7: no case changed (see § 7). No existing case encoded a corrected claim: I grepped every touched skill's evals/ for tenant_id, objectstack-ai/objectui, 18.1.0 and the three dead anchors, with no hits.

Other sites found (not changed: outside this card's file surface)

  • content/docs/releases/v12.mdx L204 and v14.mdx L298 link the archived objectui CHANGELOG. These are release notes, which Human Minimum item 7 says not to hand-edit. The other objectstack-ai/objectui hits under content/docs/frontend/** are historical issue links, which are correct as they are.
  • No other skill file holds a complete ObjectSchema.create example without sharingModel (swept: every skills/**/*.md with a create call).

Verification

Local gates: 97 derived, 97 exit 0, 0 NOT MEASURED
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 97 commands for the 20 changed paths. Each one ran under timeout 900 with NODE_OPTIONS=--max-old-space-size=8192, and its exit code was captured before any pipe. The full list with exit codes is in the project folder, card-31114/gates-e6dcc651.txt.
  • A first pass on the pre-amend commit had 5 reds: 4 from the environment, 1 real. check-plugin-teardown-shape --self-test exited 3 because this shallow clone lacks its pinned fixture commit; fixed with git fetch origin 621a4876…. check:skill-examples (exit 3), check:dts-closure (exit 1) and check:dual-build-cjs-loads (exit 3) failed with no dist/, before pnpm build (exit 0) had finished. pnpm --dir ui exec vitest run scripts/ (exit 1) caught a real defect: check-doc-links refused the relative ../README.md in skills/objectui/README.md, which now uses an absolute URL (see § 1). The rest of that file's reds were build-dependent.
  • After the fix and the build, all 97 were rerun on the amended commit (e6dcc651): 97 exit 0. That includes check:skill-identifier-liveness, check:skill-top-level-keys, check:skill-compatibility, check:skill-frame-sync, check:skill-docs, check:skill-refs, check:skill-examples (283 blocks), check:doc-authoring, check:corpus-claim-drift, the ui scripts/ suite (4996 tests) and the token ratchet.
  • The branch was then rebased onto origin/main 9f61e06e before the first push. Those 5 new main commits touch no file in this diff. The token ratchet, check:skill-docs --check, the commit-trailer check and the link walk were re-run on the rebased head, all exit 0.
  • Follow-up commit bc879f05 (seat review S1, S2, N1; 4 skill files plus the changeset bullet): node scripts/check-skills-token-ratchet.mjs, check:skill-docs --check, check:skill-refs, check:skill-compatibility, check:skill-identifier-liveness, check:corpus-claim-drift, check:doc-authoring and check-empty-changeset --base origin/main all exit 0, and all three touched eval files parse as JSON.
  • Merge commit 356cc7ae (origin/main into the branch, no rebase): the one conflict was hooks-security-seeds-datasources.json, where docs(skills): guard nullable validation operands, teach hook body, list mailbox / package-registry, drop os generate agent #31127 also appended a case 10. Both cases are kept, and this PR's case is renumbered to 11, so the ids run 1-11. Nothing else in this PR's diff against main changed. The token ratchet, check:skill-docs --check, the JSON parse of all three eval files and the link walk (249 links, 0 broken) all exit 0.
  • node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0 before each push.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (No schema touched; only a build script under packages/spec/scripts.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset ('@objectstack/skills': patch), and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched (scripts/build-skill-docs.ts): its generated artifacts (skills/README.md index, content/docs/ai/skills-reference.mdx) are regenerated and committed; check:skill-docs is green.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English. (The 维护者速读 section is Chinese, per the lane template.)
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8VVAjQXxnSqEopTLRDyHp

…he catalog index, repair dead anchors, author sharingModel in object examples

- objectui README / page-builder and the catalog README point at ui/ in
  this repository and the pinned experimental_sync install.
- build-skill-docs admits every skill directory that carries a SKILL.md
  and is not metadata.internal (the template-consistency predicate), so
  the generated index and docs page list objectui; regenerated.
- data-hooks.md drops a link to a section the data SKILL.md no longer
  has; plugin-lifecycle.md and service-registry.md point at
  references/plugin-development.md, and the hand-written row count goes.
- bootstrap.md pins 18.3.0.
- Complete ObjectSchema.create examples in relationships.md, lifecycle.md
  and datasources.md author sharingModel; indexing.md names the injected
  organization_id tenant column; query teaches $empty; the upgrade roster
  says objectstack-pm-dispatch is not in the 18 catalog.
- Eval cases for the above; paid by same-file deletions of restatement.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAjQXxnSqEopTLRDyHp
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 7, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head af6b632 · 2026-11-07T14:51Z

Full contract review of PR #31152 (#31114, claim 6707729042). The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent.

@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 56baf78e0c422b6555238043cc7d4c1a22db3568 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: af6b6321ce576254866a910d09de45937d107798
Local-runs: probe — node scripts/check-skills-token-ratchet.mjs, run in a throwaway worktree of the head (/tmp/claude-0/seat3/wt-31152, since removed), because the brief asks for the token readings from the repo's own ratchet (exit 0, 57 authored files inside their ceilings). In the same worktree I also ran tsx packages/spec/scripts/build-skill-docs.ts --check (exit 0, both generated files in sync), node scripts/pm/check-governed-merges.mjs --pr 31152 (exit 3, GOVERNED, Tier H) and the thread's linkwalk.py on the head and on the main checkout. Main-side token counts were taken by hand (git show origin/main:<file> | wc -c, release-stamp line removed on a SKILL.md, then ceil(bytes/4)).
Scope: the 20 files of git diff origin/main...refs/seat3/pr-31152 (merge base 9f61e06e6 = origin/main, one commit af6b6321c): .changeset/skills-stale-teaching-after-ui-merge.md, content/docs/ai/skills-reference.mdx, packages/spec/scripts/build-skill-docs.ts, skills/README.md, skills/objectui/README.md, skills/objectui/guides/page-builder.md, skills/objectstack-data/references/data-hooks.md, skills/objectstack-data/rules/datasources.md, indexing.md, lifecycle.md, relationships.md, skills/objectstack-data/evals/objects-fields-relationships.json, hooks-security-seeds-datasources.json, skills/objectstack-platform/references/bootstrap.md, rules/plugin-lifecycle.md, rules/service-registry.md, skills/objectstack-query/SKILL.md, rules/filters.md, evals/filters-pagination-search.json, skills/objectstack-upgrade/SKILL.md. Cited code read at the head, where none of these code paths differ from origin/main: packages/spec/src/data/object.zod.ts (sharingModel enum L3745, systemFields.tenant L3309, archive refine L1067), packages/spec/src/data/filter.zod.ts (EMPTY_PREDICATE_DESCRIPTION L1796, operator schemas L1829 / L1905, view lowering L2760-2763, FILTER_OPERATORS L3377), packages/lint/src/validate-security-posture.ts (isSystemObject L280, security-owd-unset L843-877), packages/lint/src/validate-external-owner-sharing.ts (READ_ONLY_EXTERNAL_WAY_OUT L136, externalOwnershipGap), packages/lint/src/validate-object-field-refs.ts (INDEX_POSITION L320, index judgment L551-568), packages/objectql/src/registry.ts (TENANT_SCOPE_INDEX L1692, provisionTenantScopeIndex L1694, declaresTenantIndex L1834), packages/create-objectstack/src/template-consistency.test.ts (isMarkedInternal L608), packages/spec/package.json (files), packages/skills/package.json and scripts/sync-catalog.mjs, .changeset/config.json (fixed), packages/metadata-core/src/audit-field-governance.ts, packages/spec/src/data/field-group-layout.ts, ui/scripts/check-doc-links.mjs (L732), scripts/check-skills-token-ratchet.mjs, and the package.json versions of spec, runtime, cli, driver-memory, plugin-hono-server and skills.

① Derived judgments

Inputs: card #31114 (body; triage 6706611171; claim 6707729042), the PR body (identical to /mnt/project-files/card-31114/body-v1.md apart from the attribution comment), the commit, the net diff, the gate record gates-e6dcc651.txt (97 commands, all exit 0), and the seat's mid-flight rulings A, B, C and the data-hooks.md:961 deletion. Each taught fact was checked against code:

  • Item 1, objectui is not a separate repo. TRUE.
    • No "separate repo" teaching remains in the touched files. No objectstack-ai/objectui link is left under skills/ or content/docs/ai/. The two remaining skills add objectstack-ai/objectstack/skills lines are the next channel, which is correct.
    • The objectui README's two install lines copy the catalog README's pinned block exactly (@objectstack/skills@$(…spec version) plus skills@1.7.2 experimental_sync --agent claude-code --copy -y). @objectstack/skills ships the whole skills/** tree (sync-catalog.mjs), so objectui is in it.
    • Dropping "the CLI auto-detects your agent" is right: the taught command names the agent. Its two other facts have a home in the linked catalog README (skills land in .claude/skills/; "Name your own runtime after --agent").
    • The absolute catalog README URL is needed: check-doc-links.mjs L732 judges skills/objectui against diskRoot: '../skills/objectui', so a relative ../README.md leaves the bundle. The gate record shows the ui scripts/ suite green after the change.
    • New links resolve. tree/main/ui, tree/main/ui/packages/plugin-gantt (which holds README.md) and blob/main/skills/README.md all exist. The link walk reads 243 links with 3 broken on main (exactly item 3's three) and 248 links with 0 broken at the head.
  • Item 2, the generator. TRUE and behaviour-safe.
    • The predicate is "has SKILL.md and is not metadata.internal". isMarkedInternal is a byte-for-byte copy of the test's regex pair (frontmatter block, ^metadata: line, indented internal: true). It admits objectui. No skill under skills/ is internal today and there are no template directories, so the exclusion is latent but correct. skills/README.md (a file) fails existsSync(<dir>/SKILL.md) and stays out.
    • Plain scalar: ^description:\s*([^>\s].*)$ reads objectui's one-line description. A folded > or >- still takes the old branch.
    • Clause split: \bUse (?:when|for)\b, and \bDo not use\b made case-insensitive. The first match wins.
    • Byte-identical for the other ten: build-skill-docs.ts --check exits 0 at the head, so the head script reproduces the committed files. Those files differ from main only by the added objectui row and card and the count 10 → 11. So the ten existing entries render unchanged.
    • DISPLAY gains the objectui row. The lockstep check would refuse a missing one.
  • Item 3, anchors. TRUE.
    • plugin-development.md L164 ## Complete Plugin Example gives #complete-plugin-example. That is the AuditPlugin with registerService in init(), kernel:ready / metadata:reloaded hooks and destroy(), as the sentence says.
    • L280 ## Well-Known Plugin Names & Services gives #well-known-plugin-names--services (ruling C). The table has 12 rows. "13 rows" is gone and no other "13 rows" remains under skills/.
    • data-hooks.md L961 is deleted (seat ruling). The data SKILL.md Quick Reference routes to that file.
  • Item 4, bootstrap.md pins. TRUE. All five pins read 18.3.0. packages/spec, runtime, cli, drivers/driver-memory, plugins/plugin-hono-server and skills are 18.3.0 on main, and so are all 11 SKILL.md metadata.version lines and the npm latest of the five packages.
  • Item 5, sharingModel. TRUE.
    • The enum is private | public_read | public_read_write | controlled_by_parent (object.zod.ts L3745). Every value used is valid.
    • security-owd-unset is an error for a non-system object with no OWD (validate-security-posture.ts L843-877). isSystemObject is isSystem === true or a sys_ name.
    • relationships.md: 9 of the 10 create calls now author one. controlled_by_parent sits on the two master_detail children (invoice_line_item, invoice_line), which matches the lint hint and the file's table.
    • lifecycle.md: 3 of 4. sys_automation_run is exempt by its sys_ prefix. Confirmed.
    • datasources.md: public_read on ext_customer. The binding has no external.writable: true and no declared owner, so hasUnprovableOwnerAnchor holds and the lint prescribes READ_ONLY_EXTERNAL_WAY_OUT, which is 'public_read'. Confirmed.
    • bootstrap.md L159 and plugin-development.md L33 mention ObjectSchema.create({ … }) only in prose, so neither holds a complete example. The scaffolder's note.object.ts L54 authors sharingModel: 'private'. Confirmed.
    • The relationships.md ❌ invoice_line_item block (L378) is left without one. Acceptable: it is a labelled counter-example that no reader copies. See N2 on how the body names it.
  • Item 6, indexing.md. TRUE on all three claims (ruling B: examples-objects.md is untouched, confirmed).
    • The tenant column is organization_id under systemFields.tenant (L3309: "Inject the organization_id column … the multi-tenant flag governs only its index").
    • "On a multi-tenant host the platform adds its single-column index": provisionTenantScopeIndex returns early unless multiTenant, then appends { fields: ['organization_id'] }. declaresTenantIndex accepts only a one-column entry, so an author's composite that leads with organization_id does not suppress it. The sentence is exact.
    • "An index naming an undeclared tenant_id is refused": validateObjectFieldRefs judges each indexes[].fields[] name verbatim against authored plus injected columns, and pushes object-field-ref-unknown at severity: 'error'. It runs in the reference-integrity suite, which the runtime gate uses.
    • "A unique one says unique: 'organization' instead (above)" matches § unique scopes L57 ("do NOT list organization_id yourself").
  • Item 7. No edit (ruling A). project-setup.json L20 lists @object-ui/plugin-ai under must_not_contain. The body records the file and line.
  • Item 8, $empty. TRUE.
    • It is in FILTER_OPERATORS (L3377) and on both operator schemas, and it is the target of is_empty / is_not_empty (L2760-2763).
    • The taught semantics match EMPTY_PREDICATE_DESCRIPTION: null plus '' on text-like types, null plus [] on multi-value types, null only on every other type, and false as the exact complement. A face that judges by declared type refuses it on an undeclared column such as id, so $null is used there.
    • The drivers (memory, mongodb, sql) carry expandEmptyOperator.
    • $regex / $options are not taught.
  • Item 9, upgrade wording. TRUE. "objectstack-pm-dispatch is not in the 18 catalog, only an older install has it" holds: no such directory exists under skills/. The note sits in the prose, so the command stays copy-pasteable. See S2 for a gap in the same roster.
  • Deletions paying the budget. Each cut fact checked for a surviving home:
    • objectui README: the skills.sh badge is a pointer only. The auto-detect sentence is covered above.
    • page-builder.md: a shorter URL only. No fact cut.
    • data-hooks.md: a dead link only. Its home is the file itself.
    • relationships.md post_tag block: "an explicit junction object with two required lookups" lives in § Many-to-Many: Junction Object (project_assignment, two lookups with required: true, plus the unique pair index). The link #many-to-many-junction-object resolves.
    • relationships.md // Contact can exist without account: required: false itself, the // Child: Contact (independent lifecycle) comment, and the table row "lookup | Independent | Optional by default".
    • lifecycle.md intro "the save notice a hook hands the saver": § Save Notice (L143) and the data SKILL.md Quick Reference row L45.
    • lifecycle.md // must: after === maxAge: no explicit home. See S1.
    • datasources.md ", not only on a federated object": the same bullet's "on ANY object" and "everywhere".
    • filters.md "$null: false is IS NOT NULL": the Operator Reference row (IS NULL / IS NOT NULL) and the SKILL.md Null table. Adequate.
    • filters.md date comment: its first half did not match the code, and its second half is the section's lead sentence.
  • Evals. All three JSON files parse. The ids run 1-9, 1-10 and 1-7 with no gaps.
    • Data case 8: TRUE. deleteBehavior on master_detail is cascade or restrict only, so must_not_contain: set_null is consistent.
    • Data case 9: TRUE (see item 6). See N1.
    • Data hooks case 10: TRUE. It matches the read-only external prescription.
    • Query case 7: TRUE. $null: true misses '' on a textarea, and $empty: true catches it. See N1.

② Semver level

'@objectstack/skills': patch is right. The change is skill prose, eval fixtures and the catalog README, and @objectstack/skills ships all three (the whole skills/** tree).

No '@objectstack/spec': patch is owed for the generator. The card asked for one only "if the generator ships in a published package". It does not: packages/spec/package.json files is dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json, protocol-upgrade-guide.md, and scripts/ is not in it. Its two outputs ship in @objectstack/skills (skills/README.md) or nowhere (content/docs). Also, spec and skills sit in one fixed group in .changeset/config.json, so the version moves together either way. The body states this reasoning.

Clause-②: no and Metadata-protocol: none are right: no schema, contract or metadata meaning moves. Both lines are line-initial in the changeset and in the PR body.

③ Boundary flags

  • Claim. All 20 paths are inside claim 6707729042: item 1's three files, item 2's generator and its two regenerated outputs, item 3's three files, item 4's file, item 5's three edited files, item 6's indexing.md, item 8's two files, item 9's file, eval JSONs of the touched data and query skills, and one changeset. Untouched, as ruled: examples-objects.md (B), project-setup.json (A), and plugin-development.md (no complete example). Same-file payment cuts sit outside "the complete object examples" in relationships.md, lifecycle.md, datasources.md and filters.md. The ratchet discipline requires that payment and the body names each cut. Not a breach.
  • Ratchet script. Unchanged against origin/main. No ceiling moved, so standing ruling 6513306068 was not used.
  • Tier. check-governed-merges --pr 31152: GOVERNED, Tier H, skills/** ×17. Off the register: the changeset, skills-reference.mdx and build-skill-docs.ts. Size +171 / −44 (215 lines), under 3000. Landing needs the maintainer's merge or an APPROVED review from GOVERNED_APPROVERS, and the body says so. The PR is a draft with mergeable_state blocked. Labels: documentation, size/m, tooling.
  • PR body. It has Fixes #31114 and a model-tier waiver that names no model ("the project's default model"). No model identifier appears in the body, title, diff or commit. The commit trailer is model-free.
  • Other sites outside the claim, confirmed for filing. The thread's list is short by three:
    • content/docs/releases/v12.mdx L204 and v14.mdx L298 link the archived objectui CHANGELOG. Confirmed.
    • content/docs/releases/v13.mdx L188 has the same link. The thread missed it.
    • content/docs/releases/index.mdx L8 says, in the present tense, that the Console UI is "built from the objectui repository", and L40 links the archived objectui CHANGELOG. This is the overview page, not a per-release note. Feature PRs edit it (for example feat(fields): every record reference shows a hover card with the target's declared highlights #27912), so item 1's correction can reach it without hand-editing a release note. Worth filing.
    • docs/adr/0072-…md L5 links an ADR in the objectui repo. It is historical and correct as it is.

④ Design judgment

  • One home per rule. Held for the new teaching. $empty has one row in each of the query surfaces, which mirrors $null. The tenant-column paragraph points at § unique scopes instead of restating it.
  • Token budget. No ceiling was raised and the script exits 0. All readings match the PR body and the brief.
File main head ceiling
objectui/README.md 728 733 735
objectui/guides/page-builder.md 3410 3409 3411
objectstack-data/references/data-hooks.md 10011 9987 10011
objectstack-data/rules/relationships.md 3870 3873 3873
objectstack-data/rules/lifecycle.md 1590 1588 1590
objectstack-data/rules/datasources.md 908 908 911
objectstack-data/rules/indexing.md 2200 2284 3241
objectstack-platform/references/bootstrap.md 1350 1350 1351
objectstack-platform/rules/plugin-lifecycle.md 1775 1787 2408
objectstack-platform/rules/service-registry.md 1754 1764 2331
objectstack-query/SKILL.md 4234 4329 5547
objectstack-query/rules/filters.md 2482 2477 2482
objectstack-upgrade/SKILL.md 6160 6180 6188

There is no separate line-budget gate on skills/**. The two SKILL.md files touched are 413 and 483 lines.

  • should-fix S1, lifecycle.md lost the explicit archive rule. The cut // must: after === maxAge was the page's only statement that archive.after must equal retention.maxAge. object.zod.ts L1067 refuses any mismatch. The named home, "❌ Archive window detached from the hot window", shows one refused pair (30d against 90d) but never says "equal", so a reader may think a longer after is fine. Fix it inside the budget: reword that ❌ comment to // ❌ archive.after must equal retention.maxAge, which is about 2 bytes shorter than the current comment. The lane rule is that a cut with no surviving home drops a rule. This is not blocking only because the parse refusal names the rule.
  • should-fix S2, the upgrade roster omits objectui. Until this PR, the objectui README taught npx skills add objectstack-ai/objectui. Such an install has a sourceType: github lock entry, so experimental_sync skips it, exactly as the paragraph explains for the objectstack-* names. The agent then keeps the 17.x objectui text, and the skills remove roster does not list it. Adding objectui to the roster costs about 3 tokens of the 8 left, and "a missing name is skipped" makes it safe. Fold it in, or file it with item 1's follow-up.
  • should-fix S3, the body overstates how growth was paid. The 维护者速读 section says all growth is paid by same-file deletions. Seven files grow into existing headroom: objectui README +5, relationships +3, indexing +84, plugin-lifecycle +12, service-registry +10, query SKILL.md +95 and upgrade SKILL.md +20. The English table marks five of them "inside headroom" but not the README and relationships rows. The script's discipline says new text is paid by same-file deletion, and the script itself accepts landing inside a ceiling. Correct the sentence and label the two rows.
  • nit N1, eval assertions punish a careful answer. Data case 9's must_not_contain: tenant_id fails an answer that warns "not tenant_id", and the case's own expected_output says exactly that. Query case 7's $regex / $options exclusions have the same shape. Accept the risk, or assert on fields: ['tenant_id' instead.
  • nit N2, the body names the ❌ block a "fragment that shows one key". It is a complete create call. The real reason to leave it is that it is labelled ❌ and never copied. Reword it in the body only.
  • nit N3, generator edge cases. The plain-scalar branch would read a | block indicator or a quoted scalar verbatim. No skill uses either today. Separately, the generated intro still says "one per authoring domain", and ui now has two skills.
  • nit N4, optional ceiling drops. data-hooks.md (−24), filters.md (−5), lifecycle.md (−2) and page-builder.md (−1) shrank. The script encourages lowering their ceilings. If S1 is taken, leave lifecycle.md's ceiling where it is.
  • Check-runs on this head, read 2026-11-07T14:58Z: 62 runs, 24 success, 7 skipped, 31 in progress, 0 failed.

Verdict: PASS

…e 17.x remove roster, loosen two eval exclusions

- lifecycle.md: the archive-window counter-example now says archive.after
  must equal retention.maxAge (the parse-time rule in object.zod.ts).
- objectstack-upgrade: a 17.x project installed objectui from
  objectstack-ai/objectui, so the skills remove roster names it too.
- Two new eval cases no longer fail an answer that warns against
  tenant_id or $regex/$options by name.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAjQXxnSqEopTLRDyHp
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head bc879f0 · 2026-11-07T15:04Z

Delta review against the PASS at head af6b632 (comment 6708636526: should-fixes S1–S3, nits N1–N4). The delta is one commit answering S1, S2 and N1, plus the PR body (patched by the seat) answering S3 and N2. N3 and N4 are left as they are. The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: bc879f054dff61f4a3f6c9217e40d2d30396ed2c
Local-runs: probe — node scripts/check-skills-token-ratchet.mjs, run in a throwaway worktree of the new head (/tmp/claude-0/seat3/wt-31152, since removed), because the brief asks me to confirm the body's token readings against the head (exit 0, 57 authored files inside their ceilings). In the same worktree I also ran tsx packages/spec/scripts/build-skill-docs.ts --check (exit 0), a JSON parse of the three touched eval files, and node scripts/pm/check-governed-merges.mjs --pr 31152 (exit 3, GOVERNED, Tier H).
Scope: delta review. One commit, bc879f054 (parent af6b6321c, a normal push; merge base with origin/main still 9f61e06e6). The 5 files of git diff af6b6321c refs/seat3/pr-31152: skills/objectstack-data/rules/lifecycle.md, skills/objectstack-upgrade/SKILL.md, skills/objectstack-data/evals/objects-fields-relationships.json, skills/objectstack-query/evals/filters-pagination-search.json, .changeset/skills-stale-teaching-after-ui-merge.md. Also the PR body v2 (live, diffed against v1 and against /mnt/project-files/card-31114/body-v2.md; the live copy only adds a trailing signed: comment). Cited code: packages/spec/src/data/object.zod.ts L1042-1070 (the archive refine). The full review of af6b6321c is /tmp/claude-0/seat3/review-31152.md.

① Derived judgments

  • S1, fixed. The ❌ comment in lifecycle.md § Validation Rules now reads // ❌ archive.after must equal retention.maxAge. That is TRUE. object.zod.ts L1067 refuses lc.archive.after !== lc.retention.maxAge with "must equal retention.maxAge … the hot window ends where the archive begins". The example under it (90d against 30d) is still refused. The new comment is 2 bytes shorter, so lifecycle.md stays at 1588 / 1590.
  • S2, fixed. The skills remove roster now ends … objectstack-upgrade objectui -y. This is TRUE and safe: the paragraph's own reasoning (a github-sourced lock entry, which the sync skips) applies to an objectui install from objectstack-ai/objectui, and "a missing name is skipped" covers projects without it. The changeset bullet now says the roster "also removes a 17.x objectui install (sourced from objectstack-ai/objectui)". That matches the edit. upgrade SKILL.md is 6182 / 6188.
  • N1, taken. Both must_not_contain arrays are now []. Empty arrays are an established shape in 8 other eval cases (for example objectstack-api endpoints-auth-routes.json L21 and L41, and objectui i18n.json L49). All three touched eval files parse, with ids 1-9, 1-7 and 1-10. The cases still discriminate:
    • Data case 9 must contain organization_id. The failure it guards, an index on ['tenant_id', …], does not contain that string unless the answer names the right column.
    • Query case 7 must contain $empty: true. A $null answer, a $regex answer and a hand-built $or all fail it.
  • Nothing else changed. The delta has 5 files and +5 / −7 lines, and every hunk is one of the three fixes or the changeset bullet. The ratchet script is unchanged. The generated docs are still in sync (--check exit 0).

② Semver level

Unchanged and still right. '@objectstack/skills': patch is still the only package in the changeset. No '@objectstack/spec': patch is owed, because spec does not publish scripts/ (see the full review). Clause-②: no and Metadata-protocol: none are line-initial in the changeset (L7-8) and in the body (L8-9).

③ Boundary flags

  • Claim. All 5 delta paths were already in the PR and are inside claim 6707729042: item 5's lifecycle.md, item 9's upgrade SKILL.md, eval JSONs of the touched skills, and the changeset. S2 adds one word to the roster that item 9 already touches.
  • Tier. check-governed-merges --pr 31152: GOVERNED, Tier H, skills/** ×17. Size +171 / −46 (217 lines), under 3000. Landing needs the maintainer's merge or an APPROVED review from GOVERNED_APPROVERS. The PR is still a draft.
  • PR body v2. It still has Fixes #31114 and the model waiver ("the project's default model"). No model identifier appears in the body, the title, the delta or the commit message. The trailer is model-free.
  • Other site outside the claim, new for filing. content/docs/upgrading.mdx L110-112 carries the same skills remove roster, and it still lacks objectui. The docs page and the skill now differ. No gate holds the two equal (check:corpus-claim-drift is green on both). File it with the releases sites from the full review (v12 L204, v13 L188, v14 L298, releases/index.mdx L8 and L40).

④ Design judgment

  • S3, fixed in the body. The 维护者速读 section now names the seven files that grow into existing headroom and says the rest are paid by same-file deletion. The table marks the objectui README and relationships rows "(inside headroom)".
  • N2, fixed in the body. The ❌ block is now called "a complete create call … kept as a labelled counter-example under § Incorrect vs Correct".
  • The body's token table matches the head, row for row, by the ratchet run:
File main head ceiling
objectui/README.md 728 733 735
objectui/guides/page-builder.md 3410 3409 3411
objectstack-data/references/data-hooks.md 10011 9987 10011
objectstack-data/rules/relationships.md 3870 3873 3873
objectstack-data/rules/lifecycle.md 1590 1588 1590
objectstack-data/rules/datasources.md 908 908 911
objectstack-data/rules/indexing.md 2200 2284 3241
objectstack-platform/references/bootstrap.md 1350 1350 1351
objectstack-platform/rules/plugin-lifecycle.md 1775 1787 2408
objectstack-platform/rules/service-registry.md 1754 1764 2331
objectstack-query/SKILL.md 4234 4329 5547
objectstack-query/rules/filters.md 2482 2477 2482
objectstack-upgrade/SKILL.md 6160 6182 6188

No ceiling was raised.

  • The body's lifecycle cut entry now names its home correctly. It records that the equality was restated in § Validation Rules.
  • N3 and N4 are left as they are, by the seat's choice. Neither blocks.
  • No new findings in the delta.
  • Check-runs on this head, read 2026-11-07T15:07Z: 0 runs have registered yet.

Verdict: PASS

# Conflicts:
#	skills/objectstack-data/evals/hooks-security-seeds-datasources.json
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head 356cc7a · 2026-11-07T15:11Z

Delta review against the PASS at head bc879f0 (comment 6708730294). The delta is one merge commit of origin/main that resolves the conflict with #31127 in skills/objectstack-data/evals/hooks-security-seeds-datasources.json, plus the PR body (patched by the seat). The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 356cc7aec74706a2b28cd21f98b180ee97783806
Local-runs: probe — node scripts/check-skills-token-ratchet.mjs, run in a throwaway worktree of the merge head (/tmp/claude-0/seat3/wt-31152, since removed), because the brief asks me to confirm the ratchet still exits 0 after main came in (exit 0, 57 authored files inside their ceilings). In the same worktree I also ran tsx packages/spec/scripts/build-skill-docs.ts --check (exit 0), node scripts/pm/check-governed-merges.mjs --pr 31152 (exit 3) and the thread's linkwalk.py (249 links, 0 broken). The conflict-file check was a JSON structural compare of the three trees, run from git objects with no checkout.
Scope: second delta review. The head is merge commit 356cc7aec with parents bc879f054 (the branch) and 56baf78e0 (= origin/main, which contains #31127). The merge base with origin/main is now 56baf78e0. I compared the net diff git diff origin/main...refs/seat3/pr-31152 (20 files) with the earlier net diff git diff 9f61e06e6...bc879f054. I checked every PR file's blob at bc879f054 against the head. The conflict file skills/objectstack-data/evals/hooks-security-seeds-datasources.json was compared at origin/main, bc879f054 and the head. I also read the PR body v3 (live, diffed against v2 and against /mnt/project-files/card-31114/body-v3.md). Earlier records: /tmp/claude-0/seat3/review-31152.md and review-31152-d1.md.

① Derived judgments

② Semver level

Unchanged. The changeset's blob is identical to bc879f054: '@objectstack/skills': patch, with Clause-②: no and Metadata-protocol: none line-initial. No spec patch is owed (see the full review).

③ Boundary flags

  • Claim. The same 20 paths as before, all inside claim 6707729042. The merge adds no new path to the net diff.
  • Tier. check-governed-merges --pr 31152: GOVERNED, Tier H, skills/** ×17. Size +171 / −46 (217 lines), under 3000. Landing needs the maintainer's merge or an APPROVED review from GOVERNED_APPROVERS. The PR is still a draft.
  • The merge commit. Its message is the default "Merge origin/main into claude/project-thread-4ejvqq" with the conflict list. It has no trailer and no model identifier. check-commit-card-trailers treats a trailerless merge commit as clean (its header, "carry no trailer at all, so they carry no model and are CLEAN").
  • PR body v3. It differs from v2 in exactly two places. Case 10 becomes "case 11 (… renumbered from 10 when docs(skills): guard nullable validation operands, teach hook body, list mailbox / package-registry, drop os generate agent #31127's case 10 landed on main)", and one merge-note bullet is added under Verification. The note is accurate: the one conflict, both cases kept, ids 1-11, and nothing else in the PR's diff changed (the case-3 line is main's, not the PR's). The live body matches the project copy apart from the trailing signed: comment. Fixes #31114, both declaration lines and the model-free waiver are unchanged.
  • Outside-claim sites are as listed in the earlier records (upgrading.mdx L110-112; releases v12, v13, v14 and index.mdx).

④ Design judgment

Verdict: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7

维护者速读

  • 改了什么: 技能里不再把 objectui 教成「独立仓库」(skills/README.md、skills/objectui/README.md、page-builder.md);build-skill-docs.ts 的目录过滤改为「有 SKILL.md 且非 internal」,生成的目录索引与文档页补上第 11 个技能 objectui;修三处指向已不存在章节的锚点;bootstrap.md 版本钉 18.1.0 → 18.3.0;对象示例补 sharingModel;indexing.md 租户列改为注入的 organization_id;查询技能补 $empty;升级技能的 skills remove 名册标注已删除的 pm-dispatch 并补 objectui。另有四条 eval 与 '@objectstack/skills': patch changeset。20 个文件。
  • 为什么改: skills: stale teaching after the ui merge and the moved-verbatim refactors — objectui as a separate repo, three dead SKILL.md anchors, bootstrap.md pins 18.1.0, examples omit sharingModel, retired plugin-ai eval, $empty untaught #31114。ui 合仓后技能仍教旧仓库、旧版本、发布门会拒绝的示例,以及断链。
  • 风险与回滚: 只改技能文字、eval、生成脚本与其生成物;全部文件在 token 上限内,无上调。可整 PR revert。
  • 先看: packages/spec/scripts/build-skill-docs.ts 的过滤谓词(与 template-consistency.test.ts 的 isMarkedInternal 一致),以及 skills/README.md 生成的索引。
  • 两分钟验证: node scripts/check-skills-token-ratchet.mjs 与 pnpm --filter @objectstack/spec check:skill-docs,均 exit 0。
  • 需要你做的: skills/** 是受治理 Tier H 面,需 os-zhuang 或 hotlong 在 GitHub 上 Approve 一次。达档复核:全量 6708636526 PASS(head af6b6321),增量 6708730294 PASS(head bc879f05),合并 main 后增量 6708823282 PASS,Head-sha 356cc7aec74706a2b28cd21f98b180ee97783806。批准后本席落地。
  • 席位意见: ACCEPT。

席位核对 — ACCEPT · domain:skills#3 · head 356cc7aec74706a2b28cd21f98b180ee97783806

  1. 形态: draft → main,Fixes #31114;'@objectstack/skills': patch(生成脚本不随 spec 包发布,无需 spec patch),Clause-②: no,Metadata-protocol: none;作者 objectstack-fleet[bot];20 个文件,在认领面之内。
  2. 前提实测: 复核逐项对照 main 代码:object.zod.ts(sharingModel 枚举、systemFields.tenant、archive/maxAge 相等约束 L1067)、filter.zod.ts(FILTER_OPERATORS 含 $empty、视图 is_empty 下沉)、validate-security-posture.ts(security-owd-unset、isSystemObject)、validate-object-field-refs.ts(未声明列上的索引报错)、registry.ts(provisionTenantScopeIndex 单列自动索引)、audit-field-governance.ts、各包版本 18.3.0。
  3. 门禁(钉 head 356cc7ae): dev 派生门禁 97 条全部 exit 0(记录 gates-e6dcc651);跟进提交后 ratchet、check:skill-docs、skill-refs、compatibility、identifier-liveness、corpus-claim-drift、doc-authoring 全部 0;链接巡检 main 断 3 条,分支 0/249;check-runs 69 条:60 success、9 skip、0 失败;token 读数见正文表,无上调。check-governed-merges --pr 31152:Tier H(skills/**)。
  4. 接受的偏差: 席位裁定 A(第 7 项 eval 已在 must_not_contain 里排除 plugin-ai,不改)、B(examples-objects.md 声明审计字段是受支持写法,不改;只改 indexing.md 一半)、C(service-registry 锚点改指 plugin-development.md,删「13 rows」);data-hooks.md:961 失效引用行删除;bootstrap.md 与 plugin-development.md 无完整对象示例,不补 sharingModel;生成脚本解析器两处改动(纯标量 description、Use for / Do NOT use)。复核 S1–S2 与 N1 由跟进提交改正,S3、N2 由本席改正文;N3、N4 不改。与 docs(skills): guard nullable validation operands, teach hook body, list mailbox / package-registry, drop os generate agent #31127 在 data hooks eval 上的冲突以合并提交解决(保留其 case 10,本 PR 的改为 case 11)。
  5. 范围外去向: 发布说明总览仍称 Console 由 objectui 仓构建、v12/v13/v14 与总览链向已归档的 objectui CHANGELOG,以及 content/docs/upgrading.mdx 的 skills remove 名册缺 objectui → docs(releases): the overview still says the Console UI is "built from the objectui repository" and points at the archived objectui CHANGELOG, after the ui merge #31158。
  6. 落地条款: Tier H。保持 draft,挂 pm:awaiting-merge,请 os-zhuang、hotlong 审批;获批后本席过落地前检、清标、ready、auto-merge;维护者直合亦可。

@objectstack-fleet objectstack-fleet Bot added the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 7, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review November 7, 2026 16:18
@os-zhuang
os-zhuang enabled auto-merge November 7, 2026 16:18
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit 620b6e6 Nov 7, 2026
75 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-4ejvqq branch November 7, 2026 16:39
@objectstack-fleet objectstack-fleet Bot removed the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 7, 2026
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 tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

2 participants