Skip to content

fix(app-shell): hold a new state_machine / format / json_schema validation rule until it has a field and a message - #26855

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-r4sjiv
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-r4sjiv

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #26731

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio 校验规则面板里,新建的 状态机 / 格式 / JSON schema 规则不再立刻写进对象草稿,而是先留在面板里,直到选了字段并填了错误消息才写入一次;「Add transition」的空行在填起始状态前不落盘;条件规则(conditional)的 when 换成自己的说明文字(中英文)。
  • 为什么改:原来一点「新建」就把规则存到对象的第一个字段(实测会是 created_at)上、消息为空,空转换行以 "": [] 存进去并会被发布;条件规则的说明写成「失败条件,为真时拒绝保存」,与 when 的真实含义相反。
  • 风险与回滚:只改面板的新建流程与文案,已有规则的编辑与切换类型行为不变,不改 spec;回滚即 revert 本 PR。已知代价同 objectui#11820:未补全就离开页面,这条新规则会丢弃(界面已标「未保存」)。
  • 先看:ObjectValidationsPanel.tsx 的 missingPart 与 makeSkeleton(新规则不再预填字段);同文件 TransitionsField 的空行;ObjectValidationsPanel.newRuleComplete-26731.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/ObjectValidationsPanel,预期 11 个文件 113 条全绿。
  • 需要你做的:无,席位落地。

What changes

  • A new field rule is held until it is complete. state_machine, format and json_schema now take the same in-panel hold guarded rules got in objectui#11820. A new one starts with no field (the pickField placeholder), is listed and marked not saved, and is written to the draft once, when it has a field and a non-blank message. missingPart wraps the unchanged missingGuard; the held line and the list mark name what is missing (engine.studio.held.needsRuleField / needsRuleMessage, engine.studio.rules.notSavedField / notSavedMessage), and the hold's input hint sits under the field picker or the message input.
  • An empty transition row is not stored. "Add transition" opens a blank row kept in TransitionsField state; it is written when it gets a from-state. The blank row renders at the index its written row takes, so typing its first letter keeps focus.
  • The conditional caption. A conditional rule's when group now reads "Guard (CEL) — when the condition is true, the “Then” rule below applies; otherwise the “Otherwise” rule, if one is set." (engine.studio.rules.whenPre / whenMid, en and zh). Script and cross-field keep the fail-condition caption.
  • Unchanged by design: an EXISTING rule's editing and its type switch (still the valid 'false' placeholder and the first field), presets, and the spec.

Why

Triage first grade on the card: a new state_machine / format / json_schema validation saved immediately as a live rule on created_at with an empty message, and the conditional rule's wording inverted when. On base f79ec289, makeSkeleton seeded those three types with firstField (the first non-hidden field; a system audit column is not skipped, so a served object yields created_at) and message: '', and placeNewRule wrote any guard-less rule at once.

Tests

  • New ObjectValidationsPanel.newRuleComplete-26731.test.tsx (10 tests): per type, held with no field, then field, then message → written once and parses through ValidationRuleSchema; message-first order; blank message does not complete; control that an existing rule's type switch still seeds the first field; blank transition row writes nothing until it has a from-state, and deleting it writes nothing; the conditional caption differs from the script caption in en and zh.
  • Existing tests updated only where the hold changes what they read: the newRuleWaits-11820 control ("a type with no guard is written at once") now fills field and message first, and ObjectValidationsPanel.test.tsx, whenKey, runsOn-11923 pick a field and type a message before reading the written rule. presets-11861 is untouched and green. StudioEmptyState.panels-12514.test.tsx ("a pick from it writes the rule the header's pick writes") now picks the field and types the message after picking Format from the empty block, then expects exactly one write (c6be0644).
  • ResourceEditPage.environmentOverlay-12141.test.tsx gains a module-scope await loadStudioCatalogue('zh'): its lock banner's zh row lives in the lazy studio namespace since feat(ui): the remaining Studio inspector strings and the package, form and editor strings move into the studio i18n namespace (#25922 slice S3) #26815 (app-shell: a published library that is 66% Console product surface — retire the 67 zero-reference exports now, decide the split, and fold the second i18n table into @object-ui/i18n #25922 S3), and without the preload the zh-CN banner case is red on every run (seat Claim widened 6451337559). Red without it (1 failed / 11 passed), green with it (12/12).
  • Ablation: missingPart's field-type branch replaced with if (false) { through scripts/ablation-replace.mjs → 5 of 10 new tests red (all three per-type tests, message-first, blank message); restored, blob equal to HEAD, git diff HEAD empty.

Acceptance notes

  • Same known cost as objectui#11820: a held new rule is dropped if the author leaves the Rules view or the object before completing it, and Publish does not wait for it.
  • A legacy stored "": [] transitions key is still shown as a row (and keeps "Add transition" disabled) — this PR stops writing it, it does not rewrite stored rules.

Verification

Head 5e35145d (origin/main a20824f3, with #26859, merged in): affected set 14 files / 156 tests green; 24/24 derived gates exit 0, --ran 0 NOT-MEASURED; PR CI 42 success · 10 skipped · 0 failure.

Local runs at head 6643455 (origin/main aeb9cf0 merged)
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/ObjectValidationsPanel — Test Files 11 passed (11), Tests 113 passed (113); lock VERDICT command-exit 0.
  • pnpm --filter @object-ui/app-shell run type-check — VERDICT command-exit 0.
  • node scripts/pm/dispatch-gates.mjs --commands — 24 families, each exit 0; --ran reconciliation: 24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN. Also run outside the derivation, exit 0: pnpm --dir ui run check:new-line-citations, pnpm check:i18n-stale-fill.
  • No changeset: @object-ui/app-shell is private: true (label skip-changeset).

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes (CI-owned run).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset — this one publishes nothing (skip-changeset); both declaration lines are filled in here.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block is the maintainer-facing summary).

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbaA4X9WGDi4ZgwZ4PZ


Generated by Claude Code

… and a message

A new state_machine / format / json_schema rule was written to the object
draft at once, on the object's first listed field and with no message. It now
waits in the Validations panel, the hold guarded rules already take, with no
field picked for the author. "Add transition" keeps its blank row local until
it has a from-state instead of writing the key "". A conditional rule's `when`
gets its own caption (en, zh) instead of the script rule's fail-condition one.

Claude-Session: https://claude.ai/code/session_01JQwxbaA4X9WGDi4ZgwZ4PZ
Co-authored-by: Claude <noreply@anthropic.com>
…ead transition keys directly

Claude-Session: https://claude.ai/code/session_01JQwxbaA4X9WGDi4ZgwZ4PZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Test UI (5/16) red — not this PR's; base main is red with the same failure.


Generated by Claude Code

…eld and message before it is written

Claude-Session: https://claude.ai/code/session_01JQwxbaA4X9WGDi4ZgwZ4PZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · head 5e35145d · 2026-10-27T19:55Z

席位意见:新建的状态机 / 格式 / JSON Schema 规则不再预填第一个字段,补齐字段和错误消息之前留在面板里不写入草稿,沿用 #11820 的同一套“暂存”机制;空的状态转移行在填写起始状态前不写入;条件规则的 when 改用自己的说明文字(中英)。

  1. Shape: Fixes #26731; 9 files, +496/−93: ObjectValidationsPanel.tsx +153/−75, 8 new i18n rows (en + zh) in the private table next to their families (engine.studio.held.*, engine.studio.rules.*), one new test file and five adjusted ones (incl. StudioEmptyState.panels-12514, a consumer of the panel). skip-changeset (app-shell is private).
  2. Premise measured: the seat read the source diff on the head. makeSkeleton seeds the first field only for an EXISTING rule's type switch (guard === 'false') and leaves it blank for a new rule. missingPart extends missingGuard with 'field' then 'message' for the three field types, and the held line and the list mark read from one table. The blank transition row lives in TransitionsField state until it has a from-state, keyed by rule name so it does not leak to the next rule. The conditional caption switches on rule.type. Dev: the panel suite is 11 files, 113/113; the ablation turns 5 of 10 new tests red, restored.
  3. Gates / check-runs: On head 5e35145d (origin/main a20824f3 merged), 42 success · 10 skipped · 0 failed · 0 pending; mergeable_state: clean. Dev's local run: 24/24 derived gates exit 0, --ran 0 NOT-MEASURED; app-shell type-check exit 0.
  4. Accepted deviations: newRuleWaits-11820's control "a type with no guard is written at once" is rewritten, because it pinned exactly the behaviour triage 6447132861 reverses. Four existing tests now fill field + message, one of them (StudioEmptyState.panels-12514) outside the claimed ObjectValidationsPanel.* glob because the hold changes what it reads; the seat amended the PR body for it. Four i18n rows beyond the caption (held clauses + list marks) are needed by the hold.
  5. Out of scope: the Claim was widened (6451337559) to carry ResourceEditPage.environmentOverlay-12141's zh preload, a test app-shell: a published library that is 66% Console product surface — retire the 67 zero-reference exports now, decide the split, and fold the second i18n table into @object-ui/i18n #25922 S3 left racing and red on main; the ablation of that line reds the zh-CN case, restored. None filed; a legacy stored "" transitions key still renders (body Acceptance notes). Skills-docs: none — Studio authoring flow; the written rule shapes are unchanged. app-shell: a published library that is 66% Console product surface — retire the 67 zero-reference exports now, decide the split, and fold the second i18n table into @object-ui/i18n #25922 S5 will move engine.studio.rules.* after this lands.
  6. Landing: not Tier H; the seat readies and arms auto-merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 19:57
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 19:57
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit c4a4aef Oct 27, 2026
57 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-r4sjiv branch October 27, 2026 20:18
zhuangjianguo pushed a commit that referenced this pull request Oct 27, 2026
…ries

main's #26855 added the same module-scope `loadStudioCatalogue('zh')`
await to `ResourceEditPage.environmentOverlay-12141.test.tsx`; with this
branch's copy the merged file declared the import twice and failed to
transform. Keep main's copy.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jVTqmjzhQU2Rqq79mu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants