Skip to content

Commit 75afeff

Browse files
objectstack-fleet[bot]os-warrenclaude
authored
skills(objectstack-platform): teach demoStaff and when to pick it over devLogins (#26420)
<!-- claude-projects-attribution: {"github_login":"os-warren"} --> _Requested by **Warren** · [project thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ81ut4uJxWyaaick9b2LrTc1)_ 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。 - **为什么改**:审计 #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 <details><summary>Spec parse probe — the six shapes the section describes, against the built `@objectstack/spec` (`dist/index.mjs`), exit 0</summary> ``` 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. … ``` </details> 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. <details><summary>Readings</summary> - 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. </details> ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (no schema touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` is CI's whole-tree run. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. Publishes nothing (`skills/**` has no `package.json`; `skip-changeset`); both declaration lines are above. - [x] 6. `packages/spec` not touched. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the 维护者速读 block and the quoted ruling are Chinese by the repo's own rule). - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01JQwxbX1XjSzpntF9n85TgB)_ Co-authored-by: os-warren <warren@objectstack.ai> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 08ed7e2 commit 75afeff

3 files changed

Lines changed: 68 additions & 13 deletions

File tree

‎scripts/check-skills-token-ratchet.mjs‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,27 @@ export const CEILINGS = new Map([
431431
// decision tables at 487 lines.
432432
// 5833 -> 5828: A2′ — the release-stamp line left the count (see
433433
// STAMP_LINE_REPIN); the file's count fell by the same 5, headroom unchanged.
434-
['skills/objectstack-platform/SKILL.md', 5828],
434+
// 5828 -> 5981 (card #26302, the objectstack-platform row of the skills gap
435+
// audit): the Seed Data section gains `demoStaff` against `devLogins` — a
436+
// seed deals records to people and cannot create one, so the people are
437+
// declared in `demoStaff` and `os dev` creates the accounts (position and
438+
// permission sets from the stack's own declarations, the seed password, never
439+
// in the built artifact), while `devLogins` is banner text that creates and
440+
// grants nothing. Maintainer ruling 2026-10-27 on the seat's decision card
441+
// 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, his tap verbatim
442+
// and untranslated: 「A:先削重复,余额按实测提高」. Paid down first, as the
443+
// ruling asks — four restatements cut, each with a surviving home in the
444+
// file: the `defineStack()` intro (the opening paragraph and the project
445+
// tree say it), the "read the source for the exact shape" paragraph (the
446+
// References section keeps the rule; one pointer line stays), the boot
447+
// sequence's "(see Ports & networking)" aside and the two cheat-sheet port
448+
// comments (the Port resolution paragraph says both). Arithmetic in bytes:
449+
// on `origin/main` the priced text was 23294 bytes (5824 tokens, headroom 4);
450+
// the cuts remove 309 bytes and the section adds 939, so the LANDED priced
451+
// text is 23924 bytes -> 5981 tokens: the 4 tokens of headroom are absorbed
452+
// and the ceiling moves 5828 -> 5981 (+153). Pinned AT the measurement.
453+
// ceil(($(wc -c < skills/objectstack-platform/SKILL.md) - 20) / 4) == ceil(23924 / 4)
454+
['skills/objectstack-platform/SKILL.md', 5981],
435455
// `skills/objectstack-pm-dispatch/SKILL.md` (9708) and its
436456
// `rules/dev-template.md` (1838) left this table on 2026-09-10 with the files:
437457
// the maintainer deleted the published PM skill whole (verbatim:
@@ -740,7 +760,17 @@ export const CEILINGS = new Map([
740760
// is the whole addition; pinned AT the measurement, zero headroom. The
741761
// raising PR's body carries the same arithmetic.
742762
['skills/objectstack-i18n/evals/bundles-locales-coverage.json', 1451],
743-
['skills/objectstack-platform/evals/config-plugins-ops.json', 1211],
763+
// 1211 -> 1458 (card #26302): one eval for a demo whose seed names people —
764+
// expected: both in `demoStaff` with a declared `position` /
765+
// `permissionSets`, created by `os dev`; NO `role:` alias and NO platform
766+
// set such as `admin_full_access`. Same ruling as the `SKILL.md` row above
767+
// (2026-10-27, tap A: 「A:先削重复,余额按实测提高」); the file's six fixtures
768+
// share no sentence, so there was no duplicate to cut (0 bytes). On
769+
// `origin/main` the file was 4842 bytes (1211 tokens, headroom 0); the
770+
// fixture adds +989 bytes, so the LANDED file is 5831 bytes -> 1458 tokens,
771+
// ceiling +247, pinned AT the measurement.
772+
// ceil($(wc -c < skills/objectstack-platform/evals/config-plugins-ops.json) / 4) == ceil(5831 / 4)
773+
['skills/objectstack-platform/evals/config-plugins-ops.json', 1458],
744774
['skills/objectstack-query/evals/filters-pagination-search.json', 955],
745775
// 1505 -> 1789 (#26295): two eval prompts — list grouping with `orderBy`, and the copy hole
746776
// + `onSuccess` pair — +284 tokens in the file's shape; fixtures, nothing to delete, the

‎skills/objectstack-platform/SKILL.md‎

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ development** (plugins, services, kernel hook / event handlers,
3333

3434
## `defineStack()` — The Core Configuration
3535

36-
`objectstack.config.ts` is the single entry point for every project.
37-
It calls `defineStack()` to declare all metadata.
38-
3936
→ Moved verbatim to [references/bootstrap.md](./references/bootstrap.md) § Minimal Example.
4037

4138
### Full Configuration Reference
@@ -78,11 +75,9 @@ keeping straight:
7875
scheduled migration, so a key that only warns today is expected to be
7976
refused later.
8077

81-
For the exact Zod shape — including which keys are optional and what types
82-
the collection items take — read
83-
`node_modules/@objectstack/spec/src/stack.zod.ts`
84-
(`ObjectStackDefinitionSchema`). Each collection's item shape lives in
85-
its own domain folder (`data/object.zod.ts`, `ui/view.zod.ts`, …).
78+
Exact shape: `ObjectStackDefinitionSchema` in
79+
`node_modules/@objectstack/spec/src/stack.zod.ts`; each collection's item
80+
schema sits in its domain folder (`data/object.zod.ts`, `ui/view.zod.ts`, …).
8681

8782
→ Moved verbatim to [references/bootstrap.md](./references/bootstrap.md) § Map Format (Key → Name) · § Barrel Import Pattern.
8883

@@ -348,7 +343,7 @@ CLI: `os serve` / `os dev`
348343
├── DispatcherPlugin
349344
└── AIServicePlugin (cloud / EE only — reverse-mounted by a cloud host; absent in the open framework per cloud ADR-0025)
350345
5. Runtime.start() → init + start all plugins
351-
6. Server listens on the resolved port (see "Ports & networking" in Part 3)
346+
6. Server listens on the resolved port
352347
```
353348

354349
**Port resolution** (both `os dev` and `os start` → `os serve`):
@@ -445,6 +440,26 @@ definition: never write it by hand, and never hand-write a raw
445440
| `ignore` | Insert if not exists, skip otherwise |
446441
| `replace` | ⚠️ **Data loss** — drops and re-inserts all records |
447442

443+
### Demo accounts — `demoStaff` vs `devLogins`
444+
445+
A seed deals records to people (`owner_id: 'Legal Counsel 1'`) but cannot
446+
create one: a `sys_user` row in `data` is refused (ADR-0092). Declare the
447+
people in `demoStaff`; `os dev` creates each account after the development
448+
admin, signing in with the seed password (`--admin-password`, default
449+
`admin123`) — an entry carries no `password`:
450+
451+
```typescript
452+
demoStaff: [{ name: 'Legal Counsel 1', email: 'counsel1@example.com',
453+
position: 'legal_counsel', permissionSets: ['contracts_editor'] }],
454+
```
455+
456+
`name` is what a seed reference resolves by; `position` / `permissionSets`
457+
name only what this stack declares (a platform set such as
458+
`admin_full_access` is refused); `os build` drops the key and a non-dev boot
459+
creates nothing. `devLogins` creates and grants nothing — it only prints an
460+
existing account on the boot banner. Pick `demoStaff` whenever the demo
461+
needs an account to exist.
462+
448463
---
449464

450465
## CLI Commands
@@ -455,12 +470,12 @@ Cheat sheet for the bootstrap loop:
455470
```bash
456471
npx create-objectstack my-app
457472
cd my-app && npm install
458-
os dev --ui # dev server + Console at /_console/ (auto-hops port if taken)
473+
os dev --ui # dev server + Console at /_console/
459474
os validate # metadata cross-reference checks
460475
os compile # produce dist/ artifact
461476
os migrate plan # preview metadata↔DB schema drift (additive sync never alters existing columns)
462477
os migrate apply # reconcile DB to metadata (loosening only; --allow-destructive for drops/tightenings)
463-
PORT=8080 os start # production — pin the port explicitly (see Ports & networking)
478+
PORT=8080 os start # production — pin the port explicitly
464479
```
465480

466481
---

‎skills/objectstack-platform/evals/config-plugins-ops.json‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@
6060
"must_contain": ["os start", "PORT", "OS_TRUSTED_ORIGINS", "driver-sql"],
6161
"must_not_contain": ["new DriverPlugin", "@objectstack/plugin-prometheus"]
6262
}
63+
},
64+
{
65+
"id": 7,
66+
"prompt": "Prepare a demo of our contracts app: the seed data assigns matters to 'Legal Counsel 1' and 'Paralegal 1', and the demo should open signed in as Legal Counsel 1.",
67+
"expected_output": "Both people go in `demoStaff` — `name` exactly as the seed references them, `email`, and a `position` / `permissionSets` the stack itself declares — and `os dev` creates the accounts with the seed password (`admin123` by default): no `password` key, no `role:` alias, no platform set such as `admin_full_access`, and no hand-written `sys_user` seed row (refused). `devLogins` creates nothing: at most one entry naming Legal Counsel 1's address so the boot banner prints it. Notes that `os build` drops `demoStaff` and a production boot creates no demo account.",
68+
"files": [],
69+
"assertions": {
70+
"must_contain": ["demoStaff", "position", "permissionSets", "os dev"],
71+
"must_not_contain": ["role:", "admin_full_access"]
72+
}
6373
}
6474
]
6575
}

0 commit comments

Comments
 (0)