Repository navigation
refactor(objectql): ObjectQL#delete's body moves into its facet (codemod R10 puts the module on the statics route) - #31764
Conversation
…le on the statics route A body --members moves into a facet module the first pass wrote off the statics route, and that reads a non-public static, now takes the route the first pass would have given the module: the one type-only ObjectQL import becomes the routed pair, the host interface types its members by ObjectQLClass, and the header gains the statics paragraph. The undo is the inverse rewrite under the same byte-exact proof. New self-test battery (18 cases). Claude-Session: https://claude.ai/code/session_01ADHkmNmrFUKGH6LP8Jj8ZV Co-authored-by: Claude <noreply@anthropic.com>
node scripts/codemod-split-engine.mjs --members delete --write: the body moves unedited into engine-delete-and-aggregate.ts, which R10 puts on the statics route for its ObjectQL.REFERENCE_PROBE_BATCH read. The stub keeps its signature; the bare this the body hands on reads this.facade (R1). The delete row leaves scripts/facade-delegation-registry.json. Claude-Session: https://claude.ai/code/session_01ADHkmNmrFUKGH6LP8Jj8ZV Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmNmrFUKGH6LP8Jj8ZV Co-authored-by: Claude <noreply@anthropic.com>
… site into the facet Claude-Session: https://claude.ai/code/session_01ADHkmNmrFUKGH6LP8Jj8ZV Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 42 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 21 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 92fae81695a139cde1de16b2977891640863a0c7 && git checkout 92fae81695a139cde1de16b2977891640863a0c7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9e1f1f90d5a62c81b6d1561d4baa7c822cc88b33 2a5a3a3dbeeb8326ee7daa1d69c65482ccb8cc3f && git checkout -B drift-repro 9e1f1f90d5a62c81b6d1561d4baa7c822cc88b33 && git merge --no-ff 2a5a3a3dbeeb8326ee7daa1d69c65482ccb8cc3f
node scripts/docs-audit/affected-docs.mjs --json 9e1f1f90d5a62c81b6d1561d4baa7c822cc88b33
|
|
domain:server#1 · os-steve · session_01ADHkmPF1skfu2kx89BEXZi 席位 ACCEPT · head
|
Requested by Steve · project thread
Refs #30020
Clause-②: no
Metadata-protocol: none
维护者速读
ObjectQL里delete(删除记录)的方法体原封不动地搬进同一节的 facet 模块engine-delete-and-aggregate.ts,类上只留一行转调;搬移工具 codemod 补了一条把模块切到“静态成员转发”路线的规则(R10),并删掉门禁登记表里delete这一行例外。engine.ts的既定顺序第五步(E4)。delete体里读了一个私有静态常量,目标模块原先不走静态转发路线,工具拒绝搬;补上 R10 后由工具确定性生成,不手搬。.d.ts逐字节不变,同样的语句按同样顺序执行;undo 证明逐字节还原 base。风险在删除路径(级联、回收站)全部经过它,dogfood 全量已跑绿。回滚即整体 revert。packages/objectql/src/engine-delete-and-aggregate.ts文件头的 import 对和 host 接口(R10 的改写)②scripts/codemod-split-engine.mjs的rerouteModule/unrouteModule③scripts/measure-durability-swallow-family.mjs改指向的那一条解析控制。node scripts/codemod-split-engine.mjs --members --verify --base $(git merge-base origin/main HEAD),预期打印undoing the moves does rebuild the base engine.ts and its modules byte-for-byte,退出码 0。What changes
ObjectQL#deletemoves into its facet (packages/objectql/src/engine.ts→engine-delete-and-aggregate.ts), generated bynode scripts/codemod-split-engine.mjs --members delete --writeonmain90cea476(after fix(objectql): a by-id delete the driver answers as removing nothing leaves no recycle-bin entry #31702 landed, so its by-id withdrawal moves with the body). The stub keeps its docblock and signature (asyncdropped, as every stub of the series). The one barethisthe body hands on,ql: thisin the hook context, readsql: this.facade(rule R1). The body's one static read,ObjectQL.REFERENCE_PROBE_BATCH, goes through theObjectQLStaticsforwarder that already carries it forengine-cascade-planning.ts.engine.ts10653 → 9943 lines; 12 import bindings only the moved body read are pruned from it.scripts/codemod-split-engine.mjs). Onmainthe fourth pass refused this move:delete reads statics of ObjectQL, and engine-delete-and-aggregate.ts does not take the statics route: this pass does not reroute a module. Now a mover that reads a non-public static puts a module the first pass wrote off the route onto it, exactly as the first pass writes a routed module: the oneimport type { ObjectQL }line becomes the routed pair (ObjectQLStaticsASObjectQL, the class asObjectQLClass), the host interface types its members byObjectQLClass, and the header gains the statics paragraph (now one constant,STATICS_PARA, shared with the first pass's writer). It refuses any module that is not the first pass's unrouted shape, and one whose code namesObjectQLanywhere else (static-route-conflict). The undo (unrouteModule) is the inverse rewrite, applied to the head before the moved members come out. It runs only where the base module was off the route and a moved member reads a static, and it fails a kept member that reads one. Separately, the proof now fails a moved member that reads a static in a module left off the route. Before this change that case passed the undo proof while the module could not compile. A public-only static reader still refuses, as before.scripts/facade-delegation-registry.json: theObjectQL·deleterow (refactor: move shared state out of the protocol.ts and engine.ts facades into state-owning facets, so the hot bodies left on the class can become delegations (ruling 6624345766) #30020, bare-this) leaves; no other row moves.check:facade-delegation-only9 → 8 named exceptions.scripts/measure-durability-swallow-family.mjs(one control, seat ruling A, claim amended): thedeleteRESOLUTION control pinnedengine.ts·ObjectQL·this.delete(), whose only call site was the after-abort re-entry inside the moved body. With the body moved, the control matched nothing andpnpm check:swallow-census-controlswent red (resolution control matched NO call site). The control now pins the same re-entry where it moved:engine-delete-and-aggregate.ts·DeleteAndAggregateFacet·delete→DeleteAndAggregateFacet. Measured with the real resolver on the moved tree: this site resolves to the facet's owndeletebody (the body the host'sdeletestub reaches). The cascade re-entry inengine-cascade-planning.tsresolves to REFUSAL (no same-file body). Theengine.tscross-class collision stays pinned by theupdateandtransactioncontrols..changeset/30020-objectql-delete-facet.md,@objectstack/objectqlpatch. The delta allowedskip-changesetwhen the.d.tsdiff is empty, but the published JS changes (positive control below), and AGENTS.md reservesskip-changesetfor a diff that publishes nothing. This is the S1 / E2 precedent.Tests
statics route for a written module (fourth pass, #30020 R10), 18 cases, floor 18. It runs on the identity fixture with astaticReadermethod the first pass keeps (bare-this) in a section it writes off the route. The cases cover: the reroute plan; the proof; determinism; the routed import pair; the interface alias, including the identity port; the statics paragraph in place; reroute/unroute as inverses; five failing heads (paragraph missing, wrong import pair, a member typed by the class itself, a reroute no moved member needs, a static read left off the route); and four refusals (static-route-conflict, R4 into a rerouted module, another./engine.jsshape, an already-routed module).Ablations (each red, then restored: blob == HEAD, `git diff HEAD` empty)
Via
node scripts/ablation-replace.mjs --file scripts/codemod-split-engine.mjs … -- node scripts/codemod-split-engine.mjs --self-test, on head:generateMembersdoes not reroute)the generated move proves against its base — engine-identity.ts: a member this pass moved reads a static, and the module is off the statics route (R10)a module rerouted though no member the pass moved reads a static failsa module whose code names ObjectQL outside its import and host interface refuses the routea moved member that reads a static in a module left off the route failsThe swallow-census control was red against the moved tree before the re-point (
matched NO call site) and green after.Acceptance notes
.d.tsproof bar holds. The JS changes, as for every series PR:DeleteAndAggregateFacet.deleteoccurs 0× in basedist/index.mjsand 1× in head (positive control).ObjectQL#updateand#insertstill carry their registry rows (E5, E6). Their own re-entries will meet the same census control shape when E6 movesupdate.Verification
All readings through
scripts/pm/os-verify-lock.sh(VERDICT command-exit 0each), base90cea476, head as noted.node scripts/codemod-split-engine.mjs --members --verify --base 90cea476delete), byte-exact, 12 bindings pruned--self-testpnpm check:facade-delegation-onlypnpm --filter @objectstack/objectql typecheckpnpm --filter @objectstack/objectql testdist.d.ts(core.d.ts,core.d.mts,index.d.ts,index.d.mts)cmp)pnpm --filter @objectstack/dogfood test(full, no shard, head5cf3f796)eslint --no-inline-config packages/objectql+ both scripts (objectql has nolintscript)Derived gates: 83 / 83 on head 2a5a3a3, reconciled
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat2a5a3a3dderived 83 commands; all 83 run after a fullpnpm build(lock VERDICT exit 0), each exit 0.--ran: "83 derived famil(ies) accounted for — 83 run, 0 NOT-MEASURED (a DERIVED zero)". On the first round (head5cf3f796, before the control re-point) three gates exited 3 on container prerequisites, not findings:check-plugin-teardown-shape --self-test(shallow clone; fixture commit fetched),check:dual-build-cjs-loadsandcheck:published-readme-exports(no full build yet). One was a real red,check:swallow-census-controls, fixed by the control re-point above. Extra:src/http-dispatcher.keys.test.tsin runtime (names the census script) 20/20; census--self-test(every family) exit 0.test:repowas not run locally (no diff in that project); CI's Test Core carries it.Generated by Claude Code