Twinned from https://github.com/cfsh/ninefold/issues/1050 by tools/beads/import_github.py's reconcile pass.
Deferred from #1018 by @aedanpope (chat, 2026-08-18): *"lets save more changes for later on figuring out a better way for py deps"* — filed so the shape of the fix isn't lost.
The smell. nflib.channels._load_operationalize() imports design_docs/tools/operationalize_design.py by file path via importlib, because the design-doc-followup channel needs the tool's projected_text()/_fill_doc() and there is no importable library that owns them. In Bazel terms: the tool is a py_binary (owns main(), argparse, its own sys.path bootstrap) and the gate is depending on it as if it were a py_library — a dep shape Bazel refuses outright, hand-worked-around here with the loader.
Why not just import: design_docs/tools/ is on nobody's sys.path; putting it there from library code is a process-wide side effect (status.py etc. become importable/shadowable top-level names); and the lazy by-path load is what lets a broken tool module degrade to "no grant" inside channels.grants() instead of crashing authority — and with it merge_pr and the required check — for every PR at import time.
The fix. The standard binary/library split:
projected_text, _fill_doc, PreviewImpossible, and the parse/stamp/cell helpers they need) into an importable package. tools/github_live is the natural home — already the tool's only real dependency, already GOVERNANCE (the gate executes it, #1018), and the moved code keeps its zero-clone-dependency rule (it needs only github_live's own Gh + parser, no nflib).operationalize_design.py to the binary: argparse + calls into the library. It stays beside the docs it operates on (design 008's deliberate siting).nflib.channels replaces _load_operationalize() with a plain lazy import inside the channel function — same fail-closed property, no path arithmetic.DesignDocFollowupMatchesTheTool-style pinning survives unchanged: the end-to-end test in test_nflib_channels.py already runs the real projector against github_live's fakes.Worth doing together with any broader "better way for py deps" decision (whether that's a repo-root package layout, a build system, or just a stated convention for what may import what) rather than as a one-off move.
None.
No comments.