Skip to content

feat(app-shell): show a disable refused for a dependent validation rule whole on the Setup packages page - #31016

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-llyeiu
Nov 6, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-llyeiu

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #31003

Clause-②: yes (widening)
Metadata-protocol: none

维护者速读

  • 改了什么:Setup 软件包详情里,停用被服务端以 409 PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE 拒绝时,页面先用管理员的语言显示一句标题(为什么不能停用、先停用或修改规则),再完整显示服务端原话(包 · 对象 · 规则,以及补救办法),不再只露第一句、把补救藏在「更多」后面。停用确认框里多一行,说明有规则依赖这个包时停用可能会被拒绝。
  • 为什么改:fix(runtime)!: the package disable door refuses while an enabled package's validation rule reads a field the package adds #30825 之后停用可能被拒,但页面把「停用」画成随时可用,被拒时补救办法又被折叠,管理员看不出该先去关哪条规则。
  • 风险与回滚:只改前端显示和两条新文案(en/zh),其它拒绝码的显示方式不变,服务端零改动。回滚即 revert 本 PR。
  • 先看:PackagesPage.tsx 里 run() 的 catch(按错误码加 heading)和消息框的渲染分支;确认框里新增的 pkg-detail-disable-may-refuse 一行;测试文件末尾新的 describe。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/PackagesPage.moduleDisable-28118.test.tsx,预期 15 passed,其中 en、zh 两条 409 用例都看到标题和完整原话。
  • 需要你做的:无,席位落地。

What changes

ui/packages/app-shell/src/views/metadata-admin/PackagesPage.tsx (package detail sheet):

  • The refusal, drawn whole. When an action on the sheet fails with error code PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE (read off the thrown error with errorCodeIs, which apiJson already fills from the ADR-0112 envelope), the message box draws a heading in the reader's language (engine.packages.detail.disableRestricted), and under it the server's whole message as sent. The server's message names every blocking rule as package · object · rule and then the remedy. Before, RefusalMessage cut it to its first sentence, so the remedy was behind "More". Every other refusal is drawn as before (RefusalMessage).
  • Disable no longer reads as unconditional. The confirm dialog gains one line (engine.packages.detail.disableMayBeRefused) saying the disable is refused while an active validation rule reads a field this package adds, and the refusal names each rule. Offering Disable still follows the served disableable verdict alone. Nothing is computed in the client.

ui/packages/i18n/src/namespaces/studio/{en,zh}.ts: the two new keys. They are in the lazy studio namespace, not the eager i18n-locale-en pack, so no ceiling moves.

What the server serves (measured on origin/main 8ae0ab9b, packages/runtime/src/domains/packages.ts)

  • PATCH /packages/:id/disable answers deps.error(disableDependentRulesMessage(...), 409, { code }). On the wire that is { success: false, error: { code, message } }, with no error.details. The JSDoc on the constant PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE says a machine-readable shape for the triples would be a spec contract first. The page therefore shows the message and does not parse it.
  • The served disableable is isDisableablePackage (a writable base, or a module of an installed app). It does not read readDisableDependentRules. Pre-computing it per row would need that server read on every GET /packages row (a fold of every object per package) and a change in what the field means. That is outside this card's fence (packages/**), so the page shows the refusal when the disable is attempted.

Tests

PackagesPage.moduleDisable-28118.test.tsx gets a new top-level describe, a disable the server refuses for a dependent validation rule (objectstack#31003), in the existing module-disable harness. Its wire stub gains an optional per-door answer. The describe has 5 cases:

  • the confirm dialog carries the may-be-refused line beside the existing consequence copy;
  • en and zh: a 409 with the code draws the heading in that language and the server's whole sentence (rule listing and remedy both on screen, no "More"), and Disable stays on offer;
  • CONTROL: another refusal code (403 WRITABLE_PACKAGE_REQUIRED, two sentences) keeps the first-sentence drawing with "More" and no heading;
  • CONTROL: a disable with no dependent rule lands in one confirm (one PATCH …/disable, success line, no refusal drawn).

The suite also gains module-top warm imports of @objectstack/formula and @objectstack/lint, which check:test-source-alias asks of an edited test whose reach loads them lazily.

Acceptance notes

  • The heading is console copy and the listing stays the server's English sentence. Translating the listing would need the package · object · rule triples as data (error.details), which is a packages/spec contract and not opened here.
  • The heading is keyed on the error code, not on the door, so the same drawing would apply to that code wherever the sheet's run() meets it. Today only the disable door answers it on this sheet. The install door also answers it for enableOnInstall: false, but that door belongs to the import flow and is not touched here.

Verification

Head 0b6d41bd, tree objectstack-ai/objectstack.

Tests
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/PackagesPage.moduleDisable-28118.test.tsx: Tests 15 passed (15), 10 existing and 5 new.
  • Every PackagesPage.*.test.tsx (18 files) on the first head: 17 passed, plus 1 failure in the new zh case (the test clicked the English label), fixed in the next commit. The file is green since then.
  • pnpm --dir ui exec vitest run packages/i18n/src/__tests__/studio-namespace.test.ts: 18 passed (en ⊆ zh, placeholder parity).
  • Ablation (node scripts/ablation-replace.mjs, anchor {msg.kind === 'err' && msg.heading ? ( → … && false ? (): the en and zh 409 cases fail (2 failed, 13 passed). Restored to a blob equal to HEAD, and git diff HEAD is empty.
Derived gates: 36 of 36 run

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 36 lines. All 36 were run with stdin redirected from /dev/null, and --ran reports 36 derived famil(ies) accounted for — 36 run, 0 NOT-MEASURED. On the first pass, 34 exited 0 and 2 exited 1:

  • pnpm check:test-source-alias: the edited suite reaches lazy @objectstack/formula and @objectstack/lint imports. Fixed with the warm imports. Exit 0 on 0b6d41bd.
  • pnpm --dir ui exec vitest run scripts/: 7 failures in check-doc-snippet-types.test.ts and spec-symbol-ledger-plugin-detail-7265.test.ts. Both read @objectstack/spec declarations, and this worktree's spec was built with OS_SKIP_DTS=1. After env -u OS_SKIP_DTS pnpm --filter @objectstack/spec build, the full run on 0b6d41bd gives Test Files 170 passed and 2 skipped; Tests 4991 passed and 2 skipped; VERDICT command-exit 0.

Also run beyond the derivation, all exit 0: pnpm --dir ui check:i18n-keys, check:i18n-drift, check:i18n-dead-keys (neither new key is listed), check:new-line-citations (0 new), pnpm check:undeclared-dep-imports. node scripts/check-sdui-manifest.mjs is among the derived 36.

Not run locally

pnpm --filter @object-ui/app-shell run type-check is NOT MEASURED. This worktree's @object-ui/* packages have no .d.ts, so the run reports about 1,700 missing-module errors (TS2307 and TS7006), and none of them is on a line this diff adds. Type Check UI runs it.


Generated by Claude Code

…rule whole on the Setup packages page

A 409 PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE from the disable door is
drawn under a heading in the reader's language with the server's whole
sentence (package · object · rule and the remedy), no longer cut to its first
sentence. The disable confirm dialog says such a rule can still refuse the
disable, since the served disableable verdict does not read dependent rules.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwxPsNfCDtuhas4VDr
…he module-disable suite

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwxPsNfCDtuhas4VDr
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 0b6d41bd1fce3f284632559bd655439e10e3e438
Local-runs: none

① Derived judgments

  • The declaration names the whole widening: two new leaves, engine.packages.detail.disableRestricted and engine.packages.detail.disableMayBeRefused, in the published @object-ui/i18n lazy studio namespace, which ships en and zh only (git ls-tree … ui/packages/i18n/src/namespaces/studio/: en.ts, zh.ts, index.ts), +2 lines each, nothing removed or renamed (git diff --stat origin/main...0b6d41bd, 5 files +158/−8). The eager packs are untouched.
  • No other published face moves: PackagesPage.tsx's new heading is a member of the sheet's local message state; the code constant is module-local; errorCodeIs is the existing @object-ui/types helper already used on the page (BATCH_ABORTED). The refusal code is the server's (packages/runtime/src/domains/packages.ts:803), read, not added; no packages/** file in the diff, so the 409 envelope and the served disableable verdict are unchanged.
  • Behaviour boundary: only PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE takes the new whole-text drawing; every other refusal keeps RefusalMessage (first sentence + "More") and publish refusals keep their details list.

② Semver level

@object-ui/app-shell patch and @object-ui/i18n patch, Clause-②: yes (widening), Metadata-protocol: none: additive keys, no break, the lane's patch convention for new pack keys.

③ Boundary flags

  • The server's sentence stays in its own (English) words under the console heading, as the card asks; localizing the server message is a server concern.
  • app-shell type-check was NOT MEASURED locally (no @object-ui dts in the worktree); Type Check UI on this head carries it and must be green before ACCEPT.

Implemented-by: claude/project-thread-llyeiu
Reviewed-by: session_01L9qibxW6qraU2Z3mwupUGp

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-tesla · session_01L9qibxW6qraU2Z3mwupUGp

维护者速读

  • 改了什么:Setup → 软件包详情里点「停用」被拒(409 PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE,有生效中的验证规则读取该包添加的字段)时,页面先用读者语言写一句「有验证规则在用这个包的字段,暂时无法停用,请先停用或修改下列规则」,再把服务端整句完整显示(逐条 包 · 对象 · 规则 和补救办法),不再只露第一句、其余藏在「更多」后面。停用确认框多一行提醒:这类规则会让停用被拒。
  • 为什么改:fix(runtime)!: the package disable door refuses while an enabled package's validation rule reads a field the package adds #30825 让服务端能说清是哪条规则挡住了停用,但页面把这句截断了,管理员看不到该去改哪条规则。
  • 风险与回滚:只动这一页和 studio 语言命名空间的两条新文案(en、zh);其它拒绝照旧显示;没有拒绝时一次确认就停用。纯前端,服务端不变。回滚即撤本 PR。
  • 先看:ui/packages/app-shell/src/views/metadata-admin/PackagesPage.tsx 里按错误码加 heading 的那几行和渲染分支。
  • 两分钟验证:cd ui && pnpm vitest run packages/app-shell/src/views/metadata-admin/PackagesPage.moduleDisable-28118.test.tsx,预期 15 条全绿。
  • 需要你做的:无,席位落地。
  • 席位意见:可合。服务端整句仍是英文,本地化服务端消息不在本卡范围。

席位核对 — ACCEPT · head 0b6d41b

  • 形态:5 个文件,+158/−8(页面、一个测试文件、两个 studio 命名空间包、一份 changeset)。check-governed-merges --branch origin/claude/project-thread-llyeiu:NOT governed,166 行 ≤ 3000。Fixes #31003,目标 main。与认领 6690568587 及修订 6690629020(分支)一致。本 PR 由本席派出的卡线程实现,席位不写码。
  • 契约:Clause-②: yes (widening),Metadata-protocol: none,两包 patch。TIER_DEFAULT 申报面复核 6691426425 在本 head 上 PASS。
  • 席位自己核对(读 diff):只有这一个错误码走整句加标题的新分支,其它拒绝仍用 RefusalMessage,发布拒绝的 details 列表不变;errorCodeIs 是页面已在用的 @object-ui/types 工具;没有 packages/** 改动,409 信封与 disableable 判定不变;不在客户端自算可停用性(席位裁定)。两条新键 en/zh 文案读过,与 changeset 一致。
  • 前提实测:dev 报告 6691400340(status done)。该测试文件 15/15,新增 5 条(确认框提示、en/zh 409 标题加整句、其它错误码对照、无依赖规则一次确认即停用对照),消融后 en/zh 两条变红;派生门禁 36/36 exit 0。
  • 门禁 check-runs:本 head 每个检查最新一次 44 success、11 skipped,0 红(含 Type Check UI,补上本地未测的 app-shell type-check);mergeable_state clean。
  • 落地条款:维护者常设令 「你应该是使用 pm-dispatch 技能自主审核和落地 pr」(2026-11-06T14:09Z)。中继 pr_ready + automerge_enable。合并即关卡,同笔摘 pm:dispatched。

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 6, 2026 18:00
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 584f7b8 Nov 6, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-llyeiu branch November 6, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant