Repository navigation
refactor(objectql): move the ReadableIds composition and permission resolution bodies out of engine.ts (#25522 cut 15) - #26645
Conversation
…esolution bodies out of engine.ts Eight bodies of the "Readable-ids security and permission/formula resolution" section move unedited into engine-readable-ids-permission-formula.ts behind ReadableIdsPermissionFormulaHost; the class keeps every method, signature and docblock. READABLE_IDS_MAX_CHAIN_DEPTH moves with its one reader; writeFailureLogMeta, isExpressionDefault and four shared types gain export in place and are imported back. core's row-serving census row for the ReadableIds admission ask moves with its call. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nM7fbhbE84nNy6VkE
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nM7fbhbE84nNy6VkE
📓 Docs Drift CheckThis PR changes 1 package(s): 14 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 11 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 19 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 5c37956545ca84214e45cd00fb3a8bdfebb3c158 && git checkout 5c37956545ca84214e45cd00fb3a8bdfebb3c158
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 03e898c1d3e24575310f1d4abd3798696bfe0cc0 4d72947a56925b533ac8ad37659bcf47c615ea75 && git checkout -B drift-repro 03e898c1d3e24575310f1d4abd3798696bfe0cc0 && git merge --no-ff 4d72947a56925b533ac8ad37659bcf47c615ea75
node scripts/docs-audit/affected-docs.mjs --json 03e898c1d3e24575310f1d4abd3798696bfe0cc0
|
席位核对ACCEPT · The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.
Generated by Claude Code |
Requested by Leehom · project thread
Part of #25522
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160
维护者速读
engine.ts里「ReadableIds 安全与权限/公式解析」一段的 8 个方法体(ReadableIds 读取范围链的组合、启动时 controlled_by_parent 主表的检查、单个父对象读取范围的询问、一次操作共享的权限解析及其三个使用方、公式故障的一次性告警)原样搬进新文件engine-readable-ids-permission-formula.ts,类上的方法签名与注释不变,只把方法体换成转交;只被这些方法体用到的常量READABLE_IDS_MAX_CHAIN_DEPTH随之搬走,与留下的代码共用的 2 个工具函数和 4 个类型原地加export、由新文件导入(不复制)。engine.ts22,092 → 21,947 行。src/engine.ts(23,903 lines, +7,501 in 30 days) along itsObjectQLseams, one move-only slice per PR #25522 按缝拆分engine.ts的第 15 刀(18.2.0 发布后重启)。缝表重测后,validate(约 −439)仍受.d.ts重排的裁决所限;第二名「包、应用、插件与驱动注册」(约 −233)与在途的 feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337 重叠(同一个METADATA_ARRAY_KEYS及其门禁),所以取不重叠的第三名。.d.ts六个文件逐字节不变(含正控);新文件与engine.ts互相导入(运行期循环),已用一次性探针在新旧两版构建产物上逐行对照(78 行完全一致)。回滚 = revert 本 PR。packages/objectql/src/engine-readable-ids-permission-formula.ts(搬入的方法体与ReadableIdsPermissionFormulaHost)、packages/objectql/src/engine.ts里composeReadableIdsChain的转交桩(泛型、递归经实例方法回入)与原地export、packages/core/src/security/row-serving-door-exposure.pin.test.ts(一行改键)。pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2,应见全部测试文件通过。Cut 15 of the
packages/objectql/src/engine.tssplit (#24586 ruling A, recorded in6270097840), the first after the release pause (6434935278; restart record6439182543,@objectstack/spec@18.2.0). The claim is6439254992. Eight bodies of the "Readable-ids security and permission/formula resolution" section move unedited into a new module,packages/objectql/src/engine-readable-ids-permission-formula.ts:composeReadableIdsChain(the chain of composedReadableIdsread scopes),findUnservableControlledByParentMasters(the boot screen overcontrolled_by_parentdetails),readableIdsScopeOf(the scope one leaf is composed with),resolveOptionPermissions,permissionResolution,resolveFormulaPermissionsandresolveDefaultPermissions(an operation's one effective-permission resolution and its three consumers), andreportFormulaFault. No behaviour changes. #25522 stays open for the later cuts.Branch
claude/project-thread-firh6t(the card thread's harness-pinned branch), cut fromorigin/mainatf9867020c, which contains cut 14's merge (00874b9e09, #26489) and the 18.2.0 release.What changes
Why this area
Re-measured on
f9867020cwith cut 11's measure script and cut 14's price step (price3.mjs), both unchanged: a helper a paying body shares with a staying body is exported in place and blocks nothing; one read only by moving bodies moves with them. Both earlier screens still apply (query-options erasure sites, 8 at base, none in this section; module-helper closure).engine.tsis 22,092 lines, 7,009 of them from the last 30 days (git blame --since=2026-09-27T10:15Z, clone deepened to 2026-09-22 first).scripts/pm/git-history.mjs count: 130 commits in 30 days, 35 in 7.class ObjectQLholds 318 members, 255 methods and accessors. Since cut 14, one commit touched the file (#26551, +7 lines in "Action registry and activation"); the release added no new section.Seam table on
f9867020c(41 sections ofclass ObjectQL; U = untyped receivers)txStore…constructorgetStatus…registryregisterHook…triggerHookshasHooksFor…assertBulkPerRowHookBudgetregisterAction…setActionActive_heldFileResolver…registerInsertRecomputeListenerreadableIdsSecurityReported…resolveDefaultPermissionswriteEpoch…hasObjectMiddlewareexecuteWithMiddleware…buildUserbuildDriverOptions…resolveEnginePostureprobeInstallOrganizations…transactionCoversDriverForresolveNowDefault…defaultFieldEntriesapplyAutonumbers…seedAutonumberregistrationConversionWarned…registerDriversupplyFileColumnsMovedResolver…listUnavailableDatasourcesassertWriteAllowed…publishBulkDataEventsetI18nService…objectDisplayLabelassertReferencesResolve…masterDeclaredFieldsinspectDanglingReferences…inspectCascadeDeletesetCryptoProvider…setTenancyPostureProviderencryptSecretFields…resolveInternalFieldgetSchema…judgeFilterLIFECYCLE_DATASOURCE…setDatasourceMappinginit…resolvePrimaryDatasourceobjectHasMediaField…valueShapeStrictForisFileReferencesMigrationVerified…wasDatastoreCreatedFromEmptydestroy…destroyMAX_EXPAND_DEPTH…MAX_BULK_PER_ROW_HOOK_ROWSautonumberCounters…recomputeSummariesexpandRelatedRecords…expandRelatedRecordsresolveFileReferences…readParentDerivedFilesresolveWhereTokens…requireFindOnePredicatefind…staticReadonlyCreateStripvalidate…validatereadUpdatePriorRow…insertManyupdate…updateplanCascadeAtomicity…organizationOwnedRowCountsdelete…deletecount…aggregateexecute…enforceTransactionOriginregisterObject…createThe per-member screen (movable bodies, what stays and why) and the full price output are in the project files,
pm-orders/server/25522-cut15-seam-table.md..d.tsreorder ruling (exportinginsertStaticReadonlySubject), unchanged since cut 14METADATA_ARRAY_KEYS(read only byregisterMetadataCollections, so it would move) and its gate row inscripts/check-stack-collection-maps.mjsresolveFormulaRelated(below)Why
resolveFormulaRelatedstays. Its return typeFormulaRelatedis a non-exported type that top-level helpers that stay also use (formulaHopScope,applyFormulaPlan,hydrateWriteFormulasandStoredExpressionServing), so moving the body means exporting it in place. Measured by exporting each shared declaration on its own on the base and building (dts-export-variant-cut15.sh):writeFailureLogMeta,isExpressionDefault,PermissionResolution,FormulaPlanEntry,ReadableIdsSecurityandReadableIdsChaineach leave all six declaration files byte-identical;FormulaRelated, which namesRelatedRecordBindingfromvalidation/rule-validator, makes the declaration bundler pull the validator declarations in earlier: the same declarations in another order, with the chunk renamed (util-DOIDsRyctoutil-BWosSWLp). That is the same mechanism that keepsvalidateout, and the claim's byte-identical bar forbids it, soresolveFormulaRelatedstays (39 body lines, about -30 of the priced -156). A first full move that included it is how this was found: its build reordered the chunk, and the variant measurement named the one export responsible.The shape
ReadableIdsPermissionFormulaHostmembers they read, plus a.call, marked[#25522 cut 15], as cuts 8 and 10 to 14 did. Fields go as getters over areadXclosure (_registry,logger,_effectiveObjectPermissionsResolver,formulaFaultReported); methods go as late-bound closures (refuseUncomposableReadableIdsClasses,readableIdsScopeOf,composeReadableIdsChain,uncomposableReadableIdsParent,buildEvalUser,defaultFieldEntries), so a spy or double set on the engine is still the one a call reaches. No moved body assigns a field, so there is no setter (cut 13's setter ruling has nothing to apply to).composeReadableIdsChainis generic and recursive: its stub calls the function instantiated with its type parameterNand.calls it on the host, the spelling [maintainer] refactor(metadata-protocol): splitsrc/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467's generic cuts used, and the host'scomposeReadableIdsChainclosure re-enters through the method, so the recursion still passes the instance (the probe counts both levels).resolveOptionPermissionsreads no member of the class, so its method calls the function directly (return resolveOptionPermissions(schema, payloads, resolution);).READABLE_IDS_MAX_CHAIN_DEPTHis read only bycomposeReadableIdsChain, so it moved with it, docblock included and byte for byte.writeFailureLogMeta(read too byreportFindFailure,insert,update,delete) andisExpressionDefault(applyFieldDefaults) stay where they were, byte for byte, and gainexportin place; so do the types the moved bodies share with staying code:PermissionResolution,FormulaPlanEntry,ReadableIdsSecurityandReadableIdsChain(eachexportalone was measured.d.ts-neutral, above).UnservableControlledByParentMasterwas already exported. The module imports the two functions as values and the five types as types from./engine.js; it is a new module, so before that it imported nothing from./engine.js.index.tsandcore.tsname their exports singly, so nothing new is published (below).engine.tsand the module import each other. The module runs nothing at evaluation (declarations only), andengine.tsimports it right after./engine-master-detail-related.js, after every module the moved bodies import, so the evaluation order of every other module is unchanged. Measured on the built bundles (index.mjs,core.mjs,index.js,core.js): with the// src/engine.tsregion markers set aside, the// src/...region order at head equals the base's with one line added, the new module, betweenengine-master-detail-relatedandin-memory-aggregation. Oneengine.tsregion disappears: the one that held only the external@objectstack/spec/dataimport ofReadableIds,RLS_DENY_FILTER,markFilterSubtreeProvenanceandisControlledByParentMasterField, whose readers all moved; that import now sits in the module's region (an external package already loaded by earlier regions; ESM imports are hoisted). The bundles hold both files in one module, so the published build has no cycle. The late-binding probe answers the same on base and head (Tests).ReadableIds,RLS_DENY_FILTER,isControlledByParentMasterField,markFilterSubtreeProvenance,FilterCondition(type),ExecutionContext(type),toEvalPermissions,EvalErrorandEvalPermissions(types),collectComposableReadableIds,composeReadableIdsLeaves,describeReadableIdsLeaf,readableIdsRefusalError,ComposableReadableIdsSite(type),optionVisibilityReadsPermissionsandreadsPermissionPredicate.engine.tsdropscomposeReadableIdsLeaves, the wholeReadableIds/RLS_DENY_FILTER/markFilterSubtreeProvenance/isControlledByParentMasterFieldimport line, andtoEvalPermissions, whose last readers moved. It keepsoptionVisibilityReadsPermissionsandreadsPermissionPredicate: no code inengine.tsreads them any more, but the docblocks that stay onresolveOptionPermissionsandresolveFormulaPermissions{@link}them, the same useDatasourceUnavailableErroralready has there at base (TypeScript counts a{@link}as a use undernoUnusedLocals), and that import line stays byte-identical.Net lines (the seat's rule)
engine.tsgoes from 22,092 to 21,947 lines, net -145 (59 added, 204 removed). The module is 362 lines. With the one path reader below, the diff againstorigin/mainis 628 changed lines over 3 files (+423 / -205).Readers of the moved lines
packages/core/src/security/row-serving-door-exposure.pin.test.tslists every non-test file that calls a security service'scanReadObject(.engine.ts's only call was inreadableIdsScopeOf, so its row moves to the new module, with itsnot-a-doorclassification and reason unchanged (the reason already described exactly this ask: "the ReadableIds composition (ADR-0139 D2) …"). Without the re-key the census would readengine.tsas stale and the module as unclassified.engine.tspath:objectql/src/engine.ts#NAMEpointers underpackages/spec/**,docs/**,content/**andscripts/**name none of them;content/docs/permissions/system-context.mdxand itsNON_READ_ANCHORShave no row for them (no moved body readsisSystem);federated-injected-column-readers.test.tskeys none of them (itsresolveFormulaRelatedrow stays with that body inengine.ts); no moved body callsreferenceTargetOf((core'ssecond-object-read-exposure.pin.test.tsis unchanged); no moved body holds aquery-options/no-any-erasuresite (8 at base and head), a tenant-audit untyped receiver or a private static read. Mentions by bare name (plugin-security'sREADABLE_IDS_MAX_CHAIN_DEPTHcomments,plugin.ts'sObjectQL#findUnservableControlledByParentMasters) name the constant and the method, which still exist under those names.engine.tsentry is the transaction-seam paragraph), so the module needs no anchor entry of its own.src/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467).check-durability-degradation-log-level --listat base and head is identical once line numbers are masked: 48 durability seams and 82 read seams, the same entries. No moved body is named in a read-seam entry.check-adr-anchorsat basef9867020c(clean detached worktree): 91 anchored files, 1,881 decision-letter citations on the anchored surface, 59,819 resolving citations across 8,353 files. At head: 91 anchored files, 1,880, 59,820 across 8,354. The one letter that leaves the anchored surface is[ADR-0139 D6, as amended — the nested master chain]inREADABLE_IDS_MAX_CHAIN_DEPTH's docblock, which moved with the constant into the module, which no anchor entry names; the citation still resolves (it is in the 59,820), it is just no longer counted on the anchored surface. The +1 resolving citation and +1 file are the new module (its header names ADR-0139 once). The same one-letter move was disclosed on cuts 8 and 12 of [maintainer] refactor(metadata-protocol): splitsrc/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467; anchoring the module to keep the count would mean writing a new invariant paragraph, which is not a move.Why
#25522 splits
engine.tsone seam at a time so that a change to one area reads, reviews and conflicts as that area alone. This cut takes the section that pays most under this cut's rulings and that no open PR touches (table above). Nothing about what the engine does changes.Tests
No test is added or changed apart from the re-keyed row above: the move is proved by identity, not by new behaviour.
Public
.d.tsbyte-identical, with a positive controlBuilt
@objectstack/objectqlat the base (f9867020c,engine.tsblob9c44e9da88b5) and at head (engine.tsblob19a84bece0b0), each from a clean tree (dts-cut15.sh), and hashed every declaration file. All six are byte-identical:core.d.mtse2913d082b71f3342f9013f7e75afad720488366f922beef28bbeee67a8cc81bcore.d.ts79919dabaf5a0bf7a81be2c09eee1535b789699f8e6363064e40fa8007f26c14index.d.mtse6368a2e3c25d19f03cfbc471fbdd763daf9ca19de8cf5ce22f4493c8eca5f28index.d.ts74cb25f41cf0aa8d94e495967ed228dcaaeeba8ba8fa8c54fab10eb01ddc1b51util-DOIDsRyc.d.mts791b203b5e36d557cd0d59f15c317b9d85ef644e5ed730b5f3a6aa801fd37adfutil-DOIDsRyc.d.ts791b203b5e36d557cd0d59f15c317b9d85ef644e5ed730b5f3a6aa801fd37adfThe builds are the moved code, not a stale cache:
composeReadableIdsChain.call(hostoccurs 0 times in the basedist/index.mjsand once in the head's.Positive control.
scripts/ablation-replace.mjsdroppedprivatefromprivate async readableIdsScopeOf(on the head (anchor count 1 to 0;engine.tsblob19a84bece0b0toc8dcf0a369f7) and rebuilt: every declaration hash changed (core.d.mts7f089f7719d3…,core.d.tsef7645cf34d2…,index.d.mts6927c24b7c73…,index.d.ts3d457f36059b…) and the chunk was renamedutil-BFa4erHR.d.ts, which now publishesreadableIdsScopeOf(object: string, operation: string, parent: string, svc: ReadableIdsSecurity, …)(line 5646). So the comparison sees a one-word change to a moved member's signature. The restore leg put the blob back to19a84bece0b0(git diff HEADempty), and the head was rebuilt before every later step.AST compare (move-only)
astcmp.mjs(TypeScript compiler API, comments and whitespace ignored, tokens compared) on baseengine.tsagainst headengine.tsplus the module:async, body tokens, and every body line equal after one level of indent):composeReadableIdsChain380 tokens / 46 lines,findUnservableControlledByParentMasters201 / 12,readableIdsScopeOf253 / 29,resolveOptionPermissions149 / 19,permissionResolution80 / 11,resolveFormulaPermissions178 / 25,reportFormulaFault101 / 14,resolveDefaultPermissions223 / 21.class ObjectQL: 318 of 318 members kept, in the same order; 310 byte-identical, and the 8 stubs keep docblock, modifiers and signature identical.exportcmp.mjs): the 3 import edits above; 6 declarations that gainedexportand are otherwise byte-identical with their leading docblocks (writeFailureLogMeta,isExpressionDefault,PermissionResolution,FormulaPlanEntry,ReadableIdsSecurity,ReadableIdsChain);READABLE_IDS_MAX_CHAIN_DEPTH, byte-identical in the module (1,137 characters with its docblock); and the class. The head adds one statement, the module import.Late-binding probe (base and head
dist)zz-probe-cut15.mjs(a one-off, not committed) loads the builtObjectQLand drives all eight methods with doubles set on the instance for every member the hosts read (_registry,logger,_effectiveObjectPermissionsResolver,formulaFaultReported,refuseUncomposableReadableIdsClasses,readableIdsScopeOf,composeReadableIdsChain,uncomposableReadableIdsParent,buildEvalUser,defaultFieldEntries, plushasObjectMiddlewareandresolveDatasourceBindingunder them), then prints results, the call order on the doubles and the log lines. Cases: theReadableIdschain throughcomposeReadableIdsAtBoundary(a nested two-level chain, which re-enterscomposeReadableIdsChainthrough the instance; a cycle, refused; a denied parent; no restriction;getReadFilterthrowing; the admission throwing; theexplainfallback; the deny sentinel; a non-filter answer; areadableIdsScopeOfdouble replaced after construction);findUnservableControlledByParentMastersover both D5 classes;permissionResolutionwith no user, with a user (asked once for twoget()s) and with no resolver;resolveOptionPermissions,resolveFormulaPermissionsandresolveDefaultPermissionswith no resolution, a resolution and a throwing one;reportFormulaFaulttwice on one pair (one line), and with aformulaFaultReporteddouble set after construction. The 78 output lines are identical on base and head (the engine's own construction log lines, which carry timestamps, set aside), which is the check the seat's ruling asks for on the run-time cycle. The module-order measurement on the bundles is under "The run-time cycle" above.Suites
Under
scripts/pm/os-verify-lock.shon head4d72947a5(after mergingmain):@objectstack/objectql,@objectstack/rest,@objectstack/runtime,@objectstack/client,@objectstack/client-reactand@objectstack/corewith their dependencies: exit 0.typecheckof@objectstack/objectqland@objectstack/core: exit 0 each.@objectstack/objectqlvitest--project local: 472 files, 8,795 tests passed, exit 0.packages/*/vitest.repo-tests.jsonproject: core 6 files / 83 tests (it holds the re-keyed census), objectql 1 / 5, rest 5 / 280 passed and 18 skipped, runtime 3 / 947, spec 80 / 1,293, types 1 / 11. Exit 0 each..d.tspair and the late-binding probe were run on both bases:f9867020cbefore the merge andce9bc104eafter it, with the same six hashes and the same 78 probe lines both times (engine.tsis the same blob at both bases).Verification
Head
4d72947a56925b533ac8ad37659bcf47c615ea75. The gate list isnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon this diff at that head (56 commands, merge basece9bc104e, no STALE warning), each run with its exit code captured before any pipe, then reconciled with--ran.--ranreconciliation:56 derived famil(ies) accounted for — 56 run, 0 NOT-MEASURED.check:dual-build-cjs-loadsrefused on its first pass (exit 3, a package'sdist/not yet built) and was re-run once the build closure was complete: 112 entry points across 69 packages load, exit 0.check-engine-split-ratioandcheck-plugin-teardown-shaperan aftergit fetch --shallow-since=2026-07-22 origin mainandgit fetch origin 621a487607881c66b2899b7e3477115229a156b4.node scripts/check-adr-anchors.mjs(counts above),node scripts/check-tenant-audit-census.mjs,node scripts/check-adr-symbol-anchors.mjs,node scripts/check-platform-checklist.mjs --changed-from origin/main,node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD,node scripts/check-durability-degradation-log-level.mjs --list, and eslint aspnpm lintruns it (--no-inline-config) onpackages/objectqlandpackages/core.Acceptance notes
6439254992named this branch. The branch is cut fromf9867020c, which holds cut 14's merge (00874b9e09) and the 18.2.0 release;main(ce9bc104e) was merged in once before opening (clean; no merged commit touchesengine.ts, which is the same blob at both bases).packages/objectql/**or the re-keyed core pin, listed at start and again just before opening this: feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337 (engine.tsand other objectql files), feat(spec)!: retirement kits whose conversion retired at or below 16.x age out; the strict unknown-key refusal names the protocol upgrade guide #26599 (validation/rule-validator.test.tsonly) and chore: version packages #26517 (the release PR:CHANGELOG.md,package.json). feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337 editsengine.tsin the imports,OperationContext,METADATA_ARRAY_KEYS, afterSECURITY_SERVICE_SOURCE_SLOT, and inreadUpdatePriorRow/insert/update; none of those is moved here, and it does not touch the core pin.git merge-treeof this head with feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337's current head (cbd27d9a6c) exits 0, no conflict. Whichever lands second mergesmain.resolveFormulaRelatedstays, measured. Moving it needsFormulaRelatedexported, and that export alone reorders the published declaration chunk (Why this area). It is the same question the restart carries forvalidate(may a move-only cut reorder declarations inside a published.d.tschunk when the declared surface is unchanged?), so a ruling on that question would free both:validate(-439) andresolveFormulaRelated(about -30).METADATA_ARRAY_KEYSand itscheck-stack-collection-maps.mjsrow; that row'sfile:and the constant would move withregisterMetadataCollections._registry,logger,_effectiveObjectPermissionsResolverandformulaFaultReportedas getters, so each body reads whatever the instance holds when it reads it: the probe replacesformulaFaultReportedandreadableIdsScopeOfon the instance after construction and sees the moved bodies use the replacements. No body assigns a field, so there is no setter.engine.ts(composeReadableIdsAtBoundary's andcomposeReadableIdsChain's) still say{@link READABLE_IDS_MAX_CHAIN_DEPTH}, which now lives in the module, andoptionVisibilityReadsPermissions/readsPermissionPredicatestay imported inengine.tsfor the{@link}s onresolveOptionPermissionsandresolveFormulaPermissions(above). Editing a staying docblock would break its byte identity, so these are noted here rather than touched, as cut 14 notedstaticReadonlyStripTakes.[ADR-0139 D6 …]citation moved with its constant off the anchored surface; nothing was rewritten or dropped.Human Minimum
packages/specholds no runtime logic. (Not touched.)ReadableIdsPermissionFormulaHost,engine-readable-ids-permission-formula.ts).pnpm lintpasses on the touched packages.main, one pull request.skip-changeset; both declaration lines are filled in above.packages/specnot touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.skip-changeset: move-only inside@objectstack/objectql, with the published declarations byte-identical and no behaviour change, so there is nothing for a release note to say.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5nM7fbhbE84nNy6VkE