Workflow Publish Import Validation¶
Scoped publish-validation stage that runs immediately before the current commit/push step.
Quick Navigation¶
- How to configure workflow publish import validation
- Tutorial: workflow publish import validation
- Workflow publish import validation reference
Status¶
This page describes the scoped publish-validation behavior implemented for issue 4064.
Current tree state:
amplifier-bundle/recipes/default-workflow.yamlstill uses Step 15 for Commit and Push, and now runs publish import validation immediately before the commit is createdscripts/pre-commit/build_publish_validation_scope.pybuilds the exact scoped Python validation file from the staged publish manifestscripts/pre-commit/check_imports.pysupports--files-fromfor exact-list validation without repo-wide fallback- the subsequent
git commitskips only the repo-wide pre-commitcheck-importshook because Step 15 already ran the scoped validator
Older issue discussion called this work "Step 15". That shorthand remains accurate because the validation now runs as a publish-only substep inside the existing commit/push stage, without renumbering the workflow.
What It Does¶
The publish-validation stage now:
- read the exact repo-relative staged publish manifest emitted by Step 15
- keep manifest-listed
.pyfiles as seed files - derive allowed roots from those seed files
- expand only repo-local Python dependencies that resolve inside those already-allowed roots
- write an exact scoped
.pyfile list - run
check_imports.py --files-from <scope-file> - create the commit with
SKIP=check-importsso pre-commit does not rerun the repo-wide import hook against all staged Python files
It does not fall back to a repository-wide Python scan in scoped mode. The goal is strict validation for the thing being published, not for unrelated files elsewhere in the repo.
Optional Dependency Behavior¶
textual and amplifier_core stay optional. Their absence matters only when the scoped validation set includes a file that genuinely imports them.
| Dependency | Publish fails when | Publish does not fail when |
|---|---|---|
textual | A file inside the scoped validation set imports textual. | Only files outside the staged publish surface import textual. |
amplifier_core | A file inside the scoped validation set imports amplifier_core. | Only files outside the staged publish surface import amplifier_core. |
.claude/scenarios/** Behavior¶
Unrelated .claude/scenarios/** scripts are out of scope for workflow publishes. The publish-validation stage does not discover, glob, or validate those files unless they are explicitly part of the staged publish surface. Scenario-only imports therefore cannot block an unrelated publish.
Boundary Rules¶
| Rule | Behavior | Why it matters |
|---|---|---|
| Publish-only insertion point | The new validation stage will run immediately before the current commit/push step. | Resolves the current "Step 15" naming mismatch without pretending the renumbering already happened. |
| Manifest-first scope | Validation starts from the exact staged publish manifest. | Avoids validating unrelated repo files. |
| Root-derived allowlist | Dependency expansion may add files only under roots already derived from manifest seed files. | Prevents hidden jumps into unrelated repository areas. |
src/<package>/ roots | A seed under src/<package>/... may expand within that same top-level package root. | Keeps package resolution predictable. |
amplifier-bundle roots | A seed under amplifier-bundle/modules/<name>/... stays inside that module; other amplifier-bundle/<subtree>/... seeds stay inside that subtree. | Stops sibling bundle modules from being pulled in implicitly. |
| Cross-root imports require both roots | A bundle wrapper can reach src/amplihack/... only when the manifest already seeded that src root too. | Avoids inventing hidden aliases between bundle wrappers and runtime packages. |
| No repository fallback | check_imports.py --files-from validates exactly the scoped file list. | Stops broad scans from reappearing. |
| No repo-wide hook rerun | The later git commit skips only the pre-commit check-imports hook after the scoped run succeeds. | Prevents commit-time fallback to all staged Python files. |
| Empty Python surface is explicit success | A publish with no scoped Python files exits cleanly after reporting zero validated files. | Keeps non-Python publishes from failing for the wrong reason. |
| Real missing imports still fail | A missing import in a scoped file still stops the publish. | Preserves the safety value of the new stage. |
Execution Shape¶
The publish path now looks like this:
--- Publish Import Validation ---
publish_manifest=/tmp/amplihack-publish-manifest-424242.txt
validation_scope=/tmp/amplihack-publish-scope-424242.txt
seed_count=3
expanded_local_dep_count=2
validated_count=5
python scripts/pre-commit/check_imports.py --files-from "$validation_scope"
SKIP=check-imports git commit -m "..."
If the staged publish surface contains no Python files, the stage reports an empty Python surface and succeeds without attempting repo-wide import checks.
What Happens When Something Is Wrong¶
The publish-validation stage fails when any of these conditions is true:
- the publish manifest is missing, unreadable, or contains unsafe paths
- a scoped Python file uses a missing required import
- a scoped Python file imports
textualoramplifier_coreand the dependency is not installed - the helper cannot normalize the scoped file list into safe repo-relative files
Example relevant failure:
❌ IMPORT VALIDATION FAILED - FIX BEFORE COMMITTING
Import Errors:
tests/fixtures/workflow_publish/relevant_missing_import.py:
FAILED: No module named 'definitely_missing_module'
That failure is intentional because the missing import belongs to the staged publish surface.
Where To Go Next¶
- Use the configuration guide to review the manifest, root-boundary, and scoped-validator contract.
- Use the tutorial for a design walkthrough of optional-dependency and scenario exclusions.
- Use the reference page for the workflow contract, helper CLI, and
--files-fromsemantics.