Skip to content

Commit 46ca793

Browse files
docs(skills): pages.md says what a page type, template and region name run (#23758)
Fixes #23610 Clause-②: no Executes ruling `6190536588` item 4 under claim `6204703954`: `skills/objectstack-ui/rules/pages.md` says what PR #23708 makes the page contract. This PR is the card's last piece and carries its closing keyword (#23708 is `Part of #23610`). **It turns ready only after #23708 has merged** — the seat marks it; the dev does not — and, as a `skills/**` diff (governed, Tier H), it lands only after a human approval, by the seat. ## What changes One skill file, `skills/objectstack-ui/rules/pages.md`, plus a `@objectstack/skills` patch changeset. Every sentence follows the spec text #23708 lands — `PageTypeSchema`'s docblock and enum comments, `PageTemplateSchema`, `PAGE_TEMPLATE_SLOTS`, `checkPageRegionPlacement`, `misplacedDefaultPageRefusal`, the `utility` print refusal — and `content/docs/ui/pages.mdx`'s new wording. Nothing the spec does not declare enters the skill. | Where (line on `main`) | Was | Now | | :--- | :--- | :--- | | Page Types table, `home` (24) | App home / landing page | Widest region page; not a landing (`isDefault` refused): an app opens on its first navigation item | | Page Types table, `app` (25) | App-level page with navigation context | Region page at app width | | Page Types table, `utility` (26) | Floating utility panel (e.g. notes, phone dialer) | Narrow inline region page for a tool (notes, a dialer); no floating or docked shell slot exists | | Disambiguation paragraph (29–34) | "…a utility panel is `type: 'utility'`…" plus a restatement of the table's three `type` values | The no-such-type list and the visualizations-are-not-page-types sentence stay; the restated `type` values go (the table carries them) | | Templates & Regions (38–41) | `three-column` / `two-column` / `single-column`; regions `header`, `left_sidebar`, `main`, `right_sidebar`, `footer` | `default` (header, sidebar, main, aside, footer), `header-sidebar-main` (header, sidebar, main), `three-column` (the same five), `dashboard` (header, footer; other regions are grid cells); `full-width` retired; on a `kind: 'full'` page a region the template does not place, or a second region for a filled slot, is refused at its `name`; left column `sidebar`, right `aside` | | Print pages (71–72) | "a `utility` panel" | "a `utility` page" | | Source tiers (137–138) | "The legacy value `kind:'jsx'` is a deprecated alias for `kind:'html'`" | "`kind:'jsx'` is retired: the parse refuses it and names `kind:'html'`" (#23543 F5-jsx, PR #23638) | The `home` row's landing sentence is the one `misplacedDefaultPageRefusal` prints (an app's landing is its first navigation item); the `utility` row's is `PageTypeSchema`'s ("no floating or docked shell slot"); the template sentence is `PAGE_TEMPLATE_SLOTS` plus `checkPageRegionPlacement`'s two refusals (unplaced region; second region for a filled slot). The file mentioned no page default or landing anywhere else, so nothing else moved. ## Token ratchet — paid in the same file `check:skills-token-ratchet` holds `rules/pages.md` at ceiling 5692 with 6 tokens of headroom on `main`. The new sentences cost about 135 tokens, so they are paid by deleting content from the same file, never by re-wrapping: - the disambiguation clause that restated the table's three `type` values; - the renderer clause of the five-values line (its ADR-0049 citation stays); - the `responsive.zod.ts` source pointer under the Styling rules (the field name `responsiveStyles` and every rule stay). Readings, `ceil(utf8 bytes / 4)` as the gate counts, at `a869ea6` → this head: | Reading | Before | After | | :--- | ---: | ---: | | `rules/pages.md` lines | 433 | 428 | | `rules/pages.md` bytes / tokens | 22,741 / 5,686 | 22,727 / 5,682 (ceiling 5,692) | | `skills/**/*.md` lines | 12,697 | 12,692 | | `skills/**/*.md` bytes / tokens | 576,525 / 144,132 | 576,511 / 144,128 | | sum of the eleven `SKILL.md` lines | 4,408 | 4,408 | ## Changeset `@objectstack/skills: patch` (`.changeset/23610-skills-pages-contract.md`): `packages/skills` ships the `skills/**` tree (`sync-catalog.mjs` → `dist`), so this text publishes; a docs fix in a released package takes `patch`. `Clause-②: no` — the accept set and the public surface are unchanged. ## Eval fixtures and generated references - `skills/objectstack-ui/evals/views-apps-actions-pages.json:37` names `template: 'three-column'` — a member of the closed set, so it stands. No fixture under `skills/objectstack-ui/evals/` and no sibling `rules/*.md` or `SKILL.md` names `utility`, `left_sidebar`, `right_sidebar`, `two-column`, `single-column`, `full-width` or `kind:'jsx'` (grep on this head). - `skills/objectstack-ui/references/_index.md` is generator-owned and unchanged (#23708 keeps it byte-identical). No other `skills/**` path enters this PR. ## Verification (head `e97d4c0`) - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: 41 families; each run once, exit captured before any pipe; `--ran` reconciliation: "41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED (a DERIVED zero)"; every family exit 0. The skills families all pass: `check-skills-token-ratchet` (+ `--self-test`), `check:skill-compatibility`, `check:skill-frame-sync`, `check:skill-identifier-liveness`, `check:pm-skill-id-lint`, `check:doc-authoring`, `check:role-word`, `check:nul-bytes`, the changeset gates (`check-adr-0087-registration`, `check-changeset-no-major`, `check-empty-changeset`, `check:changeset-gate-self-tests`, `check:published-files`, `check:pm-changeset-deadline-census`). - Five families first refused with exit 3 `PREREQUISITE NOT MET` on the fresh worktree (they sweep the built closure): `check:doc-formula-expressions` (lint), `check:dts-closure`, `check:dual-build-cjs-loads`, `check:lean-entry-closure`, `check:sourcemap-no-sources-content`. After `pnpm build` under the verify lock (75 tasks, 6m54s) each was re-run once and exited 0; the working tree stayed clean (no generated artifact moved). - Local-only: `check:skill-frame-freshness` exit 0 (frame byte-identical to `origin/main`). - Stale-term check on the file: zero hits for `left_sidebar`, `two-column`, `Floating`, `deprecated alias`, `landing page`, `utility … panel`. ## 维护者速读(草稿) **改了什么** 只改一个对外发布的技能文件 `skills/objectstack-ui/rules/pages.md`(加一条 `@objectstack/skills` patch changeset)。页面类型表里 `home` 不再写成「应用落地页」,改为「最宽的区域页;不是落地声明(`isDefault` 被拒),应用打开的是第一个导航项」;`utility` 不再写成「浮动工具面板」,改为「窄的内联区域页,没有浮动或停靠的外壳槽位」;「模板与区域」一段从 `three-column / two-column / single-column` 与 `left_sidebar / right_sidebar` 改为 #23708 落地的封闭模板集(`default`、`header-sidebar-main`、`three-column`、`dashboard`)和各自放置的区域名(左栏 `sidebar`、右栏 `aside`;`full-width` 退役;模板不放置的区域、重复占槽的区域被拒);`kind:'jsx'` 从「`html` 的别名」改为「已退役,解析时被拒并指向 `html`」。 **为什么改** 这份技能是 AI 写页面元数据时读的规则。它教的 `two-column`、`left_sidebar`、「home 是落地页」在 #23708 之后会被 `os validate` 和保存门直接拒收(在此之前则是静默错排或无效声明),也就是技能本身在教 AI 写出会被拒的元数据。裁决 `6190536588` 第 4 项把这份文件的更新单列为一个 Tier H PR。 **风险与代价(含回滚)** 零运行时影响:只有技能文本与 changeset,不碰 `packages/**`。文本描述的是 #23708 合入之后的契约,所以本 PR 在 #23708 合入前保持 draft,不会先于契约发布。token 棘轮零余量,新增内容靠删同文件的三处重复/指针付账(净 −14 字节),没有抬上限。回滚 = revert 这一个 commit 对,无状态可清理。 **席位意见** 同意合入。#23708 已于 10-16 02:31Z 落地(`a69a40a572`),`main` 上的 spec 现在就拒收这份技能旧的教法(`two-column`、`left_sidebar`、home 上的 `isDefault`);不合入,技能就在教 AI 写一定会被拒的页面元数据。改动只有一份技能文本加一条 patch changeset,零运行时影响,不碰契约(`Clause-②: no`),CI 全绿,与 `main` 无冲突。为满足 token 上限删掉的三处都是重复说明或源码指针,没有删任何规则;其中删 `responsive.zod.ts` 源码指针一处,席位已确认可接受。 **你要做的** 一个动作:在本 PR 上点 Approve。席位随后开 auto-merge 落地,#23610 随之关闭。 ## Acceptance notes - The text states the contract that #23708 landed on `main` as `a69a40a572` (2026-10-16T02:31Z). The seat marked this PR ready after that merge, and the skill and the parse now agree. - Content deleted to pay the ratchet (listed above) is restatement or a source pointer; no rule left the file. - No out-of-scope findings. --- _Generated by [Claude Code](https://claude.ai/code/session_01H9YpvyoScsRAsjBc2pCUgn)_ --------- Co-authored-by: objectstack-fleet[bot] <noreply@anthropic.com>
1 parent e5136ff commit 46ca793

2 files changed

Lines changed: 25 additions & 21 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the `objectstack-ui` pages rule says what a page type, template and region name run (#23610)
6+
7+
Clause-②: no
8+
9+
`skills/objectstack-ui/rules/pages.md` taught `home` as the app's landing page, `utility` as a floating utility panel, templates `two-column` / `single-column` and regions `left_sidebar` / `right_sidebar`, and `kind: 'jsx'` as a live alias of `html` — none of which the console draws or the spec accepts. The rule now states the declared contract: `home` is the widest region page and not a landing (an app opens on its first navigation item; `isDefault` on it is refused), `utility` is a narrow inline region page with no floating or docked shell slot, `template` is one of `default`, `header-sidebar-main`, `three-column` or `dashboard` with the regions each one places (`sidebar` left, `aside` right; `full-width` retired), a region the template does not place or a second region for a filled slot is refused at its `name`, and `kind: 'jsx'` is refused with the prescription `html`. Skill text only; nothing an author writes changes.

‎skills/objectstack-ui/rules/pages.md‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,28 @@ Register under `defineStack({ pages: [...] })`.
1515

1616
### Page Types
1717

18-
`PageTypeSchema` has exactly **five** values — only types with a dedicated
19-
renderer are authorizable (ADR-0049 enforce-or-remove):
18+
`PageTypeSchema` has exactly **five** values (ADR-0049 enforce-or-remove):
2019

2120
| `type` | Purpose |
2221
|:----------|:--------|
2322
| `record` | Component-based record layout with regions (overrides the default record detail) |
24-
| `home` | App home / landing page |
25-
| `app` | App-level page with navigation context |
26-
| `utility` | Floating utility panel (e.g. notes, phone dialer) |
23+
| `home` | Widest region page; not a landing (`isDefault` refused): an app opens on its first navigation item |
24+
| `app` | Region page at app width |
25+
| `utility` | Narrow inline region page for a tool (notes, a dialer); no floating or docked shell slot exists |
2726
| `list` | Record list/grid interface page — configured via `interfaceConfig` |
2827

29-
Disambiguation: there is **no** `record_detail`, `app_launcher`, or
30-
`utility_bar` type — a record layout is `type: 'record'`, an app-level page is
31-
`type: 'app'`, a utility panel is `type: 'utility'`. Likewise
32-
grid/kanban/calendar/gallery/timeline are NOT page types — they are
33-
*visualizations* of a `list` page
34-
(`interfaceConfig.appearance.allowedVisualizations`).
28+
There is **no** `record_detail`, `app_launcher` or `utility_bar` type, and
29+
grid/kanban/calendar/gallery/timeline are *visualizations* of a `list` page
30+
(`interfaceConfig.appearance.allowedVisualizations`), not page types.
3531

3632
### Templates & Regions
3733

38-
`template` controls the column layout (e.g. `'three-column'`,
39-
`'two-column'`, `'single-column'`). Each template exposes named
40-
**regions** (`header`, `left_sidebar`, `main`, `right_sidebar`, `footer`)
41-
which contain components.
34+
`template` is `default` (regions `header`, `sidebar`, `main`, `aside`, `footer`),
35+
`header-sidebar-main` (`header`, `sidebar`, `main`), `three-column` (the same
36+
five) or `dashboard` (`header`, `footer`; other regions are grid cells);
37+
`full-width` is retired (a second name for `default`). On a `kind: 'full'` page a region
38+
the template does not place, or a second one for a filled slot, is refused at
39+
its `name` — the left column is `sidebar`, the right `aside`.
4240

4341
### Component Catalogue (selection)
4442

@@ -69,7 +67,7 @@ An invoice, a delivery order, a letter or a report is an ordinary page with a
6967
the document. Only a `kind: 'full'` page of `type: 'record'`, `'home'` or
7068
`'app'` with its blocks in `regions` may declare it: the parse refuses `print`
7169
on a `list` page (its switch is `interfaceConfig.allowPrinting`), a `utility`
72-
panel, a `slotted` / `html` / `react` page and a `full` page with no regions.
70+
page, a `slotted` / `html` / `react` page and a `full` page with no regions.
7371

7472
`print` keys, each mapped to print CSS: `paperSize` (`'A4'` default, `'A5'`,
7573
`'Letter'`, `'Legal'`) and `orientation` (`'portrait'` default, `'landscape'`);
@@ -134,8 +132,8 @@ by what the page needs:
134132
| `react` | **real React** (hooks, `.map`, `onClick`, expressions) | yes (main React tree) | complex interactive business UIs — master/detail, wizards, state-driven filters |
135133

136134
`source` is the source-of-truth in both source tiers; `regions` is ignored. A
137-
`kind:'html'`/`'react'` page with no `source` fails the build (ADR-0078). The legacy
138-
value `kind:'jsx'` is a deprecated alias for `kind:'html'`.
135+
`kind:'html'`/`'react'` page with no `source` fails the build (ADR-0078).
136+
`kind:'jsx'` is retired: the parse refuses it and names `kind:'html'`.
139137

140138
#### `kind:'html'` — constrained JSX, parsed (safe by construction)
141139

@@ -284,9 +282,6 @@ Rules:
284282
}
285283
```
286284

287-
The spec field is `PageComponentSchema.responsiveStyles` (`ResponsiveStylesSchema` —
288-
see `node_modules/@objectstack/spec/src/ui/responsive.zod.ts`).
289-
290285
**In the source tiers (`kind:'html'` / `kind:'react'`) the same rule holds — no
291286
Tailwind `className` — but the primitive differs:**
292287

0 commit comments

Comments
 (0)