Repository navigation
feat(metadata-protocol,runtime,service-automation,spec)!: the protocol refuses every organization-scoped write; an uninstall is environment-wide (ADR-0131 D6/D12) - #22515
Conversation
…d write (ADR-0131 D6) Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…est keys, ADR-0087 entries Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…r rows retire Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…stry regenerated Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…red key Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…st repairs Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…e retired organizationId Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…-protocol-env-only
…e orphan-adoption double unfiltered Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
📓 Docs Drift CheckThis PR changes 5 package(s): 42 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 13 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 145 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 64a2e9fe72d9bbc6b2c1358b5b8c273e73a51838 && git checkout 64a2e9fe72d9bbc6b2c1358b5b8c273e73a51838
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5910b5e3ed5414692ae74df28e155bf16f12b5cd 2318d0ba1602368c6096c7518aef8f0d02b3cc51 && git checkout -B drift-repro 5910b5e3ed5414692ae74df28e155bf16f12b5cd && git merge --no-ff 2318d0ba1602368c6096c7518aef8f0d02b3cc51
node scripts/docs-audit/affected-docs.mjs --json 5910b5e3ed5414692ae74df28e155bf16f12b5cd
|
…ctions Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Contract reviewServed-tier: Inputs: card #15206 (body and all 36 comments, through the S4 report 6085458127); #22350 (body, its 5 comments: the grade 6068216919, the ruling 6070750378, the claims 6071732822 and 6082130422, the release 6074820322); PR #22515 (body, its 89-file list, the net diff against its merge base ① Derived judgmentsGate verdicts on this head, as read. Two shards of the required Accept-set and public-surface changes, each read off the net diff and judged.
No other hand-written page names the deleted checks (grepped at head over ② Semver level
③ Boundary flagsDev deviations and questions (6085458127), each answered:
New at this head:
Out-of-scope findings, each carried: Verdict grounds, all on this head: the required Implemented-by: VERDICT: FAIL |
…-protocol-env-only
…audit read's seed; public-form withdrawal page; seed narrowing row Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
…-protocol-env-only
…ged tree Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <[email protected]>
Contract reviewServed-tier: Inputs: card #15206 (body and all 38 comments, through the merge-main round 6089617413); #22350 (body and its 5 comments: the grade 6068216919, the ruling 6070750378, the claims 6071732822 and 6082130422, the release 6074820322); PR #22515 (body, its 93-file list, both comments — the docs-drift note and the earlier record 6085867875, FAIL on ① Derived judgmentsGate verdicts on this head, as read. Every required context is What changed since the FAIL record. The fix round's own commits touch eight files, none of them protocol, door or spec source: Accept-set and public-surface changes, each read off the net diff and judged.
S3's carried items stay closed here (no organization threaded into any ② Semver level
③ Boundary flagsDev deviations and questions, from the S4 report 6085458127, the patch round 6087716647 (
New at this head, for the seat (none a verdict ground):
Out-of-scope findings, each carried, one line: Verdict grounds, all on this head: both FAIL grounds of 6085867875 are closed — the required Implemented-by: VERDICT: PASS |
维护者速读
改了什么:这是 ADR-0131 C5 的 S4 阶段,同时落实 #22350 的裁决 A。
为什么改:ADR-0131 D6 规定,环境元数据属于整个部署,任何组织都不再有自己的一份。S3 已经让 风险与代价(含回滚):
席位意见:建议批准。
你要做的:用 |
Refs #15206 (S4)
Refs #22350
Clause-②: yes (narrowing)
Stage S4 of #15206 (ADR-0131 C5): the metadata protocol refuses every organization-scoped write, and the per-organization write path behind it is deleted. It carries #22350 (ruling A): the
organizationId/allTenantskeys and bothTENANT_SCOPE_REQUIREDrefusals of the package uninstall retire.#15206 remains open for S5. #22350 is closed by the seat with this stage's landing record, not by this PR.
What changes
Protocol (
@objectstack/metadata-protocol)organizationScopedWriteRefusalis asked FIRST, before any read:saveMetaItem(draft and publish),publishMetaItem,deleteMetaItem,rollbackMetaItem,revertCommit,rollbackToPackageCommit,publishPackageDrafts,discardPackageDrafts,revertStoredPackage,duplicatePackageandreassignOrphanedMetadata.403 NOT_OVERRIDABLEfor every type. The first sentence names the tenancy posture in force.allowOrgOverrideexemption is gone, and theOS_METADATA_WRITABLEhatch no longer opens an organization scope.organizationIdis removed from each verb's request type.orgScopedWriteRefusal(the old exemption)anonymousFormIntakeOrgScopeRefusal/anonymousFormIntakeReopenRefusal/envWideRawViewRowsresolveMetaItemOrgScope/resolveDraftOrgScopeForPublishorganization_idNULL.MetadataAuditEntry.organizationIdis typednull.revertCommitrefuses a commit row recorded in a legacy organization layer.migrateStoredMetadatareports an organization-scoped row asskipped, naming the promotion ceremony (ADR-0131 C7), and never re-saves it.applyRemoteMetadataMutationconverges the registry on the environment row.deletePackage([decision] once ADR-0131 C5 makes package metadata environment-wide, does deletePackage's organization-scope guard (organizationId / allTenants, TENANT_SCOPE_REQUIRED, #7780) retire? #22350 A).organizationIdorallTenants(any value) →400 INVALID_REQUEST, nothing removed.UninstallCleanupargs droporganizationId.findPlatformScheduleOrgGapsloses itsorganizationIdinput, because every write is platform-level now. Its hint no longer prescribes "publish into an organization".Packages door (
@objectstack/runtime,domains/packages.ts)/packagesverb, nor into the commit list orassemblePackageManifest(S3's carried finding).requireUninstallOrganizationScopeand the door's400 TENANT_SCOPE_REQUIREDare deleted. Who may uninstall stays withrequireManageMetadataplus the read-only-package gate.Callers
@objectstack/service-automationflow-credential-migration.ts: a legacy organization-scoped flow row is not re-saved. It is reported asfailedwithNOT_OVERRIDABLEand logged aterror, stating that the row still carries the credential in cleartext.@objectstack/cloud-connection: therunUninstallCleanupsrunner type drops the retiredorganizationId. Type-only; the emitted JS is unchanged.Spec (
@objectstack/spec)organizationIdleaves theSaveMetaItem,PublishMetaItemandDeleteMetaItemrequest schemas. The authorable-surface lines go with them: the defs are not reachable from a metadata root, andcheck:authorable-surfaceproves it.TENANT_SCOPE_REQUIREDledger rows are removed.metadata-write-organization-scope-refusedandpackage-uninstall-environment-wide;registry.tsand the reference docs are regenerated.Docs
environment-variables.mdx(OS_METADATA_WRITABLEno longer opens organization scope).metadata-service.mdx(uninstall is environment-wide).public-data-collection.mdx§4: an organization copy of a public form is a legacy row that no write can edit. The organization-scoped save check is deleted (patch round 1).Not in this PR (by ruling)
Cross-lane paths
domain:cli:packages/runtime/src/domains/packages.ts(declared) and runtime tests.domain:services:packages/services/service-automation/src/flow-credential-migration.ts(declared) and its test.domain:spec:packages/spec/src/api/protocol.zod.ts,error-code-ledger.zod.tsandstack.zod.ts(comment);migrations/entries/semantic/18.*(2 new);migrations/registry.ts,authorable-surface/api.jsonandsrc/api/protocol.test.ts;content/docs/references/api/*(generated). All of these are declared.domain:cli([PM seat] domain:cli — 🟢 os-project-manager · session_019SvPnd2bzECRNmAU9i6E4k #6024) 6085525732:packages/cloud-connection/src/marketplace-install-local-plugin.ts, the runtime tests and thepackages/resttests.domain:cli([PM seat] domain:cli — 🟢 os-project-manager · session_019SvPnd2bzECRNmAU9i6E4k #6024) 6088463629:packages/runtime/src/audit-meta-item-org-scope.integration.test.ts.domain:devx([PM seat] domain:devx @ objectstack — ⏳ vacant #6023) 6085543707:environment-variables.mdx,metadata-service.mdxand the two dogfood tests.domain:devx([PM seat] domain:devx @ objectstack — ⏳ vacant #6023) 6088455367:content/docs/ui/public-data-collection.mdx.domain:spec([PM seat] domain:spec — 🟢 os-project-manager · session_01S3aAf11JjbW1mSGL1EhfFj #6017) 6085530833:stack.zod.ts,authorable-surface/api.json,src/api/protocol.test.ts, and the two entries with their regenerated pages.domain:spec([PM seat] domain:spec — 🟢 os-project-manager · session_01S3aAf11JjbW1mSGL1EhfFj #6017) 6088472708: the regeneratedspec-changes.jsonanddocs/protocol-upgrade-guide.md.domain:services([PM seat] domain:services — ⏳ vacant #6021) 6085537186: theflow-credential-migrationtest.packages/objectqltest files are in this seat's own lane.Size
About 6,500 changed lines (+1,639 / −4,857, 93 files at
2318d0ba1), over the human-merge line (3,000 onmain). Stage 0's named split seam does not work, for two measured reasons:/packageswrite by an org-active caller answers 403.So this lands on the human-merge route as one PR. Most of the volume is deleted tests of deleted behaviour.
Verification
Three rounds measured this PR. The later two are summarised first; the first round's detail follows.
2318d0ba1, report 6089617413). It mergedorigin/main5910b5e3ethroughos-regen-merge.sh, then regeneratedspec-changes.jsonandprotocol-upgrade-guide.md. Every step-18 id is present inregistry.ts,spec-changes.jsonand the upgrade guide. Thepackages/specfull suite passes 19,751. All 125 derived gates exit 0.packages/runtimeis NOT MEASURED in this round: the merge touched no runtime file.7054e63de, report 6087716647). This round followed contract review 6085867875, which FAILed. Thepackages/specfull suite passes 19,716. Thepackages/runtimefull suite passes 345 files, plus the re-premisedaudit-meta-item-org-scopeat 7/7. All 125 derived gates exit 0.First round (head
537fa89c8, merge base2e10c9ab)Identity pin.
protocol.org-scoped-write-refused.test.tspasses 302 tests. It is enumerated over everyDEFAULT_METADATA_TYPE_REGISTRYtype plus the plugin typeacme_widget, and covers:403 NOT_OVERRIDABLE, with nothing persisted;single,group,isolated);Reverse verification. The fix was committed first. Using
scripts/ablation-replace.mjswith a trap, the five-type exemption was re-inserted at the save door (if (!registryAllowsOverlay(request.type))around the refusal):git diff HEAD.Suites (local, under the verification lock):
@objectstack/metadata-protocolfull suite: 223 files, 28,304 passed, exit 0.@objectstack/runtimepackages domain plus the touched integration files: 30 files, 498 passed.objectql,rest,service-automationandmetadata-corefiles each pass.objectqltypecheck pluscheck:test-typecheck: exit 0.dogfood: 11 files that exercise metadata writes and package install / uninstall / publish, 167 tests passed.Typecheck: spec, metadata-protocol, objectql, rest, service-automation, runtime, cloud-connection, cli and dogfood all pass at the merged head.
Gates:
dispatch-gates --commandsderived 125 families. All 125 were run, and--ranreconciles them with exit codes: 125 run, 0 NOT-MEASURED, all exit 0.check:error-code-provenance(the flow-credential move'sNOT_OVERRIDABLErow is now registered) andcheck:objectql-double-limit.distmid-rebuild — and were re-run green after deepening and rebuilding.check:generatedreports all 15 artifacts up to date.objectui at the pin
f0268ad784: it sends noorganizationIdorallTenantson any metadata or package write, and imports none of the changed request types orTENANT_SCOPE_REQUIRED(git grep: 0 hits).NOT MEASURED locally in the first round (declared to CI):
specsuite, which was measured in patch round 1;runtimesuite, which was measured in patch round 1;rest,objectql,cliand dogfood suites beyond the files named above;pnpm lint.🤖 Generated with Claude Code
https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca
Generated by Claude Code