The four delegation scripts become a real package. Their old paths stay as
shims because those paths are a wire contract: agent instructions, the bash
wrapper, SKILL.md, BOOTSTRAP.md, deploy/install.sh and three test modules all
call them literally.
The shim binds the lib_py.delegation *package* to the tree beside it, once per
process, and never touches sys.path. Two cheaper designs were rejected with
evidence (the context matrix now lives in the test suite):
* inserting the sibling skills dir at sys.path[0] makes the first sandbox
copy imported under pytest shadow lib_py.agents/layout/state for the whole
session, and the identity assertion cannot see it -- `is` proves same
object, not same tree.
* loading only the named module by file path leaves a module that imports
siblings pulling them from whichever tree is on the path, so a frozen
publish_event ran against live dependencies and lost half of B-13.
Binding the package fixes both: one tree for all delegation modules, the parent
lib_py untouched, and a sys.path append only when no lib_py exists anywhere
(true standalone). Bind-once rather than nearest-wins, because rebinding would
split existing references and break monkeypatching.
Also moves the env-file load off import (_load_dotenv -> ensure_env_loaded,
called by each process entry point including reconcile.sh's embedded
subscriber), so importing the library no longer mutates os.environ.
Verified: PV-1 identity+provenance, PV-4's ten import scenarios plus K1/K3/K6
in fresh interpreters, PV-5 shim byte-identity, an AST check that the package
imports no sibling lib_py module, and --help output diffed against the
pre-move capture.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
38 lines
2.1 KiB
Python
Executable File
38 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Compatibility shim -- the implementation lives in lib_py.delegation.registry.
|
|
|
|
This file's path is a wire contract (agent instructions, the bash wrapper,
|
|
SKILL.md, BOOTSTRAP.md, deploy/install.sh, tests). It binds the
|
|
``lib_py.delegation`` *package* to the tree next to this file, once per process,
|
|
without touching ``sys.path``; ``import registry`` then yields the very same module
|
|
object as ``lib_py.delegation.registry``.
|
|
|
|
Why the package and not this one module: a per-module bind leaves a non-leaf
|
|
module (one that imports its siblings) importing dependencies from whichever tree
|
|
happens to be on the path, mixing a frozen copy with a live one. Why bind-once and
|
|
never rebind: replacing a bound package would split existing references and
|
|
break monkeypatching. See docs/contracts/issue-5/ (D2) for the context matrix.
|
|
"""
|
|
import importlib, importlib.util, os, sys
|
|
_SKILLS = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
_PKG = "lib_py.delegation"
|
|
if _PKG not in sys.modules: # bind once per process; never rebind
|
|
try:
|
|
import lib_py # parent resolved normally; shims never rebind it
|
|
except ModuleNotFoundError:
|
|
sys.path.append(_SKILLS) # standalone only: no lib_py exists anywhere to shadow
|
|
import lib_py
|
|
_d = os.path.join(_SKILLS, "lib_py", "delegation")
|
|
_spec = importlib.util.spec_from_file_location(
|
|
_PKG, os.path.join(_d, "__init__.py"), submodule_search_locations=[_d])
|
|
_pkg = importlib.util.module_from_spec(_spec)
|
|
sys.modules[_PKG] = _pkg # register BEFORE exec so __init__'s own imports resolve here
|
|
_spec.loader.exec_module(_pkg)
|
|
lib_py.delegation = _pkg
|
|
_impl = importlib.import_module(_PKG + ".registry") # resolved through the bound package's __path__
|
|
if __name__ != "__main__":
|
|
sys.modules[__name__] = _impl # `import registry` is lib_py.delegation.registry
|
|
else:
|
|
_main = getattr(_impl, "main", None) # a module without a CLI keeps exit status 0
|
|
sys.exit(_main() if _main is not None else 0)
|