Skip to content

fix(metadata-protocol, cli, cloud-connection): a declared action override moved to another object is told which object the base ships the action on - #30697

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-o4ir71
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-o4ir71

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

Fixes #30623

Clause-②: no
Metadata-protocol: none

维护者速读

  1. 改了什么:.custom 动作覆盖把 objectName 写成了与基包动作不同的对象时,declared_package_ships_no_such_item 拒绝信息现在点名两个对象,并告诉作者保留基包动作的 objectName;三个入口(保存/发布门、os validate、托管安装)用同一句话。
  2. 为什么改:declared_package_ships_no_such_item: the refusal names neither the object nor the remedy when an action override moves the action to another object #30623。原话说基包「没有叫 X 的动作」、让作者「改名」,可名字是对的、错的是对象,作者会去改错地方。
  3. 风险与回滚:只改文案。规则、错误码(NOT_OVERRIDABLE)、状态码(403)、判定结果全不变;基包根本没有这个名字时,文案与今天一字不差。回滚即 revert。
  4. 先看:protocol-packaged-base-refusal.ts 的 shipsNoSuchItemMessage(唯一的句子构造器)和 OverrideWriteClosure.baseItemsOf(三个入口各自递进基包的同类条目)。
  5. 两分钟验证:pnpm --filter @objectstack/cloud-connection exec vitest run src/marketplace-install-local-override-gate.test.ts,预期 14/14 绿,其中 [#30623] 两条(换对象、CONTROL)。
  6. 需要你做的:无,席位落地。

What changes

  • One builder — shipsNoSuchItemMessage in packages/metadata-protocol/src/protocol-packaged-base-refusal.ts writes the declared_package_ships_no_such_item sentence. judgeOverrideWrite already serves all three doors, so the builder lives there, in the lowest package all three already import; no new cross-package export.
  • When a declared action override names a base that ships an action of that name on another object, the sentence becomes: 'action/NAME' declares an override of 'BASE' on object 'OVERRIDE_OBJECT', but 'BASE' ships its action 'NAME' on object 'BASE_OBJECT'. An override replaces the base's action on that action's own object: keep the base action's objectName: 'BASE_OBJECT' in the override, or remove overrides to keep it as 'PAIR''s own item (ADR-0146 D2).
  • Otherwise (another type, a name the base does not ship at all, or no base items in hand) the sentence is today's, byte for byte.
  • OverrideWriteClosure gains an optional baseItemsOf(base): the base's items of this type at any object. Each door hands it the items it already holds:
    • save/publish door (overrideWriteVerdict): the artifact lookup's items under that base's _packageId;
    • os validate (packages/cli/src/utils/override-declarations.ts): the base package's walked items, when the artifact carries it;
    • managed install (packages/cloud-connection/src/marketplace-install-local-plugin.ts): the base's listing it already reads (heldBy).
  • The packageless overlay migration (protocol-packageless-overlay-migration.ts, cli migrate packageless-overlays) only names the code in a comment and asks overrideWriteVerdict, so it gets the new sentence with no change.
  • The rule, code and status are unchanged. No packages/spec/**.

Changed lines: 174 (+165 / -9, 7 files).

Tests

  • Save door: packages/objectql/src/protocol-flow-custom-override.test.ts: [#30623] pins the full sentence through saveMetaItem (403 NOT_OVERRIDABLE) for showcase_task_close moved to showcase_other, plus a CONTROL for an unshipped name (today's sentence, whole verdict).
  • os validate: packages/cli/src/utils/override-declarations.test.ts: log_call (base on crm_account) declared on crm_lead, first sentence plus the objectName: 'crm_account' remedy; CONTROL no_such_call.
  • Managed install: packages/cloud-connection/src/marketplace-install-local-override-gate.test.ts: crm_close (base on crm_account) declared on crm_lead → 403, nothing saved or ledgered, first sentence plus remedy; separate CONTROL crm_reopen.
Ablation (one, on the builder)

node scripts/ablation-replace.mjs on protocol-packaged-base-refusal.ts, anchor if (others.length > 0) { → if (others.length > 0 && String('ABLATE30623') === 'on') {; pnpm --filter @objectstack/metadata-protocol build; ablation-dist-preflight.mjs @objectstack/metadata-protocol ABLATE30623 exit 0 (marker in dist).

  • objectql: Tests 1 failed | 14 passed (15); red: [#30623] the moved override's refusal names both objects…
  • cli: Tests 1 failed | 11 passed (12); red: [#30623] an action override moved to another object…
  • cloud-connection: Tests 1 failed | 13 passed (14); red: the moved override; the CONTROL stays green.

Restore: blob == HEAD (153a82430761), git diff HEAD empty; rebuild; preflight --absent ✓; the three files 15/15, 12/12, 14/14.

Acceptance notes

Verification

Local runs

Head after the gates: 01adff4f (the fix commit); 9569f388 adds only a merge of origin/main touching none of the 7 files.

  • Build: turbo run build closure for cli / cloud-connection / objectql + metadata-protocol: 62/62 tasks, lock VERDICT command-exit 0.
  • Typecheck: pnpm --filter metadata-protocol --filter cli --filter cloud-connection --filter objectql typecheck: VERDICT command-exit 0.
  • @objectstack/metadata-protocol vitest: Test Files 317 passed | 4 skipped; Tests 22454 passed | 26 skipped; exit 0.
  • @objectstack/cloud-connection vitest: Test Files 70 passed; Tests 892 passed; exit 0.
  • @objectstack/cli --project unit (after pnpm --filter @objectstack/cli build): Test Files 389 passed; Tests 5432 passed; VERDICT command-exit 0. Integration layer declared to CI (no spawn entry touched).
  • @objectstack/objectql: src/protocol-flow-custom-override.test.ts 15/15; the full package run is CI's.
  • dispatch-gates --commands: 64 families; 63 exit 0; check:dual-build-cjs-loads exit 3 then 1 on an unrelated @objectstack/organizations dist that this targeted build did not emit (needs a whole-tree build): NOT MEASURED, CI runs it. --ran: 64 derived famil(ies) accounted for — 63 run, 1 NOT-MEASURED.

🤖 Generated with Claude Code

https://claude.ai/code/session_016WV4cx3aafYJDsJo3siYFw

…ride moved to another object is told which object the base ships the action on

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

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

7 anchor(s) derived from 3 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 63 of 221 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 45 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 788715ef5cb205d3e70052d25a595e13a8aa9d7c → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 9c69dd2a14ec0be53319dc91e956e999b79d3729 — the merge of head 9569f3887df3b43200aae00a9f277d86615115b3 into base 788715ef5cb205d3e70052d25a595e13a8aa9d7c, 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 9c69dd2a14ec0be53319dc91e956e999b79d3729 && git checkout 9c69dd2a14ec0be53319dc91e956e999b79d3729
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 788715ef5cb205d3e70052d25a595e13a8aa9d7c 9569f3887df3b43200aae00a9f277d86615115b3 && git checkout -B drift-repro 788715ef5cb205d3e70052d25a595e13a8aa9d7c && git merge --no-ff 9569f3887df3b43200aae00a9f277d86615115b3

node scripts/docs-audit/affected-docs.mjs --json 788715ef5cb205d3e70052d25a595e13a8aa9d7c

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

维护者速读

  1. 改了什么:作者覆盖基础包的动作、却把它挂到了别的对象上时,拒绝信息现在说清「基础包把这个动作放在哪个对象上」,并让作者保留基础动作的 objectName;三个入口(保存/发布、os validate、托管安装)同一句话。
  2. 为什么改:以前说「基础包没有这个名字的动作,请改名」,可名字是对的,错的是对象,作者会去改错地方(PR fix(objectql, metadata-protocol, cloud-connection)!: a declared .custom action override is keyed and judged the same way at every door, and only its declared base's handler slots beneath it #30612 复审发现)。
  3. 风险:低。只改拒绝文字;错误码 declared_package_ships_no_such_item、状态 403、规则都不变。基础包确实没有这个名字时,文字照旧。
  4. 先看:packages/metadata-protocol/src/protocol-packaged-base-refusal.ts 的 shipsNoSuchItemMessage。
  5. 两分钟验证:pnpm --filter @objectstack/cloud-connection exec vitest run marketplace-install-local-override-gate。
  6. 需要你做的:无,席位落地。非 BREAKING,不属 Tier H,不超 3000 行。

席位意见:ACCEPT(#30623)。

席位核对

Head-sha: 9569f3887df3b43200aae00a9f277d86615115b3 · read 2026-11-05T23:05Z

Item Reading
Shape Draft → main via relay pr_create; Fixes #30623. 7 files, +165/−9. ⛔ packages/spec/**, no new error code.
Seat diff read One builder shipsNoSuchItemMessage inside judgeOverrideWrite, which all three doors already call; OverrideWriteClosure gains an optional baseItemsOf each door supplies (CLI from the walked artifact, install door from its holdings listing). Only action takes the object branch; other types and an unshipped name keep the old sentence. Absent baseItemsOf ⇒ old sentence.
Evidence Pins at the three doors with a CONTROL for an unshipped name; ablation red at all three doors, restored; metadata-protocol 22454, cloud-connection 892, cli unit 5432 pass; typecheck 4 packages 0 (os-dev-report 6671401274).
Gates (check-runs on this head) 48: 35 success, 13 skipped, 0 failed; mergeable_state clean.
Accepted deviations packages/objectql/src/protocol-flow-custom-override.test.ts (a test pin, outside the claimed list): the save door's pin lives there. Test-only, no source change in objectql.
Semver @objectstack/metadata-protocol, @objectstack/cli, @objectstack/cloud-connection: patch; Clause-②: no, Metadata-protocol: none.
Landing Not governed (check-governed-merges --pr 30697: NOT governed), 174 lines ≤ 3000, not BREAKING, so per pm-dispatch the seat lands it: pr_ready + automerge_enable.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 23:06
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 23:06
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 1030a80 Nov 5, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-o4ir71 branch November 5, 2026 23:29
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 tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

declared_package_ships_no_such_item: the refusal names neither the object nor the remedy when an action override moves the action to another object

1 participant