scaffold-ca-python 0.2.0__tar.gz → 0.2.1__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.
- scaffold_ca_python-0.2.1/.release-please-manifest.json +3 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/memory/constitution.md +25 -2
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/CHANGELOG.md +7 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/PKG-INFO +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/pyproject.toml +7 -1
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/checklists/requirements.md +35 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/contracts/cli-behavior.md +49 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/contracts/factory-extension.md +46 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/data-model.md +112 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/plan.md +189 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/quickstart.md +93 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/research.md +167 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/spec.md +241 -0
- scaffold_ca_python-0.2.1/specs/022-solid-code-cleanup/tasks.md +573 -0
- scaffold_ca_python-0.2.1/specs/023-error-hints/spec.md +25 -0
- scaffold_ca_python-0.2.1/specs/024-typed-template-contexts/spec.md +31 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/_entry_point_rules.py +53 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/_shared.py +109 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/add_mcp_tool.py +200 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/delete_module.py +110 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_driven_adapter.py +124 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_entry_point.py +249 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_helper.py +78 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_model.py +77 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_pipeline.py +114 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_project.py +159 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/commands/generate_use_case.py +83 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/commands/update_project.py +19 -32
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/commands/validate_structure.py +8 -12
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/file_writer.py +55 -70
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/mcp_tool_spec.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/module_builder.py +13 -6
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/core/module_locator.py +45 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/name_utils.py +1 -6
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/core/openapi_routes.py +34 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/project_detector.py +14 -9
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/structure_validator.py +66 -59
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/template_renderer.py +1 -9
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/driven_adapters/__init__.py +14 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/driven_adapters/base.py +23 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/driven_adapters/da_generic.py +3 -3
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/driven_adapters/da_rest_consumer.py +4 -3
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/driven_adapters/da_secrets.py +4 -3
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/entry_points/__init__.py +16 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/entry_points/base.py +63 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/entry_points/ep_agent.py +13 -4
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/entry_points/ep_generic.py +13 -4
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/entry_points/ep_mcp.py +15 -8
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/entry_points/ep_restapi.py +34 -6
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/pipelines/__init__.py +20 -0
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/pipelines/pipeline_factory.py +27 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/simple/delete_module_factory.py +10 -11
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/simple/helper_factory.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/simple/model_factory.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/simple/use_case_factory.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/models/context.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/models/layer.py +1 -1
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/models/options.py +53 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/models/violation.py +1 -1
- scaffold_ca_python-0.2.1/src/scaffold_ca_python/templates/project/package_init.py.jinja2 +1 -0
- scaffold_ca_python-0.2.1/tests/commands/test_behavior_contract.py +198 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_pipeline.py +46 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_project.py +32 -0
- scaffold_ca_python-0.2.1/tests/commands/test_shared.py +129 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_file_writer.py +36 -1
- scaffold_ca_python-0.2.1/tests/core/test_module_locator.py +62 -0
- scaffold_ca_python-0.2.1/tests/core/test_openapi_routes.py +53 -0
- scaffold_ca_python-0.2.1/tests/core/test_project_context.py +98 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_pyproject_writer.py +1 -1
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/entry_points/test_ep_mcp.py +2 -2
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/entry_points/test_ep_restapi.py +1 -3
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/test_dry_run_parity.py +4 -3
- scaffold_ca_python-0.2.1/tests/factory/test_extensibility.py +94 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/test_module_builder.py +87 -0
- scaffold_ca_python-0.2.1/tests/factory/test_registry.py +114 -0
- scaffold_ca_python-0.2.1/tests/models/test_options.py +65 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_project_templates.py +17 -0
- scaffold_ca_python-0.2.1/tests/test_source_hygiene.py +34 -0
- scaffold_ca_python-0.2.0/.release-please-manifest.json +0 -3
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/delete_module.py +0 -201
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_driven_adapter.py +0 -187
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_entry_point.py +0 -593
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_helper.py +0 -135
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_model.py +0 -134
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_pipeline.py +0 -158
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_project.py +0 -189
- scaffold_ca_python-0.2.0/src/scaffold_ca_python/commands/generate_use_case.py +0 -138
- scaffold_ca_python-0.2.0/tests/factory/test_extensibility.py +0 -46
- scaffold_ca_python-0.2.0/tests/factory/test_registry.py +0 -54
- scaffold_ca_python-0.2.0/tests/templates/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/copilot-instructions.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/issue_template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/pull_request_template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-analyze/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-checklist/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-clarify/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-constitution/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-converge/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-implement/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-plan/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-specify/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-tasks/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/skills/speckit-taskstoissues/SKILL.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/build.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/dependency-review.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/publish.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/release-please.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/scorecards-analysis.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.github/workflows/secret-scanner.yml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.gitignore +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.pre-commit-config.yaml +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.python-version +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/.gitignore +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/init-options.json +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/integration.json +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/integrations/copilot.manifest.json +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/integrations/speckit.manifest.json +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/common.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/resolve-template.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/setup-plan.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/setup-tasks.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/agent-file-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/checklist-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/constitution-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/plan-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/spec-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/.specify/templates/tasks-template.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/LICENSE +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/README.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/SECURITY.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/release-please-config.json +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/ca.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/dm.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/gda.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/gep.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/gh.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/gm.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/gpipe.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/guc.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/up.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/contracts/vs.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/004-scaffold-ca-python-cli/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/006-ca-scaffold-enhancements/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/006-ca-scaffold-enhancements/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/006-ca-scaffold-enhancements/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/006-ca-scaffold-enhancements/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/contracts/clean-architecture.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/contracts/gda.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/contracts/gep.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/contracts/gpipe.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/007-cli-usability-enhancements/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/contracts/gep.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/008-fastapi-entrypoint-baseline/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/contracts/gep-restapi.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/009-app-factory-split/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/011-fix-restapi-cleanup/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/012-fix-restapi-test-templates/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/014-tests-in-src/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/015-factory-builder-refactor/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/016-dedup-command-aliases/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/contracts/name-validation.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/017-pep8-naming-validation/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/contracts/gep-mcp.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/019-mcp-entry-point-restructure/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/contracts/readme-outline.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/020-pypi-publish-readme/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/checklists/requirements.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/contracts/gep-add-tool.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/data-model.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/plan.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/quickstart.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/research.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/spec.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/specs/021-mcp-add-tool/tasks.md +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/cli.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/commands/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/core/pyproject_writer.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/factory/__init__.py +0 -0
- {scaffold_ca_python-0.2.0/src/scaffold_ca_python/factory/driven_adapters → scaffold_ca_python-0.2.1/src/scaffold_ca_python/factory/simple}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0/src/scaffold_ca_python/factory/entry_points → scaffold_ca_python-0.2.1/src/scaffold_ca_python/models}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/models/file_operation.py +0 -0
- {scaffold_ca_python-0.2.0/src/scaffold_ca_python/factory/simple → scaffold_ca_python-0.2.1/src/scaffold_ca_python/templates}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/generic/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/generic/adapter.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/generic/test_adapter.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/rest_consumer.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/rest_consumer/test_rest_consumer.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/secrets/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/secrets/secrets_adapter.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/driven_adapter/secrets/test_secrets_adapter.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/agent/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/agent/agent.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/agent/card.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/agent/entrypoint_main.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/agent/test_agent.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/generic/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/generic/entrypoint_main.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/generic/handler.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/generic/test_handler.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/app.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/prompts.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/resources.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/server.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/test_app.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/test_prompts.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/test_resources.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/test_tool_stub.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/test_tools.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/tool_stub.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/mcp/tools.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/app.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/exception_handler.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/health.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/rest_controller.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/server.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/test_app.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/test_exception_handler.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/test_rest_controller.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/entry_point/restapi/test_server.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/helper/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/helper/helper.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/helper/test_helper.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/model/model.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/model/test_model.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/pipeline/azure/azure_pipelines.yml.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/pipeline/github/ci.yml.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/README.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/__init__.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/config.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/container.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/driven_adapters_container.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/resource_container.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/application/config/usecases_container.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/dockerfile.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/dockerignore.jinja2 +0 -0
- /scaffold_ca_python-0.2.0/src/scaffold_ca_python/models/__init__.py → /scaffold_ca_python-0.2.1/src/scaffold_ca_python/templates/project/empty.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/gitignore.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/layer_init.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/main.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/mypy_ini.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/pyproject_toml.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/project/python_version.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/use_case/test_use_case.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/src/scaffold_ca_python/templates/use_case/use_case.py.jinja2 +0 -0
- {scaffold_ca_python-0.2.0/src/scaffold_ca_python/templates → scaffold_ca_python-0.2.1/tests}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0/tests → scaffold_ca_python-0.2.1/tests/commands}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_cli.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_delete_module.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_dry_run_checksum.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_driven_adapter.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_entry_point.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_helper.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_model.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_generate_use_case.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_performance.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_update_project.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_validate_structure.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/commands/test_workflow.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/conftest.py +0 -0
- {scaffold_ca_python-0.2.0/tests/commands → scaffold_ca_python-0.2.1/tests/core}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_mcp_tool_spec.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_name_utils.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_project_detector.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_structure_validator.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/core/test_template_renderer.py +0 -0
- {scaffold_ca_python-0.2.0/tests/core → scaffold_ca_python-0.2.1/tests/factory}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0/tests/factory → scaffold_ca_python-0.2.1/tests/factory/driven_adapters}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/driven_adapters/test_da_generic.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/driven_adapters/test_da_rest_consumer.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/driven_adapters/test_da_secrets.py +0 -0
- {scaffold_ca_python-0.2.0/tests/factory/driven_adapters → scaffold_ca_python-0.2.1/tests/factory/entry_points}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/entry_points/test_ep_agent.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/entry_points/test_ep_generic.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/fixtures/dry_run_baseline.json +0 -0
- {scaffold_ca_python-0.2.0/tests/factory/entry_points → scaffold_ca_python-0.2.1/tests/factory/simple}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/simple/test_delete_module_factory.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/simple/test_helper_factory.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/simple/test_model_factory.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/factory/simple/test_use_case_factory.py +0 -0
- {scaffold_ca_python-0.2.0/tests/factory/simple → scaffold_ca_python-0.2.1/tests/models}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/models/test_context.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/models/test_file_operation.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/models/test_layer.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/models/test_violation.py +0 -0
- {scaffold_ca_python-0.2.0/tests/models → scaffold_ca_python-0.2.1/tests/templates}/__init__.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_di_config_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_docker_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_driven_adapter_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_entry_point_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_entrypoint_main_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_helper_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_model_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_pipeline_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/tests/templates/test_use_case_templates.py +0 -0
- {scaffold_ca_python-0.2.0 → scaffold_ca_python-0.2.1}/uv.lock +0 -0
|
@@ -34,6 +34,19 @@ None — all placeholders resolved.
|
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
+
### Amendment v2.1.0 (2026-10-22) — MINOR
|
|
38
|
+
**Type**: MINOR — new governance clause (materially expanded guidance).
|
|
39
|
+
|
|
40
|
+
**Changes**:
|
|
41
|
+
- Governance: added "Pre-existing violations" clause. A feature MAY keep a violation that
|
|
42
|
+
already existed on `main` if the plan documents it as pre-existing debt in Complexity
|
|
43
|
+
Tracking and names a numbered follow-up feature whose spec directory exists before merge.
|
|
44
|
+
New code introduced by a feature MUST still comply with every principle.
|
|
45
|
+
|
|
46
|
+
**Templates updated**: None. First applied by `specs/022-solid-code-cleanup/plan.md`.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
37
50
|
### Amendment v2.0.3 (2026-04-10) — PATCH
|
|
38
51
|
**Type**: PATCH — branch naming exception; no semantic change to other governance rules.
|
|
39
52
|
|
|
@@ -75,7 +88,7 @@ or artifact structure was affected.
|
|
|
75
88
|
|
|
76
89
|
# scaffold-ca-python Constitution
|
|
77
90
|
|
|
78
|
-
**Version**: 2.0
|
|
91
|
+
**Version**: 2.1.0 | **Ratified**: 2026-03-25 | **Last amended**: 2026-10-22
|
|
79
92
|
|
|
80
93
|
## Core Principles
|
|
81
94
|
|
|
@@ -255,7 +268,17 @@ dependencies listed in Principle III, installed via `uv` at generation time.
|
|
|
255
268
|
- **PATCH**: clarifications, wording improvements, or typo fixes with no semantic change.
|
|
256
269
|
- All pull requests MUST include a Constitution Check section in their plan document
|
|
257
270
|
verifying compliance with every applicable principle.
|
|
271
|
+
- **Pre-existing violations**: A feature MAY leave a violation of a principle in place only if
|
|
272
|
+
all of the following hold:
|
|
273
|
+
1. The violation existed on `main` before the feature branch was created (it is not
|
|
274
|
+
introduced or worsened by the feature).
|
|
275
|
+
2. The plan's Constitution Check marks the principle as "⚠️ pre-existing debt" and the
|
|
276
|
+
Complexity Tracking table records the violation, its measured extent, and why fixing it
|
|
277
|
+
is out of scope.
|
|
278
|
+
3. A numbered follow-up feature (e.g. `023-error-hints`) is named in Complexity Tracking
|
|
279
|
+
and its spec directory is created before the feature is merged.
|
|
280
|
+
New code introduced by the feature MUST comply with every principle.
|
|
258
281
|
- Compliance reviews MUST occur at the start of each new feature branch and before
|
|
259
282
|
merging to `main`.
|
|
260
283
|
|
|
261
|
-
**Version**: 2.0
|
|
284
|
+
**Version**: 2.1.0 | **Ratified**: 2026-03-25 | **Last Amended**: 2026-10-22
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1](https://github.com/bancolombia/scaffold-clean-architecture-py/compare/v0.2.0...v0.2.1) (2026-10-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **refactor:** simplify scaffolder internals and improve extensibility ([8cb0a96](https://github.com/bancolombia/scaffold-clean-architecture-py/commit/8cb0a967d8e00dc5f995e8178d537a3fe5bb7865))
|
|
9
|
+
|
|
3
10
|
## [0.2.0](https://github.com/bancolombia/scaffold-clean-architecture-py/compare/v0.1.4...v0.2.0) (2026-10-19)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scaffold-ca-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Scaffolder to generate Clean Architecture apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/bancolombia/scaffold-clean-architecture-py
|
|
6
6
|
Project-URL: Repository, https://github.com/bancolombia/scaffold-clean-architecture-py
|
|
@@ -75,7 +75,13 @@ line-length = 120
|
|
|
75
75
|
target-version = "py313"
|
|
76
76
|
|
|
77
77
|
[tool.ruff.lint]
|
|
78
|
-
select = ["E", "F", "I", "UP", "ANN"]
|
|
78
|
+
select = ["E", "F", "I", "UP", "ANN", "B", "SIM", "C90"]
|
|
79
|
+
|
|
80
|
+
[tool.ruff.lint.mccabe]
|
|
81
|
+
max-complexity = 10
|
|
82
|
+
|
|
83
|
+
# Temporary: removed by the end of feature 022.
|
|
84
|
+
[tool.ruff.lint.per-file-ignores]
|
|
79
85
|
|
|
80
86
|
[tool.mypy]
|
|
81
87
|
strict = true
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Specification Quality Checklist: SOLID refactor and comment cleanup
|
|
2
|
+
|
|
3
|
+
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
|
4
|
+
**Created**: 2026-10-22
|
|
5
|
+
**Feature**: [spec.md](../spec.md)
|
|
6
|
+
|
|
7
|
+
## Content Quality
|
|
8
|
+
|
|
9
|
+
- [x] No implementation details (languages, frameworks, APIs)
|
|
10
|
+
- [x] Focused on user value and business needs
|
|
11
|
+
- [x] Written for non-technical stakeholders
|
|
12
|
+
- [x] All mandatory sections completed
|
|
13
|
+
|
|
14
|
+
## Requirement Completeness
|
|
15
|
+
|
|
16
|
+
- [x] No [NEEDS CLARIFICATION] markers remain
|
|
17
|
+
- [x] Requirements are testable and unambiguous
|
|
18
|
+
- [x] Success criteria are measurable
|
|
19
|
+
- [x] Success criteria are technology-agnostic (no implementation details)
|
|
20
|
+
- [x] All acceptance scenarios are defined
|
|
21
|
+
- [x] Edge cases are identified
|
|
22
|
+
- [x] Scope is clearly bounded
|
|
23
|
+
- [x] Dependencies and assumptions identified
|
|
24
|
+
|
|
25
|
+
## Feature Readiness
|
|
26
|
+
|
|
27
|
+
- [x] All functional requirements have clear acceptance criteria
|
|
28
|
+
- [x] User scenarios cover primary flows
|
|
29
|
+
- [x] Feature meets measurable outcomes defined in Success Criteria
|
|
30
|
+
- [x] No implementation details leak into specification
|
|
31
|
+
|
|
32
|
+
## Notes
|
|
33
|
+
|
|
34
|
+
- This feature is an internal refactor, so its "users" are the maintainers. The spec deliberately names quality tools (linter, cyclomatic complexity, Google-style docstrings) because they are the goal of the feature itself, not implementation details. They are accepted as an exception to "technology-agnostic".
|
|
35
|
+
- Concrete module names (`commands/`, `gep`, `gpipe`) are used only to bound the scope.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Contract: observable CLI behavior
|
|
2
|
+
|
|
3
|
+
This refactor does **not** change the public interface. The contract is what the suite already verifies, plus the three explicit exceptions listed at the end.
|
|
4
|
+
|
|
5
|
+
## Invariants
|
|
6
|
+
|
|
7
|
+
| Aspect | Contract | Verified by |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Commands and aliases | `ca/clean-architecture`, `gm`, `guc`, `gda`, `gep`, `gh`, `gpipe`, `vs`, `dm`, `up`, with the same long names | `tests/commands/test_cli.py` |
|
|
10
|
+
| Flags and defaults | Same names, defaults, help panels and epilogs | `--help` snapshot in `test_cli.py` and per-command tests |
|
|
11
|
+
| Generated files | Byte-for-byte identical, including the files that now come from new templates (FR-004) | `tests/commands/test_dry_run_checksum.py`, `tests/templates/` |
|
|
12
|
+
| `--dry-run` | Same list of paths, no writes | `tests/factory/test_dry_run_parity.py` and per-command tests |
|
|
13
|
+
| Error messages | Same text and same `Hint:` (when present) | per-command tests (`strip_ansi`), `tests/commands/test_behavior_contract.py` |
|
|
14
|
+
| Exit codes | `0` success or help, `1` user error, `2` `uv` failure in `up` | per-command tests |
|
|
15
|
+
| `pyproject.toml` | Same injected dependencies, groups and `[project.scripts]` | `tests/core/test_pyproject_writer.py` and gep/gda tests |
|
|
16
|
+
|
|
17
|
+
## Allowed changes (exhaustive)
|
|
18
|
+
|
|
19
|
+
### C-1: unified project context (FR-010)
|
|
20
|
+
|
|
21
|
+
- **Before**: `gep` and `gep --add-tool` used `to_snake_case([project].name)`, with `"project"` as the default.
|
|
22
|
+
- **After**: every command uses `[tool.scaffold-ca-python].name`, falling back to the root directory name.
|
|
23
|
+
- **Impact**: it only changes for projects where `[project].name` was edited by hand and no longer matches the tool section.
|
|
24
|
+
|
|
25
|
+
### C-2: `gpipe` conflict message (FR-016)
|
|
26
|
+
|
|
27
|
+
- **Before**:
|
|
28
|
+
```
|
|
29
|
+
Error: '<display>' already exists at '<path>'. Use --force to overwrite.
|
|
30
|
+
Hint: Remove the existing file first or choose a different provider.
|
|
31
|
+
```
|
|
32
|
+
- **After**:
|
|
33
|
+
```
|
|
34
|
+
Error: '<display>' already exists at '<path>'.
|
|
35
|
+
Hint: Remove the existing file first or choose a different provider.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### C-3: TOML sections visible in the `gep` output (FR-021)
|
|
39
|
+
|
|
40
|
+
- **Before**: Rich interprets `[project.scripts]` as markup and drops it:
|
|
41
|
+
```
|
|
42
|
+
Would update : my_app = "my_app.server:start_server"
|
|
43
|
+
✓ Updated : my_app = "my_app.server:start_server"
|
|
44
|
+
```
|
|
45
|
+
- **After**: `escape()` is applied, as is already done for `[project.dependencies]`:
|
|
46
|
+
```
|
|
47
|
+
Would update [project.scripts]: my_app = "my_app.server:start_server"
|
|
48
|
+
✓ Updated [project.scripts]: my_app = "my_app.server:start_server"
|
|
49
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Contract: adding a new type without touching `commands/`
|
|
2
|
+
|
|
3
|
+
An internal contract for maintainers. `tests/factory/test_extensibility.py` verifies it.
|
|
4
|
+
|
|
5
|
+
## Entry point
|
|
6
|
+
|
|
7
|
+
1. Create `factory/entry_points/ep_<type>.py`:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
class EntryPointFoo(EntryPointFactory):
|
|
11
|
+
subdir: ClassVar[str] = "foo"
|
|
12
|
+
supported_flags: ClassVar[frozenset[EntryPointFlag]] = frozenset({EntryPointFlag.ENABLE_KAFKA})
|
|
13
|
+
conflicts: ClassVar[tuple[EntryPointConflict, ...]] = ()
|
|
14
|
+
|
|
15
|
+
def build(self, builder: ModuleBuilder) -> None: ...
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Register the factory with one line in `factory/entry_points/__init__.py`:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
ENTRY_POINT_FACTORIES["foo"] = EntryPointFoo
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. Add its templates under `templates/entry_point/foo/` and their test under `tests/templates/`, as Constitution II requires.
|
|
25
|
+
|
|
26
|
+
With that, `gep --type foo` does the following with no further changes:
|
|
27
|
+
|
|
28
|
+
- validates flags with messages derived from the registered types (research R-02);
|
|
29
|
+
- applies the `conflicts` guards and the duplicate guard on `subdir`;
|
|
30
|
+
- shows `result_notes()`, which by default is the `main.py` replacement notice;
|
|
31
|
+
- registers the script if the factory called `builder.set_project_script(...)`.
|
|
32
|
+
|
|
33
|
+
## Driven adapter
|
|
34
|
+
|
|
35
|
+
- Inherit from `DrivenAdapterFactory`.
|
|
36
|
+
- Declare `fixed_name`, or `None` when `--name` provides the name.
|
|
37
|
+
- Register it in `factory/driven_adapters/__init__.py`.
|
|
38
|
+
|
|
39
|
+
## Pipeline
|
|
40
|
+
|
|
41
|
+
- Add a `PipelineFactory(output_path=…, template=…, display_name=…)` instance to `PIPELINE_PROVIDERS` in `factory/pipelines/__init__.py`.
|
|
42
|
+
|
|
43
|
+
## Guarantees
|
|
44
|
+
|
|
45
|
+
- An unknown `--type` produces `Unknown type '<x>'. Allowed: <registry keys in order>.`. An unknown `--provider` produces `Unknown provider '<x>'. Allowed: <registry keys in order>.`.
|
|
46
|
+
- No module in `commands/` contains type literals (`"restapi"`, `"mcp"`, `"github"`…). The exception is `add_mcp_tool.py`, which is MCP-specific by definition: it validates `--type mcp`.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Data Model: SOLID refactor and comment cleanup
|
|
2
|
+
|
|
3
|
+
Internal entities that the refactor introduces or modifies. There is no new persistence: the only persisted state is still the generated project and its `pyproject.toml`.
|
|
4
|
+
|
|
5
|
+
## ProjectContext (modified: how it is loaded)
|
|
6
|
+
|
|
7
|
+
| Field | Type | Source |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `name` | `str` (validated by `NAME_RE`) | `[tool.scaffold-ca-python].name`; if missing, the root directory name |
|
|
10
|
+
| `python_package` | `str` (computed) | `to_snake_case(name)` |
|
|
11
|
+
| `python_package_script` | `str` (computed) | `to_kebab_case(name)` |
|
|
12
|
+
|
|
13
|
+
- **Single loader**: `core.project_detector.load_project_context(root: Path) -> ProjectContext`.
|
|
14
|
+
- **FR-011 rule**: `python_package` stays in snake_case. The code `gep` generates does not change for projects created with the tool, because in those `[project].name == [tool.scaffold-ca-python].name`.
|
|
15
|
+
- **Behavior change (FR-010)**: `gep` and `--add-tool` stop reading `[project].name`.
|
|
16
|
+
|
|
17
|
+
## EntryPointOptions (new, `models/options.py`)
|
|
18
|
+
|
|
19
|
+
Dataclass with `frozen=True, slots=True`. Groups the 12 parameters of `gep`.
|
|
20
|
+
|
|
21
|
+
| Field | Type | Default |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `type_` | `str` | — |
|
|
24
|
+
| `swagger` | `str \| None` | `None` |
|
|
25
|
+
| `enable_kafka` | `bool` | `False` |
|
|
26
|
+
| `enable_mcp_client` | `bool` | `False` |
|
|
27
|
+
| `with_resources` | `bool` | `False` |
|
|
28
|
+
| `with_prompts` | `bool` | `False` |
|
|
29
|
+
| `add_tool` | `bool` | `False` |
|
|
30
|
+
| `name` | `str \| None` | `None` |
|
|
31
|
+
| `params` | `tuple[str, ...]` | `()` |
|
|
32
|
+
| `returns` | `str` | `"str"` |
|
|
33
|
+
| `description` | `str \| None` | `None` |
|
|
34
|
+
| `dry_run` | `bool` | `False` |
|
|
35
|
+
|
|
36
|
+
Methods:
|
|
37
|
+
- `creation_flags() -> list[str]`: returns the active creation flags, in the current order (`--swagger`, `--enable-kafka`, `--enable-mcp-client`, `--with-resources`, `--with-prompts`). The `--add-tool` guard uses it.
|
|
38
|
+
- `apply_to(builder, routes) -> None`: transfers the build parameters to the builder (see research R-05).
|
|
39
|
+
|
|
40
|
+
## EntryPointFlag (new, enum in `factory/entry_points/base.py`)
|
|
41
|
+
|
|
42
|
+
| Member | Label in messages | Verb | Active when |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `SWAGGER` | `--swagger` | `is` | `options.swagger` is truthy |
|
|
45
|
+
| `ENABLE_MCP_CLIENT` | `--enable-mcp-client` | `is` | `options.enable_mcp_client` |
|
|
46
|
+
| `MCP_PRIMITIVES` | `--with-resources and --with-prompts` | `are` | `with_resources or with_prompts` |
|
|
47
|
+
| `ENABLE_KAFKA` | `--enable-kafka` | `is` | `options.enable_kafka` |
|
|
48
|
+
|
|
49
|
+
The command evaluates the flags in table order. Research R-02 describes how the message is derived.
|
|
50
|
+
|
|
51
|
+
## EntryPointConflict (new)
|
|
52
|
+
|
|
53
|
+
A named tuple `(label: str, subdir: str)`: a directory under `infrastructure/entry_points/` whose existence prevents creating the type.
|
|
54
|
+
|
|
55
|
+
## EntryPointFactory (new, ABC implementing `ModuleFactory`)
|
|
56
|
+
|
|
57
|
+
| Member | Type | Default |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `subdir` | `ClassVar[str]` | required |
|
|
60
|
+
| `supported_flags` | `ClassVar[frozenset[EntryPointFlag]]` | `frozenset()` |
|
|
61
|
+
| `conflicts` | `ClassVar[tuple[EntryPointConflict, ...]]` | `()` |
|
|
62
|
+
| `build(builder)` | abstract | — |
|
|
63
|
+
| `result_notes(project_root, pkg, type_key, *, dry_run)` | `list[str]` | `main.py` replacement notice |
|
|
64
|
+
|
|
65
|
+
Declared values, equivalent to the current logic:
|
|
66
|
+
|
|
67
|
+
| Type | subdir | supported_flags | conflicts | result_notes |
|
|
68
|
+
|---|---|---|---|---|
|
|
69
|
+
| `restapi` | `api/v1` | SWAGGER, ENABLE_MCP_CLIENT, ENABLE_KAFKA | `mcp_server`, `agent` | override: `main.py` deletion + `[project.scripts]` (escaped, C-3) |
|
|
70
|
+
| `mcp` | `mcp_server` | MCP_PRIMITIVES, ENABLE_KAFKA | `restapi`→`api` | default |
|
|
71
|
+
| `agent` | `agent` | ENABLE_MCP_CLIENT, ENABLE_KAFKA | `restapi`→`api` | default |
|
|
72
|
+
| `generic` | `generic` | ENABLE_MCP_CLIENT, ENABLE_KAFKA | — | default |
|
|
73
|
+
|
|
74
|
+
Note: today `--enable-kafka` and `--enable-mcp-client` are accepted without error by types that don't use them. Declaring them as supported keeps that behavior.
|
|
75
|
+
|
|
76
|
+
## DrivenAdapterFactory (new, ABC)
|
|
77
|
+
|
|
78
|
+
| Member | Type | Meaning |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `fixed_name` | `ClassVar[str \| None]` | when set, `--name` is ignored (`rest_consumer`, `secrets`) |
|
|
81
|
+
| `module_name(name: str \| None) -> str \| None` | method | returns `fixed_name or name`. When the result is `None`, the command fails with `"--name is required when --type is {type}."` |
|
|
82
|
+
|
|
83
|
+
The subdirectory is `to_snake_case(module_name)`.
|
|
84
|
+
|
|
85
|
+
## PipelineFactory (new, `factory/pipelines/`)
|
|
86
|
+
|
|
87
|
+
| Field | Type | github | azure |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| `output_path` | relative `PurePosixPath` | `.github/workflows/ci.yml` | `azure-pipelines.yml` |
|
|
90
|
+
| `template` | `str` | `pipeline/github/ci.yml.jinja2` | `pipeline/azure/azure_pipelines.yml.jinja2` |
|
|
91
|
+
| `display_name` | `str` | `ci.yml` | `azure-pipelines.yml` |
|
|
92
|
+
|
|
93
|
+
`PIPELINE_PROVIDERS: dict[str, PipelineFactory]` keeps the `github, azure` order for the `Allowed: …` message. `build()` renders with the `ProjectContext` (a Pydantic model), so it complies with Constitution II.
|
|
94
|
+
|
|
95
|
+
## ModuleBuilder (modified)
|
|
96
|
+
|
|
97
|
+
| Change | Detail |
|
|
98
|
+
|---|---|
|
|
99
|
+
| + `set_project_script(entry_fn: str = "start_server")` | replaces `add_param("scripts_entry"/"scripts_entry_fn")` |
|
|
100
|
+
| + `pending_project_script: str \| None` (property) | what tests and dry-run output read |
|
|
101
|
+
| `persist()` | applies dependencies, groups and the script; no longer reads magic keys from `_params` |
|
|
102
|
+
| `add_param`/`get_param` | kept for build flags (R-05) |
|
|
103
|
+
|
|
104
|
+
## ModuleTarget (new, `core/module_locator.py`)
|
|
105
|
+
|
|
106
|
+
`find_module_targets(project_root, pkg, snake) -> list[tuple[Path, Path | None]]`. A single implementation, shared by `delete_module` (preview) and `DeleteModuleFactory` (deletion).
|
|
107
|
+
|
|
108
|
+
## Internal utilities (stateless)
|
|
109
|
+
|
|
110
|
+
- `commands/_shared.py`: see research R-07.
|
|
111
|
+
- `commands/_entry_point_rules.py`: `check_flags()`, `check_conflicts()` (research R-02/R-03).
|
|
112
|
+
- New templates: `project/package_init.py.jinja2`, `project/empty.jinja2` (research R-13).
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Implementation Plan: SOLID refactor and comment cleanup of the scaffolder
|
|
2
|
+
|
|
3
|
+
**Branch**: `feature/022-solid-code-cleanup` | **Date**: 2026-10-22 | **Spec**: [spec.md](spec.md)
|
|
4
|
+
|
|
5
|
+
**Input**: Feature specification from `/specs/022-solid-code-cleanup/spec.md`
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
Internal refactor of `src/scaffold_ca_python/` with no change to the CLI's observable behavior, apart from the allowed changes C-1, C-2 and C-3. It has five parts.
|
|
10
|
+
|
|
11
|
+
1. **Shared command utilities.** A common layer for the commands (`commands/_shared.py`) centralizes:
|
|
12
|
+
- errors with a resolution hint;
|
|
13
|
+
- project-root lookup;
|
|
14
|
+
- duplicate guards;
|
|
15
|
+
- the dry-run tree;
|
|
16
|
+
- the `--dry-run` option.
|
|
17
|
+
2. **Single context loader.** `load_project_context` moves to `core/project_detector.py` and fixes the `gep` inconsistency.
|
|
18
|
+
3. **Type knowledge lives in the factories.** Entry-point, driven-adapter and pipeline factories declare what is specific to their type through base classes with `ClassVar`s. The registries move into their `factory/` packages, so a new type does not touch `commands/`.
|
|
19
|
+
4. **Complexity ≤ 10.** `_add_tool_impl`, `_generate_entry_point_impl`, `FileWriter._commit`, `StructureValidator.validate` and `DeleteModuleFactory.build` are split.
|
|
20
|
+
5. **Comments, guardrails and output fixes.** Comments and docstrings are cleaned up (Google style, no Spec Kit IDs). Ruff `B`, `SIM` and `C90` are enabled. The `gpipe` hint (FR-016) and the `[project.scripts]` output (FR-021) are fixed.
|
|
21
|
+
|
|
22
|
+
## Technical Context
|
|
23
|
+
|
|
24
|
+
**Language/Version**: Python 3.13.
|
|
25
|
+
|
|
26
|
+
**Primary Dependencies**: Typer (with `Annotated`), Rich, Jinja2, Pydantic v2, PyYAML. No dependencies are added.
|
|
27
|
+
|
|
28
|
+
**Storage**: local files (the generated project and its `pyproject.toml`).
|
|
29
|
+
|
|
30
|
+
**Testing**: pytest, pytest-cov (≥80% gate), pytest-benchmark and `typer.testing.CliRunner`. Baseline measured on 2026-10-22: **739 passed, 1 skipped, 96.50% coverage**.
|
|
31
|
+
|
|
32
|
+
**Target Platform**: cross-platform CLI (macOS, Linux, Windows) distributed through PyPI.
|
|
33
|
+
|
|
34
|
+
**Project Type**: CLI (single project, `src/` layout).
|
|
35
|
+
|
|
36
|
+
**Performance Goals**: no regression in `tests/commands/test_performance.py`.
|
|
37
|
+
|
|
38
|
+
**Constraints**:
|
|
39
|
+
- Output is byte-for-byte identical in generated files, messages and exit codes. The exceptions are:
|
|
40
|
+
- FR-010 (project context);
|
|
41
|
+
- FR-016 (`gpipe` message);
|
|
42
|
+
- FR-021 (`[project.scripts]` shown literally).
|
|
43
|
+
- Existing Jinja templates are not modified. Only two new ones are added (FR-004, research R-13).
|
|
44
|
+
- `mypy --strict` must pass.
|
|
45
|
+
|
|
46
|
+
**Scale/Scope**: about 4.4k LOC in 40 modules and 50 test files.
|
|
47
|
+
|
|
48
|
+
Violations measured today with `ruff --select B,SIM,C90` and `max-complexity=10`:
|
|
49
|
+
- **`src/`, 10 in total:**
|
|
50
|
+
- 6 × C901: `_add_tool_impl` 26, `_generate_entry_point_impl` 24, `_generate_driven_adapter_impl` 13, `StructureValidator.validate` 13, `FileWriter._commit` 12, `DeleteModuleFactory.build` 12.
|
|
51
|
+
- 2 × B904, 1 × B905 and 1 × SIM108.
|
|
52
|
+
- **`tests/`:** 2 × B017. No C90 violations.
|
|
53
|
+
- **B008:** does not appear, because Typer uses `Annotated`.
|
|
54
|
+
|
|
55
|
+
## Constitution Check
|
|
56
|
+
|
|
57
|
+
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* Constitution version: **2.1.0**.
|
|
58
|
+
|
|
59
|
+
| Principle | Assessment | Status |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| I. Clean Architecture in generated projects | Templates and generated output don't change. `vs` keeps its logic; only the complexity of `validate` is reduced. | ✅ |
|
|
62
|
+
| II. Template-driven generation | `generate_project` and `generate_pipeline` switch to `TemplateRenderer.render()` with packaged templates instead of `render_string(_tmpl())`. Two files of `ca` that don't come from a template today now do, with the same output (FR-004, R-13): the root package `__init__.py` (an f-string) and the empty `src/tests/__init__.py`. They use the new templates `project/package_init.py.jinja2` and `project/empty.jinja2`. Factories still pass template contexts as `dict`, which is pre-existing debt (see Complexity Tracking). No new code introduces `dict` contexts: the `render_into` helper was dropped. | ✅ / ⚠️ pre-existing debt (Governance v2.1.0) |
|
|
63
|
+
| III. Command parity and `--dry-run` | Commands, aliases and flags don't change, and the parity and checksum tests are kept. | ✅ |
|
|
64
|
+
| IV. Python idioms | Compliance improves: consistent `X \| None` typing, extended ruff rules and strict mypy with no new `type: ignore`. | ✅ |
|
|
65
|
+
| V. Test-first (NON-NEGOTIABLE) | Every story starts with red tests, among them the context regression (FR-020), extensibility with a fake factory, the new `gpipe` message, the `[project.scripts]` output (FR-021), `set_project_script` and the new templates. The pure refactor is covered by the existing suite, green before and after each step. | ✅ |
|
|
66
|
+
| VI. Developer Experience | FR-016 fixes an invalid hint (`--force`) and FR-021 makes `[project.scripts]` visible in the output. 38 of the 56 error messages in `commands/` have no `Hint:`. FR-003 keeps them unchanged; this is pre-existing debt. | ⚠️ pre-existing debt (Governance v2.1.0) |
|
|
67
|
+
| VII. Branches | `feature/022-solid-code-cleanup`, with the `feature/` prefix the repo uses. | ✅ |
|
|
68
|
+
|
|
69
|
+
**Result**: the gate passes. Two pre-existing violations are kept under the "Pre-existing violations" governance clause (v2.1.0):
|
|
70
|
+
- VI: missing resolution hints;
|
|
71
|
+
- II: template contexts passed as `dict`.
|
|
72
|
+
|
|
73
|
+
The feature does not introduce or worsen either one. The follow-up spec directories are created in T063 before merge.
|
|
74
|
+
|
|
75
|
+
**Post-design re-check (Phase 1)**: ✅. The design in [data-model.md](data-model.md) and [contracts/](contracts/):
|
|
76
|
+
- only adds base classes, `ClassVar`s and internal utilities;
|
|
77
|
+
- doesn't change existing templates or flags;
|
|
78
|
+
- changes the output only through C-1, C-2 and C-3.
|
|
79
|
+
|
|
80
|
+
The adapted tests only change imports or where a factory is registered (see research R-08).
|
|
81
|
+
|
|
82
|
+
## Project Structure
|
|
83
|
+
|
|
84
|
+
### Documentation (this feature)
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
specs/022-solid-code-cleanup/
|
|
88
|
+
├── plan.md # This file
|
|
89
|
+
├── research.md # Phase 0: design decisions
|
|
90
|
+
├── data-model.md # Phase 1: internal entities (options, descriptors, context)
|
|
91
|
+
├── quickstart.md # Phase 1: validation guide
|
|
92
|
+
├── contracts/
|
|
93
|
+
│ ├── cli-behavior.md # Observable behavior contract (+ allowed changes C-1..C-3)
|
|
94
|
+
│ └── factory-extension.md # Contract for adding new types
|
|
95
|
+
├── checklists/
|
|
96
|
+
│ └── requirements.md
|
|
97
|
+
└── tasks.md # Phase 2 (/speckit-tasks)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Source Code (repository root)
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
src/scaffold_ca_python/
|
|
104
|
+
├── cli.py # no functional changes
|
|
105
|
+
├── commands/
|
|
106
|
+
│ ├── _shared.py # NEW: fail(), require_project_root(), validate_name_or_exit(),
|
|
107
|
+
│ │ # ensure_absent(), print_dry_run_tree(),
|
|
108
|
+
│ │ # print_pending_dependencies(), dry_run_option(), build_and_persist()
|
|
109
|
+
│ ├── _entry_point_rules.py # NEW: check_flags(), check_conflicts() (research R-02/R-03)
|
|
110
|
+
│ ├── generate_entry_point.py # orchestration only: options → validation → factory → presentation
|
|
111
|
+
│ ├── add_mcp_tool.py # NEW: --add-tool flow extracted from generate_entry_point
|
|
112
|
+
│ ├── generate_driven_adapter.py # no if/elif per type
|
|
113
|
+
│ ├── generate_pipeline.py # uses ModuleBuilder + PIPELINE_PROVIDERS, injectable renderer/writer
|
|
114
|
+
│ ├── generate_project.py # file table + injectable ModuleBuilder
|
|
115
|
+
│ ├── generate_model.py / generate_use_case.py / generate_helper.py / delete_module.py
|
|
116
|
+
│ │ # no single-entry _REGISTRY; use _shared
|
|
117
|
+
│ ├── update_project.py # _run_uv() removes the duplicated try/except
|
|
118
|
+
│ └── validate_structure.py
|
|
119
|
+
├── core/
|
|
120
|
+
│ ├── project_detector.py # + load_project_context() (single definition)
|
|
121
|
+
│ ├── module_locator.py # NEW: find_module_targets() (shared by dm and its factory)
|
|
122
|
+
│ ├── openapi_routes.py # NEW: parse_routes() (formerly _parse_swagger in gep)
|
|
123
|
+
│ ├── module_builder.py # + set_project_script(); no magic keys in persist()
|
|
124
|
+
│ ├── file_writer.py # _commit split; zip(strict=True)
|
|
125
|
+
│ ├── structure_validator.py # validate split into _classify/_parse/_violations_in
|
|
126
|
+
│ └── mcp_tool_spec.py, pyproject_writer.py, template_renderer.py, name_utils.py # docstring cleanup
|
|
127
|
+
├── factory/
|
|
128
|
+
│ ├── __init__.py # ModuleFactory (Protocol, unchanged)
|
|
129
|
+
│ ├── entry_points/
|
|
130
|
+
│ │ ├── __init__.py # ENTRY_POINT_FACTORIES (registry)
|
|
131
|
+
│ │ ├── base.py # NEW: EntryPointFactory, EntryPointConflict, EntryPointFlag
|
|
132
|
+
│ │ └── ep_restapi.py, ep_mcp.py, ep_agent.py, ep_generic.py # declare ClassVars
|
|
133
|
+
│ ├── driven_adapters/
|
|
134
|
+
│ │ ├── __init__.py # DRIVEN_ADAPTER_FACTORIES
|
|
135
|
+
│ │ ├── base.py # NEW: DrivenAdapterFactory
|
|
136
|
+
│ │ └── da_*.py
|
|
137
|
+
│ ├── pipelines/ # NEW
|
|
138
|
+
│ │ ├── __init__.py # PIPELINE_PROVIDERS
|
|
139
|
+
│ │ └── pipeline_factory.py # PipelineFactory (github, azure as descriptor instances)
|
|
140
|
+
│ └── simple/ # no structural changes; cleanup
|
|
141
|
+
├── models/
|
|
142
|
+
│ ├── context.py # docstring cleanup
|
|
143
|
+
│ └── options.py # NEW: EntryPointOptions (frozen dataclass)
|
|
144
|
+
└── templates/project/
|
|
145
|
+
├── package_init.py.jinja2 # NEW (R-13)
|
|
146
|
+
└── empty.jinja2 # NEW (R-13)
|
|
147
|
+
|
|
148
|
+
tests/ # same layout; new tests:
|
|
149
|
+
├── commands/test_shared.py
|
|
150
|
+
├── commands/test_behavior_contract.py # US1 safety net + C-3
|
|
151
|
+
├── core/test_project_context.py # FR-010/FR-020 regression
|
|
152
|
+
├── core/test_module_locator.py
|
|
153
|
+
├── core/test_openapi_routes.py
|
|
154
|
+
├── models/test_options.py
|
|
155
|
+
├── test_source_hygiene.py # FR-015
|
|
156
|
+
└── factory/test_extensibility.py # extended: fake factory with a full descriptor
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Structure Decision**: The single project with `src/` layout stays.
|
|
160
|
+
- **Registries:** type registries move from `commands/` to the `__init__.py` of each `factory/` package, so adding a type does not modify `commands/` (SC-005).
|
|
161
|
+
- **Shared logic:** command-shared logic lives in `commands/_shared.py` and not in `core/`, because it depends on Rich and Typer (it is presentation). `core/` stays independent of the CLI.
|
|
162
|
+
- **Template helpers:** the local `tpl()` helpers in the entry-point factories stay as they are. A shared `render_into()` helper was considered and dropped, because it would be new code that accepts `dict` contexts (Constitution II, Governance v2.1.0: new code must comply).
|
|
163
|
+
|
|
164
|
+
## Suggested implementation order
|
|
165
|
+
|
|
166
|
+
Each step leaves the suite green and can be its own commit:
|
|
167
|
+
|
|
168
|
+
1. **Guardrails first:** enable `B`, `SIM` and `C90` in `pyproject.toml`, with a temporary C901 `per-file-ignores` only for the affected modules. It is removed at the end. Fix B904, B905, SIM108 and B017.
|
|
169
|
+
2. **Shared utilities:** create and test `commands/_shared.py`.
|
|
170
|
+
3. **Story 1 (P1), safety net:** behavior-contract tests, green against the current code.
|
|
171
|
+
4. **Story 2 (P1):** `EntryPointFactory` and `DrivenAdapterFactory`, registries in `factory/`, `set_project_script()` and `PipelineFactory`.
|
|
172
|
+
5. **Story 3 (P2), TDD:** single `load_project_context` and its regression test.
|
|
173
|
+
6. **Story 4 (P2):**
|
|
174
|
+
- split gep (`EntryPointOptions`, `add_mcp_tool.py`, `openapi_routes.py`), `FileWriter`, `StructureValidator`, and `delete_module` (with `module_locator`);
|
|
175
|
+
- `generate_project` switches to the file table, the new templates and an injectable builder.
|
|
176
|
+
7. **Stories 5 and 6 (P3):**
|
|
177
|
+
- comment and docstring cleanup and dead code;
|
|
178
|
+
- the `gpipe` message (C-2) and the `[project.scripts]` output (C-3);
|
|
179
|
+
- remove the temporary `per-file-ignores`.
|
|
180
|
+
8. **Final verification:** full suite, checksum, parity, generated-tree comparison ([quickstart.md](quickstart.md)), and the follow-up spec directories 023/024.
|
|
181
|
+
|
|
182
|
+
## Complexity Tracking
|
|
183
|
+
|
|
184
|
+
Pre-existing violations kept under the Constitution v2.1.0 "Pre-existing violations" governance clause:
|
|
185
|
+
|
|
186
|
+
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| **VI**: 38 of 56 error messages in `commands/` have no `Hint:`. Examples: the `gep` flag validation, `Unknown type` and `--name is required…`. They are kept unchanged. | FR-003 requires the output to stay unchanged during the refactor. Adding hints would mix a UX change into the refactor. | Adding them here would invalidate the US1 safety net (T008–T010) and multiply the allowed changes. It will be resolved in follow-up feature **023-error-hints**. |
|
|
189
|
+
| **II**: factories pass `dict` contexts to templates. The dicts come from the already validated `ModuleContext.model_dump()`, plus `bool` flags. | Keep the output identical and the refactor scope bounded. | Typing every context with Pydantic touches all 11 factories and their templates. It will be resolved in follow-up feature **024-typed-template-contexts**. No new code in this feature adds `dict` contexts. |
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Quickstart: validating the 022 refactor
|
|
2
|
+
|
|
3
|
+
End-to-end validation guide. Design details are in [data-model.md](data-model.md) and [contracts/](contracts/).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export SSL_CERT_FILE=/etc/ssl/cert.pem # only if uv fails with a TLS error
|
|
9
|
+
uv sync
|
|
10
|
+
git switch feature/022-solid-code-cleanup
|
|
11
|
+
REPO=~/projects/ingsw/scaffold-clean-architecture-py
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 1. Reference tree (before the refactor)
|
|
15
|
+
|
|
16
|
+
Run once from `main`, before starting:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
gen_tree() { # $1 = output dir, $2 = sha file
|
|
20
|
+
mkdir -p "$1" && cd "$1"
|
|
21
|
+
uv run --project "$REPO" scaffold-ca-python ca --name demo-app
|
|
22
|
+
cd demo-app
|
|
23
|
+
for t in "gm --name order" "guc --name create_order" "gh --name clock" \
|
|
24
|
+
"gda --type rest-consumer" "gda --type generic --name cache" \
|
|
25
|
+
"gep --type mcp --with-resources" "gep --type mcp --add-tool --name ping --returns str" \
|
|
26
|
+
"gpipe --provider github"; do
|
|
27
|
+
uv run --project "$REPO" scaffold-ca-python $t
|
|
28
|
+
done
|
|
29
|
+
sed -i '' '/^created_at = /d' pyproject.toml # timestamp differs on every run
|
|
30
|
+
find . -type f -print0 | sort -z | xargs -0 shasum > "$2"
|
|
31
|
+
}
|
|
32
|
+
gen_tree /tmp/ref022 /tmp/ref022.sha
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Repeat for restapi in another directory, because restapi is incompatible with mcp. Use `ca --name demo-api`, then `gep --type restapi` and `gda --type secrets`, and save the hashes to `/tmp/ref022-restapi.sha`.
|
|
36
|
+
|
|
37
|
+
After the refactor, run the same thing in `/tmp/new022` and `/tmp/new022-restapi`, then compare:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
diff /tmp/ref022.sha /tmp/new022.sha
|
|
41
|
+
diff /tmp/ref022-restapi.sha /tmp/new022-restapi.sha
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Expected**: no differences. This covers User Story 1 and SC-001.
|
|
45
|
+
|
|
46
|
+
## 2. Suite and guardrails
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv run ruff check src/ tests/
|
|
50
|
+
uv run ruff format --check src/ tests/
|
|
51
|
+
uv run mypy src/
|
|
52
|
+
uv run pytest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Expected**:
|
|
56
|
+
- Everything is green, with coverage ≥80% (baseline: 96.50%).
|
|
57
|
+
- The 739 existing tests pass, plus the new ones. Only the tests listed in research R-08 and those of C-1, C-2 and C-3 are adapted.
|
|
58
|
+
|
|
59
|
+
This covers SC-001, SC-002 and SC-007.
|
|
60
|
+
|
|
61
|
+
## 3. Measurable criteria
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# SC-003: zero Spec Kit IDs in src/
|
|
65
|
+
grep -rnE '\b(T0[0-9]{2}|FR-[0-9]{3}|US-?[0-9]|R-[0-9]{2})\b|Phase [0-9]' src/ | grep '\.py:' | wc -l # → 0
|
|
66
|
+
|
|
67
|
+
# SC-004: single definitions
|
|
68
|
+
grep -rn "def load_project_context\|def _load_project_context" src/ | wc -l # → 1
|
|
69
|
+
grep -rn "No scaffold-ca-python project found" src/ | wc -l # → 1
|
|
70
|
+
|
|
71
|
+
# SC-005: no type literals in commands/ (except add_mcp_tool.py)
|
|
72
|
+
grep -nE '"(restapi|agent|generic|rest-consumer|secrets|github|azure)"' src/scaffold_ca_python/commands/*.py # → empty
|
|
73
|
+
|
|
74
|
+
# No temporary C901 ignores left
|
|
75
|
+
grep -n "C901" pyproject.toml # → empty
|
|
76
|
+
|
|
77
|
+
# FR-004: only the two new templates were added; nothing existing was modified
|
|
78
|
+
git diff --stat main -- src/scaffold_ca_python/templates
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 4. Allowed behavior changes
|
|
82
|
+
|
|
83
|
+
- **C-1 (FR-010)**: run `uv run pytest tests/core/test_project_context.py`. It uses a project whose `[project].name` differs from `[tool.scaffold-ca-python].name`; `gep` and `gm` must resolve the same package.
|
|
84
|
+
- **C-2 (FR-016)**: run `scaffold-ca-python gpipe --provider github` twice. The second error does not mention `--force`.
|
|
85
|
+
- **C-3 (FR-021)**: `scaffold-ca-python gep --type restapi --dry-run` shows `Would update [project.scripts]: <pkg> = "<pkg>.server:start_server"`.
|
|
86
|
+
|
|
87
|
+
## 5. Extensibility
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run pytest tests/factory/test_extensibility.py -v
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Expected**: the fake factory registered in `ENTRY_POINT_FACTORIES` generates its files, validates flags and shows its notes, and `commands/` was not modified.
|