claude-code-generator 0.6.1__tar.gz → 0.6.3__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.
- {claude_code_generator-0.6.1/src/claude_code_generator.egg-info → claude_code_generator-0.6.3}/PKG-INFO +1 -1
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/pyproject.toml +1 -1
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3/src/claude_code_generator.egg-info}/PKG-INFO +1 -1
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/claude_code_generator.egg-info/SOURCES.txt +1 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/__init__.py +1 -1
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase6_5_verify.py +90 -7
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/__init__.py +3 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-6-5-verify.md +6 -2
- claude_code_generator-0.6.3/tests/test_phase6_5_port_isolation.py +87 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_prompt.py +2 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompt_prefix_snapshots.py +1 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompt_prefix_stability.py +6 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompts.py +1 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_sica.py +1 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/LICENSE +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/README.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/setup.cfg +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/claude_code_generator.egg-info/dependency_links.txt +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/claude_code_generator.egg-info/entry_points.txt +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/claude_code_generator.egg-info/requires.txt +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/claude_code_generator.egg-info/top_level.txt +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/agents.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/archive_run.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/changelog.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/checklist.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/cli.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/__init__.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_bench_io.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_crash_recovery.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_detect.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_dispatch.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_resume.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_validators.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/bench.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/bench_compare.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/bench_export.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/generate.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/init.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/optimize.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/review.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/status.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/effort.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/env.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/exceptions.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/__init__.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/actions.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/core.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/issues.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/labels.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/milestones.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/git_ops.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/logging_setup.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/manifest.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/memory.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/__init__.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/_cache_warmup.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/_client_lifecycle.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/_comments.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/_memory_writers.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/_phase5_precommit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/agent_spec.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/criteria_oracle.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/cycle_loop.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/cycle_prompts.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/deviation_detector.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/failure_report.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/ollama_budget.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase0_complexity.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase1_plan.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase2_review.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase3_4_implement.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase5_closure.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase65_budget.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase6_test.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase7_commit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase8_ci_classifier.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase8_finalization.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase8_local_verify.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase8_repair_loop.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/phase8_workflow_gen.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/scenario_builder.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/sica.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/tier_selector.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/tier_t3.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/tier_t4.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/vigil.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/preflight.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/hashes.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-cycle-specializer.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-optimize-requirements.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-0-complexity.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-1-planning.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-2-batch-review.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-3-implementation.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-5-final-review.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-6-test.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-7-commit.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-8-finalization.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-phase-8-repair.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/prompt-review.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/repo_info.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/requirements_structure.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/__init__.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/_telemetry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/batch.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/cache_breakpoints.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/codex_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/compaction_pause.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/fake_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/gemini_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/mcp.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/memory_tool.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/message_parsing.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/options.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/phase_telemetry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/protocol.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/rate_limit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/retry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/sdk_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/soft_reset.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/state_guard.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/subprocess_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/types.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/runner/utils.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/semver.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/state.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/state_retention.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/surface_scanner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/__init__.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/angular.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/base.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/fastapi.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/finance.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/fullstack.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/nestjs.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/templates/python-cli.md +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_agent_spec.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_agents.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_archive_run.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_bench.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_bench_compare.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_bench_export.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_bench_fixture.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_bench_regression.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cache_breakpoints.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cache_ttl_ordering.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cache_warmup.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_changelog.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_checklist.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_claude_md.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cli_io_logging.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_client_lifecycle.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_codex_preflight.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_codex_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_comments.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_commit_message.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_compaction_pause_handler.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_crash_recovery.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_criteria_oracle.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_loop.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_loop_multicycle.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_loop_phase6_5.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_loop_phase8.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_ollama_model.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_cycle_prompts.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_delta_planning.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_dependencies.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_detect.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_deviation_detector.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_dispatch_graph_report.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_docs_no_default_max_turns.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_docs_ollama_model_guide.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_docs_ollama_pro.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_effective_model_routing.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_effort.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_effort_routing_consistency.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_env.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_failure_report.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gemini_preflight.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gemini_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_generate.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_generate_ollama.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_generate_resume.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_actions.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_issues_create.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_labels.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_milestones.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_repo_threading.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_gh_submodules.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_git_ops.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_git_ops_phase8.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_init.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_logging_setup.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_manifest.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_max_turns_cli_flag.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_mcp.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_memory.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_memory_tool.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_memory_writers.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_message_parsing.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_no_max_turns_in_call_sites.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_no_max_turns_literal.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_non_goals_grep_guard.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_ollama_budget.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_ollama_hardening.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_ollama_rate_limit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_optimize.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_options.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase0.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase1.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase2.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase2_cache_regression.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase2_multicycle_token_reduction.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase2_token_reduction.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase3_4.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase5.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase5_precommit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase65_budget.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_integration.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_integration_cycle2.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_prompt_snapshot.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_run.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_state.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase6_5_tiers.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase7.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_access_control.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_changelog.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_ci_classifier.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_finalization.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_local_verify.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_prompt_snapshots.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_prompts.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_repair_loop.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_repair_sota.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_semver.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_state.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_status.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_surface_scanner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_trigger.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase8_workflow_gen.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase_mcp_regression.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase_telemetry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_phase_token_logging.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_preflight.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_preflight_ollama.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompt_drift.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_rate_limit.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_repo_info.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_requirements_structure.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_resume.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_retry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_review.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_runner_protocol.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_runner_protocol_annotations.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_runner_types.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_runner_utils.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_scenario_builder.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_sdk_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_sdk_runner_shared.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_session_mode.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_state.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_state_guard.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_state_retention.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_status.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_subprocess_runner.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_telemetry.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_tier_selector.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_tier_t3.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_tier_t3_pass_rate.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_tier_t4.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_version.py +0 -0
- {claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_vigil.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "claude-code-generator"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.3"
|
|
8
8
|
description = "Orchestrator CLI that drives Claude Code end-to-end to generate whole projects from a requirements.md file."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -212,6 +212,7 @@ tests/test_phase6.py
|
|
|
212
212
|
tests/test_phase65_budget.py
|
|
213
213
|
tests/test_phase6_5_integration.py
|
|
214
214
|
tests/test_phase6_5_integration_cycle2.py
|
|
215
|
+
tests/test_phase6_5_port_isolation.py
|
|
215
216
|
tests/test_phase6_5_prompt.py
|
|
216
217
|
tests/test_phase6_5_prompt_snapshot.py
|
|
217
218
|
tests/test_phase6_5_run.py
|
|
@@ -32,7 +32,7 @@ import socket
|
|
|
32
32
|
import subprocess
|
|
33
33
|
import sys
|
|
34
34
|
import time
|
|
35
|
-
from dataclasses import dataclass, field
|
|
35
|
+
from dataclasses import dataclass, field, replace
|
|
36
36
|
from typing import TYPE_CHECKING, Any
|
|
37
37
|
|
|
38
38
|
import httpx
|
|
@@ -348,6 +348,48 @@ def _spawn_child(entry_cmd: list[str], cwd: Path, env: Mapping[str, str]) -> sub
|
|
|
348
348
|
)
|
|
349
349
|
|
|
350
350
|
|
|
351
|
+
def _alloc_free_port() -> int:
|
|
352
|
+
"""Bind ``127.0.0.1:0`` to obtain an OS-assigned free TCP port, then
|
|
353
|
+
release it.
|
|
354
|
+
|
|
355
|
+
Phase 6.5 must not hardcode ``:8000`` — co-resident tooling (e.g. the
|
|
356
|
+
claude-mem plugin's ``chroma run``) squats well-known ports and returns
|
|
357
|
+
404 to every health probe, burning the entire repair-retry budget on a
|
|
358
|
+
purely environmental collision. An ephemeral port makes that collision
|
|
359
|
+
structurally impossible.
|
|
360
|
+
|
|
361
|
+
There is a benign TOCTOU window between release here and the app binding
|
|
362
|
+
the port; :func:`_ensure_verify_port` closes it by re-checking (and
|
|
363
|
+
rerolling) immediately before each attempt.
|
|
364
|
+
"""
|
|
365
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
366
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
367
|
+
sock.bind(("127.0.0.1", 0))
|
|
368
|
+
return int(sock.getsockname()[1])
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _ensure_verify_port(port: int, *, logger: logging.Logger) -> int:
|
|
372
|
+
"""Pre-flight port guard (#2).
|
|
373
|
+
|
|
374
|
+
If *port* was claimed by a foreign listener between attempts (a plugin
|
|
375
|
+
rebinding, a leaked uvicorn from a prior run), reroll to a fresh free
|
|
376
|
+
port instead of letting the squatter fail a tier and consume a retry.
|
|
377
|
+
A genuine app bug still fails the tier on its own port; only
|
|
378
|
+
environmental collisions are absorbed here.
|
|
379
|
+
"""
|
|
380
|
+
if not _port_open(port):
|
|
381
|
+
return port
|
|
382
|
+
new_port = _alloc_free_port()
|
|
383
|
+
logger.warning(
|
|
384
|
+
"Phase 6.5 verify port %d occupied by a foreign listener before the "
|
|
385
|
+
"attempt began; rerolled to %d so the retry budget is not spent on "
|
|
386
|
+
"an environmental port collision.",
|
|
387
|
+
port,
|
|
388
|
+
new_port,
|
|
389
|
+
)
|
|
390
|
+
return new_port
|
|
391
|
+
|
|
392
|
+
|
|
351
393
|
def _port_open(port: int, host: str = "127.0.0.1", timeout_s: float = 0.25) -> bool:
|
|
352
394
|
try:
|
|
353
395
|
with socket.create_connection((host, port), timeout=timeout_s):
|
|
@@ -654,6 +696,10 @@ async def run(
|
|
|
654
696
|
budget = Phase65BudgetTracker(wall_budget_s=wall_budget_s, turn_budget=turn_budget)
|
|
655
697
|
budget.start()
|
|
656
698
|
|
|
699
|
+
# Ephemeral verification port (#1): allocate once so base_url stays
|
|
700
|
+
# stable across the retry loop; re-checked per attempt by the guard (#2).
|
|
701
|
+
verify_port = _alloc_free_port()
|
|
702
|
+
|
|
657
703
|
for attempt in range(max_retries):
|
|
658
704
|
budget.check(turns_consumed=attempt, logger=logger)
|
|
659
705
|
progress = _begin_attempt(target, progress, attempt)
|
|
@@ -661,6 +707,7 @@ async def run(
|
|
|
661
707
|
if attempt > 0:
|
|
662
708
|
_soft_reset_for_repair(project_dir, attempt + 1)
|
|
663
709
|
|
|
710
|
+
verify_port = _ensure_verify_port(verify_port, logger=logger)
|
|
664
711
|
outcome = _run_tiers(
|
|
665
712
|
project_dir,
|
|
666
713
|
state,
|
|
@@ -669,6 +716,7 @@ async def run(
|
|
|
669
716
|
progress,
|
|
670
717
|
attempt,
|
|
671
718
|
target,
|
|
719
|
+
port=verify_port,
|
|
672
720
|
logger=logger,
|
|
673
721
|
detector=detector,
|
|
674
722
|
)
|
|
@@ -691,6 +739,7 @@ async def run(
|
|
|
691
739
|
max_turns=max_turns,
|
|
692
740
|
attempt=attempt,
|
|
693
741
|
target=target,
|
|
742
|
+
port=verify_port,
|
|
694
743
|
)
|
|
695
744
|
|
|
696
745
|
raise VerificationFailed(
|
|
@@ -722,6 +771,7 @@ def _run_tiers(
|
|
|
722
771
|
attempt: int,
|
|
723
772
|
target: Any,
|
|
724
773
|
*,
|
|
774
|
+
port: int,
|
|
725
775
|
logger: logging.Logger,
|
|
726
776
|
detector: DeviationDetector | None = None,
|
|
727
777
|
) -> TierResult | None:
|
|
@@ -731,13 +781,27 @@ def _run_tiers(
|
|
|
731
781
|
:func:`tier_selector.select_tiers` then iterates ``spec.tiers``,
|
|
732
782
|
skipping any tier with ``enabled=False`` and recording the
|
|
733
783
|
skip reason on ``Phase65Progress``.
|
|
784
|
+
|
|
785
|
+
*port* is the ephemeral free port allocated by :func:`run` (#1). It is
|
|
786
|
+
woven into ``base_url``, the subprocess env (``PORT`` / ``UVICORN_PORT``
|
|
787
|
+
/ ``APP_PORT``), and the persisted spec so both the programmatic tier
|
|
788
|
+
runners and the SDK repair agent bind the same collision-free port.
|
|
734
789
|
"""
|
|
735
|
-
|
|
790
|
+
base_url = f"http://127.0.0.1:{port}"
|
|
791
|
+
# The SDK repair agent does not inherit this env (its credentials are
|
|
792
|
+
# locked at shared-client open time); it learns the port from the
|
|
793
|
+
# persisted spec's base_url/T1.port instead. These vars steer the
|
|
794
|
+
# programmatic T0/T2 subprocesses and any app that honours $PORT.
|
|
795
|
+
env = {
|
|
796
|
+
**build_agent_env(),
|
|
797
|
+
"PORT": str(port),
|
|
798
|
+
"UVICORN_PORT": str(port),
|
|
799
|
+
"APP_PORT": str(port),
|
|
800
|
+
}
|
|
736
801
|
requirements_path = project_dir / ".code-generator" / "requirements.md"
|
|
737
802
|
endpoints = _load_endpoints(requirements_path)
|
|
738
|
-
base_url = "http://127.0.0.1:8000"
|
|
739
803
|
|
|
740
|
-
spec = _persist_spec_for_attempt(project_dir, requirements_path)
|
|
804
|
+
spec = _persist_spec_for_attempt(project_dir, requirements_path, port)
|
|
741
805
|
_record_skips(target, progress, spec, attempt, logger=logger)
|
|
742
806
|
save_state(state_path, state)
|
|
743
807
|
|
|
@@ -759,11 +823,15 @@ def _run_tiers(
|
|
|
759
823
|
return None
|
|
760
824
|
|
|
761
825
|
|
|
762
|
-
def _persist_spec_for_attempt(project_dir: Path, requirements_path: Path) -> AgentSpec:
|
|
826
|
+
def _persist_spec_for_attempt(project_dir: Path, requirements_path: Path, port: int) -> AgentSpec:
|
|
763
827
|
"""Build the ``AgentSpec`` for this run and atomically persist it.
|
|
764
828
|
|
|
765
829
|
The spec is the single source of truth consumed by :func:`_run_tiers`
|
|
766
|
-
and
|
|
830
|
+
*and* the SDK repair agent (the prompt instructs it to trust the spec's
|
|
831
|
+
declared ports). ``build_agent_spec`` stays pure and deterministic
|
|
832
|
+
(default ``:8000``); the ephemeral *port* (#1) is layered on here via
|
|
833
|
+
:func:`dataclasses.replace` so the agent boots the app on a
|
|
834
|
+
collision-free port instead of the well-known ``:8000``.
|
|
767
835
|
"""
|
|
768
836
|
tiers = select_tiers(project_dir, requirements_path)
|
|
769
837
|
requirements_text = (
|
|
@@ -771,6 +839,13 @@ def _persist_spec_for_attempt(project_dir: Path, requirements_path: Path) -> Age
|
|
|
771
839
|
)
|
|
772
840
|
flags = {tier.tier_id: tier.enabled for tier in tiers if tier.tier_id in {"T3", "T4"}}
|
|
773
841
|
spec = build_agent_spec(project_dir, requirements_text, flags)
|
|
842
|
+
spec = replace(
|
|
843
|
+
spec,
|
|
844
|
+
base_url=f"http://127.0.0.1:{port}",
|
|
845
|
+
tiers=tuple(
|
|
846
|
+
replace(tier, port=port) if tier.port is not None else tier for tier in spec.tiers
|
|
847
|
+
),
|
|
848
|
+
)
|
|
774
849
|
persist_agent_spec(spec, project_dir / ".code-generator")
|
|
775
850
|
return spec
|
|
776
851
|
|
|
@@ -949,8 +1024,15 @@ async def _run_repair_pass(
|
|
|
949
1024
|
max_turns: int | None,
|
|
950
1025
|
attempt: int,
|
|
951
1026
|
target: Any,
|
|
1027
|
+
port: int,
|
|
952
1028
|
) -> None:
|
|
953
|
-
"""Dispatch the Sonnet 4.6 repair pass via the per-cycle shared client (#275).
|
|
1029
|
+
"""Dispatch the Sonnet 4.6 repair pass via the per-cycle shared client (#275).
|
|
1030
|
+
|
|
1031
|
+
*port* is the ephemeral verify port. It is injected into the prompt as
|
|
1032
|
+
``VERIFY_BASE_URL`` so the repair agent binds the app to the exact
|
|
1033
|
+
host:port the orchestrator's authoritative T2 probe hits — the agent
|
|
1034
|
+
inventing its own port was the entire failure mode this guards against.
|
|
1035
|
+
"""
|
|
954
1036
|
del runner_module # rate_limit signal is replayed via run_with_shared_client
|
|
955
1037
|
requirements_path = project_dir / ".code-generator" / "requirements.md"
|
|
956
1038
|
spec_path = project_dir / ".code-generator" / "phase6_5_spec.json"
|
|
@@ -968,6 +1050,7 @@ async def _run_repair_pass(
|
|
|
968
1050
|
ORACLE_REPORT=_load_oracle_report_text(requirements_path),
|
|
969
1051
|
TIERS_ACTIVE=tiers_active,
|
|
970
1052
|
TIERS_SKIPPED=tiers_skipped,
|
|
1053
|
+
VERIFY_BASE_URL=f"http://127.0.0.1:{port}",
|
|
971
1054
|
)
|
|
972
1055
|
effort_level = _effort.resolve_effort(
|
|
973
1056
|
phase=66, complexity="", issue_labels=[], retry_count=attempt
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/prompts/__init__.py
RENAMED
|
@@ -68,6 +68,9 @@ PLACEHOLDER_SPEC: dict[str, frozenset[str]] = {
|
|
|
68
68
|
"AGENT_SPEC_PATH",
|
|
69
69
|
"TIERS_ACTIVE",
|
|
70
70
|
"TIERS_SKIPPED",
|
|
71
|
+
# Ephemeral verify-port isolation: the exact host:port the
|
|
72
|
+
# orchestrator probes; the repair agent must bind precisely this.
|
|
73
|
+
"VERIFY_BASE_URL",
|
|
71
74
|
}
|
|
72
75
|
),
|
|
73
76
|
"prompt-phase-7-commit.md": frozenset(
|
|
@@ -14,6 +14,8 @@ Verification runs in five tiers, lightest first; each is a hard gate on the next
|
|
|
14
14
|
- **T0 — Build.** Run the canonical build command for the detected stack. Compile errors here block T1.
|
|
15
15
|
- **T1 — Boot smoke.** Start the application or its main entry point. Watch for crash-on-boot, missing dependencies, unreachable migrations, or import-time errors. Time-bound: a successful boot is detected by either an explicit "ready" log line or the process surviving for `BOOT_SMOKE_WINDOW_SECONDS` (default 8 seconds) without exiting.
|
|
16
16
|
- **T2 — API contract.** When the project exposes HTTP routes, replay the acceptance-criteria endpoint list against the running service from T1. Each route must return its documented status code; response-shape checks are advisory unless the criterion specifies them.
|
|
17
|
+
|
|
18
|
+
> **Mandatory bind address.** The orchestrator runs its own authoritative T2 probe against **exactly** the URL in `{VERIFY_BASE_URL}` (see `## Volatile Context`) — nothing else. The service you boot in T1 **must listen on that exact host and port**. Do not invent your own port, do not "pick a free one", do not switch the host. A self-reported `=== TIER 2: PASS ===` against any other port is meaningless: the orchestrator only sees `{VERIFY_BASE_URL}`, so a different port is an automatic T2 failure no matter what your local curl shows.
|
|
17
19
|
- **T3 — Browser end-to-end (Playwright MCP).** When the project ships a frontend, drive the running app through the Playwright MCP server. Execute every acceptance flow grouped under the relevant `## Scope` subsection. On any scenario failure, persist a screenshot to `.code-generator/screenshots/<scenario>.png`, drain the browser console messages, and attach both to the failure report. Skip cleanly with a single-line reason when no frontend is in scope.
|
|
18
20
|
- **T4 — Container lifecycle.** When the project ships `docker-compose.yml`, `docker-compose.yaml`, or a bare `Dockerfile`, bring the container(s) up (`docker compose up -d --build` or `docker build && docker run`), wait for the health endpoint, replay the T2 contract suite against the containerized service, then tear down via `try/finally` on every code path. Skip cleanly with a logged reason when no docker manifest exists.
|
|
19
21
|
|
|
@@ -27,7 +29,7 @@ Verification runs in five tiers, lightest first; each is a hard gate on the next
|
|
|
27
29
|
|
|
28
30
|
2. **Emit a tier plan.** Before running anything, write a short plan covering:
|
|
29
31
|
- T0 build command (string, no chaining).
|
|
30
|
-
- T1 entry-point command
|
|
32
|
+
- T1 entry-point command. It **must bind the exact host and port in `{VERIFY_BASE_URL}`** (e.g. `--host 127.0.0.1 --port <that-port>`), plus the readiness signal (log substring or, by default, the boot-window timer). The port is not yours to choose — it is fixed by `{VERIFY_BASE_URL}` and the persisted `AgentSpec`.
|
|
31
33
|
- T2 endpoint list: one row per `(METHOD, PATH, EXPECTED_STATUS)` extracted from the acceptance criteria. When no HTTP routes are extractable, mark T2 as `SKIP` — this is not a failure.
|
|
32
34
|
|
|
33
35
|
3. **Run the tiers.** For each tier in order:
|
|
@@ -56,6 +58,7 @@ Verification runs in five tiers, lightest first; each is a hard gate on the next
|
|
|
56
58
|
- **Do not modify or delete tests added by Phase 6.** The unit tests are now part of the contract; if a test fails after a repair edit, the patch is wrong, not the test.
|
|
57
59
|
- **Never touch `state.json`.** It is owned by the orchestrator and made read-only during your run.
|
|
58
60
|
- **Never touch `.code-generator/checklists/`.** Tick decisions are computed in Python from your exit code, not by editing the JSON.
|
|
61
|
+
- **Bind the exact `{VERIFY_BASE_URL}` host:port.** This is non-negotiable and overrides any port in `requirements.md`, a Dockerfile, or your own judgement. The orchestrator's authoritative probe hits only `{VERIFY_BASE_URL}`; a service on any other port fails T2 regardless of local curl output. If the app cannot bind that port, fix the app's port configuration (env var, CLI flag, settings) — never relocate the service to a different port to make a local check pass.
|
|
59
62
|
- **Run long-running daemons in the background** — wrap them with `nohup`, `&`, or an equivalent so the verification harness can reclaim the shell, and tear them down via the PID you captured.
|
|
60
63
|
- Stay inside the tiered loop: do not escalate effort by editing this prompt or invoking other agents.
|
|
61
64
|
- Keep repairs minimal — edit the smallest scope that fixes the failing tier; refactors are out of scope here.
|
|
@@ -79,7 +82,7 @@ A first-attempt run on a FastAPI project where T0 passes and T1 fails:
|
|
|
79
82
|
<example>
|
|
80
83
|
Tier plan:
|
|
81
84
|
T0: pip install -e .
|
|
82
|
-
T1: uvicorn app.main:app --port
|
|
85
|
+
T1: uvicorn app.main:app --host 127.0.0.1 --port <VERIFY_BASE_URL port> (ready = "Application startup complete" or 8s window)
|
|
83
86
|
T2: GET /health -> 200; POST /items -> 201
|
|
84
87
|
T3: SKIP (no frontend)
|
|
85
88
|
T4: SKIP (no docker manifest)
|
|
@@ -101,6 +104,7 @@ Still red: T1 (and dependent T2). Repair this attempt; T3/T4 remain SKIP.
|
|
|
101
104
|
|
|
102
105
|
## Volatile Context
|
|
103
106
|
|
|
107
|
+
- **Mandatory bind address (orchestrator probes EXACTLY this, nothing else):** {VERIFY_BASE_URL}
|
|
104
108
|
- **Project directory:** {PROJECT_DIR}
|
|
105
109
|
- **Requirements file:** {REQUIREMENTS_MD}
|
|
106
110
|
- **Detected stack:** {DETECTED_STACK}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Phase 6.5 ephemeral-port isolation (#1) and pre-flight port guard (#2).
|
|
2
|
+
|
|
3
|
+
Regression cover for the well-known-port collision that exhausted the
|
|
4
|
+
repair-retry budget: a co-resident ``chroma run`` (claude-mem plugin)
|
|
5
|
+
squatting ``:8000`` returned 404 to every health probe, so attempts 1+2
|
|
6
|
+
failed environmentally and attempt 3's real fix landed after the budget
|
|
7
|
+
was already spent. The fix moves verification onto an OS-assigned free
|
|
8
|
+
port and rerolls if that port is squatted before an attempt starts.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import socket
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from code_generator.orchestrator.agent_spec import load_agent_spec
|
|
18
|
+
from code_generator.orchestrator.phase6_5_verify import (
|
|
19
|
+
_alloc_free_port,
|
|
20
|
+
_ensure_verify_port,
|
|
21
|
+
_persist_spec_for_attempt,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
_LOGGER = logging.getLogger("test.phase6_5.port_isolation")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _make_project(tmp_path: Path) -> Path:
|
|
28
|
+
project_dir = tmp_path / "project"
|
|
29
|
+
(project_dir / ".code-generator").mkdir(parents=True)
|
|
30
|
+
(project_dir / ".code-generator" / "requirements.md").write_text(
|
|
31
|
+
"# Demo\n\n## Tech Stack\n\nFastAPI\n", encoding="utf-8"
|
|
32
|
+
)
|
|
33
|
+
return project_dir
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_alloc_free_port_returns_a_bindable_ephemeral_port() -> None:
|
|
37
|
+
port = _alloc_free_port()
|
|
38
|
+
assert 1024 < port < 65536
|
|
39
|
+
# Released back to the OS — re-bindable, proving it was genuinely free.
|
|
40
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
41
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
42
|
+
sock.bind(("127.0.0.1", port))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_persisted_spec_carries_ephemeral_port_not_8000(tmp_path: Path) -> None:
|
|
46
|
+
project_dir = _make_project(tmp_path)
|
|
47
|
+
port = _alloc_free_port()
|
|
48
|
+
|
|
49
|
+
_persist_spec_for_attempt(
|
|
50
|
+
project_dir, project_dir / ".code-generator" / "requirements.md", port
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
spec = load_agent_spec(project_dir / ".code-generator")
|
|
54
|
+
assert spec.base_url == f"http://127.0.0.1:{port}"
|
|
55
|
+
assert spec.base_url != "http://127.0.0.1:8000"
|
|
56
|
+
# Every tier that declares a port (T1) is rewritten to the free port —
|
|
57
|
+
# this is the field the SDK repair agent reads to boot the app.
|
|
58
|
+
ported = [t for t in spec.tiers if t.port is not None]
|
|
59
|
+
assert ported, "expected at least one tier with an explicit port (T1)"
|
|
60
|
+
assert all(t.port == port for t in ported)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_guard_passes_through_a_free_port() -> None:
|
|
64
|
+
port = _alloc_free_port()
|
|
65
|
+
assert _ensure_verify_port(port, logger=_LOGGER) == port
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_guard_rerolls_when_port_is_squatted(caplog) -> None:
|
|
69
|
+
"""A foreign listener on the chosen port → reroll, never reuse it.
|
|
70
|
+
|
|
71
|
+
This is the chroma-on-:8000 scenario in miniature: the guard must
|
|
72
|
+
hand back a *different*, free port so the squatter cannot fail a
|
|
73
|
+
tier and burn a retry.
|
|
74
|
+
"""
|
|
75
|
+
squatter = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
76
|
+
squatter.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
77
|
+
squatter.bind(("127.0.0.1", 0))
|
|
78
|
+
squatter.listen(1)
|
|
79
|
+
squatted_port = squatter.getsockname()[1]
|
|
80
|
+
try:
|
|
81
|
+
with caplog.at_level(logging.WARNING):
|
|
82
|
+
rerolled = _ensure_verify_port(squatted_port, logger=_LOGGER)
|
|
83
|
+
assert rerolled != squatted_port
|
|
84
|
+
assert 1024 < rerolled < 65536
|
|
85
|
+
assert "rerolled" in caplog.text
|
|
86
|
+
finally:
|
|
87
|
+
squatter.close()
|
|
@@ -20,6 +20,7 @@ _EXPECTED_PLACEHOLDERS = frozenset(
|
|
|
20
20
|
"AGENT_SPEC_PATH",
|
|
21
21
|
"TIERS_ACTIVE",
|
|
22
22
|
"TIERS_SKIPPED",
|
|
23
|
+
"VERIFY_BASE_URL",
|
|
23
24
|
}
|
|
24
25
|
)
|
|
25
26
|
|
|
@@ -37,6 +38,7 @@ def _valid_kwargs() -> dict[str, str]:
|
|
|
37
38
|
"AGENT_SPEC_PATH": "/tmp/proj/.code-generator/phase6_5_spec.json",
|
|
38
39
|
"TIERS_ACTIVE": "T0,T1,T2",
|
|
39
40
|
"TIERS_SKIPPED": "T3 (no frontend), T4 (no docker)",
|
|
41
|
+
"VERIFY_BASE_URL": "http://127.0.0.1:59568",
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompt_prefix_snapshots.py
RENAMED
|
@@ -82,6 +82,7 @@ PLACEHOLDER_SNAPSHOT_FIXTURES: dict[str, str] = {
|
|
|
82
82
|
"AGENT_SPEC_PATH": ".code-generator/phase6_5_spec.json",
|
|
83
83
|
"TIERS_ACTIVE": "T0,T1,T2",
|
|
84
84
|
"TIERS_SKIPPED": "",
|
|
85
|
+
"VERIFY_BASE_URL": "http://127.0.0.1:PORT",
|
|
85
86
|
"CI_LOGS": "",
|
|
86
87
|
"FAILING_JOBS": "",
|
|
87
88
|
"MAX_ATTEMPTS": "5",
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/tests/test_prompt_prefix_stability.py
RENAMED
|
@@ -175,6 +175,10 @@ _FIXTURES: dict[str, list[dict[str, str]]] = {
|
|
|
175
175
|
"AGENT_SPEC_PATH": "/tmp/proj-a/.code-generator/phase6_5_spec.json",
|
|
176
176
|
"TIERS_ACTIVE": "T0,T1,T2",
|
|
177
177
|
"TIERS_SKIPPED": "T3 (no frontend), T4 (no docker)",
|
|
178
|
+
# Identical across all three fixtures: VERIFY_BASE_URL appears in
|
|
179
|
+
# the cached prefix (T2 section), so the 2048-byte stability
|
|
180
|
+
# contract requires the same value in every variant.
|
|
181
|
+
"VERIFY_BASE_URL": "http://127.0.0.1:PORT",
|
|
178
182
|
},
|
|
179
183
|
{
|
|
180
184
|
"PROJECT_DIR": "/srv/proj-b",
|
|
@@ -188,6 +192,7 @@ _FIXTURES: dict[str, list[dict[str, str]]] = {
|
|
|
188
192
|
"AGENT_SPEC_PATH": "/srv/proj-b/.code-generator/phase6_5_spec.json",
|
|
189
193
|
"TIERS_ACTIVE": "T0,T1,T2,T4",
|
|
190
194
|
"TIERS_SKIPPED": "T3 (no frontend)",
|
|
195
|
+
"VERIFY_BASE_URL": "http://127.0.0.1:PORT",
|
|
191
196
|
},
|
|
192
197
|
{
|
|
193
198
|
"PROJECT_DIR": "/work/proj-c",
|
|
@@ -201,6 +206,7 @@ _FIXTURES: dict[str, list[dict[str, str]]] = {
|
|
|
201
206
|
"AGENT_SPEC_PATH": "/work/proj-c/.code-generator/phase6_5_spec.json",
|
|
202
207
|
"TIERS_ACTIVE": "T0,T3",
|
|
203
208
|
"TIERS_SKIPPED": "T4 (no docker)",
|
|
209
|
+
"VERIFY_BASE_URL": "http://127.0.0.1:PORT",
|
|
204
210
|
},
|
|
205
211
|
],
|
|
206
212
|
"prompt-phase-7-commit.md": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/archive_run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/__init__.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_bench_io.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_detect.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_dispatch.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/_resume.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/bench.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/generate.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/init.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/optimize.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/review.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/commands/status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/exceptions.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/__init__.py
RENAMED
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/actions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/gh/milestones.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/logging_setup.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_generator-0.6.1 → claude_code_generator-0.6.3}/src/code_generator/orchestrator/sica.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|