Skip to content

refactor phase 0: safety net (SCC ratchet, real lint gate, CI matrix, soundness reorg) - #295

Merged
hussainsultan merged 10 commits into
mainfrom
refactor/phase0-safety-net
Aug 18, 2026
Merged

refactor phase 0: safety net (SCC ratchet, real lint gate, CI matrix, soundness reorg)#295
hussainsultan merged 10 commits into
mainfrom
refactor/phase0-safety-net

Conversation

@hussainsultan

Copy link
Copy Markdown
Collaborator

Phase 0 of the SCC-driven refactor plan: lock the safety net before any structural change. No compiler logic is touched; the full suite is green (1707 passed, 1 skipped, 11 xfailed).

What's in here

Import-graph SCC ratchet (tests/test_import_graph.py)
The intra-package import graph (lazy function-local imports counted as edges — they are cycle workarounds, not absences of a dependency) contains one 23-module strongly connected component: __init__, ops, expr, query, api, serialization/*, chart/*, and more are all mutually importable. The new test snapshots that component as a shrink-only allowlist: no module may join a cycle, and modules detached by later phases must be removed from the list in the same PR. End state: an acyclic, layered module graph.

Lint gate now enforces what the config claims
CI ran ruff check --select F,E9 while pyproject configured E,F,I,UP,B,SIM. All 125 latent violations are fixed (import sorting, contextlib.suppress, unused loop vars, one B023 loop-capture binding, ops.py E402s); CI runs the full ruleset plus ruff format --check; pre-commit's ruff hook is un-skipped and pinned to the locked ruff version. Deliberate, documented ignores: E731/E741 (named lambdas and the l, r join-predicate convention), tests get E402 + B017 (revisit with the phase-2 exception hierarchy). One mechanical ruff format commit (75 files).

CI matrix + faster suite

  • Python 3.11 / 3.12 / 3.13 on the full leg; no-xorq leg on 3.12
  • pytest -n auto via pytest-xdist; --strict-markers + declared integration marker
  • Weekly scheduled job runs make test IBIS_VERSION=all so upstream ibis releases can't silently break us between pushes

Packaging fixes

  • The bsl console script is installed unconditionally but imported python-dotenv (agent extra) at module level — a plain pip install boring-semantic-layer yielded a broken command. The import is now guarded; skill management works everywhere, and loading an explicit env file without the dep raises a clear install hint.
  • Wheels no longer ship test suites, fixtures, or the sys.path-mutating conftest (verified: 0 test files in the built wheel).
  • Deleted agents/chats/slack.py: unimportable dead code (imported a nonexistent backends.langchain.LangChainAgent, referenced a nonexistent [slack] extra, zero referrers, zero tests).

Soundness suites reorganized by invariant
The chronological test_soundness_roundN files were bug-fix journals — a failure didn't say which invariant it guarded. They now live under tests/soundness/, named by invariant (test_fanout_preagg_regressions, test_join_many_participation, …) with a README mapping each file to its original finding IDs and a do-not-weaken warning. Test bodies unchanged; also commits the previously untracked round-5 suite (12 passing tests). 152 tests total.

Hygiene
Stale RELEASE_NOTES_v0.3.12.md and docs/web/bun.lockb (CI builds with npm) removed; ghost ops//malloy/ bytecode-only directories purged; uv.lock/requirements-dev.txt relocked for pytest-xdist (xorq's packager exports --locked).

Verification

  • python3 -m pytest src/boring_semantic_layer: 1707 passed, 1 skipped, 11 xfailed, 4 xpassed
  • ruff check . and ruff format --check .: clean
  • Built wheel inspected: 0 test files
  • bsl import verified with python-dotenv absent

Next phase: dead-code deletion + the four cheap edge cuts that detach the agents and chart clusters from the SCC.

🤖 Generated with Claude Code

hussainsultan and others added 10 commits August 18, 2026 10:31
Measures the intra-package import graph (AST-level, counting lazy
function-local imports as edges) and locks in the current 23-module
strongly connected component as a shrink-only allowlist. No module may
join a cycle; detached modules must be removed from the allowlist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The configured rules (E,F,I,UP,B,SIM) were never enforced (CI ran
--select F,E9 only). Fix all 125 violations: import sorting, unused
loop variables, contextlib.suppress, ternaries, explicit zip strict,
bind the loop variable in resolve_on_join (B023), and move
_reductions_for_expr below ops.py's import block (E402).

Deliberate ignores, now documented in pyproject: E731/E741 (named
lambdas and l/r join-predicate convention), tests get E402+B017.
Dead ignores referencing unselected rules (S101, COM812, PLR2004,
ANN) removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mechanical formatting only; ruff format --check joins CI in this
branch so drift can't reaccumulate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ests

- CI lint now runs the full configured ruleset plus ruff format --check
  (was --select F,E9 only); pre-commit's ruff hook is un-skipped and
  pinned to the locked ruff version
- Test matrix covers Python 3.11-3.13 (full) and the no-xorq leg;
  pytest runs with -n auto via pytest-xdist
- Weekly scheduled job runs make test IBIS_VERSION=all so upstream
  ibis releases can't silently break us
- pytest: --strict-markers and a declared integration marker
- Wheel no longer ships test suites, fixtures, or the sys.path-mutating
  conftest (verified: 0 test files in built wheel)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bsl entry point is installed unconditionally but agents/cli.py
imported python-dotenv (agent extra) at module level, so a plain
install produced a broken command. The import is now guarded: skill
management works everywhere; loading an explicit env file without the
dependency raises a clear install hint.

Also delete agents/chats/slack.py: unimportable dead code — it imported
agents.backends.langchain.LangChainAgent, which does not exist (the
real backend is LangGraphBackend with a different interface), and
referenced a nonexistent [slack] extra. No referrers, no tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ode dirs

- RELEASE_NOTES_v0.3.12.md: one-off notes for a past release
- docs/web/bun.lockb: CI builds with npm ci + package-lock.json; the
  bun lockfile was stale and misleading
- src/boring_semantic_layer/{ops,malloy}/: directories containing only
  orphaned __pycache__ from deleted packages (untracked; removed from
  the working tree so the names stop shadowing future modules)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'round N' regression files were chronological bug-fix journals; a
reader (or a refactor) couldn't tell which invariant a failure guarded
without opening the file. Group them under tests/soundness/ named by
the invariant each pins, with a README index mapping files to the
original finding IDs. Test bodies are unchanged; this also commits the
previously untracked round-5 suite (12 tests, passing on main) as
test_join_namespacing_and_inline_totals.py.

152 tests, all passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
uv.lock and requirements-dev.txt regenerated after adding pytest-xdist
to the test-core and dev extras; xorq's packager exports with --locked
and fails on a stale lockfile (caught by test_xorq_rebuild).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
examples/{malloy_interop,nested_queries,worldcup}.py are untracked
local work that a broad 'git add -- examples' swept into the lint
commit by mistake. malloy_interop.py imports boring_semantic_layer
.malloy, which only exists on feat/malloy-interop, so 'make examples'
failed in CI. Restore all three to untracked working-tree files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The same broad 'git add -- src' that swept the WIP examples also
tracked test_soundness_round5.py at its pre-reorg path; the suite
lives at soundness/test_join_namespacing_and_inline_totals.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hussainsultan
hussainsultan marked this pull request as ready for review August 18, 2026 23:03
@hussainsultan
hussainsultan merged commit 6e96525 into main Aug 18, 2026
9 checks passed
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.

1 participant