Repository navigation
refactor(objectql): move file-field hydration on read out of engine.ts into engine-file-reference-hydration.ts (#25522 cut 11) - #26351
Conversation
…s into engine-file-reference-hydration.ts Cut 11 of the engine.ts split. The five File-reference hydration bodies (resolveFileReferences, callerMayReadSysFile, serveRefusedFileHydration, servableFileRows, readParentDerivedFiles) move unedited into a new module, with the three module helpers only they use (isReadRefusal, toFileValue, PARENT_DERIVED_FILE_COLUMNS). The class keeps each method's name, modifiers, signature, docblock and position; each body becomes one FileReferenceHydrationHost literal plus a .call. engine.ts drops the isFileIdToken, FileRefusedValue and withoutOperationPrivateKeys imports, whose last readers moved. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011J7U85Djs3JuvHhG5gdcM9
…door pin callerMayReadSysFile's canReadObject call now lives in engine-file-reference-hydration.ts; the pin classifies callers by file. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011J7U85Djs3JuvHhG5gdcM9
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011J7U85Djs3JuvHhG5gdcM9
📓 Docs Drift CheckThis PR changes 1 package(s): 9 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 7 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 028eda1036a0b314d3ffb268ccbdc844e4f2777a && git checkout 028eda1036a0b314d3ffb268ccbdc844e4f2777a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 83e9d718718508cc27cc3e889ea594b2b0d1d221 4acced1d8d710799dfc9c6ba29d8cade2de54838 && git checkout -B drift-repro 83e9d718718508cc27cc3e889ea594b2b0d1d221 && git merge --no-ff 4acced1d8d710799dfc9c6ba29d8cade2de54838
node scripts/docs-audit/affected-docs.mjs --json 83e9d718718508cc27cc3e889ea594b2b0d1d221
|
席位核对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
Cut 11 of the
packages/objectql/src/engine.tssplit (#24586 ruling A, recorded in6270097840). The claim is6426204595. The whole "File-reference hydration" section moves unedited into a new module,packages/objectql/src/engine-file-reference-hydration.ts:resolveFileReferences(a read's file-field ids expanded to thesys_fileread form),callerMayReadSysFile(#24335, the admission asked before the caller's ownsys_fileread),serveRefusedFileHydration(the refused arm),servableFileRows(the one servability rule both arms use) andreadParentDerivedFiles(#22637, the field-owned verdict). The three module helpers only they use move with them:isReadRefusal,toFileValueandPARENT_DERIVED_FILE_COLUMNS. No behaviour changes. #25522 stays open for the later cuts.Branch
claude/project-thread-umvn9e(the card thread's harness-pinned branch), cut fromorigin/mainatbdfad1fc7, which is cut 10's merge (#26308). Nothing was edited before that merge landed.origin/main(a8e7393dd) was merged in once before this PR opened; none of the commits it brought touchpackages/objectql/**,packages/core/src/security/**,content/docs/permissions/**orscripts/adr-anchors/**.Why this area
Re-measured on
bdfad1fc7with cut 10's scripts, unchanged (both screens: erasure sites and module-helper closure).engine.tsis 22,942 lines, 7,374 of them from the last 30 days (git blame -s --since=2026-09-26T21:39Z).scripts/pm/git-history.mjs count: 129 commits in 30 days, 35 in 7.class ObjectQLholds 318 members, 255 methods and accessors. The file atbdfad1fc7is byte-identical to cut 10's head, where the table was first pre-measured while #26308 was in CI.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 full per-method screen is in the project file
pm-orders/server/25522-cut11-seam-table.md; the move script ispm-orders/server/evidence/25522/move-cut11.mjs.buildDriverOptions,driverReadScope,wallExemptedOperation,resolveEnginePosture;engineLayer0Verdictonly together withdriverWriteTarget(they shareaccessibleOrganizationsOf)The shape
private async), signature, docblock and position. Each body is now one host literal of exactly theFileReferenceHydrationHostmembers it reads, plus a.call, marked[#25522 cut 11], as cuts 8 and 10 did. Fields go as getters over areadXclosure (_registry,logger,_heldFileResolver,_fieldOwnedFileReadAuthorizer); methods go as late-bound closures (find,callerMayReadSysFile,serveRefusedFileHydration,servableFileRows,readParentDerivedFiles,resolveReadableIdsSecurity), so a spy or double set on the engine is still the one a call reaches.FileReferenceHydrationHosttypes each member as the class member (ObjectQL['find']and so on); each function'sthisis thePickof what it reads. The module imports the engine only as a type.isReadRefusal,toFileValueandPARENT_DERIVED_FILE_COLUMNSmove with their docblocks byte for byte and are not exported; every user of each was one of the five bodies. One copy, no re-derivation.FILE_REFERENCE_TYPES,isFileIdToken,RAW_FILE_VALUES_CONTEXT_KEYand the typeFileRefusedValue(@objectstack/spec/data),ExecutionContext(type),withoutOperationPrivateKeys(@objectstack/core, with its three-line import comment, which namesreadParentDerivedFiles) andisMissingTableError(@objectstack/metadata/errors): the bindingsengine.tsused.engine.tsdropsisFileIdToken,FileRefusedValueandwithoutOperationPrivateKeys(their last readers moved) and gains the module import with a two-line comment.FILE_REFERENCE_TYPES,RAW_FILE_VALUES_CONTEXT_KEYandisMissingTableErrorhave readers left inengine.tsand stay imported there.Net lines (the seat's rule)
engine.tsgoes from 22,942 to 22,651 lines, net -291 (44 added, 335 removed). The module is 451 lines. With the pin row below, the diff againstorigin/mainis 838 changed lines over 3 files (+503 / -335).The published
.d.tsdoes not change (ruling6348891160)Base:
@objectstack/objectqlbuilt withengine.tsrestored frombdfad1fc7(blob0603fb25checked) and the new module removed; restored withgit checkout HEAD --, both blob hashes compared,git diff HEADempty. Head: built at596517727.resolveFileReferences.call(hostoccurs 0 times in the basedist/index.mjsand once in the head's, so each leg built the source it names. All six declaration files are byte-identical, and equal to the hashes cuts 7 to 10 recorded:core.d.mtsef178bf0725eccc2f358f082ce13dc5122a6d5a53c19ef630017256f67de03b4core.d.ts1d20303a455a909e4b55fd0802fb0b0bcb59ec51784daf27d5ef4c0659410953index.d.mtsccf900240aa137abe72f82b8abfc872d42c5645467400134c580285f2a3b3090index.d.ts0454d5e70b156d8effbf27b8915587c7cbee241dcd7d698013c0a4c369a02aa5util-CVzOGxAn.d.mts85ef1cbec2b016d5f7afabaa21689c86c6dffc573076fdfdeb8ea0f1a1b1ad53util-CVzOGxAn.d.ts85ef1cbec2b016d5f7afabaa21689c86c6dffc573076fdfdeb8ea0f1a1b1ad53Positive control: dropping
privatefrom theservableFileRowsstub (anchor landed once; 0 private hits after, 1 public) and rebuilding changed all six hashes and the chunk name (util-CBKDhiuL.d.tsf9beab24567a…,index.d.ts2a876e08b028…), and the chunk now printsservableFileRows(objectName: string, rows: any[]): Promise of Map of string to any. Restored withgit checkout HEAD --(blob hash compared,git diff HEADempty, the private spelling back to 1 hit), rebuilt, and all six files compared equal to the head build again.Proof of move-only
A TypeScript-AST leaf-token compare (
pm-orders/server/evidence/25522/astcmp.mjs, unchanged from cuts 9 and 10) of baseengine.ts(bdfad1fc7) against the head module:async, and every body line equals the base line less two leading spaces, comments included:resolveFileReferences584 tokens / 150 lines,callerMayReadSysFile81 / 8,serveRefusedFileHydration239 / 30,servableFileRows190 / 49,readParentDerivedFiles427 / 51.engine.tsno longer declares them.@objectstack/spec/datavalue import, lessisFileIdToken; theFileRefusedValuetype import, dropped; the@objectstack/coreimport, lesswithoutOperationPrivateKeysand its comment.readStoredAutonumberCounter, which followed the helpers, keeps its own text and its one leading blank line. Head adds the new module import with its comment.Readers of the moved lines
packages/core/src/security/row-serving-door-exposure.pin.test.ts(core'srepovitest project, CI'sTest Core) classifies every file that calls.canReadObject(, andcallerMayReadSysFilemakes such a call. It gets anot-a-doorrow forengine-file-reference-hydration.ts, built from the method's own docblock: the ask only narrows what the caller's ownsys_fileread reads, and serves no row. Theengine.tsrow stays, since the ReadableIds composition still calls the admission there (2 sites). Control: without the row, the pin fails with exactly one unclassified file, the new module; with it, 6 of 6 files and 83 of 83 tests pass.repoproject (core,objectql,rest,runtime,spec,types) was run after the build: all green (6, 1, 5, 3, 79 and 1 files). No other census keys a moved body:second-object-read-exposure.pin.test.tskeys callers ofreferenceTargetOf, which none of the five call;operation-private-keys.pin.test.tskeys declarations of the helper, not its callers.readParentDerivedFileswritesisSystem: trueinto its sub-read's context; that is not a read site, so the page needs no row.check-system-context-censusat basea8e7393ddand at head: 153 read sites across 82 files, 145 of 145 symbols cited, OK at both ends.isFederatedObject,referenceTargetOfor the tenant-field readers).scripts/adr-anchors/entry describes a moved body (the engine entry's one paragraph is the transaction seam), so no entry follows. Two body comments cite a decision letter (ADR-0104 D3inreadParentDerivedFiles,ADR-0110 D3inresolveFileReferences'catch) and leave the anchoredengine.tswith their bodies, so the decision-letter count drops by two.check-adr-anchorsat basea8e7393dd(clean detached worktree): 90 anchored files, 1,880 decision-letter citations, 59,270 resolving citations; at head: 90, 1,878, 59,270. The method docblocks that cite ADR-0104 D3 stay on the class.objectql/src/engine.ts#NAMEpointer underpackages/spec/**,docs/adr/**,docs/qa/**orcontent/**names any of the five or the helpers. Prose that namesresolveFileReferences(driver-sql'ssql-driver.ts, the hydration tests,service-storage's agreement test,check-durability-degradation-log-level.mjsheader comments, CHANGELOGs) still resolves, because the method stays on the class. No gate baseline keys a moved body (durability-read-invention.baseline.jsondoes not; the moved bodies hold noquery-options/no-any-erasuresite, andquery-options-erasure-baseline.jsonkeepsengine.tsat 8).Acceptance notes
pr_create(29 open PRs): one opened after this cut started touchesengine.ts. feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337 (draft, ADR-0142 phase 2, opened 21:46Z) edits it in nine hunks: an import near line 241, three type and constant declarations, and theinsert/updatebodies (from base line 15727 on). None is in the moved section (base lines 13473 to 13916) or on the import lines this cut edits, andgit merge-tree --write-treeof this head with its head578e7a417merges cleanly (exit 0; its own generatedpackages/specfiles are regenerated by their merge driver, as on any merge). Under the card's rule 4 whichever lands second mergesmain. Otherwise feat(spec,cli)!: retire the ≤16.x retirement kits; the strict unknown-key refusal names the protocol upgrade guide #26138 editsvalidation/rule-validator.test.tsonly and chore: version packages #25640 the objectqlCHANGELOG.mdandpackage.jsononly; no open PR touches the row-serving pin,system-context.mdxorscripts/adr-anchors/.servableFileRowscallsthis._heldFileResolver(tombstoned). In the class the call's receiver was the engine; in the module it is the host, whose getter returns the same function. Both registrations (service-storage's plugin and the parent-derived test) pass arrow functions, andHeldFileResolverdeclares nothis, so nothing reads the receiver.readParentDerivedFilescopies its authorizer into a local before calling it, so that call has no receiver at either end.engineLayer0Verdictmoves only withdriverWriteTarget, soaccessibleOrganizationsOfstays module-local; 84 of 146 body lines are recent). Migration flags still needs a setter ruling.Verification
At
596517727(the cut and the pin row; the merge oforigin/mainafter it changes no file underpackages/objectql/**orpackages/core/**):pnpm --filter @objectstack/objectql typecheck(tsc --noEmit+check:test-typecheck): VERDICT command-exit 0.pnpm exec eslint --no-inline-config packages/objectql packages/core/src/security: exit 0.pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2: 472 files, 8,789 tests passed (VERDICT command-exit 0). The three hydration suites (engine-file-hydrate-outage,-parent-derived,-refused) are among them, 53 tests.vitest run --project repoin every package that has one, after the^...closure builds:core6/6 files (83 tests),objectql1/1,rest5/5,runtime3/3,spec79/79,types1/1, all VERDICT command-exit 0..d.tsfiles are byte-identical, so no dependant can see a difference. CI'sTypeScript Type Checkcovers them.At
4acced1d8(final head):dispatch-gates --commandsderived 62 families on the real diff. Every one was run, each exit code captured before any pipe, then reconciled with--ran: 62 accounted for, 61 run green, 1 NOT MEASURED (exit 3, PREREQUISITE NOT MET; CI runs it):check:dual-build-cjs-loads(needs every package'sdist/). Named readings:check-system-context-censusOK,check:durability-log-level(82 read seams, none invents an answer),check:query-options-erasure(none new),check:engine-double-contractOK,check:lean-entry-closure,check:type-check-debt(0 raw tsc errors above the ledger),check:logger-receiver-detach,check:org-identifier,check:nul-bytes,check-affected-docsexit 0.check-adr-anchorsat base and head (above),check-adr-symbol-anchors,check-tenant-audit-census,check-system-context-census,check-platform-checklist --changed-from origin/main(13 anchors judged, 0 lost) andcheck-commit-card-trailers --range origin/main..HEAD.Test Corefarm is CI's.skip-changeset: move-only. The published.d.tsfiles are byte-identical,liveness/and every other published path are untouched, and the module's runtime is the same code under a different file name. The pin edit is a test file.🤖 Generated with Claude Code
https://claude.ai/code/session_011J7U85Djs3JuvHhG5gdcM9
Generated by Claude Code