Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions autoassistant/audit_skill_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,26 @@ def compute_baseline() -> dict:
}


def write_baseline(root: Path) -> Path:
def write_baseline(root: Path, *, allow_dev_stack: bool = False) -> Path:
# The committed baseline is the contract "these docs were validated against this
# released stack". Nightly releases are wheels/tags-only, so a source checkout /
# PYTHONPATH / editable stack reports the *last-committed* version string, not the
# latest release — a baseline snapshotted from one silently pins a version PyPI has
# moved past (this exact incident shipped once and was caught by the wiki-currency
# CI). Refuse unless the caller explicitly owns the risk.
if not allow_dev_stack:
check = inspect_installation()
if check.install_kind not in (
"packaged install (pip/conda provenance not distinguishable)",
):
sys.exit(
f"[baseline] refusing to write: the active stack is a dev install "
f"({check.install_kind}), whose version string can trail the latest "
f"release (wheels/tags-only nightlies never bump source `main`). "
f"Write the baseline from a clean venv with the released wheel "
f"(`env -u PYTHONPATH <venv>/bin/python ... --write-baseline`), or "
f"pass --allow-dev-stack to snapshot this stack deliberately."
)
baseline = compute_baseline()
path = root / BASELINE_REL_PATH
path.parent.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -1378,7 +1397,14 @@ def main() -> int:
"--write-baseline",
action="store_true",
help="Snapshot the installed stack (versions + API-surface hash) to "
"wiki/core/api_audit_baseline.json and exit. Re-pin after a deliberate upgrade.",
"wiki/core/api_audit_baseline.json and exit. Re-pin after a deliberate upgrade. "
"Refuses a dev-source stack unless --allow-dev-stack is passed.",
)
parser.add_argument(
"--allow-dev-stack",
action="store_true",
help="Permit --write-baseline against a source-checkout/PYTHONPATH/editable "
"stack, whose version string can trail the latest PyPI release.",
)
parser.add_argument(
"--check-version",
Expand Down Expand Up @@ -1472,7 +1498,7 @@ def main() -> int:
return install_status
return check_version(root)
if args.write_baseline:
path = write_baseline(root)
path = write_baseline(root, allow_dev_stack=args.allow_dev_stack)
print(f"[baseline] wrote {path}", file=sys.stderr)
return 0

Expand Down
32 changes: 32 additions & 0 deletions autoassistant/tests/test_install_preflight.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,35 @@ def test_version_check_routes_absent_stack_to_install_preflight():
assert process.returncode == 2
assert "[install] NOT INSTALLED" in process.stderr
assert "API DRIFT" not in process.stderr


def test_write_baseline_refuses_dev_stack(tmp_path, monkeypatch):
"""The baseline contract is 'validated against this RELEASED stack'; a dev-source
stack's version string can trail PyPI (wheels/tags-only nightlies), so snapshotting
one without --allow-dev-stack must refuse."""
import importlib.util
import sys as _sys

spec = importlib.util.spec_from_file_location(
"audit_under_test_baseline", ROOT / "autoassistant" / "audit_skill_apis.py"
)
mod = importlib.util.module_from_spec(spec)
_sys.modules[spec.name] = mod
spec.loader.exec_module(mod)

dev_check = mod.InstallationCheck(
status="ready", python="py", prefix="env", versions={}, locations={},
missing=[], errors={}, install_kind="source checkout or PYTHONPATH install",
cache_defaults={},
)
monkeypatch.setattr(mod, "inspect_installation", lambda: dev_check)

import pytest as _pytest

with _pytest.raises(SystemExit) as exc:
mod.write_baseline(tmp_path)
assert "refusing to write" in str(exc.value)

# With the explicit flag the same stack is snapshotted deliberately.
path = mod.write_baseline(tmp_path, allow_dev_stack=True)
assert path.exists()
7 changes: 7 additions & 0 deletions skills/af_audit_skill_apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ python autoassistant/audit_skill_apis.py --check-version
python autoassistant/audit_skill_apis.py --write-baseline
```

`--write-baseline` **refuses a dev-source stack** (source checkout / PYTHONPATH /
editable): nightly releases are wheels/tags-only, so a dev stack's version string can
trail the latest PyPI release and would bake a stale pin into the baseline. Write the
baseline from a clean venv holding the released wheel
(`env -u PYTHONPATH <venv>/bin/python autoassistant/audit_skill_apis.py --write-baseline`);
`--allow-dev-stack` overrides deliberately.

The workflow is: `--check-version` flags that the installed autofit moved → run the full
`--scope all` audit to find what broke → fix the references (per the Branch section below)
→ `--write-baseline` to re-pin once the audit is clean. **Only re-pin after fixing**, never
Expand Down
Loading