diff --git a/scripts/check-skills-token-ratchet.mjs b/scripts/check-skills-token-ratchet.mjs index dc50a8cacfb..fe4c35991cb 100644 --- a/scripts/check-skills-token-ratchet.mjs +++ b/scripts/check-skills-token-ratchet.mjs @@ -421,7 +421,27 @@ export const CEILINGS = new Map([ // decision tables at 487 lines. // 5833 -> 5828: A2′ — the release-stamp line left the count (see // STAMP_LINE_REPIN); the file's count fell by the same 5, headroom unchanged. - ['skills/objectstack-platform/SKILL.md', 5828], + // 5828 -> 5981 (card #26302, the objectstack-platform row of the skills gap + // audit): the Seed Data section gains `demoStaff` against `devLogins` — a + // seed deals records to people and cannot create one, so the people are + // declared in `demoStaff` and `os dev` creates the accounts (position and + // permission sets from the stack's own declarations, the seed password, never + // in the built artifact), while `devLogins` is banner text that creates and + // grants nothing. Maintainer ruling 2026-10-27 on the seat's decision card + // 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, his tap verbatim + // and untranslated: 「A:先削重复,余额按实测提高」. Paid down first, as the + // ruling asks — four restatements cut, each with a surviving home in the + // file: the `defineStack()` intro (the opening paragraph and the project + // tree say it), the "read the source for the exact shape" paragraph (the + // References section keeps the rule; one pointer line stays), the boot + // sequence's "(see Ports & networking)" aside and the two cheat-sheet port + // comments (the Port resolution paragraph says both). Arithmetic in bytes: + // on `origin/main` the priced text was 23294 bytes (5824 tokens, headroom 4); + // the cuts remove 309 bytes and the section adds 939, so the LANDED priced + // text is 23924 bytes -> 5981 tokens: the 4 tokens of headroom are absorbed + // and the ceiling moves 5828 -> 5981 (+153). Pinned AT the measurement. + // ceil(($(wc -c < skills/objectstack-platform/SKILL.md) - 20) / 4) == ceil(23924 / 4) + ['skills/objectstack-platform/SKILL.md', 5981], // `skills/objectstack-pm-dispatch/SKILL.md` (9708) and its // `rules/dev-template.md` (1838) left this table on 2026-09-10 with the files: // the maintainer deleted the published PM skill whole (verbatim: @@ -724,7 +744,17 @@ export const CEILINGS = new Map([ // is the whole addition; pinned AT the measurement, zero headroom. The // raising PR's body carries the same arithmetic. ['skills/objectstack-i18n/evals/bundles-locales-coverage.json', 1451], - ['skills/objectstack-platform/evals/config-plugins-ops.json', 1211], + // 1211 -> 1458 (card #26302): one eval for a demo whose seed names people — + // expected: both in `demoStaff` with a declared `position` / + // `permissionSets`, created by `os dev`; NO `role:` alias and NO platform + // set such as `admin_full_access`. Same ruling as the `SKILL.md` row above + // (2026-10-27, tap A: 「A:先削重复,余额按实测提高」); the file's six fixtures + // share no sentence, so there was no duplicate to cut (0 bytes). On + // `origin/main` the file was 4842 bytes (1211 tokens, headroom 0); the + // fixture adds +989 bytes, so the LANDED file is 5831 bytes -> 1458 tokens, + // ceiling +247, pinned AT the measurement. + // ceil($(wc -c < skills/objectstack-platform/evals/config-plugins-ops.json) / 4) == ceil(5831 / 4) + ['skills/objectstack-platform/evals/config-plugins-ops.json', 1458], ['skills/objectstack-query/evals/filters-pagination-search.json', 955], // 1505 -> 1789 (#26295): two eval prompts — list grouping with `orderBy`, and the copy hole // + `onSuccess` pair — +284 tokens in the file's shape; fixtures, nothing to delete, the diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md index 4979af2ac36..4a212db40b3 100644 --- a/skills/objectstack-platform/SKILL.md +++ b/skills/objectstack-platform/SKILL.md @@ -33,9 +33,6 @@ development** (plugins, services, kernel hook / event handlers, ## `defineStack()` — The Core Configuration -`objectstack.config.ts` is the single entry point for every project. -It calls `defineStack()` to declare all metadata. - → Moved verbatim to [references/bootstrap.md](./references/bootstrap.md) § Minimal Example. ### Full Configuration Reference @@ -78,11 +75,9 @@ keeping straight: scheduled migration, so a key that only warns today is expected to be refused later. -For the exact Zod shape — including which keys are optional and what types -the collection items take — read -`node_modules/@objectstack/spec/src/stack.zod.ts` -(`ObjectStackDefinitionSchema`). Each collection's item shape lives in -its own domain folder (`data/object.zod.ts`, `ui/view.zod.ts`, …). +Exact shape: `ObjectStackDefinitionSchema` in +`node_modules/@objectstack/spec/src/stack.zod.ts`; each collection's item +schema sits in its domain folder (`data/object.zod.ts`, `ui/view.zod.ts`, …). → Moved verbatim to [references/bootstrap.md](./references/bootstrap.md) § Map Format (Key → Name) · § Barrel Import Pattern. @@ -348,7 +343,7 @@ CLI: `os serve` / `os dev` ├── DispatcherPlugin └── AIServicePlugin (cloud / EE only — reverse-mounted by a cloud host; absent in the open framework per cloud ADR-0025) 5. Runtime.start() → init + start all plugins - 6. Server listens on the resolved port (see "Ports & networking" in Part 3) + 6. Server listens on the resolved port ``` **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 | `ignore` | Insert if not exists, skip otherwise | | `replace` | ⚠️ **Data loss** — drops and re-inserts all records | +### Demo accounts — `demoStaff` vs `devLogins` + +A seed deals records to people (`owner_id: 'Legal Counsel 1'`) but cannot +create one: a `sys_user` row in `data` is refused (ADR-0092). Declare the +people in `demoStaff`; `os dev` creates each account after the development +admin, signing in with the seed password (`--admin-password`, default +`admin123`) — an entry carries no `password`: + +```typescript +demoStaff: [{ name: 'Legal Counsel 1', email: 'counsel1@example.com', + position: 'legal_counsel', permissionSets: ['contracts_editor'] }], +``` + +`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. Pick `demoStaff` whenever the demo +needs an account to exist. + --- ## CLI Commands @@ -455,12 +470,12 @@ Cheat sheet for the bootstrap loop: ```bash npx create-objectstack my-app cd my-app && npm install -os dev --ui # dev server + Console at /_console/ (auto-hops port if taken) +os dev --ui # dev server + Console at /_console/ os validate # metadata cross-reference checks os compile # produce dist/ artifact os migrate plan # preview metadata↔DB schema drift (additive sync never alters existing columns) os migrate apply # reconcile DB to metadata (loosening only; --allow-destructive for drops/tightenings) -PORT=8080 os start # production — pin the port explicitly (see Ports & networking) +PORT=8080 os start # production — pin the port explicitly ``` --- diff --git a/skills/objectstack-platform/evals/config-plugins-ops.json b/skills/objectstack-platform/evals/config-plugins-ops.json index a114aa80a0e..b5c9dca96cd 100644 --- a/skills/objectstack-platform/evals/config-plugins-ops.json +++ b/skills/objectstack-platform/evals/config-plugins-ops.json @@ -60,6 +60,16 @@ "must_contain": ["os start", "PORT", "OS_TRUSTED_ORIGINS", "driver-sql"], "must_not_contain": ["new DriverPlugin", "@objectstack/plugin-prometheus"] } + }, + { + "id": 7, + "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.", + "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.", + "files": [], + "assertions": { + "must_contain": ["demoStaff", "position", "permissionSets", "os dev"], + "must_not_contain": ["role:", "admin_full_access"] + } } ] }