Repository navigation
feat(plugin-security)!: no seeder or materializer writes a sys_permission_set row; the boot seeds no row for a declared set (#15204 stage 6b-2) - #22900
Conversation
…efusal diagnostics and managed_by normalizer (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…log row; os meta resync is retired (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…us retires with its writer (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…ift_status / drift_detail (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…the legacy platform-bucket rows themselves (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…face-only disposition (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…ed seeders (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…new one (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…wn changeset (#15204 stage 6b-2a) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…ermission_set row; existing-database cases write the legacy row themselves (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…places did (#15204 stage 6b-2) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
…r, a command that exists (#15204 stage 6b-2a) Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 6 package(s): 54 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 16 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 150 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 5a6c315123e36862b162d4a4a2b6869fc825133b && git checkout 5a6c315123e36862b162d4a4a2b6869fc825133b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 038d4c958837fb42e71842c18f062f37bd866811 320ce20b743c40d6908ae9fb83ccc2e1efba3cec && git checkout -B drift-repro 038d4c958837fb42e71842c18f062f37bd866811 && git merge --no-ff 320ce20b743c40d6908ae9fb83ccc2e1efba3cec
node scripts/docs-audit/affected-docs.mjs --json 038d4c958837fb42e71842c18f062f37bd866811
|
… seeder was the only caller of (#15204 stage 6b-2) warnOrganizationLessRows, catalogIsPerOrganization and listSeedOrganizationIds had one caller, bootstrap-declared-permissions.ts, deleted in this PR. Re-measured: no live caller and no test. Internal (never exported from the package index). Also carries T1's buildExistingByName key-set fence byte-for-byte. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
…15204 stage 6b-2) No assertion changes; keeps the residual under the 3,000-line ruling after the organization-scope deletion. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
Regenerated with `node scripts/tenant-audit-census.mjs --write`; the population is unchanged at 225, only the measuring commit moves. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
Contract reviewServed-tier: Inputs: card #15204 (body and all 188 comments; the maintainer's rulings record 6123311533 「W3 选 A,D 选 1」, the ① Derived judgmentsEach line names a change the diff implies and judges it; (a) to (k) follow the brief's lettering. (a) The ruled uninstall cleanup.
(b) Position bindings against ADR-0090 D5, answered from the code and the ADR text.
(c) The deletions and their callers.
(d) Schema and data.
(e) Publish-time re-derivation.
(f) Changesets — ② below. (g) Size and tier, reproduced. In the scratch clone: (h) The T1 / T2 bytes D carries. T1's 16 files: 13 blob-identical at D's head (the six deleted suites deleted, the seven trims byte-identical); 3 differ — the two baselines (above: merged with T2's removals) and (i) Rewritten tests. (j) The developer's verification and the 8 anchors. (k) No collateral. No Gate verdicts on ② Semver level
③ Boundary flagsDev acceptance notes (4) — each answered:
Reviewer's flags (4) — none fails the head:
Out-of-scope findings, carriers accepted as filed: the 8 checklist anchors (the checklist areas' owners, via the watchdog); Implemented-by: VERDICT: PASS Generated by Claude Code |
…retired seeder and materializer Text only, from the contract review's flag ③3: `authorization.mdx`'s package-door paragraph, `permission-model.md`'s install sentence, and three code comments (the name-collision report, install-local's `metadata:reloaded` note, `sys_permission_set.managed_by`) spoke of the seeder, the publish materializer and the managed_by normalizer in the present tense. They now describe the catalog serving the package's sets, or name those writers as retired. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
Contract reviewServed-tier: Inputs: the delta brief; the full contract review 6128268740 on ① Derived judgmentsDelta round. This record judges the one commit (a) The delta is text-only. Right. One commit, (b) ③3, sentence by sentence against the tree at
(c) ③1. Closed. The PR body at (d) CI on (e) No collateral. Right. The 121 files on the PR hold no (f) The grep the brief asked for — present-tense mentions of the four names at
② Semver levelUnchanged by this delta: it touches no ③ Boundary flags
Out-of-scope findings, carriers as filed: 6128268740's two (the 8 checklist anchors; Implemented-by: VERDICT: FAIL Generated by Claude Code |
…publish; retire the remaining seeder prose Delta review ③3-a: no seeder or materializer writes a `sys_permission_set` row, but until stage 7 retires the ADR-0094 projector a permission-set publish (a package-door publish, or a writable base's direct publish) still has it write a projection row, `managed_by: 'admin'` with no `package_id`, and the boot reconcile re-creates it when missing. No authorization path reads it, and uninstalling the package removes it. `authorization.mdx`, the changeset and the deletePackage dogfood header now say so. ③3-b: the remaining present-tense mentions of the retired seeder and materializer are reworded: `authorization.mdx`'s isSystem bypass and the lifecycle table; `sys_permission_set`'s `package_id` and `managed_by` descriptions (English bundle regenerated with `check-i18n-bundles --write`); install-local's two metadata:reloaded warnings, which no longer claim permission sets wait for a restart; and comments in `protocol.ts`, `permission-set-projection.ts`, `packaged-permission-set-lock.ts` and `permission-set-name-collision.ts`. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
…ional projection row The Environment-admin bullet's "pure projection … re-derived on every metadata mutation" now notes that a package's published set gets such a row too until stage 7, the transitional `admin` row the Package-door bullet describes, so the two bullets agree. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
Contract reviewServed-tier: Inputs: the round-2 delta brief; the full contract review 6128268740 on ① Derived judgmentsDelta round 2. This record judges the two commits (a) Scope of the round. Text-only; right. Two commits, (b) ③3-a, sentence by sentence against the tree at
(c) ③3-b.
(d) Changeset and semver. Unchanged and right. The round's two hunks in (e) CI on ② Semver levelUnchanged by this round in level and marker: ③ Boundary flags
Out-of-scope findings, carriers as filed: 6128268740's two (the 8 checklist anchors; Implemented-by: VERDICT: PASS Generated by Claude Code |
Seat ACCEPT: PR #22900 (stage 6b-2 D, the declared-permission seeders retired) at
|
维护者速读(终稿)· #15204 阶段 6b-2 D:播种器和物化器不再写
|
Part of #15204
Clause-②: yes (narrowing)
Stage 6b-2: no seeder or materializer writes a
sys_permission_setrow, and the boot seeds no row for a declared set. The declared-permission seeder, the platform-default materialization, thepermissionpublish materializer, themetadata:reloadedre-seed and the organization-creation hook are deleted, with drift, the seed refusal diagnostics and themanaged_bynormalizer ("only delete, never fix", batch #310 item 4). An uninstall still revokes every grant of the package's sets, now by name (option 1, the maintainer's ruling 6123311533; mechanism B, the seat's choice under option 1). Until stage 7 (7a, #22975) retires the ADR-0094 projector, a permission-set publish still has it write a transitionaladminprojection row (see "The ADR-0094 projector until stage 7" below). This PR leaves #15204 open: stages 7a, 7b, 8, 8-post, C7b and 6c remain.Landing — draft until the seat marks it ready
main, last feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939 (grant-name pickers) and chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) #22967 (the console pin), with CD (feat(runtime): POST /security/permission-sets/:name/clone, the permission-set clone door (#15204 stage CD) #22881) and 6b-2a (feat(cli)!: delete os meta resync and the example position binders (#15204 stage 6b-2a) #22899) before them.main(df7a137923) is merged into this branch.mainwith their pins gone. Ifmainmoves first, it is merged into all three again just before landing.main(simulated:maindf7a137923+ T1bb7b4cef36+ T2a38b54f6f2, then this head): 3,601 changed lines (48 files, +945 / −2,656). The uninstall revoke and its pins (mechanism B) took it over 3,000. This diff touches no governed path. Until T1 and T2 land, GitHub shows the whole branch.mainis merged in after T1 and T2:scripts/engine-double-contract.pinned.json: regenerate withnode scripts/check-engine-double-contract.mjs --write(measured: the regeneration produces no change against this branch).*.baseline.jsonledgers: T1 and T2 conflict with each other there; drop every entry for a deleted suite.What changes
bootstrap-declared-permissions.ts(522 lines)managed_by:'package'row, once per organization under a wallbootstrap-platform-admin.tsresyncreconciled themadmin_full_accessrow only for leg C (a grant written before the name column; restrict-only). A refused read withholds the promotion and says so once. Noresyncoption, noseeded/resynced/resyncSkippedpermissionpublish materializer (SP)everyone's re-derivation only when it materialized and the body carriedisDefaultonMetadataMutation: every landedpermissionpublish, direct save or delete, unconditionally. Drafts and other types do nothing (closes U2 contract flag A, 6109964380). The ADR-0094 projector still writes anadminprojection row on the publish until stage 7 (next section)metadata:reloadedre-seed, organization-creation hook (SP)permission-set-drift.ts,normalize-managed-by.ts,seed-refusal-diagnostics.tswarnOrganizationLessRows,catalogIsPerOrganization,listSeedOrganizationIds(organization-scope.ts, internal)sys_permission_set.drift_status/drift_detailand the Needs Attention viewreadDeclareddeclared-capability-context.ts(its two readers: the capability context and the managed-object write denies). It is a read of the registry, the catalog's one home, never of a rowsecurity.package-permissions, both doors)managed_by:'package'rowsThe ADR-0094 projector until stage 7 (measured)
With the
permissionmaterializer gone, the awaited ADR-0094 projector (projectPermissionMutation, retired in stage 7 / 7a #22975) is the one writer left on a publish. Measured on the CRM stack, fresh database, this head againstmain:mainpublishPackageDrafts)managed_by:'admin', nopackage_idmanaged_by:'package',package_idsaveMetaItempublishadmin, nopackage_idPATCHsys_metadatarow (no environment overlay); the catalog serves the editDELETEsys_metadatarow and the served setsuccess:false; the row stays, thesys_metadatarow goesdeletePackageadminrowNo authorization path reads the row (the resolver reads set bodies from the catalog). The one change from
mainis the provenance of a package-door publish's row (package→admin) and what a data-door delete of it does. Stage-plan rule:permission-set-projection.tsretires in 7a, so it is not fixed here ("only delete, never fix"). The seat carries "after 7a, a package-door publish writes no row" on 7a's card. The alternative, a projector guard that creates no row for a package-held name, is offered to the maintainer as (A).Uninstall: the grants naming the package's sets (ADR-0090 D5)
With no row standing for a package's set, the cleanup found no grant to revoke: a grant naming the set survived the uninstall, inert while nothing served the name, and live again on reinstall. Option 1 (the maintainer's ruling on #15204, 6123311533): revoke by the package's catalog set names, read before the package is withdrawn. Mechanism B (the seat's choice under option 1): capture before the withdrawal and hand the names to the cleanups; the lifecycle order is untouched.
captureUninstallDeclared(registry, packageId, stored?)(@objectstack/metadata-protocol) runs just beforeregistry.uninstallPackage, indeletePackageand in install-local'sDELETE /api/v1/marketplace/install-local/:id. The withdrawal still precedes the cleanups ([finding] After an install-local uninstall, a later hot install of ANOTHER package re-projects the uninstalled package's permission set, which survives the restart as an orphan package-managed row #21576 / [finding] An install-local uninstall (DELETE /api/v1/marketplace/install-local/:id) leaves the package's permission sets in sys_permission_set: the "no ghost grants" uninstall cleanup never runs on that door #21490 race guard unchanged); the capture is synchronous, so install-local still has noawaitbetween the ledger removal and the withdrawal.SchemaRegistry.securityCatalogNamesHeldBy(packageId, 'permission')(new; the package's claims and<packageId>:<name>item slots, unfiltered by disable, since a disabled package still holds its names). This names an installed (artifact / install-local) package's sets.deletePackage, thepermissionrows of the package'ssys_metadatathat the door already read before any delete. A base-authored item is held in the registry's bare slot with no_packageId(provenanceorg) (measured on the CRM stack:securityCatalogNamesHeldBy(base)answers[], whilesys_metadataholds{ type: 'permission', name }), so the registry alone cannot attribute it to the base.UninstallCleanup's args gaindeclared?: { permission?: string[] }, passed byrunUninstallCleanupsonly when the capture named a set. A package that declared none hands its cleanups exactly the request they had before.PACKAGE_JOBS_UNINSTALL_CLEANUPis unchanged.sys_user_permission_setgrant naming a captured set. A name has one holder (the registry refuses a second at install), so each such grant was a grant of this package's set.managed_by:'package'rows until C7b (this PR's changeset says so). Grants written before the name column andsys_position_permission_setbindings (which carry onlypermission_set_id, no name column) are still reached through such a row.Pins
builtin-positions.boot.test.ts(real plugin boot, real SQLite, every scenario): zerosys_permission_setrows after boot, with a positive census control. The first platform administrator (single) and the organization administrator are still granted. The grant golden is unchanged, with no row at all.grant-permission-set-name.writers.test.ts: the promotion leaves zero rows and the holder reads by name. The 6b-2-pre pins stay green.everyone-rederivation-on-permission-mutation.test.ts: one listener even across a bootstrap re-run. Publish and delete of apermissionre-derive; a draft or another type does not.showcase-permission-seeding.dogfood.test.ts(thedeclarative-permission-seedingauthz row, rewritten): the showcase's sets are served by the catalog with their package, and the boot writes no row.bootstrap-platform-admin-refused-existence-read.test.ts: a refused legacy read withholds the promotion and writes nothing.marketplace-install-local-uninstall-withdrawal.test.ts: the order is capture → withdraw → cleanups, and the cleanups get the names; control: a registry that cannot say hands nothing. End to end,package-install-local-uninstall-cleanups.integration.test.ts(CLI, four orders of events, rewritten to the catalog): grant by name → DELETE → the grant is gone → after a restart, another package's hot install, and a reinstall of the same package, the grant is not live again ("the grant revoked by the DELETE does not come back with the set"). Ablation: the capture answering nothing turned the door pin red (1 of 8); the controls stayed green.deletePackagedoor).package-uninstall-revokes-named-grants.dogfood.test.ts(CRM stack): a writable base publishes a set, a user is granted it by name,deletePackage→ the grant is gone; the base publishes the set again → it is served, and the grant does not come back. Ablation: dropping the capture indeletePackageturned 2 of 3 red. Before the stored-row source existed, this pin was red with the registry-only capture.protocol.uninstall-declared-capture.test.ts: the helper (both sources, the union, nothing when nothing names a set), the runner's hand-off, anddeletePackage's order.protocol.uninstall-cleanups-runner.test.ts's control (a request with no capture is passed through unchanged) stays green.registry-security-catalog-names-held-by.test.ts: the names a package holds, a disabled package included, none after uninstall.cleanup-package-permissions.test.ts: the named grants go, with a no-names control in which they survive.Tests this branch rewrites (they pinned the rows it removes)
standalone-stack-seeder-declaration-copy.test.ts(runtime): asserts no row for a declared set, as it already did for a capability.package-install-local-boot-steps.integration.test.ts(CLI, Hot install via os package install leaves record-change flows unbound and the package's permission sets unprojected until a restart, and says nothing #21322): the hot-installed set is read fromGET /meta/permission/…. The flow cases still pin Hot install via os package install leaves record-change flows unbound and the package's permission sets unprojected until a restart, and says nothing #21322's defect; the permission-set case now pins the current contract (the catalog served the set before Hot install via os package install leaves record-change flows unbound and the package's permission sets unprojected until a restart, and says nothing #21322 too).Also in this PR
permission.packageIdre-points to its surviving reader (the CLI's compile-time collision door).permission.managedByis corrected todead(see Acceptance notes).main:mainhas 227 write sites, and this branch's removal of the normalizer's and the platform-admin bootstrap'supdatesites takes it to 225. The hand-written figures ontenant-audit-census.mdxfollow.permission-sets.mdx(built-in sets, provenance, the drift section reduced to overlay shadow) andauthorization.mdx.Changeset
One file,
.changeset/15204-s6b2-declared-permission-seeders.md:@objectstack/plugin-securityminor, BREAKING,Clause-②: yes (narrowing), ADR-0087not-required (no-migration-prescription). The level is unchanged by the uninstall work: nothing an author writes moves.@objectstack/metadata-protocolminor and@objectstack/objectqlminor, additive: the optionaldeclaredargument of the exportedUninstallCleanuptype and ofrunUninstallCleanups' request, theUninstallDeclaredtype,captureUninstallDeclared, andSchemaRegistry.securityCatalogNamesHeldBy.@objectstack/cloud-connectionpatch (its door hands the names on).cleanupPackagePermissionstakes an optional fourth argument.check:changeset-no-majorandcheck:adr-0087-registrationexit 0.Verification (local, at this head)
At
ecfb54f8b8,maindf7a137923merged in (c60e08810). The merge had two conflicts: install-local's imports, where both sides' imports were kept, and the declaration-copy test's persisted-row case, which #22994 had rewritten and which keeps this branch's "no row" side.turbo run build, every task green. Typecheck green for the 21 packages below and dogfood.turbo run test, 21 packages: plugin-security, platform-objects, runtime, metadata-protocol, cli (unit and integration), objectql, cloud-connection, plugin-auth, organizations, plugin-approvals, plugin-sharing, mcp, rest, hono, client, http-conformance, core, example-crm, example-showcase, example-todo, example-multi-package): 82 of 82 tasks green. plugin-auth: 136 files, 2,780 passed. cloud-connection: 43 files, 519 passed (from source; see below).deletePackagedoor pin, the grant-name pickers andmain's walled-catalog suites included).check-i18n-bundles: green after the full build.dispatch-gates --commands: 117 derived families, all run and reconciled by--ran, 0 not measured.check:test-source-aliaswent red on this diff earlier (cloud-connection's new runtime import of@objectstack/metadata-protocol). It is now aliased to source and green.check-engine-split-rationeeds history covering its 90-day window; the clone was deepened to it, exit 0.check:platform-checklist, the same 8 absent-symbol anchors on T1 (which touches no checklist file). That check is the scheduled watchdog's (checklist-status.yml), not a per-PR gate, andmain's checklist cites none of T1's deleted files.check:changeset-no-majorandcheck:adr-0087-registration: exit 0.check-tenant-audit-census: OK, 225 sites.After
ecfb54f8b8, three text rounds from the contract reviews:5cc2ef8629,70a42bf2f5and320ce20b74. They change docs prose, code comments, the changeset's wording, twosys_permission_setfield descriptions (with the English translation bundle regenerated) and two install-local warn strings; no code path. At320ce20b74:check-i18n-bundles, the docs checks,check:changeset-no-majorandcheck:adr-0087-registration: all 0;dispatch-gates: 119/119 run, the only non-zero being the checklist watchdog.Acceptance notes
Data-door reach on a package-door-published set (a writable base, package installed; measured on the CRM stack, this PR vs
main):PATCHis 200 on both and lands in the base's ownsys_metadatarow, with no environment overlay;DELETEdeletes end to end here (the row, thesys_metadatarow and the catalog entry), whilemainhalf-applies it (success:false;sys_metadatagone, the row and the served body kept);mainafter a reload;singlethe wall is inert, so the door is open to any caller with CRUD onsys_permission_set(the platform operator in practice); undergroup/isolatedthe wall refuses everyone but the operator (ADR-0131 D3);managed_by:'package'is what the projector's delete leg, the data-layer gate'stransfer/restore/purgerefusals and the uninstall cleanup's legacy row path key on, and a publish no longer stamps it here. The packaged-set lock (packaged-permission-set-lock.ts) keys on the artifact, not the row, and answers the same on both trees (delta review 6130075012 ①8);Stale text left to its carriers:
packages/spec/src/security/permission.zod.ts:845(managedBy's JSDoc, "seeded bybootstrapDeclaredPermissions, re-seeded on upgrade"): the spec seat, with themanagedByenforce-or-remove item.seed-name-lookup.ts:9andpackages/objectql/src/engine-capability-provenance.test.ts:164–165(comments): C7b.permission.managedByis an authored key with no reader (pre-existing; the ledger now saysdead). Retiring it is an enforce-or-remove item for the spec seat. It is not done here.The name-fold census instrument (
scripts/measure-position-name-fold-census.mjs, not a CI gate) refuses to report since 6b-2a deleted the binders. Carrier: whoever next runs it re-aims its junction scan atPositionSchema.permissionSets.Two dogfood suites (
two-doors-permission,showcase-permission-projection) keep their data-door cases on an existing database (the fixture writes the legacy row), because the gate still guards such rows until 7a / stage 8.plugin-auth's two grant-reader suites read the legacy platform-bucket rows; their fixture is T2's item (d) (test(dogfood): fixtures read permission sets from the security catalog (#15204 stage 6b-2, T2) #22898,
a38b54f6f), carried here byte-identical (8e40fb06b) as this branch carries T2's other bytes, so it cancels out of the measured size.维护者速读(草稿)
改了什么:不再有任何播种器或物化器向
sys_permission_set表写行,启动时也不再为声明的权限集播种行(在阶段 7 删除 ADR-0094 投影器之前,发布权限集时投影器仍会写一条admin投影行,鉴权不读它,卸载包时会被删掉)。删除了:包声明权限集的播种器、平台默认权限集的物化、包发布时的物化器、热安装后的重播种、新建组织时的播种,以及基于这些行的漂移诊断、managed_by归一化和播种拒绝诊断。drift_status/drift_detail两个字段及「需要关注」视图随写入者一并删除。卸载包时仍会撤销所有指向该包权限集的授权:两个卸载入口在把包从注册表撤下之前,先记下该包持有的权限集名称(注册表中的名称,加上deletePackage已读到的该包已存储的权限集行),交给清理步骤按名称撤销授权(方案 1 是你的裁定 6123311533;机制 B 是席位在方案 1 之下的选择)。为什么改:ADR-0131 D3 规定权限集只有一个家——注册表。鉴权解析器早已从注册表读定义,授权按名称写入,这些行已不再决定任何权限。卸载按名称撤销,是为了守住 ADR-0090 D5「不留幽灵授权」:否则授权会在卸载后残留,并在重新安装后重新生效。
风险与代价(含回滚):已有数据库保留旧行(直到 C7b),旧行路径的撤销照旧。删除了若干公开导出和
bootstrapPlatformAdmin的resync选项,changeset 已逐项列出;新增的卸载交接字段是可选的,不读它的清理步骤行为不变。本 PR 单独计 3,601 行(超过 3,000),因此为 Tier H。回滚:直接 revert,无数据迁移。席位意见:
你要做的:T1、T2、本 PR 依次合并;本 PR 因体量为 Tier H,需要你批准。
🤖 Generated with Claude Code
https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49