Skip to content

test(mutation): mutate sql_builder + nl_queries live (B2)#115

Merged
brownjuly2003-code merged 2 commits into
mainfrom
test/mutation-b2-query-modules
Jun 29, 2026
Merged

test(mutation): mutate sql_builder + nl_queries live (B2)#115
brownjuly2003-code merged 2 commits into
mainfrom
test/mutation-b2-query-modules

Conversation

@brownjuly2003-code

Copy link
Copy Markdown
Owner

What

Close the mutation declared-vs-live gap for the NL→SQL query surface (roadmap R2 / B2): make sql_builder.py and nl_queries.py mutate live in the gate, not just be declared.

  • Add serving/semantic_layer/query/sql_builder.py and .../nl_queries.py to MODULE_TARGETS in scripts/mutation_report.py (threshold 0.90 each, real gate — sub-threshold → non-zero exit).
  • New duckdb-free, fixtureless tests tests/unit/test_sql_builder_mutation.py (583 LOC) and test_nl_queries_mutation.py (855 LOC): both stub serving.semantic_layer.query.{engine,contracts} + src.* helpers before importing under a top-level serving package; nl_queries repoints its .sql_guard shim at the real top-level guard so the validate_nl_sql boundary is genuinely exercised.
  • tests/unit/test_mutmut_policy.py: narrow the declared-only serving surface to just auth (manager / key_rotation) — the remaining B3 item.

This follows the proven pattern from sql_guard / masking / rate_limiter (B1, #114).

Verification

  • Local (WSL mutmut, py3.10): sql_builder 96.0% (killed 167/174), nl_queries 94.4% (killed 323/342); survivors are documented equivalents.
  • Golden gate (py3.11): mutation.yml dispatched on this branch — see run linked in checks; both modules gate at ≥90%.
  • Standard required CI (ruff, mypy strict, full unit suite) runs on this PR.

Scope

Test/config only — no src/ changes. Next: B3 (auth manager + key_rotation live).

Close the declared-vs-live gap for the query surface: sql_builder.py and
nl_queries.py were declared mutation targets but the gate only ran retry,
sql_guard, masking and rate_limiter. Add duckdb-free fixtureless mutation
tests for both and wire them into scripts/mutation_report.py MODULE_TARGETS
@ 0.90, so 6 of 8 security modules are now mutated live (auth manager /
key_rotation remain declared-only pending their own duckdb-free tests).

Both modules live under the query package whose __init__ imports the
duckdb-backed QueryEngine, so each test stubs
serving.semantic_layer.query.{engine,contracts} (plus the src.* helpers)
before importing the module under a top-level `serving` name. nl_queries'
.sql_guard shim is repointed at the real top-level sql_guard so the
validate_nl_sql boundary runs against the genuine guard.

Reproduced on the WSL/mutmut harness (py3.10): sql_builder 96.0%
(killed 167/174), nl_queries 94.4% (killed 323/342). Remaining survivors
are documented equivalents (typing.cast type-string, dialect=duckdb->None
renders, sqlglot/regex table-extraction convergence, telemetry no-ops,
*1001 elapsed). The CI gate (mutation.yml, py3.11) is the source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

DORA Metrics

  • Window: last 30 days
  • Branch: main
  • Deployment frequency: 156 total / 36.4 per week
  • Lead time for changes: avg 0.28h / median 0.0h
  • Change failure rate: 62.18% (97/156)
  • MTTR: 0.25h across 3 incident(s)

…arness (B2)

The B2 duckdb-free mutation tests gated stub installation on `import src`
succeeding ("workspace has no top-level src"). That assumption is false: the
editable-installed repo keeps the real `src` on sys.path even inside mutmut's
mutants/ workspace, so the stubs were skipped there and the import fell through
to the real `src.serving.semantic_layer.query` package -> `from .engine import
QueryEngine` -> `import duckdb`. Under mutmut's coverage-instrumented stats pass
on py3.11 that trips duckdb's lazy `_duckdb._sqltypes` import (the same break
ci.yml already works around with `coverage run`), so `mutmut run` exited -11 with
no scored mutants and the gate failed.

Discriminate on the real signal instead: the workspace copies src/serving to a
TOP-LEVEL `serving` package, which ordinary pytest never has. Gate stub install
on `importlib.util.find_spec("serving")`. The stub path (engine/contracts/auth
neutered to no-ops) was effectively never exercised before -- WSL py3.10 also had
`src` importable, so its 96.0%/94.4% came from the real modules.

Verified locally in a simulated workspace (top-level `serving` + editable `src`,
as in CI): both modules import with duckdb NOT in sys.modules, subject under test
is `serving.semantic_layer.query.*` (the mutation target), 101 tests pass via the
stub path; the ordinary-pytest path still passes 101.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@brownjuly2003-code

Copy link
Copy Markdown
Owner Author

Update — py3.11 gate green after a harness fix.

The first mutation.yml dispatch on this branch failed: mutmut run exited -11 with no scored mutants for both modules. Root cause was not a low score — the duckdb-free tests still pulled real duckdb in the workspace. The stub guard keyed on import src, but the editable-installed repo keeps src on sys.path even inside mutmut's mutants/ workspace, so the stubs were skipped and the import fell through to the real query/__init__from .engine import QueryEngineimport duckdb. Under mutmut's coverage-instrumented stats pass on py3.11 that trips duckdb's lazy _duckdb._sqltypes import (the same break ci.yml already works around with coverage run).

Fix (2aebace): gate stub install on the real signal — the workspace's top-level serving package (find_spec("serving")), which ordinary pytest never has. Verified locally in a simulated workspace (top-level serving + editable src): both modules import with duckdb not in sys.modules, 101 tests pass via the stub path, ordinary pytest still 101.

Golden gate (py3.11, run 28407501469) — Mutation scores meet thresholds:

  • sql_builder.py: 96.0% (killed 167, survived 7) — threshold 90%
  • nl_queries.py: 94.4% (killed 323, survived 19) — threshold 90%

Matches the WSL py3.10 reproduction exactly.

@brownjuly2003-code brownjuly2003-code merged commit 2ad6665 into main Jun 29, 2026
20 checks passed
@brownjuly2003-code brownjuly2003-code deleted the test/mutation-b2-query-modules branch June 29, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants