Skip to content

runtime: withhold the cross-field refusal's own engine noise (#10983) - #11246

Merged
os-elon merged 1 commit into
mainfrom
claude/issue-10983-cross-field-refusal-noise
Aug 23, 2026
Merged

runtime: withhold the cross-field refusal's own engine noise (#10983)#11246
os-elon merged 1 commit into
mainfrom
claude/issue-10983-cross-field-refusal-noise

Conversation

@os-elon

Copy link
Copy Markdown
Collaborator

Fixes#10983

What changed

packages/runtime/src/expected-read-refusal-noise.ts gets a second, independent
predicate
captureExpectedCrossFieldRefusalNoise(objects) — alongside the existing
table-keyed captureExpectedReadRefusals. cross-field-refusal-operand-withhold.test.ts
now installs it on its ObjectQL engine (the CRUD-face describe block) before any read
runs, and asserts the withheld counts in that block's own afterAll.

The existing table-keyed predicate is untouched — no lines in it were changed, only new
code was added after it.

Why a second predicate (per triage, comment 5380559336)

The existing predicate withholds an engine Find operation failed frame only when it
sits above a driver refusal its own captureDriver sink already recognised (table +
no such table reason). A cross-field { $field } refusal (#7929) never reaches
SqlDriver.backendStatementFault — it's a compile-time validation refusal — so there is
no driver-channel line, no pending entry, and no table at all for the existing
predicate to key on.

The key, and why it's stable

Measured directly off a real run (--reporter=default, see below): the 6 ERROR frames in
this file carry two different message shapes, both produced by
uncompilableFieldReferenceError in driver-sql/src/sql-driver.ts:

A predicate keyed on the withheld wording alone would silently miss the disclosed half —
4 withheld, 2 loud is a partial mute with a passing assertion on top. Both strings share
exactly two substrings that no other refusal in the file shares: cannot be compiled here (grepped — appears nowhere else in sql-driver.ts; it's this one builder's own
wording) and $field. Requiring both, mirroring the existing predicate's "table
AND reason" pairing, keeps a sibling { $field } family (bareFieldReferenceError's
"bare field reference … with no operator" — contains $field but never "cannot be
compiled here") outside the match.

How the counting/assert side survives losing the table dimension

There's no driver-channel table to count against, so the counting dimension moves from
"per table, across two correlated channels" to "per object, on the one channel that
exists" (the engine frame's own object meta, scoped to the caller's declared list). What
does not change: a frame is withheld only on an exact identity match (declared object
AND both message markers), the withholding is counted per object, and the caller
asserts those counts — expect(crossFieldNoise.silentChannels()).toEqual([]) and
expect(crossFieldNoise.totalFrames()).toBe(6) in the CRUD-face describe's afterAll. A
capture nobody asserts is a mute, whichever dimension it counts by.

Measurement — before / after (--reporter=default, required to match CI)

pnpm --filter @objectstack/runtime exec vitest run --reporter=default --maxWorkers=2 \
src/cross-field-refusal-operand-withhold.test.ts
beforeafter
ERROR Find operation failed (this file)60
tests passing11/1111/11

Full-package sweep (pnpm --filter @objectstack/runtime exec vitest run --reporter=default --maxWorkers=2, no path filter): 183 files / 2706 tests, 0ERROR Find operation failed lines anywhere in the package — consistent with #10629's own after-measurement (0
for its own population) now that this file's 6 are also withheld.

Anti-vacuity

  1. Exactly 6, not 0 and not partial. The suite's afterAll asserts
    totalFrames() === 6 — a run that withholds 0 (or any count other than 6) fails the
    suite. Verified by breaking the predicate (see leg 3) and confirming the assertion
    actually reds.
  2. An unexpected error on the same channel/object stays loud. Isolated probe against
    the predicate directly (fake engine.logger.error, not the real driver): an unrelated
    Error ("DATABASE_ERROR: the connection pool was destroyed mid-statement") on
    object: 'cross_field_deal' reaches the loud sink untouched — not withheld, not
    counted. Also checked: a matching message on an undeclared object stays loud
    (object-scoped, like the table predicate), and a sibling { $field } family (bare
    field reference — contains $field but not "cannot be compiled here") is not
    swallowed.
  3. Reverse-verification — full integration, not just the isolated probe. With the
    fix committed, temporarily changed the predicate's matched phrase to a string that
    cannot appear (REVERSE_VERIFICATION_PROBE_NEVER_MATCHES), reran the same
    --reporter=default command:
    • the 6 ERROR Find operation failed frames came back loud (verbatim, matching the
      "before" measurement byte-for-byte);
    • the suite's own afterAll assertion failed
      (AssertionError: expected [ Array(1) ] to deeply equal []silentChannels()
      correctly named the now-unmatched channel), proving the assert side is real and not
      vacuous;
    • reverted with git checkout HEAD -- packages/runtime/src/expected-read-refusal-noise.ts
      back to the committed, correct predicate (confirmed clean via git diff --stat HEAD).

Changeset

None.expected-read-refusal-noise.ts is test-only by its own docblock (not imported
by src/index.ts, so tsup never bundles it) and packages/runtime/package.json's
"files" is ["dist", "README.md", "CHANGELOG.md"] — nothing in this diff ships. Purely
test-noise suppression, no shipped-behaviour change.

Gates run

All of the below ran against the final commit 1e3b71d419.

  • pnpm --filter @objectstack/runtime test (--reporter=default --maxWorkers=2, no path
    filter) — Test Files 183 passed (183) / Tests 2706 passed (2706), 0 ERROR Find operation failed lines anywhere in the package.
  • pnpm --filter @objectstack/runtime typecheck — clean (tsc --noEmit, no output).
  • pnpm --filter @objectstack/runtime build — clean (tsup, DTS build success).
  • node scripts/pm/dispatch-gates.mjs derived these named local gates; every one run and
    green, verdict line quoted:
    • pnpm check:cross-package-test-inputs (explicitly re-run per standing instruction)
      OK: 14 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob. (plus its own 104/104 self-test)
    • pnpm check:published-files69 publishable package(s) ... declare a files whitelist that covers every entry point ...; 1 publish more than dist/ + README.md + CHANGELOG.md, each with a registered reason.
    • pnpm check:slot-lookupslot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new ... baseline key set verified against e4a71d4: no files added.
    • pnpm check:test-source-aliascheck-test-source-alias OK — 72 packages with tests scanned; ...
    • pnpm check:type-source-resolutioncheck-type-source-resolution OK — 77 packages with a tsconfig.json scanned; ...
    • node scripts/check-ci-filter-parity.mjsOK: all 88 declared cross-package glob(s) (76 unique) are covered by core or crosspkg ...
    • node scripts/check-cross-package-test-inputs.mjs — same OK line as above (ci.yml
      entry point)
    • node scripts/check-plugin-teardown-shape.mjs63 Plugin implementation(s) ...; every teardown-shaped method ... sits beside a real destroy() (0 known-unreached, SHRINK-ONLY, baseline fully burned down).
    • node scripts/docs-audit/check-affected-docs.mjs — exit 0, informational
      reachability report only (no assertion failure).
    • Test-file-edit convention set:
      • pnpm check:query-options-erasurequery-options-erasure ratchet holds: 67 unswept non-test site(s) in 17 file(s), none new ...; baseline key set verified against e4a71d4: no files added.
      • pnpm check:type-check-coveragecheck-type-check-coverage: OK — 65/78 workspace packages type-checked (plus the root), 13 in the DEBT ledger ..., 1 exempt.
      • pnpm check:type-check-debt (workspace closure built first —
        pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*',
        70/70 tasks successful — then re-measured) — check-type-check-coverage --re-measure: OK — 33 ledger entr(ies) re-measured in 240.1s, 1896 raw tsc error(s) total, none above its recorded number. (an unrelated pre-existing-debt
        improvement surfaced — @objectstack/runtime: TEST_DEBT records 227, tsc now reports 225 (-2) — not introduced by this diff, left as-is; lowering ledger
        ceilings for packages this card did not touch is out of scope here)
      • pnpm check:engine-double-contractcheck-engine-double-contract: OK — 384 pinned, 133 in the DEBT ledger, 2 exempt.
      • pnpm check:where-matcherwhere-matcher conformance holds: 282 matcher(s) discovered, 282 answer the combinator battery correctly or refuse it loudly (170 refuse). 0 silently-wrong and 0 unjudged matcher(s) ...; baseline key set verified against e4a71d4: no files added.
  • pnpm check:nul-bytescheck-nul-bytes: OK (scanned 6521 text file(s) ...; no raw ASCII control bytes).

Out of scope

Nothing found beyond this card's scope during implementation.


Generated by Claude Code

extend expected-read-refusal-noise.ts with a second predicate keyed on
the cross-field refusal's own message identity, since the refusal never
reaches the driver's backendStatementFault and so has no table to key
on. Counts per object instead of per table; the caller asserts the
counts in its own afterAll, same withhold-and-assert discipline as
#10629/#10630.
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

6 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 45 of 221 client-bound route-ledger rows — the other 176 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run: node scripts/docs-audit/affected-docs.mjs --bridge-coverage

Coarse fallback — 23 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 824a996c07e7c7ae7a6f84159233ee779122c283packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8d5ea8388cb9486506cccb301dbd9708a3489e78 — the merge of head 1e3b71d4192d3fa7fc624ba59f6d4d9463fdc107 into base 824a996c07e7c7ae7a6f84159233ee779122c283, 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 8d5ea8388cb9486506cccb301dbd9708a3489e78 && git checkout 8d5ea8388cb9486506cccb301dbd9708a3489e78
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 824a996c07e7c7ae7a6f84159233ee779122c283 1e3b71d4192d3fa7fc624ba59f6d4d9463fdc107 && git checkout -B drift-repro 824a996c07e7c7ae7a6f84159233ee779122c283 && git merge --no-ff 1e3b71d4192d3fa7fc624ba59f6d4d9463fdc107
node scripts/docs-audit/affected-docs.mjs --json 824a996c07e7c7ae7a6f84159233ee779122c283

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-elonos-elon added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 23, 2026 — with Claude
@os-elonClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM seat: applied the skip-changeset label. Check Changeset was the one red check — the six required checks are all green.

Why the label rather than a changeset

The PR body's reasoning is right on the facts, and I verified it independently at origin/main rather than taking it on report:

  • every importer of expected-read-refusal-noise.ts is a *.test.ts file (16 of them, no production source);
  • it is not referenced from packages/runtime/src/index.ts, package.json, or tsup.config.ts, so it is unreachable from the bundle entry;
  • packages/runtime's files is ["dist", "README.md", "CHANGELOG.md"];
  • the diff is exactly two files, both on the test surface.

So the PR genuinely releases nothing. What was missing is that this repo makes that a declaration, not an absence — the gate's own message says so: "If it releases nothing … apply the skip-changeset label … An empty-frontmatter changeset is NOT a third option any more." The fact was right; the convention wanted it stated.

⛔ Worth being explicit that this is not a gate being weakened: skip-changeset is the affordance this gate declares for exactly this case, and applying it truthfully is the gate working as designed. Applying it to a PR that did ship something would be the weakening.

On the diff itself

One thing in here went further than the dispatch asked for and is worth recording. The predicate's key was measured, not assumed — and the measurement found that the 6 frames carry two message shapes, not one: the withheld generic wording (4 of 6) and the #8220 author-disclosed wording (2 of 6). The docblock states the consequence exactly:

A predicate keyed on the withheld wording alone would silently miss the disclosed half — 4 of 6 withheld and 2 loud is not "expected-noise withholding", it is a partial mute with a passing assertion sitting on top of it.

That is the failure family this whole helper exists against, caught before the predicate was written rather than after. The uniqueness of cannot be compiled here was then verified by source grep, and the sibling bareFieldReferenceError family — which carries $field but not that phrase — was deliberately left loud, mirroring the existing predicate's "table AND reason" pairing.

Re-checking CI now; enqueueing once Check Changeset re-evaluates green.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@os-elon@claude