feat(lint): read runtime module list from wheel manifest, not inline (#9)
Switches the bare-imports lint from an inline RUNTIME_MODULES list to the _runtime_modules.json manifest emitted by molecule-core's build_runtime_package.py. Eliminates the third place the runtime module list lived — now the build script is the single source of truth. Tonight surfaced that the same closed list lived in three places that drifted independently. The build script's TOP_LEVEL_MODULES went stale on transcript_auth, the smoke-test step here had a hardcoded mirror that would have drifted next time a top-level module was added, and runtime-pin-compat tested transitively via import molecule_runtime.main (which only catches breakage, not drift). One source of truth fixes all three at once. Implementation: - pip download molecule-ai-workspace-runtime --no-deps to /tmp - unzip _runtime_modules.json from the wheel - merge top_level_modules + subpackages into the regex alternation (subpackages can be bare-imported too — `from lib.pre_stop`) - on any fetch failure (network, missing manifest in older wheel), fall back to the inline list with a workflow warning so the lint still runs but the operator knows to investigate Two consequences: - Templates rebuilt against runtime ≥ the version that ships the manifest get the always-fresh list automatically. - Templates rebuilt against the old wheel (pre-manifest) still get the working inline list — no regression. Future cleanup (separate PR after a few release cycles): once all template repos have rebuilt at least once with the manifest path, the inline fallback can shrink to a panic message. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7315460ff5
commit
0335ec169c
43
.github/workflows/publish-template-image.yml
vendored
43
.github/workflows/publish-template-image.yml
vendored
@ -99,16 +99,45 @@ jobs:
|
||||
# package. This bit claude-code (5 imports), langgraph,
|
||||
# deepagents, and gemini-cli on 2026-04-27 — each one a
|
||||
# separate workspace-stuck-in-provisioning incident.
|
||||
# The set of names mirrors workspace/*.py basenames at the time
|
||||
# this lint was added; if a new runtime module ships, the
|
||||
# build will fail loud with a clear message instead of
|
||||
# silently shipping broken templates. Fail-fast: this runs
|
||||
# before docker login + buildx setup so a bad PR returns red
|
||||
# in seconds, not minutes.
|
||||
#
|
||||
# Source of truth: molecule_runtime/_runtime_modules.json
|
||||
# inside the published wheel (emitted by
|
||||
# scripts/build_runtime_package.py). Pulling the manifest
|
||||
# from PyPI's latest wheel ensures the lint never drifts from
|
||||
# the rewriter's actual closed list. If the manifest can't be
|
||||
# fetched (older wheel, PyPI down, etc.), falls back to the
|
||||
# inline list — known to be correct as of 2026-04-27 — so
|
||||
# the lint never silently passes on a fetch failure.
|
||||
#
|
||||
# Fail-fast: this runs before docker login + buildx setup so
|
||||
# a bad PR returns red in seconds, not minutes.
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
RUNTIME_MODULES='plugins|adapter_base|config|main|preflight|prompt|coordinator|consolidation|events|heartbeat|transcript_auth|runtime_wedge|watcher|skill_loader|policies|adapters|builtin_tools|executor_helpers|a2a_executor|a2a_client|a2a_tools|a2a_cli|a2a_mcp_server|agent|agents_md|initial_prompt|molecule_ai_status|platform_auth|shared_runtime'
|
||||
|
||||
# Fallback list — used only when the manifest fetch fails.
|
||||
# Mirrors scripts/build_runtime_package.py:TOP_LEVEL_MODULES
|
||||
# at the time this comment was written.
|
||||
FALLBACK_MODULES='plugins|adapter_base|config|main|preflight|prompt|coordinator|consolidation|events|heartbeat|transcript_auth|runtime_wedge|watcher|skill_loader|policies|adapters|builtin_tools|executor_helpers|a2a_executor|a2a_client|a2a_tools|a2a_cli|a2a_mcp_server|agent|agents_md|initial_prompt|molecule_ai_status|platform_auth|shared_runtime'
|
||||
|
||||
RUNTIME_MODULES=""
|
||||
mkdir -p /tmp/runtime-wheel
|
||||
if pip download --quiet molecule-ai-workspace-runtime --no-deps -d /tmp/runtime-wheel 2>/dev/null; then
|
||||
WHEEL=$(ls /tmp/runtime-wheel/*.whl 2>/dev/null | head -1)
|
||||
if [ -n "$WHEEL" ]; then
|
||||
# Pull both top_level + subpackage names; both can be bare-imported.
|
||||
RUNTIME_MODULES=$(unzip -p "$WHEEL" molecule_runtime/_runtime_modules.json 2>/dev/null \
|
||||
| python3 -c "import sys,json; m=json.load(sys.stdin); print('|'.join(sorted(set(m['top_level_modules']) | set(m['subpackages']))))" 2>/dev/null || echo "")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$RUNTIME_MODULES" ]; then
|
||||
echo "::notice::lint module list pulled from molecule-ai-workspace-runtime wheel manifest"
|
||||
else
|
||||
RUNTIME_MODULES="$FALLBACK_MODULES"
|
||||
echo "::warning::could not read _runtime_modules.json from PyPI wheel — using inline fallback list"
|
||||
fi
|
||||
|
||||
# Match `from <module> import` at start of line OR after any whitespace
|
||||
# (function-scope imports inside if/try blocks count too).
|
||||
if HITS=$(grep -nE "^\s*from (${RUNTIME_MODULES}) import" *.py 2>/dev/null); then
|
||||
|
||||
Loading…
Reference in New Issue
Block a user