graphite-code 0.5.2__tar.gz → 0.5.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.
- {graphite_code-0.5.2 → graphite_code-0.5.3}/CHANGELOG.md +23 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/PKG-INFO +1 -1
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/__init__.py +1 -1
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/git.py +24 -17
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_git_security.py +41 -8
- {graphite_code-0.5.2 → graphite_code-0.5.3}/.gitignore +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/ARCHITECTURE.md +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/CONTRIBUTING.md +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/LICENSE +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/README.md +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/RELEASING.md +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/pyproject.toml +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/__main__.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/_cleanup_worker.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/agent_hooks.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/agent_settings.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/analyze.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/answer_contract.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/bootstrap.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/buildlock.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cache.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/channel.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cli.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cluster.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/config.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/context.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/daemon.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/daemon_health.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/debt.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/dependency_install.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/detach.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/doctor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/doctor_probes.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/engine_identity.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/__init__.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/html.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/json.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/md.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/extract/__init__.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/extract/ast.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/freshness.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/graph.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/graph_io.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/health.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hook_entry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hookinstall.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hookshim.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/incident_ledger.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ingest.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/init.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/io.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/listing.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/llm.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/llm_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/mcp.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/mcp_server.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/natural_query.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/overlays.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/probe_process.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/probe_workspace.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/process_contracts.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/provider_observer.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/query.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/query_plan.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/replacement_audit.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/resolve.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/review.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/__init__.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/approval.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/classifier.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/claude_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/claude_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/cli_identity.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/codex_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/codex_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/context_builder.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/contracts.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/diff_policy.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/edit_apply.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/effort.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_operator.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_service.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_storage.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/ollama_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/ollama_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/openrouter_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/openrouter_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/policy.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/probe_runner.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/process_runner.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/profiles.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/prompt.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/registry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/route_pool.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/route_pool_execution.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/schema_validation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/service.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/settings.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/shadow.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/storage.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/telemetry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/worktree.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_edit.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/savings.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ts_bridge.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ts_resolver.mjs +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/typescript_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/usage_ledger.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/validation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/watch.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_job.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_startup.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_task.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/conftest.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/data/sqloracle/blindspots.py.txt +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/data/sqloracle/round69.py.txt +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fake_clis/fake_cli.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_activation_backstop.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_hook_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_hooks.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_settings.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_answer_contract.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_arrow_and_constructor_binding.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_atomic_write.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_bootstrap.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_build_detach.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_buildlock.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_engine_identity.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_file_set.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_pruning.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_call_graph.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_cli.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_core.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_lock.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_mcp.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_register.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_report.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_status.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_class_field_arrow_binding.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cli_channel.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cli_version.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_context.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cwd_relative_config.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_build_lock.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_child_lock.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_engine_staleness.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_health.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_health_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_debt.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_destructured_binding.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_determinism.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_dispatch_evidence.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_agent_hooks.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_hooks.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_managed_docs.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_documentation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_edit_apply.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_engine_identity.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_external_calls.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_go_rust.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_graph_io.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_graph_provider_isolation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hardening.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_health.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hook_entry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hook_template.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hookinstall.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hookshim.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_html_security.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_incident_ledger.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_activation_doctrine.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_hooks.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_validation_exit.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_lifecycle_operator.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_listing.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_listing_surfaces.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_llm.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_mcp.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_method_dispatch_scope.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_monorepo.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_natural_query.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_node_identity.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_overlays.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_path_leak_fixture.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_probe_diagnostics.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_probe_workspace.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_claude_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_codex_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle_service.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle_storage.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_observer.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_ollama_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_openrouter_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_probe_runner.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_public_surface.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_published_schemas.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_python_resolver.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_query_plan.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_reliability.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_replacement_audit.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_resolve.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_review.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_route_pool.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_approval.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_benchmark.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_classifier.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_claude_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli_contracts.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli_recovery.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_codex_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_context.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_contracts.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_diff_policy.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_openrouter_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_policy.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_process_runner.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_profiles.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_registry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_schema_validation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_security.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_service.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_shadow.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_storage.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_telemetry.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_worktree.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_zai_executor.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_zai_probe.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_savings.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_search.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_smoke.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_sqloracle.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_typescript_activation.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_typescript_resolver.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_usage_ledger.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_verify_artifact.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_verify_published_release.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_watch.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_windows_startup.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_windows_task.py +0 -0
- {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_zai_edit.py +0 -0
|
@@ -12,6 +12,29 @@ machine-checkable identity; the version is for humans.
|
|
|
12
12
|
|
|
13
13
|
[Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
|
|
14
14
|
|
|
15
|
+
## [0.5.3] — 2026-08-28
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
**The `git --version` probe no longer has a fixed two-second budget of its
|
|
20
|
+
own** (#37). Every production caller gave its real Git command 5–300 seconds
|
|
21
|
+
and then paid a fixed 2.0 seconds for the version probe that gates it -- the
|
|
22
|
+
one number in that path tuned to a quiet machine, in the step that runs first
|
|
23
|
+
on a loaded CI runner. A probe that outlived it was folded into
|
|
24
|
+
`GitUnsupportedVersionError` and widened upstream to `git_unavailable`, which
|
|
25
|
+
is how #37's single Windows sighting logged an installed, working Git as
|
|
26
|
+
unavailable. The probe now runs under the budget the caller gave its command:
|
|
27
|
+
`--version` is Git's cheapest command, so a budget the real command can
|
|
28
|
+
survive is one the probe can survive -- a derivation, not a wider number.
|
|
29
|
+
Probe and command keep separate budgets on purpose; a shared deadline would
|
|
30
|
+
make the command's budget vary with probe latency, a new way to time out
|
|
31
|
+
spuriously. `_GIT_VERSION_TIMEOUT_SECONDS` is gone. Recorded rather than
|
|
32
|
+
fixed: `_version` is still cached per `GitRunner`, so one routing operation
|
|
33
|
+
still runs the probe several times (exposure, not cause), and the 0.1 s
|
|
34
|
+
reader-thread join in `_run_bounded` is a second fixed bound feeding the same
|
|
35
|
+
bucket -- measured 0 of 400 runs live on a loaded 12-core box, so left alone
|
|
36
|
+
on evidence.
|
|
37
|
+
|
|
15
38
|
## [0.5.2] — 2026-08-28
|
|
16
39
|
|
|
17
40
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: graphite-code
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: Local-first, zero-LLM knowledge graph extraction for codebases.
|
|
5
5
|
Project-URL: Homepage, https://github.com/jared0565/graphite
|
|
6
6
|
Project-URL: Repository, https://github.com/jared0565/graphite
|
|
@@ -38,4 +38,4 @@ __all__ = ["__version__"]
|
|
|
38
38
|
#: Coarse and hand-maintained by construction. It is a release label, not
|
|
39
39
|
#: evidence that a given fix is present -- to answer that, survey for the marker
|
|
40
40
|
#: the fix introduced, or compare `graphite --version` fingerprints.
|
|
41
|
-
__version__ = "0.5.
|
|
41
|
+
__version__ = "0.5.3"
|
|
@@ -12,7 +12,6 @@ from typing import Sequence
|
|
|
12
12
|
|
|
13
13
|
DEFAULT_GIT_STDOUT_MAX_BYTES = 16 * 1024 * 1024
|
|
14
14
|
_MINIMUM_GIT_VERSION = (2, 38, 0)
|
|
15
|
-
_GIT_VERSION_TIMEOUT_SECONDS = 2.0
|
|
16
15
|
_GIT_VERSION_STDOUT_MAX_BYTES = 256
|
|
17
16
|
_READ_CHUNK_BYTES = 64 * 1024
|
|
18
17
|
_PROCESS_CLEANUP_TIMEOUT_SECONDS = 0.1
|
|
@@ -124,17 +123,18 @@ class GitUnsupportedVersionError(_StepGitError):
|
|
|
124
123
|
Three unrelated conditions land here, and the failure this class is NAMED
|
|
125
124
|
for is the rarest of them. Git really being older than 2.38 is a permanent,
|
|
126
125
|
obvious, one-machine fact. The other two are transient: the `--version`
|
|
127
|
-
probe timed out
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
`
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
instead of blaming the
|
|
126
|
+
probe timed out, or it could not be launched at all. Both then widen into
|
|
127
|
+
`git_unavailable` upstream, which is how graphite#37 got a CI log saying an
|
|
128
|
+
installed, working Git was unavailable.
|
|
129
|
+
|
|
130
|
+
The probe runs under the budget the caller gave its command. It used to
|
|
131
|
+
have a fixed two seconds of its own -- the one number in this path tuned to
|
|
132
|
+
a quiet machine, and #37's leading mechanism on a loaded Windows runner.
|
|
133
|
+
`_version` is still cached per RUNNER -- `collect_diff_evidence`,
|
|
134
|
+
`create_task_worktree` and `accept` each build their own -- so a single
|
|
135
|
+
routing operation pays the probe several times over. `reason` is what lets
|
|
136
|
+
a sighting say which of the three conditions it was instead of blaming the
|
|
137
|
+
Git version.
|
|
138
138
|
"""
|
|
139
139
|
|
|
140
140
|
|
|
@@ -165,7 +165,7 @@ class GitRunner:
|
|
|
165
165
|
"""Run one bounded Git command with fixed process security controls."""
|
|
166
166
|
if max_stdout_bytes <= 0:
|
|
167
167
|
raise GitOutputLimitError("Git command output limit exceeded")
|
|
168
|
-
self._ensure_supported_version()
|
|
168
|
+
self._ensure_supported_version(timeout_seconds)
|
|
169
169
|
command = [
|
|
170
170
|
str(self.executable),
|
|
171
171
|
"--no-optional-locks",
|
|
@@ -181,24 +181,31 @@ class GitRunner:
|
|
|
181
181
|
max_stdout_bytes=max_stdout_bytes,
|
|
182
182
|
)
|
|
183
183
|
|
|
184
|
-
def _ensure_supported_version(self) -> None:
|
|
184
|
+
def _ensure_supported_version(self, timeout_seconds: float) -> None:
|
|
185
185
|
if self._version is not None:
|
|
186
186
|
return
|
|
187
187
|
with self._version_lock:
|
|
188
188
|
if self._version is not None:
|
|
189
189
|
return
|
|
190
190
|
try:
|
|
191
|
+
# The probe runs under the caller's own budget, not a fixed one
|
|
192
|
+
# of its own. `--version` is Git's cheapest command, so a budget
|
|
193
|
+
# the caller's real command can survive is one the probe can
|
|
194
|
+
# survive -- a derivation, where the old two seconds was a
|
|
195
|
+
# number tuned to a quiet machine (graphite#37). The two budgets
|
|
196
|
+
# stay separate on purpose: sharing one deadline would make the
|
|
197
|
+
# command's budget vary with probe latency.
|
|
191
198
|
result = self._run_bounded(
|
|
192
199
|
[str(self.executable), "--version"],
|
|
193
|
-
timeout_seconds=
|
|
200
|
+
timeout_seconds=timeout_seconds,
|
|
194
201
|
max_stdout_bytes=_GIT_VERSION_STDOUT_MAX_BYTES,
|
|
195
202
|
)
|
|
196
203
|
except (GitTimeoutError, GitLaunchError, GitOutputLimitError) as exc:
|
|
197
204
|
# The probe never returned a version, so nothing here is
|
|
198
205
|
# evidence about Git's version -- carry what actually happened.
|
|
199
206
|
# `os_error` rides along when the inner failure had one; the
|
|
200
|
-
# class name alone cannot separate "spawn
|
|
201
|
-
#
|
|
207
|
+
# class name alone cannot separate "spawn outlived its budget"
|
|
208
|
+
# from "spawn was refused".
|
|
202
209
|
probe_reason = f"probe_{type(exc).__name__}"
|
|
203
210
|
raise GitUnsupportedVersionError(
|
|
204
211
|
git_version_failure_message(probe_reason),
|
|
@@ -810,15 +810,16 @@ def _trusted_repository(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path
|
|
|
810
810
|
def test_a_version_probe_that_timed_out_does_not_read_as_an_old_git(
|
|
811
811
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
812
812
|
) -> None:
|
|
813
|
-
"""The likeliest reading of graphite#37, and
|
|
813
|
+
"""The likeliest reading of graphite#37, and before this it was unfalsifiable.
|
|
814
814
|
|
|
815
|
-
`_ensure_supported_version`
|
|
816
|
-
|
|
817
|
-
GitOutputLimitError into `GitUnsupportedVersionError`
|
|
818
|
-
then buckets into `git_unavailable`. So "this runner was
|
|
819
|
-
process
|
|
820
|
-
string, and the first is exactly what a loaded
|
|
821
|
-
intermittently while every earlier Git call in
|
|
815
|
+
`_ensure_supported_version` runs `git --version` under a budget (once a
|
|
816
|
+
fixed 2.0 seconds of its own; now the caller's) and folds GitTimeoutError,
|
|
817
|
+
GitLaunchError and GitOutputLimitError into `GitUnsupportedVersionError`
|
|
818
|
+
-- which `_run_git` then buckets into `git_unavailable`. So "this runner was
|
|
819
|
+
too slow to spawn a process inside the budget" and "this machine has Git
|
|
820
|
+
2.20" arrived as the same string, and the first is exactly what a loaded
|
|
821
|
+
Windows CI runner produces intermittently while every earlier Git call in
|
|
822
|
+
the same test succeeded.
|
|
822
823
|
|
|
823
824
|
Naming the inner cause is what makes the next sighting decide between them
|
|
824
825
|
instead of restating the bucket.
|
|
@@ -927,3 +928,35 @@ def test_a_genuinely_old_git_stays_distinguishable_from_a_slow_one(
|
|
|
927
928
|
diagnostic = error.value.diagnostic()
|
|
928
929
|
assert "GitTimeoutError" not in diagnostic, "an old Git must not report a timeout"
|
|
929
930
|
assert "too_old" in diagnostic
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
@pytest.mark.parametrize("budget", [7.5, 1.0])
|
|
934
|
+
def test_the_version_probe_runs_under_the_budget_the_caller_gave_its_command(
|
|
935
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, budget: float
|
|
936
|
+
) -> None:
|
|
937
|
+
"""graphite#37: the probe had a fixed two-second budget of its own.
|
|
938
|
+
|
|
939
|
+
Every production caller gives its real command 5-300 seconds and then paid
|
|
940
|
+
a fixed 2.0 seconds for the `git --version` that gates it -- a number tuned
|
|
941
|
+
to a quiet machine, in the one path that runs first on a loaded CI runner.
|
|
942
|
+
`--version` is Git's cheapest command, so a budget the caller's own command
|
|
943
|
+
can survive is one the probe can survive: derive it, and the number goes.
|
|
944
|
+
|
|
945
|
+
Both parameters carry weight. 7.5 shows the caller's budget reaches the
|
|
946
|
+
probe; 1.0 shows no floor was smuggled back in under the derivation.
|
|
947
|
+
"""
|
|
948
|
+
version_process = _FakeProcess(b"git version 2.38.0\n")
|
|
949
|
+
process = _FakeProcess(b"tracked.py\0")
|
|
950
|
+
runner, _calls = _runner_with_fake_process(
|
|
951
|
+
tmp_path, monkeypatch, process, version_process=version_process
|
|
952
|
+
)
|
|
953
|
+
|
|
954
|
+
runner.run(["ls-files", "-z"], timeout_seconds=budget)
|
|
955
|
+
|
|
956
|
+
assert version_process.wait_calls == [budget], (
|
|
957
|
+
"the version probe must run under the budget the caller gave its command"
|
|
958
|
+
)
|
|
959
|
+
# Falsifiability control: the command keeps its own, full budget. A shared
|
|
960
|
+
# deadline would make the command's budget vary with probe latency, which
|
|
961
|
+
# is a new way to time out spuriously, not a fix for one.
|
|
962
|
+
assert process.wait_calls == [budget]
|
|
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
|
|
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
|
|
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
|
|
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
|
{graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|