claude-code-conductor 2.72.0__tar.gz → 2.74.0__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_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/config-policy.md +28 -2
- claude_code_conductor-2.74.0/.claude/state/setup_done.flag +0 -0
- claude_code_conductor-2.74.0/.claude/tmp/.gitkeep +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.gitignore +8 -3
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/CHANGELOG.md +55 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/PKG-INFO +1 -1
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/pyproject.toml +18 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/__init__.py +1 -1
- claude_code_conductor-2.74.0/tests/__init__.py +0 -0
- claude_code_conductor-2.74.0/tests/_sync_semantics.py +421 -0
- claude_code_conductor-2.74.0/tests/hooks/__init__.py +0 -0
- claude_code_conductor-2.74.0/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_ci_workflows.py +124 -2
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_claude_gitignore.py +13 -2
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_scripts_src_bootstrap.py +5 -5
- claude_code_conductor-2.74.0/tests/test_three_file_sync.py +1318 -0
- claude_code_conductor-2.74.0/tests/test_verify_wheel.py +1939 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/.gitignore +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/design-critic.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/agents/wt_tester.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/breaking-changes.txt +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/deletions.txt +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/autonomous-mode-onboarding.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/nul-boundary.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/platform-adapters.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/_hook_utils.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/patterns_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/recall_autorebuild.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/report_contract_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/report_path_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/session_mode_watch.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/tier_autoapply.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/tier_gap_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.72.0/.claude/state → claude_code_conductor-2.74.0/.claude/memory/archive}/.gitkeep +0 -0
- /claude_code_conductor-2.72.0/tests/__init__.py → /claude_code_conductor-2.74.0/.claude/memory/sessions/.gitkeep +0 -0
- /claude_code_conductor-2.72.0/tests/hooks/__init__.py → /claude_code_conductor-2.74.0/.claude/reports/.gitkeep +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/rules/judgment-principles.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/settings.json +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/autonomous-mode/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/autonomous-mode/scripts/mode_line.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/brainstorm/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/codex-review/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/c3-omission-declaration.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/reachability-map.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/record-protocol.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/scripts/detect_execution_verification.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/init-session/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/init-session/scripts/session_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/start/SKILL.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/.claude/skills/start/scripts/archive_reports.py +0 -0
- /claude_code_conductor-2.72.0/tests/skills/__init__.py → /claude_code_conductor-2.74.0/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/ARCHITECTURE.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSES/numpy-LICENSE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/README.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/hatch_build.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/_db_params.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/adapters.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_ask.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_metrics.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_run.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/db.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/gitutil.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrate.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/001_initial.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/003_tier_cost.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/004_agent_outcomes.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/006_review_decisions_severity.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/007_review_decisions_resolution.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/008_drop_agent_runs.sql +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/README.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/migrations/__init__.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/pricing.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/question.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/refgraph.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/src/c3/usage_ingester.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/_pre_compact_helpers.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/conftest.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/fixtures/usage/README.md +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/fixtures/usage/mainline.jsonl +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_detect_execution_verification.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_hook_utils.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_recall_autorebuild.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_record_agent_outcome.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_report_path_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_settings_tier_autoapply_registration.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_tier_autoapply.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_tier_gap_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/hooks/test_tier_security_fixes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/_skill_helpers.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_c3_omission_declaration.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_e0_verification_exit.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_init_session_no_task_type.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_marker_compliance.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_parallel_agents_skill_tier.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_reachability_map.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_session_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_start_skill_new_flow.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_adapters.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_archive_reports.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_audit_review_decisions.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_check_deletions.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_ask.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_doctor.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_doctor_launcher.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_metrics.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_run.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_update_breaking_changes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_cli_update_deletions.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_db.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_db_connect_lint.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_extract_breaking_changes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_gitutil.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_hooks_stdin_idiom.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_init_only_patterns.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_migrate.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_mode_line.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_no_bare_python_launcher.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_no_passonly_tests.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_nul_boundary_lint.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_patterns_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_permission_handler_removal.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_pricing.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_refgraph.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_refgraph_query.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_refgraph_structural.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_report_contract_check.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_scripts_stdout_encoding.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_session_mode_watch.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_settings_hooks_registration.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_start_skill_archive_contract.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_stop_agent_memory_warn.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_usage_ingester.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_worktree_guard.py +0 -0
- {claude_code_conductor-2.72.0 → claude_code_conductor-2.74.0}/tests/test_wt_agent_sync.py +0 -0
|
@@ -280,17 +280,43 @@ C3 の wheel 配布除外パターンは **3 つのファイルに分散して
|
|
|
280
280
|
`hatch_build.py` の重複が必要な理由: hatch build hook はパッケージ import 前に走るため、
|
|
281
281
|
`_excludes.py` を import できない。2 ファイルの完全一致が必須。
|
|
282
282
|
|
|
283
|
+
**KEEP 対象が sdist exclude 配下にある場合は `pyproject.toml` の force-include も同期対象**:
|
|
284
|
+
公開ビルドは sdist を経由するため、sdist から落ちたファイルは wheel にも届かない。
|
|
285
|
+
|
|
286
|
+
この辺(KEEP ↔ sdist exclude / force-include)は `tests/test_three_file_sync.py` が双方向に機械検証する
|
|
287
|
+
(救済漏れと、用途不明な force-include キーの増殖の両方を検出する)。
|
|
288
|
+
ただし **KEEP に相当する配布必須ファイルは force-include による救済を認めず、ignore 規則そのもの(否定行)で戻す**
|
|
289
|
+
(force-include で救うと git 履歴から消える脆い救済になるため。force-include が担うのは sdist exclude 経路の救済に限る)。
|
|
290
|
+
この検査は**配布元 C3 のリポジトリ専用**である: 配布元 C3 が公開する wheel に `tests/` は含まれず、
|
|
291
|
+
利用先プロジェクトにこの検査は配置されない。ただし**配布元 C3 が PyPI へ公開する第二の成果物である
|
|
292
|
+
sdist には `tests/` が含まれる**(`pyproject.toml` の sdist `include`)。sdist は PyPI で公開されるため
|
|
293
|
+
`tests/` 配下の内容は第三者が閲覧可能であり、機密情報を書いてはならない。
|
|
294
|
+
|
|
283
295
|
### 同期確認の方法
|
|
284
296
|
|
|
285
297
|
`.dev/hooks/_sync_check.py`(PostToolUse hook)が、3 ファイルのいずれかを変更した時に
|
|
286
298
|
残り 2 ファイルの同期を `stderr` で警告する。警告が出たら必ず対応する。
|
|
287
299
|
|
|
300
|
+
同期の実効一致はテスト 2 本が機械検証する(hook の警告は編集時の即時注意喚起、テストは CI /
|
|
301
|
+
フルスイートでの機械判定という役割分担):
|
|
302
|
+
|
|
303
|
+
| テスト | 検証する辺 |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `tests/test_excludes.py` | `_excludes.py` ↔ `hatch_build.py`(パターン集合の完全一致) |
|
|
306
|
+
| `tests/test_three_file_sync.py` | `.gitignore` ↔ `_excludes.py`(挙動の一致)・`pyproject.toml` の sdist exclude / force-include |
|
|
307
|
+
|
|
308
|
+
これらのテストも**配布元 C3 のリポジトリ専用**である: 配布元 C3 が公開する wheel に `tests/` は
|
|
309
|
+
含まれず、利用先プロジェクトにこれらのテストは配置されない。ただし**配布元 C3 が PyPI へ公開する
|
|
310
|
+
第二の成果物である sdist には `tests/` が含まれる**(`pyproject.toml` の sdist `include`)。
|
|
311
|
+
sdist は PyPI で公開されるため `tests/` 配下の内容は第三者が閲覧可能であり、機密情報を書いてはならない。
|
|
312
|
+
|
|
288
313
|
### 変更手順
|
|
289
314
|
|
|
290
315
|
1. `.gitignore` / `_excludes.py` / `hatch_build.py` のいずれかを変更
|
|
291
316
|
2. `_sync_check.py` の警告を確認
|
|
292
|
-
3. 残り 2
|
|
293
|
-
4.
|
|
317
|
+
3. 残り 2 ファイルに同じパターンを追加(または削除)。3 ファイルが既に同じ意図を持っている場合は、出遅れた 1 ファイルを合わせるだけでよい(配布元の root `.gitignore` を `KEEP_PATTERNS` の意図へ合わせた 2026-08-14 の是正が実例)
|
|
318
|
+
4. 意図的差分(3 ファイルの意図をあえて揃えない例外)を増減する場合は、`tests/test_three_file_sync.py` の許容リスト(理由文字列必須)と件数定数群を同時更新する(配布元専用。増減いずれの場合もレビュー対象)
|
|
319
|
+
5. 配布元では `python scripts/verify_wheel.py` で wheel 実体を機械検証する(`scripts/` は配布物に含まれないため、利用先には存在しないコマンド)
|
|
294
320
|
|
|
295
321
|
### 過去の同期漏れ defect
|
|
296
322
|
|
|
File without changes
|
|
File without changes
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
!.claude/reports/.gitkeep
|
|
4
4
|
|
|
5
5
|
# Session memory (personal)
|
|
6
|
-
|
|
7
|
-
.
|
|
6
|
+
# ディレクトリ形除外(`dir/`)の中へ git は降りないため否定行が効かない。
|
|
7
|
+
# KEEP_PATTERNS(_excludes.py / hatch_build.py)は各ディレクトリの .gitkeep を
|
|
8
|
+
# 配布対象としているため、`dir/*` 形+否定行で .gitkeep だけを tracked にする。
|
|
9
|
+
.claude/memory/sessions/*
|
|
10
|
+
!.claude/memory/sessions/.gitkeep
|
|
11
|
+
.claude/memory/archive/*
|
|
8
12
|
!.claude/memory/archive/.gitkeep
|
|
9
13
|
.claude/memory/patterns.json
|
|
10
14
|
.claude/memory/agent-audit.log
|
|
@@ -15,7 +19,8 @@
|
|
|
15
19
|
.claude/agent-memory/
|
|
16
20
|
|
|
17
21
|
# Temporary files
|
|
18
|
-
.claude/tmp
|
|
22
|
+
.claude/tmp/*
|
|
23
|
+
!.claude/tmp/.gitkeep
|
|
19
24
|
|
|
20
25
|
# PO task execution logs
|
|
21
26
|
.claude/logs/
|
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.74.0] - 2026-08-15
|
|
4
|
+
|
|
5
|
+
### 追加
|
|
6
|
+
|
|
7
|
+
- **3 ファイル同期(`.gitignore` / `_excludes.py` / `pyproject.toml`)を機械検証化した**:
|
|
8
|
+
`tests/test_three_file_sync.py`(検査)と `tests/_sync_semantics.py`(検出器・引数注入の
|
|
9
|
+
純粋関数)を追加した。これまで `.dev/hooks/_sync_check.py` の警告(編集時の注意喚起)しか
|
|
10
|
+
無かった辺を、CI / フルスイートで機械判定する:
|
|
11
|
+
- 辺 1: `_excludes.py` の `EXCLUDE_PATTERNS` / `KEEP_PATTERNS` と root `.gitignore` の意図一致を、
|
|
12
|
+
表記の一致ではなく**挙動の一致**(プローブパス+`git check-ignore` の実挙動/`should_skip`)で
|
|
13
|
+
双方向に検証する
|
|
14
|
+
- 辺 2: `KEEP_PATTERNS` と `pyproject.toml` の sdist force-include を双方向に検証する
|
|
15
|
+
(救済漏れと、用途不明な force-include キーの増殖の両方を検出)
|
|
16
|
+
- 辺 3: sdist exclude の `.claude/` エントリが `should_skip` の意図と整合することを検証する
|
|
17
|
+
|
|
18
|
+
意図的差分は理由文字列必須の許容リストとして明示し、実効検査件数の下限・許容リスト件数を
|
|
19
|
+
凍結して「何も検査していないのに緑」になる退化を塞いでいる。
|
|
20
|
+
`.dev/hooks/_sync_check.py` は編集時の即時フィードバック層として存置する。
|
|
21
|
+
|
|
22
|
+
### 変更
|
|
23
|
+
|
|
24
|
+
- `/CLAUDE.md` §2 と `.claude/docs/config-policy.md` §6 に、上記の機械検証 2 本と
|
|
25
|
+
許容リスト・件数定数群の同時更新の運用を追記した(**配布元 C3 のリポジトリ専用の検査**である旨の
|
|
26
|
+
但し書き付き。配布元 C3 が公開する wheel に `tests/` は含まれず利用先プロジェクトには配置されないが、
|
|
27
|
+
配布元 C3 が PyPI へ公開する第二の成果物である sdist には `tests/` が含まれる。sdist は PyPI で
|
|
28
|
+
公開されるため `tests/` 配下の内容は第三者が閲覧可能であり、機密情報を書いてはならない)。
|
|
29
|
+
|
|
30
|
+
## [2.73.0] - 2026-08-15
|
|
31
|
+
|
|
32
|
+
### 追加
|
|
33
|
+
|
|
34
|
+
- **リリース前 wheel 実体検証を CI 機械化した**: `scripts/verify_wheel.py`(配布元専用 dev ツール・
|
|
35
|
+
wheel/sdist 非収録)を追加し、`.github/workflows/test.yml` に `wheel-check` job を新設した。
|
|
36
|
+
公開経路と同じビルド(sdist 経由)で作った wheel の中身が `src/c3/_excludes.py` の意図
|
|
37
|
+
(EXCLUDE 不混入・KEEP 全件存在・`breaking-changes.txt` 在/`state/c3_version.txt` 不在)と
|
|
38
|
+
一致するかを毎 push 検証する。exit code は 0 = PASS / 1 = 違反 / 3 = 検証不能。
|
|
39
|
+
「除外フィルタが実際には何も落としていないのに緑」になるのを防ぐため、
|
|
40
|
+
`.claude/state/setup_done.flag` を sdist にだけ注入する正の対照を組み込んでいる。
|
|
41
|
+
- sdist(第二の公開成果物)側の EXCLUDE 混入検査と対照サイズ検査を追加
|
|
42
|
+
(違反種別 `SDIST_EXCLUDE_VIOLATION` / `CONTROL_NOT_EMPTY`)。違反 detail のサニタイズは
|
|
43
|
+
正本 `.claude/hooks/_hook_utils.py` の `_TERMINAL_SANITIZE_RE` と同一の全クラス
|
|
44
|
+
(C0/DEL/C1・ゼロ幅・行区切り・双方向制御・BOM)へ被覆拡張し、sdist member は
|
|
45
|
+
種別(file/link/dir)で検査対象を振り分ける(EXCLUDE 名前検査は file+link・
|
|
46
|
+
候補件数の母数と対照系検査は file のみ・dir は全検査の対象外)。
|
|
47
|
+
|
|
48
|
+
### 修正
|
|
49
|
+
|
|
50
|
+
- **KEEP 対象の `.gitkeep` が公開 wheel に届いていなかった問題を是正した**: `KEEP_PATTERNS` が
|
|
51
|
+
配布対象と定めている `.claude/memory/sessions/.gitkeep` と `.claude/tmp/.gitkeep` を新規作成し、
|
|
52
|
+
root `.gitignore` のディレクトリ形除外(否定行が効かない形)を `dir/*` 形+否定行へ直した。
|
|
53
|
+
この是正により、既存の `.claude/memory/archive/.gitkeep` も新たに git 追跡対象になった。
|
|
54
|
+
あわせて `pyproject.toml` の sdist force-include で `reports/.gitkeep` /
|
|
55
|
+
`memory/sessions/.gitkeep` / `tmp/.gitkeep` を救済し、sdist 経由の公開 wheel に KEEP 8 件が
|
|
56
|
+
すべて入るようにした(これまでの公開 wheel は `reports/.gitkeep` 等を欠いていた)。
|
|
57
|
+
|
|
3
58
|
## [2.72.0] - 2026-08-14
|
|
4
59
|
|
|
5
60
|
### 破壊的変更
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: claude-code-conductor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.74.0
|
|
4
4
|
Summary: Multi-agent orchestration framework for Claude Code with Codex/Cursor adapters (C3)
|
|
5
5
|
Project-URL: Homepage, https://github.com/satoh-y-0323/claude-code-conductor
|
|
6
6
|
Project-URL: Repository, https://github.com/satoh-y-0323/claude-code-conductor
|
|
@@ -72,6 +72,24 @@ exclude = [
|
|
|
72
72
|
".claude/docs/taxonomy.md",
|
|
73
73
|
]
|
|
74
74
|
|
|
75
|
+
# 公開ビルドは `python -m build`(引数なし)= sdist を作り、その sdist から wheel を作る。
|
|
76
|
+
# 上の exclude / VCS ignore で落ちるが sdist に入れなければならないファイルをここで救済する。
|
|
77
|
+
# **役割が逆向きの 2 群**が同居しているので取り違えないこと。
|
|
78
|
+
#
|
|
79
|
+
# 群 1: KEEP 救済(wheel に **残る** べき側)
|
|
80
|
+
# `_excludes.py` / `hatch_build.py` の KEEP_PATTERNS が配布対象と定めている .gitkeep。
|
|
81
|
+
# sdist exclude に該当して落ちると、sdist 経由の wheel から KEEP が欠落する。
|
|
82
|
+
# 群 2: 注入対照(wheel で **落ちる** べき側)
|
|
83
|
+
# `state/setup_done.flag` は VCS ignore(root `.gitignore` の `.claude/state/*`)で
|
|
84
|
+
# sdist から落ちるが、これが無いと除外フィルタが実際に通過する候補が 0 件になり
|
|
85
|
+
# 「空の緑」(何も落とさずに緑)になる。sdist にだけ入れ、wheel ビルド時に
|
|
86
|
+
# hatch_build の should_skip が `state/*` で落とすことを scripts/verify_wheel.py が検証する。
|
|
87
|
+
[tool.hatch.build.targets.sdist.force-include]
|
|
88
|
+
".claude/reports/.gitkeep" = ".claude/reports/.gitkeep"
|
|
89
|
+
".claude/memory/sessions/.gitkeep" = ".claude/memory/sessions/.gitkeep"
|
|
90
|
+
".claude/tmp/.gitkeep" = ".claude/tmp/.gitkeep"
|
|
91
|
+
".claude/state/setup_done.flag" = ".claude/state/setup_done.flag"
|
|
92
|
+
|
|
75
93
|
[tool.pytest.ini_options]
|
|
76
94
|
testpaths = ["tests"]
|
|
77
95
|
markers = ["slow: marks tests as slow"]
|
|
File without changes
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""3 ファイル同期(``.gitignore`` / ``_excludes.py`` / ``pyproject.toml``)の検出器.
|
|
2
|
+
|
|
3
|
+
``tests/test_three_file_sync.py`` の被テスト実装。pytest には収集されない
|
|
4
|
+
(ファイル名が ``test_`` で始まらない)。先例: ``tests/_pre_compact_helpers.py``。
|
|
5
|
+
|
|
6
|
+
設計の正本: architecture-report-20260815-164137.md(改訂 5・最終)
|
|
7
|
+
+ requirements-report-20260815-164117.md(改訂 3)。
|
|
8
|
+
戻り値・型・カテゴリ語彙の凍結は ``tests/test_three_file_sync.py`` 冒頭の
|
|
9
|
+
設計判断メモ(tester が正本)に従う。
|
|
10
|
+
|
|
11
|
+
本モジュールの関数はすべて**引数注入の純粋関数**である: ファイル I/O をせず、
|
|
12
|
+
``git`` を呼ばず、``c3._excludes`` を import しない。実物(root ``.gitignore``・
|
|
13
|
+
``pyproject.toml``・``c3._excludes``・``git check-ignore`` の実挙動)の供給は
|
|
14
|
+
呼び出し側(テストモジュール)の責務であり、判定関数(``check_ignore_fn`` /
|
|
15
|
+
``should_skip_fn``)と導出関数(``derive_probe`` / ``normalize``)は引数として
|
|
16
|
+
注入される。これにより負の対照(同期漏れ・do-nothing スタブ)を実ファイルを
|
|
17
|
+
変異させずに実行できる(ADR-4)。
|
|
18
|
+
|
|
19
|
+
戻り値は**全判定レコード列**(``Verdict``)であり、違反専用の戻り値ではない。
|
|
20
|
+
関数名は ``find_*_violations`` のままだが、**違反の取得は結果フィルタ経由に限る**
|
|
21
|
+
(``assert not find_...(...)`` の形は誤り・ADR-9 再改訂 / DC-AM-004)。
|
|
22
|
+
許容リストに当たった対象も ``allowlisted=True`` のレコードとして**残す**
|
|
23
|
+
(残さない実装は契約違反)。導出関数が ``None`` を返した対象にはレコードを作らない。
|
|
24
|
+
|
|
25
|
+
--------------------------------------------------------------------------
|
|
26
|
+
docstring 記載義務 ①: 辺 1 の測定射程
|
|
27
|
+
--------------------------------------------------------------------------
|
|
28
|
+
辺 1 が測るのは「root ``.gitignore`` の意図と ``_excludes.py`` の意図の一致」であり、
|
|
29
|
+
配布元リポジトリでの git の最終判定ではない(実挙動は root と ``.claude/.gitignore``
|
|
30
|
+
〔配布物・ネストが深い側が優先〕の合成で決まる)。合成状態での判定を課すのは
|
|
31
|
+
**KEEP の not-ignored だけ**であり、EXCLUDE 側には合成判定を課さない
|
|
32
|
+
(deeper 側が広く除外していても root の意図一致とは独立のため)。
|
|
33
|
+
``.claude/.gitignore`` は**検証対象ではなく合成判定の入力**である
|
|
34
|
+
(requirements 改訂 2 §4 但し書き)。
|
|
35
|
+
判定は**ユーザー全体設定(``core.excludesFile``)と init テンプレート由来
|
|
36
|
+
(``.git/info/exclude``)の両方を排して隔離**した一時リポジトリで行う
|
|
37
|
+
(呼び出し側が ``git -c core.excludesFile= check-ignore`` の形+``git init`` 直後の
|
|
38
|
+
``.git/info/exclude`` 空上書きで隔離する・DC-AS-002)。
|
|
39
|
+
|
|
40
|
+
--------------------------------------------------------------------------
|
|
41
|
+
docstring 記載義務 ⑤: 件数運用
|
|
42
|
+
--------------------------------------------------------------------------
|
|
43
|
+
件数の正本は ``tests/test_three_file_sync.py`` の件数定数群。増減いずれの場合も
|
|
44
|
+
理由文字列とセットでレビューする(DC-AM-003 / ADR-10)。実効検査件数は
|
|
45
|
+
「当該由来カテゴリかつ許容リスト適用 False のレコード件数」、許容リスト件数は
|
|
46
|
+
「適用 True のレコード件数」で数える。更新せずに実データだけ変えると赤になるのは
|
|
47
|
+
仕様(黙って通さないための番兵)である。
|
|
48
|
+
|
|
49
|
+
--------------------------------------------------------------------------
|
|
50
|
+
docstring 記載義務 ⑦: docs/spec 凍結乖離の記録
|
|
51
|
+
--------------------------------------------------------------------------
|
|
52
|
+
``docs/spec/06-distribution.md:67, 332-348``・``00-index.md:125`` は本検査の導入で
|
|
53
|
+
失効するが 2026-08-05 凍結裁定により意図的に未更新(本文を編集しないのが正・ADR-11)。
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
from __future__ import annotations
|
|
57
|
+
|
|
58
|
+
import fnmatch
|
|
59
|
+
from collections.abc import Callable, Container, Iterable
|
|
60
|
+
from typing import NamedTuple
|
|
61
|
+
|
|
62
|
+
# プローブ名(literal 確定・DC-GP-005)。グロブ ``*`` とディレクトリ形の 1 段補いに使う。
|
|
63
|
+
PROBE_NAME = "__sync_probe__"
|
|
64
|
+
CLAUDE_PREFIX = ".claude/"
|
|
65
|
+
|
|
66
|
+
# 由来カテゴリの語彙 8 種(architecture 改訂 5 §3)
|
|
67
|
+
CATEGORY_EXCLUDE = "EXCLUDE"
|
|
68
|
+
CATEGORY_KEEP = "KEEP"
|
|
69
|
+
CATEGORY_KEEP_COMPOSITE = "合成KEEP"
|
|
70
|
+
CATEGORY_CLAUDE_LINE = "claude行"
|
|
71
|
+
CATEGORY_UNIVERSAL = "全体パターン"
|
|
72
|
+
CATEGORY_EDGE2_RESCUE = "辺2救済"
|
|
73
|
+
CATEGORY_EDGE2_CLASSIFY = "辺2分類"
|
|
74
|
+
CATEGORY_EDGE3 = "辺3"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Verdict(NamedTuple):
|
|
78
|
+
"""判定レコード(必須 5 フィールド・ADR-9 再改訂).
|
|
79
|
+
|
|
80
|
+
- ``subject``: 対象(プローブ相対パスまたは force-include キー)
|
|
81
|
+
- ``expected``: 課した期待
|
|
82
|
+
- ``actual``: 判定結果
|
|
83
|
+
- ``allowlisted``: 許容リスト適用の有無
|
|
84
|
+
- ``category``: 由来カテゴリ(本モジュールの ``CATEGORY_*`` 8 種のいずれか)
|
|
85
|
+
|
|
86
|
+
違反は ``actual != expected and not allowlisted``。この判定は呼び出し側の
|
|
87
|
+
結果フィルタで行う(本モジュールは違反専用の戻り値を持たない)。
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
subject: str
|
|
91
|
+
expected: bool
|
|
92
|
+
actual: bool
|
|
93
|
+
allowlisted: bool
|
|
94
|
+
category: str
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# プローブ導出(P1)
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _replace_glob_with_probe(s: str) -> str:
|
|
103
|
+
"""グロブ ``*`` をプローブ名 ``__sync_probe__`` へ置換する(導出 3 関数の共通部分).
|
|
104
|
+
|
|
105
|
+
切り出しの射程は**グロブ置換のみ**であり、``.claude/`` プレフィックスの付与・剥離は
|
|
106
|
+
各導出関数に残す(方向〔付与 / 剥離〕も戻り値型も関数ごとに異なるため・CR-M-001)。
|
|
107
|
+
公開 API・挙動は不変。
|
|
108
|
+
"""
|
|
109
|
+
return s.replace("*", PROBE_NAME)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def derive_probe_from_pattern(pattern: str) -> str | None:
|
|
113
|
+
"""``EXCLUDE_PATTERNS`` / ``KEEP_PATTERNS`` のパターン → プローブパス.
|
|
114
|
+
|
|
115
|
+
グロブ ``*`` はプローブ名 ``__sync_probe__`` へ置換し、リテラルはそのまま、
|
|
116
|
+
先頭に ``.claude/`` を付す(例: ``reports/*`` →
|
|
117
|
+
``.claude/reports/__sync_probe__``)。プローブの実体は作らない
|
|
118
|
+
(``git check-ignore`` はパス実在を要求しない・ADR-6。D-1 で実測固定済み)。
|
|
119
|
+
"""
|
|
120
|
+
return CLAUDE_PREFIX + _replace_glob_with_probe(pattern)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def derive_probe_from_gitignore_line(line: str) -> tuple[str, bool] | None:
|
|
124
|
+
"""root ``.gitignore`` の 1 行 → ``(プローブ相対パス, 否定行か)``.
|
|
125
|
+
|
|
126
|
+
戻り値は ``tuple[str, bool] | None``。**コメント / 空行 / ``.claude/`` 外の行は
|
|
127
|
+
``None``**。否定行(``!.claude/...``)は ``(プローブ, True)`` を返す
|
|
128
|
+
(改訂 1 §2-1 手順 1 の「対象外」列挙に含まれる否定行は**抽出段階**の話であり、
|
|
129
|
+
本関数の戻り値契約ではない・DC-AM-002)。
|
|
130
|
+
|
|
131
|
+
プローブは ``.claude/`` プレフィックスを剥がし、ディレクトリ形(末尾 ``/``)は
|
|
132
|
+
プローブ名を 1 段補い、``dir/*`` 形はグロブをプローブ名へ置換し、リテラルは
|
|
133
|
+
そのままとする(例: ``.claude/agent-memory/`` → ``agent-memory/__sync_probe__``・
|
|
134
|
+
``.claude/memory/patterns.json`` → ``memory/patterns.json``)。
|
|
135
|
+
"""
|
|
136
|
+
entry = line.strip()
|
|
137
|
+
if not entry or entry.startswith("#"):
|
|
138
|
+
return None
|
|
139
|
+
negated = entry.startswith("!")
|
|
140
|
+
if negated:
|
|
141
|
+
entry = entry[1:]
|
|
142
|
+
if not entry.startswith(CLAUDE_PREFIX):
|
|
143
|
+
return None
|
|
144
|
+
rel = entry[len(CLAUDE_PREFIX) :]
|
|
145
|
+
if not rel:
|
|
146
|
+
return None
|
|
147
|
+
if rel.endswith("/"):
|
|
148
|
+
rel += PROBE_NAME
|
|
149
|
+
else:
|
|
150
|
+
rel = _replace_glob_with_probe(rel)
|
|
151
|
+
return rel, negated
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _derive_probe_from_sdist_entry(entry: str) -> str | None:
|
|
155
|
+
"""正規化済み sdist exclude エントリ → プローブ相対パス(辺 3 の内部既定).
|
|
156
|
+
|
|
157
|
+
``.claude/`` 外のエントリは ``None``(辺 3 の射程は ``.claude/`` エントリのみ)。
|
|
158
|
+
正規化でディレクトリ形は ``dir/*`` になっているため、ここではグロブ置換のみで
|
|
159
|
+
方向 B と同じ「1 段補い」の結果になる。
|
|
160
|
+
"""
|
|
161
|
+
if not entry.startswith(CLAUDE_PREFIX):
|
|
162
|
+
return None
|
|
163
|
+
rel = entry[len(CLAUDE_PREFIX) :]
|
|
164
|
+
if not rel:
|
|
165
|
+
return None
|
|
166
|
+
return _replace_glob_with_probe(rel)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ---------------------------------------------------------------------------
|
|
170
|
+
# 正規化(ADR-8 改訂)
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def normalize_sdist_exclude_entry(entry: str) -> str:
|
|
175
|
+
"""sdist exclude エントリを判定形式へ正規化する(辺 2・辺 3 共通).
|
|
176
|
+
|
|
177
|
+
受理して正規化する形式は 3 つ:
|
|
178
|
+
|
|
179
|
+
- リテラル(グロブなし)… そのまま
|
|
180
|
+
- ``dir/*`` 形(末尾セグメントが ``*`` のみ)… そのまま
|
|
181
|
+
- ディレクトリ形 ``dir/`` … ``dir/*`` 相当へ正規化する
|
|
182
|
+
|
|
183
|
+
docstring 記載義務 ⑥(正規化関数と辺 3 導出の整合): **ディレクトリ形は辺 2 の
|
|
184
|
+
正規化と辺 3 のプローブ導出(方向 B と同じ規則)で同じ 1 段補いになる**
|
|
185
|
+
(``dir/`` → ``dir/*`` → ``dir/__sync_probe__``)。
|
|
186
|
+
|
|
187
|
+
上記 3 形に該当しないもの(``**`` を含む・先頭 ``/``・``!`` 否定・空文字・
|
|
188
|
+
その他)は**正規化規則を持たない形式**として fail-loud で ``ValueError`` を
|
|
189
|
+
送出する(サイレント近似を許さない=検査の想定更新を要求する)。
|
|
190
|
+
"""
|
|
191
|
+
if not isinstance(entry, str) or not entry:
|
|
192
|
+
raise ValueError(f"sdist exclude エントリが空または文字列でない: {entry!r}")
|
|
193
|
+
if "**" in entry:
|
|
194
|
+
raise ValueError(f"正規化規則を持たない形式(`**` を含む): {entry!r}")
|
|
195
|
+
if entry.startswith("/"):
|
|
196
|
+
raise ValueError(f"正規化規則を持たない形式(先頭 `/`): {entry!r}")
|
|
197
|
+
if entry.startswith("!"):
|
|
198
|
+
raise ValueError(f"正規化規則を持たない形式(`!` 否定): {entry!r}")
|
|
199
|
+
if entry.endswith("/"):
|
|
200
|
+
if "*" in entry:
|
|
201
|
+
raise ValueError(f"正規化規則を持たない形式(ディレクトリ形にグロブ): {entry!r}")
|
|
202
|
+
return entry + "*"
|
|
203
|
+
if "*" not in entry:
|
|
204
|
+
return entry
|
|
205
|
+
if entry.endswith("/*") and "*" not in entry[:-1]:
|
|
206
|
+
return entry
|
|
207
|
+
raise ValueError(f"正規化規則を持たない形式(想定外のグロブ): {entry!r}")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# ---------------------------------------------------------------------------
|
|
211
|
+
# 辺 1 方向 A(+ P2b 合成 KEEP / P2c 全体パターン git 側の再利用)
|
|
212
|
+
# ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def find_gitignore_intent_violations(
|
|
216
|
+
exclude_patterns: Iterable[str],
|
|
217
|
+
keep_patterns: Iterable[str],
|
|
218
|
+
check_ignore_fn: Callable[[str], bool],
|
|
219
|
+
allowlist_a: Container[str],
|
|
220
|
+
*,
|
|
221
|
+
derive_probe: Callable[[str], str | None] = derive_probe_from_pattern,
|
|
222
|
+
category_exclude: str = CATEGORY_EXCLUDE,
|
|
223
|
+
category_keep: str = CATEGORY_KEEP,
|
|
224
|
+
) -> list[Verdict]:
|
|
225
|
+
"""辺 1 方向 A(``_excludes.py`` の意図 → git が同じ扱いをするか).
|
|
226
|
+
|
|
227
|
+
EXCLUDE パターンのプローブは ignored 期待(``expected=True``)、KEEP パターンの
|
|
228
|
+
プローブは not-ignored 期待(``expected=False``)。``allowlist_a`` に載っている
|
|
229
|
+
**パターン**から導いたレコードは ``allowlisted=True`` になり、期待に反していても
|
|
230
|
+
違反にならない(レコード自体は残す)。
|
|
231
|
+
|
|
232
|
+
``check_ignore_fn`` の判定契約(ADR-6): 呼び出し側は ``git check-ignore`` の
|
|
233
|
+
returncode 0 を ignored(True)・1 を not ignored(False)とし、それ以外
|
|
234
|
+
(128 等)は検証不能として fail-loud(例外送出)にする。本関数はその真偽値を
|
|
235
|
+
そのままレコードの ``actual`` にする。
|
|
236
|
+
|
|
237
|
+
**測定射程(記載義務 ①)**: 測るのは root ``.gitignore`` の意図と
|
|
238
|
+
``_excludes.py`` の意図の一致であり、配布元での git の最終判定ではない。
|
|
239
|
+
``.claude/.gitignore`` は検証対象ではなく、KEEP 合成判定(P2b)の**入力**として
|
|
240
|
+
のみ用いる(requirements 改訂 2 §4 但し書き)。合成判定を課すのは KEEP の
|
|
241
|
+
not-ignored だけで EXCLUDE には課さない。判定はユーザー全体設定
|
|
242
|
+
(``core.excludesFile``)と init テンプレート由来(``.git/info/exclude``)の
|
|
243
|
+
両方を排して隔離した一時リポジトリで行う。
|
|
244
|
+
|
|
245
|
+
**KEEP の VCS ignore 救済を認めない禁止規範(記載義務 ②・ADR-7 再改訂)**:
|
|
246
|
+
KEEP は VCS ignore で落ちてはならない。``force-include`` による KEEP の救済は
|
|
247
|
+
認めない(git 履歴から消える脆い救済になるため)。KEEP を ignore している
|
|
248
|
+
``.gitignore`` は root と ``.claude/.gitignore`` のどちらでもありうる(git は
|
|
249
|
+
よりネストの深い側を優先し root から取り消せない)ため、**是正は ignore の
|
|
250
|
+
出所側の否定行で戻す**。出所が ``.claude/.gitignore``(配布物)の場合、その編集は
|
|
251
|
+
本スライスのスコープ外=debug-needed で申告し別スライスで扱う。
|
|
252
|
+
なお辺 2 逆方向の分類名「KEEP 救済」は **sdist exclude 経路の救済**を指す語であり、
|
|
253
|
+
ここで禁止している「VCS ignore で落ちた KEEP の force-include 救済」とは別物である
|
|
254
|
+
(2 検査の判定が割れないための語彙の書き分け)。
|
|
255
|
+
|
|
256
|
+
P2b(KEEP 合成判定)と P2c(全体パターン git 側)は、``exclude_patterns`` /
|
|
257
|
+
``keep_patterns`` / ``category_exclude`` / ``category_keep`` / ``check_ignore_fn``
|
|
258
|
+
を差し替えた**別呼び出し**として本関数を再利用する(新関数を作らない)。
|
|
259
|
+
"""
|
|
260
|
+
records: list[Verdict] = []
|
|
261
|
+
for patterns, expected, category in (
|
|
262
|
+
(exclude_patterns, True, category_exclude),
|
|
263
|
+
(keep_patterns, False, category_keep),
|
|
264
|
+
):
|
|
265
|
+
for pattern in patterns:
|
|
266
|
+
probe = derive_probe(pattern)
|
|
267
|
+
if probe is None:
|
|
268
|
+
continue
|
|
269
|
+
records.append(
|
|
270
|
+
Verdict(
|
|
271
|
+
subject=probe,
|
|
272
|
+
expected=expected,
|
|
273
|
+
actual=bool(check_ignore_fn(probe)),
|
|
274
|
+
allowlisted=pattern in allowlist_a,
|
|
275
|
+
category=category,
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
return records
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# ---------------------------------------------------------------------------
|
|
282
|
+
# 辺 1 方向 B
|
|
283
|
+
# ---------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def find_gitignore_line_violations(
|
|
287
|
+
gitignore_lines: Iterable[str],
|
|
288
|
+
should_skip_fn: Callable[[str], bool],
|
|
289
|
+
allowlist_b: Container[str],
|
|
290
|
+
*,
|
|
291
|
+
derive_probe: Callable[[str], tuple[str, bool] | None] = derive_probe_from_gitignore_line,
|
|
292
|
+
category: str = CATEGORY_CLAUDE_LINE,
|
|
293
|
+
) -> list[Verdict]:
|
|
294
|
+
"""辺 1 方向 B(root ``.gitignore`` の ``.claude/`` 行 → ``should_skip`` の一致).
|
|
295
|
+
|
|
296
|
+
非否定行のプローブは ``should_skip`` True 期待(git が個人状態として捨てるものは
|
|
297
|
+
wheel からも落ちる)、否定行のプローブは False 期待(KEEP 対応の確認)。
|
|
298
|
+
``allowlist_b`` に載っている**プローブ**のレコードは ``allowlisted=True`` になり、
|
|
299
|
+
期待に反していても違反にならない(レコード自体は残す)。
|
|
300
|
+
|
|
301
|
+
**限界(記載義務 ④)**: 本検査が測るのは ``.claude/`` 配下の行のみである。
|
|
302
|
+
リポジトリ全体パターンについては、``should_skip`` が特別分岐で扱う 3 種
|
|
303
|
+
(``__pycache__`` / ``*.pyc`` / ``*.pyo``)に対応するプローブを ``.claude/`` 配下の
|
|
304
|
+
行として与えた場合の対応だけを測る。**それ以外の全体パターン**
|
|
305
|
+
(``.pytest_cache/`` / ``build/`` / ``*.egg-info/`` 等)**とアンカー形は射程外**で
|
|
306
|
+
あり、``should_skip`` に対応分岐が無いことと併せてここに限界として記す。
|
|
307
|
+
"""
|
|
308
|
+
records: list[Verdict] = []
|
|
309
|
+
for line in gitignore_lines:
|
|
310
|
+
derived = derive_probe(line)
|
|
311
|
+
if derived is None:
|
|
312
|
+
continue
|
|
313
|
+
probe, negated = derived
|
|
314
|
+
records.append(
|
|
315
|
+
Verdict(
|
|
316
|
+
subject=probe,
|
|
317
|
+
expected=not negated,
|
|
318
|
+
actual=bool(should_skip_fn(probe)),
|
|
319
|
+
allowlisted=probe in allowlist_b,
|
|
320
|
+
category=category,
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
return records
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# ---------------------------------------------------------------------------
|
|
327
|
+
# 辺 2(KEEP ↔ sdist force-include・双方向)
|
|
328
|
+
# ---------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def find_force_include_violations(
|
|
332
|
+
keep_patterns: Iterable[str],
|
|
333
|
+
sdist_exclude: Iterable[str],
|
|
334
|
+
force_include_keys: Iterable[str],
|
|
335
|
+
injection_controls: Container[str],
|
|
336
|
+
*,
|
|
337
|
+
normalize: Callable[[str], str] = normalize_sdist_exclude_entry,
|
|
338
|
+
) -> list[Verdict]:
|
|
339
|
+
"""辺 2 双方向(``KEEP_PATTERNS`` ↔ ``pyproject.toml`` の sdist force-include).
|
|
340
|
+
|
|
341
|
+
- 救済要求(``辺2救済``): ``.claude/`` を付した KEEP パスが正規化後の sdist
|
|
342
|
+
``exclude`` のいずれかに一致する場合、その ``.claude/`` 付きリテラルパスが
|
|
343
|
+
``force-include`` のキーに**存在すること**を要求する(sdist 経由の wheel から
|
|
344
|
+
KEEP が欠落する過去 defect の型)。sdist exclude 配下でない KEEP は対象外=
|
|
345
|
+
レコードを作らない。
|
|
346
|
+
- 分類要求(``辺2分類``): ``force-include`` の各キーは「KEEP 救済(KEEP パターンに
|
|
347
|
+
一致)」または「注入対照」に分類できること(用途不明キーの増殖防止)。
|
|
348
|
+
``injection_controls`` に載っているキーは ``allowlisted=True`` となり、KEEP に
|
|
349
|
+
一致しなくても違反にならない。
|
|
350
|
+
|
|
351
|
+
ここでの「KEEP 救済」は **sdist exclude 経路の救済**を指す(VCS ignore で落ちた
|
|
352
|
+
KEEP を force-include で救うことは辺 1 の禁止規範で認めていない・記載義務 ②)。
|
|
353
|
+
|
|
354
|
+
本検出器は判定関数を注入されない(キー存在の照合のみ)。計数の seam は戻り値が
|
|
355
|
+
レコード列であることにより成立するため、P7(e)/(f) のスタブ反転の対象外である。
|
|
356
|
+
"""
|
|
357
|
+
normalized_exclude = [normalize(entry) for entry in sdist_exclude]
|
|
358
|
+
keep_paths = [CLAUDE_PREFIX + pattern for pattern in keep_patterns]
|
|
359
|
+
keys = list(force_include_keys)
|
|
360
|
+
|
|
361
|
+
records: list[Verdict] = []
|
|
362
|
+
for keep_path in keep_paths:
|
|
363
|
+
if not any(fnmatch.fnmatchcase(keep_path, pat) for pat in normalized_exclude):
|
|
364
|
+
continue
|
|
365
|
+
records.append(
|
|
366
|
+
Verdict(
|
|
367
|
+
subject=keep_path,
|
|
368
|
+
expected=True,
|
|
369
|
+
actual=keep_path in keys,
|
|
370
|
+
allowlisted=False,
|
|
371
|
+
category=CATEGORY_EDGE2_RESCUE,
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
for key in keys:
|
|
375
|
+
records.append(
|
|
376
|
+
Verdict(
|
|
377
|
+
subject=key,
|
|
378
|
+
expected=True,
|
|
379
|
+
actual=any(fnmatch.fnmatchcase(key, pat) for pat in keep_paths),
|
|
380
|
+
allowlisted=key in injection_controls,
|
|
381
|
+
category=CATEGORY_EDGE2_CLASSIFY,
|
|
382
|
+
)
|
|
383
|
+
)
|
|
384
|
+
return records
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# ---------------------------------------------------------------------------
|
|
388
|
+
# 辺 3(sdist exclude → EXCLUDE の意図・片方向)
|
|
389
|
+
# ---------------------------------------------------------------------------
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def find_sdist_exclude_violations(
|
|
393
|
+
sdist_exclude: Iterable[str],
|
|
394
|
+
should_skip_fn: Callable[[str], bool],
|
|
395
|
+
*,
|
|
396
|
+
normalize: Callable[[str], str] = normalize_sdist_exclude_entry,
|
|
397
|
+
derive_probe: Callable[[str], str | None] = _derive_probe_from_sdist_entry,
|
|
398
|
+
) -> list[Verdict]:
|
|
399
|
+
"""辺 3 片方向(sdist ``exclude`` の ``.claude/`` エントリ → ``should_skip`` True 期待).
|
|
400
|
+
|
|
401
|
+
sdist が意図的に落とすものは ``EXCLUDE_PATTERNS`` の意図と整合していること
|
|
402
|
+
(``should_skip`` が True であること)を要求する。
|
|
403
|
+
|
|
404
|
+
**逆方向は要求しない(非対称の根拠・記載義務 ③・改訂 3 §2-3 の確定文面)**:
|
|
405
|
+
sdist exclude はローカル作業ファイル対策の部分列であり網羅を要求しない。この非網羅は他のどの検査でも代替されない(`scripts/verify_wheel.py` の sdist 検査は sdist に実体として入った EXCLUDE 対象の混入のみを見る。tracked / 非 ignore の未追跡作業ファイルの双方が対象で、clean checkout での実効候補は注入対照 1 件)
|
|
406
|
+
"""
|
|
407
|
+
records: list[Verdict] = []
|
|
408
|
+
for entry in sdist_exclude:
|
|
409
|
+
probe = derive_probe(normalize(entry))
|
|
410
|
+
if probe is None:
|
|
411
|
+
continue
|
|
412
|
+
records.append(
|
|
413
|
+
Verdict(
|
|
414
|
+
subject=probe,
|
|
415
|
+
expected=True,
|
|
416
|
+
actual=bool(should_skip_fn(probe)),
|
|
417
|
+
allowlisted=False,
|
|
418
|
+
category=CATEGORY_EDGE3,
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
return records
|
|
File without changes
|
|
File without changes
|