Skip to content

skills(objectstack-platform): teach demoStaff and when to pick it over devLogins - #26420

Merged
os-zhuang merged 2 commits into
mainfrom
claude/project-thread-sfzn7w
Oct 27, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/project-thread-sfzn7w

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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

维护者速读

  • 改了什么:objectstack-platform 技能包的 Seed Data 节新增一小节「Demo accounts — demoStaff vs devLogins」:种子数据把记录分给人,但造不出人(data 里写 sys_user 行会被拒),人声明在 demoStaff,os dev 在开发管理员之后创建账号(用种子密码,条目不带 password;position / permissionSets 只能是本 stack 自己声明的;os build 不写进产物,非开发启动不创建);devLogins 只是启动横幅文字,不创建、不授权。配一条 eval。
  • 为什么改:审计 skills: audit what the skills teach against the protocol since 18.0 — (A) published skills/ vs every added, changed or retired authorable key; (B) where pm-dispatch requires the skills/docs follow-up #26184 的 P1 行 —— 包里只在顶层键清单提到 demoStaff,AI 作者准备 demo 时只声明横幅登录、手写用户种子行,启动后 owner_id 解析不到人。
  • 风险与回滚:只改技能 markdown、eval JSON 和 scripts/check-skills-token-ratchet.mjs 两行天花板数字;不发版、无运行时改动,回滚 = revert 本 PR。风险在教学措辞与 spec 是否一致 —— 六个探针(合法条目、role: 别名、平台权限集、password 键、重名、未声明职位)都用构建后的 defineStack 跑过,结果见 Tests。
  • 先看:① skills/objectstack-platform/SKILL.md 新小节(Seed Data 表之后);② 同文件四处删重复(defineStack() 开头两句、「读源码看精确形状」段、启动序列第 6 步的括号、速查表两条端口注释);③ scripts/check-skills-token-ratchet.mjs 两行天花板(5828→5981、1211→1458)。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs —— 全绿,objectstack-platform 的 SKILL.md 与 eval 文件 headroom 都是 0。
  • 需要你做的:Approve(Tier H,skills/** 是发布面),席位随后落地。

What changes

Row P1 of the audit on #26184 (comment 6425678185, § objectstack-platform), taught in the fewest lines an AI author needs, in the file that names devLogins:

  • skills/objectstack-platform/SKILL.md — a Demo accounts — demoStaff vs devLogins subsection under Seed Data, next to the mode table and the bootstrap cheat sheet: a seed deals records to people and cannot create one (a sys_user row in data is refused, ADR-0092); the people go in demoStaff and os dev creates each account after the development admin, signing in with the seed password (an entry carries no password); one example entry; name is what a seed reference resolves by; position / permissionSets name only what this stack declares (a platform set such as admin_full_access is refused); os build drops the key and a non-dev boot creates nothing; devLogins creates and grants nothing, it only prints an existing account on the boot banner. The choice rule: pick demoStaff whenever the demo needs an account to exist.
  • skills/objectstack-platform/evals/config-plugins-ops.json — eval 7: a demo whose seed names two people and should open signed in as one of them. Expected: both in demoStaff with a declared position / permission set, created by os dev; must_not_contain the role: alias and admin_full_access.
  • scripts/check-skills-token-ratchet.mjs — the two touched CEILINGS rows, each raised by exactly the measured remainder with the arithmetic in the row comment (below).

Every sentence of the section is read off the spec: packages/spec/src/system/demo-staff.zod.ts (the schema, its aliases and guidance), stack.zod.ts (collectDemoStaffErrors, the demoStaff / devLogins TSDoc, the envelope-key note), packages/plugins/plugin-auth/src/demo-staff.ts (the environment gate and the provisioning order) and packages/cli/src/commands/compile.ts (the artifact drops the key). Nothing was taught beyond the card's Wanted.

Why

Who pays: an AI author preparing a demo. The package named demoStaff only in its top-level key list, so the author declared banner logins and hand-wrote user seed rows, and the seed's owner_id references resolved to nobody on the first boot.

Line budget (skills/** is a published surface)

Whole-file, before → after, lines:

File Before After
skills/objectstack-platform/SKILL.md 488 503
skills/objectstack-platform/evals/config-plugins-ops.json 65 75

Whole-package (SKILL.md + references/**/*.md + rules/**/*.md): 2092 → 2107 (+15; the seven other .md files are untouched). references/_index.md is generator-owned and unchanged (41).

Token ratchet — maintainer ruling A

Both touched files sat at the ceiling (SKILL.md headroom 4, the eval file 0). Paid as the maintainer ruled on the seat thread's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」 (2026-10-27T01:21Z), his tap verbatim and untranslated: 「A:先削重复,余额按实测提高」.

Cut first — four genuine restatements in SKILL.md, each with its surviving home in the same file:

Cut Surviving home
The two-sentence intro under ## defineStack() — The Core Configuration ("objectstack.config.ts is the single entry point … calls defineStack()") the opening paragraph (one defineStack() surface over objectstack.config.ts) and the project-tree comment ← THE entry point — defineStack()
The five-line "For the exact Zod shape … read stack.zod.ts …" paragraph, compacted to one pointer line ## References ("Always Read the source for exact field shapes"); the ObjectStackDefinitionSchema pointer stays
Boot sequence step 6's aside (see "Ports & networking" in Part 3) the Port resolution paragraph three lines below, which links the same section
The cheat-sheet comments (auto-hops port if taken) and (see Ports & networking) the same Port resolution paragraph (dev hops, production fails loudly, link)

Then raised by the measured remainder (bytes, because ceil(utf8 bytes / 4) is the convention; the SKILL.md count excludes its 20-byte release-stamp line):

Row Before Cuts Added After Ceiling
SKILL.md 23294 B = 5824 tok (ceiling 5828) −309 B +939 B 23924 B = 5981 tok 5828 → 5981 (+153)
evals/config-plugins-ops.json 4842 B = 1211 tok (ceiling 1211) 0 (six fixtures share no sentence) +989 B 5831 B = 1458 tok 1211 → 1458 (+247)

Both rows are pinned AT the measurement (headroom 0). No other row of the script is touched.

Tests

Spec parse probe — the six shapes the section describes, against the built `@objectstack/spec` (`dist/index.mjs`), exit 0
valid: ACCEPTED
role_alias: REFUSED — demoStaff.0: Unrecognized key(s) on a `demoStaff` entry: `role`. Did you mean `role` → `position`? …
platform_set: REFUSED — Demo account 'Legal Counsel 1' (stack.demoStaff[0]) is granted permission set 'admin_full_access', which this stack does not declare in permissions. A demo account can hold only a permission set its application declares, never a platform set; …
password_key: REFUSED — demoStaff.0: Unrecognized key(s) on a `demoStaff` entry: `password`. | a `demoStaff` entry carries no password: every demo account signs in with the development seed password (`os dev --admin-password`, default `admin123`) …
duplicate_name: REFUSED — Demo account name 'Legal Counsel 1' is declared twice in `demoStaff` … Seed data deals a record to a person by name …
undeclared_position: REFUSED — Demo account 'Paralegal 1' (stack.demoStaff[0]) is assigned position 'paralegal', which this stack does not declare in positions. …

No TypeScript changed, so no package test / typecheck is owed; the new typescript block is a fragment (not os:check-marked), and check:skill-examples still type-checks the package's marked blocks (below). Dogfood battery: n/a — no ! in the title and no (narrowing) arm.

Acceptance notes

  • The section lives in SKILL.md (the routing file, loaded first) rather than references/bootstrap.md: the failure the card names happens while writing seed data, and SKILL.md is where the package's Seed Data section and its only devLogins mention sit. The dispatch order allowed either.
  • references/_index.md is generator-owned; check:skill-refs reports it in sync, so it is not touched.
  • Metadata-protocol: none ⇒ no Skills-docs: line is owed.
  • Noted, not fixed (out of scope): packages/spec/src/system/dev-login.zod.ts carries three guidance strings telling the author to "seed the account itself in data" / "Seed the user record in the stack's data fixtures", while demo-staff.zod.ts says a sys_user row written through data is refused (ADR-0092) — the refusal prescription points at a write the runtime refuses. Reported to the seat in the os-dev report; not reproduced with a boot here.
  • Commit author: the commit was made with an explicit os-warren author override instead of the clone's configured Claude identity; the branch is a harness-owned thread branch, so it was not rewritten. Reported as a deviation.

Verification

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the branch tree (54 families; the derived set is identical before and after the merge of origin/main at 5507225e), each command run locally with its exit code captured before any pipe, then reconciled.

dispatch-gates --ran at head f0926209: 54 derived families accounted for — 53 run (exit 0), 1 NOT-MEASURED, 0 UNRUN. The one NOT-MEASURED is pnpm check:dual-build-cjs-loads, recorded exit 3 (PREREQUISITE NOT MET: it needs every package's dist), so CI's run is its reading.

Readings
  • Ratchet family on the merged head f0926209: node scripts/check-skills-token-ratchet.mjs exit 0 — "81 authored bundle file(s) within their ceilings"; objectstack-platform/SKILL.md 5981 / 5981 (headroom 0), evals/config-plugins-ops.json 1458 / 1458 (headroom 0); --self-test exit 0 (79 cases).
  • The card's three acceptance gates on the merged head: pnpm --filter @objectstack/spec check:skill-docs exit 0 ("Skill docs in sync"); check:skill-refs exit 0 ("9 generated files in sync with packages/spec"); check:skill-examples exit 0 ("264 prose examples type-check across 3 surface(s)"). The latter two sit outside the derived set and were run for the card's acceptance line.
  • The other 50 derived commands ran at 01d2b0f8, whose diff against main is byte-identical to the merged head's (the merge brought other packages' ratchet rows and unrelated files): every exit 0, including pnpm check:pm-dispatch-gates (run detached), pnpm --filter @objectstack/lint run check:doc-formula-expressions and pnpm check:lean-entry-closure.
  • Builds under scripts/pm/os-verify-lock.sh (slot issue-26302): pnpm --filter '@objectstack/client-react...' build VERDICT command-exit 0 (265 s held), which is what lets check:skill-examples type-check the client blocks.
  • Not owed locally: no package test / typecheck (no TypeScript changed); test:repo, pnpm lint and the whole-tree scans are CI's.
  • CI on the PR: not waited for (the order forbids it); the seat reads the check-runs.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (no schema touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's whole-tree run.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. Publishes nothing (skills/** has no package.json; skip-changeset); both declaration lines are 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 Chinese by the repo's own rule).
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

os-warren and others added 2 commits October 27, 2026 02:56
… it over devLogins

The platform skill named `demoStaff` only in its top-level key list, so an
author preparing a demo declared banner logins and hand-wrote user seed
rows. The Seed Data section now says what each key does and which to pick,
with one example and the refusals an author meets, and the package's eval
file gains one prompt for it.

Paid under the token ratchet's ruling A: four restatements cut from
SKILL.md first, then the two touched CEILINGS rows raised by exactly the
measured remainder, each row comment carrying the arithmetic.

Claude-Session: https://claude.ai/code/session_01JQwxbX1XjSzpntF9n85TgB
Co-authored-by: Claude <noreply@anthropic.com>
…-sfzn7w

# Conflicts:
#	scripts/check-skills-token-ratchet.mjs
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Oct 27, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Reviewed at 2026-10-27T03:30Z — independent contract review of PR #26420 (card #26302, skills/objectstack-platform), rendered on head f0926209 from git show f0926209:PATH against the spec and runtime on origin/main (tip 9a0108cd at review time; the PR's merge base is 5507225e). Adversarial by brief: not the dispatch order's conclusions, not the seat's, not the dev's report.

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f092620956fb037651f1300911515854c252ca4d
Local-runs: probe — the two ratchet rows were recomputed by hand as ceil(bytes / 4) over wc -c of the git show blobs (the script's own documented hand audit) and the eval file was JSON-parsed from its blob; nothing was built, run or re-run
Scope: skills/objectstack-platform/SKILL.md, skills/objectstack-platform/evals/config-plugins-ops.json, scripts/check-skills-token-ratchet.mjs + packages/spec/src/system/demo-staff.zod.ts, packages/spec/src/system/dev-login.zod.ts, packages/spec/src/stack.zod.ts (demoStaff / devLogins TSDoc, collectDemoStaffErrors, envelope keys), packages/spec/src/kernel/unmanaged-install.ts, packages/spec/src/kernel/execution-context.zod.ts (SEED_WRITE_EXECUTION_CONTEXT), packages/plugins/plugin-auth/src/demo-staff.ts, auth-plugin.ts, identity-write-guard.ts (+ its test), walled-owner-verification-path.ts (devSeedAdminPassword), dev-admin-seed-gate.ts, demo-staff-provisioning.test.ts, packages/cli/src/commands/dev.ts, build.ts, compile.ts, packages/cli/test/build-demo-staff-artifact.test.ts, packages/runtime/src/app-plugin.ts, app-plugin.seed.test.ts, app-plugin.seed-demo-staff.test.ts, docs/adr/0092-sys-user-profile-field-delegation.md, content/docs/references/system/demo-staff.mdx, dev-login.mdx, skills/objectstack-platform/references/bootstrap.md, operations.md, .github/workflows/lint.yml, ci.yml, .claude/agents/os-dev.md

Landing state when read (2026-10-27T03:21Z): state: open, draft: false, merged: false, mergeable: true, mergeable_state: blocked, auto_merge armed (method merge, enabled by os-zhuang), two APPROVED reviews by os-zhuang on f0926209 (2026-10-27T03:16Z), zero PR comments. Check-runs on f0926209, read once at 2026-10-27T03:21Z: 45 runs; 3 still in_progress — Lint · PM dispatch-gates, Test Core (1/8), Test Core (2/8); every other run success or skipped. The gates this PR answers to: Type Check · source gates (hosts check-skills-token-ratchet + --self-test, check:skill-docs, check:skill-refs on the head's lint.yml) success; Type Check · consumer gates (check:skill-examples) success; Lint · ESLint success; Lint · repo & tooling gates success; Lint · docs & code guards success; Build Core (hosts check:dual-build-cjs-loads, the dev's NOT-MEASURED family) success; Check Changeset success; Governed Surface Queue Guard success (twice); Part-of PR must not also close its card, The card this PR closes must claim this branch, both single-writer guards success. Pending runs are reported as pending, not as green.

① Derived judgments

(a) Every new sentence against the spec and runtime on origin/main

  1. ⛔ FALSE — "a sys_user row in data is refused (ADR-0092)" (SKILL.md line 446; repeated by eval 7's expected output "no hand-written sys_user seed row (refused)"). The sentence copies the TSDoc of packages/spec/src/system/demo-staff.zod.ts lines 14–16, and that TSDoc is wrong against the platform it describes:

    • ADR-0092 D2 (lines 205–220) says the identity write guard "applies to user-context writes only"; "plugin system writes (SYSTEM_CTX) … bypass". identity-write-guard.ts isUserContextWrite() returns false for isSystem: true, and identity-write-guard.test.ts line 84 pins "bypasses system-context … writes" on sys_user.
    • Every seed insert runs under SEED_WRITE_EXECUTION_CONTEXT (packages/spec/src/kernel/execution-context.zod.ts line 630: isSystem: true, skipTriggers: true, seedReplay: true; app-plugin.ts line 56 SEED_WRITE_OPTIONS).
    • The runtime pins the row LANDING: app-plugin.seed.test.ts lines 43, 79, 113 and 290–327 seed data: [{ object: 'sys_user', records: [...] }] and assert insert was called with 'sys_user'. auth-plugin.ts line 1656: "app seeds insert sys_user via raw engine.insert". dev-admin-seed-gate.ts lines 10–22 measured it end to end: "13 sys_user rows, zero sys_account rows, POST /auth/sign-in/email → 401" — a seeded person is "a directory row with no account", not a refusal.
    • ADR-0092 never mentions seed data in those words; its only seed reference (line 214) is the permission-set seed.
      The true reason the spec also gives — "it could not sign in anyway — signing in needs a hashed credential the auth pipeline mints" — is the clause the section dropped. An AI author reading the landed text expects a sys_user seed to fail at load; on the platform it lands silently as a dead row, which is the worse outcome and exactly the "who pays" the card names. A published teaching that states a refusal the platform does not perform is a falsehood under ①(a) — the same bar the sibling brief sets for a wrong parenthetical. FAIL item. Remedy (small): replace the reason with the true one, e.g. "a seed cannot create a person: a sys_user row written through data lands as a directory row with no account, so nobody can sign in as it"; drop "(ADR-0092)"; drop "(refused)" from eval 7's expected output (its assertions need no change); then re-measure both ratchet rows (the SKILL.md byte count will move; both rows must land again at headroom 0 and the row comments' byte arithmetic must be rewritten to match).
  2. ✓ "A seed deals records to people (owner_id: 'Legal Counsel 1') but cannot create one" — true (the dead-row measurement above; demo-staff.zod.ts name TSDoc; collectDemoStaffErrors duplicate-name message "Seed data deals a record to a person by name").

  3. ✓ "Declare the people in demoStaff; os dev creates each account after the development admin" — auth-plugin.ts lines 1442–1446 register the demoStaff kernel:ready hook right after maybeSeedDevAdmin; stack.zod.ts line 1258 "after the development admin"; demo-staff.ts gate 2 explains why the order is load-bearing.

  4. ✓ "signing in with the seed password (--admin-password, default admin123) — an entry carries no password" — dev.ts line 405 declares the admin-password flag and line 804 exports it as OS_SEED_ADMIN_PASSWORD; devSeedAdminPassword() (walled-owner-verification-path.ts line 153) defaults to 'admin123' and maybeProvisionDemoStaff (line 2501) hands exactly that to provisionDemoStaff; DemoStaffSchema is a strictObject with a guidance.password refusal, so password on an entry is refused at parse (pinned by stack-demo-staff.test.ts line 123), not merely absent. The sentence says "carries no password" — true either way.

  5. ✓ The example entry parses: name, email, position, permissionSets are the four keys of DemoStaffSchema; it is a fragment inside a typescript fence, not os:check-marked, and check:skill-examples is green.

  6. ✓ "name is what a seed reference resolves by" — demo-staff.zod.ts name TSDoc and .describe() ("the value a seed dataset names it by in a sys_user reference such as owner_id"); the generated demo-staff.mdx carries the same description.

  7. ✓ "position / permissionSets name only what this stack declares (a platform set such as admin_full_access is refused)" — collectDemoStaffErrors (stack.zod.ts lines 4010–4057) resolves both against the stack's own positions / permissions (top level and assembled package bodies) at defineStack time; the refusal message says "never a platform set"; stack-demo-staff.test.ts line 152 pins admin_full_access as the refused spelling. Parse-time, which the section does not misstate.

  8. ✓ "os build drops the key" — build.ts is an alias for compile; compile.ts line 1011 delete finalBundle.demoStaff at the one place the artifact is written; build-demo-staff-artifact.test.ts measures it by key, by text and through loadArtifactBundle. (The cheat sheet two screens down says os compile; both names are real.)

  9. ✓ "a non-dev boot creates nothing" — decideDemoStaffEnvironmentGate refuses NODE_ENV !== 'development' (and migrate-and-exit, walled posture, non-loopback base URL) and maybeProvisionDemoStaff logs the refusal; serve.ts line 4366 hands the key over on every boot so the refusal is said, not silent. Precision, not a defect: the gate is narrower than "dev boot" (loopback base URL, single posture, an existing login) — "fewest lines" tolerates the elision.

  10. ✓ "devLogins creates and grants nothing — it only prints an existing account on the boot banner" — dev-login.zod.ts "declaring an entry here CREATES NOTHING … presentation"; guidance.permissions "grants nothing — it only names an account for the boot banner to print"; stack.zod.ts line 1227. "Existing" is the intended use (the schema says an entry naming an account nothing seeds "prints a credential that does not work"), so the word is right as teaching.

  11. ✓ The choice rule "Pick demoStaff whenever the demo needs an account to exist" follows from 3 and 10.

(b) The cuts — duplicates with a surviving home (ruling A 「先削重复」), judged on the whole head SKILL.md

  1. ✓ defineStack() intro (two sentences: objectstack.config.ts is the entry point; it calls defineStack()). Home: head line 27–28 "Two concerns over one defineStack() / kernel surface: project setup (objectstack.config.ts, …)" and line 209 objectstack.config.ts # ← THE entry point — defineStack(). Both clauses survive.
  2. ✓ "For the exact Zod shape … read stack.zod.ts … Each collection's item shape lives in its own domain folder" compressed to the pointer at head lines 78–80 (ObjectStackDefinitionSchema, the path, the domain folders all kept). The imperative "read the source" survives at lines 501–502 ("Always Read the source for exact field shapes"). Only the gloss "which keys are optional and what types the collection items take" is gone — that is what reading the schema answers, not a rule.
  3. ✓ Boot step 6's aside "(see Ports & networking in Part 3)". Home: the Port resolution paragraph at lines 349–352 links [Ports & networking](./references/operations.md#ports--networking).
  4. ✓ Cheat-sheet comments "(auto-hops port if taken)" and "(see Ports & networking)". Home: the same paragraph — "dev hops to the next free port, production fails loudly" + the link; operations.md § Ports & networking (lines 61–74) carries the full rule. "pin the port explicitly" stays on the os start line.
    No rule was lost; each cut is a restatement. Under the shared Acceptance ("nothing removed beyond the stale lines the card names") ruling A — the maintainer's own tap, newer — widens the licence to genuine duplicates, and these are.

(c) Ratchet rows pinned at the measurement; ruling quoted where the script requires

  • Convention read off the script: Math.ceil(Buffer.byteLength(text,'utf8') / 4) (line 734), minus the release-stamp line's bytes for a stamped SKILL.md (line 785; hand audit on header line 111). Recomputed over the blobs: origin/main SKILL.md 23314 B − 20 B stamp line = 23294 B → 5824 tokens (ceiling 5828, headroom 4); head SKILL.md 23944 B − 20 B = 23924 B → 5981 (row 5981, headroom 0 ✓). Eval file origin/main 4842 B → 1211; head 5831 B → 1458 (row 1458, headroom 0 ✓). The row comments' arithmetic holds: 23294 − 309 + 939 = 23924; 4842 + 989 = 5831. Neither row carries smuggled headroom; neither is below the measurement.
  • Raise rule (header lines 124–129): a raise "lands only in a PR whose body quotes a maintainer ruling". The PR body quotes the tap verbatim (「A:先削重复,余额按实测提高」, 2026-10-27T01:21Z, the card title) and so do both row comments. ✓
  • scripts/** has no max-len rule in eslint.config.mjs; Lint · ESLint is green on the head. ✓
  • Merge-base reconcile: git diff origin/main f0926209 -- scripts/check-skills-token-ratchet.mjs against the merge base 5507225e shows ONLY this PR's two rows and their comments ✓, and 01d2b0f8's SKILL.md and eval file are byte-identical to the merge head (only the ratchet script differs, by the sibling rows the merge of 5507225e brought: ui skills(objectstack-ui): teach list-view grouping and orderBy, the duration measure, action copy holes, and a flow action's onSuccess #26295 ×5 rows, i18n docs(skills): objectstack-i18n lists every top-level translation group and the nested form, tab and approval keys #26388). Against origin/main NOW (9a0108cd), the head carries three STALE automation rows that docs(skills): objectstack-automation teaches the emailField recipient, flow requiredPermissions, excludeSubmitter and the screen file field #26390 (landed 2026-10-27T02:57Z, before the dev's merge commit at 2026-10-27T03:12Z, so the dev merged a stale origin/main) lowered since: objectstack-automation/SKILL.md 6004 (main 5780), evals/flows-triggers-approvals.json 1823 (main 1255), references/state-machines-and-approvals.md 5587 (main 5569). The PR did not touch those lines, GitHub reports mergeable: true, and a merge-method landing keeps main's values — so this is not a red gate, but it is why the head's ratchet script is not "main + two rows" today.

(d) Eval

  • Eval 7: id unique and sequential (1–7), file JSON-parses, shape identical to the six fixtures (prompt, expected_output, files: [], assertions). must_contain ["demoStaff", "position", "permissionSets", "os dev"] all appear in the expected output. ✓
  • Weakness, not a FAIL: must_not_contain ["role:", "admin_full_access"] names two strings the expected output itself writes in negation ("no role: alias, no platform set such as admin_full_access") — the exemplar answer trips its own assertions. The file already carries this pattern (eval 2's "data:beforeInsert" / "onInstall", eval 4's "@objectstack/adapter-"), so it is the inherited fixture convention, and no in-repo runner reads these files (package.json has no eval script; skills/objectstack-data/evals/README.md calls them "JSON fixtures in the objectui shape"). To-do for the seat below.
  • The eval's "(refused)" parenthetical inherits the ①(a)-1 falsehood and goes with the fix.
  • The card asks "one eval"; the new teaching has one. ✓

(e) Card Wanted met, nothing beyond

  • One short section beside the bootstrap docs, demoStaff against devLogins ✓ — 19 lines under Seed Data, the section that owns data:, in the file that carries the package's only devLogins mention (line 49). The dispatch order allowed SKILL.md or references/bootstrap.md.
  • Line 1 of SKILL.md untouched (PR chore: version packages #25640 owns it): the first 23 lines (whole frontmatter, stamp line version: "18.1.0" at line 20) are byte-identical to origin/main; the first hunk starts at line 33. ✓
  • No file outside the claim's surface: three files; references/_index.md untouched (generator-owned; check:skill-refs green). ✓
  • Line counts as the shared Acceptance demands, verified: SKILL.md 488 → 503; eval 65 → 75; package .md total (SKILL.md + references//*.md + rules//*.md, eight files) 2092 → 2107 (+15). The body's table matches. ✓

(f) PR body

  • Line 1 the harness attribution HTML comment, line 2 _Requested by_, line 3 Fixes #26302, then Clause-②: no and Metadata-protocol: none line-initial. os-dev.md line 323 is the exemption: "harness 自写的 PR 正文首行归属注释原样留、只报;Fixes #N 紧随其后" — the _Requested by_ line is part of the harness block, and the two body-parsing guards (Part-of PR must not also close its card, The card this PR closes must claim this branch) are green, so the parsers read Fixes fine. ✓ No Skills-docs: line: os-dev.md line 279 owes it only for a non-none kind or (narrowing) — none owed, none written ✓ (the triage line's "Skills-docs: updated here" is a loose note, not the rule).
  • ## 维护者速读 six labels in order; 需要你做的 = one action (Approve), right for Tier H; 先看 three items naming the hunks; 两分钟验证 one command — the script prints tokens / ceiling (delta) per row, so "headroom 都是 0" reads as (+0) on both platform rows — a fair paraphrase. English sections What changes / Tests / Acceptance notes / Verification present, readings folded in details blocks. Both readings (file and package lines, plus tokens) present. ✓
  • The body's Tests section quotes six defineStack probes — all six consistent with demo-staff.zod.ts / collectDemoStaffErrors messages read here. The body's own "What changes" repeats the ①(a)-1 sentence ("a sys_user row in data is refused, ADR-0092") — amend with the fix.

(g) Report and claim

  • os-dev-report 6432875949 (2026-10-27T03:17Z) carries deviations (6), line_budget, out_of_scope_findings (1), mcp_calls: 2 (reads only), api_writes: 2; files_changed / rules_retired are not keys of the os-dev.md template on origin/main (lines 362–380), so not owed. Branch claude/project-thread-sfzn7w = the claim's Branch: line. ✓
  • The report's session field spells out raw model identifiers ("session_context.model …") where the claim and the fleet's records use the tier name; the card comment is the dev's, not this record's, but it is a norm slip for the seat's roster.
  • Commit 01d2b0f8: author/committer os-warren (the reported override; the harness thread branch is not rewritten, AGENTS.md §3); both commit trailers model-free; no model name in either commit message or the PR body. ✓

② Semver level

skip-changeset is right: skills/objectstack-platform/ has no package.json; scripts/check-skills-token-ratchet.mjs publishes nothing; no .changeset/*.md touched. Check Changeset green. Clause-②: no and Metadata-protocol: none line-initial in the body (and the claim). The skill teaches keys (demoStaff, devLogins) the protocol already carries since 18.2 / 17.5 — no protocol change, no Skills-docs: owed.

③ Boundary flags

  1. Card candidate (from ①(a)-1, widening the dev's class-c finding and reversing its direction): packages/spec/src/system/demo-staff.zod.ts TSDoc (lines 14–16) states "a sys_user row written through data is refused (ADR-0092)", which the runtime does not do — a seeded sys_user lands as an account-less directory row (dev-admin-seed-gate.ts, app-plugin.seed.test.ts). dev-login.zod.ts guidance ("seed the account itself in data", "Seed the user record in the stack's data fixtures") describes a write that lands but produces a row nobody can sign in as — a prescription for the dead-row defect, now that demoStaff exists. One card: correct both spec texts to the measured behaviour and point devLogins guidance at demoStaff. Class c (spec prose vs runtime), reach: public teaching surfaces (@objectstack/spec TSDoc, generated reference docs are unaffected since they render .describe() only, this skill). Dedupe words: demo-staff.zod.ts ADR-0092 refused seed sys_user TSDoc, seeded sys_user directory row no account, dev-login.zod.ts guidance seed data demoStaff.
  2. Landing order: two APPROVED reviews by os-zhuang on f0926209 (2026-10-27T03:16Z), the PR readied and auto-merge armed before any contract review existed; Governed Surface Queue Guard passed twice before this record. os-zhuang is an authorized approver under the dispatch order's Tier H wording, so the approval itself is within the ruling — the sequence (approve, ready, arm, then review) is not what the Tier H text describes ("the seat runs the independent review; the maintainer's hand … lands it"), and with a FAIL record on the head the auto-merge should be disarmed by someone with the write (this record is read-only). If the queue took the PR before this posted, the record stands against head f0926209 and the fix is a follow-up PR on the same card.
  3. Stale sibling rows (①(c)): three automation rows on the head are older than origin/main's; a merge-method landing resolves them to main's values. No action unless the landing is squashed onto a rebased head, in which case the rebase must take main's rows.
  4. Dev's deviations, verified: 2 GitHub MCP reads before the ban was read (no writes; stated); author override on 01d2b0f8 (not rewritten, per AGENTS.md §3; the queue squashes); check:dual-build-cjs-loads NOT-MEASURED locally — CI's Build Core hosts it and is green on the head; worktree cleaned (dev's word; not verifiable here).
  5. Eval must_not_contain strings that the ideal answer writes in negation (①(d)) — a fixture-convention weakness across this file and the sibling files; a to-do for the skills lane, not a card.

Implemented-by: claude/project-thread-sfzn7w
Reviewed-by: session_01LqKsGyMNFwwnbF5FTAqyPn

VERDICT: FAIL — ①(a) item 1: the new section's opening reason "a sys_user row in data is refused (ADR-0092)" (SKILL.md line 446, repeated as "(refused)" in eval 7 and in the PR body) teaches a refusal the platform does not perform; the runtime pins the row landing under the system seed context. Every other item passes (cuts, both ratchet rows at headroom 0, line counts, body shape, semver). Fix: reword the one sentence to the true reason, drop the ADR citation and the eval's parenthetical, re-measure the two rows, amend the body.


Generated by Claude Code

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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills(objectstack-platform): teach demoStaff and when to pick it over devLogins

3 participants