patchshuttle 0.1.0a5__tar.gz → 0.1.0a7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/.github/workflows/ci.yml +37 -5
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/CHANGELOG.md +54 -1
- patchshuttle-0.1.0a5/README.md → patchshuttle-0.1.0a7/PKG-INFO +143 -13
- patchshuttle-0.1.0a5/PKG-INFO → patchshuttle-0.1.0a7/README.md +99 -50
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/SPEC_V0_1.md +85 -1
- patchshuttle-0.1.0a7/docs/CHATGPT_INTEGRATION.md +54 -0
- patchshuttle-0.1.0a7/docs/DJANGO_MIGRATIONS.md +83 -0
- patchshuttle-0.1.0a7/docs/NEXT_RELEASE.md +193 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/docs/RELEASE.md +43 -3
- patchshuttle-0.1.0a7/docs/ROADMAP.md +56 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/pyproject.toml +5 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_architecture.py +3 -1
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_discovery.py +16 -2
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_symbols.py +13 -1
- patchshuttle-0.1.0a7/src/patchshuttle/_refactor.py +147 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_version.py +1 -1
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/__init__.py +20 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/constructors.py +170 -3
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/create.py +6 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/modify.py +12 -0
- patchshuttle-0.1.0a7/src/patchshuttle/analysis/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/analysis/dependencies.py +160 -0
- patchshuttle-0.1.0a7/src/patchshuttle/analysis/references.py +136 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/audit.py +81 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/backup.py +28 -2
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/cli.py +4 -141
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/context.py +10 -1
- patchshuttle-0.1.0a7/src/patchshuttle/django_app/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/django_app/management/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/django_app/management/commands/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/django_app/management/commands/patchshuttle_migrate.py +50 -0
- patchshuttle-0.1.0a7/src/patchshuttle/django_app/workflow.py +306 -0
- patchshuttle-0.1.0a7/src/patchshuttle/documentation/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/documentation/cli.py +93 -0
- patchshuttle-0.1.0a7/src/patchshuttle/documentation/refresh.py +132 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/execution.py +2 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/formatters/runner.py +5 -1
- patchshuttle-0.1.0a7/src/patchshuttle/integrations/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/integrations/mcp_server.py +182 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/linters/runner.py +1 -1
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/logging.py +10 -57
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/models.py +173 -5
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/planner.py +236 -191
- patchshuttle-0.1.0a7/src/patchshuttle/planning/__init__.py +1 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/discovery_log.py +70 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/display.py +114 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/guidance.py +38 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/imports.py +209 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/symbols.py +53 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/templates.py +39 -0
- patchshuttle-0.1.0a7/src/patchshuttle/planning/types.py +199 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/preflight.py +2 -0
- patchshuttle-0.1.0a7/src/patchshuttle/resources/AI_GUIDE.md +734 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/PATCHSHUTTLE_PROTOCOL.md +229 -4
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/rollback.py +6 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/runner.py +18 -18
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/selfdoc.py +67 -6
- patchshuttle-0.1.0a7/tests/integrations/test_django_migrations.py +356 -0
- patchshuttle-0.1.0a7/tests/integrations/test_imports.py +186 -0
- patchshuttle-0.1.0a7/tests/integrations/test_mcp_server.py +242 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_cli.py +2 -2
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_formatters.py +4 -0
- patchshuttle-0.1.0a7/tests/unit/test_move_file.py +217 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_package.py +1 -1
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_preflight.py +2 -0
- patchshuttle-0.1.0a7/tests/unit/test_refactor.py +330 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_release_configuration.py +23 -3
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_selfdoc.py +1 -1
- patchshuttle-0.1.0a7/tests/unit/test_structural_guards.py +251 -0
- patchshuttle-0.1.0a5/src/patchshuttle/resources/AI_GUIDE.md → patchshuttle-0.1.0a7/tests/unit/workflow/fixtures/a6-guide.md +83 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_ai_doc_contract.py +108 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_ai_guidance.py +122 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_audit_templates.py +131 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_dependencies.py +142 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_guide_refresh.py +180 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_import_batch.py +167 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_references.py +118 -0
- patchshuttle-0.1.0a7/tests/unit/workflow/test_symbol_diagnostics.py +81 -0
- patchshuttle-0.1.0a7/tools/django_postgres_smoke.py +88 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tools/wheel_smoke.py +12 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/.github/workflows/release.yml +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/.github/workflows/testpypi.yml +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/.gitignore +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/LICENSE +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/SECURITY.md +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_ai_log.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_diff.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_html_lint.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_line_ranges.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_process.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_structure.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/constructors.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/runner.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/config.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/errors.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/formatter_policy.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/formatters/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/history/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/history/cli.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/history/models.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/history/records.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/history/storage.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/identifiers.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/inventory.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/linters/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/operations.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/parser.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/policy.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/project_python.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/py.typed +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/registry.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/AUDIT-EXAMPLE.psh.yaml +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/PATCH-EXAMPLE.psh.yaml +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/__init__.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/runtime_cache.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/verification.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/warning_baseline.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/src/patchshuttle/workspace.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/e2e/test_cli_project_cycle.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/integration/test_workflows.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/history/test_history.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/history/test_history_integration.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/history/test_history_storage_edges.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_a4_coverage_regressions.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_actions.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_ai_log.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_architecture.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_attempt_logging.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_audit_verify_execution.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_backup.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_change_transaction.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_check_transaction.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_checks.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_config.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_context_and_constructors.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_diff.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_execution.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_formatting_transaction.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_guarded_ranges.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_html_lint.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_identifiers.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_inventory.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_inventory_transaction.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_logging.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_manual_rollback.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_models.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_modify_actions.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_operational_execution.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_parser.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_phase19_cli.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_planner.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_planner_ux.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_policy.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_project_python.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_python_discovery.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_python_structure.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_python_structure_action.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_python_symbols.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_registry.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_rollback.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_runner.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_runtime_cache.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_warning_baseline.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tests/unit/test_workspace.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tools/check_tag.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tools/index_smoke.py +0 -0
- {patchshuttle-0.1.0a5 → patchshuttle-0.1.0a7}/tools/release_checks.py +0 -0
|
@@ -47,14 +47,46 @@ jobs:
|
|
|
47
47
|
- name: Check formatting
|
|
48
48
|
run: python -m black --check src tests tools
|
|
49
49
|
- name: Run tests with branch coverage
|
|
50
|
-
run:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
run: python -m coverage run -m pytest -q
|
|
51
|
+
- name: Require full branch coverage
|
|
52
|
+
run: python -m coverage report --fail-under=100
|
|
53
|
+
|
|
54
|
+
postgres:
|
|
55
|
+
name: Django / PostgreSQL 16
|
|
56
|
+
runs-on: ubuntu-24.04
|
|
57
|
+
timeout-minutes: 10
|
|
58
|
+
services:
|
|
59
|
+
postgres:
|
|
60
|
+
image: postgres:16
|
|
61
|
+
env:
|
|
62
|
+
POSTGRES_DB: patchshuttle_test
|
|
63
|
+
POSTGRES_USER: postgres
|
|
64
|
+
POSTGRES_PASSWORD: disposable-ci-password
|
|
65
|
+
ports:
|
|
66
|
+
- 5432:5432
|
|
67
|
+
options: >-
|
|
68
|
+
--health-cmd pg_isready
|
|
69
|
+
--health-interval 10s
|
|
70
|
+
--health-timeout 5s
|
|
71
|
+
--health-retries 5
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v7.0.1
|
|
74
|
+
- uses: actions/setup-python@v7.0.0
|
|
75
|
+
with:
|
|
76
|
+
python-version: "3.12"
|
|
77
|
+
- name: Install Django adapter and PostgreSQL driver
|
|
78
|
+
run: python -m pip install -e ".[django]" "psycopg[binary]>=3.2,<4"
|
|
79
|
+
- name: Check migration lifecycle and cross-connection lock
|
|
80
|
+
env:
|
|
81
|
+
PSH_PG_DATABASE: patchshuttle_test
|
|
82
|
+
PSH_PG_USER: postgres
|
|
83
|
+
PSH_PG_PASSWORD: disposable-ci-password
|
|
84
|
+
PSH_PG_PORT: "5432"
|
|
85
|
+
run: python tools/django_postgres_smoke.py
|
|
54
86
|
|
|
55
87
|
package:
|
|
56
88
|
name: Build and smoke-test distributions
|
|
57
|
-
needs: test
|
|
89
|
+
needs: [test, postgres]
|
|
58
90
|
runs-on: ubuntu-24.04
|
|
59
91
|
timeout-minutes: 20
|
|
60
92
|
steps:
|
|
@@ -3,7 +3,60 @@
|
|
|
3
3
|
All notable changes to PatchShuttle are recorded in this file. The project
|
|
4
4
|
uses semantic versioning, including Python-compatible pre-release versions.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## 0.1.0a7 - release candidate (not yet published)
|
|
7
|
+
|
|
8
|
+
- Audit AI instructions: complete action catalogs, correct method YAML indentation
|
|
9
|
+
and job-ID rules, clarify guard sources, MCP limits and database boundaries.
|
|
10
|
+
|
|
11
|
+
- Add `python_references` for bounded, explicitly unverified symbol-reference
|
|
12
|
+
candidates with import aliases and unresolved attributes.
|
|
13
|
+
|
|
14
|
+
- Add read-only `python_dependencies` for static local import candidates, cycle
|
|
15
|
+
groups and explicitly unresolved/dynamic cases before module refactoring.
|
|
16
|
+
|
|
17
|
+
- Add opt-in, bounded action drafts to symbol/import audits with observed guards;
|
|
18
|
+
fragments require review and never execute during audit.
|
|
19
|
+
|
|
20
|
+
- Add `edit_imports`: 1-100 ordered import edits guarded by one initial import
|
|
21
|
+
hash, with step diagnostics and the existing import safety checks.
|
|
22
|
+
|
|
23
|
+
- Explain structural replacement failures with bounded indentation context and
|
|
24
|
+
YAML guidance, without rewriting input or changing guard semantics.
|
|
25
|
+
|
|
26
|
+
- Add reviewed `docs refresh` for recognized AI guide templates, retaining
|
|
27
|
+
appended owner notes and exact backups; unknown inline edits require review.
|
|
28
|
+
- Add conditional Python symbol-edit guidance to CLI plans, full and compact
|
|
29
|
+
logs, including targeting failures; advisory does not alter guards or policy.
|
|
30
|
+
- Add operation-selection rules and an audit-to-patch example to AI guidance.
|
|
31
|
+
- Prefer configured MCP history retrieval, retaining manual logs as fallback.
|
|
32
|
+
- Count symbol/range transfers and report structural imports and file moves.
|
|
33
|
+
- Extract plan and discovery-log presentation into smaller modules without
|
|
34
|
+
relaxing the existing architecture ratchet.
|
|
35
|
+
|
|
36
|
+
## 0.1.0a6 - 2026-10-21
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- Guarded `read_imports`, `ensure_import` and `remove_import` with alias-aware AST matching, comment preservation and binding checks.
|
|
41
|
+
|
|
42
|
+
- Optional authenticated MCP history server for ChatGPT, scoped to one workspace and OAuth subject.
|
|
43
|
+
- Optional Django migration command with hashed plans, database locks, pre/post checks, explicit reversals and separate recovery journals.
|
|
44
|
+
- Guarded `move_range` and `move_symbol` source transfers between files,
|
|
45
|
+
including destination fingerprints, structural validation, Python constructors,
|
|
46
|
+
and shared transaction rollback.
|
|
47
|
+
- Guarded `move_file` with destination absence checks, byte/mode preservation,
|
|
48
|
+
explicit deleted-file reporting, and automatic and manual rollback.
|
|
49
|
+
|
|
50
|
+
- Optional AST guards for `replace_symbol`, with hashes and Python version
|
|
51
|
+
reported by `read_symbol`, replacement declaration validation and compile
|
|
52
|
+
validation. Existing text-only job serialization remains compatible.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- Formatter child interpreters and Black preflight explicitly enable Python
|
|
57
|
+
UTF-8 mode, including under isolated execution.
|
|
58
|
+
|
|
59
|
+
See `docs/NEXT_RELEASE.md` for implemented scope and remaining release work.
|
|
7
60
|
|
|
8
61
|
## 0.1.0a5 - 2026-08-28
|
|
9
62
|
|
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: patchshuttle
|
|
3
|
+
Version: 0.1.0a7
|
|
4
|
+
Summary: Local, auditable patch workflows for AI-assisted software development
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: ai,automation,cli,development-tools,patch
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: black<27,>=24
|
|
21
|
+
Requires-Dist: click<9,>=8.1
|
|
22
|
+
Requires-Dist: filelock<4,>=3.30
|
|
23
|
+
Requires-Dist: isort<7,>=5.13
|
|
24
|
+
Requires-Dist: pydantic<3,>=2.6
|
|
25
|
+
Requires-Dist: pyyaml<7,>=6
|
|
26
|
+
Requires-Dist: ruff<1,>=0.16
|
|
27
|
+
Requires-Dist: tomli<3,>=2; python_version < '3.11'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: build<2,>=1.2; extra == 'dev'
|
|
30
|
+
Requires-Dist: django<7,>=5.2; extra == 'dev'
|
|
31
|
+
Requires-Dist: mcp<2,>=1.30; extra == 'dev'
|
|
32
|
+
Requires-Dist: pyjwt[crypto]<3,>=2.10; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov<8,>=5; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
35
|
+
Requires-Dist: twine<7,>=6.1; extra == 'dev'
|
|
36
|
+
Provides-Extra: django
|
|
37
|
+
Requires-Dist: django<7,>=5.2; extra == 'django'
|
|
38
|
+
Provides-Extra: html
|
|
39
|
+
Requires-Dist: djlint<2,>=1.44; extra == 'html'
|
|
40
|
+
Provides-Extra: mcp
|
|
41
|
+
Requires-Dist: mcp<2,>=1.30; extra == 'mcp'
|
|
42
|
+
Requires-Dist: pyjwt[crypto]<3,>=2.10; extra == 'mcp'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
1
45
|
# PatchShuttle
|
|
2
46
|
|
|
3
47
|
PatchShuttle is intended to provide local, auditable patch workflows for
|
|
@@ -6,7 +50,8 @@ describes a small job, the user reviews and runs it locally, and PatchShuttle
|
|
|
6
50
|
records the result for the next iteration.
|
|
7
51
|
|
|
8
52
|
> [!IMPORTANT]
|
|
9
|
-
> PatchShuttle is alpha software.
|
|
53
|
+
> PatchShuttle is alpha software. This branch prepares `0.1.0a7`; the latest
|
|
54
|
+
> recorded published version is `0.1.0a6`. It implements the complete
|
|
10
55
|
> local v0.1 workflow. It executes bounded read-only
|
|
11
56
|
> audits, approved patch transactions, and approved one-pass verification jobs
|
|
12
57
|
> under a project lock. Patch jobs retain backups, run controlled checks, apply
|
|
@@ -63,7 +108,7 @@ After publication, install the exact alpha release from PyPI:
|
|
|
63
108
|
```bash
|
|
64
109
|
python -m venv .venv
|
|
65
110
|
python -m pip install --upgrade pip
|
|
66
|
-
python -m pip install "patchshuttle==0.1.
|
|
111
|
+
python -m pip install "patchshuttle==0.1.0a6"
|
|
67
112
|
```
|
|
68
113
|
|
|
69
114
|
For development from a local checkout:
|
|
@@ -76,7 +121,7 @@ To enable opt-in HTML template linting in an installed release, install the
|
|
|
76
121
|
`html` extra:
|
|
77
122
|
|
|
78
123
|
```bash
|
|
79
|
-
python -m pip install "patchshuttle[html]==0.1.
|
|
124
|
+
python -m pip install "patchshuttle[html]==0.1.0a6"
|
|
80
125
|
```
|
|
81
126
|
|
|
82
127
|
For a local development checkout, install both development and HTML extras:
|
|
@@ -439,7 +484,8 @@ retained formatted-file states, final check results, audit observations, and a
|
|
|
439
484
|
workspace comparison where applicable.
|
|
440
485
|
|
|
441
486
|
An audit executes `tree`, `read`, literal `search`, bounded `search_context`,
|
|
442
|
-
Python `read_symbol`, `
|
|
487
|
+
Python `read_symbol`, `read_imports`, `python_structure`, `python_dependencies`,
|
|
488
|
+
`python_references`, `find_files`, `file_info`, SHA-256 `hash`, canonical
|
|
443
489
|
`hash_range`, `git_status`, and `environment`. Traversal, file reads, match
|
|
444
490
|
counts, and recorded output are bounded by local policy. Protected and ignored
|
|
445
491
|
paths are skipped, source content appears only when explicitly requested by a
|
|
@@ -459,7 +505,8 @@ automatically undo those changes.
|
|
|
459
505
|
|
|
460
506
|
A patch plan may contain `create_directory`, `create_file`, `replace_exact`,
|
|
461
507
|
`replace_symbol`, `insert_before`, `insert_after`, `delete_exact`,
|
|
462
|
-
`replace_range`, `delete_range`, `insert_at_line`,
|
|
508
|
+
`replace_range`, `delete_range`, `insert_at_line`, `apply_diff`, `ensure_import`,
|
|
509
|
+
`remove_import`, `edit_imports`, `move_file`, `move_range`, or `move_symbol` actions and
|
|
463
510
|
applies the final bytes already computed by the planner.
|
|
464
511
|
|
|
465
512
|
The optional line-range actions are strict guarded operations for cases where
|
|
@@ -478,6 +525,13 @@ rejects missing, duplicate, syntactically invalid, or stale targets, and does
|
|
|
478
525
|
not use fuzzy relocation or automatic line shifting. Exact desired symbol
|
|
479
526
|
content is an idempotent `NO_CHANGE`.
|
|
480
527
|
|
|
528
|
+
The optional `expected_ast_sha256` guard uses the structural hash from
|
|
529
|
+
`read_symbol` to tolerate formatting changes. It ignores ordinary comments,
|
|
530
|
+
includes docstrings and decorators, and is scoped to the reported Python minor
|
|
531
|
+
version. Supply the text hash too when comments must be guarded. AST-guarded
|
|
532
|
+
replacements retain the name and kind and undergo compile and resolution
|
|
533
|
+
validation. See [next-release work](docs/NEXT_RELEASE.md) for current scope.
|
|
534
|
+
|
|
481
535
|
For a supported plan, the implemented sequence is:
|
|
482
536
|
|
|
483
537
|
1. validate the workspace lock file and acquire a non-blocking cross-platform
|
|
@@ -713,18 +767,19 @@ actions:
|
|
|
713
767
|
symbol: Service.run
|
|
714
768
|
```
|
|
715
769
|
|
|
716
|
-
If a change is needed,
|
|
717
|
-
|
|
770
|
+
If a change is needed, use the audit-derived draft or copy `ast_sha256` from
|
|
771
|
+
`read_symbol` on the same Python minor version. Add its text `sha256` too when
|
|
772
|
+
comments must be guarded. The action below is illustrative:
|
|
718
773
|
|
|
719
774
|
```yaml
|
|
720
775
|
actions:
|
|
721
776
|
- replace_symbol:
|
|
722
777
|
path: src/example/service.py
|
|
723
778
|
symbol: Service.run
|
|
724
|
-
|
|
725
|
-
new_content: |
|
|
726
|
-
|
|
727
|
-
|
|
779
|
+
expected_ast_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
|
780
|
+
new_content: |2
|
|
781
|
+
def run(self, value):
|
|
782
|
+
return value
|
|
728
783
|
```
|
|
729
784
|
|
|
730
785
|
The same audit can be constructed through the public Python adapter:
|
|
@@ -840,7 +895,7 @@ python -m coverage report --fail-under=100
|
|
|
840
895
|
python -m build
|
|
841
896
|
python -m twine check dist/*
|
|
842
897
|
python tools/release_checks.py dist
|
|
843
|
-
python tools/wheel_smoke.py dist/patchshuttle-0.1.
|
|
898
|
+
python tools/wheel_smoke.py dist/patchshuttle-0.1.0a7-py3-none-any.whl --version 0.1.0a7
|
|
844
899
|
```
|
|
845
900
|
|
|
846
901
|
The `0.1.0a2`, `0.1.0a3`, and `0.1.0a4` alpha releases each passed the
|
|
@@ -958,7 +1013,9 @@ The implemented local cycle is:
|
|
|
958
1013
|
5. For a patch, run optional changed-HTML linting, controlled checks, the
|
|
959
1014
|
locally resolved isort/Black scopes, and final checks.
|
|
960
1015
|
6. Receive a timestamped log or generate a fresh handoff.
|
|
961
|
-
7.
|
|
1016
|
+
7. Retrieve configured MCP history or provide the log through an authorized
|
|
1017
|
+
channel. Current MCP history returns summaries/references, not full logs.
|
|
1018
|
+
Review the observed result before continuing with the next job.
|
|
962
1019
|
|
|
963
1020
|
See [SPEC_V0_1.md](SPEC_V0_1.md) for the approved product contract and
|
|
964
1021
|
[CHANGELOG.md](CHANGELOG.md) for release notes. PatchShuttle is designed for
|
|
@@ -971,3 +1028,76 @@ model, or project.
|
|
|
971
1028
|
## License
|
|
972
1029
|
|
|
973
1030
|
PatchShuttle is licensed under the MIT License.
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
## Guarded source transfers
|
|
1034
|
+
|
|
1035
|
+
- `move_range`: `path`, `start_line`, `end_line`, source `expected_content`
|
|
1036
|
+
and/or `expected_sha256`, `destination`, `destination_line` and
|
|
1037
|
+
`expected_destination_sha256`.
|
|
1038
|
+
- `move_symbol`: `path`, `symbol`, `expected_ast_sha256`, `destination`,
|
|
1039
|
+
`expected_destination_sha256` and optional `destination_class`.
|
|
1040
|
+
|
|
1041
|
+
Destination hashes cover simulated raw bytes; source range hashes cover
|
|
1042
|
+
canonical LF/UTF-8 text. Destinations must exist or be created earlier in the
|
|
1043
|
+
same job. Range insertion is before the 1-based destination line; EOF+1 appends.
|
|
1044
|
+
Symbol insertion appends at module scope or to the named class. Both files are
|
|
1045
|
+
validated and participate in the same backup/check/rollback transaction.
|
|
1046
|
+
|
|
1047
|
+
Same-file transfers, case-only path differences, duplicate destination names,
|
|
1048
|
+
closure extraction, class-bound super/private-name moves and multiline-string
|
|
1049
|
+
reindentation are rejected. Imports and callers are not automatically rewritten;
|
|
1050
|
+
include explicit edits and focused project checks. These actions move source
|
|
1051
|
+
content and leave the source file present. Whole-file moves are separate work.
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
## Whole-file transfers
|
|
1055
|
+
|
|
1056
|
+
`move_file` moves an existing supported text file to an absent destination.
|
|
1057
|
+
Supply `path`, `destination`, and `expected_sha256` of the original raw bytes.
|
|
1058
|
+
The transaction preserves original bytes and permissions, creates missing
|
|
1059
|
+
parent directories, and reports the source in `deleted_files`. Formatters and
|
|
1060
|
+
checks target the surviving destination. Add explicit import and caller edits
|
|
1061
|
+
when moving Python modules; imports are not automatically rewritten.
|
|
1062
|
+
|
|
1063
|
+
The source and destination must not have been touched earlier in the job.
|
|
1064
|
+
Subsequent edits to the destination are supported. Case-only moves, chains,
|
|
1065
|
+
swaps, binary files and reuse of the vacated path are currently rejected.
|
|
1066
|
+
A failed check restores the source and removes the destination. Manual rollback
|
|
1067
|
+
also verifies the applied state and refuses to overwrite a recreated source.
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
## Optional integrations
|
|
1071
|
+
|
|
1072
|
+
- `patchshuttle[mcp]`: authenticated, read-only history retrieval for ChatGPT. See [setup and deployment limits](docs/CHATGPT_INTEGRATION.md).
|
|
1073
|
+
- `patchshuttle[django]`: reviewed migration plans, explicit execution/reversal, and a separate recovery journal. See [Django workflow](docs/DJANGO_MIGRATIONS.md).
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
## Structural editing and optional adapters in 0.1.0a6
|
|
1077
|
+
|
|
1078
|
+
Use `read_symbol` AST hashes for guarded class/method replacements; use
|
|
1079
|
+
`read_imports`, `ensure_import`, and `remove_import` for structural imports.
|
|
1080
|
+
`move_file`, `move_range`, and `move_symbol` support explicit refactoring plans
|
|
1081
|
+
with shared checks and rollback. Imports and callers are not inferred.
|
|
1082
|
+
See [scope and examples](docs/NEXT_RELEASE.md).
|
|
1083
|
+
|
|
1084
|
+
Optional [ChatGPT history retrieval](docs/CHATGPT_INTEGRATION.md) uses an
|
|
1085
|
+
owner-configured authenticated MCP server (`patchshuttle[mcp]`).
|
|
1086
|
+
Optional [Django migrations](docs/DJANGO_MIGRATIONS.md) provide reviewed plans,
|
|
1087
|
+
locks and recovery journals (`patchshuttle[django]`). A live ChatGPT deployment
|
|
1088
|
+
requires the owner's HTTPS endpoint and OAuth configuration.
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
## AI workflow in a7 development
|
|
1092
|
+
|
|
1093
|
+
Start with the installed capabilities/schema and the workspace handoff. The
|
|
1094
|
+
[AI guide](src/patchshuttle/resources/AI_GUIDE.md) contains the operation decision
|
|
1095
|
+
table, guard sources, refactoring checklist and recovery boundaries. Existing
|
|
1096
|
+
Python declaration edits should normally use `read_symbol` then `replace_symbol`;
|
|
1097
|
+
request `include_template: true` for a guarded draft. Use `edit_imports` for a
|
|
1098
|
+
sequence of import edits. Keep audits separate from patches and review actual
|
|
1099
|
+
execution outcomes. The explicit `|2` in the method example preserves Python
|
|
1100
|
+
indentation after YAML parsing. Documentation examples use illustrative bodies
|
|
1101
|
+
and hashes; replace these with observed source and guards before submitting.
|
|
1102
|
+
|
|
1103
|
+
This section describes the development branch, not a published a7 release.
|
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: patchshuttle
|
|
3
|
-
Version: 0.1.0a5
|
|
4
|
-
Summary: Local, auditable patch workflows for AI-assisted software development
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
License-File: LICENSE
|
|
7
|
-
Keywords: ai,automation,cli,development-tools,patch
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Environment :: Console
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
-
Classifier: Typing :: Typed
|
|
19
|
-
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist: black<27,>=24
|
|
21
|
-
Requires-Dist: click<9,>=8.1
|
|
22
|
-
Requires-Dist: filelock<4,>=3.30
|
|
23
|
-
Requires-Dist: isort<7,>=5.13
|
|
24
|
-
Requires-Dist: pydantic<3,>=2.6
|
|
25
|
-
Requires-Dist: pyyaml<7,>=6
|
|
26
|
-
Requires-Dist: ruff<1,>=0.16
|
|
27
|
-
Requires-Dist: tomli<3,>=2; python_version < '3.11'
|
|
28
|
-
Provides-Extra: dev
|
|
29
|
-
Requires-Dist: build<2,>=1.2; extra == 'dev'
|
|
30
|
-
Requires-Dist: django<7,>=5.2; extra == 'dev'
|
|
31
|
-
Requires-Dist: pytest-cov<8,>=5; extra == 'dev'
|
|
32
|
-
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
33
|
-
Requires-Dist: twine<7,>=6.1; extra == 'dev'
|
|
34
|
-
Provides-Extra: html
|
|
35
|
-
Requires-Dist: djlint<2,>=1.44; extra == 'html'
|
|
36
|
-
Description-Content-Type: text/markdown
|
|
37
|
-
|
|
38
1
|
# PatchShuttle
|
|
39
2
|
|
|
40
3
|
PatchShuttle is intended to provide local, auditable patch workflows for
|
|
@@ -43,7 +6,8 @@ describes a small job, the user reviews and runs it locally, and PatchShuttle
|
|
|
43
6
|
records the result for the next iteration.
|
|
44
7
|
|
|
45
8
|
> [!IMPORTANT]
|
|
46
|
-
> PatchShuttle is alpha software.
|
|
9
|
+
> PatchShuttle is alpha software. This branch prepares `0.1.0a7`; the latest
|
|
10
|
+
> recorded published version is `0.1.0a6`. It implements the complete
|
|
47
11
|
> local v0.1 workflow. It executes bounded read-only
|
|
48
12
|
> audits, approved patch transactions, and approved one-pass verification jobs
|
|
49
13
|
> under a project lock. Patch jobs retain backups, run controlled checks, apply
|
|
@@ -100,7 +64,7 @@ After publication, install the exact alpha release from PyPI:
|
|
|
100
64
|
```bash
|
|
101
65
|
python -m venv .venv
|
|
102
66
|
python -m pip install --upgrade pip
|
|
103
|
-
python -m pip install "patchshuttle==0.1.
|
|
67
|
+
python -m pip install "patchshuttle==0.1.0a6"
|
|
104
68
|
```
|
|
105
69
|
|
|
106
70
|
For development from a local checkout:
|
|
@@ -113,7 +77,7 @@ To enable opt-in HTML template linting in an installed release, install the
|
|
|
113
77
|
`html` extra:
|
|
114
78
|
|
|
115
79
|
```bash
|
|
116
|
-
python -m pip install "patchshuttle[html]==0.1.
|
|
80
|
+
python -m pip install "patchshuttle[html]==0.1.0a6"
|
|
117
81
|
```
|
|
118
82
|
|
|
119
83
|
For a local development checkout, install both development and HTML extras:
|
|
@@ -476,7 +440,8 @@ retained formatted-file states, final check results, audit observations, and a
|
|
|
476
440
|
workspace comparison where applicable.
|
|
477
441
|
|
|
478
442
|
An audit executes `tree`, `read`, literal `search`, bounded `search_context`,
|
|
479
|
-
Python `read_symbol`, `
|
|
443
|
+
Python `read_symbol`, `read_imports`, `python_structure`, `python_dependencies`,
|
|
444
|
+
`python_references`, `find_files`, `file_info`, SHA-256 `hash`, canonical
|
|
480
445
|
`hash_range`, `git_status`, and `environment`. Traversal, file reads, match
|
|
481
446
|
counts, and recorded output are bounded by local policy. Protected and ignored
|
|
482
447
|
paths are skipped, source content appears only when explicitly requested by a
|
|
@@ -496,7 +461,8 @@ automatically undo those changes.
|
|
|
496
461
|
|
|
497
462
|
A patch plan may contain `create_directory`, `create_file`, `replace_exact`,
|
|
498
463
|
`replace_symbol`, `insert_before`, `insert_after`, `delete_exact`,
|
|
499
|
-
`replace_range`, `delete_range`, `insert_at_line`,
|
|
464
|
+
`replace_range`, `delete_range`, `insert_at_line`, `apply_diff`, `ensure_import`,
|
|
465
|
+
`remove_import`, `edit_imports`, `move_file`, `move_range`, or `move_symbol` actions and
|
|
500
466
|
applies the final bytes already computed by the planner.
|
|
501
467
|
|
|
502
468
|
The optional line-range actions are strict guarded operations for cases where
|
|
@@ -515,6 +481,13 @@ rejects missing, duplicate, syntactically invalid, or stale targets, and does
|
|
|
515
481
|
not use fuzzy relocation or automatic line shifting. Exact desired symbol
|
|
516
482
|
content is an idempotent `NO_CHANGE`.
|
|
517
483
|
|
|
484
|
+
The optional `expected_ast_sha256` guard uses the structural hash from
|
|
485
|
+
`read_symbol` to tolerate formatting changes. It ignores ordinary comments,
|
|
486
|
+
includes docstrings and decorators, and is scoped to the reported Python minor
|
|
487
|
+
version. Supply the text hash too when comments must be guarded. AST-guarded
|
|
488
|
+
replacements retain the name and kind and undergo compile and resolution
|
|
489
|
+
validation. See [next-release work](docs/NEXT_RELEASE.md) for current scope.
|
|
490
|
+
|
|
518
491
|
For a supported plan, the implemented sequence is:
|
|
519
492
|
|
|
520
493
|
1. validate the workspace lock file and acquire a non-blocking cross-platform
|
|
@@ -750,18 +723,19 @@ actions:
|
|
|
750
723
|
symbol: Service.run
|
|
751
724
|
```
|
|
752
725
|
|
|
753
|
-
If a change is needed,
|
|
754
|
-
|
|
726
|
+
If a change is needed, use the audit-derived draft or copy `ast_sha256` from
|
|
727
|
+
`read_symbol` on the same Python minor version. Add its text `sha256` too when
|
|
728
|
+
comments must be guarded. The action below is illustrative:
|
|
755
729
|
|
|
756
730
|
```yaml
|
|
757
731
|
actions:
|
|
758
732
|
- replace_symbol:
|
|
759
733
|
path: src/example/service.py
|
|
760
734
|
symbol: Service.run
|
|
761
|
-
|
|
762
|
-
new_content: |
|
|
763
|
-
|
|
764
|
-
|
|
735
|
+
expected_ast_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
|
736
|
+
new_content: |2
|
|
737
|
+
def run(self, value):
|
|
738
|
+
return value
|
|
765
739
|
```
|
|
766
740
|
|
|
767
741
|
The same audit can be constructed through the public Python adapter:
|
|
@@ -877,7 +851,7 @@ python -m coverage report --fail-under=100
|
|
|
877
851
|
python -m build
|
|
878
852
|
python -m twine check dist/*
|
|
879
853
|
python tools/release_checks.py dist
|
|
880
|
-
python tools/wheel_smoke.py dist/patchshuttle-0.1.
|
|
854
|
+
python tools/wheel_smoke.py dist/patchshuttle-0.1.0a7-py3-none-any.whl --version 0.1.0a7
|
|
881
855
|
```
|
|
882
856
|
|
|
883
857
|
The `0.1.0a2`, `0.1.0a3`, and `0.1.0a4` alpha releases each passed the
|
|
@@ -995,7 +969,9 @@ The implemented local cycle is:
|
|
|
995
969
|
5. For a patch, run optional changed-HTML linting, controlled checks, the
|
|
996
970
|
locally resolved isort/Black scopes, and final checks.
|
|
997
971
|
6. Receive a timestamped log or generate a fresh handoff.
|
|
998
|
-
7.
|
|
972
|
+
7. Retrieve configured MCP history or provide the log through an authorized
|
|
973
|
+
channel. Current MCP history returns summaries/references, not full logs.
|
|
974
|
+
Review the observed result before continuing with the next job.
|
|
999
975
|
|
|
1000
976
|
See [SPEC_V0_1.md](SPEC_V0_1.md) for the approved product contract and
|
|
1001
977
|
[CHANGELOG.md](CHANGELOG.md) for release notes. PatchShuttle is designed for
|
|
@@ -1008,3 +984,76 @@ model, or project.
|
|
|
1008
984
|
## License
|
|
1009
985
|
|
|
1010
986
|
PatchShuttle is licensed under the MIT License.
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
## Guarded source transfers
|
|
990
|
+
|
|
991
|
+
- `move_range`: `path`, `start_line`, `end_line`, source `expected_content`
|
|
992
|
+
and/or `expected_sha256`, `destination`, `destination_line` and
|
|
993
|
+
`expected_destination_sha256`.
|
|
994
|
+
- `move_symbol`: `path`, `symbol`, `expected_ast_sha256`, `destination`,
|
|
995
|
+
`expected_destination_sha256` and optional `destination_class`.
|
|
996
|
+
|
|
997
|
+
Destination hashes cover simulated raw bytes; source range hashes cover
|
|
998
|
+
canonical LF/UTF-8 text. Destinations must exist or be created earlier in the
|
|
999
|
+
same job. Range insertion is before the 1-based destination line; EOF+1 appends.
|
|
1000
|
+
Symbol insertion appends at module scope or to the named class. Both files are
|
|
1001
|
+
validated and participate in the same backup/check/rollback transaction.
|
|
1002
|
+
|
|
1003
|
+
Same-file transfers, case-only path differences, duplicate destination names,
|
|
1004
|
+
closure extraction, class-bound super/private-name moves and multiline-string
|
|
1005
|
+
reindentation are rejected. Imports and callers are not automatically rewritten;
|
|
1006
|
+
include explicit edits and focused project checks. These actions move source
|
|
1007
|
+
content and leave the source file present. Whole-file moves are separate work.
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
## Whole-file transfers
|
|
1011
|
+
|
|
1012
|
+
`move_file` moves an existing supported text file to an absent destination.
|
|
1013
|
+
Supply `path`, `destination`, and `expected_sha256` of the original raw bytes.
|
|
1014
|
+
The transaction preserves original bytes and permissions, creates missing
|
|
1015
|
+
parent directories, and reports the source in `deleted_files`. Formatters and
|
|
1016
|
+
checks target the surviving destination. Add explicit import and caller edits
|
|
1017
|
+
when moving Python modules; imports are not automatically rewritten.
|
|
1018
|
+
|
|
1019
|
+
The source and destination must not have been touched earlier in the job.
|
|
1020
|
+
Subsequent edits to the destination are supported. Case-only moves, chains,
|
|
1021
|
+
swaps, binary files and reuse of the vacated path are currently rejected.
|
|
1022
|
+
A failed check restores the source and removes the destination. Manual rollback
|
|
1023
|
+
also verifies the applied state and refuses to overwrite a recreated source.
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
## Optional integrations
|
|
1027
|
+
|
|
1028
|
+
- `patchshuttle[mcp]`: authenticated, read-only history retrieval for ChatGPT. See [setup and deployment limits](docs/CHATGPT_INTEGRATION.md).
|
|
1029
|
+
- `patchshuttle[django]`: reviewed migration plans, explicit execution/reversal, and a separate recovery journal. See [Django workflow](docs/DJANGO_MIGRATIONS.md).
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
## Structural editing and optional adapters in 0.1.0a6
|
|
1033
|
+
|
|
1034
|
+
Use `read_symbol` AST hashes for guarded class/method replacements; use
|
|
1035
|
+
`read_imports`, `ensure_import`, and `remove_import` for structural imports.
|
|
1036
|
+
`move_file`, `move_range`, and `move_symbol` support explicit refactoring plans
|
|
1037
|
+
with shared checks and rollback. Imports and callers are not inferred.
|
|
1038
|
+
See [scope and examples](docs/NEXT_RELEASE.md).
|
|
1039
|
+
|
|
1040
|
+
Optional [ChatGPT history retrieval](docs/CHATGPT_INTEGRATION.md) uses an
|
|
1041
|
+
owner-configured authenticated MCP server (`patchshuttle[mcp]`).
|
|
1042
|
+
Optional [Django migrations](docs/DJANGO_MIGRATIONS.md) provide reviewed plans,
|
|
1043
|
+
locks and recovery journals (`patchshuttle[django]`). A live ChatGPT deployment
|
|
1044
|
+
requires the owner's HTTPS endpoint and OAuth configuration.
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
## AI workflow in a7 development
|
|
1048
|
+
|
|
1049
|
+
Start with the installed capabilities/schema and the workspace handoff. The
|
|
1050
|
+
[AI guide](src/patchshuttle/resources/AI_GUIDE.md) contains the operation decision
|
|
1051
|
+
table, guard sources, refactoring checklist and recovery boundaries. Existing
|
|
1052
|
+
Python declaration edits should normally use `read_symbol` then `replace_symbol`;
|
|
1053
|
+
request `include_template: true` for a guarded draft. Use `edit_imports` for a
|
|
1054
|
+
sequence of import edits. Keep audits separate from patches and review actual
|
|
1055
|
+
execution outcomes. The explicit `|2` in the method example preserves Python
|
|
1056
|
+
indentation after YAML parsing. Documentation examples use illustrative bodies
|
|
1057
|
+
and hashes; replace these with observed source and guards before submitting.
|
|
1058
|
+
|
|
1059
|
+
This section describes the development branch, not a published a7 release.
|
|
@@ -863,7 +863,9 @@ Fields:
|
|
|
863
863
|
|
|
864
864
|
- `path`: required existing Python text file;
|
|
865
865
|
- `symbol`: required dotted class, function, method, or nested-symbol name;
|
|
866
|
-
- `expected_sha256`:
|
|
866
|
+
- `expected_sha256`: optional canonical text hash returned by `read_symbol`;
|
|
867
|
+
- `expected_ast_sha256`: optional structural hash returned by `read_symbol`;
|
|
868
|
+
- at least one hash is required; when both are supplied both must match;
|
|
867
869
|
- `new_content`: required complete replacement source.
|
|
868
870
|
|
|
869
871
|
Planning parses the current sequential simulated file without importing it,
|
|
@@ -874,6 +876,15 @@ desired symbol content returns `NO_CHANGE`. Execution publishes the planner's
|
|
|
874
876
|
final file bytes through the normal guarded transaction, backup, check,
|
|
875
877
|
workspace-comparison, and rollback lifecycle.
|
|
876
878
|
|
|
879
|
+
With `expected_ast_sha256`, whitespace and ordinary comment differences do not
|
|
880
|
+
invalidate the guard. Hashes include AST fields but exclude source positions,
|
|
881
|
+
and are scoped to the `ast_python` major/minor version reported by the audit.
|
|
882
|
+
Docstrings, decorators and annotations remain part of the AST. The replacement
|
|
883
|
+
must be one declaration of the same name and kind, the final module must compile
|
|
884
|
+
without execution, and the qualified target must still resolve uniquely.
|
|
885
|
+
Use the text guard as well when comment changes must invalidate the job.
|
|
886
|
+
Old text-guarded jobs retain their normalized serialization and registry hash.
|
|
887
|
+
|
|
877
888
|
### 13.5 `insert_before`
|
|
878
889
|
|
|
879
890
|
Fields:
|
|
@@ -2085,3 +2096,76 @@ unless this specification is explicitly revised:
|
|
|
2085
2096
|
- logs are plain UTF-8 text with timestamped names and an AI handoff block;
|
|
2086
2097
|
- implementation begins with tests for the contract before completing the
|
|
2087
2098
|
execution engine.
|
|
2099
|
+
|
|
2100
|
+
|
|
2101
|
+
## Guarded source transfers
|
|
2102
|
+
|
|
2103
|
+
- `move_range`: `path`, `start_line`, `end_line`, source `expected_content`
|
|
2104
|
+
and/or `expected_sha256`, `destination`, `destination_line` and
|
|
2105
|
+
`expected_destination_sha256`.
|
|
2106
|
+
- `move_symbol`: `path`, `symbol`, `expected_ast_sha256`, `destination`,
|
|
2107
|
+
`expected_destination_sha256` and optional `destination_class`.
|
|
2108
|
+
|
|
2109
|
+
Destination hashes cover simulated raw bytes; source range hashes cover
|
|
2110
|
+
canonical LF/UTF-8 text. Destinations must exist or be created earlier in the
|
|
2111
|
+
same job. Range insertion is before the 1-based destination line; EOF+1 appends.
|
|
2112
|
+
Symbol insertion appends at module scope or to the named class. Both files are
|
|
2113
|
+
validated and participate in the same backup/check/rollback transaction.
|
|
2114
|
+
|
|
2115
|
+
Same-file transfers, case-only path differences, duplicate destination names,
|
|
2116
|
+
closure extraction, class-bound super/private-name moves and multiline-string
|
|
2117
|
+
reindentation are rejected. Imports and callers are not automatically rewritten;
|
|
2118
|
+
include explicit edits and focused project checks. These actions move source
|
|
2119
|
+
content and leave the source file present. Whole-file moves are separate work.
|
|
2120
|
+
|
|
2121
|
+
|
|
2122
|
+
## Whole-file transfers
|
|
2123
|
+
|
|
2124
|
+
`move_file` moves an existing supported text file to an absent destination.
|
|
2125
|
+
Supply `path`, `destination`, and `expected_sha256` of the original raw bytes.
|
|
2126
|
+
The transaction preserves original bytes and permissions, creates missing
|
|
2127
|
+
parent directories, and reports the source in `deleted_files`. Formatters and
|
|
2128
|
+
checks target the surviving destination. Add explicit import and caller edits
|
|
2129
|
+
when moving Python modules; imports are not automatically rewritten.
|
|
2130
|
+
|
|
2131
|
+
The source and destination must not have been touched earlier in the job.
|
|
2132
|
+
Subsequent edits to the destination are supported. Case-only moves, chains,
|
|
2133
|
+
swaps, binary files and reuse of the vacated path are currently rejected.
|
|
2134
|
+
A failed check restores the source and removes the destination. Manual rollback
|
|
2135
|
+
also verifies the applied state and refuses to overwrite a recreated source.
|
|
2136
|
+
|
|
2137
|
+
|
|
2138
|
+
## Structural import edits
|
|
2139
|
+
|
|
2140
|
+
`read_imports` accepts `path` and optional `max_bytes`. It reports top-level
|
|
2141
|
+
imports, `imports_ast_sha256`, and `ast_python`. The hash ignores formatting
|
|
2142
|
+
and comments, includes alias names and order, and is Python-minor-specific.
|
|
2143
|
+
Nested/conditional imports are not selected. Use the same interpreter for
|
|
2144
|
+
inspection and planning.
|
|
2145
|
+
|
|
2146
|
+
`ensure_import` and `remove_import` require `path`, `statement` and
|
|
2147
|
+
`expected_imports_ast_sha256`. The statement must be exactly one Python
|
|
2148
|
+
`import` or `from ... import ...` with one alias, optionally renamed. Relative
|
|
2149
|
+
imports are supported. Star requests and ambiguous duplicate matches fail.
|
|
2150
|
+
The guard is always checked, including for already-present/absent imports.
|
|
2151
|
+
|
|
2152
|
+
```yaml
|
|
2153
|
+
- ensure_import:
|
|
2154
|
+
path: services/offers.py
|
|
2155
|
+
statement: from .pricing import calculate_price
|
|
2156
|
+
expected_imports_ast_sha256: "<64 hex digits from read_imports>"
|
|
2157
|
+
```
|
|
2158
|
+
|
|
2159
|
+
An existing alias in a multi-alias import satisfies `ensure_import` without
|
|
2160
|
+
rewriting that line. Removal from a multi-alias import requires a separately
|
|
2161
|
+
reviewed rewrite. Removal retains comments, including comments inside a
|
|
2162
|
+
parenthesized import. Shared semicolon lines are rejected when editing them.
|
|
2163
|
+
Insertion preserves headers, the module docstring and future-import ordering.
|
|
2164
|
+
Existing bindings are checked conservatively across scopes; a conflicting
|
|
2165
|
+
local name may therefore require a separately reviewed edit too. The resulting
|
|
2166
|
+
module is compiled without importing or executing it.
|
|
2167
|
+
|
|
2168
|
+
Unrelated source remains intact before the normal scoped formatter phase.
|
|
2169
|
+
Neither action rewrites callers, proves runtime compatibility, nor infers
|
|
2170
|
+
imports when moving files or symbols. A sequence of import edits needs the
|
|
2171
|
+
hash of each simulated intermediate import set, or separate audited jobs.
|