Repository navigation
Commit cea0871
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X5TDYgc33GQV9hiYvxWt8f8)_
Part of #25522
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160 + 6441032442
## 维护者速读
- **改了什么**:把 `engine.ts` 里包注册区的三个方法体(`convertPackageBodyForward`
注册门的协议前向转换、`registerPlugin` 嵌套插件注册、`resolveNavObjectNames`
导航对象名解析)原样搬进新文件
`engine-package-registration.ts`;类上的方法签名、注释、位置不变,方法体换成转交。两者与留下的
`registerApp` 共用的 `stampPackage` / `stampObjectPackage` 原地加
`export`、由新文件导入(不复制)。`engine.ts` 21,733 → 21,661 行。
- **为什么改**:#25522 按缝拆分 `engine.ts` 的第 17 刀。本区原定价 −233,但 #26337 落地时在
`packages/spec/liveness/` 里把 `engine.ts#registerMetadataCollections`
登记为生产者(18 处),它按系列规则留在原文件;剩下可搬的三个方法重定价 −75,仍高于 −30,按派单取本区。
- **风险与回滚**:纯搬移,无行为变化;公开 `.d.ts`
六个文件与基线逐字节相同(含正控);运行期导出名单相同;构建产物里只多出新文件一个区段,外部包的导入顺序一条不差(新文件在
`engine.ts` 原先导入 `@objectstack/metadata-core`
的位置导入);一次性晚绑定探针在新旧两版构建产物上逐行一致。回滚 = revert 本 PR。
- **先看**:`packages/objectql/src/engine-package-registration.ts`(三个函数与
`PackageRegistrationHost`)、`packages/objectql/src/engine.ts`
里三个转交桩、新的导入行与两处原地 `export`。
- **两分钟验证**:`pnpm --filter @objectstack/objectql exec vitest run
--project local --maxWorkers=2
src/engine-nested-plugin-collections.test.ts
src/registry-installed-package-retired-page-declarations.test.ts`,应见两个文件全部通过(嵌套插件注册与注册门前向转换各自的测试)。
- **需要你做的**:无,席位落地。
Cut 17 of the `packages/objectql/src/engine.ts` split (#24586 ruling A,
recorded in `6270097840`), under the claim `6450667239`. Three bodies of
the "Package, app, plugin and driver registration" section move unedited
into a new module,
`packages/objectql/src/engine-package-registration.ts`, behind
`PackageRegistrationHost`: `convertPackageBodyForward` (ADR-0087 D2's
forward conversion at the package registration door), `registerPlugin`
(a nested plugin's objects, plugin-as-app and stack collections,
registered under its parent package) and `resolveNavObjectNames` (the
navigation `objectName` resolution). No behaviour changes. Every
published declaration file is byte-identical to the base. #25522 stays
open for the later cuts.
Branch `claude/project-thread-y39a3j` (the card thread's harness-pinned
branch), cut from `origin/main` at `e1bfde3601`, which contains cut 16's
merge (`d8b943b620`, #26792) and #26337.
## What changes
### Why this area, and why it now pays -75 and not -233
Re-measured on `e1bfde3601` with cut 11's measure script and cut 14's
price step (`price3.mjs`), both unchanged. `engine.ts` is 21,733 lines,
6,745 of them from the last 30 days (`git blame
--since=2026-09-27T18:45Z`, clone deepened to 2026-09-21 first); `class
ObjectQL` holds 324 members, 259 methods and accessors. Query-options
erasure sites: 8 at base (lines 8372, 9690, 9936, 10000, 10332, 13612,
13911, 18522), none in this area.
Cut 16's table priced the section at -233 with four bodies,
`registerMetadataCollections` (166 body lines) the largest. #26337, the
PR that held the section out, landed with 18 producer pointers
`packages/objectql/src/engine.ts#registerMetadataCollections` in
`packages/spec/liveness/queue.json` (6) and `assignment_rule.json` (12).
A body named by an `engine.ts#NAME` pointer under `packages/spec` stays
in this series, and the claim forbids `packages/spec/**` edits, so
`registerMetadataCollections` stays, and with it `METADATA_ARRAY_KEYS`,
`resolveMetadataItemName` and `permissionSetOwnerRegistrationRefusal`
(its helpers) and the `check-stack-collection-maps.mjs` row that names
`METADATA_ARRAY_KEYS` in `engine.ts`. `registerApp` and `registerDriver`
stay as the order says (public, inferred return type). The other three
re-price at **-75**. That still pays more than -30, so under the order
this cut takes the section rather than the fallback (Delete cascade and
reference walking, -124). It is also the colder of the two: 36 of 98
body lines from the last 30 days, against 128 of 167.
<details><summary>Seam table on <code>e1bfde3601</code> (43 sections of
<code>class ObjectQL</code>; U = untyped receivers)</summary>
| range | section | first … last member | lines | 30-day lines | methods
| inferred public | U | private statics |
|---|---|---|---|---|---|---|---|---|
| range | section | first … last member | lines | 30-day lines | methods
| inferred public | U | private statics |
|---|---|---|---|---|---|---|---|---|
| 4706-4937 | Instance state and constructor | `txStore` … `constructor`
| 232 | 56 | 0 (0 public) | - | 0 | - |
| 4938-4960 | Status and registry accessor | `getStatus` … `registry` |
23 | 0 | 2 (2 public) | getStatus | 0 | - |
| 4961-5304 | Hook and function registry | `registerHook` …
`triggerHooks` | 344 | 6 | 16 (16 public) | registerHook, triggerHooks |
1 | - |
| 5305-5660 | Hook dispatch internals | `hasHooksFor` …
`assertBulkPerRowHookBudget` | 356 | 61 | 7 (0 public) | - | 0 | - |
| 5661-5823 | Action registry and activation | `registerAction` …
`setActionActive` | 163 | 24 | 10 (10 public) | - | 1 | - |
| 5824-6105 | Registered resolvers and write-gate probes |
`_heldFileResolver` … `registerInsertRecomputeListener` | 282 | 116 | 6
(6 public) | - | 0 | - |
| 6106-6747 | Readable-ids security and permission/formula resolution |
`readableIdsSecurityReported` … `resolveDefaultPermissions` | 642 | 509
| 16 (2 public) | - | 0 | - |
| 6748-6854 | Authz invalidation and middleware registration |
`writeEpoch` … `hasObjectMiddleware` | 107 | 18 | 4 (4 public) | - | 0 |
- |
| 6855-7032 | Execution plumbing (middleware, session, provenance,
users) | `executeWithMiddleware` … `buildUser` | 178 | 45 | 7 (0 public)
| - | 0 | - |
| 7033-7241 | Driver options and engine posture | `buildDriverOptions` …
`resolveEnginePosture` | 209 | 150 | 6 (0 public) | - | 0 | - |
| 7242-7451 | Organization probe and system-insert organization |
`probeInstallOrganizations` … `transactionCoversDriverFor` | 210 | 45 |
4 (0 public) | - | 0 | - |
| 7452-7817 | Field defaults | `resolveNowDefault` …
`defaultFieldEntries` | 366 | 4 | 6 (0 public) | - | 0 | - |
| 7818-8430 | Autonumber | `applyAutonumbers` … `seedAutonumber` | 613 |
80 | 6 (0 public) | - | 1 | - |
| 8431-9095 | Package, app, plugin and driver registration |
`registrationConversionWarned` … `registerDriver` | 665 | 170 | 6 (3
public) | registerApp, registerDriver | 0 | - |
| 9096-9304 | Datasource registry | `supplyFileColumnsMovedResolver` …
`listUnavailableDatasources` | 209 | 1 | 8 (7 public) | - | 3 | - |
| 9305-9456 | Write guard and realtime publish | `assertWriteAllowed` …
`publishBulkDataEvent` | 152 | 18 | 4 (1 public) | - | 0 | - |
| 9457-9564 | Validation-message i18n | `setI18nService` …
`objectDisplayLabel` | 108 | 24 | 4 (1 public) | - | 0 | - |
| 9565-10273 | Referential integrity and master-detail resolution |
`assertReferencesResolve` … `masterDeclaredFields` | 709 | 308 | 12 (0
public) | - | 0 | - |
| 10274-10389 | Dangling-reference and cascade inspection |
`inspectDanglingReferences` … `inspectCascadeDelete` | 116 | 48 | 2 (2
public) | - | 0 | - |
| 10390-10484 | Crypto and tenancy providers | `setCryptoProvider` …
`setTenancyPostureProvider` | 95 | 20 | 4 (4 public) | - | 1 | - |
| 10485-10904 | Secret and internal-field handling |
`encryptSecretFields` … `resolveInternalField` | 420 | 61 | 9 (3 public)
| - | 0 | - |
| 10905-10973 | Schema lookup and filter judging | `getSchema` …
`judgeFilter` | 69 | 25 | 3 (2 public) | - | 0 | - |
| 10974-11239 | Datasource routing | `LIFECYCLE_DATASOURCE` …
`setDatasourceMapping` | 266 | 20 | 8 (3 public) | setDatasourceMapping
| 0 | - |
| 11240-11407 | Lifecycle init and health | `init` …
`resolvePrimaryDatasource` | 168 | 16 | 3 (3 public) | init | 0 | - |
| 11408-11481 | Media and value-shape presence | `objectHasMediaField` …
`valueShapeStrictFor` | 74 | 13 | 4 (0 public) | - | 0 |
mediaFieldPresence, coveredValueFieldPresence |
| 11482-12071 | Migration flags and attestations |
`isFileReferencesMigrationVerified` … `wasDatastoreCreatedFromEmpty` |
590 | 96 | 17 (8 public) | - | 0 | - |
| 12072-12094 | destroy | `destroy` … `destroy` | 23 | 0 | 1 (1 public)
| destroy | 0 | - |
| 12095-12113 | Expand/cascade limits (statics) | `MAX_EXPAND_DEPTH` …
`MAX_BULK_PER_ROW_HOOK_ROWS` | 19 | 0 | 0 (0 public) | - | 0 |
MAX_EXPAND_DEPTH, MAX_CASCADE_DEPTH |
| 12114-12564 | Roll-up summaries | `autonumberCounters` …
`recomputeSummaries` | 451 | 0 | 7 (1 public) | - | 0 | - |
| 12565-12818 | Related-record expansion | `expandRelatedRecords` …
`expandRelatedRecords` | 254 | 10 | 1 (0 public) | - | 0 | - |
| 12819-13016 | File-reference hydration | `resolveFileReferences` …
`readParentDerivedFiles` | 198 | 183 | 5 (0 public) | - | 0 | - |
| 13017-13495 | Query lowering | `resolveWhereTokens` …
`requireFindOnePredicate` | 479 | 271 | 9 (0 public) | - | 0 | - |
| 13496-14052 | find / findOne | `find` … `staticReadonlyCreateStrip` |
557 | 142 | 4 (2 public) | - | 0 | - |
| 14053-14364 | validate | `validate` … `assignment` | 312 | 224 | 4 (1
public) | - | 0 | - |
| 14365-15734 | insert / insertMany | `readUpdatePriorRow` …
`insertMany` | 1370 | 462 | 3 (2 public) | - | 1 | - |
| 15735-17682 | update | `update` … `update` | 1948 | 290 | 1 (1 public)
| - | 0 | - |
| 17683-19223 | Delete cascade and reference walking |
`planCascadeAtomicity` … `organizationOwnedRowCounts` | 1541 | 733 | 22
(1 public) | - | 0 | storedReferenceIncludes,
remainderAfterMemberRemoval, referenceCheckContext,
outlivesOrganization, keepsOrganizationReference,
organizationCountContext |
| 19224-19793 | delete | `delete` … `delete` | 570 | 47 | 1 (1 public) |
- | 0 | - |
| 19794-20413 | count / aggregate | `count` … `aggregate` | 620 | 192 |
3 (2 public) | - | 0 | - |
| 20414-20722 | execute and transactions | `execute` …
`enforceTransactionOrigin` | 309 | 74 | 8 (2 public) | - | 0 | - |
| 20723-21015 | Compatibility API | `registerObject` … `create` | 293 |
52 | 16 (16 public) | - | 0 | - |
The per-member screen and the full price output are in the project
files, `pm-orders/server/25522-cut17-seam-table.md`. (The seam script's
section boundary after `validate` now lands on an orphaned docblock, so
its "validate" row reads `validate` … `assignment`; the member screen is
unaffected.)
</details>
| price (net lines) | section | taken? |
|---|---|---|
| -233 priced at `fe53769a8e`, **-75 re-priced**, **-72 landed** |
Package, app, plugin and driver registration | **yes**
(`convertPackageBodyForward` 28 body lines, `resolveNavObjectNames` 15,
`registerPlugin` 55; `registerMetadataCollections` stays, pointed at
from `packages/spec/liveness/`) |
| -124 | Delete cascade and reference walking | no: the order takes the
registration section while it pays more than -30 |
| -71 or less | count / aggregate, Query lowering, the rest | pays less
|
| -27 | `resolveFormulaRelated` | a later cut, as the order says |
### The shape
- The class keeps each of the three methods with name, modifiers,
signature, docblock and position. A body becomes one host literal of
exactly the `PackageRegistrationHost` members it reads, plus a `.call`,
marked `[#25522 cut 17]`, as cuts 8 and 10 to 16 did. Fields go as
getters over a `readX` closure (`registrationConversionWarned`,
`logger`, `_registry`); methods go as late-bound closures
(`resolveNavObjectNames`, `registerMetadataCollections`), so a spy or
double set on the engine is still the one a call reaches.
`resolveNavObjectNames` reads no member, so its stub calls the function
directly. No body assigns a field (`registrationConversionWarned.add(`
mutates the set the getter returns, the same object), so there is no
setter.
- **Series limits.** `convertPackageBodyForward` is public with a
declared return type (`any`); `registerPlugin` and
`resolveNavObjectNames` are private, so their `.d.ts` line is `private
NAME;` either way. No moved body has a
`this.FIELD.delete/insert/update(` site, a private-static read, a
self-call to `insert` / `update` / `delete`, an `engine.ts#NAME` pointer
or an ADR anchor paragraph of its own.
- **Helpers, under the cut-14 seat ruling.** `registerPlugin` reads two
top-level helpers, both also read by bodies that stay:
`stampObjectPackage` (`registerApp`) and `stampPackage` (`registerApp`,
`registerMetadataCollections`, `stampObjectPackage`). Both gain `export`
in place, byte for byte otherwise (leading docblocks included), and the
module imports them as values from `./engine.js`; nothing is copied.
Measured alone before the move (`dts-export-variant-cut17.sh`, base
engine.ts plus the `export`, no move): each export and both together
leave all published declaration files byte-identical. `index.ts` and
`core.ts` name their exports singly, so nothing new is published.
- **The run-time cycle and the load order (measured).** The value import
makes `engine.ts` and the module import each other. The module runs
nothing at evaluation (declarations only). The moved
`convertPackageBodyForward` was `engine.ts`'s only reader of
`@objectstack/metadata-core`, so that import line leaves `engine.ts`
with it. The first build imported the module after
`./engine-validate.js` (the cut-16 position); that kept the internal
module order but moved `@objectstack/metadata-core`'s first import in
the ESM bundles three externals later (after
`@objectstack/metadata/view-container`, `ajv`, `ajv-formats`). So the
module is imported exactly where `engine.ts` imported
`@objectstack/metadata-core`. The module's other imports
(`./registry.js`, `./engine.js`, a type from `@objectstack/spec/data`)
are already loaded by then: the bundles place `registry.ts` long before
that region. Measured on the built bundles (`bundlecmp.py`; `index.mjs`,
`core.mjs`, `index.js`, `core.js`): with the `// src/engine.ts` markers
set aside (9 at base, 10 at head, because the new region splits one),
the `// src/...` region order at head equals the base's with one line
added, `// src/engine-package-registration.ts`, inside the `engine.ts`
region where the import sat. Every external `import` statement (113 and
96 in the ESM bundles) and every `require(` call (148 and 130 in the CJS
bundles) is identical and in the same order. The late-binding probe
answers the same on base and head (Tests).
- **Imports.** The module imports `ServiceObject` (type),
`applyArtifactForwardConversions` and `resolveDeclaredRange`
(`@objectstack/metadata-core`), `computeFQN` (`./registry.js`),
`stampObjectPackage` and `stampPackage` (values) and `ObjectQL` (type)
from `./engine.js`. `engine.ts` loses the `@objectstack/metadata-core`
import line (its last reader moved) and `computeFQN` from the
`./registry.js` line (likewise).
- The module header names what moved, how the bodies reach the class,
why `registerApp`, `registerMetadataCollections` and `registerDriver`
stay, and how the helpers were handled.
### Net lines (the seat's rule)
`engine.ts` goes from 21,733 to 21,661 lines, **net -72** (30 added, 102
removed). The module is 192 lines. The diff against `origin/main` is 324
changed lines over 2 files (+222 / -102).
### Readers of the moved lines
- No census, ADR anchor, docs row or test key names a moved member by
`engine.ts` path. Searched: `engine.ts#NAME` and `engine.ts … NAME`
spellings of all three methods, the two helpers,
`registrationConversionWarned`, `applyArtifactForwardConversions`,
`resolveDeclaredRange` and `computeFQN` under `packages/**`,
`scripts/**`, `docs/**` and `content/**`: none. The prose mentions found
(`packages/cli/src/**` comments,
`docs/qa/platform-checklist/areas/platform-core.json`, ADR-0029 line
559) name `registerApp`, `registerMetadataCollections`,
`METADATA_ARRAY_KEYS` or `computeFQN`'s behaviour, not a moved body.
- `scripts/check-stack-collection-maps.mjs`'s `METADATA_ARRAY_KEYS` row
reads `packages/objectql/src/engine.ts`, where the constant stays (it is
`registerMetadataCollections`' helper), so it does not move. The gate is
green at head.
- The bodies call no `canReadObject(` (core's
`row-serving-door-exposure.pin.test.ts` is unchanged), no
`referenceTargetOf(` (`second-object-read-exposure.pin.test.ts` is
unchanged), no `isFederatedObject` / `resolveTenantFieldName`
(`federated-injected-column-readers.test.ts` keys none), and read no
`isSystem` (`system-context.mdx` is unchanged; its census is green).
They hold no `query-options/no-any-erasure` site and no tenant-audit
untyped receiver.
- **No ADR anchor paragraph describes a moved body** (the `engine.ts`
entry is the transaction-seam paragraph), so the module needs no anchor
entry of its own.
- **Read-seam census (the cut-21 trap of #25467).**
`check-durability-degradation-log-level --list` at base and head:
identical once line numbers are masked (164 lines: 48 durability seams
and 88 read seams, the same entries); none of the moved names appears.
- **Decision-letter count:** `check-adr-anchors` at base `e1bfde3601`
(clean detached worktree): **1,898** decision-letter citations on the
anchored surface, 59,997 resolving citations across 8,409 files. At
head: **1,898**, 59,998 across 8,410 (the new module: one more file, and
the header's `ADR-0087 D2`). The moved bodies cite ADR-0087, ADR-0010
and ADR-0122 without a decision letter, so no letter leaves the anchored
surface.
## Why
#25522 splits `engine.ts` one seam at a time so that a change to one
area reads, reviews and conflicts as that area alone. The registration
section was next in cut 16's table and was held out only for #26337,
which has landed. Nothing about what the engine does changes.
## Tests
No test is added and none is edited: the move is proved by identity, not
by new behaviour, and no test reads a moved line by path.
<details><summary>Public <code>.d.ts</code>: byte-identical (ruling
<code>6348891160</code> item 1), with the <code>6441032442</code> report
block and a positive control</summary>
Built `@objectstack/objectql` at the base (`e1bfde3601`: `engine.ts`
blob `fa37297312da`, no `engine-package-registration.ts`) and at head
(`engine.ts` blob `f9aa217bc55d`), each from a clean `src/`
(`dts-cut17.sh`: the base leg restores all of `src/` from the base and
deletes the module; both legs check the blob). The builds are the moved
code, not a stale cache: `convertPackageBodyForward.call(host` occurs 0
times in the base `dist/index.mjs` and once in the head's.
Every declaration file is **raw byte-identical** base to head, so
`6348891160` item 1 holds without any normalisation, and no chunk is
renamed (`util-DdsJlVTF` at both). The `6441032442` block, for the
record (normaliser `pm-orders/server/evidence/25522/dtsnorm.mjs`, sha256
`25226e0677bdad24726e9eff76a7e247bf7319440d2430d28cbaab0db6add94b`, run
as `node dtsnorm.mjs --diff BASE_FILE HEAD_FILE`):
| file | raw sha256 (base = head) | raw-diff lines | statements base /
head | normalised sha256 (base = head) | declared-surface digest (base =
head) | import / export specifier sets |
|---|---|---|---|---|---|---|
| `core.d.ts` |
`642b5a3662c27aabde2dae4bb5877f515cb89f4c1e8075f21c0598b7e6025206` | 0 |
14 / 14 |
`40e2fde86719d3ccd1cf492314c426c977ab836a5ab54580800cd1f41352247a` |
`4450aaf478092516…` (1 decl) EQUAL | 0 / 84, EQUAL |
| `core.d.mts` |
`07f5718a09a2662c2f94bc3d79a8e74b67310efa82071a5d81ed1b716adaa69c` | 0 |
14 / 14 |
`171eab8743fd8dfabc014a162c40c3e034be29f262b26a2bcc24cb3e06be0459` |
`4450aaf478092516…` EQUAL | 0 / 84, EQUAL |
| `index.d.ts` |
`6dd970eb9c7dc4364e2fe99d22460672edc270302287f812231d823090491122` | 0 |
122 / 122 |
`2bb6a21a929b41c8dbb85c72c600f87ed3a3af12ca731d1cace61f5d4aa3d57e` |
`9136189ce4d0aba3…` (103 decls) EQUAL | 18 / 284, EQUAL |
| `index.d.mts` |
`37153868b48bef0e9ad655d74b549a30f51510977cb704e0d6624db1d8e83781` | 0 |
122 / 122 |
`c7d7bab765f3b0fb35241fa03bd0b716a93139c98e5638d209379dad96528f98` |
`9136189ce4d0aba3…` EQUAL | 18 / 284, EQUAL |
| `util-DdsJlVTF.d.ts` |
`856d98e0e45ced3ec15bf72a1ac09420a2c4f73b5165ab598c1d7d0000705f02` | 0 |
185 / 185 |
`a4372dd015163a46e90b82473d806423a5ca982b8bef21e6e8bfed2b0655b9dd` |
`71a464127e0b90b1…` (173 decls) EQUAL | 55 / 147, EQUAL |
| `util-DdsJlVTF.d.mts` |
`856d98e0e45ced3ec15bf72a1ac09420a2c4f73b5165ab598c1d7d0000705f02` | 0 |
185 / 185 |
`a4372dd015163a46e90b82473d806423a5ca982b8bef21e6e8bfed2b0655b9dd` |
`71a464127e0b90b1…` EQUAL | 55 / 147, EQUAL |
- (a) Every file: statements in the same order, `statements only in
base: 0; only in head: 0`, declared-surface digest EQUAL. (b) Every
normalised sha256 EQUAL. (c) Specifier sets EQUAL; the run-time export
lists are too (`index` 182 names and `core` 54, ESM and CJS, the same
sorted list at base and head). (d) Raw diff: 0 lines in every file; the
same 14 files in `dist/` at both. (e) After the head build, the full
`turbo run build` (116 of 116 tasks, the dependents' DTS builds
included) and `pnpm --filter @objectstack/core typecheck` ran on the
head `dist/`: exit 0 each.
- Premises re-checked at this head: (P2)
`packages/objectql/package.json` `exports` names `./dist/index.*` and
`./dist/core.*` only, `driver-sql`'s `./dist/index.*` only; (P3) `git
grep -n -E 'objectql/dist|driver-sql/dist' -- scripts package.json`: 0
hits.
- **Each in-place export alone, before the move**
(`dts-export-variant-cut17.sh`, base `engine.ts` with only `export`
added): `none`, `stampObjectPackage`, `stampPackage`, and both together
all print the same `util-DdsJlVTF.d.ts`, `index.d.ts` `6dd970eb9c7d…`
and `core.d.ts` `642b5a3662c2…`.
**Positive control.** On this head, one `sed` dropped `private` from `
private registerPlugin(` (a moved member's stub; anchor count 1 to 0,
replacement count 0 to 1; `engine.ts` blob `f9aa217bc55d` to
`7c36c1c279c1`) and rebuilt (`posctl17.sh`, build exit 0). The chunk is
renamed `util-Xhg7Kcdw` and now publishes `registerPlugin(plugin: any,
parentId: string, parentNamespace?: string, parentVersion?: string):
void;` (line 7555); its normalised sha256 is
`668033198231cb9bda8545cd23975b0ce61c92a81952ef2dc84f8f692e694852` ≠
`a4372dd0…`, its declared-surface digest `a2448d3c517a96ad…` ≠
`71a464127e0b90b1…` (the `declare class ObjectQL` statement named as the
one changed), and the raw `core.d.ts` (`d1b150bdbefd…`) and `index.d.ts`
(`ac50bb3fc445…`) change with the chunk name. `index.d.ts` normalises
EQUAL under the control (an entry only re-exports), which is why every
declaration file is read. The restore leg put the blob back to
`f9aa217bc55d` (`git diff HEAD` empty), and `@objectstack/objectql` was
rebuilt and its chunk compared equal to the head build before anything
else read `dist/`.
</details>
<details><summary>AST compare (move-only)</summary>
`astcmp.mjs` (TypeScript compiler API, comments and whitespace ignored,
tokens compared) on base `engine.ts` against head `engine.ts` plus the
module:
- The three moved bodies are **SAME** against base `e1bfde3601`
(parameters, return type, `async`, body tokens, and every body line
equal after one level of indent): `convertPackageBodyForward` 309 tokens
/ 28 lines, `resolveNavObjectNames` 122 / 15, `registerPlugin` 367 / 55.
- `class ObjectQL`: 324 of 324 members kept, in the same order; 321
byte-identical, and the 3 stubs keep docblock, modifiers and signature
identical.
- Top level: 229 of 234 base statements byte-identical. The other 5
(`exportcmp.mjs`): the `@objectstack/metadata-core` import, moved
verbatim to the module; the `./registry.js` import, which loses
`computeFQN`; `stampPackage` and `stampObjectPackage`, exported in place
with statement and leading docblock otherwise identical; and the class.
The head adds one statement: the module import.
</details>
<details><summary>Load order (base and head bundles)</summary>
`bundlecmp.py` on the four built bundles. `// src/engine.ts` markers set
aside (9 at base, 10 at head: the new region splits one), the region
order at head is the base's plus `//
src/engine-package-registration.ts`, everything else in order
(`index.mjs` 98 to 99 regions, `core.mjs` 87 to 88, `index.js` 99 to
100, `core.js` 88 to 89). The external module statements are identical
and in the same order: 113 `import` statements in `index.mjs` and 96 in
`core.mjs`, 148 `require(` calls in `index.js` and 130 in `core.js`. The
first build of this cut, with the module imported after
`./engine-validate.js`, kept the region order but printed `engine.ts`'s
`@objectstack/metadata-core` import (now the module's) 41 statements
later in the ESM bundles, after `@objectstack/metadata/view-container`,
`ajv` and `ajv-formats`; the second commit moves the import to the line
where `engine.ts` imported `@objectstack/metadata-core`, which closes
that.
</details>
<details><summary>Late-binding probe (base and head
<code>dist</code>)</summary>
`zz-probe-cut17.mjs` (a one-off, not committed; in the project files)
loads the built `ObjectQL` and drives the three moved bodies with
doubles set on the instance after construction. Cases:
`convertPackageBodyForward` on a non-object, a number and an array
(returned as is); on a body with no declared range (the same reference
back); on HotCRM 4.0.1's published body from
`src/__fixtures__/hotcrm-4.0.1-published-pages.artifact.json` (pages
converted, four `warn` lines, the second call warns nothing and returns
a new body); with `logger` replaced after construction (the replacement
warns); with `registrationConversionWarned` replaced after construction
by a set that already holds one pair (that pair is not warned again, and
the replacement set is the one filled). `resolveNavObjectNames` on
nested navigation and on an app with none (the same reference).
`registerPlugin` with array objects, navigation and an `actions`
collection (objects stamped with the parent's id and version, the
plugin-as-app registered, `resolveNavObjectNames` and
`registerMetadataCollections` reached through spies set on the
instance); with map objects and no version; with a registry that throws
on objects and on the app (both `warn` lines); with `_registry` and
`logger` replaced after construction; with both host methods replaced by
doubles; and `registerApp` reaching a nested plugin through the real
registry. The 42 output lines are identical on base `e1bfde3601` and
head (the 15 construction log lines, which carry timestamps, set aside);
stderr is identical too.
</details>
<details><summary>Suites</summary>
Under `scripts/pm/os-verify-lock.sh` on head `1e7a0e96f`:
- Full `turbo run build` (the root `build` filters): 116 of 116 tasks,
exit 0.
- `typecheck` of `@objectstack/objectql` and `@objectstack/core`: exit 0
each.
- `@objectstack/objectql` vitest `--project local`: 475 files, 8,843
tests passed, exit 0 (`engine-nested-plugin-collections.test.ts`,
`engine-capability-provenance.test.ts` and
`registry-installed-package-retired-page-declarations.test.ts`, which
drive these bodies, among them).
- Every `packages/*/vitest.repo-tests.json` project: core 6 files / 83
tests, objectql 1 / 5, rest 5 / 280 passed and 18 skipped, runtime 3 /
947, spec 80 / 1,295, types 1 / 11. Exit 0 each.
</details>
## Verification
Head `1e7a0e96fe6b004796be314008b5972bd2292c6f`. The gate list is `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on this diff at that head (48 commands,
merge base `e1bfde3601`), each run with its exit code captured before
any pipe, then reconciled with `--ran`.
- **Derived gates: 48 of 48 run, exit 0 each; `--ran`: 48 run, 0
NOT-MEASURED, 0 UNRUN.** `check:dual-build-cjs-loads` and
`check:dts-closure` ran after the full build;
`check-plugin-teardown-shape --self-test` after fetching `621a4876` and
deepening the clone. The exit codes are in
`pm-orders/server/evidence/25522/cut17-ran-final.txt`.
- **Hand gates, exit 0 each:** `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-system-context-census.mjs`, `node
scripts/check-nul-bytes.mjs`, `node
scripts/check-durability-degradation-log-level.mjs --list` (base and
head identical, masked), and eslint as `pnpm lint` runs it
(`--no-inline-config`) on `packages/objectql`.
## Acceptance notes
- **Serial order.** Nothing was edited before the claim `6450667239`
named this branch. The branch is `origin/main` at `e1bfde3601` plus two
commits.
- **Overlap.** Open PRs touching `packages/objectql/**`,
`scripts/check-stack-collection-maps.mjs` or the two liveness files,
listed at start (each head fetched, `git diff --name-only
origin/main...pr/N`) and again just before opening this. At start: none
touched `engine.ts`. Before opening: #26864 now edits `engine.ts` in the
delete-cascade section (hunks at lines 4518 and 18680 to 19416) and
#26831 edits `engine-execution-plumbing.ts`; neither touches this area,
the two helpers or the import lines, and `git merge-tree` of this head
with #26864's head and with `origin/main` `20457f6f9` exits 0. Whichever
lands second merges `main`.
- **Why -72 and not -233.** #26337 made `registerMetadataCollections` a
named producer in `packages/spec/liveness/queue.json` and
`assignment_rule.json` (`engine.ts#registerMetadataCollections`, 18
rows). Moving it would mean re-keying those rows, a `packages/spec` edit
this claim forbids, so it stays. Should a later card re-key them,
`registerMetadataCollections` (about -150) and its three helpers can
follow this module as their own cut.
- **The second commit.** The first commit imported the module where cut
16 imported its own (after `./engine-validate.js`). Measured, that moved
the first `@objectstack/metadata-core` import in the ESM bundles three
externals later; the second commit moves the import line so the external
order is identical (Load order, above). Both commits are in the PR so
the measurement can be re-run on either.
- **Receivers.** The host literal carries
`registrationConversionWarned`, `logger` and `_registry` as getters, so
a body reads whatever the instance holds when it reads it: the probe
replaces each after construction and sees the moved bodies use the
replacements. No body assigns a field, so there is no setter.
- **Left as is.** The interface docblock on `PackageRegistrationHost` is
the series' shared paragraph, word for word as on `ValidateHost`. The
moved `registerPlugin` body's comment "the manifest map branch above"
now points across files; it is moved verbatim, not edited. ADR-0029 line
559 says `computeFQN` lives in `engine.ts`; it has lived in
`registry.ts` since before this cut, and `docs/adr/**` is outside this
claim.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(Not touched.)
- [x] 2. Every name I added uses the casing for its kind
(`PackageRegistrationHost`, `engine-package-registration.ts`).
- [x] 3. No formatter ran; `pnpm lint` passes on the touched package.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. No publish-visible change, so `skip-changeset`; both
declaration lines are filled in above.
- [x] 6. `packages/spec` not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English, apart from the
maintainer quick-read block the project asks for.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
`skip-changeset`: move-only inside `@objectstack/objectql`, with every
published declaration file byte-identical and no behaviour change, so
there is nothing for a release note to say.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5psvNaMgx2AgmL3NgA
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 57e00f5 commit cea0871
2 files changed
Lines changed: 222 additions & 102 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
0 commit comments