Repository navigation
Commit fb4e0bb
feat(spec): a record:path block may opt in to allowStageChange, so a stage can be pressed to move the record there (#28198)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoAkUMdnw6MHYbw4FotfMxXw)_
Fixes #28061
Clause-②: yes (widening)
Metadata-protocol: added
Skills-docs: none — `skills/objectstack-ui/rules/pages.md` teaches
`record:path` as `statusField` + `stages` and every taught use stays
true; teaching `allowStageChange` waits for the console half that makes
it do something, so the skill line belongs to that follow-up.
## 维护者速读
- 改了什么:`record:path` 区块的 spec(`RecordPathProps`)新增一个可选布尔键
`allowStageChange`,作者打开后,路径上的阶段可以被点击来请求把记录改到该状态;不写或写 `false`
时仍是今天的只读进度条。
- 为什么改:HotCRM 销售测试反馈(#27355 第 1 行):想把商机推进到下一阶段只能打开编辑表单改下拉框。本 PR 只做 spec
半边,声明这个开关和它的含义;控制台渲染(`plugin-detail` 的 `record-path.tsx`)是另一张
`domain:ui` 卡。
- 风险与回滚:纯加宽,没有 schema
默认值,已有页面解析结果完全不变;服务端不改,状态机校验和字段编辑权限照旧由普通的记录更新判定。回滚即 revert 本 PR。
- 先看:`packages/spec/src/ui/component.zod.ts` 的
`allowStageChange`(describe
写明含义)、`packages/spec/src/ui/component.test.ts`
新增的三条测试、`ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`
新增的一条 `UNPUBLISHED_EXEMPTIONS` 豁免。
- 两分钟验证:`pnpm --filter @objectstack/spec exec vitest run
src/ui/component.test.ts -t allowStageChange`,预期 3 条全部通过。
- 需要你做的:无,席位落地(等契约复审记录)。
## What changes
- `RecordPathProps` (`ComponentPropsMap['record:path']`) declares
`allowStageChange: z.boolean().optional()`, with no schema default (the
`RecordChatterProps` reason: a default would write `false` onto every
parsed component). Absent or `false` is the read-only progress rail, as
today. The `.describe()` and docblock state the console contract from
the card: with the key on, each stage the reader may move the record to
is a button, offered only to a reader who may edit `statusField`; a
press confirms, then saves `statusField` through the same record update
`record:details` uses, with the record's concurrency token, so the
object's `state_machine` validation (ADR-0020) and field edit rights
decide; a refusal is shown in place. No server change.
- Regenerated: `packages/spec/authorable-surface/ui.json` (+1 row,
`ui/RecordPathProps:allowStageChange`) and
`content/docs/references/ui/component.mdx` (+1 row).
- `ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts`:
one `UNPUBLISHED_EXEMPTIONS` entry, `'record:path.allowStageChange'`,
citing objectstack#28061. Without it the gate's reverse direction (a key
the spec declares must be published in the block's registry `inputs`)
reds Test UI, because `ui/` consumes this PR's spec through
`workspace:^`. The key is not published because the path renderer does
not read it yet, the file's own bar for an entry. When the console half
publishes the input, the file's stale check demands the entry's deletion
in that change. Seat ruling A (this card's thread) widened the file
surface by exactly this entry; nothing else under `ui/` changes.
- Changeset `28061-record-path-allow-stage-change.md`:
`@objectstack/spec` minor, both declaration lines.
**Console follow-up for the seat to file (`domain:ui`):**
`ui/packages/plugin-detail/src/renderers/record-path.tsx` honours
`allowStageChange` (stage buttons gated by the reader's edit verdict on
`statusField`, confirm, write through the `record:details` update path
with the concurrency token, refusal shown in place), the `record:path`
registration publishes the input, the `UNPUBLISHED_EXEMPTIONS` entry
above is deleted, and `skills/objectstack-ui/rules/pages.md` teaches the
key.
## Tests
`packages/spec/src/ui/component.test.ts`, new block "RecordPathProps
allowStageChange — opt-in, off unless authored":
- `accepts the opt-in and keeps the authored value`: `safeParse`
succeeds and `allowStageChange` is `true`.
- `leaves an existing path unchanged: no default is written` (control):
the showcase-shaped `statusField` + `stages` input parses to an object
equal to the input, with no `allowStageChange` key.
- `refuses a non-boolean at the key, with the code and path`: `'yes'`
gives exactly one issue, `code: 'invalid_type'`, `path:
['allowStageChange']`.
<details><summary>Local runs</summary>
- `pnpm --filter @objectstack/spec typecheck` and `pnpm --filter
@objectstack/spec exec vitest run` on `d9b26f02`, under the verify lock:
VERDICT command-exit 0; Test Files 843 passed (843), Tests 23972 passed,
1 todo.
- `pnpm --dir ui exec vitest run
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts` on
`d9b26f02`: Test Files 1 passed, Tests 261 passed (261).
- Control for the exemption entry: with the
`'record:path.allowStageChange'` entry removed (`grep -c` 0 after the
edit), the same file fails exactly one case, "record:path publishes
every top-level key its spec props schema declares" (`expected [
'allowStageChange' ] to deeply equal []`), 1 failed and 260 passed.
Restored with `git checkout HEAD --`; `git diff HEAD` empty.
- After merging `origin/main` (4 commits, `packages/spec` changes in the
automation domain only), on `526055d6`: workspace build exit 0, `pnpm
--filter @objectstack/spec check:generated` "All 14 generated artifacts
are up to date", `src/ui/component.test.ts` 353/353 and the parity file
261/261.
- Dogfood not run: no `!` in the title and no `(narrowing)` arm.
</details>
## Acceptance notes
- The key name is the card's "name for review"; the contract review
judges it. It is named for the act (changing the stage), not the widget.
- The order's file surface was `packages/spec` only. The ui parity gate
made that impossible without a red Test UI; reported to the seat before
any code and ruled A (one exemption entry).
- `content/docs/ui/components/record.mdx` is generated from the registry
`inputs`, so it does not list the key until the console half publishes
it.
## Verification
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 106 commands on `d9b26f02`. All 106
ran with stdin from /dev/null, exit codes captured before any pipe: 106
exited 0. Commands 60 to 106 first ran while a dts-less build of the
console's dependencies was rewriting `dist/`; they were re-run after a
full declaration build and all 47 exited 0 again.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran FILE`: "106 derived famil(ies) accounted for — 106 run, 0
NOT-MEASURED".
- The gate sweep was taken on `d9b26f02`; the merge with `origin/main`
(`526055d6`) brought in 4 commits, none touching `packages/spec/src/ui`
or `ui/`.
- `test:repo` not run locally (CI's Test Core).
- CI on this PR: not yet read; the seat reads the check-runs.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibxNQzFQH8nBAaoSUkx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent e26cf9a commit fb4e0bb
6 files changed
Lines changed: 74 additions & 0 deletions
File tree
- .changeset
- content/docs/references/ui
- packages/spec
- authorable-surface
- src/ui
- ui/apps/console/src/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1882 | 1882 | | |
1883 | 1883 | | |
1884 | 1884 | | |
| 1885 | + | |
1885 | 1886 | | |
1886 | 1887 | | |
1887 | 1888 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1197 | 1197 | | |
1198 | 1198 | | |
1199 | 1199 | | |
| 1200 | + | |
1200 | 1201 | | |
1201 | 1202 | | |
1202 | 1203 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2602 | 2602 | | |
2603 | 2603 | | |
2604 | 2604 | | |
| 2605 | + | |
| 2606 | + | |
| 2607 | + | |
| 2608 | + | |
| 2609 | + | |
| 2610 | + | |
| 2611 | + | |
| 2612 | + | |
| 2613 | + | |
| 2614 | + | |
| 2615 | + | |
| 2616 | + | |
| 2617 | + | |
| 2618 | + | |
| 2619 | + | |
| 2620 | + | |
| 2621 | + | |
| 2622 | + | |
| 2623 | + | |
| 2624 | + | |
| 2625 | + | |
| 2626 | + | |
| 2627 | + | |
| 2628 | + | |
| 2629 | + | |
| 2630 | + | |
| 2631 | + | |
| 2632 | + | |
| 2633 | + | |
| 2634 | + | |
| 2635 | + | |
| 2636 | + | |
2605 | 2637 | | |
2606 | 2638 | | |
2607 | 2639 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2082 | 2082 | | |
2083 | 2083 | | |
2084 | 2084 | | |
| 2085 | + | |
| 2086 | + | |
| 2087 | + | |
| 2088 | + | |
| 2089 | + | |
| 2090 | + | |
| 2091 | + | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
2085 | 2103 | | |
2086 | 2104 | | |
2087 | 2105 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1663 | 1663 | | |
1664 | 1664 | | |
1665 | 1665 | | |
| 1666 | + | |
| 1667 | + | |
| 1668 | + | |
| 1669 | + | |
| 1670 | + | |
| 1671 | + | |
1666 | 1672 | | |
1667 | 1673 | | |
1668 | 1674 | | |
| |||
0 commit comments