Repository navigation
fix(objectql): the raw-statement door and the lifecycle sweep cut a driver fault by construction (#21345) - #21384
Conversation
…river fault by construction Position 1: ObjectQL.execute declares that it sent a raw statement, so the boundary cut runs on every message of the fault's chain without waiting for the shared leak predicate to recognise the statement's leading verb. The predicate's frozen list is untouched. Position 2: the lifecycle sweep's per-object catch routes the fault through the same boundary helper before it is reported or logged, so a direct-driver fault from the Archiver's cold or hot calls is cut like an engine door's. Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
…sentinel The objectql pins hold the raw-statement door and the lifecycle sweep over shapes mirroring the measured raw-path and cold-write faults; the dogfood pin drives a real SqlDriver (SQLite always, PostgreSQL and MySQL where their URLs are set) and the Archiver over two real SQLite stores. Controls: class and codes survive, a statement the predicate already recognised is cut exactly as before, a non-dump error leaves unchanged. Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
… real dispatch contract Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check6 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. 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): 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 d6226d4bbf94f0607f711c3d4f989fa708696015 && git checkout d6226d4bbf94f0607f711c3d4f989fa708696015
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 43e928dd4c0be18b5a10430239371332f2ee47f4 e036911f5bc4fc37796f8fd870abe38bae80d9db && git checkout -B drift-repro 43e928dd4c0be18b5a10430239371332f2ee47f4 && git merge --no-ff e036911f5bc4fc37796f8fd870abe38bae80d9db
node scripts/docs-audit/affected-docs.mjs --json 43e928dd4c0be18b5a10430239371332f2ee47f4 |
…ult cut, moved to core (objectstack-ai#21414) Fixes objectstack-ai#21385 Clause-②: no Security handling: this body, the commits, the changesets and the test names carry classes and positions only. Every pin plants a synthetic sentinel and asserts it is ABSENT. No measured log line is copied anywhere, and the local probe printed booleans only. ## What this changes This implements the maintainer's ruling on objectstack-ai#21385 (comment 5950942037, letter A): one cutter for every log face. The cutter's home is `@objectstack/types`, per the claim's amendment 1 (5954587444) and triage's pointer (5954318919). See "Patch round 1" below. 1. **The redaction module moves to `@objectstack/types`.** `packages/objectql/src/driver-fault-redaction.ts` becomes `packages/types/src/driver-fault-redaction.ts`. Against `main`, that is the PR's one git rename (`R092`). The cut is the same code: the same split, the same structural cut at the separator, the same value templates and the same property rules. - The module's one import, `looksLikeInternalErrorLeak`, is now the package-local `./error-leak.js`. `error-leak.ts` and its frozen list are not edited. - The types entry exports four names, listed by name: `redactBoundStatement`, `redactStatementFromMessage`, `redactPropagatedDriverFault` and the `DriverFaultOrigin` type. - The template table and its load-time guard stay package-internal. The guard's eight cases moved verbatim beside it, to `packages/types/src/driver-fault-redaction.test.ts`. - Why `types`: it is the lowest package every face of this family can reach. `driver-sql`, `objectql` and `core` all depend on it, and the family's fourth position, `operatorFacingErrorText`, lives inside it (objectstack-ai#21418). The module header says so. - There is no copy of the cut, no edit to `error-leak.ts` or `driver-error-classification.ts`, and no row added to the frozen predicate list. `packages/core` is not in the diff. 2. **One widening, on the log face.** `redactStatementFromMessage` takes an optional second argument: the same `{ statementSent: true }` that `redactPropagatedDriverFault` already took. Without it, the answer is unchanged. 3. **objectql calls the moved code.** `engine.ts` and `lifecycle/lifecycle-service.ts` now import from `@objectstack/types`, with the same arguments as before. Five objectql test files repoint their import. None of the moved names was on objectql's entries. 4. **driver-sql's five lines call it.** In `sql-driver.ts`, each refusal line writes the dialect's text through `redactStatementFromMessage(text, { statementSent: true })`, imported from `@objectstack/types`. The lines are: - the unresolvable WHERE column (`INVALID_FILTER`), on `find` and on `count`; - the read terminal (`DATABASE_ERROR`); - the raw-statement terminal (`DATABASE_ERROR`), which no longer writes the sent statement as a separate field; - the unresolvable groupBy / aggregation column (`INVALID_FIELD`); - the unresolvable listed-distinct column (`INVALID_FIELD`). `statementSent` holds by construction: each line writes a fault raised by a statement this driver sent, which is the same knowledge the engine's raw door passes. The read terminal's cut sits where its text is computed, so the two debug lines that demote it inside a scope take the cut too (see Acceptance notes). 5. **`driver-turso`'s remote transport is covered by the same line.** Its refusals reach the base class's raw terminal. Its transport error carries no statement (the bare shape), so the line now writes the engine's diagnostic and nothing of the statement it was sent. 6. **Two envelope sentences are corrected.** The read terminal's and the raw terminal's composed `DATABASE_ERROR` messages said the statement was written to the server log. After this change that is not true, so each now says the diagnostic was written, with the statement and its bound values cut. Code, status, `cause` and the withheld text are unchanged. See Acceptance notes, deviation 1. ## Measured: sentinel on each line, before and after Probe: drive each line through the public driver method on better-sqlite3, a live PostgreSQL 16 and a live MySQL 8.0.46, with one synthetic sentinel. An extractor printed only whether the captured line held the sentinel, and on which field. BEFORE was measured at `ecb6ca0258` (base), and AFTER at `0cbd86d55e`, with the same extractor. The committed pins re-measure AFTER at the final head, `992e940fff`. | line | drive | sqlite before → after | pg before → after | mysql before → after | |---|---|---|---|---| | WHERE column | `find` | present → absent | absent → absent | present → absent | | WHERE column | `count` | present → absent | absent → absent | present → absent | | read terminal | missing table (sqlite, mysql); 22P02 value (pg) | present → absent | present → absent | present → absent | | raw terminal | bound value | present (dialect field) → absent | present (dialect field) → absent | present (dialect field) → absent | | raw terminal | value spelled inline | present (statement field and dialect field) → absent | same → absent | same → absent | | groupBy / aggregation column | — | present → absent | absent → absent | present → absent | | listed-distinct column | — | present → absent | absent → absent | present → absent | After the change, on every row: the lead (code and class of fault, object and column) is kept, the dialect's own diagnostic is kept, and the cut's marker stands where the statement was. On the pg read and raw rows, the 22P02 value slot reads as the value marker. The raw line no longer carries a `statement:` field. The `driver-turso` remote transport, with a sentinel spelled inline in the sent statement: the raw terminal was handed it in the statement and not in the transport's bare error, and the line carries none of it. No marker appears there, because the bare error has no statement to cut. ## Zone 2 hypotheses - **H1 confirmed, with one amendment.** All five lines were driven on all three dialects. At base they sit at `sql-driver.ts` `:10087`, `:10215`, `:10284`, `:10960` and `:11253`. The amendment: on PostgreSQL, the three unresolvable-column lines never carried the sentinel. pg positions bindings as `$n` before knex formats the message, and its column diagnostic names identifiers only. Those three pg cells are recorded in the pin as non-regression cells, not as non-vacuous ones. The pg read and raw terminals did carry it, through the 22P02 diagnostic and through the raw statement's own text. - **H2 superseded in patch round 1.** Round 0 confirmed that `packages/core` could hold the module. Amendment 1 moved it to `packages/types`, where it also fits. Measured, the package takes a new runtime module: - its `tsup` entry is `src/index.ts` (edge-safe; the module uses no `node:` builtin); - its `tsconfig` includes `src/**/*`, and `--listFiles` shows both the module and its test; - `check-dts-emitted` runs in its build, and `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:published-files` all pass; - no gate refused it, and none was edited. The WHOLE module moved, not only the cutter. The two faces and the property rules are thin wrappers over the module's private split, so objectql no longer has a wrapper of its own. - **H3 confirmed.** Each line keeps its lead, plus `(CODE)` on the read and raw lines, and the dialect's diagnostic. It loses the statement and any template-owned value. The raw terminal's separately logged `statement:` field carried an inline sentinel on all three dialects at base, and it is no longer written. - **H4 partly falsified.** Every envelope's code, status, `cause` and withheld text are unchanged. But two composed messages described the log half ("the statement … written to the server log"), and this change made them false. They were corrected; see deviation 1. The engine's existing pins for the two earlier positions (the cards behind PR objectstack-ai#21335 and PR objectstack-ai#21384) stay green: - the full objectql suite, which includes `driver-fault-boundary-redaction.test.ts` and `driver-fault-redaction-residue.test.ts`; - the dogfood suite, which includes `raw-statement-fault-redaction.test.ts`; - the plugin-auth carrier pin, 15/15 on three dialects. ## Pins - **New: `packages/drivers/driver-sql/src/sql-driver-21385-refusal-log-line-redaction.test.ts`, 46 cases.** It runs on every cell of the driver axis: SQLite always, live PostgreSQL and MySQL when their URLs are set. - Per cell, each of the seven drives has two cases: - a SENTINEL case: the text handed to the line carried the sentinel as measured, the written line does not carry it, and the marker is present; - a CONTROL case: the envelope's code and status, the lead, the diagnostic, the dialect code and the named object and column. - Each cell also has one success control. - One case pins the deferred-DDL debug line. - Non-vacuity is read off what each protected refusal method was HANDED, through a recording subclass. Every assertion on a line is a boolean, so a red names the line and never prints it. - **Flipped: nine existing pins in eight files.** Each of these pinned the retired design, in which the statement was in the log line: - in `driver-sql`: `sql-driver-11455-…`, `-11541-…`, `-16019-…`, `-17639-…`, `-17857-…`, `sql-driver-backend-fault-envelope` (two cases) and `sql-driver-unresolvable-where-column-refusal` (the positive control); - in `driver-turso` (patch round 1): `turso-driver-16019-remote-raw-statement-fault-envelope`. Each now asserts the diagnostic and that the statement is absent. The `driver-sql` ones also assert the marker. The positive controls, and the turso pin, read the sentinel's presence on what the refusal was handed (or on the envelope's `cause`) instead of on the log. ## Reverse verification **The five calls (round 0).** The change was committed first (head `7445ed5cda`, `sql-driver.ts` blob `ede93583a0f1`). Only the five calls were reverted: the four identical call sites and the read terminal's one. This used two nested `scripts/ablation-replace.mjs` legs: anchor x4 → x0 (blob `ede93583a0f1` → `e4243feaf00e`), then anchor x1 → x0 (blob `e4243feaf00e` → `a8ea87a6014b`). The driver-sql pin loads `./sql-driver.js` from source, so no build sits between the mutation and the run. - **Mutated: 22 red / 24 green of 46.** - Red on "the sentinel reached the line": sqlite 7/7, mysql 7/7, pg 3 (read, raw bound, raw inline), and the debug-line case. That is 18. - Red on "says a statement was cut": the 4 pg cells that were never handed the sentinel (WHERE find and count, aggregate, distinct). - Green: all 21 CONTROL cases and the 3 success controls. - **Restored.** Proven by the tool twice and by a script trap once: blob == HEAD, and `git diff HEAD` is empty. **The turso flip (patch round 1, at `992e940fff`).** Only the `driver-sql` change this pin depends on was reverted: the raw terminal's dropped `statement:` field was put back. `driver-turso` reads `driver-sql` from its dist, so each leg was rebuilt and its dist checked before the run. - The first attempt was a no-op. The replacement text contained the anchor, so `ablation-replace.mjs` refused it (anchor x1 → x1) and ran nothing. The anchor was changed and the leg re-run. - **Mutate.** Anchor x1 → x0, blob `ae07547bcd68` → `025ec6208050`. The on-disk marker count was 1. `driver-sql` was rebuilt, and `ablation-dist-preflight.mjs` found the marker present in 2 built files. - The turso pin went 1 red / 3 green; the red is "the sentinel reached the server log". - The driver-sql raw pins went 7 red / 46 green: the six raw-terminal sentinel cases on three cells, and the `16019` raw-line pin. - **Restore.** Proven by the tool and by a trap: blob == HEAD `ae07547bcd68`, and `git diff HEAD` is empty. After a rebuild, the preflight with `--absent` found the marker absent from all 6 built files. The turso pin went back to 4/4, and the driver-sql raw pins to 53/53. ## Verification Final head: `992e940fff`. Live servers: PostgreSQL 16 and MySQL 8.0.46, throwaway instances that were stopped by recorded PID and removed. `TZ=America/New_York` was set, as the live CI job sets it. - `@objectstack/types`: `test` 23 files / 696 tests passed; `test:repo` 1 file / 7 tests passed; `typecheck` exit 0. - `@objectstack/core` (the module left it): `test` 76 files / 2156 tests passed; `typecheck` exit 0. - `@objectstack/objectql`: `test` 365 files / 7379 tests passed; `test:repo` 1 file / 5 tests passed; `typecheck` exit 0, with `check:test-typecheck` OK. - `@objectstack/driver-sql`, full suite (`vitest run --maxWorkers=2`), with both live URLs: 227 files passed; 5472 tests passed and 1 skipped; 0 sentinel occurrences in the run log. `typecheck`: exit 0. - `@objectstack/driver-turso`: `test` 88 files passed; 2365 tests passed and 33 skipped. `typecheck`: exit 0. - `@objectstack/driver-sqlite-wasm`: `test` 36 files / 675 tests passed; `typecheck` exit 0. - The `Test Core (1/6)` packages that CI never reached: - `spec`: `test` 600 files, 17606 passed + 1 todo; `test:repo` 48 files / 849 passed; - `service-settings` 33 / 591; - `cloud-connection` 31 / 401; - `service-messaging` 46 / 507; - `example-showcase` 31 / 394; - `plugin-pinyin-search` 2 / 21; - `connector-mcp` 3 / 23; - `knowledge-memory` 1 / 8. All exited 0. - Dogfood, against freshly built dists (`turbo run build --filter=@objectstack/dogfood... …`, 63/63), with both live URLs: `test` 171 files passed and 1 skipped; 1402 tests passed and 3 skipped. - `typecheck` exit 0, after `pnpm install --frozen-lockfile`. The first attempt failed on a missing link for `@objectstack/trigger-api`: the `main` merge had added that dependency, and this worktree's install predated the merge. - The plugin-auth carrier pin (`driver-fault-auth-log-carriers.test.ts`), on three dialects: 15/15. - The runtime files that read these lines (`seed-tenancy-autonumber-split`, `expected-read-refusal-noise.channel-asymmetry`, `metadata-list-ambient-vs-bare-transaction`, `first-boot-migration-gate-read`): 4 files, 22 tests passed. - Gates: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 70 at `992e940fff`. All 70 ran with exit 0, and `--ran` reconciles 70 derived / 70 run / 0 NOT-MEASURED / 0 UNRUN. - `check:dual-build-cjs-loads` first answered PREREQUISITE NOT MET (exit 3) for 8 packages without a dist. After those were built, it exited 0. - Also run: `pnpm check:live-db-isolation` PASS, and a control-byte self-scan of the 26 touched files, with no hit. - ESLint, narrowed to the 23 touched TS files, at `992e940fff`: - the population read from `eslint.config.mjs` is `packages/**/*.{ts,tsx,mts,cts}`; - `--format json` gives 23 files, 0 errors and 0 warnings; - invariance: the config enables no type-aware linting (no `parserOptions.project`), so this diff cannot move an untouched file's verdict. - The repo-wide `pnpm lint` is CI's. ## Patch round 1 - **Why.** CI on `7445ed5cda` went red in `Test Core (1/6)`, on the `driver-turso` pin that asserted the statement on the raw terminal's line. That pin is this PR's, and it is flipped here. The shard's first attempt had failed earlier, in an unrelated `spec` hook timeout (objectstack-ai#21421). Separately, the seat moved the cutter's home to `@objectstack/types` (amendment 1, 5954587444), so that objectstack-ai#21418 can call it from `operatorFacingErrorText`. - **What moved.** The module, its guard test and the four named exports moved from `packages/core` to `packages/types`, and core's export block was removed. Every importer was repointed, with the module-path strings and comments that named core. The core `minor` changeset became a types `minor` one, and the driver-sql and objectql changesets now name `@objectstack/types`. Net against `main`: one rename, `objectql` → `types`; `git diff origin/main...HEAD -- packages/core` is empty. - **The sweep for other pins of the retired line.** - Command: `git grep -n -E` over the test files of all 18 packages that depend on `@objectstack/driver-sql`. The pattern covered the five lines' leads, the `[sql-driver]` prefix, `refused a raw statement` / `refused a read on` / `could not be resolved on`, `kept server-side`, `statement: `, and an `includes('DATABASE_ERROR' | 'INVALID_FILTER' | 'INVALID_FIELD')` filter. - Result: 35 hit lines in 28 files. Read one by one, exactly one is a pin of the retired content, the `driver-turso` pin above. - The rest are prose, unrelated words, the objectstack-ai#7929 withheld-filter line, or line consumers that key on the lead and the diagnostic. The four runtime consumers among them were run, and are green. - No other lane's package needed an edit. - **Does `dispatch-gates --commands` derive the suites of packages that depend on a changed package?** Measured: no. - It maps a file surface to `check:*` gate families. Of its 70 commands at `992e940fff`, none is a package test suite: the only `--filter` command is `spec`'s `check:duration-unit-keys`. - So it derives neither the changed packages' own suites nor their dependents'. That is why round 0's local runs never reached `driver-turso`. ## Acceptance notes - **Deviation 1: two caller-facing envelope messages changed by one sentence each.** The dispatch said no caller-facing envelope changes. The read terminal's and the raw terminal's composed messages stated that the statement was written to the server log, and this change makes that false. The agent definition requires a released string that a change makes false to be corrected in that change, and it wins on a conflict. So each sentence now states what is written: the diagnostic, with the statement and its bound values cut. - The disclosure, code, status and `cause` are unchanged. - `operatorFacingErrorText`'s copy matches only the leading "refused to run a raw statement" fragment, which is kept; the producer pin `sql-driver-16657-…` is green. - Six hand-built fixture copies in five test files still carry the old second sentence, in `metadata`, `metadata-protocol`, `rest`, `types` and `objectql`. They stay green because the matcher keys only on the leading fragment. They are left as they are: four of the files sit outside this claim's surface, and editing only the fifth would split the copies. - **Bounded in-place extension: the read terminal's two debug lines.** The read terminal computes its dialect text once and writes it on the warn line or on one of two debug lines (a pre-DDL question, or a table whose DDL the driver deferred). The cut sits where the text is computed, so all three take it. It is the same defect class and the same mechanical call, in the claimed file, with the same gate family. It is pinned on the deferred-DDL debug line. - **The turso pin keeps no marker assertion.** The remote transport's error is bare (no statement in front of the diagnostic), so the cut has nothing to cut and adds no marker. The pin asserts the diagnostic, the class of fault, no sentinel and no `statement:` field. Non-vacuity is read off the sent statement the raw terminal was handed. - **The process timezone.** Three live-matrix files require the process zone to differ from UTC. Local runs set `TZ=America/New_York`, as CI's live job does. ## Out of scope (reported, not edited) - **`operatorFacingErrorText` (`@objectstack/types`) hands the raw path's `cause` text back whole.** Measured on SQLite with a synthetic sentinel bound into a raw statement: the envelope's message carries none, and the helper's answer carries it. This is objectstack-ai#21418's (the family's fourth position), which can now call the cutter from the same package. Its docblock also says the driver writes the statement one line earlier, which is no longer true. - **Stale prose outside this surface.** These no longer match the driver's lines: - `packages/qa/dogfood/test/raw-statement-fault-redaction.test.ts` (its header says the driver's raw line writes the statement); - `sql-driver-diagnostic-value-probe.test.ts`'s rationale for not importing the redactor (the module paths in its failure messages are updated here). --- _Generated by [Claude Code](https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #21345
Clause-②: no
Security handling: this body, the commits, the changeset and the test names carry classes and positions only. Every pin plants a synthetic sentinel and asserts it is ABSENT; no measured log line is copied anywhere.
What this changes
The engine-boundary cut from #21274 left two positions. Both now take the same helper,
redactPropagatedDriverFaultinpackages/objectql/src/driver-fault-redaction.ts. There is no second redaction and no copy of the cut, and the frozen verb list inpackages/types/src/error-leak.tsis untouched.ObjectQL.execute). The helper cutmessageandstackonly when the shared leak predicate recognised the text as a driver dump, and the predicate reads a statement by four leading verbs. The door now passes{ statementSent: true }: it handed the driver a statement, so it knows by construction that one may lead every message on the fault's chain. The cut then runs without asking the predicate. Same split, same structural cut at the separator, same value templates, same property rules. A statement whose leading verb is not one of the four leaves the bare marker, with no verb kept.lifecycle-service.ts). The sweep's per-object catch routes the fault through the same helper before it is pushed toreport.errorsor logged at WARN. Faults from the engine doors this loop also uses arrive already cut, and the helper hands those back unchanged.Measured baseline (before the fix)
Probe:
ObjectQL.executeover a realSqlDriver, one synthetic sentinel bound into the statement, an extractor printing only the carrier paths that hold it. Measured on better-sqlite3 13, live PostgreSQL 16 and live MySQL 8.0 at base23365eaed.cause.message,cause.stack, defaultinspectcause.message,cause.stack, defaultinspectcause.message,cause.stack, defaultinspectcause.message,cause.stack, defaultinspectcause.message,cause.stack, defaultinspectcause.message,cause.stack, defaultinspectIn every row the envelope's own message was composed,
String()and JSON were clean, and mysql2'ssqlwas already cut by the unconditional property rule. The engine's logger received nothing on this door, because the execute door writes no engine log line. After the fix, every row reads "none", with the class,code,statusandcause.codeunchanged.Zone 2 hypotheses
driver-sql's own raw-terminal line (see "Out of scope" below).{ statementSent: true }, in one place. The engine door is the cleaner site: it covers every driver behind it, and the triage direction's second clause holds there too, because the propagated fault'scauseleaves carrying no statement in any field.driver-sqlis not edited.mapDataErrorstatus, code andfield) and the missing-table classifier are pinned equal raw-versus-cut on every new shape. The [security] A driver error on an auth-table write reaches the auth library's logger unredacted: the server log carries the statement's bound values (credential material among them), while the engine's own line is redacted #21274 suites stay green:driver-fault-boundary-redaction.test.tswith its byte-identical WARN-line controls, the full objectql suite, and theplugin-authcarrier pin against the rebuilt objectql dist. That pin's SQLite cell passed 5/5; its PostgreSQL and MySQL cells were a named skip, because the live servers had been stopped by then.Per-site table: direct-driver calls in
lifecycle-service.tscold.syncSchemahot.finddriver-sql, the read terminal already composes its messagecold.upsert, per rowhot.bulkDeletecold.deleteManydriver.rotateShardsdriver.reclaimSpacedriver.count(name)with no filterdriver-sqlread fault is a composed envelopeengine.find)Pins
packages/objectql/src/driver-fault-redaction-residue.test.tsholds 48 cases:inspect,String, JSON), class, codes, non-enumerable cause, diagnostic, REST answer and idempotence.ObjectQL.execute, with no sentinel in the engine logger.report.errorsentry carries the sentinel, both keep the diagnostic, and nothing is hot-deleted.packages/qa/dogfood/test/raw-statement-fault-redaction.test.tsholds 10 cases on real stores:ObjectQL.executeover a realSqlDriver. SQLite always runs. The PostgreSQL and MySQL cells run whenOS_TEST_POSTGRES_URL/OS_TEST_MYSQL_URLare set, as a named skip otherwise, each in a schema or database derived from the file name.Reverse verification
Both legs were run with the fix committed, the mutation applied through
scripts/ablation-replace.mjs(anchor hit 1 to 0, blob changed, restored to the HEAD blob with an emptygit diff HEAD), objectql rebuilt, andscripts/ablation-dist-preflight.mjsreadingdist/before each colour was believed.Verification (final head)
Final head:
e036911f5b. The full suites ran at69ba7adfbd, the merge oforigin/mainf39760864c. The one later commit touches only the two new test files, which were re-run there, as were both typechecks.pnpm --filter @objectstack/objectql test: 363 files, 7325 tests passed.test:repo: 1 file, 5 tests passed.pnpm --filter @objectstack/objectql typecheck: exit 0, test layer included (check:test-typecheckOK, no new debt).pnpm --filter @objectstack/dogfood typecheck: exit 0 (itsincludeistest/**/*).pnpm --filter @objectstack/dogfood test, against freshly built dists with both live URLs set: 167 files passed and 1 skipped; 1379 tests passed and 3 skipped. The new file alone: 10/10 on SQLite, live PostgreSQL 16 and live MySQL 8.0.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 70 ate036911f5b. All 70 were run, every one exited 0, and--ranreconciles 70/70.check:dual-build-cjs-loadsfirst answered PREREQUISITE NOT MET (exit 3, nothing measured). The 8 packages it named were then built (a full turbo cache hit), and it re-ran with exit 0.pnpm check:live-db-isolationPASS (it sees the new live file),node scripts/check-nul-bytes.mjsexit 0, and a control-byte self-scan of every touched file with no hit.eslint.config.mjs:packages/**/*.{ts,tsx,mts,cts}. JSON output: 5 files, 0 errors, 0 warnings.parserOptions.project), so this diff cannot move any untouched file's verdict.pnpm lintis CI's.Acceptance notes and deviations
objectql". The real-driver pin lives inpackages/qa/dogfood/test/, becauseobjectqlhas nodriver-sqldependency and dogfood is where this repo pairs an objectql unit pin with a real-driver pin. Dogfood is private, so the changeset is unaffected.Lint & Repo Gatesscript set locally. The agent definition rules that enumeration CI's, and says it wins on a conflict. The derived union, plus the named extras above, ran locally, and CI runs the full set.Out of scope (reported, not edited)
driver-sql's own server-log line for a refused raw statement.rawStatementFaultwrites the statement and the dialect's message to the driver logger before composing the envelope.driver-sql, which this dispatch stops at, so the dev report raises it for the seat and the maintainer. The dogfood pin silences that logger and names the position in its header.Generated by Claude Code