Repository navigation
Commit 97277f1
Part of #25522
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160
Cut 3 of the `packages/objectql/src/engine.ts` split (#24586 ruling A,
recorded in `6270097840`). The claim is `6386147359`. Two public
`ObjectQL` method bodies move unedited into a new module,
`packages/objectql/src/engine-lifecycle-health.ts`: `checkDriversHealth`
and `resolvePrimaryDatasource`. `init` stays: its return type is
inferred. #25522 stays open for the later cuts.
Branch `claude/issue-25522-objectql-engine-cut-3`, cut from
`origin/main` at `24d350b45`. Since then `main` has moved five commits
(to `b2909fd46`). None touches `packages/objectql/src/**`; #25657
changes `packages/objectql/package.json`'s zod range only. The branch
has not been merged forward; CI builds the merge ref.
**Serial with the file's in-flight PRs (A1).** At start, none of the 14
open PRs touched `packages/objectql/src/engine.ts` (every file list read
through the REST API, the 183-file Version Packages PR #25640 page by
page). Just before this PR was opened I measured again: 10 PRs are open,
and none touches it (the two new ones, #25682 and #25684, read file by
file; the other 8 unchanged).
## What moves, re-measured on `origin/main` `24d350b45`
The cut-2 dev proposed this area in PR #25636's body. I measured it
again before moving anything, and every premise holds:
- **Both are public with explicit return types:**
`checkDriversHealth(opts?: { timeoutMs?: number })`, which returns a
`Promise` of `DriverHealth[]`, and `resolvePrimaryDatasource():
PrimaryDatasourceVerdict`. The stubs keep both signatures, so the
`.d.ts` keeps its bytes (measured below).
- **0 lines from the last 30 days.** `git blame
--since=2026-09-24T16:00Z` over both methods, docblocks included (156
lines), finds 0 recent lines. Control on the same blame: the whole file
has 8,293 recent lines. History was deepened to 2026-09-15 first (126
commits touch the file in 30 days, 35 in 7).
- **No `this.FIELD.delete/insert/update(` site, and no static read.**
`PLATFORM_PROVIDED_OBJECT_NAMES` is a module import from
`@objectstack/spec/system`, not a class static. It has no other reader
in `engine.ts`, so it leaves `engine.ts`'s import and the new module
imports it.
- **No `engine.ts#…` path reader** for either symbol anywhere in the
repo (`packages/spec/liveness/**`, `scripts/**`, `docs/**`,
`content/**`).
- **No spy and no instance double on a real engine.** The two names
appear in tests only as direct calls on a real engine
(`engine-driver-health.test.ts`, `engine-primary-datasource.test.ts`,
`engine-driver-eviction.test.ts`, `datasource-unavailable.test.ts`) or
as whole-engine fakes
(`packages/runtime/src/http-dispatcher.ready.test.ts`), which never
reach `ObjectQL`.
## The shape (#23050 shape B, as cuts 1 and 2 apply it)
- The class keeps each method with its name, signature, docblock and
position. Each body is now one host literal plus `fn.call(host, …)`,
marked `[#25522 cut 3]`.
- `LifecycleHealthHost` is new. It types each member as the class member
itself (`ObjectQL['drivers']`, `ObjectQL['_registry']`,
`ObjectQL['isSystemLedgerObject']`,
`ObjectQL['resolveDatasourceBinding']`). Each moved function types its
`this` as the `Pick` of the host over exactly the members its body
reads, and each stub annotates its literal as the `ThisParameterType` of
the moved function. There is no cast, and no member becomes public or
protected.
- **Fields go as getters:** `drivers` (both bodies) and `_registry`
(`resolvePrimaryDatasource`). Each read happens when the body makes it,
so a driver registered or evicted later is seen as before.
- **Methods go as late-bound closures:** `isSystemLedgerObject` and
`resolveDatasourceBinding`. A double set on the instance is still the
one the body calls.
- `checkDriversHealth` stays `async` on both the stub and the moved
function, so a throw inside the body is still a rejected promise.
- **Imports.** The module imports `ObjectQL` as a type only, so there is
no module cycle at run time. It imports `DriverHealth` and
`PrimaryDatasourceVerdict` as types from `./driver-connect-errors.js`
and `PLATFORM_PROVIDED_OBJECT_NAMES` from `@objectstack/spec/system`,
the specifiers `engine.ts` uses. `engine.ts` gains one import and drops
`PLATFORM_PROVIDED_OBJECT_NAMES` from its `@objectstack/spec/system`
import, its only other reader being a backticked docblock mention.
Nothing re-exports the module.
## Net lines (this seat's rule: an area moves only when `engine.ts`
shrinks)
| | base `24d350b45` | head |
|---|---|---|
| `engine.ts` (`wc -l`) | 23,807 | 23,755 (−52) |
| `engine-lifecycle-health.ts` | — | 143 |
Diff: +163 / −72 over 2 files, under the 3,000-line manual-merge line.
## The published `.d.ts` does not change (ruling `6348891160`)
Base: the `@objectstack/objectql` dependency closure built at this
branch (`pnpm --filter '@objectstack/objectql^...' build`, which the
diff does not touch), then `pnpm --filter @objectstack/objectql build`
with `engine.ts` restored from `24d350b45` (tree only) and the base
`dist/` saved; the head build runs after `git checkout HEAD --
packages/objectql/src/engine.ts` with `git status` clean. The head
`dist/index.mjs` carries `readRegistry` twice and the base copy 0 times,
so each build is the one it claims to be.
All six declaration files are **byte-identical**. The raw diff of each
is 0 lines. The util chunk name, `util-ByiLm3B6`, is the same at both
ends.
| file | raw sha256, base = head | normalised (ruling, verbatim), base =
head | normalised (single-quoted spelling), base = head |
|---|---|---|---|
| `index.d.ts` |
`9ca22071717e3f761198115fa54a143df4151a52950d826a10677420dcad16ae` |
`9ca22071717e…` | `c15106196eb2…` |
| `index.d.mts` |
`69dd1cfe3875024f434b2d7defce771ebc8c7e48a05be7c946fa6ecdbd912b40` |
`69dd1cfe3875…` | `a2d6d7b241e8…` |
| `core.d.ts` |
`d27b72bde2eec9a47c7dd3c104976321533cf397452ca9f84491a455ec28e73b` |
`d27b72bde2ee…` | `d27b72bde2ee…` |
| `core.d.mts` |
`5a0cca505296b678b31c742c285e028fe434f5467bb8d27e052e470ce0e09652` |
`5a0cca505296…` | `5a0cca505296…` |
| `util-ByiLm3B6.d.ts` and `.d.mts` |
`1742a9cb029654d1ca4e8e392e98001eec85963987f516b1b76f672ecd08e5a9` |
`1742a9cb0296…` | `bffd1b630dab…` |
- Normaliser, the ruling's one-liner verbatim (double-quoted unions):
`node -e 'const
s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join("
| ")))' FILE | sha256sum`. This package prints single-quoted literals,
so on these files it changes nothing and normalised = raw. The third
column is the same single class spelled with a single quote; it also
matches. This cut does not depend on it, because the raw bytes are
identical.
- **Positive control**, in the same run, on a copy of the head
`util-ByiLm3B6.d.ts`: line 8318 `private isSystemLedgerObject;` made
public (`isSystemLedgerObject;`, raw diff 2 lines) gives raw =
ruled-normalised
`c944677ee7e7c23a9ecabb6466a616a9f993d3e41fbee3b854527e039c7d19cd`,
which differs from `1742a9cb…`. The single-quote normalisation gives
`e86dbb567ef0…`, which differs from `bffd1b630dab…`.
- **Export lists**, loaded at run time from the built bundles (ESM
`import()` and CJS `require`), are identical at base and head. `.` has
182 exports under ESM and 182 under CJS; `./core` has 54 and 54. The
sorted lists hash
`881616cc179189098182bd6b8a95701d9922f9677b786bc12e2d31c1adb0adaa` and
`393e806906e876c2e020aa96617d54050a35ae63cd483b67d8e968b7b5390f49` at
both ends (the same as cut 2's).
No changeset: `skip-changeset`, per ruling `6348891160` item 4.
## Proof of move-only
- **Bodies, by AST token** (recursive `getChildren` leaves of the
TypeScript parse). For each moved function, the parameters (without the
added `this`), the return type, the `async` modifier and the body have
the same token sequence as the base method: `checkDriversHealth` 251
tokens, `resolvePrimaryDatasource` 218 tokens, all SAME. Every body line
is the base line less two leading spaces (36 and 39 lines, braces
included). **Negative control:** one changed token in the moved
`resolvePrimaryDatasource` (`'system-object-unbound'` misspelled in
memory) makes the same check report DIFFER.
- **Class side.** The class has 317 members at base and at head. The 315
that did not move are byte-identical to base (full text, docblocks
included). The 2 stubs keep their docblocks and signatures
byte-identical.
- **Top level of `engine.ts`.** 234 of the 235 base statements outside
the class are byte-identical at head. The other is the
`@objectstack/spec/system` import less `PLATFORM_PROVIDED_OBJECT_NAMES`.
The one new statement is the import of the new module.
- **The tests reach the moved bodies** through the stubs:
`engine-driver-health.test.ts` (7 cases on `checkDriversHealth`, timeout
and skip paths included), `engine-primary-datasource.test.ts` (every
`resolvePrimaryDatasource` verdict), `engine-driver-eviction.test.ts`
and `datasource-unavailable.test.ts`. All pass at head (below).
## Readers of the moved lines
- **ADR anchors (A2).**
`scripts/adr-anchors/packages__objectql__src__engine.ts.json`'s one
paragraph is about the transaction seam (`buildDriverOptions`,
`enforceTransactionOrigin`), neither of which moves. The ADR-0057 §3.6
mention in `resolvePrimaryDatasource`'s docblock stays on the stub; the
one-line `// ADR-0057 §3.6` comment inside the body moves with it. No
anchor entry describes a moved body, so none is added.
`check:adr-anchors` exit 0 at both ends: 85 anchored files; **1,847
decision-letter citations on the anchored surface at base and at head**;
52,546 citations at both ends (6,610 files at base, 6,611 at head: the
new module).
- **Liveness ledgers.** `pnpm --filter @objectstack/spec check:liveness`
exits 0 at head. No ledger points at either moved symbol.
- **Other path readers.** `check-adr-symbol-anchors`: 2,384 anchors
resolve at head. `check-platform-checklist --changed-from origin/main`:
1 anchored file in the change set, 14 anchors judged, 0 lost.
## Direct dependants (A3)
The moved members are reached from `@objectstack/runtime`
(`http-dispatcher.ts`'s `/ready` handler calls both) and named in
`@objectstack/service-datasource`'s comments. I built their dependency
closures (`pnpm --filter '@objectstack/runtime^...' --filter
'@objectstack/service-datasource^...' build`, under `os-verify-lock`,
VERDICT command-exit 0) and ran `pnpm --filter @objectstack/runtime
--filter @objectstack/service-datasource typecheck` (VERDICT
command-exit 0): `service-datasource` `tsc --noEmit` done; `runtime`
`tsc --noEmit` and `check:test-typecheck` OK; 0 `error TS` lines. Both
read the published declarations, which are byte-identical above.
## For the next dispatch (cut 4)
- **Proposed area: Realtime publish** (the tail of the "Write guard and
realtime publish" row): `publishDataEvent` (58-line body) and
`publishBulkDataEvent` (55-line body).
- Both private with explicit return types; no
`this.FIELD.delete/insert/update(` site; no static read; no
`engine.ts#…` path reader; no `vi.spyOn` or instance assignment on
either, measured repo-wide.
- 18 lines from the last 30 days (16 in `publishDataEvent`'s range, 2 in
`publishBulkDataEvent`'s).
- Host: three getters only (`realtimeService`, `logger`, `_registry`).
- **Priced against the net-line rule:** 113 body lines out, about 2 × 7
stub lines and 3 import lines in, so `engine.ts` drops by roughly 95
lines.
- **Stays from that row:** `assertWriteAllowed`.
`packages/spec/liveness/datasource.json` cites
`packages/objectql/src/engine.ts#assertWriteAllowed` as evidence, the
same reason `resolveDatasourceBinding` stayed in cut 2.
`setRealtimeService` and `listUnavailableDatasources` are 1–2-line
bodies, shorter than a host literal.
- **Still waiting:** Roll-up summaries (spec-coupled, see cut 1); the
Datasource registry (U = 3); Related-record expansion
(`expandRelatedRecords` reads the private static `MAX_EXPAND_DEPTH`).
## Verification
All at head `7b61487ac`.
- `pnpm --filter @objectstack/objectql typecheck` (`tsc --noEmit` and
`check:test-typecheck`), under `os-verify-lock`: VERDICT command-exit 0;
39 files / 233 errors / 64 pinned signatures held.
- `packages/objectql` suite (`vitest run --project local
--maxWorkers=2`, under `os-verify-lock`, VERDICT command-exit 0): 466
files, 1,899 suites, 8,700 tests, 8,700 passed, 0 failed, 0 skipped.
- `eslint --no-inline-config packages/objectql`: exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 56 families on the real diff at
`7b61487ac` (stderr names the repo and the commit). All 56 were run,
each exit code recorded before any pipe. 53 exit 0 on the first pass,
and `check-engine-split-ratio --days 90` exit 0 after the history
deepening it names as its remedy (`git fetch
--shallow-since=2026-07-19`; it had refused with exit 2, CANNOT COMPUTE;
ratio 98.1%). `--ran` reconciles: 56 accounted for, 54 run, 2 NOT
MEASURED. CI runs both:
- `check-plugin-teardown-shape --self-test` exit 3: its pinned fixture
commit is not in this shallow clone.
- `check:dual-build-cjs-loads` exit 3, PREREQUISITE NOT MET: 54 export
entries of other packages have no `dist/` (9 listed, "… 45 more"). The
export lists above answer its question for this package.
- Hand gates, all exit 0: `check-adr-anchors` (base and head),
`check-adr-symbol-anchors`, `check-platform-checklist --changed-from
origin/main`, `pnpm --filter @objectstack/spec check:liveness`.
- `test:repo` was not run locally; CI's `Test Core` runs it.
---
_Generated by [Claude
Code](https://claude.ai/code/session_0161WE4VX4T7VT66M6pYcVjD)_
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5cf1b9d commit 97277f1
2 files changed
Lines changed: 163 additions & 72 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
108 | 111 | | |
109 | 112 | | |
110 | 113 | | |
| |||
250 | 253 | | |
251 | 254 | | |
252 | 255 | | |
253 | | - | |
| 256 | + | |
254 | 257 | | |
255 | 258 | | |
256 | 259 | | |
| |||
12662 | 12665 | | |
12663 | 12666 | | |
12664 | 12667 | | |
12665 | | - | |
12666 | | - | |
12667 | | - | |
12668 | | - | |
12669 | | - | |
12670 | | - | |
12671 | | - | |
12672 | | - | |
12673 | | - | |
12674 | | - | |
12675 | | - | |
12676 | | - | |
12677 | | - | |
12678 | | - | |
12679 | | - | |
12680 | | - | |
12681 | | - | |
12682 | | - | |
12683 | | - | |
12684 | | - | |
12685 | | - | |
12686 | | - | |
12687 | | - | |
12688 | | - | |
12689 | | - | |
12690 | | - | |
12691 | | - | |
12692 | | - | |
12693 | | - | |
12694 | | - | |
12695 | | - | |
12696 | | - | |
12697 | | - | |
12698 | | - | |
| 12668 | + | |
| 12669 | + | |
| 12670 | + | |
| 12671 | + | |
| 12672 | + | |
| 12673 | + | |
12699 | 12674 | | |
12700 | 12675 | | |
12701 | 12676 | | |
| |||
12754 | 12729 | | |
12755 | 12730 | | |
12756 | 12731 | | |
12757 | | - | |
12758 | | - | |
12759 | | - | |
12760 | | - | |
12761 | | - | |
12762 | | - | |
12763 | | - | |
12764 | | - | |
12765 | | - | |
12766 | | - | |
12767 | | - | |
12768 | | - | |
12769 | | - | |
12770 | | - | |
12771 | | - | |
12772 | | - | |
12773 | | - | |
12774 | | - | |
12775 | | - | |
12776 | | - | |
12777 | | - | |
12778 | | - | |
12779 | | - | |
12780 | | - | |
12781 | | - | |
12782 | | - | |
12783 | | - | |
12784 | | - | |
12785 | | - | |
12786 | | - | |
12787 | | - | |
12788 | | - | |
12789 | | - | |
12790 | | - | |
12791 | | - | |
12792 | | - | |
12793 | | - | |
| 12732 | + | |
| 12733 | + | |
| 12734 | + | |
| 12735 | + | |
| 12736 | + | |
| 12737 | + | |
| 12738 | + | |
| 12739 | + | |
| 12740 | + | |
| 12741 | + | |
12794 | 12742 | | |
12795 | 12743 | | |
12796 | 12744 | | |
| |||
0 commit comments