From c421baee4ec417af2a22762173890b2968ec9c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=91=A8=E6=B6=9B?= Date: Mon, 29 Jun 2026 12:12:06 -0700 Subject: [PATCH] docs(skill): document auto status path + detail.stageField opt-out The distributed objectstack-ui skill never mentioned that ObjectUI auto- synthesizes a detail page and auto-detects a status field for a top record:path stepper, nor the detail.stageField:false opt-out (objectstack-ai/objectui#2066). AI authors install framework's skills, so without this they re-hit the 'non-linear status rendered as an ordered path, can't disable it' trap. Adds, after the record:path example: the detectStatusField precedence and a detail:{ stageField:false } example, stressing it must live in the passthrough detail block (top-level unknown keys are rejected by ObjectSchema.create()). Closes #2452 --- skills/objectstack-ui/SKILL.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/skills/objectstack-ui/SKILL.md b/skills/objectstack-ui/SKILL.md index b7fe0bd9c9..0ec30a8cb3 100644 --- a/skills/objectstack-ui/SKILL.md +++ b/skills/objectstack-ui/SKILL.md @@ -709,6 +709,35 @@ export const LeadDetailPage = definePage({ }); ``` +> **Auto-synthesized detail pages & the status path.** When an object has **no +> authored record page**, ObjectUI synthesizes a default detail page and +> auto-detects a status field to drive a top `record:path` stepper. The stage +> hint lives in the object def's `detail` block (`object.zod.ts` — a +> `.passthrough()` block documented as "Detail-page UI hints consumed by +> @object-ui/plugin-detail synth"). Detection precedence (`detectStatusField`): +> (0) `detail.stageField === false | null` → explicit opt-out, no path; +> (1) `detail.stageField` is a field name → use it; (2) else first field named +> `status` / `stage` / `state` / `phase`; (3) else first field whose `type` is +> `status` / `stage`; (4) else no path. +> +> **Opt out with `detail: { stageField: false }`.** Many objects carry a +> `status` *select* that is a **non-linear** picklist (e.g. 正常 / 暂停 / 作废), +> not an ordered pipeline — rendering it as an ordered stepper is wrong: +> +> ```typescript +> ObjectSchema.create({ +> name: 'production_plan', +> detail: { stageField: false }, // suppress the auto status path +> fields: { status: Field.select({ options: [...] }) /* … */ }, +> }); +> ``` +> +> **Put it under `detail`, not top-level.** `ObjectSchema.create()` rejects +> unknown *top-level* keys (a bare `stageField:` fails to compile and is rejected +> at build). The `detail` block is `.passthrough()`, so author-facing synth hints +> like `stageField` belong there. Use `detail: { stageField: 'my_field' }` to +> pick which field drives the path. + > **Variable substitution** — `{first_name}`, `{current_user.first_name}`, > `{current_quarter_start}` etc. resolve from the page's `variables` block, > the bound record, and the runtime context. Declare `variables: [...]` at