Skip to content

refactor(objectql): move 36 hand-series private docblocks out of engine.ts with the codemod's third pass (slice 1 of 2) - #30341

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-7wiz8y
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-7wiz8y

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

Refs #30053

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:scripts/codemod-split-engine.mjs 加了第三遍 --hand-docs:手写系列([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 等)私有桩的 docblock 从 engine.ts 的类上搬到手写模块里它调用的那个函数上,替换原来的占位注释;公有 / protected 的 docblock 留在类上。本 PR 是两片中的第一片:8 个手写模块、36 块、929 行。生成物未手改。
  • 为什么改:维护者在 refactor(objectql): generate the engine.ts section split with a deterministic codemod #30012 上说「我觉得文件还是太长,还有进一步的拆分优化空间吗」「可以后续立卡处理」「合并之后再继续」。整卡约 4,100 行改动,超过 3,000 行线,所以席位定为拆两个串行 PR、不申请冻结窗口。
  • 风险与回滚:只搬注释。撤销证明逐字节还原 base engine.ts 和 21 个手写模块;公有 .d.ts 相等;objectql 测试 base 550 文件 / 10,951 = head;回滚就是 revert。
  • 先看:① 下方「留在类上的」表;② engine.ts 顶部被剪掉的 5 个 import 绑定(只被搬走的 docblock 的 {@link} 引用);③ 任一手写模块头部新增的一段说明。
  • 两分钟验证:pnpm install --frozen-lockfile 后运行 node scripts/codemod-split-engine.mjs --hand-docs --verify --base a26abbc6,应看到 36 moved (929 lines) across 8 module(s)、13550 -> 12618 lines,退出码 0;--self-test 105 例通过。
  • 需要你做的:改动共 2,573 行(未超 3,000 行线),本 PR 保持草稿,按席位安排落地。第二片(其余 10 个模块,Fixes #30053)在本 PR 合并后从同一分支名接着开。

What changes

  • scripts/codemod-split-engine.mjs: a third pass, --hand-docs. The hand series moved its bodies out of engine.ts before the codemod existed and kept every docblock on the class; each hand-module function carries the placeholder /** The body of \ObjectQL#x`; the method's docblock there is its contract. */`. The codemod's own rule moves a private method's docblock with its body and keeps a public or protected one on the class. This pass applies that rule to the hand series and touches nothing else.
    • Which stubs. A method whose body opens with a hand marker: [#25522 cut N] (83), [#27495] (2) or the untagged The body lives in of serveReferenceNames (1). 86 in all.
    • The move. A private stub's docblock leaves the class and replaces its function's placeholder, one level out (the hand series re-indented every body it moved, so the functions stand at column 0). The stub's marker gains , its docblock with it, the phrase the codemod's own stubs use. The module's header docblock gains one paragraph saying private docblocks moved here, because each header says the docblock stays on the class.
    • The import prune. noUnusedLocals counts a JSDoc {@link X} as a read, so five engine.ts import bindings went unused once their docblocks moved: RelatedFieldBinding, collectReferenceTraversals, optionVisibilityReadsPermissions, readsPermissionPredicate and READABLE_IDS_MAX_CHAIN_DEPTH. The pass prunes them with the first pass's pruneImports. The last one was a whole import type that existed only for those links, so it goes with the two // lines directly above it (a new dropAttachedComments option; the first pass keeps its default and its output is unchanged).
    • Slices. --modules a.ts,b.ts moves only the named modules' stubs, and a stub already moved is skipped, so the next slice runs on this one's output.
    • The proof. It undoes every move in the head and in the base (each docblock back on its stub, re-indented; the placeholder back; the marker phrase and the header note out) and requires the two to be equal, engine.ts and each hand module byte for byte. The import prune is recomputed from the head and applied to the base, and every pruned name must be linked by a moved docblock. A base no slice touched undoes to itself, so against main this is "the undo rebuilds the base"; against a base an earlier slice landed in, it proves only the new slice. --hand-docs --verify --base <ref> re-proves a tree on disk.
    • --self-test: 105 cases in 8 batteries (was 86 in 7). The new battery "hand-series docblocks (third pass)" (floor 19) covers the verdicts, the move, the marker, the header note, determinism, slices composing, the prune, and feeds the proof what it must refuse: one character edited in a moved docblock, one edited elsewhere in a hand module, a moved docblock dropped, a staying docblock dropped, a public docblock moved, a marker over a docblock still on the class, a missing header note, a dropped binding no moved docblock links, and an unknown --modules name.
  • The generated slice. --hand-docs --modules <the 8 below> --write on main a26abbc6, unedited (the branch merged main and its tree equals a fresh --write there).

What moved in this slice (8 modules, 36 docblocks, 929 lines)

Hand module Docblocks Lines Before → after
engine-secret-internal-fields.ts 8 276 605 → 878
engine-master-detail-related.ts 4 184 512 → 697
engine-readable-ids-permission-formula.ts 7 171 362 → 531
engine-delete-cascade.ts 5 169 498 → 667
engine-execution-plumbing.ts 4 56 128 → 185
engine-migration-flags.ts 3 32 295 → 329
engine-datasource-routing.ts 3 25 185 → 212
engine-package-registration.ts 2 16 212 → 231

packages/objectql/src/engine.ts: 13,550 → 12,618 lines.

What stays on the class

Stubs Why
20 public stubs (validate, count, execute, resolveSecret, checkDriversHealth, the compatibility API, …) the docblock is the contract and stays on the facade
validationMessageContext its function already carries a docblock with more than the placeholder (an ADR-0029 D9.2a note); merging two docblocks is an edit, not a move
noteAdmittedValueShapeViolation it has no docblock

The second slice

10 modules, 28 docblocks, 858 lines: engine-count-aggregate.ts, engine-driver-options.ts, engine-execute-transactions.ts, engine-file-reference-hydration.ts, engine-hook-dispatch.ts, engine-query-lowering.ts, engine-realtime-publish.ts, engine-reference-name-visible.ts, engine-referential-integrity.ts, engine-validation-messages.ts. The plan on this head prints exactly that list (--hand-docs with no --modules), and its in-run proof against this slice passes. It opens after this PR merges and carries Fixes #30053.

Verification

All at head b09479c5 unless stated.

  • Proof. node scripts/codemod-split-engine.mjs --hand-docs --verify --base a26abbc6: exit 0. 36 moved (929 lines) across 8 module(s), 0 already moved at base; engine.ts 13550 -> 12618 lines; undoing every move rebuilds the base, undone the same way, for engine.ts and its 21 hand module(s) byte-for-byte, once the 5 import binding(s) only a moved docblock linked are pruned.
  • Determinism. The head's script, run with --write in a separate worktree at a26abbc6, writes engine.ts and the 8 modules byte-identical to the committed head (cmp, all 9), output tree sha256 7883ed99…8ea5.
  • .d.ts. packages/objectql/dist built at base a26abbc6 twice and at head twice. Base 1 = base 2 and head 1 = head 2, byte for byte. Base against head: core and index (.d.ts and .d.mts) are byte-identical; util-HASH has 193/193 statements and 334/334 private members, and its public surface (each class's private members removed with their docblocks) is EQUAL. The raw difference is the 929 lines of moved private docblocks (tsc emits a private member's docblock). Control: dropping one public docblock from the head's .d.ts is caught (DIFFERS).
  • Ablation. Three single-line ablations through scripts/ablation-replace.mjs, each restored to the HEAD blob: the per-module comparison off → "one edited character elsewhere in a hand module fails" goes red (this ablation first stayed green, which is why that case exists); the engine.ts comparison off → "one edited character in a moved docblock fails" and "a staying docblock dropped from the class fails" go red; the pruned-name link check off → "a binding the head dropped that no moved docblock links fails" goes red.
  • Suites. objectql test: base a26abbc6 550 files / 10,951 passed, head 550 / 10,951. objectql typecheck (tsc + check:test-typecheck): exit 0.
  • Readers of these files by path. core second-object-read-exposure.pin.test.ts and row-serving-door-exposure.pin.test.ts (7/7), types driver-error-classification.callers.test.ts (11/11), check-facade-delegation-only (OK, registry unchanged), check:adr-anchors (OK; engine.ts still names ADR-0057, ADR-0067 and ADR-0119), eslint on every changed file: exit 0.
  • Gates. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 72 commands, each run after a full turbo run build --filter='!@objectstack/docs' (exit 0). All 72 exit 0; --ran: 72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN.

Acceptance notes

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes on the changed files.
  • 4. One issue, one branch off an up-to-date main, one pull request. (the designated thread branch, as the Claim records; first of two slices)
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ

…ne.ts with the codemod's third pass (slice 1 of 2)

scripts/codemod-split-engine.mjs gains --hand-docs: a private hand-series
stub's docblock moves onto the function in its hand module (replacing the
placeholder, one level out), the stub's marker says so, the module header
gains one note; public and protected docblocks stay on the class. The
proof undoes every move and rebuilds the base engine.ts and hand modules
byte for byte. This slice runs it on 8 hand modules (929 docblock lines).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ
…n earlier slice landed in

The proof now undoes every move in the head and in the base and compares
the two, so the second slice's in-run proof holds on the first slice's
output and against the unsliced base alike. One self-test case pins it.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ
…ed, and prove the prune

noUnusedLocals counts a JSDoc {@link X} as a read, so five engine.ts
import bindings went unused once their docblocks moved. --hand-docs now
prunes them (and the // lines directly above a declaration that goes
whole); the proof recomputes the prune from the head and requires every
pruned name to be linked by a moved docblock. Re-run on main a26abbc:
the tree equals a fresh --write there.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ
…cs proof

An ablation of the per-module comparison stayed green: every case so far
edited a moved docblock, which the engine.ts half catches. One case now
edits a body byte in a hand module.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ
…agged marker as a hand stub

Its marker is 'The body lives in' with no tag, so the pass saw 85 of the
86 hand stubs. The fixture's beta stub now carries the untagged form.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYHBS7P5hkUQrNHkHZ
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tooling labels Nov 5, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-bill · session_01Utp6CYHBS7P5hkUQrNHkHZ

os-dev report: #30053 slice 1 of 2, PR #30341 (draft), head b09479c5

  • Branch claude/project-thread-7wiz8y; base main a26abbc6 (merged in); Claim 6650363315.
  • Size: 11 files, +1,563 / −1,010 = 2,573 changed lines (< 3,000). The whole card measured ~4,100, so the seat split it in two serial PRs (no freeze window).
  • Codemod third pass --hand-docs (--modules slices): 86 hand stubs (83 [#25522 cut N], 2 [#27495], 1 untagged serveReferenceNames); this slice moves 36 private docblocks, 929 lines, from 8 modules. Stay: 20 public, validationMessageContext (its function already carries a richer docblock), noteAdmittedValueShapeViolation (none).
  • Five engine.ts import bindings that only a moved {@link} read are pruned (noUnusedLocals), plus the two // lines above the whole import type { READABLE_IDS_MAX_CHAIN_DEPTH }.
  • engine.ts 13,550 → 12,618.
  • Proof: --hand-docs --verify --base a26abbc6 exit 0 (undo of head = undo of base, engine.ts and 21 hand modules byte-exact; 5 pruned names each linked by a moved docblock). Determinism: the head script run with --write in a separate worktree at a26abbc6 writes files byte-identical to the head (all 9, cmp).
  • .d.ts: base ×2 and head ×2 builds stable; core/index byte-identical; util public surface EQUAL, raw diff = the 929 moved private docblock lines; control (one public docblock dropped) caught.
  • Ablation ×3 (module comparison, engine.ts comparison, pruned-name link check): each turns its case red, restored to the HEAD blob. The first module ablation stayed green, so a case pinning a non-docblock module edit was added.
  • --self-test: 105 cases in 8 batteries (new battery floor 19).
  • Suites: objectql test base 550 files / 10,951 = head; objectql typecheck 0; eslint on the changed files 0; core by-path pins 7/7; types callers 11/11; check-facade-delegation-only OK; check:adr-anchors OK.
  • Gates: dispatch-gates --commands 72, all exit 0 after a full build; --ran 72/72, 0 NOT-MEASURED.
  • Slice 2 (after this merges, same branch name, Fixes #30053): 10 modules, 28 docblocks, 858 lines; its in-run proof on this head passes.
  • Changeset: patch @objectstack/objectql (Clause-②: no, Metadata-protocol: none). Not assigned, no review requested.
  • Write budget: 2 GitHub writes (relay pr_create with an identical 10,719-byte read-back, and this report). No GitHub MCP write.

Report taken 2026-11-05T06:35Z.


Generated by Claude Code

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql, touching 38 documentable anchor(s). ⚠️ 7 changed file(s) yielded no anchor (packages/objectql/src/engine-datasource-routing.ts, packages/objectql/src/engine-delete-cascade.ts, packages/objectql/src/engine-execution-plumbing.ts, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/permissions/system-context.mdx (via buildSession (symbol, a method of class ObjectQL), encryptSecretFields (symbol, a method of class ObjectQL), recordReferenceCheckElevation (symbol, a method of class ObjectQL), resolveOneHopRelated (symbol, a method of class ObjectQL), stripSearchCompanionFromRead (symbol, a method of class ObjectQL))
  • content/docs/protocol/kernel/lifecycle.mdx (via registerPlugin (symbol, a method of class ObjectQL))
What this run could not see
  • 7 changed file(s) yielded no anchor (packages/objectql/src/engine-datasource-routing.ts, packages/objectql/src/engine-delete-cascade.ts, packages/objectql/src/engine-execution-plumbing.ts, …) — pages documenting those are invisible to this run
  • 1 anchor(s) matched too much of the corpus to be a work list: ObjectQL (symbol, 80 pages)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 21 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json bfca0efb79ac5df2049f392cdecd3bbeeea9ec61 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 3ff9df97a33a575420bfa5b46d48790417fd1fde — the merge of head b09479c5ddb37e675eeb246ea187ed0adfe8fb25 into base bfca0efb79ac5df2049f392cdecd3bbeeea9ec61, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3ff9df97a33a575420bfa5b46d48790417fd1fde && git checkout 3ff9df97a33a575420bfa5b46d48790417fd1fde
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bfca0efb79ac5df2049f392cdecd3bbeeea9ec61 b09479c5ddb37e675eeb246ea187ed0adfe8fb25 && git checkout -B drift-repro bfca0efb79ac5df2049f392cdecd3bbeeea9ec61 && git merge --no-ff b09479c5ddb37e675eeb246ea187ed0adfe8fb25

node scripts/docs-audit/affected-docs.mjs --json bfca0efb79ac5df2049f392cdecd3bbeeea9ec61

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs bfca0efb79ac5df2049f392cdecd3bbeeea9ec61 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-bill · session_01Utp6CbPxYq1wQmUNWvMZkC

Flake note · 2026-11-05T07:14Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#3 · os-bill · session_01Utp6CbPxYq1wQmUNWvMZkC

席位核对

ACCEPT · head b09479c5ddb37e675eeb246ea187ed0adfe8fb25 · card #30053 (claim 6650363315, amendment 6650390462), slice 1 of 2 · 2026-11-05T07:25Z

  • Shape: draft PR to main, author objectstack-fleet[bot] (relay), attribution block then Refs #30053 (slice 2 carries Fixes #30053, as the amendment set). 11 files, +1567 −1010. check-governed-merges.mjs --pr 30341: NOT governed, 2577 changed lines ≤ 3000 ⇒ ordinary queue landing.
  • Declarations: Clause-②: no, Metadata-protocol: none, matching the claim; changeset @objectstack/objectql patch (as refactor: facade ObjectRepository and ScopedContext in engine.ts with the same codemod (about 700 lines), as the ObjectQL class already is #30052's). Neither widening nor narrowing ⇒ the seat's own review of record.
  • Seat review: comment-only move. Private stubs' docblocks leave engine.ts for the hand modules' functions, public and protected ones stay on the facade; the five pruned import bindings were read only by moved {@link}s (noUnusedLocals), and the proof requires each pruned name to be linked by a moved docblock. The undo proof rebuilds base engine.ts and all 21 hand modules byte for byte; built public .d.ts equal base↔head with a control that catches one dropped public docblock; objectql 550 files / 10,951 tests at base = head. The generated slice is an unedited --write (determinism re-run, 9/9 cmp). {@link} targets inside moved text are left as written, noted in the PR, read by no gate.
  • Gates (check-runs on this head): 48 runs, 35 success, 13 skipped, 0 failed. Live E2E UI failed once on attempt 1 (studio-customize-journey.spec.ts:121, one ECONNRESET), flake note 6652122573, re-ran once, attempt 2 green. Skips read by name (path-gated, opt-in harnesses): check-expected-skips.mjs cannot run in this container (yaml not installed).
  • Landing: ready + auto-merge by the seat. Slice 2 opens from the same branch name after this merges.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 07:26
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 07:26
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit f672e0d Nov 5, 2026
73 of 74 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-7wiz8y branch November 5, 2026 07:52
This was referenced Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant