Crane Migration: Python to Go -- Full APM CLI Rewrite
- Lenguaje dominante
- Python
- Estrellas
- 5
- Forks
- 2
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Descripción
---
schedule: every 5m
strategy: greenfield
source-language: python
target-languages: [go]
target-metric: 1.0
metric_direction: higher
completion-framework: deletion-grade-golden-fixture-cutover-v3
---
# APM CLI: Python to Go -- Full Rewrite
Complete rewrite of the APM CLI from Python to Go. The Python implementation
stays in place as the authoritative reference until the Go CLI proves complete
black-box equivalence. The end state is 100% Go for the shipping `apm` command,
but Python must not be removed until the deletion-grade parity gates below pass.
> **Current guidance supersedes prior completion claims.**
>
> Previous Crane iterations reported `migration_score: 1.0` and marked this
> migration complete, but that was not deletion-grade proof. The current Go CLI
> still contains simplified command bodies and approved parity exceptions. This
> issue is not complete until the stricter framework in
> https://github.com/githubnext/apm/issues/96 is implemented and all gates here
> are green.
## Source
- **Language**: Python 3.10+ with Click/Rich
- **Paths**:
- `src/apm_cli/` -- authoritative Python implementation
- `tests/` -- Python reference test suite
- **Role during migration**: runnable oracle for CLI behavior, filesystem
mutations, generated artifacts, lockfiles, config, cache, and benchmark
comparison.
## Target
- **Language**: Go
- **Paths**:
- `cmd/apm/` -- CLI entry point
- `internal/` -- internal packages mirroring Python behavior
- `pkg/` -- public library APIs if needed
- **Bridge**: none for the final shipping CLI. Temporary test-time use of
Python is only for parity verification.
## Completion Definition
`migration_score: 1.0` must mean the Python CLI can be removed from the
shipping path. It is not enough for `TestParity*` tests to pass, for help text
to match, or for Go command stubs to return successful exit codes.
Crane may mark this migration complete only when every gate is true:
1. `python_reference_required = true`
2. `surface_parity = 100%`
3. `help_parity = 100%`
4. `functional_contracts = 100%`
5. `state_diff_contracts = 100%`
6. `known_exceptions = 0`
7. `go_tests = pass`
8. `python_tests = pass`
9. `benchmarks = pass`
10. `golden_fixture_corpus = present`
11. `all_go_golden_tests = pass`
12. `no_python_runtime_dependency = pass`
13. release/install/cutover path ships the Go CLI or documents a temporary shim
with explicit removal criteria.
If any gate is false, the score must be less than `1.0`.
## Required Crane Framework Update
Implement the framework described in #96 before accepting further completion
claims:
- Missing `APM_PYTHON_BIN` is a hard failure, never a warning or vacuous pass.
- Empty or cached Go test event streams must fail scoring.
- The score script must not derive completion from test names alone.
- "Approved exceptions", "simplified help", and "Go is more lenient" logs are
allowed only as temporary progress notes; final completion requires zero.
- Every PR commit on a Crane branch must run parity and benchmarks, then post
the benchmark and parity summary back to the PR.
## Surface Parity Gate
Generate a CLI inventory for both Python and Go, then diff them.
The inventory must include:
- commands and subcommands
- aliases, including hidden aliases
- positional arguments
- options and flags
- defaults
- required/repeated/multiple-value behavior
- hidden/deprecated status
- invalid usage behavior
Fail on any missing or mismatched public behavior unless the issue explicitly
records a temporary non-cutover exception.
## Help And Usage Gate
For every command and subcommand, compare Python and Go:
- `apm --help`
- `apm --help`
- `apm --help`
- invalid option
- missing required argument
- unknown subcommand
Compare exit code, stdout, and stderr after only deterministic normalization.
Final cutover requires no help truncation exceptions.
## Functional State-Diff Gate
Crane must use a black-box contract harness:
1. Create two identical temp homes and repos.
2. Run Python in one.
3. Run Go in the other.
4. Compare observable results.
Compare:
- exit code
- stdout/stderr
- files created, removed, and modified
- file contents
- `apm.yml`
- `apm.lock.yaml`
- `.apm/` package directories
- managed-file manifests
- generated `AGENTS.md`, `CLAUDE.md`, Copilot, Codex, Gemini, Cursor,
Windsurf, and OpenCode files
- marketplace config
- user config
- cache layout where deterministic
- audit artifacts such as JSON, SARIF, and markdown
Mutating commands do not count as complete until their filesystem and config
effects match Python, not just their exit code.
## Required Command Contract Matrix
Crane must cover the full supported Python CLI surface, including:
- `init`: defaults, explicit project name, explicit targets, plugin mode,
marketplace mode, existing `apm.yml`, non-interactive behavior.
- `compile`: all canonical targets, `--target`, `--all`, `--clean`,
`--validate`, `--dry-run`, generated file parity, orphan cleanup.
- `install`: local bundle, local plugin directory, local skill bundle, fixture
git repo, transitive deps, skill subset, MCP deps, global scope, `--frozen`,
policy, collisions, `--force`, lockfile writes, managed-file writes.
- `uninstall`: direct deps, transitive orphan cleanup, global scope, dry-run,
stale integrated files, manifest mutation.
- `update` and `deps update`: no-op, changed refs, selected packages,
target-specific update, lockfile mutation, dry-run.
- `deps`: list, tree, info, clean, global scope, insecure-only views.
- `pack` and `unpack`: bundle contents, marketplace artifacts, manifest fields,
hidden-character audit, JSON output, dry-run, `--force`, `--skip-verify`.
- `marketplace`: add/list/remove/update/browse/validate,
init/check/outdated/doctor/publish dry-run/migrate, package add/set/remove,
config mutation, fixture refs.
- `audit`: package scan, arbitrary file scan, hidden Unicode findings, `--strip`,
`--dry-run`, text/json/sarif/markdown, `--ci`,
policy/no-policy/no-cache/no-drift.
- `policy`: status, check, local policy, inherited policy, no-cache, output
format parity.
- `mcp`: list, search, inspect/show, install, fixture registry, client config
mutation.
- `run`, `preview`, and `list`: scripts, params, missing script, default script,
prompt output parity, verbose output.
- `config`: get, set, unset, config path handling, missing config, invalid
key/value.
- `runtime`: list, setup, remove, status, fixture runtime adapters.
- `targets`: auto-detection, explicit `apm.yml` targets, `--json`, `--all`,
ambiguous/missing target behavior.
- `view`: installed package metadata, missing package, versions using fixture
refs, global scope.
- `cache`: info, clean, prune, cache path/env behavior.
- `prune`: no-op, undeclared package removal, dry-run, integration cleanup.
- `outdated`: missing lockfile, no outdated deps, outdated dependency fixture,
prerelease behavior where applicable.
- `self-update`: `--check`, platform-specific messaging, no real install or
network in parity tests.
## Fixture Policy
Parity tests must not depend on live GitHub, registries, or external services.
Use local git repos, local tarballs, local fixture registries, local HTTP
fixture servers, fake homes, fake config paths, and fake cache roots.
Real-network smoke tests may exist, but they are not cutover evidence.
## Golden Fixture Cutover Gate
Final completion requires a committed, versioned golden fixture corpus captured
from the last passing Python-reference parity run. The corpus must cover the
full command contract matrix above, including CLI inventory, help and usage
output, error output, exit codes, generated files, lockfiles, config files,
managed-file manifests, cache/config layout where deterministic, and audit
artifacts.
Crane may not mark this migration complete until an all-Go replay proves the
Go CLI against those fixtures with no Python runtime available. The completion
run must include a hard no-Python check, such as removing or hiding `src/apm_cli`,
clearing `APM_PYTHON_BIN`, building `cmd/apm`, and running the golden replay
with only the Go binary and checked-in fixtures as the oracle.
A Python-vs-Go parity pass is necessary to create or refresh the corpus, but it
is not sufficient final completion evidence. The final gate is Go-vs-golden,
not Go-vs-live-Python.
## Python Tests
Keep running the original Python unit suite while Python exists. Python tests
prove the reference still works; they do not prove Go parity. Cutover readiness
comes from black-box contracts that both Python and Go satisfy.
## Benchmarks
Benchmarks must run on every Crane PR commit and post results to the PR. A
benchmark pass is required for final completion, but speed cannot compensate for
missing parity.
## Crane Operating Rule
For every accepted iteration:
1. Pick one Python CLI behavior.
2. Add a black-box Python-vs-Go contract test for it.
3. See the test fail for Go.
4. Implement Go behavior.
5. Confirm the contract passes.
6. Update the PR/issue report with the exact behavior now covered and the
remaining gates still false.
No final cutover exceptions. No vacuous parity. No deleting Python until the
deletion-grade gate is green.
## Verification
Minimum local checks:
```bash
uv sync --extra dev
go test ./...
APM_PYTHON_BIN="$PWD/.venv/bin/apm" go test -count=1 ./...
APM_PYTHON_BIN="$PWD/.venv/bin/apm" go test -count=1 -json ./... | go run .crane/scripts/score.go
python scripts/ci/migration_cli_benchmark.py \
--python-bin "$PWD/.venv/bin/apm" \
--go-bin /tmp/apm-go \
--json-out /tmp/migration-cli-benchmark.json \
--markdown-out /tmp/migration-cli-benchmark.md
```
The exact harness can be richer, but final completion must execute both CLIs
and compare observable behavior. A skipped Python invocation, a Go-only unit
test, or a help-only fixture is not completion evidence.
## Out Of Scope During Migration
- Do not delete `src/apm_cli/` until all deletion-grade gates pass.
- Do not remove the existing Python tests while they are still the reference.
- Do not claim completion from benchmark speed alone.
- Do not rely on live external services for parity evidence.
Guía de contribución
Línea de trabajo
Start with src/apm_cli/ and the Python tests as the reference, then inspect cmd/apm/, internal/, and .crane/scripts/score.go alongside issue #96. Run the listed Go and Python parity checks and benchmark command to establish the current gaps. Done means the deletion-grade gates pass, including golden-fixture replay, zero known exceptions, and no Python runtime dependency.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- go, python
- Área
- cli, developer-experience
- Tipo de issue
- Refactorización
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Tranquilo
- Claridad
- Necesita aclaración
- Aptitud para principiantes
- 15/100