patchshuttle 0.1.0a3__tar.gz → 0.1.0a4__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.0a3 → patchshuttle-0.1.0a4}/CHANGELOG.md +67 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/PKG-INFO +281 -50
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/README.md +279 -49
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/SPEC_V0_1.md +246 -43
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/docs/RELEASE.md +38 -10
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/pyproject.toml +1 -0
- patchshuttle-0.1.0a4/src/patchshuttle/_ai_log.py +437 -0
- patchshuttle-0.1.0a4/src/patchshuttle/_architecture.py +334 -0
- patchshuttle-0.1.0a4/src/patchshuttle/_python_discovery.py +236 -0
- patchshuttle-0.1.0a4/src/patchshuttle/_python_structure.py +220 -0
- patchshuttle-0.1.0a4/src/patchshuttle/_python_symbols.py +58 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/_version.py +1 -1
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/actions/__init__.py +8 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/actions/constructors.py +75 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/audit.py +190 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/checks/__init__.py +2 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/checks/constructors.py +5 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/checks/runner.py +90 -16
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/cli.py +111 -4
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/config.py +102 -7
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/context.py +22 -8
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/errors.py +5 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/logging.py +232 -14
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/models.py +82 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/planner.py +214 -8
- patchshuttle-0.1.0a4/src/patchshuttle/project_python.py +79 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/resources/AI_GUIDE.md +102 -4
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/resources/PATCHSHUTTLE_PROTOCOL.md +105 -5
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/runner.py +1 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/selfdoc.py +48 -1
- patchshuttle-0.1.0a4/src/patchshuttle/warning_baseline.py +271 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/workspace.py +12 -0
- patchshuttle-0.1.0a4/tests/unit/test_a4_coverage_regressions.py +568 -0
- patchshuttle-0.1.0a4/tests/unit/test_ai_log.py +273 -0
- patchshuttle-0.1.0a4/tests/unit/test_architecture.py +350 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_attempt_logging.py +6 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_audit_verify_execution.py +64 -1
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_checks.py +80 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_cli.py +111 -3
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_config.py +5 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_context_and_constructors.py +92 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_logging.py +83 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_models.py +65 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_operational_execution.py +39 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_package.py +1 -1
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_planner.py +200 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_policy.py +30 -0
- patchshuttle-0.1.0a4/tests/unit/test_project_python.py +219 -0
- patchshuttle-0.1.0a4/tests/unit/test_python_discovery.py +307 -0
- patchshuttle-0.1.0a4/tests/unit/test_python_structure.py +194 -0
- patchshuttle-0.1.0a4/tests/unit/test_python_structure_action.py +151 -0
- patchshuttle-0.1.0a4/tests/unit/test_python_symbols.py +72 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_release_configuration.py +1 -1
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_selfdoc.py +11 -1
- patchshuttle-0.1.0a4/tests/unit/test_warning_baseline.py +126 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_workspace.py +2 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/.github/workflows/ci.yml +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/.github/workflows/release.yml +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/.github/workflows/testpypi.yml +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/.gitignore +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/LICENSE +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/SECURITY.md +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/__init__.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/_diff.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/_html_lint.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/_line_ranges.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/_process.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/actions/create.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/actions/modify.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/backup.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/execution.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/formatter_policy.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/formatters/__init__.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/formatters/runner.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/identifiers.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/inventory.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/linters/__init__.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/linters/runner.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/operations.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/parser.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/policy.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/preflight.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/py.typed +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/registry.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/resources/AUDIT-EXAMPLE.psh.yaml +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/resources/PATCH-EXAMPLE.psh.yaml +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/resources/__init__.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/rollback.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/runtime_cache.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/src/patchshuttle/verification.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/e2e/test_cli_project_cycle.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/integration/test_workflows.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_actions.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_backup.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_change_transaction.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_check_transaction.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_diff.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_execution.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_formatters.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_formatting_transaction.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_guarded_ranges.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_html_lint.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_identifiers.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_inventory.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_inventory_transaction.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_manual_rollback.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_modify_actions.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_parser.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_phase19_cli.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_planner_ux.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_preflight.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_registry.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_rollback.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_runner.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tests/unit/test_runtime_cache.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tools/check_tag.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tools/index_smoke.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tools/release_checks.py +0 -0
- {patchshuttle-0.1.0a3 → patchshuttle-0.1.0a4}/tools/wheel_smoke.py +0 -0
|
@@ -5,6 +5,73 @@ uses semantic versioning, including Python-compatible pre-release versions.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.1.0a4 - 2026-08-27
|
|
9
|
+
|
|
10
|
+
Third alpha release, focused on bounded Python source discovery, compact
|
|
11
|
+
structure output, and owner-controlled architecture ratchets.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- Owner-controlled Python architecture ratchets evaluate the planner's virtual
|
|
15
|
+
file state before execution. Defaults warn at 500 lines per module, 15 direct
|
|
16
|
+
Python files per package, five new Python files, or one new package; hard
|
|
17
|
+
limits are 1000, 25, 10, and three respectively. Stable bounded `ARCH` findings
|
|
18
|
+
appear in plans and logs, while unchanged or improving legacy violations remain
|
|
19
|
+
allowed.
|
|
20
|
+
|
|
21
|
+
- Read-only `python_structure` uses the standard-library AST to report a
|
|
22
|
+
bounded declaration map for one Python file or directory, including
|
|
23
|
+
imports, classes, functions, methods, parameters, decorators, bases,
|
|
24
|
+
source ranges, parse errors, and explicit file and symbol limit signals,
|
|
25
|
+
without importing or executing project code. Its opt-in `compact: true`
|
|
26
|
+
mode retains navigational symbol identities and ranges while omitting
|
|
27
|
+
detailed import and declaration metadata; full output remains the default.
|
|
28
|
+
|
|
29
|
+
- Read-only `search_context` returns bounded physical-line context around
|
|
30
|
+
literal matches, and `read_symbol` returns one exactly resolved
|
|
31
|
+
decorator-aware Python symbol with its physical range and canonical
|
|
32
|
+
LF/UTF-8 SHA-256.
|
|
33
|
+
- Guarded `replace_symbol` replaces one exactly resolved Python class,
|
|
34
|
+
function, method, or nested symbol using the hash returned by
|
|
35
|
+
`read_symbol` and the planner's sequential simulated file state.
|
|
36
|
+
- The built-in `ruff: {}` check runs fixed Ruff `F` rules without fixes
|
|
37
|
+
over only the Python files changed by the current patch.
|
|
38
|
+
- `logs --last --ai` and `logs --last --ai-json` render bounded
|
|
39
|
+
deterministic text and JSON views of the newest stored log without
|
|
40
|
+
changing it or executing project code.
|
|
41
|
+
- Run and early-failure logs include evidence-only
|
|
42
|
+
`PYTHON_DISCOVERY_EVALUATION` telemetry for the current job. It records
|
|
43
|
+
explicit Python paths, audit action/output volume, targeting styles, and
|
|
44
|
+
relevant failure signals without estimating tokens or deciding whether a
|
|
45
|
+
project symbol index should be implemented.
|
|
46
|
+
- Python discovery telemetry also aggregates reported file and search
|
|
47
|
+
matches, result-limit signals, and durations already present in bounded
|
|
48
|
+
audit results. Newly generated workspace policy covers conventional
|
|
49
|
+
`.venv`, `venv`, and `node_modules` trees at any depth; backup directories
|
|
50
|
+
remain owner-configured exclusions.
|
|
51
|
+
- Best-effort whole-log redaction recognizes common sensitive Python
|
|
52
|
+
assignment identifiers, including prefixed passwords, API and access keys,
|
|
53
|
+
secret and private keys, tokens, and one-line `SECRET_KEY_FALLBACKS`
|
|
54
|
+
collections. Safe annotations, same-name references, and loader calls remain
|
|
55
|
+
visible; the redaction guarantee remains `NONE`.
|
|
56
|
+
- Explicit project-local Django warning baselines classify known and new
|
|
57
|
+
W-class system-check warnings without changing the check exit status.
|
|
58
|
+
- Optional owner-controlled `[execution].python_executable` selects the
|
|
59
|
+
interpreter for Python-based project checks and `{python}` local
|
|
60
|
+
profiles. Jobs cannot set it, and omitted configuration retains the
|
|
61
|
+
existing interpreter behavior.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- AI handoffs use a deterministic capability hash, generated handoff trees
|
|
66
|
+
omit legacy backup and archive artifacts, and source audit output avoids
|
|
67
|
+
the confirmed token-name redaction false positive.
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
- `replace_symbol` execution now enters the same guarded file-change
|
|
72
|
+
transaction as other planned text modifications, including revalidation,
|
|
73
|
+
backups, checks, rollback, logging, and workspace comparison.
|
|
74
|
+
|
|
8
75
|
## 0.1.0a3 - 2026-08-23
|
|
9
76
|
|
|
10
77
|
Second alpha release, focused on AI-facing planning diagnostics, legacy-project
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patchshuttle
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a4
|
|
4
4
|
Summary: Local, auditable patch workflows for AI-assisted software development
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -23,6 +23,7 @@ Requires-Dist: filelock<4,>=3.30
|
|
|
23
23
|
Requires-Dist: isort<7,>=5.13
|
|
24
24
|
Requires-Dist: pydantic<3,>=2.6
|
|
25
25
|
Requires-Dist: pyyaml<7,>=6
|
|
26
|
+
Requires-Dist: ruff<1,>=0.16
|
|
26
27
|
Requires-Dist: tomli<3,>=2; python_version < '3.11'
|
|
27
28
|
Provides-Extra: dev
|
|
28
29
|
Requires-Dist: build<2,>=1.2; extra == 'dev'
|
|
@@ -42,7 +43,7 @@ describes a small job, the user reviews and runs it locally, and PatchShuttle
|
|
|
42
43
|
records the result for the next iteration.
|
|
43
44
|
|
|
44
45
|
> [!IMPORTANT]
|
|
45
|
-
> PatchShuttle is alpha software. Version `0.1.
|
|
46
|
+
> PatchShuttle is alpha software. Version `0.1.0a4` implements the complete
|
|
46
47
|
> local v0.1 workflow. It executes bounded read-only
|
|
47
48
|
> audits, approved patch transactions, and approved one-pass verification jobs
|
|
48
49
|
> under a project lock. Patch jobs retain backups, run controlled checks, apply
|
|
@@ -53,8 +54,9 @@ records the result for the next iteration.
|
|
|
53
54
|
> Trusted Publishing workflows are implemented. Every versioned release must
|
|
54
55
|
> pass its own local qualification, GitHub-hosted Windows/Ubuntu matrix,
|
|
55
56
|
> TestPyPI installation, production publication, and post-release smoke gates.
|
|
56
|
-
> The immutable `0.1.0a2`
|
|
57
|
-
> are retained in
|
|
57
|
+
> The immutable `0.1.0a2` and `0.1.0a3` qualification evidence, plus the
|
|
58
|
+
> separately scoped `0.1.0a2` ChatGPT end-to-end workflow, are retained in
|
|
59
|
+
> [docs/RELEASE.md](docs/RELEASE.md).
|
|
58
60
|
|
|
59
61
|
> [!NOTE]
|
|
60
62
|
> Compared with `0.1.0a2`, version `0.1.0a3` adds AI-facing planner diagnostics,
|
|
@@ -64,6 +66,16 @@ records the result for the next iteration.
|
|
|
64
66
|
> cleanup, and guarded physical-line range actions with a canonical read-only
|
|
65
67
|
> range hash.
|
|
66
68
|
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> The current development branch also contains unreleased work completed after
|
|
71
|
+
> `0.1.0a3`: `search_context`, `read_symbol`, guarded `replace_symbol`, a fixed
|
|
72
|
+
> Ruff F-only check, compact text and JSON AI log views, explicit Django warning
|
|
73
|
+
> baselines, owner-controlled project-check Python selection, evidence-only
|
|
74
|
+
> Python discovery telemetry, expanded Python secret redaction, nested
|
|
75
|
+
> dependency-environment exclusions, and bounded declaration-only
|
|
76
|
+
> `python_structure` discovery. These features are available from the source
|
|
77
|
+
> branch and are not part of the immutable `0.1.0a3` PyPI artifacts.
|
|
78
|
+
|
|
67
79
|
## Design goals
|
|
68
80
|
|
|
69
81
|
- Keep every change local and explicitly initiated by the user.
|
|
@@ -82,7 +94,7 @@ After publication, install the exact alpha release from PyPI:
|
|
|
82
94
|
```bash
|
|
83
95
|
python -m venv .venv
|
|
84
96
|
python -m pip install --upgrade pip
|
|
85
|
-
python -m pip install "patchshuttle==0.1.
|
|
97
|
+
python -m pip install "patchshuttle==0.1.0a4"
|
|
86
98
|
```
|
|
87
99
|
|
|
88
100
|
For development from a local checkout:
|
|
@@ -95,7 +107,7 @@ To enable opt-in HTML template linting in an installed release, install the
|
|
|
95
107
|
`html` extra:
|
|
96
108
|
|
|
97
109
|
```bash
|
|
98
|
-
python -m pip install "patchshuttle[html]==0.1.
|
|
110
|
+
python -m pip install "patchshuttle[html]==0.1.0a4"
|
|
99
111
|
```
|
|
100
112
|
|
|
101
113
|
For a local development checkout, install both development and HTML extras:
|
|
@@ -158,6 +170,7 @@ initializing a workspace or reading protected generated files:
|
|
|
158
170
|
patchshuttle capabilities
|
|
159
171
|
patchshuttle schema
|
|
160
172
|
patchshuttle explain replace_exact
|
|
173
|
+
patchshuttle explain replace_symbol
|
|
161
174
|
patchshuttle explain replace_range
|
|
162
175
|
patchshuttle explain hash_range
|
|
163
176
|
patchshuttle explain apply_diff
|
|
@@ -299,9 +312,14 @@ checks:
|
|
|
299
312
|
modules: [email_client.views, email_client.urls]
|
|
300
313
|
```
|
|
301
314
|
|
|
302
|
-
PatchShuttle runs the
|
|
303
|
-
internally generated import code. The
|
|
304
|
-
|
|
315
|
+
PatchShuttle runs the owner-selected project interpreter with
|
|
316
|
+
`manage.py shell -c` and internally generated import code. The optional local
|
|
317
|
+
`[execution] python_executable` value in `patches/patchshuttle.toml` may be an
|
|
318
|
+
absolute path or a path relative to the workspace root. When it is omitted,
|
|
319
|
+
PatchShuttle preserves the current `sys.executable` behavior. Jobs cannot set
|
|
320
|
+
or override the interpreter, and PatchShuttle does not auto-detect a virtual
|
|
321
|
+
environment. The YAML accepts only bounded dotted module identifiers, not an
|
|
322
|
+
arbitrary expression or shell command.
|
|
305
323
|
|
|
306
324
|
Load a job from disk with the same validation contract:
|
|
307
325
|
|
|
@@ -329,10 +347,11 @@ patchshuttle plan patches/examples/PATCH-EXAMPLE.psh.yaml
|
|
|
329
347
|
patchshuttle plan patches/examples/PATCH-EXAMPLE.psh.yaml --diff
|
|
330
348
|
```
|
|
331
349
|
|
|
332
|
-
The command displays the normalized job hash,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
350
|
+
The command displays the normalized job hash, effective project Python
|
|
351
|
+
interpreter when one is used, sequential action dispositions, files and
|
|
352
|
+
directories that would be created or modified, requested checks, Python
|
|
353
|
+
formatting scope, a per-file isort/Black decision matrix, optional HTML lint
|
|
354
|
+
scope, successful quality preflight records, protected-path result, backup
|
|
336
355
|
destination template, rollback policy, and whether later execution will
|
|
337
356
|
require confirmation.
|
|
338
357
|
`--diff` also prints a bounded unified preview of the final resolved bytes
|
|
@@ -450,12 +469,18 @@ locations, the archived job copy, initial check results, formatter results,
|
|
|
450
469
|
retained formatted-file states, final check results, audit observations, and a
|
|
451
470
|
workspace comparison where applicable.
|
|
452
471
|
|
|
453
|
-
An audit executes `tree`, `read`, literal `search`,
|
|
454
|
-
|
|
455
|
-
Traversal, file reads, match
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
472
|
+
An audit executes `tree`, `read`, literal `search`, bounded `search_context`,
|
|
473
|
+
Python `read_symbol`, `find_files`, `file_info`, SHA-256 `hash`, canonical
|
|
474
|
+
`hash_range`, `git_status`, and `environment`. Traversal, file reads, match
|
|
475
|
+
counts, and recorded output are bounded by local policy. Protected and ignored
|
|
476
|
+
paths are skipped, source content appears only when explicitly requested by a
|
|
477
|
+
content-reading audit action, and a before/after inventory verifies that the
|
|
478
|
+
audit did not modify the workspace.
|
|
479
|
+
|
|
480
|
+
`search_context` reports bounded physical-line windows around literal matches.
|
|
481
|
+
`read_symbol` parses Python source without importing it, resolves exactly one
|
|
482
|
+
class, function, method, or nested symbol, includes its decorators, and reports
|
|
483
|
+
the canonical source range and SHA-256 used by `replace_symbol`.
|
|
459
484
|
|
|
460
485
|
A verify job runs its controlled checks once, does not create a backup or run
|
|
461
486
|
formatters, and compares the workspace before and after. A successful check
|
|
@@ -464,9 +489,9 @@ project checks can have external effects, PatchShuttle reports but does not
|
|
|
464
489
|
automatically undo those changes.
|
|
465
490
|
|
|
466
491
|
A patch plan may contain `create_directory`, `create_file`, `replace_exact`,
|
|
467
|
-
`insert_before`, `insert_after`, `delete_exact`,
|
|
468
|
-
`delete_range`, `insert_at_line`, or `apply_diff` actions and
|
|
469
|
-
bytes already computed by the planner.
|
|
492
|
+
`replace_symbol`, `insert_before`, `insert_after`, `delete_exact`,
|
|
493
|
+
`replace_range`, `delete_range`, `insert_at_line`, or `apply_diff` actions and
|
|
494
|
+
applies the final bytes already computed by the planner.
|
|
470
495
|
|
|
471
496
|
The optional line-range actions are strict guarded operations for cases where
|
|
472
497
|
a current audit already established an exact physical range. Lines are 1-based
|
|
@@ -477,6 +502,13 @@ and SHA-256 over UTF-8 bytes. PatchShuttle never fuzzes, relocates, partially
|
|
|
477
502
|
applies, or automatically shifts a stale range. Use an audit `hash_range` when
|
|
478
503
|
a digest is more compact than repeating a large old block.
|
|
479
504
|
|
|
505
|
+
A `replace_symbol` action names a dotted Python symbol, supplies the canonical
|
|
506
|
+
SHA-256 returned by `read_symbol`, and provides complete replacement source.
|
|
507
|
+
Planning resolves the symbol against the current sequential simulated file,
|
|
508
|
+
rejects missing, duplicate, syntactically invalid, or stale targets, and does
|
|
509
|
+
not use fuzzy relocation or automatic line shifting. Exact desired symbol
|
|
510
|
+
content is an idempotent `NO_CHANGE`.
|
|
511
|
+
|
|
480
512
|
For a supported plan, the implemented sequence is:
|
|
481
513
|
|
|
482
514
|
1. validate the workspace lock file and acquire a non-blocking cross-platform
|
|
@@ -532,18 +564,21 @@ overwritten. Rollback validates retained originals before restoring them,
|
|
|
532
564
|
refuses to follow symbolic links or remove foreign non-empty directories, and
|
|
533
565
|
does not claim success when a tracked path cannot be restored.
|
|
534
566
|
|
|
535
|
-
The internal check runner supports
|
|
536
|
-
checks and tests, plain validated
|
|
537
|
-
imports
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
567
|
+
The internal check runner supports the fixed `ruff: {}` F-only check,
|
|
568
|
+
`compileall`, `pytest`, `unittest`, Django checks and tests, plain validated
|
|
569
|
+
module imports, Django-aware validated module imports through
|
|
570
|
+
`manage.py shell -c`, and locally configured profiles. Ruff receives only the
|
|
571
|
+
immutable ordered Python scope derived from current non-no-change patch actions;
|
|
572
|
+
a job cannot supply paths, rules, fixes, or arbitrary Ruff arguments.
|
|
573
|
+
Project checks inherit the current process environment because they execute
|
|
574
|
+
project code and PatchShuttle is not an operating-system sandbox. PatchShuttle
|
|
575
|
+
overrides `PYTHONPYCACHEPREFIX` with a fresh temporary directory for each check
|
|
576
|
+
and removes that directory afterward, keeping ordinary generated Python
|
|
577
|
+
bytecode outside the workspace. A defensive cache ledger also handles `.pyc`
|
|
578
|
+
files created inside newly added packages despite that override. Formatter
|
|
579
|
+
order is fixed to isort then Black for protocol 1; local exact-path exclusions
|
|
580
|
+
are resolved separately for each tool. Non-Python jobs skip formatting and do
|
|
581
|
+
not repeat checks. Optional djLint uses a locally selected template profile,
|
|
547
582
|
targets only changed `.html` files, never reformats them, and triggers the same
|
|
548
583
|
rollback path on failure. It reads content through stdin from an isolated
|
|
549
584
|
temporary configuration root, so project djLint configuration cannot weaken
|
|
@@ -592,9 +627,12 @@ Every job run log contains all standard sections in a fixed order, including
|
|
|
592
627
|
`LINT_HTML`, using `NOT_APPLICABLE` where a stage did not run, and ends with
|
|
593
628
|
`PATCHSHUTTLE_AI_HANDOFF`. Check and formatter output is bounded by local
|
|
594
629
|
policy, as is HTML linter output. Common password, token, API-key,
|
|
595
|
-
authorization-header,
|
|
596
|
-
|
|
597
|
-
|
|
630
|
+
authorization-header, private-key, and sensitive Python assignment shapes are
|
|
631
|
+
masked when redaction is enabled. Python assignment matching includes prefixed
|
|
632
|
+
passwords, API and access keys, secret and private keys, tokens, and one-line
|
|
633
|
+
`SECRET_KEY_FALLBACKS` collections while preserving loader calls such as
|
|
634
|
+
`config("SECRET_KEY")`. Redaction is best-effort and is not a guarantee that a
|
|
635
|
+
log contains no secrets; review a log before uploading it to any AI service.
|
|
598
636
|
|
|
599
637
|
Early `VALIDATION_FAILED` and `PLAN_FAILED` logs use a smaller fixed attempt
|
|
600
638
|
format with `SUMMARY` and `PATCHSHUTTLE_AI_HANDOFF` sections. They record no
|
|
@@ -602,16 +640,162 @@ project changes, backup, job archive, or registry update. An explicitly
|
|
|
602
640
|
declined reviewed plan continues to use the full job log and exact failed-job
|
|
603
641
|
archive with result `USER_DECLINED`.
|
|
604
642
|
|
|
605
|
-
|
|
643
|
+
Django system-check warnings can use an explicit project-local baseline:
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
patchshuttle warnings
|
|
647
|
+
patchshuttle warnings --add urls.W005
|
|
648
|
+
patchshuttle warnings --remove urls.W005
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
Only explicit W-class IDs are accepted. A `django_check` retains its normal
|
|
652
|
+
exit code and full log output while adding `known_warnings`, `new_warnings`,
|
|
653
|
+
and complete new-warning details. If captured output is truncated,
|
|
654
|
+
classification is reported as incomplete. Existing workspaces without the
|
|
655
|
+
protected baseline file start with an empty baseline; `patchshuttle init`
|
|
656
|
+
creates the missing scaffold file without overwriting existing state.
|
|
657
|
+
Find or compactly render the latest upload-friendly log:
|
|
606
658
|
|
|
607
659
|
```bash
|
|
608
660
|
patchshuttle logs --last
|
|
661
|
+
patchshuttle logs --last --ai
|
|
662
|
+
patchshuttle logs --last --ai-json
|
|
609
663
|
```
|
|
610
664
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
665
|
+
The default prints the path. `--ai` prints a bounded deterministic text view,
|
|
666
|
+
while `--ai-json` prints the same selected data as compact JSON. These modes
|
|
667
|
+
read the already stored log, preserve it unchanged, and never execute project
|
|
668
|
+
code. They are mutually exclusive and retain useful audit outputs and failed
|
|
669
|
+
check diagnostics within explicit bounds.
|
|
670
|
+
|
|
671
|
+
Run and early validation/planning failure logs also expose
|
|
672
|
+
`PYTHON_DISCOVERY_EVALUATION`. The section records only current-job evidence:
|
|
673
|
+
explicit Python paths, executed audit action counts and bounded output size
|
|
674
|
+
before whole-log redaction,
|
|
675
|
+
declared text/symbol/line targeting, and relevant failure signals.
|
|
676
|
+
`index_assessment: NOT_EVALUATED` is intentional: the report neither estimates
|
|
677
|
+
AI token savings nor decides whether a project symbol index is needed.
|
|
678
|
+
|
|
679
|
+
### Discover Python structure before targeted reads
|
|
680
|
+
|
|
681
|
+
The read-only `python_structure` audit action collects a bounded declaration
|
|
682
|
+
map before targeted reads. Start with the narrowest useful directory or one
|
|
683
|
+
`.py` file because a broad package can produce a large audit result.
|
|
684
|
+
|
|
685
|
+
A complete YAML audit job looks like this:
|
|
686
|
+
|
|
687
|
+
```yaml
|
|
688
|
+
protocol: 1
|
|
689
|
+
project_id: PSH-0123456789ABCDEF
|
|
690
|
+
id: AUDIT-PYTHON-STRUCTURE-001
|
|
691
|
+
kind: audit
|
|
692
|
+
actions:
|
|
693
|
+
- python_structure:
|
|
694
|
+
path: src/example
|
|
695
|
+
max_files: 50
|
|
696
|
+
max_symbols: 400
|
|
697
|
+
compact: true
|
|
698
|
+
checks: []
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
`path` defaults to `.`, `max_files` defaults to `300`, `max_symbols`
|
|
702
|
+
defaults to `2000`, and `compact` defaults to `false`. A file target must end
|
|
703
|
+
in `.py`. Directory traversal respects the workspace's protected and ignored
|
|
704
|
+
paths. The standard-library AST is used without importing or executing project
|
|
705
|
+
code. Use `compact: true` for a navigational overview and omit it when detailed
|
|
706
|
+
imports, parameters, decorators, and bases are required.
|
|
707
|
+
|
|
708
|
+
Compact output begins with the same collection counts, parse errors, and limit
|
|
709
|
+
signals as full output, followed by per-file records containing only counts and
|
|
710
|
+
navigational symbol metadata:
|
|
711
|
+
|
|
712
|
+
```text
|
|
713
|
+
schema: patchshuttle.python_structure_collection.compact.v1
|
|
714
|
+
path: src/example
|
|
715
|
+
glob: *.py
|
|
716
|
+
files_considered: 1
|
|
717
|
+
files_parsed: 1
|
|
718
|
+
parse_errors: 0
|
|
719
|
+
imports_reported: 3
|
|
720
|
+
symbols_available: 2
|
|
721
|
+
symbols_reported: 2
|
|
722
|
+
file_limit_reached: false
|
|
723
|
+
symbol_limit_reached: false
|
|
724
|
+
|
|
725
|
+
schema: patchshuttle.python_structure.compact.v1
|
|
726
|
+
file: "src/example/service.py"
|
|
727
|
+
imports: 3
|
|
728
|
+
symbols: 2
|
|
729
|
+
symbol: {"kind":"class","lines":[10,42],"qualified_name":"Service"}
|
|
730
|
+
symbol: {"kind":"method","lines":[14,31],"qualified_name":"Service.run"}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
With `compact: false`, the existing
|
|
734
|
+
`patchshuttle.python_structure_collection.v1` and
|
|
735
|
+
`patchshuttle.python_structure.v1` schemas remain unchanged and additionally
|
|
736
|
+
include top-level import records, parameters, decorators, and bases.
|
|
737
|
+
|
|
738
|
+
Use the reported qualified name for a smaller follow-up audit:
|
|
739
|
+
|
|
740
|
+
```yaml
|
|
741
|
+
actions:
|
|
742
|
+
- read_symbol:
|
|
743
|
+
path: src/example/service.py
|
|
744
|
+
symbol: Service.run
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
If a change is needed, copy the canonical SHA-256 returned by `read_symbol`
|
|
748
|
+
into a guarded patch action:
|
|
749
|
+
|
|
750
|
+
```yaml
|
|
751
|
+
actions:
|
|
752
|
+
- replace_symbol:
|
|
753
|
+
path: src/example/service.py
|
|
754
|
+
symbol: Service.run
|
|
755
|
+
expected_sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
|
756
|
+
new_content: |
|
|
757
|
+
def run(self, value):
|
|
758
|
+
return value
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
The same audit can be constructed through the public Python adapter:
|
|
762
|
+
|
|
763
|
+
```python
|
|
764
|
+
from patchshuttle import Job
|
|
765
|
+
from patchshuttle.actions import python_structure
|
|
766
|
+
|
|
767
|
+
job = Job(
|
|
768
|
+
protocol=1,
|
|
769
|
+
project_id="PSH-0123456789ABCDEF",
|
|
770
|
+
id="AUDIT-PYTHON-STRUCTURE-001",
|
|
771
|
+
kind="audit",
|
|
772
|
+
actions=[
|
|
773
|
+
python_structure(
|
|
774
|
+
"src/example", max_files=50, max_symbols=400, compact=True
|
|
775
|
+
)
|
|
776
|
+
],
|
|
777
|
+
)
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
Full `python_structure` output reports declarations, top-level imports,
|
|
781
|
+
parameters, decorators, bases, source ranges, parse errors, and explicit limit
|
|
782
|
+
signals. Compact output retains file and symbol counts, symbol kinds, qualified
|
|
783
|
+
names, ranges, parse errors, and limit signals. Both modes exclude source values,
|
|
784
|
+
calls, references, inferred types, caching, persistence, and automatic patch
|
|
785
|
+
scope.
|
|
786
|
+
|
|
787
|
+
The same section reports aggregate Python file/search matches, whether file
|
|
788
|
+
discovery or searches reached their declared result bounds, and total duration
|
|
789
|
+
of executed Python-targeted audit actions. Newly initialized workspaces ignore
|
|
790
|
+
and protect conventional `.venv`, `venv`, and `node_modules` trees at any
|
|
791
|
+
depth. Existing `patches/patchshuttle.toml` files are never rewritten by
|
|
792
|
+
`init`; owners must add nested environment patterns and project-specific
|
|
793
|
+
backup paths to `project.ignored_paths` when needed.
|
|
794
|
+
|
|
795
|
+
The command selects the newest recorded run, snapshot, handoff, or
|
|
796
|
+
failure-attempt log. Commands that intentionally produce no artifact,
|
|
797
|
+
including successful `validate`, successful `plan`, `version`,
|
|
798
|
+
`capabilities`, `schema`, and `explain`, do not replace it.
|
|
615
799
|
|
|
616
800
|
Inspect all registered jobs or one job ID:
|
|
617
801
|
|
|
@@ -687,17 +871,64 @@ python -m coverage report --fail-under=100
|
|
|
687
871
|
python -m build
|
|
688
872
|
python -m twine check dist/*
|
|
689
873
|
python tools/release_checks.py dist
|
|
690
|
-
python tools/wheel_smoke.py dist/patchshuttle-0.1.
|
|
874
|
+
python tools/wheel_smoke.py dist/patchshuttle-0.1.0a4-py3-none-any.whl --version 0.1.0a4
|
|
691
875
|
```
|
|
692
876
|
|
|
693
|
-
The `0.1.0a2` alpha
|
|
694
|
-
compatibility matrix, TestPyPI qualification, production PyPI Trusted
|
|
695
|
-
Publishing, and a clean post-release installation.
|
|
696
|
-
links
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
877
|
+
The `0.1.0a2` and `0.1.0a3` alpha releases each passed the required Ubuntu and
|
|
878
|
+
Windows compatibility matrix, TestPyPI qualification, production PyPI Trusted
|
|
879
|
+
Publishing, and a clean post-release installation. Their exact release and
|
|
880
|
+
workflow links and artifact hashes, together with the separately scoped
|
|
881
|
+
`0.1.0a2` ChatGPT end-to-end evidence, are recorded in
|
|
882
|
+
[docs/RELEASE.md](docs/RELEASE.md). Follow that guide in order for every future
|
|
883
|
+
release and append separate immutable evidence after each gate completes.
|
|
884
|
+
Rerun CI after every release-candidate change.
|
|
885
|
+
|
|
886
|
+
## Python architecture policy
|
|
887
|
+
|
|
888
|
+
PatchShuttle can stop an AI-generated patch from making an already crowded Python
|
|
889
|
+
codebase worse. The policy is local owner configuration, not a job option, and is
|
|
890
|
+
enabled by default for the fixed `modular-monolith` / `package-by-feature`
|
|
891
|
+
profile in `ratchet` mode.
|
|
892
|
+
|
|
893
|
+
```toml
|
|
894
|
+
[architecture]
|
|
895
|
+
enabled = true
|
|
896
|
+
profile = "modular-monolith"
|
|
897
|
+
organization = "package-by-feature"
|
|
898
|
+
mode = "ratchet"
|
|
899
|
+
exclude = ["**/migrations/**", "**/generated/**"]
|
|
900
|
+
max_report_items = 50
|
|
901
|
+
|
|
902
|
+
[architecture.module]
|
|
903
|
+
warning_lines = 500
|
|
904
|
+
max_lines = 1000
|
|
905
|
+
|
|
906
|
+
[architecture.package]
|
|
907
|
+
warning_python_files = 15
|
|
908
|
+
max_python_files = 25
|
|
909
|
+
|
|
910
|
+
[architecture.patch]
|
|
911
|
+
warning_new_python_files = 5
|
|
912
|
+
max_new_python_files = 10
|
|
913
|
+
warning_new_packages = 1
|
|
914
|
+
max_new_packages = 3
|
|
915
|
+
```
|
|
700
916
|
|
|
917
|
+
The planner evaluates its in-memory result before touching the workspace. A file
|
|
918
|
+
already above a limit may stay the same size or shrink; making it larger is a new
|
|
919
|
+
regression and is blocked at the hard limit. The same rule applies to direct
|
|
920
|
+
Python-file counts in touched directories. Patch-wide file and package budgets
|
|
921
|
+
catch the kind of broad root-level file growth that is difficult to review.
|
|
922
|
+
|
|
923
|
+
Plans and stored logs expose the profile, status, measured counts, bounded
|
|
924
|
+
findings, and whether the report was truncated. `ARCH001`/`ARCH002` cover module
|
|
925
|
+
size, `ARCH010`/`ARCH011` package size, and `ARCH020`/`ARCH021` patch growth.
|
|
926
|
+
Warnings remain visible but do not block execution; errors fail planning before
|
|
927
|
+
confirmation, backup, or project checks.
|
|
928
|
+
|
|
929
|
+
This is deliberately a structural guard. It does not infer feature boundaries,
|
|
930
|
+
build dependency or call graphs, detect cycles, judge semantic responsibility,
|
|
931
|
+
reorganize files, or change the patch scope selected by the AI.
|
|
701
932
|
## Manual workflow
|
|
702
933
|
|
|
703
934
|
The implemented local cycle is:
|