docs(objectql): state the #16074 per-row previous rule in the published docblock - #18625
Merged
huangyiirene merged 3 commits intoSep 17, 2026
Merged
Conversation
…shed docblock `dispatchPerRowBeforeHooks`'s docblock and one test comment still stated the RETIRED rule — per-row `previous` supplied "so a guard can REFUSE the write (throw), not so a rewrite can be aimed". Ruling #16074 (landed in `@objectstack/spec` by PR #17249) admits a row-invariant-in-effect rewrite: the same written key set on every matched row, assigned IN PLACE, kept safe by the engine's `MULTI_UPDATE_HOOK_KEY_DIVERGENCE` refusal. Key-set divergence, a per-row value and a row-conditioned REPLACEMENT of `ctx.input.data` stay out of contract. Prose only; the runtime already follows the new rule. The docblock is published surface — the retired sentence ships in six files of the `@objectstack/objectql@17.4.0` tarball, including `dist/util-Dw5ZTIII.d.ts:3554` on a member of the exported `ObjectQL` class — so a changeset is owed. Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af Co-authored-by: Claude <noreply@anthropic.com>
The docblock is published text (it ships in `dist/util-*.d.ts`), so a changeset is owed. Graded `minor` because this PR declares clause ②: the level axis in `check-changeset-no-major.mjs` refuses a declared clause ② whose every moved package is graded `patch`. Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 17 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
…s declared The seat overturned its own `Clause-②: yes` grading on #17975 and posted the correction: this card adds no exported symbol, no key and no accepted value, so it widens nothing. The widening was PR #17249's, in `@objectstack/spec`. The `yes` had leaned on a precedent that moved exported SYMBOLS through a barrel; this moves prose, and the four in-repo precedents for a prose repair inside a published package are all `patch`. With no clause ② declared, `check-changeset-no-major`'s level axis stands down, which is what made the `minor` grade necessary in the first place. Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 17, 2026
huangyiirene
marked this pull request as ready for review
September 17, 2026 10:20
huangyiirene
deleted the
claude/issue-17975-objectql-previous-docblock
branch
September 17, 2026 10:44
huangyiirene
pushed a commit
that referenced
this pull request
Sep 17, 2026
…ocks Brings in PR #18625 (card #17975), the sibling prose repair in the same contract family, so this branch's wording can be aligned with the spelling that actually shipped. Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af Co-authored-by: Claude <noreply@anthropic.com>
huangyiirene
pushed a commit
that referenced
this pull request
Sep 17, 2026
…bulary, add the changeset Follow-up to the same two sites after merging PR #18625 (card #17975), the sibling prose repair that landed in this package. - Both sites now use the package's shipped spelling for the dispatch model: per matched row, on the single-record shape, ADR-0058 Addendum II D1/D2. - The second site no longer names the opt-in `dispatchUnscopedMultiWrite` dispatch. `wrapDeclarativeHook` is applied at registration (`hook-binder.ts:221`), but no metadata binding can set that flag today, so naming it as an absence case this function observes would be a claim that cannot be shown to be reachable. The truthful statement — any update-shaped context whose prior row is not in hand — is true by construction. - Adds the `patch` changeset: the first docblock is emitted verbatim onto the exported `hookRecordState` declaration in the published `.d.ts`. Prose only: no behaviour change, no assertion change. Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #17975
Clause-②: no
What moved
Two sites still stated the RETIRED per-row
previousrule in the present tense. Both now state the #16074 ruling as@objectstack/specstates it (PR #17249:hook.zod.ts,bulk-write-hook-conformance.ts):packages/objectql/src/engine.ts— the docblock ofprivate async dispatchPerRowBeforeHooks, clause D3.packages/objectql/src/bulk-write-per-row-hooks.test.ts— the comment ona 'previous'-reading GUARD can now refuse a bulk write per row.The ruled contract as written: a per-row
previous-conditioned rewrite is ADMITTED when its written KEY SET is the same on every matched row AND is assigned IN PLACE; key-set divergence is REFUSED byMULTI_UPDATE_HOOK_KEY_DIVERGENCE(#14099); a rewrite AIMED at one row stays outside the contract. Both sites were located by SYMBOL, not by the line numbers on the card.⛔ No behaviour change. The runtime already follows the new rule — the three provenance stamps (
email-template-provenance.ts,sharing-rule-provenance.ts,webhook-provenance.ts) all assign in place. ⛔packages/objectql/CHANGELOG.mdis untouched: a changelog is a dated record of what was true then.R2, re-measured here: the docblock IS published surface, and the repair reaches it
The card's load-bearing claim, verified against the real tarball rather than taken on trust:
npmtarball@objectstack/objectql@17.4.0unpacked: the retired sentence is present in 6 published files —dist/core.js,dist/core.mjs,dist/index.js,dist/index.mjs,dist/util-Dw5ZTIII.d.mtsanddist/util-Dw5ZTIII.d.tsline 3554 — the exact reading the card recorded. It sits on a member ofdeclare class ObjectQL, which both the.and./coreentrypoints export, so every consumer's editor surfaces it on hover.pnpm --filter '@objectstack/objectql...' buildon this branch: the retired sentence is absent fromdist/entirely, and the corrected text is atdist/util-B8LXqiG6.d.ts:3613(plus.d.mtsand the four JS bundles) — the same six files, corrected.⇒ the grading stands: this is a contract-face edit on published text, and
'@objectstack/objectql'owes a changeset.R3, the broader sweep: still exactly two live restatements
The card's instrument (
not so a rewrite) was 8 hits, 2 live. The sweep here covered the IDEA, not one string — 15 further spellings, includingrewrite can be aimed,aimed at one row,widens to every matched row,is supplied so,conditioned on the row,row-invariant/ROW-INVARIANT,out of contract,outside the contract,guard can REFUSE,can REFUSE,not to aim,never so a rewrite,only a guard,cannot rewrite,must not rewrite— overpackages/**,docs/**,content/docs/**,scripts/**andskills/**.Result: no third live restatement. Everything else is one of (a) already stating the ruled contract —
packages/spec/src/data/hook.zod.ts,packages/spec/src/data/bulk-write-hook-conformance.ts,content/docs/data-modeling/formulas.mdx:405,scripts/adr-anchors/packages__spec__src__data__bulk-write-hook-conformance.ts.json; or (b) a dated record — the four CHANGELOG lines,docs/adr/0058-*.md:236(which carries its own "Amended in Amendment II.3 below" pointer), and.changeset/hook-previous-row-invariant-rewrite.mdquoting the old text on purpose.packages/objectql/src/multi-update-hook-key-divergence.ts:12-15quotes the addendum's widening MECHANISM, which #16074 did not retire — swept and left alone.The changeset level — asked, answered,
patchGraded
patch, and this PR declares no clause ②.It moves published PROSE: no exported symbol, no key, no accepted value. The accept set was widened by PR #17249 in
@objectstack/spec, not here. The dispatching seat had graded the cardClause-②: yesas the conservative call, re-measured it, and overturned its own grading — the correction is on the card as comment 5712379730, in the fixed spelling (Clause-②-correction: 5711903408, thenClause-②: no). The originalyesleaned on #16872, which moved exported SYMBOLS through a barrel; this moves prose, and the four in-repo precedents for a prose repair inside a published package are allpatch(abc4b83ce8,484484041a,7851fa3146,2d5945a00f).With no clause ② declared,
check-changeset-no-major's level axis stands down. Measured on this head through the gate's ownjudgeLevelwith this PR's real inputs (packagesTouchednames@objectstack/objectql):patchplusnoreturnsnot-declared, 0 offenders. Theminorthis PR carried for one commit existed only to satisfy that axis under the declaration since corrected.Verification
Two runs, each named with the sha it was taken at. The full sweep below ran at
cd22004048; the regrade commitc3de704e18is this PR head, and the families the changeset path derives were re-run and re-reconciled there.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsagainst the real change set (3 paths) → 63 families. All 63 ran, each exit code written to disk before any was read, then reconciled:dispatch-gates --ranreports63 derived, 61 run, 2 NOT-MEASURED, 0 UNRUN.c3de704e18.dispatch-gates --commands .changeset/17975-objectql-per-row-previous-docblock.mdderives 18 families for the changeset path; all 18 ran and all 18 exited 0. One reconciliation, one count:18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN. ⛔ The other 60 were not re-run — a changeset level is outside what they read.cd22004048. Includingcheck:nul-bytes,check:engine-double-contract,check:dts-closure,check:published-files,check:test-source-alias,check:type-check-coverage,check:comment-mask-adoption,check:comment-mask-corpus,check:changeset-gate-self-tests,check-empty-changeset --base origin/main,check-changeset-no-major --base origin/main(locallyno-pull-request: the axis has no PR body to read outside CI, which is why the table above was measured throughjudgeLeveldirectly).pnpm check:dual-build-cjs-loads— exit 3,PREREQUISITE NOT MET: reads built output for 66 packages, needs a whole-repopnpm build. CI's.pnpm check:type-check-debt— exit 3, same class: 18 workspace dependencies have no built type entry point here, and the gate refuses rather than measuring a different world.node scripts/check-engine-split-ratio.mjs --days 90— exit 2, REFUSED: this clone is shallow and its oldest visible commit sits inside the 90-day window. The--self-testleg is green.pnpm check:cross-package-test-inputsexits 1 here, onpackages/cli/test/init-created-files-summary.e2e.test.tsdescendingpackages/spec/dist/. It is gated onstatSync(packages/spec/dist).isDirectory(), so it fires only in a tree where spec has been BUILT. Control: the same gate run in a fresh, unbuiltorigin/mainworktree exits 0. None of this PR's three paths appears in the finding.pnpm --filter @objectstack/objectql test→ 298 files, 4990 tests, all passing.pnpm --filter @objectstack/objectql typecheck→ exit 0. Targeted re-run of the two files that carry this contract (bulk-write-per-row-hooks.test.ts,multi-update-hook-key-divergence.test.ts): 77 passing. Every heavy run went throughscripts/pm/os-verify-lock.sh; all three reportVERDICT command-exit 0.multi-update-hook-key-divergence.test.tspins both directions (a row-invariant rewrite is never refused, however its values differ, and the divergence refusal). The repaired test comment now points a reader at it.pnpm exec eslint --no-inline-config --format jsonover the two changed source files: 2 files, 0 errors, 0 warnings. Population:eslint.config.mjs:971lints**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}minusNEVER_LINTED. Why the narrowing excludes nothing: that config, in its own words ateslint.config.mjs:328, "never enables type-aware linting (noparserOptions.project, no typed@typescript-eslintrules) for ANY file" — with no cross-file type information in play, a comment-only diff cannot move the verdict on a file it does not contain. The repo-wide sweep is CI's run.Authored by the
domain:enginedev seat, sessionsession_01CqmCgU5RGDoJYhHUMVp2af(https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af).Acceptance notes
scripts/check-cross-package-test-inputs.mjschanges verdict on build state: the walked-root leg is guarded bystatSync(ROOT).isDirectory(), so a clean checkout passes and the same commit fails oncepackages/spec/dist/exists. CI lints before building, somainstays green and only local runs see it. Not fixed here (out of scope, and it is a gate, not this contract) — reported to the dispatching seat with dedupe words.dispatch-gatesreports this branch as STALE TREE —origin/mainmoved 2 commits during the run and one derived file (scripts/pm/check-harness-current.mjs) changed across that range. The derivation above is against this PR's own tree; no path of this diff is in that file.Generated by Claude Code