Skip to content

refactor(objectql): move five delete-cascade bodies out of engine.ts into engine-delete-cascade.ts (#25522 cut 19) - #27391

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-f9p63p
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-f9p63p

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread
Part of #25522
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160 + 6441032442

维护者速读

  • 改了什么:把 engine.ts「删除级联与引用遍历」区里 5 个方法体(级联删除集合的收集遍历 collectCascadeDeleteSet、级联内 restrict 判定 refuseRestrictsInsideOwnCascade、409 DELETE_RESTRICTED 拒绝的构造 deleteRestrictedError、引用探测过滤 referenceProbeFilter、引用检查提权记录 recordReferenceCheckElevation)原样搬进新文件 engine-delete-cascade.ts;类上的方法签名、注释、位置不变,方法体换成转交。只被搬走代码读的顶层 helper cascadeReachOf 随之搬走;与留下代码共用的 4 个 helper 和 CascadeDeleteSet 类型原地加 export、由新文件导入(不复制)。engine.ts 22,110 → 21,874 行。
  • 为什么改:[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 按缝拆分 engine.ts 的第 19 刀。此区此前因 fix(objectql)!: a predicate delete honours deleteBehavior for every matched row: restrict refuses, master_detail cascades, set_null clears (#26871) #26930 在改而被排除,现已空出。重新测价:区内 24 个成员里,读私有静态成员的 10 个方法(含 walkReferencingRelations、cascadeDeleteRelations、planCascadeAtomicity)和 7 个私有静态本身按系列限制必须留下,cascadeRelationBehavior 因 federated-injected-column-readers.test.ts 按同文件读 via helper 也留下,所以实际可搬的是 5 个付得起转交成本的方法体,净 −236 行(不是派单估计的 18 个 / 约 1,069 行)。
  • 风险与回滚:纯搬移,无行为变化;公开 .d.ts 六个文件与基线逐字节相同(含阳性对照);运行期导出名单与函数名相同;构建产物只多出新文件一个区段,外部包首次加载顺序不变;一次性晚绑定探针在新旧两版构建产物上逐行一致。回滚 = revert 本 PR。
  • 先看:packages/objectql/src/engine-delete-cascade.ts(5 个函数与 DeleteCascadeHost)、packages/objectql/src/engine.ts 里 5 个转交桩、新导入行与 5 处原地 export、content/docs/permissions/system-context.mdx 第 29 行登记的锚点改指新文件。
  • 两分钟验证:pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2 src/engine-cascade-delete.test.ts src/engine-cascade-delete-sibling-restrict.test.ts src/engine-cascade-delete-tree.test.ts,应见三个文件全部通过(级联收集、同级 restrict 判定与拒绝信封各自走到的测试)。
  • 需要你做的:无,席位落地。

Cut 19 of the packages/objectql/src/engine.ts split (#24586 ruling A, recorded in 6270097840), under the claim 6487687348. Five bodies of the "Delete cascade and reference walking" section move unedited into a new module, packages/objectql/src/engine-delete-cascade.ts, behind DeleteCascadeHost. No behaviour changes. Every published declaration file is byte-identical to the base. #25522 stays open for the later cuts.

Branch claude/project-thread-f9p63p (the card thread's harness-pinned branch), cut from origin/main at c4c515ad3c, with origin/main 7e200b4a68 merged in before this PR was opened (that merge touched none of this diff's paths).

What changes

Why this area, and why only five bodies

The claim names this section: it was excluded from cuts 17 and 18 while #26930 was open in it, and #26930 and #27073 have since merged. Its old price (−248) was stale, so it was re-priced member by member on c4c515ad3c (engine.ts 22,110 lines, blob 50a504332d70). The section runs from planCascadeAtomicity to organizationOwnedRowCounts (base lines 17,647 to 19,591) and holds 27 members.

member body lines disposition
planCascadeAtomicity 81 stays: reads the private statics MAX_CASCADE_DEPTH; also a liveness / reader-test site
warnCascadeNotAtomic 12 stays: a host of three members costs 10 lines, pays 2
referenceProbeFilter 13 moves (reads no member; direct call), −11
storedReferenceIncludes, remainderAfterMemberRemoval, referenceCheckContext 7, 2, 1 stay: private statics
recordReferenceCheckElevation 24 moves, −18 (its system-context census row is re-keyed)
dependentCountIsDisclosable 49 stays: reads the private static storedReferenceIncludes
cascadeDeleteRelations 45 stays: reads MAX_CASCADE_DEPTH; packages/spec/liveness/field.json names engine.ts#cascadeDeleteRelations
REFERENCE_PROBE_BATCH - stays: private static
collectCascadeDeleteSet 64 moves, −57
cascadeRelationBehavior 60 stays: federated-injected-column-readers.test.ts checks the organizationOwnedRowCounts row's via: 'cascadeRelationBehavior' by reading that helper in the SAME file as the site; moving it would mean changing the test's logic, not re-keying a row
fileReferenceCheckElevation 4 stays: pays nothing (stub 5 lines)
probeReferencingRows 100 stays: reads referenceCheckContext, storedReferenceIncludes
referenceProbeFilterOfSet 8 stays: pays 3
probeReferencingRowsOfSet 38 stays: reads REFERENCE_PROBE_BATCH
walkReferencingRelations 318 stays: reads keepsOrganizationReference, remainderAfterMemberRemoval
refuseRestrictsInsideOwnCascade 74 moves, −65
deleteRestrictedError 81 moves, −74
isTenantColumnSetNull 5 stays: pays 3, and a reader-test key names it
outlivesOrganization, keepsOrganizationReference, organizationCountContext 2, 2, 5 stay: private statics
countReferencingRowsOutside 11 stays: reads organizationCountContext
organizationCountIsDisclosable 9 stays: pays 2
refuseOrganizationDeleteWhileOwned 38 stays: reads outlivesOrganization
organizationOwnedRowCounts 23 stays: reads outlivesOrganization, organizationCountContext; public

So the order's hypothesis ("~18 movable bodies, ~1,069 lines") does not hold: the series limit on private statics keeps 17 members, the largest body (walkReferencingRelations, 318 lines) among them, and the five that move pay −225 in bodies, −236 in all. One PR, under 3,000 changed lines (753), so no further split was needed.

The shape

  • The class keeps all five methods with name, modifiers, signature, docblock and position. A body becomes one host literal of exactly the DeleteCascadeHost members it reads, plus a .call, marked [#25522 cut 19], as cuts 8 and 10 to 18 did. referenceProbeFilter reads no member, so its stub calls the function directly. The one field read (logger, by recordReferenceCheckElevation) goes as a getter over a readLogger closure; the methods go as late-bound closures (cascadeRelationBehavior, fileReferenceCheckElevation, probeReferencingRowsOfSet, deleteRestrictedError, referenceProbeFilter, validationMessageContext, dependentCountIsDisclosable, objectDisplayLabel), so a double set on the engine is still the one a call reaches. No moved body assigns a field, so there is no setter (6430872749 not needed).
  • Series limits. All five are private with declared return types, so each .d.ts line stays private NAME;. No moved body reads a private static, has a this.FIELD.delete/insert/update( site, calls this.insert / this.update / this.delete, or carries an engine.ts#NAME liveness pointer.
  • Helpers, under the cut-14 seat ruling 6432376812. The bodies read cascadeMemberKey, cascadeSetAdd, cascadeSetHas, declaredMultiValued and the CascadeDeleteSet interface, all also read by bodies that stay (cascadeDeleteRelations, walkReferencingRelations, countReferencingRowsOutside, resolveOptionDefault and probeReferencingRows for declaredMultiValued). Each gains export in place, byte for byte otherwise, and the module imports them from ./engine.js (values; the interface type-only). cascadeReachOf is read only by refuseRestrictsInsideOwnCascade, so it moves with it, byte-identical. Nothing re-exports any of them from the package entry.
  • Imports. renderOperationMessage (@objectstack/spec/system) and resolveFieldLabel (./validation/record-validator.js) were read in engine.ts only by deleteRestrictedError, so they leave engine.ts's import lists (one specifier each; both modules are still imported there for other names) and the module imports them. The module also imports ServiceObject and ExecutionContext as types.
  • Load order (measured). engine.ts imports the module right after cut 16's type import, after every module the new one imports, so no module is evaluated earlier than before. On the head bundles, with the // src/engine.ts markers set aside, the // src/... region order equals the base's with one line added, // src/engine-delete-cascade.ts (index.mjs 101 to 102 regions, core.mjs 90 to 91, index.js 102 to 103, core.js 91 to 92). The external modules load in the same first-occurrence order (index.mjs import specifiers, deduplicated in order: md5 853c7898… both). The ESM bundle has one more import statement (150 to 151 in index.mjs, 132 to 133 in core.mjs; CJS require( 150 to 151 / 132 to 133): the module's own renderOperationMessage import from @objectstack/spec/system, a package engine.ts already loads first, so no load moves.

Net lines

engine.ts goes from 22,110 to 21,874 lines, net −236 (42 added, 278 removed). The module is 429 lines. The diff against origin/main is 753 changed lines over 4 files (+473 / −280).

Readers of the moved lines

  • content/docs/permissions/system-context.mdx: recordReferenceCheckElevation holds row 29's elevation read (context?.isSystem). The register row is re-keyed from engine.ts#recordReferenceCheckElevation to engine-delete-cascade.ts#recordReferenceCheckElevation (moved to its sorted place); the row's own Symbol cell names the symbol only and is unchanged. node scripts/check-system-context-census.mjs: OK (154 read sites, register matches the tree).
  • docs/qa/platform-checklist/areas/records-forms.json: one source citation, packages/objectql/src/engine.ts#required, named the required local of deleteRestrictedError; re-pointed to engine-delete-cascade.ts#required, its text otherwise unchanged. check-platform-checklist --changed-from origin/main: 13 judged, 0 lost; the full checklist gate: OK.
  • federated-injected-column-readers.test.ts keys name cascadeRelationBehavior, planCascadeAtomicity, organizationOwnedRowCounts and isTenantColumnSetNull, all of which stay; no moved body holds a seam use, and the test passes. packages/spec/liveness/field.json names engine.ts#cascadeDeleteRelations, which stays: nothing under packages/spec changes.
  • Prose mentions of moved names outside the package (packages/spec CHANGELOG/comments, engine-cascade-delete.test.ts and delete-reference-cleanup-system-identity.test.ts comments, a runtime integration test docblock naming ObjectQL.refuseRestrictsInsideOwnCascade) name the method by behaviour, and the method still exists on the class.
  • Read-seam census. check-durability-degradation-log-level --list at base and head: identical once line numbers are masked (165 lines). No moved body guards a storage read.
  • No ADR anchor paragraph describes a moved body (the engine.ts entry is the transaction-seam paragraph), so the module needs no anchor entry of its own.
  • Decision-letter count: check-adr-anchors at base c4c515ad3c (clean checkout): 1,900 decision-letter citations on the anchored surface, 60,466 resolving citations across 8,527 files. At head: 1,900, 60,466 across 8,528. The moved bodies carry no [ADR-NNNN Dn] letter.

Why

#25522 splits engine.ts one seam at a time so that a change to one area reads, reviews and conflicts as that area alone. The delete-cascade section is the largest section left and was free once #26930 merged. Nothing about what the engine does changes.

Tests

No test is added and none is edited: the move is proved by identity, not by new behaviour.

Public .d.ts: byte-identical (ruling 6348891160 item 1), with a positive control

Built @objectstack/objectql at the base (c4c515ad3c, engine.ts blob 50a504332d70, no module; turbo run build --filter=@objectstack/objectql..., 14 of 14 tasks) and at head (engine.ts blob a5687d70a2f0; pnpm --filter @objectstack/objectql build). The builds are the moved code, not a stale cache: collectCascadeDeleteSet.call(host and // src/engine-delete-cascade.ts each occur 0 times in the base dist/index.mjs and once in the head's.

file sha256 base = head raw-diff lines
core.d.ts bdc32f3004ee12903aba75d2f07929f8e8abdacc135f7ca65e6b66e625a16876 0
core.d.mts ae601360109a2117cbcac69f9a5d28c5334cdff8abed80b35057fe0dd41de73b 0
index.d.ts bcb31057f6f7e50f34792c621026e92bc95764160843924aa25c72c476073505 0
index.d.mts 943aad8e39db6806e5585acd220b33be7219804cb27a225052b1feea873fb64e 0
util-6U6fCMd3.d.ts 146d109c8c793af1dc26780171712da9570d87eef2e4fcadebfe32e62fb7fa37 0
util-6U6fCMd3.d.mts 146d109c8c793af1dc26780171712da9570d87eef2e4fcadebfe32e62fb7fa37 0
  • Every declaration file is raw byte-identical, and no chunk is renamed (util-6U6fCMd3 at both), so 6348891160 item 1 holds with no normalisation and the 6441032442 reorder bar is not reached. The 6441032442 normaliser (dtsnorm.mjs) lives in another project's files and was not available in this thread's container; with a 0-line raw diff on all six files there is nothing for it to normalise.
  • The run-time export lists are equal too: index 182 names and core 54, ESM and CJS, and a sha256 over every export's name and function .name is the same at base and head (2aaa13a11288fd84… / 70d1bf1f346b2793…), so no bundler same-name rename happened.
  • (e) After the head build, the full turbo run build (115 of 115 tasks, the dependents' DTS builds included) and pnpm --filter @objectstack/core typecheck ran: exit 0 each. (P2) packages/objectql/package.json exports names ./dist/index.* and ./dist/core.* only; (P3) git grep -n -E 'objectql/dist|driver-sql/dist' -- scripts package.json: 0 hits.

Positive control. On the head, node scripts/ablation-replace.mjs dropped private from private async deleteRestrictedError(args: { (a moved member's stub; anchor 1 to 0, blob a5687d70a2f0 to 1850f07b29d3) and rebuilt (exit 0). The chunk is renamed util-Dd_AzMXV and now publishes deleteRestrictedError(args: { object: string; … context: ExecutionContext | undefined; }): Promise of Error (line 11117, where the head prints private deleteRestrictedError;); every declaration file's sha256 changes (core.d.ts 68f57645…, index.d.ts b9136807…, chunk 519be62f…). The restore leg put the blob back to a5687d70a2f0 (git diff HEAD empty), and the rebuild that followed produced six declaration files and four bundles that compare equal to the head build.

AST compare (move-only)

A one-off script (TypeScript compiler API; leaf tokens by recursive getChildren) on base engine.ts against head engine.ts plus the module:

  • The five moved bodies are SAME (parameters, return type, async, body tokens, and every body line equal after one level of indent): referenceProbeFilter 97 tokens / 13 lines, recordReferenceCheckElevation 107 / 24, collectCascadeDeleteSet 582 / 64, refuseRestrictsInsideOwnCascade 810 / 74, deleteRestrictedError 323 / 81. Negative control: one changed token in the module copy (slice(1, -1) to slice(1, -2)) reads DIFF.
  • class ObjectQL: 330 of 330 members kept, in the same order; 325 byte-identical including leading trivia, and the 5 stubs keep docblock, modifiers and signature identical.
  • Top level: 229 of 238 base statements byte-identical. The other 9: the two import lists that lose one specifier; declaredMultiValued, CascadeDeleteSet, cascadeMemberKey, cascadeSetHas and cascadeSetAdd, each with export added and otherwise byte-identical; cascadeReachOf, moved into the module byte-identical; and the class. The head adds one statement: the module import.
Late-binding probe (base and head dist)

zz-probe-cut19.mjs (a one-off, not committed) loads the built ObjectQL from each dist/ and drives the five bodies with doubles set on the instance after construction: referenceProbeFilter on a single-valued lookup, a multi-valued lookup, an id needing JSON escaping (the $or arm) and a multiselect; recordReferenceCheckElevation with userId, actor, isSystem and no context, the logger replaced twice after construction; collectCascadeDeleteSet over a three-level master-detail fixture with every host member replaced and each call recorded in order, with and without fileElevations; refuseRestrictsInsideOwnCascade on both sets after a second generation of doubles is wired (it reaches the second generation, and refuses through the replaced deleteRestrictedError with the replaced referenceProbeFilter's filter); and the class's own deleteRestrictedError with its three host members replaced, for a restrict and a required relation, with count disclosure off and on. The 16 output lines are identical on base c4c515ad3c and head (the 5 construction log lines, which carry timestamps, set aside); stderr is empty on both.

Suites

Under scripts/pm/os-verify-lock.sh:

  • Full turbo run build: 115 of 115 tasks, exit 0.
  • typecheck of @objectstack/objectql (tsc + check:test-typecheck) and @objectstack/core: exit 0 each.
  • @objectstack/objectql vitest --project local: 479 files, 8,942 tests passed, exit 0 (the engine-cascade-delete* files, engine-cascade-reference-carrier.test.ts, engine-dangling-reference-audit.test.ts and federated-injected-column-readers.test.ts among them).
  • Beyond the package, the real-driver cascade suites that run these bodies end to end: @objectstack/runtime cascade-delete-multivalue-lookup-real-driver, cascade-delete-restrict-same-parent-real-driver and sandbox/referential-cascade-delete-signal integration tests (3 files, 15 passed, 1 skipped), and @objectstack/plugin-security delete-reference-cleanup-system-identity.test.ts (18 passed).
  • test:repo projects were not run locally (the published surface is byte-identical); Test Core runs them in CI.

Verification

The gate list is node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on this diff (merge base c4c515ad3), each run with its exit code captured before any pipe, then reconciled with --ran (each line carrying its exit N).

  • Derived gates: 80 of 80 run, exit 0 each; --ran: 80 derived, 80 run, 0 NOT-MEASURED, 0 UNRUN ("a DERIVED zero — all 80 recorded an exit code and none of them is 3"). check:dual-build-cjs-loads and check:dts-closure ran after the full build; check-plugin-teardown-shape and check-engine-split-ratio --self-test after deepening the clone to 2026-07-22 and fetching 621a4876.
  • Hand gates, exit 0 each: node scripts/check-adr-anchors.mjs (counts above), node scripts/check-tenant-audit-census.mjs (245 write call sites), node scripts/check-adr-symbol-anchors.mjs (2,798 anchors), node scripts/check-platform-checklist.mjs --changed-from origin/main and the full check-platform-checklist.mjs, node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD, node scripts/check-system-context-census.mjs, node scripts/check-nul-bytes.mjs, node scripts/check-durability-degradation-log-level.mjs --list (base and head identical, masked), and eslint as pnpm lint runs it (--no-inline-config) on packages/objectql.
  • After origin/main 7e200b4a68 was merged (15 files under ui/ and the Studio, none of this diff's paths), the change set against origin/main is the same four files, so the derived list is unchanged.

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 (DeleteCascadeHost, engine-delete-cascade.ts).
  • 3. No formatter ran; pnpm lint passes on the touched package.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. No publish-visible change, so skip-changeset; both declaration lines are filled in above.
  • 6. packages/spec 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, apart from the maintainer quick-read block the project asks for.
  • The Before Submitting list in CONTRIBUTING.md is done.

skip-changeset: move-only inside @objectstack/objectql, with every published declaration file byte-identical and no behaviour change, so there is nothing for a release note to say.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6bhgXPvYEKGGY6sms31q2


Generated by Claude Code

…into engine-delete-cascade.ts

Part of the engine.ts seam split: collectCascadeDeleteSet,
refuseRestrictsInsideOwnCascade, deleteRestrictedError,
referenceProbeFilter and recordReferenceCheckElevation move unedited
behind DeleteCascadeHost; cascadeReachOf moves with its only reader;
four shared helpers and CascadeDeleteSet are exported in place.

Claude-Session: https://claude.ai/code/session_01L6bhgXPvYEKGGY6sms31q2
Co-authored-by: Claude <noreply@anthropic.com>
…-delete-cascade.ts

The `required` local it names moved with deleteRestrictedError.

Claude-Session: https://claude.ai/code/session_01L6bhgXPvYEKGGY6sms31q2
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 29, 2026
@objectstack-fleet
objectstack-fleet Bot requested a review from os-sales October 29, 2026 04:55
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql, touching 31 documentable anchor(s).

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

  • content/docs/api/data-api.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/api/error-catalog.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/api/error-handling-server.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/api/index.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/kernel/contracts/data-engine.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/permissions/system-context.mdx (via dependentCountIsDisclosable (symbol, a field of interface DeleteCascadeHost), recordReferenceCheckElevation (symbol, a method of class ObjectQL; a top-level function), dependentCountIsDisclosable (literal, a string literal in deleteRestrictedError; a string literal in dependentCountIsDisclosable))
  • content/docs/protocol/kernel/error-handling.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))
  • content/docs/protocol/objectql/types.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))

⛔ 1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-6.mdx (via DELETE_RESTRICTED (literal, a string literal in deleteRestrictedError))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 58 of 210 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 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; 97 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 — 19 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 7e200b4a68c242afc9f7caf0289e985eff3fcac6 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 816dd7f1022cb0c2b7d462f467023bfa8c6c24cc — the merge of head 4a55c08e2ddd816e83b6e6acb6e4299d943ea354 into base 7e200b4a68c242afc9f7caf0289e985eff3fcac6, 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 816dd7f1022cb0c2b7d462f467023bfa8c6c24cc && git checkout 816dd7f1022cb0c2b7d462f467023bfa8c6c24cc
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7e200b4a68c242afc9f7caf0289e985eff3fcac6 4a55c08e2ddd816e83b6e6acb6e4299d943ea354 && git checkout -B drift-repro 7e200b4a68c242afc9f7caf0289e985eff3fcac6 && git merge --no-ff 4a55c08e2ddd816e83b6e6acb6e4299d943ea354

node scripts/docs-audit/affected-docs.mjs --json 7e200b4a68c242afc9f7caf0289e985eff3fcac6

⚠️ 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 7e200b4a68c242afc9f7caf0289e985eff3fcac6 → 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#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw

维护者速读(席位终稿)

  • 改了什么:把 engine.ts「删除级联与引用遍历」区里 5 个方法体原样搬进新文件 packages/objectql/src/engine-delete-cascade.ts:collectCascadeDeleteSet、refuseRestrictsInsideOwnCascade、deleteRestrictedError、referenceProbeFilter、recordReferenceCheckElevation。类上的方法签名、注释、位置不变,方法体换成转交。只被搬走代码读的顶层 helper cascadeReachOf 一起搬走。与留下代码共用的 4 个 helper 和 CascadeDeleteSet 类型原地加 export、由新文件导入,不复制。engine.ts 从 22,110 行减到 21,874 行。另有两处文档登记行改指新文件。
  • 为什么改:这是 [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 按缝拆分 engine.ts 的第 19 刀。此区先前因 fix(objectql)!: a predicate delete honours deleteBehavior for every matched row: restrict refuses, master_detail cascades, set_null clears (#26871) #26930 在改而被排除,现已空出。按成员重新测价,区内共 27 个成员:
    • 读私有静态成员的 10 个方法,加 7 个私有静态本身,按系列限制必须留下;
    • cascadeRelationBehavior 因读取测试的同文件规则留下;
    • 其余付不起转交成本的也留下;
    • 实际可搬的是 5 个方法体,净 −236 行。派单估计的是 18 个、约 1,069 行。
  • 风险与回滚:纯搬移,无行为变化。公开 .d.ts 六个文件与基线逐字节相同,并有阳性对照。运行期导出名单相同。晚绑定探针在新旧两版构建产物上逐行一致。回滚即 revert 本 PR。
  • 先看:
    • engine-delete-cascade.ts:5 个函数与 DeleteCascadeHost;
    • engine.ts:5 个转交桩、新导入行与 5 处原地 export;
    • content/docs/permissions/system-context.mdx:第 29 行登记的锚点改指新文件。
  • 两分钟验证:pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2 src/engine-cascade-delete.test.ts src/engine-cascade-delete-sibling-restrict.test.ts src/engine-cascade-delete-tree.test.ts,应见三个文件全部通过。
  • 需要你做的:无,席位落地(非受管面,753 行)。
  • 席位意见:收下。席位自己逐个比过 6 个搬移体的词法 token,与基线一致;[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 继续开着,留给后续刀。

席位核对 — ACCEPT · domain:server#1 · head 4a55c08e · 2026-10-29T05:18Z

  • Shape: 4 files, +473/−280 (753 lines).
    • engine-delete-cascade.ts is new (+429) and engine.ts is +42/−278.
    • Two registers are re-keyed: the system-context.mdx census row 29, and the records-forms.json source pointer for #required.
    • check-governed-merges --pr 27391: 0 of 4 paths governed, under the 3,000-line bar. No packages/spec. skip-changeset fits: the change is move-only, and every published .d.ts is byte-identical.
  • Premise, measured by the seat: I compared the six moved bodies at token level with a TypeScript scanner, base c4c515ad3c against the head blobs. The local copies are byte-equal to 4a55c08e on both files.
    • collectCascadeDeleteSet (570), refuseRestrictsInsideOwnCascade (800), referenceProbeFilter (97) and cascadeReachOf (104) are token-identical, with this replaced by host.
    • deleteRestrictedError (313) and recordReferenceCheckElevation (84) have equal token counts. Their only differences are the leading whitespace inside a template-literal tail and the closing-paren indent: one indent level, from method to top-level function.
    • The five stubs keep their docblock, modifiers and signature. referenceProbeFilter reads no member, so its stub calls the function directly.
  • Re-price, accepted: the order guessed "~18 bodies / ~1,069 lines". The dev re-priced all 27 members on base and found 17 that the private-static series limit keeps, cascadeRelationBehavior kept by the reader test's same-file via rule, and 5 that pay their forwarding cost (−236 in all). The draft's 速读 said 24 members; the English table and text say 27, and the seat's 速读 above is corrected to 27.
  • Gates:
    • On 4a55c08e: 37 success and 18 skipped, none other. check-expected-skips --pr 27391: OK, all 18 skips are in main's roster. mergeable_state: clean.
    • The dev's derived gates: 80 of 80 run, and --ran shows 0 NOT-MEASURED.
    • .d.ts bar 6348891160 item 1: six raw byte-identical declaration files, plus the drop-private positive control and its restore.
  • Accepted deviations: the 6441032442 normaliser was not available in the card thread's container. With a 0-line raw diff on all six declaration files, there is nothing for it to normalise.
  • Out of scope + Skills-docs:
  • Landing: ready, then auto-merge through the queue. After the merge, [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 (Part of) goes back to pm:queue with a delivered/remaining note.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 29, 2026 05:19
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit 5c0e4fd Oct 29, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-f9p63p branch October 29, 2026 05:42
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw

Landed · domain:server#1 · 2026-10-29T05:44Z

Reading Value
PR #27391 merged at 2026-10-29T05:42Z, merge commit 5c0e4fd0c6, head 4a55c08e (the ACCEPTed head)
Card #25522 open (Part of), released to pm:queue with a delivered/remaining note

State change: #25522 pm:dispatched → pm:queue, assignee cleared. No card was closed by this PR's body.


Generated by Claude Code

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/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants