Skip to content

fix(python): break trust and projects import cycle - #2387

Merged
codeforester merged 3 commits into
mainfrom
enhancement/2356-20260928-fix-python-break-the-circular-import-between-base-trust-and
Sep 28, 2026
Merged

codeforester merged 3 commits into
mainfrom
enhancement/2356-20260928-fix-python-break-the-circular-import-between-base-trust-and

Conversation

@codeforester

@codeforester codeforester commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Break the base_trust/base_projects import cycle by moving shared manifest-trust primitives to the neutral base_setup layer, preserving compatibility facades, and deferring project imports in the trust engine. Add subprocess import-boundary coverage.

Validation

  • 1,705 Python tests
  • 394 subtests
  • Pylint
  • git diff --check

Fixes #2356

@codeforester
codeforester requested a review from a team as a code owner September 28, 2026 06:34
@codeforester

Copy link
Copy Markdown
Collaborator Author

Automated review findings (no correctness bugs found; the trust_store.py/guidance.py -> manifest_trust.py/manifest_trust_guidance.py moves are confirmed byte-identical, and both new shims' __all__ lists are verified complete against every real caller in the repo)

  1. cli/python/base_trust/engine.py (~line 11): every base_projects import except one was converted to a function-local lazy import to break the cycle, but from base_projects.workspace_errors import ProjectDiscoveryError was left at module level with no stated reason for the exception. Not wrong today, but there's no rule a future contributor can follow to know which base_projects imports need to stay lazy versus which are safe at module scope - if workspace_errors (or anything it imports) ever grows a back-reference into base_trust, the cycle returns silently since this one import was never made consistent with the rest.

  2. cli/python/base_trust/tests/test_import_boundaries.py (~line 31): the new regression test only asserts two specific module pairs don't cross-import (base_trust.engine vs. base_projects.engine/workspace_onboarding), not a general layering invariant like "base_trust/base_setup must never import base_projects at module scope." A future cycle formed through a different pair (e.g. base_trust.guidance -> some base_projects module) would pass this test untouched, so the same class of import-time crash this PR fixes could reappear without any test catching it.

  3. cli/python/base_trust/trust_store.py (~line 5): imports run_git/parse_origin_remote with # pylint: disable=unused-import, but never uses or re-exports them (they're absent from the file's own __all__, unlike every other imported symbol). Confirmed these exist solely to satisfy cli/python/base_setup/tests/test_compatibility_facades.py::test_trust_store_uses_focused_git_modules, which does a literal source-text assertIn check for those two import lines rather than testing any behavior. Simpler: delete the two unused imports and either drop that assertion or rewrite it as a behavioral test - as written, the test forces production code to carry dead, lint-suppressed imports indefinitely.

Posted via Claude Code

@codeforester

Copy link
Copy Markdown
Collaborator Author

Follow-up on the previous review comment

All three findings are addressed, two fully:

  1. run_git/parse_origin_remote in trust_store.py: fully fixed. Unused imports removed, and the brittle text-matching test (test_trust_store_uses_focused_git_modules) was replaced with a genuine behavioral test (test_manifest_trust_git_identity_helpers_use_focused_modules) that mocks the helpers and asserts they're actually called correctly.

  2. The workspace_errors import in engine.py: fixed via a documented justification comment rather than making it lazy - and the claim checks out: workspace_errors.py contains only exception class definitions with zero imports of its own, so it genuinely cannot introduce a cycle. Good resolution.

  3. The general layering invariant in test_import_boundaries.py: broadened meaningfully (grew from 2 to 5 checked module pairs, plus a new "importing manifest_trust/manifest_trust_guidance pulls in no base_projects.* at all" check) - real progress, and confirmed via repo-wide grep that no live gap exists today. But it's still entry-point-based (4 named entry points), not a full scan of every base_trust/base_setup submodule for module-scope base_projects imports. A new file added later that isn't reachable from one of those 4 entry points still wouldn't be caught by this test. Not blocking, but worth a note for whoever next touches import boundaries here.

51/51 tests pass across base_trust/tests/ and base_setup/tests/test_compatibility_facades.py.

Posted via Claude Code

@codeforester
codeforester merged commit 2677c48 into main Sep 28, 2026
22 checks passed
@codeforester
codeforester deleted the enhancement/2356-20260928-fix-python-break-the-circular-import-between-base-trust-and branch September 28, 2026 18:00
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.

fix(python): break the circular import between base_trust and base_projects

1 participant