Repository navigation
[maintainer] refactor(objectql): split src/engine.ts (23,903 lines, +7,501 in 30 days) along its ObjectQL seams, one move-only slice per PR #25522
Description
Filing gate ③: a task the maintainer dispatched, quoted below. Filed by domain:services seat 1 (seat post #6021) · os-sales · session session_016g7nYP9wdNx1GDa5XDr7Uy, as the third engine-surface file of #24586's restart act. #25467 (protocol.ts) went first as the ruling orders, and its cut 1 landed in PR #25494. ⛔ Not a claim.
The maintainer's words, verbatim (#24586, recorded in 6270097840): 「24586 同意A,是否建议这波分拆等 v18 发布之后再处理。」 The restart act calls for "one [maintainer] card per file over 10,000 lines into its owning lane … Each card starts with a fresh seam measurement taken at that time, in #23050's shape". Triage read the restart condition as true in 6291735609.
Reader who acts: the domain:server lane, engine surface. One dispatch per slice. The first act is the seam table, sections by contiguous member ranges with their 30-day lines, measured fresh at claim.
Measured (on origin/main 842a0aef9d, 2026-10-23)
- Size and churn:
- 23,903 lines, up from 16,402 thirty days ago (
dabf8d795e), a gain of +7,501 (+45.7%). - 34 commits in 7 days and 125 in 30 days, which makes it the hottest of the three engine-surface files.
git blame --since=2026-09-23T15:00Zattributes 8,337 lines (34.9%) to the last 30 days.
- 23,903 lines, up from 16,402 thirty days ago (
- Structure:
- One
ObjectQLclass of 18,214 lines with 254 methods: 147 private or protected, 107 public. - 8 public methods have an inferred return type and stay under the series limit below unless a ruling says otherwise:
registerApp(178 lines),registerHook(75),registerDriver(44),init(40),triggerHooks(32),destroy(22),setDatasourceMapping(13) andgetStatus(8). - The rest is the module preamble and the helpers.
- One
- What reads it by path:
- the ADR anchor file
scripts/adr-anchors/packages__objectql__src__engine.ts.json; - 21 files under
scripts/; - 33 files under
docs/andcontent/, 18 of them ADRs.
- the ADR anchor file
- In flight: none of the 13 open PRs touch the file today. At 34 commits a week, that changes fast, so every slice re-measures it at claim.
The ask (from #24586's ruling and #23050's shape, as on #25467)
- Split along the existing seams, one area per PR. Each slice is move-only: no logic changes.
- Shared state stays explicit. Moved code reaches the class's shared members through one named host object, as in [maintainer] refactor(rest): split
packages/rest/src/rest-server.ts(13,701 lines, 70 commits in 30 days) along itsregister*Endpointsseams, one move-only slice per PR,/metaafter #22877 stage 2 #23050, [maintainer] refactor(service-automation): splitsrc/engine.ts(13,735 lines, +2,199 in 30 days) along itsAutomationEngineseams, one move-only slice per PR #25222, [maintainer] refactor(plugin-security): splitsrc/security-plugin.ts(10,746 lines, +2,803 in 30 days) along itsSecurityPluginseams, one move-only slice per PR #25223, [maintainer] refactor(plugin-auth): splitsrc/auth-manager.ts(10,338 lines, +1,867 in 30 days) along itsAuthManagerseams, one move-only slice per PR #25224 and [maintainer] refactor(metadata-protocol): splitsrc/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467.- ⛔ Not a second copy of a helper.
- ⛔ Not a re-derivation.
- Every slice proves it moved nothing:
- Every gate, baseline, ADR anchor and docs anchor that reads the file by path is migrated in the same PR and stays green.
- When an ADR anchor entry's paragraph describes a moved body, even half of it, the new module gets its own entry that carries that paragraph.
- The package's public
.d.tsstays identical under ruling6348891160item 1, with a positive control. - The decision-letter count of
check:adr-anchorsis reported at base and at head. - ⛔ A gate whose target moved must not go silently empty.
- Serial with the file's in-flight PRs. A slice waits for an open PR on the same region, or that PR merges
mainafter the slice. Every slice measures the file's open PRs again at claim. - ⛔ No new gate.
Series limits already measured (carry them forward)
- Inferred return types. A public method whose return type is inferred cannot move under the host pattern. The
.d.tswould then be inferred through the new module, and tsup drops property JSDoc and splices unrelated docblocks into it (measured on [maintainer] refactor(metadata-protocol): splitsrc/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467 cut 2,getDiscovery). Such a member stays. Annotating it is a signature edit, which needs a ruling. - The tenant-audit census.
UNTYPED_RECEIVERSis shrink-only. A body with athis.<field>.delete/insert/update(site becomes an untyped receiver in aPick-host module, so that body stays unless a ruling says otherwise ([maintainer] refactor(plugin-auth): splitsrc/auth-manager.ts(10,338 lines, +1,867 in 30 days) along itsAuthManagerseams, one move-only slice per PR #25224 cut 8, [maintainer] refactor(service-automation): splitsrc/engine.ts(13,735 lines, +2,199 in 30 days) along itsAutomationEngineseams, one move-only slice per PR #25222 slice 2). - Private statics stay in the class (entangled-shape rule, [maintainer] refactor(plugin-auth): split
src/auth-manager.ts(10,338 lines, +1,867 in 30 days) along itsAuthManagerseams, one move-only slice per PR #25224).
Order and pace
- Because of the churn, each slice should take the coldest section the seam table finds, as [maintainer] refactor(metadata-protocol): split
src/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467 did with batch and*Many. - A seat may hold this card behind
sql-driver.ts's first slices when the file's in-flight PRs make a move-only slice collide.
Not in this card
- Any behaviour change, and any design change to the shared members beyond giving them an explicit host.
driver-sql/src/sql-driver.ts, filed beside this one as its own card.
Dedupe
MCP search_issues on this repository, closed issues included: "split objectql engine.ts or sql-driver.ts move-only cut ruling 24586". There were 113 hits. None is a split card for objectql/src/engine.ts. The related ones are #24586 (the ruling), #25467 (protocol.ts), and #25222, #25223 and #25224 (the services files). New.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1
Session:
session_01JVTd3PprStGa26aez5omLBAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25522-objectql-engine-cut-1Worktree:
objectstack-issue-25522Domain:
domain:serverSeat:
domain:server#2File surface:
packages/objectql/src/**(engine.tsand the new seam module of this slice),scripts/adr-anchors/**entries for moved bodies, the path readers ofengine.tsunderscripts/andcontent/that the slice must migrate, one changeset. ⛔ Nodocs/adr/**(governed) (stop on breach; explain in the report)Container & model:
M(one move-only slice plus the seam table),mode:subagent,model: TIER_DEFAULT(dispatch-gates --tierat8801f2bb3: "no path-derived mandate … the tier stays the PM's per-card judgment call"),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Serial constraints cleared: none. No open PR touches
packages/objectql/src/engine.ts(13 open PRs read this fire); last touch onmainis77a77e4(#25396).Premise: re-read on
origin/main8801f2bb3:engine.tsis 23,903 lines, as the card measured; no split has started.Generated by Claude Code
refactor(objectql): move the validation-message i18n helpers out of e…
objectstack-fleet commentedon Oct 24, 2026
os-dev-report
{
"issue": 25522,
"status": "done",
"branch": "claude/issue-25522-objectql-engine-cut-1",
"pr": "#25615",
"session": "session_01JVTd3PprStGa26aez5omLB — the dispatching seat's session (mode:subagent), on the Claude-Session: trailer of commit 328b5b1",
"premise_still_valid": true,
"summary": "Seam table measured fresh at origin/main e649c2d (engine.ts 23,903 lines; 8,253 from the last 30 days; 124 commits in 30 days, 33 in 7; class ObjectQL 317 members, 255 methods, 147 private / 108 public; the same 8 inferred-return public methods the card lists). It is in the PR body as 41 contiguous sections, each with its 30-day lines. Cut 1 is the coldest area that meets every series limit and has no path reader outside objectql: the validation-message i18n block (122 lines, 0 from the last 30 days). The private bodies of ObjectQL#validationMessageContext, #negotiatedMessageLocale and #objectDisplayLabel moved unedited to packages/objectql/src/engine-validation-messages.ts through ValidationMessageHost: the i18nService getter plus a late-bound negotiatedMessageLocale closure; objectDisplayLabel reads no member and is called directly. setI18nService stays: it is a two-line field setter. The new module imports ObjectQL as a type only, so there is no runtime cycle. Two spec/system imports with no other reader in engine.ts (objectLabelKey, resolveBundleLocale) left engine.ts. All six published declaration files are byte-identical, the export lists are identical, and the draft PR is Part of #25522 with skip-changeset. Roll-up summaries (0 lines in 30 days) was set aside for cut 1: buildSummaryIndex is the liveness ledger's evidence by path (packages/spec/liveness/field.json, summaryOperations), and recomputeSummaries has a this.update( write and passes this to aggregateSummaryValue. Proposed cut 2: Datasource routing (isSystemLedgerObject, getDriver, resolveDatasourceBinding, resolveEffectiveDatasource, resolveMappedDatasource, resolveDatasourceFromMapping, matchPattern; 343 lines, 1 from the last 30 days; setDatasourceMapping and the two public statics stay; the new module gets its own anchor entry for the ADR-0057 routing sentence). Measure getDriver's spies and doubles before choosing it. Draft only, per the release terms: no ready flip, no auto-merge, no queue, no merge.",
"tests": "At head 328b5b1. (1) pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2 under os-verify-lock: VERDICT command-exit 0; JSON report: 466 files, 1,899 suites, 8,700 tests, 8,700 passed, 0 failed, 0 skipped. That includes engine-validation-locale.test.ts, engine-validation-locale-negotiation.test.ts and engine-delete-restricted-locale.test.ts, which pin these helpers. (2) pnpm --filter @objectstack/objectql typecheck (tsc --noEmit plus check:test-typecheck) under the lock: VERDICT command-exit 0, 'check:test-typecheck: OK — ... 39 file(s) / 233 error(s) / 64 pinned signature(s) held in test-typecheck-debt.json'. (3) Move proof by AST token (recursive getChildren leaves): validationMessageContext 104, negotiatedMessageLocale 134, objectDisplayLabel 133 tokens, all SAME, every body line the base line less 2 leading spaces. Negative control: one changed token in negotiatedMessageLocale reports DIFFER. Class side: 317 members at base and head, the 314 that did not move byte-identical, the 3 stubs keep docblock and signature byte-identical. Top level: 232 of 233 statements byte-identical (the other is the spec/system import less two names) plus one new import. (4) .d.ts bar, ruling 6348891160: index.d.ts 9ca22071717e3f761198115fa54a143df4151a52950d826a10677420dcad16ae, index.d.mts 69dd1cfe3875024f434b2d7defce771ebc8c7e48a05be7c946fa6ecdbd912b40, core.d.ts d27b72bde2eec9a47c7dd3c104976321533cf397452ca9f84491a455ec28e73b, core.d.mts 5a0cca505296b678b31c742c285e028fe434f5467bb8d27e052e470ce0e09652, util-ByiLm3B6.d.ts = .d.mts 1742a9cb029654d1ca4e8e392e98001eec85963987f516b1b76f672ecd08e5a9. Each is raw = normalised and base = head, raw diff 0 lines, using the ruling's normaliser verbatim. Note: this package prints single-quoted literals (23 single-quoted literal unions, 0 double-quoted), so that normaliser is a no-op here. Positive control: line 7261 private objectDisplayLabel; made public gives raw = normalised 270f913f734273e380af6ab964e8b15206aa7c511892dea58cc8f6fd9adf5ef7, not equal to 1742a9cb. Export lists from the built bundles: '.' 182 ESM = 182 CJS, './core' 54 = 54, identical at base and head (sorted-list sha256 881616cc... and 393e8069...). (5) One-off mutation, not a kept test (move-only, so no ablation is owed): scripts/ablation-replace.mjs replaced the moved 'return resolveBundleLocale(offered, requested) ?? requested;' with 'return requested;' (anchor 1 -> 0, blob 5d9194fa75bb -> 88406d6408d5). engine-validation-locale-negotiation.test.ts went to 3 failed / 3 passed. Restore: blob == HEAD 5d9194fa75bb and git diff HEAD empty. vitest resolves the relative import from src/, so there is no dist/ leg. test:repo was not run locally (CI's Test Core runs it).",
"gates": "Local, on the real diff (2 files, +135/-39): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 56 families at 328b5b1 (stderr first line names the repo and the commit). All 56 were run at head, each exit code captured before any pipe. 53 exit 0. Three are NOT MEASURED: node scripts/check-engine-split-ratio.mjs --days 90 exit 2 (CANNOT COMPUTE: the shallow clone's history starts 2026-09-15, inside the 90-day window); node scripts/check-plugin-teardown-shape.mjs --self-test exit 3 (cannot read pinned positive-control commit 621a487 in this shallow clone); pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: no dist/ for 70 packages; the export lists in tests (4) answer its question for objectql). Reconciliation: dispatch-gates --ran with ':: exit N' lines prints '56 derived famil(ies) accounted for — 54 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)'. It counts the exit-2 refusal as run; by that script's own header it is CANNOT COMPUTE, so this report counts it NOT MEASURED. Outside the derivation, all exit 0: eslint --no-inline-config packages/objectql; eslint on both files; node scripts/check-adr-anchors.mjs (base and head: 84 anchored files, 1,883 decision-letter citations, 52,465 citations across 6,583 files, the same at both ends); node scripts/check-adr-symbol-anchors.mjs (2,384 anchors resolve); node scripts/check-nul-bytes.mjs; node scripts/check-platform-checklist.mjs --changed-from origin/main ('1 anchored file(s) in the change set, 14 anchor(s) judged, 0 lost'). CI on PR #25615 head 328b5b1 at report time: Check Changeset success; No other open PR may claim the same issue success; Type Check (workspace, debt ledger, source gates, consumer gates), the Lint lanes (PM dispatch-gates, CI release & engine gates, ESLint, repo & tooling gates, docs & code guards, the scoped lanes), Governed Surface Queue Guard, Part-of PR must not also close its card, Check PR Size and the rest: in_progress. Opt-in lanes skipped. Not waited on, per the contract.",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm (Clause-②: no)","mcp_calls": "0 — no GitHub MCP tool called",
"api_writes": "2 relay strokes, both through scripts/pm/fleet-write/dispatch.mjs as POST /repos/objectstack-ai/objectstack/dispatches, executed by the relay as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /issues/25615/assignees [sunhaolin] + POST /issues/25615/labels [skip-changeset]; run 40082586078 success; read-back 18,999 bytes sent = stored, identical; assignee and label listed. (2) This report: POST /repos//issues/25522/comments via scripts/pm/post-stamped.mjs. Not REST: git push to the branch, twice (the empty-branch probe, then commit 328b5b1).",
"open_questions": [
{
"question": "Later cuts of this file: @objectstack/objectql's .d.ts prints string literals in SINGLE quotes, so ruling 6348891160's verbatim normaliser (double quotes only) cannot absorb a union-member-order swap here. This cut is raw byte-identical, so nothing depended on it. A later cut that moves a body the DTS program checks before the rest of engine.ts could reorder a union. That shows as a raw diff the normaliser leaves in place, which under the ruling's item 1 is a stop. Does the ruling seat want to decide this before cut 2 is dispatched?",
"options": [
"A — The ruling seat states that item 1(b)'s normalisation covers single-quoted literal unions too: the same single class (member order within one literal union), spelled with the quote this printer uses, nothing else normalised. Real business need: the maintainer's split order for a file with 124 commits in 30 days. Long-term: the bar stays on the contract (declarations, visibility, exports), not on printer quote style. AI-error prevention: unchanged, because 1(a), 1(d) and the positive control still catch every change of kind. No sprawl: a ruling sentence, no script, no gate. Effort: one ruling comment.",
"B — Keep the normaliser verbatim. Any later cut whose raw diff carries a union-order swap stops and returns needs_decision, and the ruling seat decides then. Real business need: the same. Long-term: an equivalent outcome, one round later. AI-error prevention: the same. No sprawl: none added. Cost: one stopped cut and a ruling lap mid-series, at a cut whose timing nobody chooses."
],
"recommendation": "A, decided by the ruling seat, not by a dev: it is the class ruling A already judged meaningless to every consumer (the quote character is a printer setting), and deciding it before cut 2 costs one sentence instead of a stopped cut. ⛔ Not acted on here: this dev did not widen the normaliser and adds no script (ruling item 3, card ask 5)."
}
],
"out_of_scope_findings": [
"carrier: the ruling seat, through open_questions[0] above · the single-quote blind spot of the ruling's normaliser on @objectstack/objectql · noted, not filed (not a defect, contract violation or authoring trap)",
"carrier: none (承接者:无) · cut-2 pricing note: Roll-up summaries is cold (0 lines in 30 days), but buildSummaryIndex is the liveness evidence pointer for field.summaryOperations (packages/spec/liveness/field.json: evidence packages/objectql/src/engine.ts, key-mention), so that cut owes a packages/spec ledger edit, and recomputeSummaries stays (a this.update( write, and this passed to aggregateSummaryValue) · noted in the PR body, not filed"
],
"line_budget": "174 changed lines (+135 / -39) over 2 files, under the 3,000 human-merge line; engine.ts 23,903 -> 23,881; engine-validation-messages.ts 118",
"files_changed": [
"packages/objectql/src/engine-validation-messages.ts (added)",
"packages/objectql/src/engine.ts (modified)"
],
"deviations": [
"Commit trailers: the model-free pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md and os-dev.md, in place of the harness reminder's model-named Co-Authored-By line (the pre-push hook refuses a model identifier). PR body footer: AGENTS.md's session-URL form, in place of the harness's line.",
"A2: no scripts/adr-anchors entry added for the new module. The engine.ts entry's one paragraph is the transaction seam and describes no moved body, and the moved bodies cite no ADR (the ADR-0053 Phase 2 cite is in a docblock that stays on the stub). Card ask 3 owes an entry only when a paragraph describes a moved body.",
"A3, narrowed and declared: no direct dependant was type-checked locally. Every moved member is private (reachable from no dependant), and all six published declaration files are byte-identical, so the dependants' input bytes are unchanged. CI's TypeScript Type Check lanes cover them.",
"No baseline objectql test run (head only). The base-vs-head per-test comparison PR #25494 carried is not repeated; the head suite is 8,700/8,700.",
"History: a sibling agent's git fetch --shallow-since=2026-09-15 held .git/shallow.lock, so this run waited on that PID (tail --pid) and read 30-day blame from the deepened history. It did not remove the lock or deepen further, so the 90-day split-ratio gate stays NOT MEASURED.",
"Created a fetch ref refs/issue-25522/main in the shared ref namespace to re-read main without moving origin/main; deleted at cleanup."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
ACCEPT → PR #25615 comment 6382672482 (cut 1, head
328b5b194e; lands once CI is green on that head) ·domain:serverseat 2 ·session_01JVTd3PprStGa26aez5omLBGenerated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Release:
domain:serverseat 2 ·sunhaolin· sessionsession_01JVTd3PprStGa26aez5omLB· 2026-10-24T10:42Z · cause: cut 1 landed (Part of #25522) · destination:pm:queue, unassigned, for cut 2Landed: PR #25615 →
481ac6211(#25522 cut 1)merged: true, merge commit481ac6211641ccb7292508ed423f02e432322e4a, merged 2026-10-24T10:42:01Z through the merge queueorigin/main481ac6211is an ancestor oforigin/main(481ac62116), single parent (squash)gh-readonly-queue/main/*head for PR 25615 remainsvalidationMessageContext,negotiatedMessageLocale,objectDisplayLabel) lives inpackages/objectql/src/engine-validation-messages.ts.engine.tsis 23,881 lines.getDriver's spies and doubles first; the new module owes its own anchor entry for the ADR-0057 routing sentence). Roll-up summaries waits:buildSummaryIndexis the liveness evidence path inpackages/spec/liveness/field.json, so that cut is spec-lane-coupled.pm:dispatched→pm:queue, assignee cleared, in this act. The series card stays open. This seat re-claims cut 2 when a dispatch slot frees.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1 · cut 2
Session:
session_01JVTd3PprStGa26aez5omLBAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25522-objectql-engine-cut-2Worktree:
objectstack-issue-25522Domain:
domain:serverSeat:
domain:server#2File surface:
packages/objectql/src/**(engine.tsand the new seam module of cut 2; the dev proposes Datasource routing),scripts/adr-anchors/**(the new module's own entry for the ADR-0057 routing sentence), test files that spy on or double a moved member.skip-changesetunder ruling 6348891160. ⛔ Nodocs/adr/**, ⛔ nopackages/spec/**(stop on breach; explain in the report)Container & model:
M,mode:cloud(maintainer: 「并发加到5,可以用云卡片」),model: TIER_DEFAULT(dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6383241311
Serial constraints cleared: cut 1 (PR #25615) merged as
481ac6211; no open PR touchespackages/objectql/src/engine.ts(open PRs read this fire).Premise: cut 1 landed; the 41-section seam table in PR #25615's body is the baseline; the cut-2 dev re-measures it on
origin/mainat start.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
os-dev-report
{
"issue": 25522,
"status": "done",
"branch": "claude/issue-25522-objectql-engine-cut-2",
"pr": "#25636",
"session": "session_017jiggF9SoTgeCHgPWuGdU9 — this cloud run's own session (mode:cloud), on the Claude-Session: trailer of commit c70b6b5; dispatched by domain:server seat 2 session_01JVTd3PprStGa26aez5omLB",
"premise_still_valid": true,
"summary": "Cut 2 moves the bodies of ObjectQL#getDriver, #resolveDatasourceFromMapping and #matchPattern (all private) unedited into packages/objectql/src/engine-datasource-routing.ts through DatasourceRoutingHost. Fields go as getters (drivers, logger, unavailableDatasources, datasourceMapping), resolveDatasourceBinding and matchPattern go as late-bound closures, and the module imports ObjectQL as a type only. Each stub keeps its name, signature, docblock and position. A1 measured: the one real-engine double, vi.spyOn(engine, 'getDriver') in engine-judge-filter.test.ts, still sees every call, and the rest are instance overrides of an unmoved member or whole-engine fakes. The cut is narrower than A1's proposal. resolveDatasourceBinding stays, because packages/spec/liveness/object.json and manifest.json (and docs/adr/0139) cite engine.ts#resolveDatasourceBinding, and both paths are forbidden to this dispatch. resolveEffectiveDatasource, resolveMappedDatasource and isSystemLedgerObject stay because their 1-4 line bodies are shorter than a host literal. A2 disproved: the ADR-0057 paragraph describes resolveDatasourceBinding step 3 and isSystemLedgerObject, which both stay, so no new anchor entry is owed or added. All six .d.ts are raw byte-identical, the export lists are identical, and the draft PR is Part of #25522 with skip-changeset. engine.ts goes from 23,881 to 23,807 lines. Proposed cut 3: Lifecycle init and health less init (checkDriversHealth, resolvePrimaryDatasource).",
"tests": "At head c70b6b5. (1) pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2 under os-verify-lock: VERDICT command-exit 0; JSON report: 466 files, 1,899 suites, 8,700 tests, 8,700 passed, 0 failed, 0 skipped. (2) pnpm --filter @objectstack/objectql typecheck under the lock: VERDICT command-exit 0, 'check:test-typecheck: OK — 39 file(s) / 233 error(s) / 64 pinned signature(s) held'. (3) Move proof by AST token (recursive getChildren leaves, params less this + return type + body): getDriver 206, resolveDatasourceFromMapping 168, matchPattern 54 tokens, all SAME; 428 tokens, 0 differ; every body line is the base line less 2 leading spaces (56/34/7 lines). Negative control: one changed token in resolveDatasourceFromMapping reports DIFFER. Class: 317 members at base and head, 314 unmoved byte-identical, 3 stubs keep docblock and signature byte-identical. Top level: 234/234 base statements byte-identical plus 1 new import. (4) .d.ts bar, ruling 6348891160, base turbo build at cc10e74 (14/14 tasks, 0 cached), head objectql build at c70b6b5 (dist/index.mjs carries readUnavailableDatasources x2, so it is the head build): index.d.ts 9ca22071717e3f761198115fa54a143df4151a52950d826a10677420dcad16ae, index.d.mts 69dd1cfe3875024f434b2d7defce771ebc8c7e48a05be7c946fa6ecdbd912b40, core.d.ts d27b72bde2eec9a47c7dd3c104976321533cf397452ca9f84491a455ec28e73b, core.d.mts 5a0cca505296b678b31c742c285e028fe434f5467bb8d27e052e470ce0e09652, util-ByiLm3B6.d.ts = .d.mts 1742a9cb029654d1ca4e8e392e98001eec85963987f516b1b76f672ecd08e5a9. Raw base = head on all six, raw diff 0 lines. Ruled normaliser (verbatim, double-quoted) = raw on all six. Single-quote spelling of the same class, base = head: index.d.ts c15106196eb2, index.d.mts a2d6d7b241e8, core d27b72bde2ee/5a0cca505296 (no unions), util bffd1b630dab. Positive control: util line 8412 'private matchPattern;' made public gives raw = ruled-normalised e1ebae28ec516d6480a51cf8551a7eeb62498e24d2409140e0199dcf4ecc34be (not equal to 1742a9cb) and single-quote normalised f715c98bfa40 (not equal to bffd1b630dab). Export lists from the built bundles: '.' 182 ESM = 182 CJS, './core' 54 = 54, sorted-list sha256 881616cc179189098182bd6b8a95701d9922f9677b786bc12e2d31c1adb0adaa and 393e806906e876c2e020aa96617d54050a35ae63cd483b67d8e968b7b5390f49 at both ends. (5) One-off mutations via scripts/ablation-replace.mjs (move-only, so no kept test and no ablation owed; vitest resolves src/, so no dist leg): matchPattern '.*' -> 'Z' (anchor 1 -> 0, blob f6252c183b12 -> df7bca74964b) turns datasource-mapping.test.ts 2 failed / 8 passed. getDriver's unavailableDatasources.get(...) -> undefined (blob -> b029b2fde4b1) turns datasource-unavailable.test.ts 4 failed / 14 passed with federated-binding-policy-denied-report.test.ts. The same mutation left datasource-mapping.test.ts 10/10 green (see out_of_scope_findings). Each run restored: blob == HEAD f6252c183b12 and git diff HEAD empty. test:repo was not run locally (CI Test Core runs it).",
"gates": "Local, on the real diff (2 files, +208/-97): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 56 families at c70b6b5 (stderr first line names the repo and the commit). All 56 were run at head, each exit code captured before any pipe; 53 exit 0. Three are NOT MEASURED: node scripts/check-engine-split-ratio.mjs --days 90 exit 2 (CANNOT COMPUTE: history starts 2026-09-15, inside the 90-day window); node scripts/check-plugin-teardown-shape.mjs --self-test exit 3 (pinned fixture commit not in this shallow clone); pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: no dist/ for the other packages; the export lists in tests (4) answer it for objectql). Reconciliation: dispatch-gates --ran exit 0, '56 derived famil(ies) accounted for — 54 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)'. It counts the exit-2 refusal as run, and this report counts it NOT MEASURED. Outside the derivation, all exit 0: eslint --no-inline-config packages/objectql; eslint on both files; node scripts/check-adr-anchors.mjs (base and head: 85 anchored files, 1,871 decision-letter citations, 52,481 citations across 6,594 files); node scripts/check-adr-symbol-anchors.mjs (2,384 anchors resolve); node scripts/check-nul-bytes.mjs; node scripts/check-platform-checklist.mjs --changed-from origin/main ('1 anchored file(s) in the change set, 14 anchor(s) judged, 0 lost'); pnpm --filter @objectstack/spec check:liveness (982 path#symbol pointers resolve; key-mention 753 asked, 752 anchored, 1 exempt). CI on PR #25636 head c70b6b5 at report time: Check Changeset success; No other open PR may claim the same issue success; Type Check (workspace, debt ledger, source gates, consumer gates), the Lint lanes (repo & tooling, CI release & engine, ESLint, docs & code guards, PM dispatch-gates, the scoped lanes), Governed Surface Queue Guard, Part-of PR must not also close its card, The card this PR closes must claim this branch, Check PR Size, Check Documentation Links: in_progress. Opt-in lanes skipped. Not waited on, per the contract.",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm (Clause-②: no)","mcp_calls": "10 — all read-only GitHub MCP, no write tool: issue_read x2 (get and get_comments on #25522); pull_request_read x6 (get #25615; get_files #25633, #25632, #25626; get #25636; get_check_runs #25636); list_pull_requests x2 (open PRs at start and before the PR)",
"api_writes": "2 relay strokes through scripts/pm/fleet-write/dispatch.mjs (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /issues/25636/assignees [sunhaolin] + POST /issues/25636/labels [skip-changeset]; run 40091238518 success; read-back 20,183 bytes sent = stored, identical; assignee listed; draft true and label skip-changeset confirmed by a later read. (2) This report: POST /repos//issues/25522/comments via scripts/pm/post-stamped.mjs. Not REST: one git push of commit c70b6b5 to the branch.",
"fixed_overhead": "pnpm install --frozen-lockfile in the fresh worktree: 27 s wall ('Done in 23.7s'). Turbo remote-cache pull: 0 s. turbo printed 'Remote caching disabled, using shared worktree cache', and the build closure of @objectstack/objectql (14 tasks) was 0 cached / 14 built, 196 s under the lock.",
"open_questions": [
{
"question": "Cut 2 narrowed (decided here, recorded for the seat): A1 proposed moving the whole Datasource routing row. resolveDatasourceBinding is cited by symbol as liveness evidence from packages/spec/liveness/object.json and manifest.json, and from docs/adr/0139. Card ask 3 wants path readers migrated in the same PR, and this dispatch forbids both paths. Was keeping it in the class the right call?",
"options": [
"A (taken) — Keep resolveDatasourceBinding, and move getDriver, resolveDatasourceFromMapping and matchPattern. Real business need: the split order the maintainer ruled (24586 A) advances at no cost to the ledgers' truth. Long-term soundness: the ledger pointers keep naming the code they quote, and routing stays the single resolver the ledgers verify. Preventing AI errors: no ledger points at a stub that delegates elsewhere, the shape #12516 calls rot in range. No sprawl: no packages/spec or ADR edit and no new gate. Cost: engine.ts shrinks by 74 lines, not about 150.",
"B — Move resolveDatasourceBinding too and leave both ledger pointers at the stub. Both gates stay green (the stub still names the symbol and engine.ts still mentions defaultDatasource), but the evidence the ledgers quote moves out of the cited file. Long-term soundness: a pointer that no longer points at its evidence. Preventing AI errors: worse, a silent green over moved evidence.",
"C — Move it with a packages/spec ledger repoint in the same PR. This needs the seat to lift the packages/spec ban for this cut, and it couples a spec-lane edit into an engine slice, the reason A3 set Roll-up summaries aside."
],
"recommendation": "A, taken on the long-term-soundness axis: ledger evidence must stay where the code is. If the seat wants resolveDatasourceBinding moved later, do it as C in a cut that is cleared for packages/spec."
}
],
"out_of_scope_findings": [
"carrier: none (承接者:无) · packages/objectql/src/datasource-mapping.test.ts 'when the connect verdict is known, the error says WHY rather than "not registered"' asserts /analytics database unreachable|ERR_DATASOURCE_UNAVAILABLE|broken/. The fallback 'mapped ... is not registered' message also contains 'broken', so the case stays green with the unavailableDatasources branch deleted (measured by mutation). datasource-unavailable.test.ts pins that branch (4 red under the same mutation), so no behaviour is unpinned · weak assertion, not a defect class a/b/c · noted in the PR's Acceptance notes, not filed",
"carrier: the seat · the md5 abff5f852c8fd09b79ec0623439aa4f0 in the dispatch matches the quoted SKILL.md paragraph (from 「每个方案必须沿四条固定评估轴分析」 through 「交维护者拍板。」), not the whole file (whole file 872a170a0ba15ac248b85b2a9be278a0 at e073455) · noted, not filed"
],
"line_budget": "305 changed lines (+208 / -97) over 2 files, under the 3,000 human-merge line; engine.ts 23,881 -> 23,807; engine-datasource-routing.ts 185",
"files_changed": [
"packages/objectql/src/engine-datasource-routing.ts (added)",
"packages/objectql/src/engine.ts (modified)"
],
"seam_table": "In the PR body: 41 sections measured at origin/main cc10e74. engine.ts 23,881 lines; 8,270 (34.6%) from the last 30 days; 126 commits in 30 days, 35 in 7; class 317 members. The Datasource routing row is 343 lines with 0 from the last 30 days, and 266 lines at head after the cut.",
"proposed_next_cut": "Cut 3: Lifecycle init and health less init. It moves checkDriversHealth (34-line body) and resolvePrimaryDatasource (37-line body): public with explicit return types, 0 lines from the last 30 days, no this.FIELD.delete/insert/update( site, no static, no engine.ts# path reader, no spy or instance double (measured repo-wide). Host: drivers and _registry as getters; isSystemLedgerObject and resolveDatasourceBinding as late-bound closures.",
"deviations": [
"Scope narrowed against A1's proposal (resolveDatasourceBinding, resolveEffectiveDatasource, resolveMappedDatasource and isSystemLedgerObject stay); reasons in open_questions[0] and the PR body.",
"A2 disproved: no scripts/adr-anchors entry added (no moved body is described by the engine.ts entry's paragraph). Decision-letter count 1,871 at base and head.",
"Commit trailers: the model-free pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md and os-dev.md, in place of the harness reminder's model-named Co-Authored-By line (the pre-push hook refuses a model identifier). PR body footer: AGENTS.md's session-URL form, in place of the harness's footer lines.",
"Shared .git state: the A4 check fetched 14 open-PR heads with git fetch --depth=80, which wrote a 2026-10-23 shallow boundary (b62ca78) onto main's own ancestry in the shared .git/shallow. That truncated history for every worktree for some minutes. Repaired in the same run with git fetch --shallow-since=2026-09-15 origin main: the only boundary is now 99d20cf (2026-09-15), deeper than the 2026-09-16 boundary found at start, and 126 commits are visible in the 30-day window. The later re-check of new PRs used the API's file lists.",
"Worktree: the shared checkout at /home/user/objectstack held this branch at start, so it was detached (git checkout --detach, same commit cc10e74) to let the worktree take the branch. It stays detached.",
"Not merged forward: main moved two commits (#25621, #25620) since cc10e74, and neither touches packages/objectql/**. No merge, per os-dev's 'merge main only on conflict, main-caused red or dequeue'. AGENTS.md §10's 'pull main before opening a PR' was not applied; CI builds the merge ref.",
"A3, narrowed and declared: no direct dependant was type-checked locally. Every moved member is private, and all six published declaration files are byte-identical. CI's TypeScript Type Check lanes cover them.",
"No baseline objectql test run (head only); head suite 8,700/8,700."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
ACCEPT → PR #25636 comment 6385311045 (cut 2, head
c70b6b5df4; landing in the same act) ·domain:serverseat 2 ·session_01JVTd3PprStGa26aez5omLBGenerated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Release:
domain:serverseat 2 ·sunhaolin· sessionsession_01JVTd3PprStGa26aez5omLB· 2026-10-24T15:04Z · cause: cut 2 landed (Part of #25522) · destination:pm:queue, unassigned, for cut 3Landed: PR #25636 →
702b44f8c(#25522 cut 2)merged: true, merge commit702b44f8c35832f8fa2e6bc751ae429d50b5d92b, merged 2026-10-24T15:01:15Z through the merge queueorigin/main702b44f8cis an ancestor oforigin/main(dc6c7ee738), single parent (squash)gh-readonly-queue/main/*head for PR 25636 remainsgetDriver,resolveDatasourceFromMapping,matchPattern) lives inpackages/objectql/src/engine-datasource-routing.ts.resolveDatasourceBindingstays in the class (the liveness ledgers and ADR-0139 cite it by symbol and path), and so do the 1–4-line members shorter than a host literal.engine.tsis 23,807 lines onorigin/main.initfor cut 3:checkDriversHealth(34-line body) andresolvePrimaryDatasource(37-line body), both public with explicit return types, 0 lines from the last 30 days, no static read, nothis.FIELD.delete/insert/update(site, no path reader, spy or instance double (PR refactor(objectql): move the datasource-routing bodies out of engine.ts into engine-datasource-routing.ts (#25522 cut 2) #25636's body). Still waiting: Roll-up summaries (spec-coupled); the Datasource registry (U = 3).pm:dispatched→pm:queue, assignee cleared, in this act. The cloud sessionsession_017jiggF9SoTgeCHgPWuGdU9is archived.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1 · cut 3
Session:
session_01JVTd3PprStGa26aez5omLBAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25522-objectql-engine-cut-3Worktree:
objectstack-issue-25522Domain:
domain:serverSeat:
domain:server#2File surface:
packages/objectql/src/**(engine.tsand the new seam module of cut 3; the cut-2 dev proposes Lifecycle init and health, lessinit:checkDriversHealth,resolvePrimaryDatasource),scripts/adr-anchors/**only if a moved member is cited, test files that spy on or double a moved member.skip-changesetunder ruling 6348891160. ⛔ Nodocs/adr/**, ⛔ nopackages/spec/**(stop on breach; explain in the report)Container & model:
M,mode:cloud(maintainer: 「并发加到5,可以用云卡片」; threemode:subagentdevs already share this seat's container),model: TIER_DEFAULT(dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6385780360
Serial constraints cleared: cut 2 (PR #25636) merged as
702b44f8c; no open PR touchespackages/objectql/src/engine.ts(every open PR's file list read this fire). #25649's dispatch is barred fromengine.ts.Premise: re-read on
origin/maindc6c7ee738+:engine.tsis 23,807 lines;checkDriversHealth(opts?): Promise<DriverHealth[]>andresolvePrimaryDatasource(): PrimaryDatasourceVerdictare in the class with explicit return types. The net-line rule set on #25521 (an area moves only when the file's net line count drops) applies to this series too.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
os-dev-report
{
"issue": 25522,
"status": "done",
"branch": "claude/issue-25522-objectql-engine-cut-3",
"pr": "#25686",
"session": "session_0161WE4VX4T7VT66M6pYcVjD — this cloud run's own session (mode:cloud), on the Claude-Session: trailer of commit 7b61487; dispatched by domain:server seat 2 session_01JVTd3PprStGa26aez5omLB",
"premise_still_valid": true,
"summary": "Cut 3 moves the bodies of the public ObjectQL#checkDriversHealth and #resolvePrimaryDatasource unedited into packages/objectql/src/engine-lifecycle-health.ts through LifecycleHealthHost: drivers and _registry as getters, isSystemLedgerObject and resolveDatasourceBinding as late-bound closures; the module imports ObjectQL as a type only. Each stub keeps its name, signature (async included), docblock and position; init stays (inferred return type). Every premise from cut 2's measurement held on origin/main 24d350b: explicit return types, 0 lines from the last 30 days, no U site, no static read, no engine.ts# path reader, no spy or instance double on a real engine. engine.ts goes from 23,807 to 23,755 lines (net -52, the seat's net-line rule met). All six published .d.ts are raw byte-identical, export lists identical, draft PR is Part of #25522 with skip-changeset; no ADR anchor entry owed (A2), decision-letter count 1,847 at base and head.",
"tests": "At head 7b61487. (1) pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2 under os-verify-lock: VERDICT command-exit 0; JSON report 466 files, 1,899 suites, 8,700 tests, 8,700 passed, 0 failed, 0 skipped. Includes engine-driver-health.test.ts (7 cases), engine-primary-datasource.test.ts, engine-driver-eviction.test.ts and datasource-unavailable.test.ts, which call both moved bodies through the stubs. (2) pnpm --filter @objectstack/objectql typecheck under the lock: VERDICT command-exit 0, 'check:test-typecheck: OK — 39 file(s) / 233 error(s) / 64 pinned signature(s) held'. (3) A3: pnpm --filter '@objectstack/runtime^...' --filter '@objectstack/service-datasource^...' build then pnpm --filter @objectstack/runtime --filter @objectstack/service-datasource typecheck, both under the lock, VERDICT command-exit 0 each; runtime tsc --noEmit + check:test-typecheck OK, service-datasource tsc --noEmit done, 0 'error TS' lines. These are the two packages outside objectql that name the moved members (runtime's http-dispatcher /ready handler calls both; service-datasource names checkDriversHealth in comments). (4) Move proof by AST token (recursive getChildren leaves; params less this, return type, async modifier, body): checkDriversHealth 251 tokens SAME, resolvePrimaryDatasource 218 tokens SAME; every body line is the base line less 2 leading spaces (36/39 lines with braces). Negative control: one changed token in the moved resolvePrimaryDatasource reports DIFFER. Class: 317 members at base and head, 315 unmoved byte-identical (full text), 2 stubs keep docblock and signature byte-identical. Top level: 234/235 base statements byte-identical; the other is the spec/system import less PLATFORM_PROVIDED_OBJECT_NAMES; 1 new import. (5) .d.ts bar, ruling 6348891160, base = objectql built with engine.ts restored from 24d350b (tree only, then git checkout HEAD -- and git status clean), head = objectql built at 7b61487, same dependency closure; head dist/index.mjs carries readRegistry x2, base x0. Raw sha256 base = head on all six, raw diff 0 lines each: index.d.ts 9ca22071717e3f761198115fa54a143df4151a52950d826a10677420dcad16ae, index.d.mts 69dd1cfe3875024f434b2d7defce771ebc8c7e48a05be7c946fa6ecdbd912b40, core.d.ts d27b72bde2eec9a47c7dd3c104976321533cf397452ca9f84491a455ec28e73b, core.d.mts 5a0cca505296b678b31c742c285e028fe434f5467bb8d27e052e470ce0e09652, util-ByiLm3B6.d.ts = .d.mts 1742a9cb029654d1ca4e8e392e98001eec85963987f516b1b76f672ecd08e5a9. Ruled normaliser (verbatim one-liner, double-quoted) = raw on all six, base = head. Single-quote spelling of the same class, base = head: index.d.ts c15106196eb2, index.d.mts a2d6d7b241e8, util bffd1b630dab. Positive control, same run: util line 8318 'private isSystemLedgerObject;' made public gives raw = ruled-normalised c944677ee7e7c23a9ecabb6466a616a9f993d3e41fbee3b854527e039c7d19cd (not 1742a9cb) and single-quote normalised e86dbb567ef0 (not bffd1b630dab). Export lists from the built bundles: '.' 182 ESM = 182 CJS, './core' 54 = 54, sorted-list sha256 881616cc179189098182bd6b8a95701d9922f9677b786bc12e2d31c1adb0adaa and 393e806906e876c2e020aa96617d54050a35ae63cd483b67d8e968b7b5390f49 at base and head. (6) No mutation run: move-only, no tested behaviour changed, so no ablation is owed. test:repo was not run locally (CI Test Core runs it).",
"gates": "Local, on the real diff (2 files, +163/-72): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 56 families at 7b61487 (stderr first line names the repo and the commit). All 56 were run at head, each exit code captured before any pipe; 53 exit 0 on the first pass. node scripts/check-engine-split-ratio.mjs --days 90 first exit 2 (CANNOT COMPUTE, shallow history), then exit 0 after the remedy it prints (git fetch --shallow-since=2026-07-19 origin main; ratio 98.1%). Two NOT MEASURED, CI runs both: node scripts/check-plugin-teardown-shape.mjs --self-test exit 3 (pinned fixture commit absent from this shallow clone); pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: 54 export entries of other packages have no dist/; tests (5) export lists answer it for objectql). Reconciliation: dispatch-gates --ran exit 0, '56 derived famil(ies) accounted for — 54 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)'. Outside the derivation, all exit 0: pnpm exec eslint --no-inline-config packages/objectql (the lint family, touched package); eslint --no-inline-config on both files; node scripts/check-adr-anchors.mjs at base (detached worktree at 24d350b) and head: 85 anchored files, 1,847 decision-letter citations, 52,546 citations (6,610 files base, 6,611 head: the new module); node scripts/check-adr-symbol-anchors.mjs (2,384 anchors resolve); node scripts/check-platform-checklist.mjs --changed-from origin/main ('1 anchored file(s) in the change set, 14 anchor(s) judged, 0 lost'); pnpm --filter @objectstack/spec check:liveness. CI on PR #25686 head 7b61487 at report time: Check Changeset success; No other open PR may claim the same issue success; Type Check (workspace, debt ledger, source gates, consumer gates), the Lint lanes (repo & tooling, CI release & engine, ESLint, docs & code guards, PM dispatch-gates, three scoped lanes), Governed Surface Queue Guard, Part-of PR must not also close its card, The card this PR closes must claim this branch, No other open PR may claim the same single-writer path, Check PR Size, Check Documentation Links, Flag docs affected by code changes: in_progress. Opt-in lanes skipped. Not waited on, per the contract.",
"dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm (Clause-②: no)","mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read went through the gh CLI's REST reads (card, comments, ruling 6348891160, PR #25636 body, open-PR lists and file lists, PR #25686 read-back and check-runs)",
"api_writes": "2 relay strokes, executed as objectstack-fleet[bot]. (1) pr_create through scripts/pm/fleet-write/dispatch.mjs (POST /repos/objectstack-ai/objectstack/dispatches, run 40110833014 success): POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /issues/25686/assignees [sunhaolin] + POST /issues/25686/labels [skip-changeset]; read-back 13,728 bytes sent = stored, identical; assignee listed; draft true, label skip-changeset, 2 files +163/-72 confirmed by a later read. (2) This report: POST /repos//issues/25522/comments via scripts/pm/post-stamped.mjs. Not REST: two git pushes (the empty-branch probe at 24d350b, then commit 7b61487).",
"open_questions": [],
"out_of_scope_findings": [],
"line_budget": "235 changed lines (+163 / -72) over 2 files, under the 3,000 human-merge line; engine.ts 23,807 -> 23,755 (net -52); engine-lifecycle-health.ts 143",
"files_changed": [
"packages/objectql/src/engine-lifecycle-health.ts (added)",
"packages/objectql/src/engine.ts (modified)"
],
"proposed_next_cut": "Cut 4: 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 (repo-wide). 18 lines from the last 30 days (16 + 2). Host: three getters (realtimeService, logger, _registry), no closures. Priced against the net-line rule: 113 body lines out, about 2 x 7 stub lines and 3 import lines in, engine.ts drops by roughly 95. assertWriteAllowed stays (packages/spec/liveness/datasource.json cites engine.ts#assertWriteAllowed); setRealtimeService and listUnavailableDatasources are 1-2-line bodies. Still waiting: Roll-up summaries (spec-coupled), Datasource registry (U = 3), Related-record expansion (expandRelatedRecords reads the private static MAX_EXPAND_DEPTH).",
"deviations": [
"Commit trailers: the model-free pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md and os-dev.md, in place of the harness reminder's model-named Co-Authored-By line. PR body footer: AGENTS.md's session-URL form.",
"Not merged forward: main moved five commits since 24d350b (to b2909fd); the only one under packages/objectql/ is #25657, packages/objectql/package.json's zod range, no engine.ts line. No merge, per os-dev ('merge main only on conflict, main-caused red or dequeue'); CI builds the merge ref. The .d.ts and test readings are on the 24d350b dependency tree.",
"Shared .git state: history was deepened twice in this container (git fetch --shallow-since=2026-09-15, then --shallow-since=2026-07-19, the remedy check-engine-split-ratio prints). Both only deepen; the container is this session's alone.",
"The base .d.ts build restored engine.ts from 24d350b inside this worktree (git restore --source, tree only) instead of a second full worktree build; restored with git checkout HEAD -- and verified by git status --porcelain empty before the head build.",
"PR activity subscription: not armed. os-dev.md's dispatch contract overrides the platform's auto-subscribe posture; delivery ends at the draft PR and this report. No pr_ready, no auto-merge, no queue."
]
}
Generated by Claude Code