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 <noreply@anthropic.com>
…est keys, ADR-0087 entries Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…r rows retire Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…stry regenerated Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…red key Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…st repairs Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…e retired organizationId Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…-protocol-env-only
…e orphan-adoption double unfiltered Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
📓 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
…-protocol-env-only
…ged tree Claude-Session: https://claude.ai/code/session_01NcYr731pAx356wDedHe9Ca Co-authored-by: Claude <noreply@anthropic.com>
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).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.packages/cloud-connection/src/marketplace-install-local-plugin.ts(one type line; a consumer ofDeletePackageRequestthe census missed);packages/objectql,packages/restandpackages/qa/dogfood;content/docs/deployment/environment-variables.mdxandcontent/docs/kernel/contracts/metadata-service.mdx.Size
About 6,300 changed lines (+1,502 / −4,802, 89 files), over the human-merge line (3,000 on
mainat PR time). 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 (head
537fa89c8,origin/mainmerged ate148ca98)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 (declared to CI):
runtime,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