chore(sweep): retire ObjectLevelPermission and delete the console metadata duplicates (#4364, #4368) - #4410
Merged
Conversation
…adata duplicates (#4364, #4368) Post-retirement dead-surface pair, both premises re-measured at 456aac8. #4364 — `ObjectLevelPermission` is retired from `@object-ui/types` and the `@object-ui/permissions` re-export. Its only referents were its own definition and the two barrel lines; the wired home for object-scoped grants is `ObjectPermissionConfig.roles`, which declares its grant shape inline. The retirement note goes on that survivor, per the RoleDefinition convention from PR #4366. `PermissionCondition` is KEPT — the card's premise ("only referent is ObjectLevelPermission.conditions") does not hold: it types the parameter of `evaluateCondition` in packages/permissions/src/evaluator.ts, under a 26-case suite. Its doc comment now records why it survived a sweep aimed at it. `PermissionEffect` is untouched; FieldLevelPermission.effect still reads it. #4368 — the two console-local duplicates are deleted (410 lines, zero importers post-#4365). Both had drifted behind the live app-shell copies they duplicate: the console converter never read the server's `reference` key, and the console service predates the #4373 view cache-invalidation seam. The `@object-ui/plugin-designer` dependency is KEPT — it does not dangle; app-shell's DefaultAppContent, which the console renders, lazy-loads it for four live routes, so the console suite's vi.mock is load-bearing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
ACCEPT — PM 复核 (session
Flipping ready + arming auto-merge. Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #4364
Fixes #4368
Dead-surface deletions, post-retirement pair. Both cards record surfaces that lost their
last consumer when an earlier retirement landed, and both premises were re-measured at
this branch point (
456aac831) rather than taken from the cards. One of the two heldin full; one held in half, and the half that did not is reported rather than forced.
456aac831ObjectLevelPermissionPermissionConditionevaluateCondition, under a 26-case suitegit diff --statis 6 files: 2 deletions, 3 edited, 1 changeset. Nothing else.Member 1a — #4364:
ObjectLevelPermissionretiredRuling (PM seat, recorded on #4364, quoted verbatim):
Zero-consumer evidence —
git grep -n 'ObjectLevelPermission'over the whole tree at456aac831, excludingnode_modules, four hits:Nothing constructs one, nothing accepts one, nothing reads one — the only non-definition,
non-barrel hit is the prose in
RoleDefinition's #4288 note. The grants the evaluatoractually applies come from
ObjectPermissionConfig.roles, whose inner shape is declaredinline and never names this type.
Deleted: the interface, and its line from both barrels
(
packages/types/src/index.ts,packages/permissions/src/index.ts).Retirement record — following the
RoleDefinitionconvention PR #4366 established (adoc-comment note at the survivor site naming the retirement and its issue), the note goes
on
ObjectPermissionConfig, which is the survivor: it is the single wired home forobject-scoped grants.
RoleDefinition's existing #4288 note gains one sentence recordingthat the element type of its retired field has now gone the same way.
PermissionEffectstays, as the ruling requires — verified before touching the fileand after:
FieldLevelPermission.effectatpermissions.ts:71still reads it. It lostone referent (
ObjectLevelPermission.effect) and keeps the live one.Member 1b — #4364:
PermissionConditionkept, premise disprovenThe card states its case for this type transitively:
That is not true at this branch point, and it is not a drift — the referent predates the
card.
git grep -n 'PermissionCondition':evaluator.ts:115is an exported function that takes this shape and implements alleleven of the operators the type declares, including a prototype-pollution guard:
It is covered by 26 assertions in
packages/permissions/src/__tests__/evaluator.test.ts(lines 171-236) — one per operator, plus the three prototype-pollution cases. Deleting
ObjectLevelPermissionremoves theconditions?field atpermissions.ts:69; it doesnot leave
PermissionConditionunreferenced, becauseevaluateCondition's referentis independent of it. So this half of the ruling was declined rather than executed, and
the type's doc comment now records why it survived a sweep aimed at it.
The follow-on question this raises is real but is not ruled here, and is not mine to
guess:
evaluateConditionis itself exported fromevaluator.tsbut not from the@object-ui/permissionsbarrel (index.tsre-exports onlyevaluatePermissionfromthat module), and its only importer in the repo is its own test file. That is a
dead-surface shape one hop further out again — but retiring a function with real
behaviour, a security guard and a 26-case suite is a third judgement call that neither
the card nor the ruling names. Raised for triage on #4364 rather than acted on, which is
why this PR says
Part of #4364and notFixes.Member 2 — #4368: the two console-local duplicates deleted
Ruling (same claim comment, quoted verbatim):
Zero-importer evidence, the card's own re-check command, run at
456aac831(post-#4365):Two hits, both self-references in the deleted files' own docblocks. Zero importers, exactly
as the card predicted once PR #4365 removed
objectDetailWidgets.tsxandObjectFieldDesignerWidget.tsx.Copy divergence — measured first, and both copies had drifted
The card asks for the diff before the deletion, because which behaviour is the live one is
the fact that matters. Neither pair is byte-identical, and in both cases the live
app-shell copy is the one carrying the newer behaviour — the console copies are stale, not
merely redundant.
metadataConverters.ts(console 130 lines, app-shell 132) — the live copy reads onemore relational key:
The live copy resolves
referenceTofromfield.reference, which its comment identifiesas the key the server actually serves. The console copy would have returned
undefinedfor exactly that shape.
MetadataService.ts(console 280 lines, app-shell 313) — the live copy carries the#4373 view cache-invalidation seam; the console copy predates it entirely:
A
viewwrite through the console copy would have left the object page's override mapstale for the cache's 5-minute TTL — #4373's defect, on a writer nothing reaches. The live
copy also carries the doc block explaining why
deleteMetadataItemis deliberately notwired to that seam.
Both divergences are evidence for the deletion rather than against it: this is precisely
the imitation trap the card named — an author grepping for "the converter" or "the metadata
service" lands on a copy that no test covers and no user reaches, and drifts it further.
The app-shell copies and their suites (
MetadataService.saveAdvisories.test.ts,MetadataService.viewInvalidation.test.ts) are untouched.The
@object-ui/plugin-designerdependency — measured, and it does not dangleThe card's third item reads:
The textual observation is right and the conclusion does not follow. The dependency is
kept, and the
vi.mockwith it, because the measurement says the console's runtimeimport graph still reaches the package — through its shell, not through its own sources.
apps/console/src/AppContent.tsxis a thin wrapper that rendersDefaultAppContentfrom@object-ui/app-shell. That module ispackages/app-shell/src/console/AppContent.tsx,and it lazy-loads plugin-designer for three route elements that are live in the console:
So the
vi.mock('@object-ui/plugin-designer', …)in the console's own suite isload-bearing, not a leftover of the deleted
FieldDesigner: it stubs a module therendered tree lazily reaches, which is the flaky-import hazard AGENTS.md warns about.
The vite alias at
apps/console/vite.config.ts:152exists for the same reason — it iswhat makes that lazy import resolve to source in the console dev server. Removing the
declaration would have removed a package the console genuinely serves at runtime.
node scripts/check-phantom-dependencies.mjs(the gate PR #4407 landed) is green on thisbranch, and confirms the direction it checks: every import is declared by the package that
publishes it.
Residual sweeps after deletion
Each retired symbol swept individually across the whole tree, not only
.ts/.tsx:ObjectLevelPermissionpackages/types/src/permissions.tsdoc commentsutils/metadataConverterspackages/app-shell/src/utils/metadataConverters.tsdocblockservices/MetadataServiceuseMetadataServiceimportmetadataConverters|MetadataServiceunderapps/consolePermissionConditionconditions?field's removalVerification
CI on this branch has converged green as well — all 20 checks completed with no failure,
including Type Check, Lint (where this repo's family gates run), and all four
Test shards.
The repo-root vitest form is the one AGENTS.md mandates; the heavy phases ran under the
shared verification lock. The type gate is run repo-wide rather than scoped on
purpose: two packages' export surfaces narrow here, so the no-downstream-red proof is
load-bearing and a scoped run could not carry it — 78 of 78 packages type-check clean with
ObjectLevelPermissiongone from both barrels.Reverse verification is the retirement pattern's form — zero-consumer evidence plus a
green ladder after deletion (per #4365) — with the direction predicted before running
it: re-adding
ObjectLevelPermissionto a barrel while the interface stays deleted mustturn the type gate red, because a barrel cannot re-export a name that does not exist.
tsc --noEmitinpackages/typesObjectLevelPermission,restored tosrc/index.tssrc/index.ts(551,3): error TS2724: '"./permissions"' has no exported member named 'ObjectLevelPermission'. Did you mean 'RowLevelPermission'?git checkout -- packages/types/src/index.tsOne honest correction to the prediction: the expected code was
TS2305(the plainno-exported-member error); the compiler emitted
TS2724, its "did you mean" variant,because
RowLevelPermissionis a near-miss neighbour in the same export block. Samefailure, more specific code. The fix was taken out with
git checkout, nevergit stash—that stack is shared across every worktree of the repo.
No pin tests are added. For member 1a there is nothing left to pin — the type is gone from
both barrels, and a re-introduction is a type error rather than a silent regression. For
member 2 the deleted files had no test file at all (that absence is the card's point), and
the behaviour they duplicated is already pinned on the live app-shell copies.
Changeset
.changeset/dead-surface-pair-4364-4368.md—@object-ui/typesminor,@object-ui/permissionsminor,@object-ui/consolepatch. Both barrels narrow, soboth released packages are graded as export narrowings;
minorrather thanmajorperAGENTS.md, which reserves objectui's major for tracking
@objectstackand requiresobjectui's own breaking changes to be
minorwith the breaking semantics spelled out inthe body.
@object-ui/consoletakespatchfor the two file deletions, following the#4365 precedent for console-only deletions. The changeset body also records the
PermissionConditionandPermissionEffectretentions so a reader of the release notesdoes not infer the whole permission-condition surface went.
Note for triage
This PR opens with
Part of #4364, notFixes— the ruling names two types and one ofthem is measured live, so merging this does not close that card. #4368 is delivered in
full and carries
Fixes. The open question for #4364 is whetherevaluateCondition(zero production callers, not barrel-exported, 26-case suite) should itself be retired,
which is what would free
PermissionCondition; that is recorded on the card rather thanfiled as a separate issue, since it sits inside #4364's own completion scope.
Generated by Claude Code