patchshuttle 0.1.0a6__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.
Files changed (169) hide show
  1. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/CHANGELOG.md +30 -0
  2. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/PKG-INFO +33 -12
  3. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/README.md +32 -11
  4. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/docs/NEXT_RELEASE.md +28 -5
  5. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/docs/RELEASE.md +36 -10
  6. patchshuttle-0.1.0a7/docs/ROADMAP.md +56 -0
  7. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_discovery.py +16 -2
  8. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_version.py +1 -1
  9. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/__init__.py +6 -0
  10. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/constructors.py +64 -3
  11. patchshuttle-0.1.0a7/src/patchshuttle/analysis/__init__.py +1 -0
  12. patchshuttle-0.1.0a7/src/patchshuttle/analysis/dependencies.py +160 -0
  13. patchshuttle-0.1.0a7/src/patchshuttle/analysis/references.py +136 -0
  14. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/audit.py +51 -4
  15. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/cli.py +4 -141
  16. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/context.py +10 -1
  17. patchshuttle-0.1.0a7/src/patchshuttle/documentation/__init__.py +1 -0
  18. patchshuttle-0.1.0a7/src/patchshuttle/documentation/cli.py +93 -0
  19. patchshuttle-0.1.0a7/src/patchshuttle/documentation/refresh.py +132 -0
  20. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/logging.py +9 -57
  21. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/models.py +60 -2
  22. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/planner.py +12 -28
  23. patchshuttle-0.1.0a7/src/patchshuttle/planning/discovery_log.py +70 -0
  24. patchshuttle-0.1.0a7/src/patchshuttle/planning/display.py +114 -0
  25. patchshuttle-0.1.0a7/src/patchshuttle/planning/guidance.py +38 -0
  26. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/planning/imports.py +31 -6
  27. patchshuttle-0.1.0a7/src/patchshuttle/planning/symbols.py +53 -0
  28. patchshuttle-0.1.0a7/src/patchshuttle/planning/templates.py +39 -0
  29. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/planning/types.py +5 -0
  30. patchshuttle-0.1.0a7/src/patchshuttle/resources/AI_GUIDE.md +734 -0
  31. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/PATCHSHUTTLE_PROTOCOL.md +153 -5
  32. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/selfdoc.py +34 -3
  33. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_cli.py +2 -2
  34. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_package.py +1 -1
  35. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_release_configuration.py +1 -1
  36. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_selfdoc.py +1 -1
  37. patchshuttle-0.1.0a7/tests/unit/workflow/test_ai_doc_contract.py +108 -0
  38. patchshuttle-0.1.0a7/tests/unit/workflow/test_ai_guidance.py +122 -0
  39. patchshuttle-0.1.0a7/tests/unit/workflow/test_audit_templates.py +131 -0
  40. patchshuttle-0.1.0a7/tests/unit/workflow/test_dependencies.py +142 -0
  41. patchshuttle-0.1.0a7/tests/unit/workflow/test_guide_refresh.py +180 -0
  42. patchshuttle-0.1.0a7/tests/unit/workflow/test_import_batch.py +167 -0
  43. patchshuttle-0.1.0a7/tests/unit/workflow/test_references.py +118 -0
  44. patchshuttle-0.1.0a7/tests/unit/workflow/test_symbol_diagnostics.py +81 -0
  45. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tools/wheel_smoke.py +12 -0
  46. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/.github/workflows/ci.yml +0 -0
  47. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/.github/workflows/release.yml +0 -0
  48. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/.github/workflows/testpypi.yml +0 -0
  49. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/.gitignore +0 -0
  50. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/LICENSE +0 -0
  51. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/SECURITY.md +0 -0
  52. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/SPEC_V0_1.md +0 -0
  53. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/docs/CHATGPT_INTEGRATION.md +0 -0
  54. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/docs/DJANGO_MIGRATIONS.md +0 -0
  55. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/pyproject.toml +0 -0
  56. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/__init__.py +0 -0
  57. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_ai_log.py +0 -0
  58. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_architecture.py +0 -0
  59. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_diff.py +0 -0
  60. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_html_lint.py +0 -0
  61. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_line_ranges.py +0 -0
  62. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_process.py +0 -0
  63. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_structure.py +0 -0
  64. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_python_symbols.py +0 -0
  65. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/_refactor.py +0 -0
  66. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/create.py +0 -0
  67. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/actions/modify.py +0 -0
  68. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/backup.py +0 -0
  69. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/__init__.py +0 -0
  70. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/constructors.py +0 -0
  71. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/checks/runner.py +0 -0
  72. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/config.py +0 -0
  73. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/django_app/__init__.py +0 -0
  74. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/django_app/management/__init__.py +0 -0
  75. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/django_app/management/commands/__init__.py +0 -0
  76. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/django_app/management/commands/patchshuttle_migrate.py +0 -0
  77. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/django_app/workflow.py +0 -0
  78. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/errors.py +0 -0
  79. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/execution.py +0 -0
  80. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/formatter_policy.py +0 -0
  81. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/formatters/__init__.py +0 -0
  82. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/formatters/runner.py +0 -0
  83. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/history/__init__.py +0 -0
  84. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/history/cli.py +0 -0
  85. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/history/models.py +0 -0
  86. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/history/records.py +0 -0
  87. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/history/storage.py +0 -0
  88. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/identifiers.py +0 -0
  89. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/integrations/__init__.py +0 -0
  90. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/integrations/mcp_server.py +0 -0
  91. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/inventory.py +0 -0
  92. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/linters/__init__.py +0 -0
  93. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/linters/runner.py +0 -0
  94. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/operations.py +0 -0
  95. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/parser.py +0 -0
  96. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/planning/__init__.py +0 -0
  97. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/policy.py +0 -0
  98. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/preflight.py +0 -0
  99. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/project_python.py +0 -0
  100. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/py.typed +0 -0
  101. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/registry.py +0 -0
  102. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/AUDIT-EXAMPLE.psh.yaml +0 -0
  103. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/PATCH-EXAMPLE.psh.yaml +0 -0
  104. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/resources/__init__.py +0 -0
  105. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/rollback.py +0 -0
  106. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/runner.py +0 -0
  107. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/runtime_cache.py +0 -0
  108. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/verification.py +0 -0
  109. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/warning_baseline.py +0 -0
  110. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/src/patchshuttle/workspace.py +0 -0
  111. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/e2e/test_cli_project_cycle.py +0 -0
  112. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/integration/test_workflows.py +0 -0
  113. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/integrations/test_django_migrations.py +0 -0
  114. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/integrations/test_imports.py +0 -0
  115. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/integrations/test_mcp_server.py +0 -0
  116. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/history/test_history.py +0 -0
  117. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/history/test_history_integration.py +0 -0
  118. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/history/test_history_storage_edges.py +0 -0
  119. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_a4_coverage_regressions.py +0 -0
  120. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_actions.py +0 -0
  121. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_ai_log.py +0 -0
  122. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_architecture.py +0 -0
  123. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_attempt_logging.py +0 -0
  124. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_audit_verify_execution.py +0 -0
  125. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_backup.py +0 -0
  126. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_change_transaction.py +0 -0
  127. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_check_transaction.py +0 -0
  128. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_checks.py +0 -0
  129. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_config.py +0 -0
  130. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_context_and_constructors.py +0 -0
  131. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_diff.py +0 -0
  132. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_execution.py +0 -0
  133. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_formatters.py +0 -0
  134. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_formatting_transaction.py +0 -0
  135. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_guarded_ranges.py +0 -0
  136. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_html_lint.py +0 -0
  137. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_identifiers.py +0 -0
  138. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_inventory.py +0 -0
  139. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_inventory_transaction.py +0 -0
  140. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_logging.py +0 -0
  141. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_manual_rollback.py +0 -0
  142. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_models.py +0 -0
  143. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_modify_actions.py +0 -0
  144. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_move_file.py +0 -0
  145. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_operational_execution.py +0 -0
  146. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_parser.py +0 -0
  147. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_phase19_cli.py +0 -0
  148. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_planner.py +0 -0
  149. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_planner_ux.py +0 -0
  150. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_policy.py +0 -0
  151. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_preflight.py +0 -0
  152. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_project_python.py +0 -0
  153. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_python_discovery.py +0 -0
  154. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_python_structure.py +0 -0
  155. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_python_structure_action.py +0 -0
  156. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_python_symbols.py +0 -0
  157. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_refactor.py +0 -0
  158. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_registry.py +0 -0
  159. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_rollback.py +0 -0
  160. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_runner.py +0 -0
  161. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_runtime_cache.py +0 -0
  162. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_structural_guards.py +0 -0
  163. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_warning_baseline.py +0 -0
  164. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tests/unit/test_workspace.py +0 -0
  165. /patchshuttle-0.1.0a6/src/patchshuttle/resources/AI_GUIDE.md → /patchshuttle-0.1.0a7/tests/unit/workflow/fixtures/a6-guide.md +0 -0
  166. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tools/check_tag.py +0 -0
  167. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tools/django_postgres_smoke.py +0 -0
  168. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tools/index_smoke.py +0 -0
  169. {patchshuttle-0.1.0a6 → patchshuttle-0.1.0a7}/tools/release_checks.py +0 -0
@@ -3,6 +3,36 @@
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
+ ## 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
+
6
36
  ## 0.1.0a6 - 2026-10-21
7
37
 
8
38
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchshuttle
3
- Version: 0.1.0a6
3
+ Version: 0.1.0a7
4
4
  Summary: Local, auditable patch workflows for AI-assisted software development
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -50,7 +50,8 @@ describes a small job, the user reviews and runs it locally, and PatchShuttle
50
50
  records the result for the next iteration.
51
51
 
52
52
  > [!IMPORTANT]
53
- > PatchShuttle is alpha software. Version `0.1.0a6` implements the complete
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
54
55
  > local v0.1 workflow. It executes bounded read-only
55
56
  > audits, approved patch transactions, and approved one-pass verification jobs
56
57
  > under a project lock. Patch jobs retain backups, run controlled checks, apply
@@ -483,7 +484,8 @@ retained formatted-file states, final check results, audit observations, and a
483
484
  workspace comparison where applicable.
484
485
 
485
486
  An audit executes `tree`, `read`, literal `search`, bounded `search_context`,
486
- Python `read_symbol`, `find_files`, `file_info`, SHA-256 `hash`, canonical
487
+ Python `read_symbol`, `read_imports`, `python_structure`, `python_dependencies`,
488
+ `python_references`, `find_files`, `file_info`, SHA-256 `hash`, canonical
487
489
  `hash_range`, `git_status`, and `environment`. Traversal, file reads, match
488
490
  counts, and recorded output are bounded by local policy. Protected and ignored
489
491
  paths are skipped, source content appears only when explicitly requested by a
@@ -503,7 +505,8 @@ automatically undo those changes.
503
505
 
504
506
  A patch plan may contain `create_directory`, `create_file`, `replace_exact`,
505
507
  `replace_symbol`, `insert_before`, `insert_after`, `delete_exact`,
506
- `replace_range`, `delete_range`, `insert_at_line`, or `apply_diff` actions and
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
507
510
  applies the final bytes already computed by the planner.
508
511
 
509
512
  The optional line-range actions are strict guarded operations for cases where
@@ -764,18 +767,19 @@ actions:
764
767
  symbol: Service.run
765
768
  ```
766
769
 
767
- If a change is needed, copy the canonical SHA-256 returned by `read_symbol`
768
- into a guarded patch action:
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:
769
773
 
770
774
  ```yaml
771
775
  actions:
772
776
  - replace_symbol:
773
777
  path: src/example/service.py
774
778
  symbol: Service.run
775
- expected_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
776
- new_content: |
777
- def run(self, value):
778
- return value
779
+ expected_ast_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
780
+ new_content: |2
781
+ def run(self, value):
782
+ return value
779
783
  ```
780
784
 
781
785
  The same audit can be constructed through the public Python adapter:
@@ -891,7 +895,7 @@ python -m coverage report --fail-under=100
891
895
  python -m build
892
896
  python -m twine check dist/*
893
897
  python tools/release_checks.py dist
894
- python tools/wheel_smoke.py dist/patchshuttle-0.1.0a6-py3-none-any.whl --version 0.1.0a6
898
+ python tools/wheel_smoke.py dist/patchshuttle-0.1.0a7-py3-none-any.whl --version 0.1.0a7
895
899
  ```
896
900
 
897
901
  The `0.1.0a2`, `0.1.0a3`, and `0.1.0a4` alpha releases each passed the
@@ -1009,7 +1013,9 @@ The implemented local cycle is:
1009
1013
  5. For a patch, run optional changed-HTML linting, controlled checks, the
1010
1014
  locally resolved isort/Black scopes, and final checks.
1011
1015
  6. Receive a timestamped log or generate a fresh handoff.
1012
- 7. Review the log, upload it to the AI, and continue with the next job.
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.
1013
1019
 
1014
1020
  See [SPEC_V0_1.md](SPEC_V0_1.md) for the approved product contract and
1015
1021
  [CHANGELOG.md](CHANGELOG.md) for release notes. PatchShuttle is designed for
@@ -1080,3 +1086,18 @@ owner-configured authenticated MCP server (`patchshuttle[mcp]`).
1080
1086
  Optional [Django migrations](docs/DJANGO_MIGRATIONS.md) provide reviewed plans,
1081
1087
  locks and recovery journals (`patchshuttle[django]`). A live ChatGPT deployment
1082
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.
@@ -6,7 +6,8 @@ describes a small job, the user reviews and runs it locally, and PatchShuttle
6
6
  records the result for the next iteration.
7
7
 
8
8
  > [!IMPORTANT]
9
- > PatchShuttle is alpha software. Version `0.1.0a6` implements the complete
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
10
11
  > local v0.1 workflow. It executes bounded read-only
11
12
  > audits, approved patch transactions, and approved one-pass verification jobs
12
13
  > under a project lock. Patch jobs retain backups, run controlled checks, apply
@@ -439,7 +440,8 @@ retained formatted-file states, final check results, audit observations, and a
439
440
  workspace comparison where applicable.
440
441
 
441
442
  An audit executes `tree`, `read`, literal `search`, bounded `search_context`,
442
- Python `read_symbol`, `find_files`, `file_info`, SHA-256 `hash`, canonical
443
+ Python `read_symbol`, `read_imports`, `python_structure`, `python_dependencies`,
444
+ `python_references`, `find_files`, `file_info`, SHA-256 `hash`, canonical
443
445
  `hash_range`, `git_status`, and `environment`. Traversal, file reads, match
444
446
  counts, and recorded output are bounded by local policy. Protected and ignored
445
447
  paths are skipped, source content appears only when explicitly requested by a
@@ -459,7 +461,8 @@ automatically undo those changes.
459
461
 
460
462
  A patch plan may contain `create_directory`, `create_file`, `replace_exact`,
461
463
  `replace_symbol`, `insert_before`, `insert_after`, `delete_exact`,
462
- `replace_range`, `delete_range`, `insert_at_line`, or `apply_diff` actions and
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
463
466
  applies the final bytes already computed by the planner.
464
467
 
465
468
  The optional line-range actions are strict guarded operations for cases where
@@ -720,18 +723,19 @@ actions:
720
723
  symbol: Service.run
721
724
  ```
722
725
 
723
- If a change is needed, copy the canonical SHA-256 returned by `read_symbol`
724
- into a guarded patch action:
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:
725
729
 
726
730
  ```yaml
727
731
  actions:
728
732
  - replace_symbol:
729
733
  path: src/example/service.py
730
734
  symbol: Service.run
731
- expected_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
732
- new_content: |
733
- def run(self, value):
734
- return value
735
+ expected_ast_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
736
+ new_content: |2
737
+ def run(self, value):
738
+ return value
735
739
  ```
736
740
 
737
741
  The same audit can be constructed through the public Python adapter:
@@ -847,7 +851,7 @@ python -m coverage report --fail-under=100
847
851
  python -m build
848
852
  python -m twine check dist/*
849
853
  python tools/release_checks.py dist
850
- python tools/wheel_smoke.py dist/patchshuttle-0.1.0a6-py3-none-any.whl --version 0.1.0a6
854
+ python tools/wheel_smoke.py dist/patchshuttle-0.1.0a7-py3-none-any.whl --version 0.1.0a7
851
855
  ```
852
856
 
853
857
  The `0.1.0a2`, `0.1.0a3`, and `0.1.0a4` alpha releases each passed the
@@ -965,7 +969,9 @@ The implemented local cycle is:
965
969
  5. For a patch, run optional changed-HTML linting, controlled checks, the
966
970
  locally resolved isort/Black scopes, and final checks.
967
971
  6. Receive a timestamped log or generate a fresh handoff.
968
- 7. Review the log, upload it to the AI, and continue with the next job.
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.
969
975
 
970
976
  See [SPEC_V0_1.md](SPEC_V0_1.md) for the approved product contract and
971
977
  [CHANGELOG.md](CHANGELOG.md) for release notes. PatchShuttle is designed for
@@ -1036,3 +1042,18 @@ owner-configured authenticated MCP server (`patchshuttle[mcp]`).
1036
1042
  Optional [Django migrations](docs/DJANGO_MIGRATIONS.md) provide reviewed plans,
1037
1043
  locks and recovery journals (`patchshuttle[django]`). A live ChatGPT deployment
1038
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.
@@ -1,7 +1,29 @@
1
1
  # Next release: structural editing and controlled refactoring
2
2
 
3
- Status: 0.1.0a6 candidate undergoing release qualification.
4
- Base: 0.1.0a5. Publication requires the release gates below.
3
+ Status: 0.1.0a6 published; see RELEASE.md for immutable publication evidence.
4
+ The sections below describe a6 scope and remaining work.
5
+
6
+ ## 0.1.0a7 release candidate
7
+
8
+ Implemented a7 scope:
9
+
10
+ - Python operation-selection rules and conditional advisory feedback in plans,
11
+ full/compact logs and handoff; transfer/import telemetry.
12
+ - Reviewed `docs refresh` for recognized AI guide templates, preserving appended
13
+ owner notes and backups; inline customizations still require manual review.
14
+ - Bounded indentation diagnostics for structural replacements.
15
+ - `edit_imports`: ordered import changes with one initial import-set guard.
16
+ - Optional `include_template` drafts from `read_symbol` and `read_imports`.
17
+ - Read-only `python_dependencies` and `python_references` for bounded static
18
+ dependency/cycle and unverified reference candidates. No automatic rewrites.
19
+ - Audited AI guide, handoff, protocol and CLI explanations, with executable
20
+ YAML example tests and action-catalog checks.
21
+
22
+ No a7 publication is recorded yet. Source version is now `0.1.0a7` for candidate
23
+ qualification. Final commit CI, TestPyPI and production publication gates remain
24
+ required before recording this version as released.
25
+ See ROADMAP.md for the broader backlog. The following sections record the a6
26
+ foundation and its remaining limitations, not additional a7 completion claims.
5
27
 
6
28
  ## Implemented in this branch
7
29
 
@@ -28,7 +50,7 @@ This is AST-selected source replacement, not AST unparse of the whole file.
28
50
  path: services/offers.py
29
51
  symbol: OfferService.calculate
30
52
  expected_ast_sha256: "<64 hex digits from read_symbol>"
31
- new_content: |
53
+ new_content: |2
32
54
  def calculate(self, amount):
33
55
  return amount * 2
34
56
  ```
@@ -166,5 +188,6 @@ module is compiled without importing or executing it.
166
188
 
167
189
  Unrelated source remains intact before the normal scoped formatter phase.
168
190
  Neither action rewrites callers, proves runtime compatibility, nor infers
169
- imports when moving files or symbols. A sequence of import edits needs the
170
- hash of each simulated intermediate import set, or separate audited jobs.
191
+ imports when moving files or symbols. Separate import actions need the hash of each simulated intermediate import
192
+ set, or separate audited jobs. In a7, prefer `edit_imports` for multiple ordered
193
+ changes: its guard targets the import set at entry to that action.
@@ -1,6 +1,6 @@
1
1
  # PatchShuttle release guide
2
2
 
3
- This guide records the immutable published `0.1.0a2`, `0.1.0a3`, and `0.1.0a4` evidence and
3
+ This guide records immutable published release evidence through `0.1.0a6` and
4
4
  the staged qualification procedure for later releases. Do not publish a
5
5
  stable `0.1.0` release until every acceptance criterion in `SPEC_V0_1.md` has
6
6
  passed and the stable release is approved.
@@ -158,7 +158,7 @@ python tools/wheel_smoke.py dist/patchshuttle-<VERSION>-py3-none-any.whl --versi
158
158
  `release_checks.py` requires exactly one wheel and one source archive for the
159
159
  source version and writes `dist/SHA256SUMS`. Replace `<VERSION>` with the exact
160
160
  source version under qualification. For the most recent recorded qualification it
161
- was `0.1.0a4`. Do not reuse an immutable published version for a future upload.
161
+ was `0.1.0a6`. Do not reuse an immutable published version for a future upload.
162
162
 
163
163
  During a source-version transition, metadata in an already-installed editable
164
164
  environment may still report the previous version until the package is
@@ -181,7 +181,8 @@ logs must keep exposing resolved formatter and architecture decisions.
181
181
  3. Do not upload `.venv/`, caches, previous phase archives, or local runtime
182
182
  `patches/` directories.
183
183
  4. Push the default branch and wait for the `CI` workflow.
184
- 5. Require all five matrix jobs and the package job to pass before publishing.
184
+ 5. Require all five matrix jobs, the PostgreSQL integration job and the package
185
+ job to pass before publishing.
185
186
 
186
187
  The required matrix is Ubuntu/Python 3.10, 3.12, and 3.14 plus
187
188
  Windows/Python 3.12 and 3.14. A local Linux result does not replace these jobs.
@@ -252,15 +253,40 @@ statement also requires a separate recorded ChatGPT end-to-end workflow using
252
253
  that released protocol and must state the tested scope.
253
254
 
254
255
 
255
- ## 0.1.0a6 candidate
256
+ ## Recorded `0.1.0a6` qualification
257
+
258
+ Published on 2026-10-22 from immutable tag `v0.1.0a6`, resolving to
259
+ `831dc2a8b4342150785a227a4834e5c1efdfc5be`.
256
260
 
257
- Source candidate prepared on 2026-10-21. This is not a publication record.
258
261
  Scope: AST-guarded symbol/import edits, guarded file/range/symbol transfers,
259
262
  UTF-8 formatter subprocesses, optional authenticated MCP history retrieval,
260
263
  and an optional Django migration command with reviewed plans and journals.
261
264
  The owner must configure the live HTTPS/OAuth deployment separately.
262
-
263
- Adapter commit `738366bfe1c6c02442913703e9d9bafaafd7065c` passed
264
- [Linux/Windows, PostgreSQL 16, and distribution CI](https://github.com/ratundo/patchshuttle/actions/runs/39432455841).
265
- The final versioned candidate still requires its own complete gates before
266
- TestPyPI, GitHub pre-release and production PyPI publication.
265
+ Refactoring does not automatically rewrite callers or infer dependencies;
266
+ database recovery requires explicit owner review rather than automatic rollback.
267
+
268
+ External gates completed successfully:
269
+
270
+ - [main CI: all seven jobs](https://github.com/ratundo/patchshuttle/actions/runs/39643741606),
271
+ including Ubuntu, Windows, PostgreSQL 16 and clean-wheel checks;
272
+ - [tag CI](https://github.com/ratundo/patchshuttle/actions/runs/39741537873);
273
+ - [TestPyPI build, publish and clean-index verification](https://github.com/ratundo/patchshuttle/actions/runs/39740928641);
274
+ - [GitHub pre-release](https://github.com/ratundo/patchshuttle/releases/tag/v0.1.0a6);
275
+ - [PyPI build, publish and clean-index verification](https://github.com/ratundo/patchshuttle/actions/runs/39741537464),
276
+ with `INDEX_SMOKE_OK pypi 0.1.0a6`;
277
+ - [PyPI version](https://pypi.org/project/patchshuttle/0.1.0a6/).
278
+
279
+ The qualified suite passed 1,112 tests with 100% statement and branch coverage.
280
+ Windows pytest and coverage-report steps are separate so a later successful
281
+ native command cannot mask a failed test command.
282
+
283
+ The TestPyPI and production PyPI JSON APIs independently reported byte-identical
284
+ artifacts (matching sizes and SHA-256 digests):
285
+
286
+ - `patchshuttle-0.1.0a6-py3-none-any.whl`, 202331 bytes:
287
+ `fd83e54be01115af1217d56ae73bd7cf2c8880ce79b84a7fd7d5b06678efb92f`;
288
+ - `patchshuttle-0.1.0a6.tar.gz`, 355211 bytes:
289
+ `15654537705304ab843ba6cfa5d615900420efd2f6ebefc83b28ca7d64da8c91`.
290
+
291
+ This publication record does not extend the separately scoped a2
292
+ **Tested with ChatGPT** claim or claim deployment of a live MCP endpoint.
@@ -0,0 +1,56 @@
1
+ # Development roadmap after 0.1.0a6
2
+
3
+ This is a backlog, not a statement that every item ships in a7.
4
+ Published a6 evidence remains in RELEASE.md. Source version stays a6 until
5
+ an a7 candidate is qualified; no a7 package has been published.
6
+
7
+ ## First a7 milestone
8
+
9
+ Implemented locally: conditional symbol-edit advisory in plans/full/compact logs,
10
+ operation selection rules, handoff example, MCP-aware retrieval guidance,
11
+ transfer/import telemetry, and smaller presentation modules.
12
+ The first guidance milestone passed hosted Linux/Windows/PostgreSQL CI.
13
+ Guide refresh now supports reviewed updates of recognized current/a4/a5/a6
14
+ templates with appended notes, hashes and backups; inline customizations require
15
+ manual review.
16
+ Guide refresh passed hosted CI. Structural replacement failures now include
17
+ bounded indentation context and YAML guidance; input is never reindented.
18
+ Indentation diagnostics passed both hosted CI runs. Batch import editing with
19
+ one initial guard is implemented; qualification is in progress.
20
+ Batch imports passed hosted CI. Opt-in audit-derived action drafts are
21
+ implemented. Static module-import dependency auditing is implemented;
22
+ dependency auditing passed hosted CI. Syntactic symbol-reference candidates
23
+ are implemented; binding-aware resolution, rewrites and release qualification
24
+ remain pending.
25
+
26
+ ## Subsequent work, in priority order
27
+
28
+ 1. Synchronize AI guide, protocol and explain output; detect stale generated
29
+ guides and support reviewed refresh preserving owner additions.
30
+ 2. Batch import edits with one initial guard; audit-derived action templates;
31
+ explain conflicts with initial versus simulated intermediate state.
32
+ 3. Static dependency/reference analysis before moves, unresolved dynamic cases,
33
+ import-cycle reporting, reviewed updates and optional compatibility reexports.
34
+ 4. End-to-end refactors: rename symbols/modules, extract selected declarations,
35
+ move groups into packages, report architecture before/after.
36
+ 5. Extend transfers: same-file moves, multiple destinations/anchors, move chains,
37
+ case-only renames, binary files, multi-alias and selected conditional imports.
38
+ 6. Improve indentation diagnostics; evaluate explicit dedented input and CST
39
+ for targeted edits while preserving multiline-string semantics.
40
+ 7. Deploy and test read-only MCP with real owner HTTPS/OAuth configuration;
41
+ retrieve bounded diagnostics and the separate migration journal.
42
+ 8. Migration data checks, partial-success reports, recovery integration and
43
+ imported-helper identity. Do not claim file/database atomic rollback.
44
+ 9. Reproduce the owner's original Windows isort error and add a regression test;
45
+ cover Cyrillic paths, CRLF/BOM and subprocess output encodings.
46
+ 10. Benchmark discovery/planning/checks/output size/retries before optimizing
47
+ AST reuse, traversal or owner-configured focused check profiles.
48
+ 11. Maintain reproducible dogfooding tasks with model/instruction versions,
49
+ input state, timings, attempt counts, outputs and recovery outcomes.
50
+
51
+ ## Release gates
52
+
53
+ Formatting, meaningful regression tests, full statement/branch coverage,
54
+ Ubuntu/Windows/PostgreSQL CI, build and clean-wheel checks, TestPyPI verification,
55
+ then a tagged GitHub prerelease and PyPI verification. Record evidence only after
56
+ completion. Do not weaken guards or architecture policy to pass these gates.
@@ -11,8 +11,10 @@ from patchshuttle.models import Job
11
11
  _TEXT_ACTIONS = frozenset(
12
12
  {"delete_exact", "insert_after", "insert_before", "replace_exact"}
13
13
  )
14
- _SYMBOL_ACTIONS = frozenset({"replace_symbol"})
15
- _LINE_ACTIONS = frozenset({"delete_range", "insert_at_line", "replace_range"})
14
+ _SYMBOL_ACTIONS = frozenset({"replace_symbol", "move_symbol"})
15
+ _LINE_ACTIONS = frozenset(
16
+ {"delete_range", "insert_at_line", "replace_range", "move_range"}
17
+ )
16
18
  _FAILURE_SIGNALS = {
17
19
  "LINE_RANGE_GUARD_MISMATCH": "LINE_TARGETING_FAILURE",
18
20
  "LINE_RANGE_OUT_OF_BOUNDS": "LINE_TARGETING_FAILURE",
@@ -47,6 +49,8 @@ class PythonDiscoveryEvaluation:
47
49
  declared_python_line_actions: int
48
50
  failure_signal: str | None
49
51
  reason_codes: tuple[str, ...]
52
+ declared_python_import_actions: int = 0
53
+ declared_python_file_move_actions: int = 0
50
54
 
51
55
 
52
56
  def evaluate_python_discovery(
@@ -77,6 +81,8 @@ def evaluate_python_discovery(
77
81
  declared_python_symbol_actions = 0
78
82
  declared_python_line_actions = 0
79
83
 
84
+ import_actions = 0
85
+ file_moves = 0
80
86
  for index, action in enumerate(job.actions, start=1):
81
87
  name = action.name
82
88
  parameters = action.parameters
@@ -118,6 +124,10 @@ def evaluate_python_discovery(
118
124
 
119
125
  if not python_targeted:
120
126
  continue
127
+ if name in {"ensure_import", "remove_import", "edit_imports"}:
128
+ import_actions += 1
129
+ if name == "move_file":
130
+ file_moves += 1
121
131
  if name in _TEXT_ACTIONS:
122
132
  declared_python_text_actions += 1
123
133
  elif name in _SYMBOL_ACTIONS:
@@ -142,6 +152,8 @@ def evaluate_python_discovery(
142
152
  declared_python_line_actions=declared_python_line_actions,
143
153
  failure_signal=failure_signal,
144
154
  )
155
+ reason_codes += ("PYTHON_IMPORT_TARGETING_USED",) if import_actions else ()
156
+ reason_codes += ("PYTHON_FILE_MOVE_USED",) if file_moves else ()
145
157
  applicable = bool(python_paths or reason_codes)
146
158
  return PythonDiscoveryEvaluation(
147
159
  applicable=applicable,
@@ -164,6 +176,8 @@ def evaluate_python_discovery(
164
176
  declared_python_line_actions=declared_python_line_actions,
165
177
  failure_signal=failure_signal,
166
178
  reason_codes=reason_codes,
179
+ declared_python_import_actions=import_actions,
180
+ declared_python_file_move_actions=file_moves,
167
181
  )
168
182
 
169
183
 
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for the PatchShuttle package version."""
2
2
 
3
- __version__ = "0.1.0a6"
3
+ __version__ = "0.1.0a7"
@@ -10,6 +10,7 @@ from patchshuttle.actions.constructors import (
10
10
  create_file,
11
11
  delete_exact,
12
12
  delete_range,
13
+ edit_imports,
13
14
  ensure_import,
14
15
  environment,
15
16
  file_info,
@@ -23,6 +24,8 @@ from patchshuttle.actions.constructors import (
23
24
  move_file,
24
25
  move_range,
25
26
  move_symbol,
27
+ python_dependencies,
28
+ python_references,
26
29
  python_structure,
27
30
  read,
28
31
  read_imports,
@@ -91,8 +94,11 @@ __all__ = [
91
94
  "read",
92
95
  "read_symbol",
93
96
  "read_imports",
97
+ "edit_imports",
94
98
  "ensure_import",
95
99
  "remove_import",
100
+ "python_references",
101
+ "python_dependencies",
96
102
  "python_structure",
97
103
  "move_file",
98
104
  "move_range",
@@ -86,8 +86,9 @@ def read_symbol(
86
86
  symbol: str,
87
87
  *,
88
88
  max_bytes: int | None = None,
89
+ include_template: bool = False,
89
90
  ) -> Action:
90
- parameters = {"path": path, "symbol": symbol}
91
+ parameters = {"path": path, "symbol": symbol, "include_template": include_template}
91
92
  if max_bytes is not None:
92
93
  parameters["max_bytes"] = max_bytes
93
94
  return Action({"read_symbol": parameters})
@@ -445,8 +446,10 @@ def _add_guards(
445
446
  parameters["expected_sha256"] = expected_sha256
446
447
 
447
448
 
448
- def read_imports(path: str, *, max_bytes: int | None = None) -> Action:
449
- parameters = {"path": path}
449
+ def read_imports(
450
+ path: str, *, max_bytes: int | None = None, include_template: bool = False
451
+ ) -> Action:
452
+ parameters = {"path": path, "include_template": include_template}
450
453
  if max_bytes is not None:
451
454
  parameters["max_bytes"] = max_bytes
452
455
  return Action({"read_imports": parameters})
@@ -480,8 +483,66 @@ def remove_import(
480
483
  )
481
484
 
482
485
 
486
+ def edit_imports(path: str, edits, *, expected_imports_ast_sha256: str) -> Action:
487
+ """Apply ordered import edits guarded by the initial simulated import set."""
488
+ return Action(
489
+ {
490
+ "edit_imports": {
491
+ "path": path,
492
+ "edits": edits,
493
+ "expected_imports_ast_sha256": expected_imports_ast_sha256,
494
+ }
495
+ }
496
+ )
497
+
498
+
499
+ def python_dependencies(
500
+ path: str = ".",
501
+ *,
502
+ max_files: int = 300,
503
+ max_findings: int = 2000,
504
+ max_bytes: int = 50000,
505
+ ) -> Action:
506
+ return Action(
507
+ {
508
+ "python_dependencies": dict(
509
+ path=path,
510
+ max_files=max_files,
511
+ max_findings=max_findings,
512
+ max_bytes=max_bytes,
513
+ )
514
+ }
515
+ )
516
+
517
+
518
+ def python_references(
519
+ module: str,
520
+ symbol: str,
521
+ *,
522
+ path: str = ".",
523
+ max_files: int = 300,
524
+ max_findings: int = 2000,
525
+ max_bytes: int = 50000,
526
+ ) -> Action:
527
+ return Action(
528
+ {
529
+ "python_references": dict(
530
+ module=module,
531
+ symbol=symbol,
532
+ path=path,
533
+ max_files=max_files,
534
+ max_findings=max_findings,
535
+ max_bytes=max_bytes,
536
+ )
537
+ }
538
+ )
539
+
540
+
483
541
  __all__ = [
542
+ "python_references",
543
+ "python_dependencies",
484
544
  "read_imports",
545
+ "edit_imports",
485
546
  "ensure_import",
486
547
  "remove_import",
487
548
  "apply_diff",
@@ -0,0 +1 @@
1
+ """Read-only static analysis helpers."""