diff --git a/content/docs/getting-started/build-with-claude-code.mdx b/content/docs/getting-started/build-with-claude-code.mdx index cd473f894b..0229c2153a 100644 --- a/content/docs/getting-started/build-with-claude-code.mdx +++ b/content/docs/getting-started/build-with-claude-code.mdx @@ -356,7 +356,7 @@ prompt you can give verbatim: |:---|:---|:---| | Data model — objects, fields, relationships, validations, seeds | `objectstack-data` | "Add an `account` object and link tickets to it with a required lookup. Seed three demo accounts." | | Queries & reports over records | `objectstack-query` | "Show me the count of open tickets per priority, using an aggregation." | -| Views, dashboards, apps, record pages | `objectstack-ui` | "Add a dashboard with a metric for open tickets and a bar chart of tickets by priority." | +| Views, dashboards, apps, record pages | `objectstack-ui` | "Declare a `tickets` dataset over the ticket object, then add a dashboard with a metric for open tickets and a bar chart of tickets by priority." | | Business automation — flows, approvals, schedules | `objectstack-automation` | "Every day at 9:00, escalate tickets that have been open more than 48 hours." | | Permissions & row-level security | `objectstack-data` (security sections) | "Members should only see their own tickets; support managers see everything." | | Formula / conditional-field logic (CEL) | `objectstack-formula` | "Make `resolved_at` required and visible only when status is resolved." | @@ -364,8 +364,16 @@ prompt you can give verbatim: | REST/auth surface tuning | `objectstack-api` | "Restrict the ticket API to read-only for non-members." | | Translations | `objectstack-i18n` | "Add a zh-CN translation bundle for the ticket object and app navigation." | -Two habits keep this reliable as the app grows: +Three habits keep this reliable as the app grows: +- **A module is not finished until its analytics face exists.** Objects, views + and a nav entry make an object usable; they do not make it *reportable*. + Dashboards and reports bind a **declared dataset** by name + (`src/datasets/*.dataset.ts`) — the layer that carries the governed joins, + filters and measure definitions an object does not express — so an object with + no dataset simply never appears in the report builder. Ask for the dataset in + the same breath as the views, and `objectstack-ui`'s completeness blueprint + lists it as its own line item. - **The gate applies to every domain.** Flows, dashboards, permissions, and translations all go through the same `npm run validate` — the agent should run it after each change, exactly as `AGENTS.md` instructs. diff --git a/scripts/check-skills-token-ratchet.mjs b/scripts/check-skills-token-ratchet.mjs index 1c34a0aeb3..eace267b2e 100644 --- a/scripts/check-skills-token-ratchet.mjs +++ b/scripts/check-skills-token-ratchet.mjs @@ -272,7 +272,21 @@ export const CEILINGS = new Map([ // minimal anchor form; the raising PR's body carries the arithmetic. ['skills/objectstack-pm-dispatch/SKILL.md', 14391], ['skills/objectstack-query/SKILL.md', 5552], // -17 (was 5569) - ['skills/objectstack-ui/SKILL.md', 25125], // -29 (was 25154) + // 25125 -> 25143: the CRM UI Blueprint — the catalog's module-completeness + // list, and the only place an agent is told what a finished module contains — + // priced `src/views/**`, `src/apps/**`, dashboards and reports but never the + // DATASET those last two bind, so an agent grew the app face and left the + // analytics face silently empty (a module shipped with views, nav, approvals + // and permissions was simply absent from the report builder). Maintainer + // ruling 2026-08-31, director seat batch #15, verbatim and untranslated: + // 「同意」 — accepting option C, whose text is: 「发布技能与文档的「长模块」路径 + // 必须把 dataset 声明列为模块完整性的一部分」. Arithmetic, in bytes because that + // is what this convention divides: +204 for the new blueprint row, -7 for the + // Reports row it lets shrink, and -77 for a sentence deleted in the same file + // that restated report binding a second time inside its own paragraph — +120 + // net, 25113 -> 25143 tokens. The row's 12 tokens of headroom absorb part of + // it, so the CEILING moves 18. The raising PR's body carries the same numbers. + ['skills/objectstack-ui/SKILL.md', 25143], ['skills/objectstack-upgrade/SKILL.md', 8333], // -2 (was 8335) // ── the #12392 extension: the rest of the AUTHORED bundle ──────────────── diff --git a/skills/objectstack-ui/SKILL.md b/skills/objectstack-ui/SKILL.md index 5312175192..960d88598f 100644 --- a/skills/objectstack-ui/SKILL.md +++ b/skills/objectstack-ui/SKILL.md @@ -688,7 +688,7 @@ allowed joins, intrinsic filter, dimensions, and certified measures. The legacy per-widget inline query (`object` + `categoryField` + `valueField` + `aggregate`) **was removed** — a widget now requires `dataset` + `values`; the closed schema REJECTS the inline keys by name, and one lacking `dataset` fails `os validate`. -Reports bind the same way (`dataset` + `rows` + `values` + `runtimeFilter`). The dataset shape is +The dataset shape is `DatasetSchema` — see `node_modules/@objectstack/spec/src/ui/dataset.zod.ts`. A widget's presentation-scope `filter` flows into the query as the runtime @@ -1404,8 +1404,9 @@ Use this CRM-style structure as the canonical UI assembly reference: | Multi-view object UI | `src/views/*.view.ts` | Define default `list` + `form`, then named `listViews` / `formViews` for scenarios | | **Public / anonymous form** | `src/views/*.view.ts` (formView with `sharing.allowAnonymous: true`) | Web-to-Lead / Web-to-Case. Auto-exposed at `GET/POST /api/v1/forms/:slug` | | App navigation | `src/apps/*.app.ts` | Use grouped nav trees, `viewName` shortcuts, and `requiresObject` for capability-aware visibility | +| **Analytics dataset** | `src/datasets/*.dataset.ts` | One per object you want reportable — dashboards and reports bind a **declared** dataset by name, so an object without one has no analytics face | | Dashboards | `src/dashboards/*.dashboard.ts` | Combine KPI + chart + table widgets with shared `dateRange` and `globalFilters` | -| Reports | `src/reports/*.report.ts` | Bind a `dataset` + `rows` (dimensions) + `values` (measures) for tabular/summary/matrix/joined analytics | +| Reports | `src/reports/*.report.ts` | Select `rows` (dimensions) + `values` (measures) from that dataset; tabular/summary/matrix/joined | | Record pages | `src/pages/*.page.ts` | Compose `regions` + components (`page:header`, `record:highlights`, related lists, tabs) | | User actions | `src/actions/*.actions.ts` | Use `flow` for orchestration and `modal` for parameterized bulk mutations |