Make the import-surface scan cover symlinked external plugins
All checks were successful
CI / backend (push) Successful in 23s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s

Path.rglob does not descend symlinks, so a symlinked external plugin
(the ADR-003 dev loop) silently escaped the contract-purity scan. The
scanner now resolves plugin dirs before walking, a regression test
plants a symlinked plugin with a real violation and asserts it is
flagged, and the known-limitation notes in the external-repo docs are
lifted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-11 10:36:28 -04:00
parent 529b9f2fed
commit 81178b7be3
3 changed files with 52 additions and 14 deletions

View File

@@ -32,12 +32,12 @@
# # Offline: test a bundled plugin against this checkout, no network
# LOCAL_FRAMEWORK=. PLUGIN_DIR=plugins/warranty scripts/test-external-plugin.sh
#
# Note on coverage: a symlinked plugin is discovered and loaded by the plugin
# loader (so loadability, manifest validity, and the core_version range are all
# checked), but the import-surface scan in test_plugin_contract.py uses
# Path.rglob over plugins/, which does not descend symlinked directories on
# CPython 3.12. To have that scan cover your plugin too, keep an equivalent
# import-surface assertion in your own tests/ (see docs/PLUGIN-EXTERNAL-REPO.md).
# Coverage: a symlinked plugin is discovered and loaded by the plugin loader
# (loadability, manifest validity, core_version range) AND scanned by the
# import-surface contract test - the scanner resolves each plugin dir before
# walking, since bare Path.rglob does not descend symlinks. Optionally keep an
# equivalent import-surface assertion in your own tests/ so violations fail
# in your repo's CI too (see docs/PLUGIN-EXTERNAL-REPO.md).
set -eu