Repository navigation
feat(metadata-protocol, spec): a publish whose registry refused an object answers published_unregistered naming it - #33528
objectstack-fleet[bot] wants to merge 8 commits into
Conversation
…ject answers published_unregistered naming it The batch publish answers outcome published_unregistered, success false, and unregistered[] naming each object the runtime registry refused, under the object-registry-refused rule. The REST door's visibility flip keeps following this outcome, as it followed the published answer before. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
…e published answer it used to be Studio, the package sheet, Publish all and the AI chat card treated every success false as a failed publish. The new outcome answers success false over drafts that landed, with the refused object's warning already reported by the client, so each caller keeps the presentation it had. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
…ess counts for unregistered[] Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
… merge Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
📓 Docs Drift CheckThis PR changes 4 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 182 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b0af166ca6566870eb03ba573d8b26abb90b4a77 && git checkout b0af166ca6566870eb03ba573d8b26abb90b4a77
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e3f0cfd422d69100448ccd4f6a329c90a25715f7 85137fb0e84f3d42845f2a4799a15520bc0902d1 && git checkout -B drift-repro e3f0cfd422d69100448ccd4f6a329c90a25715f7 && git merge --no-ff 85137fb0e84f3d42845f2a4799a15520bc0902d1
node scripts/docs-audit/affected-docs.mjs --json e3f0cfd422d69100448ccd4f6a329c90a25715f7
|
|
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn Request: review · area E1 · head 28691d1 · 2026-11-14T23:43Z |
|
Contract-review-claim: session_016WV4cwxS1ZpSu2hAMRcqbt · head 28691d1 · 2026-11-14T23:46Z |
Review — changes neededHead-sha: must-fix 1 — the Metadata-protocol kind is wrong, and Check Changeset is red on it.
nit 2 — "pending a ruling" wording. The two status-quo choices are ruled here, so the comments can cite this review instead of "pending a ruling" / "until ruled otherwise" (packages/runtime/src/domains/packages.ts at
What I checked and found sound
VERDICT: changes needed (must-fix 1; nit 2 is optional) |
…pec minor Contract review of the publish-drafts outcome change: the authorable surface gained PublishPackageDraftsResponse:unregistered and the same event answers outcome/success differently, so the declaration is semantic and spec is minor. The two status-quo choices now cite that review instead of a pending ruling. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
|
Contract-review-claim: session_016WV4cwxS1ZpSu2hAMRcqbt · head 719d31d · 2026-11-14T23:49Z |
Contract reviewServed-tier: Face: schema (a ① Derived judgments
② Semver level
ADR-0087 entry ③ Boundary flags
④ Design judgment
No must-fix or should-fix remains; the round-one nit is applied. This is the final round. Implemented-by: VERDICT: PASS |
|
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn ACCEPT · area E1 · 2026-11-14T23:50Z
|
… the publish-outcome tests Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
|
Contract-review-claim: session_016WV4cwxS1ZpSu2hAMRcqbt · head 85137fb · 2026-11-14T23:55Z |
Contract reviewServed-tier: Delta of record 6886142557 (PASS on ① Derived judgments
② Semver levelUnchanged from record 6886142557: ③ Boundary flagsUnchanged. Land on this head's own green CI only. ④ Design judgmentUnchanged. Record 6886142557's judgment carries to this head. Implemented-by: VERDICT: PASS |
|
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn ACCEPT (head moved) · area E1 · 2026-11-14T23:56Z
|
Requested by Elon · project thread
Fixes #33277
Clause-②: yes (widening)
Metadata-protocol: semantic
维护者速读
published_unregistered(success: false),并在unregistered[]里点名这些对象,沿用 Publish: a seed load right after publishPackageDrafts can hit OBJECT_NOT_FOUND for objects the data door serves a minute later — the registry write-through swallows a registerObject failure #33005 的规则码object-registry-refused。packages/metadata-protocol/src/protocol-history-and-publish.ts(outcome 推导)、packages/runtime/src/domains/packages.ts(翻转白名单,新值保持翻转)、packages/spec/src/api/protocol.zod.ts(契约)。pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol-publish-drafts-advisories.test.ts,预期 14 个用例全绿,含[#33277]四个。What changes
PublishPackageDraftsResponseSchema):outcomegainspublished_unregistered; the response gains optionalunregistered: [{ type, name, rule: 'object-registry-refused' }], present if and only if the outcome ispublished_unregistered.successstays exactlyoutcome === 'published', so it is false on the new value. Describes updated; reference docs,authorable-surface/api.jsonand the strictness counts regenerated. One ADR-0087 semantic entry for major 18 (publish-drafts-outcome-published-unregistered), because a caller branching onsuccessoroutcomenow takes a different branch for the same server event.publishPackageDrafts, metadata-protocol): each object whose registry write-through was refused (the Publish: a seed load right after publishPackageDrafts can hit OBJECT_NOT_FOUND for objects the data door serves a minute later — the registry write-through swallows a registerObject failure #33005registryRefusedreceipt) is collected in publish order; the batch answerspublished_unregistered,success: false,unregistered[]. Nothing else moves: the drafts landed and stay live, every object is still inpublished[]with its warning,failed[]stays empty, and commit, seeds, probes and receipts are unchanged. Return types inprotocol-history-and-publish.tsandprotocol.tswidened.PUBLISH_OUTCOMES_THAT_FLIP):published_unregisteredis added, so the ADR-0045 visibility flip and themetadata:reloadedannounce run exactly as they did when this answer readpublished. Kept as the status quo pending a ruling (below).packages.publishDraftsdocblock no longer sayssuccess: falseon a 200 means nothing landed; it names the three non-success outcomes.ui/packages/app-shell): Studio's publish, the package sheet, Home's Publish all and the AI chat card treated everysuccess: falseas a failed publish. Each now readspublished_unregisteredas it read thepublishedanswer the server gave for this before: the refused object'sobject-registry-refusedwarning still reaches the author through the client's advisory sink, and no caller reports "Action failed" / "Publish failed" for drafts that landed.Tests
protocol-publish-drafts-advisories.test.ts(the shared harness): a new[#33277]describe pins the refused object named inunregistered[]withpublished_unregistered/success: falsein both publish orders (refused object first and second), two refused objects named in publish order, and a CONTROL that a batch the registry takes whole still answerspublished,success: true, with nounregisteredkey. The Publish: a seed load right after publishPackageDrafts can hit OBJECT_NOT_FOUND for objects the data door serves a minute later — the registry write-through swallows a registerObject failure #33005 case no longer pinsoutcome: 'published'.packages/spec/src/api/protocol.test.ts: the new value and key parse and round-trip; an entry with an unknown rule or no rule is refused; the vocabulary stays closed.packages/runtime/src/http-dispatcher.test.ts: the flip still runs afterpublished_unregistered(status-quo pin).PackagesPage.publishRefusal-11922,usePublishAllDrafts.refusal-11922,AiChatPage.publishAdvisoryReachesAuthorandStudioDesignSurface.publishCount-11807.scripts/ablation-replace.mjsreplaced theunregistered.push(...)line with a no-op (anchor 1 to 0, blob 8035b04df7e5 to 78b920f646cd); the pin file went to 3 failed / 11 passed, exactly the three negative[#33277]cases, CONTROL and the Publish: a seed load right after publishPackageDrafts can hit OBJECT_NOT_FOUND for objects the data door serves a minute later — the registry write-through swallows a registerObject failure #33005 cases green; restored to blob 8035b04df7e5 equal to HEAD,git diff HEADempty. The test imports./protocol.jsfromsrc, so no rebuild was needed.Acceptance notes
published_unregisteredstill flips_unpublishedapps (status quo: this answer used to readpublished). Alternative: drop it from the allow-list so an app whose object is not served stays hidden until a re-publish. Listed for a ruling; not changed here.ui/packages/data-objectstack/src/metadata-client.tsdoes not switch on the outcome (it returns a 2xx unexamined and only emits advisories); the switches are in the fourapp-shellcallers above, which this PR adapts.published_unregistered, keyed onunregistered[]or theobject-registry-refusedrule. Cloud already ships a bounded retry for the seed race; it should now branch on the outcome instead.publishMetaItem, a publish-mode save) still answer success with the warning onadvisories; the other write-through callers Publish: a seed load right after publishPackageDrafts can hit OBJECT_NOT_FOUND for objects the data door serves a minute later — the registry write-through swallows a registerObject failure #33005's report listed stay warn-only.protocol-history-and-publish.ts,protocol.ts,protocol.zod.ts,packages.ts, the advisories test,http-dispatcher.test.ts; the merge was clean and every suite below was re-run on the merged head.Verification
Premise measured first, at
origin/mainba35dfd (producer file restored from that commit, blob 884d24a1313b): a publish with the registry refusingticketanswered{"success":true,"outcome":"published","publishedCount":2,"failedCount":0}withticketcarryingobject-registry-refused, in both publish orders. At this branch:{"success":false,"outcome":"published_unregistered",...,"unregistered":[...]}in both orders.Package suites, final head 28691d1 (merged with origin/main), under os-verify-lock
@objectstack/metadata-protocoltypecheck exit 0 (tsc --listFilesOnlyincludes the advisories test);test: Test Files 340 passed, 9 skipped (349); Tests 22870 passed, 43 skipped.@objectstack/specsrc/api/protocol.test.ts+src/migrations/: Test Files 6 passed; Tests 451 passed.@objectstack/runtimehttp-dispatcher.test.ts,packages-publish-drafts-change-note.integration.test.ts,packages-publish-drafts-response-conformance.test.ts: Test Files 3 passed; Tests 275 passed.@objectstack/objectqlpublish-package-drafts-response-conformance.test.ts: 16 passed.@object-ui/app-shell, the four UI files: Test Files 4 passed; Tests 23 passed.Gates (local subset; CI owns the rest)
Exit 0 at the final head:
check:generated(all 14 artifacts current),check:strictness-ledger,check:api-surface(unchanged),check:doc-authoring,check-adr-0087-registration(no breaking changeset),check-nul-bytes. Exit 0 before the merge:check:spec-changes,check:upgrade-guide,check:authorable-surface,check:docs,check-changeset-no-major,check-empty-changeset,check:durability-log-level; eslint--no-inline-configon the nine touched package files and eslint on the four UI files (0 errors).dispatch-gates --ran: 12 of 123 derived families run locally, 111 left to CI by declared narrowing (the verify lock was held 3h20m by another run).NOT MEASURED locally: app-shell
type-check(needs every@object-ui/*dist built; Type Check UI owns it); thecheck:test-typecheckleg of runtime and client typecheck (their maintsc --noEmitpassed; the test layer reported errors in test files this diff does not touch, which import packages not built here).Session: https://claude.ai/code/session_016WV4cy1y7UNVbT2QAdmgdn
🤖 Generated with Claude Code