Skip to content

Commit ee75a2d

Browse files
peteromalletclaude
andcommitted
fix(ci): import-sort cleanup (ruff I) under baseline + add Makefile local gate
- ruff baseline regressed after the restructure/epic (1536 > 1383 → deploy blocked). Safe import-sort-only fix (ruff --select I, 184 fixes, 161 files, zero names removed) → 1320, under baseline. No re-exports/ side-effect imports touched (import-smoke clean). Avoided bulk --fix which wrongly strips re-exports. - Makefile: 'make check' (structure/doctor/ruff/mypy/cycles, seconds) + 'make ci' (full deploy mirror). Mirrors .github/workflows/ci.yml so deploy failures are caught locally before pushing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b697080 commit ee75a2d

162 files changed

Lines changed: 879 additions & 801 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Astrid local gate — run before pushing to catch CI/deploy failures locally.
2+
#
3+
# make check fast pre-deploy gates (structure, doctor, ruff, mypy, cycles) — seconds
4+
# make ci full mirror of the CI deploy job (adds wheel-install + pytest+coverage) — minutes
5+
#
6+
# `make check` green ≈ the CI "Python quality gates" deploy job will pass its fast gates.
7+
# These run the SAME scripts CI runs (see .github/workflows/ci.yml), so they stay in lockstep.
8+
9+
PY ?= python3
10+
11+
.PHONY: help check ci structure doctor ruff mypy cycles wheel ci-mirror editable
12+
13+
help:
14+
@echo "make check - fast pre-deploy gates: structure, doctor, ruff, mypy, cycles (seconds)"
15+
@echo "make ci - full CI deploy mirror: check + editable + wheel-install + pytest/coverage (minutes)"
16+
@echo "make <gate> - run one gate: structure | doctor | ruff | mypy | cycles | wheel | ci-mirror | editable"
17+
18+
# --- Fast gates: catch the common deploy blockers in seconds. Run before every push. ---
19+
check: structure doctor ruff mypy cycles
20+
@echo "✅ make check: fast pre-deploy gates passed"
21+
22+
structure:
23+
@$(PY) -c "import sys; from astrid.core.structure import validate_repo_structure as v; r=v(); [print('STRUCTURE ERROR:', e) for e in r.errors]; sys.exit(1 if r.errors else 0)"
24+
@echo "✓ repo structure (canonical top-level dirs)"
25+
26+
doctor:
27+
@$(PY) -m astrid doctor --json >/dev/null
28+
@echo "✓ doctor (deploy health gate)"
29+
30+
ruff:
31+
@$(PY) scripts/reshape/compare_ruff_baseline.py
32+
@echo "✓ ruff baseline (no lint regression)"
33+
34+
mypy:
35+
@$(PY) scripts/reshape/compare_mypy_baseline.py
36+
@echo "✓ mypy baseline (no type regression)"
37+
38+
cycles:
39+
@$(PY) -m scripts.reshape.import_cycles --baseline scripts/reshape/baselines/import_cycles.json
40+
@echo "✓ import cycles (no new cross-package cycle)"
41+
42+
# --- Full mirror of the CI deploy job (slow). Run before a release / when in doubt. ---
43+
ci: check editable wheel ci-mirror
44+
@echo "✅ make ci: full CI deploy mirror passed — deploy should be green"
45+
46+
editable:
47+
@$(PY) -c "import astrid; print('✓ editable install imports')"
48+
49+
wheel:
50+
bash scripts/smoke_wheel_install.sh
51+
52+
ci-mirror:
53+
bash scripts/reshape/run_ci_checks.sh

astrid/core/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"""Core Astrid framework modules."""
22

3-
from astrid.core.pack.alias_resolver import AliasResolutionError, AliasResolver, create_shared_alias_resolver
3+
from astrid.core.pack.alias_resolver import (
4+
AliasResolutionError,
5+
AliasResolver,
6+
create_shared_alias_resolver,
7+
)
48
from astrid.core.pack.store import InstalledPackStore, InstallRecord, installed_pack_roots
59

610
__all__ = [

astrid/core/adapter/local.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
from pathlib import Path
1010

1111
from astrid.core.adapter import CompleteResult, DispatchResult, PollResult, RunContext
12+
from astrid.core.adapter._common import _read_cost_sidecar, _step_dir
1213
from astrid.core.project.sidecar import write_json_sidecar
1314
from astrid.core.subprocess_env import build_child_subprocess_env
14-
from astrid.core.adapter._common import _read_cost_sidecar, _step_dir
1515
from astrid.core.task.plan import CostEntry, Step
1616
from astrid.core.util.time import utc_now_milliseconds
17+
18+
1719
class LocalAdapter:
1820
"""Local subprocess adapter. Spawns detached so a closed tab does not kill the child."""
1921

astrid/core/adapter/manual.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
from pathlib import Path
77

88
from astrid.core.adapter import CompleteResult, DispatchResult, PollResult, RunContext
9-
from astrid.core.project.sidecar import write_json_sidecar
109
from astrid.core.adapter._common import _step_dir
10+
from astrid.core.project.sidecar import write_json_sidecar
1111
from astrid.core.task.plan import CostEntry, Step
1212
from astrid.core.util.time import utc_now_milliseconds
13+
1314
# Inbox completion-entry contract — parity with the ack identity contract:
1415
# every inbox-driven completion MUST carry submitted_by + submitted_by_kind.
1516
REQUIRED_INBOX_KEYS = ("submitted_by", "submitted_by_kind")

astrid/core/adapter/remote_artifact.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from pathlib import Path
1010

1111
from astrid.core.adapter import CompleteResult, DispatchResult, PollResult, RunContext
12+
from astrid.core.adapter._common import _read_cost_sidecar, _step_dir
1213
from astrid.core.project.sidecar import write_json_sidecar
1314
from astrid.core.subprocess_env import build_child_subprocess_env
14-
from astrid.core.adapter._common import _read_cost_sidecar, _step_dir
1515
from astrid.core.task.plan import CostEntry, Step
1616
from astrid.core.util.time import utc_now_milliseconds
1717

astrid/core/adapter/remote_artifact_fetch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from pathlib import Path
88
from typing import Any, Literal
99

10-
from astrid.core.project.sidecar import write_json_sidecar
1110
from astrid.core.adapter._common import _step_dir
12-
from astrid.core.task.plan import Step
1311
from astrid.core.foundation.hash import sha256_file as _sha256
12+
from astrid.core.project.sidecar import write_json_sidecar
13+
from astrid.core.task.plan import Step
1414

1515
FetchStatus = Literal["completed", "awaiting_fetch", "failed"]
1616

astrid/core/cli/project.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,20 @@
2727
from pathlib import Path
2828
from typing import Any, TypedDict
2929

30-
from astrid.core.contracts.errors import AstridError, coerce_astrid_error
3130
from astrid.core.cli_choices import RecoverableArgumentParser, add_choice_arg
31+
from astrid.core.contracts.errors import AstridError, coerce_astrid_error
32+
from astrid.core.foundation import project_paths as paths
33+
from astrid.core.project.project import (
34+
ProjectError,
35+
create_project,
36+
get_project_theme,
37+
register_source_file,
38+
require_project,
39+
set_project_theme,
40+
show_project,
41+
)
42+
from astrid.core.project.schema import SOURCE_KINDS
43+
from astrid.core.project.source import add_source
3244
from astrid.core.session.binding import (
3345
SessionBindingError,
3446
resolve_current_session,
@@ -42,18 +54,6 @@
4254
from astrid.core.session.discovery import discover_projects
4355
from astrid.core.util.log_and_swallow import log_and_swallow
4456

45-
from astrid.core.foundation import project_paths as paths
46-
from astrid.core.project.project import (
47-
ProjectError,
48-
create_project,
49-
get_project_theme,
50-
register_source_file,
51-
require_project,
52-
set_project_theme,
53-
show_project,
54-
)
55-
from astrid.core.project.schema import SOURCE_KINDS
56-
from astrid.core.project.source import add_source
5757

5858
def main(argv: list[str] | None = None) -> int:
5959
parser = build_parser()

astrid/core/cli/project_handlers.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
from typing import Any, TypedDict
1414

1515
from astrid.core.contracts.errors import AstridError
16-
from astrid.core.session.binding import resolve_current_session
17-
from astrid.core.session.config import (
18-
load_user_config,
19-
load_workspace_config,
20-
resolve_default_project,
21-
set_default_project,
22-
)
23-
from astrid.core.session.discovery import discover_projects
24-
2516
from astrid.core.foundation import project_paths as paths
2617
from astrid.core.project.project import (
2718
ProjectError,
@@ -33,6 +24,14 @@
3324
show_project,
3425
)
3526
from astrid.core.project.source import add_source
27+
from astrid.core.session.binding import resolve_current_session
28+
from astrid.core.session.config import (
29+
load_user_config,
30+
load_workspace_config,
31+
resolve_default_project,
32+
set_default_project,
33+
)
34+
from astrid.core.session.discovery import discover_projects
3635

3736
REPO_ROOT = Path(__file__).resolve().parents[3]
3837
OPS_HELPER = REPO_ROOT / "scripts" / "node" / "ops_helper.mjs"

astrid/core/cli/session.py

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,6 @@
2222
from pathlib import Path
2323
from typing import Any
2424

25-
from astrid.core.project.current_run import read_current_run
26-
from astrid.core.foundation.project_paths import project_dir
27-
from astrid.core.session.binding import (
28-
ASTRID_SESSION_ID_ENV,
29-
SESSION_FILE_NAME, # noqa: F401 — re-export; tests patch cli.SESSION_FILE_NAME
30-
attach_session,
31-
)
32-
from astrid.core.session.constants import STUCK_NO_EVENT_SECONDS
33-
from astrid.core.session.identity import (
34-
Identity,
35-
IdentityError,
36-
bootstrap_identity,
37-
read_identity,
38-
# validate_agent_slug moved to cli_attach
39-
)
40-
from astrid.core.session.lease import read_lease
41-
# lifecycle imports (SessionTakeoverTargetError, takeover_session) moved to cli_sessions;
42-
# load_session moved to cli_attach.
43-
from astrid.core.session.model import (
44-
Session,
45-
SessionRole,
46-
SessionStore,
47-
# SessionRecordNotFoundError moved to cli_status
48-
# SessionStoreError moved to cli_sessions
49-
)
50-
from astrid.core.session.paths import (
51-
# session_path moved to cli_sessions
52-
sessions_dir,
53-
)
54-
from astrid.core.task.events import EVENTS_FILENAME, read_events
55-
# timeline_crud, read_project_default, find_timeline_slug_for_ulid moved to cli_status
56-
from astrid.core.threads.ids import generate_ulid
57-
5825
# M4 T44: Re-export attach command and templates from cli_attach.py.
5926
# Tests call ``cli.cmd_attach(...)`` and reference ``cli.ATTACH_HEADER``.
6027
from astrid.core.cli.session_attach import ( # noqa: E402, F401
@@ -66,6 +33,19 @@
6633
cmd_attach,
6734
)
6835

36+
# STATUS_UNBOUND_HEADER, ATTACH_SUGGESTION_TEMPLATE, NO_PROJECTS_FOUND moved to cli_status
37+
# ----- argparse glue ----------------------------------------------------
38+
#
39+
# M4 T50: Parser construction moved to cli_parser.py. ``build_parser`` is
40+
# re-exported here so existing callers of ``cli.build_parser()`` continue to
41+
# work. The parser uses the shared CommandSpec convention with late imports
42+
# from this facade so monkeypatch seams (``cli.cmd_attach``, ``cli.cmd_status``,
43+
# etc.) remain interceptable.
44+
from astrid.core.cli.session_parser import ( # noqa: E402, F401
45+
COMMANDS, # re-export for CLI conformance allowlist
46+
build_parser,
47+
)
48+
6949
# M4 T46: Re-export sessions subcommand handlers from cli_sessions.py.
7050
# Tests call ``cli.cmd_sessions_ls(...)``, ``cli.cmd_sessions_detach(...)``,
7151
# ``cli.cmd_sessions_takeover(...)``, ``cli.cmd_sessions_prune(...)`` and
@@ -95,6 +75,8 @@
9575
_status_state_for,
9676
cmd_status,
9777
)
78+
from astrid.core.foundation.project_paths import project_dir
79+
from astrid.core.project.current_run import read_current_run
9880

9981
# ----- Templates & shared helpers ---------------------------------------
10082
#
@@ -104,7 +86,6 @@
10486
# re-exported here so ``astrid.core.session.cli.<name>`` keeps resolving for the
10587
# test monkeypatches that target the facade. Tests assert on the literal
10688
# template strings; keep them stable.
107-
10889
from astrid.core.session._shared import ( # noqa: E402, F401
10990
FIRST_RUN_PROMPT_HEADER,
11091
NONE_PLACEHOLDER,
@@ -119,21 +100,38 @@
119100
_make_bootstrap_session,
120101
_session_store,
121102
)
122-
# STATUS_UNBOUND_HEADER, ATTACH_SUGGESTION_TEMPLATE, NO_PROJECTS_FOUND moved to cli_status
123-
124-
125-
# ----- argparse glue ----------------------------------------------------
126-
#
127-
# M4 T50: Parser construction moved to cli_parser.py. ``build_parser`` is
128-
# re-exported here so existing callers of ``cli.build_parser()`` continue to
129-
# work. The parser uses the shared CommandSpec convention with late imports
130-
# from this facade so monkeypatch seams (``cli.cmd_attach``, ``cli.cmd_status``,
131-
# etc.) remain interceptable.
103+
from astrid.core.session.binding import (
104+
ASTRID_SESSION_ID_ENV,
105+
SESSION_FILE_NAME, # noqa: F401 — re-export; tests patch cli.SESSION_FILE_NAME
106+
attach_session,
107+
)
108+
from astrid.core.session.constants import STUCK_NO_EVENT_SECONDS
109+
from astrid.core.session.identity import (
110+
Identity,
111+
IdentityError,
112+
bootstrap_identity,
113+
read_identity,
114+
# validate_agent_slug moved to cli_attach
115+
)
116+
from astrid.core.session.lease import read_lease
132117

133-
from astrid.core.cli.session_parser import ( # noqa: E402, F401
134-
COMMANDS, # re-export for CLI conformance allowlist
135-
build_parser,
118+
# lifecycle imports (SessionTakeoverTargetError, takeover_session) moved to cli_sessions;
119+
# load_session moved to cli_attach.
120+
from astrid.core.session.model import (
121+
Session,
122+
SessionRole,
123+
SessionStore,
124+
# SessionRecordNotFoundError moved to cli_status
125+
# SessionStoreError moved to cli_sessions
136126
)
127+
from astrid.core.session.paths import (
128+
# session_path moved to cli_sessions
129+
sessions_dir,
130+
)
131+
from astrid.core.task.events import EVENTS_FILENAME, read_events
132+
133+
# timeline_crud, read_project_default, find_timeline_slug_for_ulid moved to cli_status
134+
from astrid.core.threads.ids import generate_ulid
137135

138136

139137
def main(argv: list[str] | None = None) -> int:

astrid/core/cli/session_attach.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,19 @@
1616
from typing import Any
1717

1818
from astrid.core.contracts.errors import AstridError
19-
from astrid.core.project.current_run import read_current_run
2019
from astrid.core.foundation.project_paths import project_dir, resolve_projects_root
20+
from astrid.core.project.current_run import read_current_run
2121
from astrid.core.project.project import ProjectError, require_project
22+
from astrid.core.session._shared import (
23+
NONE_PLACEHOLDER,
24+
TAKEOVER_HINT_ORPHAN,
25+
TAKEOVER_HINT_READER,
26+
_emit_notice,
27+
_ensure_identity,
28+
_find_reusable_session,
29+
_json_mode,
30+
)
31+
2232
# attach_session is imported via late import inside cmd_attach to preserve
2333
# monkeypatch seams (tests setattr on cli.attach_session).
2434
from astrid.core.session.config import resolve_default_project, set_default_project
@@ -33,15 +43,6 @@
3343
SessionRole,
3444
)
3545
from astrid.core.session.paths import sessions_dir
36-
from astrid.core.session._shared import (
37-
NONE_PLACEHOLDER,
38-
TAKEOVER_HINT_ORPHAN,
39-
TAKEOVER_HINT_READER,
40-
_emit_notice,
41-
_ensure_identity,
42-
_find_reusable_session,
43-
_json_mode,
44-
)
4546
from astrid.core.task.cli_contract import emit_lifecycle_json
4647
from astrid.core.timeline.crud import list_timelines
4748
from astrid.core.timeline.defaults import read_project_default

0 commit comments

Comments
 (0)