Skip to content

feat(spec,i18n): register the delete_package platform tool and label it in every pack (cloud#3656) - #31037

Open
objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/issue-31020-platform-tool-delete-package
Open

objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/issue-31020-platform-tool-delete-package

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #31020

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:平台工具名单 PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio'] 登记了 delete_package,十种界面语言都补上了这一步的显示名(中文「删除一个应用包」)。
  • 为什么改:cloud 新增的「删除环境里搭的应用包」工具(只发起删除,由人确认)要求在平台名单里登记;不登记,cloud 的工具名一致性测试一直是红的(objectstack-ai/cloud#3686)。
  • 风险与回滚:风险很低——只是名单里多一个名字、语言包里多一行文字,不改任何结构或行为;回滚即撤掉这一个 PR。
  • 先看:packages/spec/src/system/constants/platform-tool-names.ts(新名字的位置与注释);ui/packages/i18n/src/locales/zh.ts(中文措辞);ui/packages/i18n/src/locales/en.ts。
  • 两分钟验证:cd ui && pnpm exec vitest run packages/plugin-chatbot/src/__tests__/toolLabels-locale-parity-7481.test.ts,预期全部通过(每种语言都有 delete_package 的显示名)。
  • 需要你做的:无,席位落地。

What changes

  • spec — PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio'] gains delete_package in its sorted place (after delete_field), and the group's docblock says what the tool is: it only stages the removal of a package built in the environment, and a person confirms before anything is deleted (objectstack-ai/cloud#3656). PLATFORM_PROVIDED_TOOL_NAMES therefore carries it, so a skill whose tools[] names delete_package resolves under ADR-0109 reference integrity.
  • i18n — chatbot.tool.delete_package in all ten ui/packages/i18n/src/locales/ packs, worded like the sibling delete_field / create_package labels: en "Delete a package", zh 「删除一个应用包」, ar "حذف حزمة", de "Ein Paket löschen", es "Eliminar un paquete", fr "Supprimer un paquet", ja 「パッケージを削除する」, ko 「패키지 삭제하기」, pt "Excluir um pacote", ru "Удалить пакет".
  • Two patch changesets (@objectstack/spec, @object-ui/i18n), each carrying both declaration lines.

Consumer: objectstack-ai/cloud#3686 (cloud#3656) — its platform-tool-names-conformance.test.ts goes green once a cloud pin round carries this change. Same file set as the cloud record-write precedent (eca7cd2) minus its chatbot card work, which this tool does not need.

Tests

  • packages/spec/src/system/constants/platform-tool-names.test.ts — 5/5 (snake_case, no cross-package collision, no family-prefix shadowing, sorted groups).
  • ui — toolLabels-locale-parity-7481, toolLabels-sentences-12724 and the whole packages/i18n/ suite: Test Files 99 passed (99), Tests 1549 passed / 13 skipped, against a rebuilt spec dist that carries delete_package (so the parity suite read the new name from the registry, not a stale build).
  • pnpm --filter @objectstack/spec run typecheck and pnpm --filter @object-ui/i18n run type-check: exit 0.

Acceptance notes

  • delete_package is not added to PLATFORM_DESTRUCTIVE_TOOL_NAMES in packages/mcp/src/mcp-server-runtime.ts. That set is a by-name fallback for platform tools that carry no requiresConfirmation; a tool outside it gets no destructiveHint, which MCP reads as its own default true. remove_sample_data (the precedent's destructive tool) is not in it either. No change needed for this card.

Verification

All readings at head 97f93b5503, objectstack, worktree off origin/main 7d9f1e973e.

Derived gate union — 77 families, reconciled with dispatch-gates --ran (exit 0)

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran over a record carrying every command's exit code, captured before any pipe: 77 derived, 74 run, 3 NOT-MEASURED, 0 UNRUN.

  • 73 families exit 0 (all packages/spec checks incl. check:api-surface, check:authorable-surface, check:docs, check:export-origins, check:liveness; check:nul-bytes, check:doc-authoring, check:issue-citations, check:published-files, the changeset gates, and the rest of the list).
  • NOT MEASURED, reason: prerequisite not built in this fresh worktree (exit 3, the gates' own refusal) — pnpm --filter @objectstack/lint run check:doc-formula-expressions, pnpm check:dual-build-cjs-loads, pnpm check:lean-entry-closure. They read built dist/ of packages this diff does not touch; CI's Lint & Repo Gates runs them on a built tree.
  • NOT MEASURED, reason: prerequisite not built (exit 1) — pnpm --dir ui exec vitest run scripts/: 169/170 files pass; the one failure is unit-registry-absence-collision refusing because @objectstack/client has no dist/ here (37 import failures, all that one package). CI's Test UI owns it.
  • A closure build to measure those four waited 18 minutes on the shared verify lock (two queue-timeout 99s behind another run) and did not acquire it — a declared narrowing, not a pass.
Beyond the derivation
  • pnpm --dir ui run check:i18n-keys, check:i18n-drift, check:i18n-dead-keys: exit 0.
  • pnpm --filter @objectstack/spec run typecheck, pnpm --filter @object-ui/i18n run type-check: exit 0.
  • node scripts/check-platform-checklist.mjs --changed-from origin/main: exit 0 (no anchored file in the change set).
  • pnpm check:i18n, pnpm check:i18n-coverage: NOT MEASURED (exit 3, workspace CLI not built). Both gate the server-side *.generated.ts translation bundles and example configs, none of which this diff touches; the ui locale packs are covered by the suites under Tests.

Generated by Claude Code

…it in every pack

PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio'] lists delete_package, the
cloud build tool that only stages a person-confirmed removal of a package
built in the environment (cloud#3656). Every ui locale pack gains its
chatbot.tool.delete_package step label.

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

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

⛔ 1 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v18/18-3.mdx (via PLATFORM_TOOLS_BY_PACKAGE (symbol, a top-level const object))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see

Coarse fallback — 171 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 90523379a149e85afa1ed49286a3abaa95075c42 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from e4c9c98b3840f43ab212a68fe7b45f180ef39f18 — the merge of head 97f93b5503d18dc18d5c4dc24aa443ddc7f0f68c into base 90523379a149e85afa1ed49286a3abaa95075c42, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e4c9c98b3840f43ab212a68fe7b45f180ef39f18 && git checkout e4c9c98b3840f43ab212a68fe7b45f180ef39f18
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 90523379a149e85afa1ed49286a3abaa95075c42 97f93b5503d18dc18d5c4dc24aa443ddc7f0f68c && git checkout -B drift-repro 90523379a149e85afa1ed49286a3abaa95075c42 && git merge --no-ff 97f93b5503d18dc18d5c4dc24aa443ddc7f0f68c

node scripts/docs-audit/affected-docs.mjs --json 90523379a149e85afa1ed49286a3abaa95075c42

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 90523379a149e85afa1ed49286a3abaa95075c42 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2

Contract-review-claim: session_01Q4EjjRhUZjdy8VXs6Kkur2 · head 97f93b5 · 2026-11-06T19:30Z

Face: schema. packages/spec PLATFORM_TOOLS_BY_PACKAGE[service-ai-studio] gains delete_package, plus chatbot.tool.delete_package labels in ten locales; declared Clause-②: no → reviewed by an isolated reviewer the seat starts now (domain:cloud lane seat). ⛔ Not queued before a PASS on this head.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 97f93b5503d18dc18d5c4dc24aa443ddc7f0f68c
Local-runs: none
Scope: packages/spec/src/system/constants/platform-tool-names.ts + packages/spec/src/ai/skill.zod.ts, packages/lint/src/validate-ai-tool-references.ts, packages/lint/src/validate-ai-tool-references.test.ts, packages/spec/src/system/constants/platform-tool-names.test.ts, packages/mcp/src/mcp-server-runtime.ts, packages/mcp/src/mcp-tool-bridge-safety-annotations.test.ts, ui/scripts/check-i18n-call-site-keys.mjs, ui/packages/plugin-chatbot/src/tests/toolLabels-locale-parity-7481.test.ts, ui/packages/plugin-chatbot/src/tests/toolLabels-sentences-12724.test.ts, ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts, the two changesets, and cloud packages/service-ai-studio/src/__tests__/platform-tool-names-conformance.test.ts (the named consumer)

Rendered 2026-11-06T19:38Z on the schema face (record-recognisers --template --paths read the face off the PR's file list; Served-tier: CONTRACT_REVIEW_TIER is the tier it prescribed, not one forced). Read-only: the net diff origin/main...97f93b55 (13 files, +35/−1), card #31020, cloud#3656, precedent eca7cd2008 and the head's check-runs, read once. The dev's report and the seat's conclusions were not used; every judgment below was re-derived from the cited code.

① Derived judgments

  • Clause-②: no — right. The question is whether a published accept set or public surface widens. The accept set for skill.tools[] is packages/spec/src/ai/skill.zod.ts: z.array(z.string().regex(/^[a-z_][a-z0-9_]*\*?$/)) — a free snake_case string, unchanged by this diff. The only consumer that validates against the list is packages/lint/src/validate-ai-tool-references.ts (collectToolUniverse = PLATFORM_PROVIDED_TOOL_NAMES ∪ stack.tools[] ∪ the action_ family), and its one verdict, ai-skill-tool-unresolved, is warning severity by design (ADR-0078 advisory-first; the runtime "deliberately tolerates unresolved names"). So before this diff a skill naming delete_package was advised, not refused; after it, it is not advised. Nothing a published package refused is now accepted, no export is added or removed (PLATFORM_PROVIDED_TOOL_NAMES is the same ReadonlySet export with one more member). Same reading the precedent eca7cd2008 recorded for +3/−1 names.
  • Consumers of the list, read off the code: @objectstack/lint (validate-ai-tool-references.ts, the universe above); @objectstack/mcp (mcp-server-runtime.ts worldAnnotation: a registered name gets openWorldHint: false — a closed-world claim that is true of delete_package, which acts on the environment's own packages; and the two hand-held safety sets, pinned as a SUBSET of the registry by mcp-tool-bridge-safety-annotations.test.ts, so an addition cannot red them); the ui label suites toolLabels-locale-parity-7481 (every registered name needs a non-empty label in all ten packs) and toolLabels-sentences-12724 (no value equals the id or the title-caser's output); ui/scripts/check-i18n-call-site-keys.mjs names the registry as the chatbot.tool. vocabulary and defers the set check to the parity suite; and the named consumer, cloud's platform-tool-names-conformance.test.ts, which asserts exact equality between PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio'] and SERVICE_AI_STUDIO_TOOL_DEFINITIONS.
  • Metadata-protocol: none — right. No authorable key, accepted value or type changes: the Zod accept set for tools[] is the regex string above, and no packages/spec/authorable-surface/ shard moves in the diff (none is touched, and no other file in the repo mirrors the list — the grep for the sibling names outside the locales finds only the registry, the MCP sets and card tests, no generated artifact).
  • Registry edit holds. delete_package sits in its sorted place (delete_field < delete_package < describe_metadata), snake_case, no cross-group collision, outside the action_ family — the four invariants platform-tool-names.test.ts pins. The header docblock's maintenance contract (a new name needs its chatbot.tool. label in every pack) is met.

② Semver level

patch on both @objectstack/spec and @object-ui/i18n is right: Metadata-protocol: none takes patch whatever the commit type (ruling A), and the changeset gate's two cross-checks (added under no, narrowed without the arm) are not triggered. Both changesets carry both declaration lines at line start, as does the PR body. Check Changeset is green on this head.

③ Boundary flags

  • Docblock accuracy against cloud#3656: the group comment says delete_package "only stages the removal of a package built in the environment — a person confirms before anything is deleted". That matches the tool's semantics as cloud#3656 records them: in the chat it queues a pending action and the write happens only on confirm (the dispatcher re-gates and calls protocol.deletePackage with the actor); on the MCP door it queues nothing and points the person to Studio's existing person-confirmed Delete package dialog; it refuses marketplace installs, code packages and system/cloud scopes — "built in the environment" is the right scope word. Accurate.
  • Ten translations, read one by one against their siblings in the same block: en "Delete a package" (differs from the title-caser's output, so the sentences pin holds); zh 「删除一个应用包」 — 应用包 is the word the zh block already uses for create_package 「新建一个应用包」, get_active_package 「确认当前应用包」, list_packages 「列出已有应用包」, so "app" vs "package" is consistent, not a drift; de "Ein Paket löschen" (siblings: "Ein Paket anlegen", "Ein Feld löschen"); es "Eliminar un paquete" ("Crear un paquete", "Eliminar un campo"); fr "Supprimer un paquet" ("Créer un nouveau paquet", "Supprimer le champ"); ja 「パッケージを削除する」 (「パッケージを新しく作成する」, 「項目を削除する」); ko 「패키지 삭제하기」 (「패키지 새로 만들기」, 「필드 삭제하기」); pt "Excluir um pacote" ("Criar um pacote", "Excluir um campo"); ru "Удалить пакет" ("Создать новый пакет", "Удалить одно поле"); ar "حذف حزمة" ("إنشاء حزمة جديدة", "حذف أحد الحقول"). All ten are real sentences in their language, each using the package noun its own block already uses, no placeholder, no English fallback, and each lands in the same alphabetical slot so the key sets stay equal across packs.
  • Precedent file set (eca7cd2008): registry + ten locales + one spec changeset + one i18n changeset — matched. The precedent's plugin-chatbot / app-shell work was the record-write card itself, which this tool does not need here (a packageRemoval card renderer is filed separately per the cloud#3656 seat record). The one precedent file this PR did not touch that is NOT card work is packages/lint/src/validate-ai-tool-references.test.ts — see ④.
  • MCP safety sets: delete_package is not added to PLATFORM_DESTRUCTIVE_TOOL_NAMES. Read against safetyAnnotations: a declared requiresConfirmation on the definition outranks the name, and an unlisted name gets no destructiveHint, which the SDK reads as its default true — the cautious reading. The sets are "deliberately partial" by their own docblock and remove_sample_data is absent too. Not a finding.
  • Pin ordering for the consumer (advisory, outside this PR): cloud's conformance test asserts exact equality, so a cloud pin move that carries this registry must land together with or after cloud#3686's manifest, or the test flips red in the other direction.
  • Check-runs on 97f93b55, read once: green — Governed Surface Queue Guard, Check Changeset, PR-body guards, Check PR Size, Spec property liveness, Lint · ESLint, Lint · repo & tooling gates, Lint · docs & code guards, Lint · CI/release/engine gates, Lint · PM dispatch-gates, Lint · scoped · query-options erasure, Lint · scoped · tooling self-tests, Type Check · source gates, Build UI Deps, Plan Test Core shards, Dogfood Regression Gate, Auto Label, Flag docs. NOT MEASURED (in progress at read time; not polled): Build Core, Test Core 1–8 and its gate, Type Check · workspace / · debt ledger / · consumer gates, Lint · scoped · slot lookup & corpus, Type Check UI, Lint UI, Test UI 1–16 and its gate, Build & E2E UI, Live E2E UI. The PR body's locally NOT-MEASURED gates map to those pending jobs: check:doc-formula-expressions, check:i18n and check:i18n-coverage run in Type Check · consumer gates; check:dual-build-cjs-loads and check:lean-entry-closure in Build Core; the ui scripts/ vitest in Test UI. None is yet covered by green CI; the queue guard holds the landing until every check is green, so this record does not stand in for them.

④ Design judgment

For the one hits file, read against the ruling it implements (cloud#3656's staged-only tool, blocked on this registry) and its first consumer (cloud's exact-equality conformance test): the change holds. The registry gains the name the consumer registers, the docblock says what the name does in the terms the tool actually honours, the label contract the registry's own header imposes is met in all ten packs, and the declarations match what the code's accept sets show.

No must-fix found.

Implemented-by: claude/issue-31020-platform-tool-delete-package
Reviewed-by: session_01Q4EjjRhUZjdy8VXs6Kkur2

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2

席位核对 · ACCEPT · 2026-11-06T19:56Z

Head-sha: 97f93b5503d18dc18d5c4dc24aa443ddc7f0f68c
Implemented-by: os-dev (session session_01Q4EjjRhUZjdy8VXs6Kkur2, branch claude/issue-31020-platform-tool-delete-package) · Reviewed-by: repo:cloud#3

  • 形态: 在 PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio'] 里加上 delete_package(按字母顺序排在 delete_field 之后),注释写明这个工具只发起删除、由人确认。10 种语言都加了 chatbot.tool.delete_package 显示名,全部是真实翻译,没有英文占位。spec 和 i18n 各一个 patch changeset。先例是 eca7cd2。
  • 契约复核: schema 面,PASS 6693733275。Clause-②: no、patch、Metadata-protocol: none 都确认无误,10 种翻译都已核过。唯一一条 should-fix:packages/lint/src/validate-ai-tool-references.test.ts 里缺一个固定 delete_package 为「已登记」的测试(以往每次往名单里加名字都补了一个)。这条交给后续卡,不移动本 PR 的 head。
  • 门禁: dispatch-gates 推导出 77 个检查,73 个 exit 0;4 个因新 worktree 里缺前置构建没测,由 CI 覆盖。spec 和 ui 的 i18n 相关测试全部通过(1549 个)。dev 申报:label 实际在 locales/ 而不在认领写的 namespaces/,已按先例放在 locales/。
  • check-runs(head 97f93b5503):落地脚本等必需检查全部 success 后才动作。
  • 下游: 合并后 cloud pin 跟进,objectstack-ai/cloud#3686 的工具名单一致性测试就会转绿。⛔ cloud 的工具名单一致性测试要求逐项完全相等,所以 cloud#3661 的 pin 只移到本 PR 之前的提交;带上本 PR 的那次 pin 移动由 cloud#3686 连同它的工具一起做。
  • 落地条款: 非受治理面,CI 绿 ⇒ 席位翻 ready、挂 auto-merge,经合并队列落地。

This branch has not been deployed

No deployments
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 protocol:system size/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant