Skip to content

docs(objectql): state the #16074 per-row previous rule in the published docblock - #18625

Merged
huangyiirene merged 3 commits into
mainfrom
claude/issue-17975-objectql-previous-docblock
Sep 17, 2026
Merged

huangyiirene merged 3 commits into
mainfrom
claude/issue-17975-objectql-previous-docblock

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #17975

Clause-②: no

What moved

Two sites still stated the RETIRED per-row previous rule in the present tense. Both now state the #16074 ruling as @objectstack/spec states it (PR #17249: hook.zod.ts, bulk-write-hook-conformance.ts):

  • packages/objectql/src/engine.ts — the docblock of private async dispatchPerRowBeforeHooks, clause D3.
  • packages/objectql/src/bulk-write-per-row-hooks.test.ts — the comment on a '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 by MULTI_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.md is 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:

  • BEFORE — npm tarball @objectstack/objectql@17.4.0 unpacked: the retired sentence is present in 6 published filesdist/core.js, dist/core.mjs, dist/index.js, dist/index.mjs, dist/util-Dw5ZTIII.d.mts and dist/util-Dw5ZTIII.d.ts line 3554 — the exact reading the card recorded. It sits on a member of declare class ObjectQL, which both the . and ./core entrypoints export, so every consumer's editor surfaces it on hover.
  • AFTER — pnpm --filter '@objectstack/objectql...' build on this branch: the retired sentence is absent from dist/ entirely, and the corrected text is at dist/util-B8LXqiG6.d.ts:3613 (plus .d.mts and 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, including rewrite 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 — over packages/**, docs/**, content/docs/**, scripts/** and skills/**.

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.md quoting the old text on purpose. packages/objectql/src/multi-update-hook-key-divergence.ts:12-15 quotes the addendum's widening MECHANISM, which #16074 did not retire — swept and left alone.

The changeset level — asked, answered, patch

Graded 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 card Clause-②: yes as 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, then Clause-②: no). The original yes leaned 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 all patch (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 own judgeLevel with this PR's real inputs (packagesTouched names @objectstack/objectql): patch plus no returns not-declared, 0 offenders. The minor this 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 commit c3de704e18 is this PR head, and the families the changeset path derives were re-run and re-reconciled there.

  • Gates, derived not guessed. node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands against 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 --ran reports 63 derived, 61 run, 2 NOT-MEASURED, 0 UNRUN.
  • Re-run after the regrade, at c3de704e18. dispatch-gates --commands .changeset/17975-objectql-per-row-previous-docblock.md derives 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.
  • 61 green in the full sweep at cd22004048. Including check: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 (locally no-pull-request: the axis has no PR body to read outside CI, which is why the table above was measured through judgeLevel directly).
  • NOT MEASURED (3), each with its reason — none of them a finding:
    • pnpm check:dual-build-cjs-loads — exit 3, PREREQUISITE NOT MET: reads built output for 66 packages, needs a whole-repo pnpm 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-test leg is green.
  • One non-zero that is not this diff. pnpm check:cross-package-test-inputs exits 1 here, on packages/cli/test/init-created-files-summary.e2e.test.ts descending packages/spec/dist/. It is gated on statSync(packages/spec/dist).isDirectory(), so it fires only in a tree where spec has been BUILT. Control: the same gate run in a fresh, unbuilt origin/main worktree exits 0. None of this PR's three paths appears in the finding.
  • Tests. pnpm --filter @objectstack/objectql test298 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 through scripts/pm/os-verify-lock.sh; all three report VERDICT command-exit 0.
  • No new test is owed. The shape this text now admits already has coverage: multi-update-hook-key-divergence.test.ts pins 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.
  • Lint, narrowed and declared. pnpm exec eslint --no-inline-config --format json over the two changed source files: 2 files, 0 errors, 0 warnings. Population: eslint.config.mjs:971 lints **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus NEVER_LINTED. Why the narrowing excludes nothing: that config, in its own words at eslint.config.mjs:328, "never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) 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:engine dev seat, session session_01CqmCgU5RGDoJYhHUMVp2af (https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af).

Acceptance notes

  • scripts/check-cross-package-test-inputs.mjs changes verdict on build state: the walked-root leg is guarded by statSync(ROOT).isDirectory(), so a clean checkout passes and the same commit fails once packages/spec/dist/ exists. CI lints before building, so main stays 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-gates reports this branch as STALE TREE — origin/main moved 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.
  • The paragraph after the repaired one still opens "That last paragraph used to end …", quoting a version older than the one replaced here. It stays true as history and was left alone rather than re-written on the way past.

Generated by Claude Code

…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>
@github-actions

github-actions Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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
  • 1 anchor(s) matched too much of the corpus to be a work list: ObjectQL (symbol, 69 pages)
  • 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.

Coarse fallback — 17 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 7299b945a2fcdc649de1a59ac71a006c6f38ff9bpackageMentionDocs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 17, 2026
…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>
@huangyiirene
huangyiirene marked this pull request as ready for review September 17, 2026 10:20
@huangyiirene
huangyiirene added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 17005cc Sep 17, 2026
41 of 42 checks passed
@huangyiirene
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>
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/s tests tooling

Projects

None yet

2 participants