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.
Files changed (256) hide show
  1. {graphite_code-0.5.2 → graphite_code-0.5.3}/CHANGELOG.md +23 -0
  2. {graphite_code-0.5.2 → graphite_code-0.5.3}/PKG-INFO +1 -1
  3. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/__init__.py +1 -1
  4. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/git.py +24 -17
  5. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_git_security.py +41 -8
  6. {graphite_code-0.5.2 → graphite_code-0.5.3}/.gitignore +0 -0
  7. {graphite_code-0.5.2 → graphite_code-0.5.3}/ARCHITECTURE.md +0 -0
  8. {graphite_code-0.5.2 → graphite_code-0.5.3}/CONTRIBUTING.md +0 -0
  9. {graphite_code-0.5.2 → graphite_code-0.5.3}/LICENSE +0 -0
  10. {graphite_code-0.5.2 → graphite_code-0.5.3}/README.md +0 -0
  11. {graphite_code-0.5.2 → graphite_code-0.5.3}/RELEASING.md +0 -0
  12. {graphite_code-0.5.2 → graphite_code-0.5.3}/pyproject.toml +0 -0
  13. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/__main__.py +0 -0
  14. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/_cleanup_worker.py +0 -0
  15. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/activation.py +0 -0
  16. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/agent_hooks.py +0 -0
  17. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/agent_settings.py +0 -0
  18. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/analyze.py +0 -0
  19. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/answer_contract.py +0 -0
  20. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/bootstrap.py +0 -0
  21. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/buildlock.py +0 -0
  22. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cache.py +0 -0
  23. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/channel.py +0 -0
  24. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cli.py +0 -0
  25. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/cluster.py +0 -0
  26. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/config.py +0 -0
  27. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/context.py +0 -0
  28. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/daemon.py +0 -0
  29. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/daemon_health.py +0 -0
  30. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/debt.py +0 -0
  31. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/dependency_install.py +0 -0
  32. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/detach.py +0 -0
  33. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/doctor.py +0 -0
  34. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/doctor_probes.py +0 -0
  35. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/engine_identity.py +0 -0
  36. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/__init__.py +0 -0
  37. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/html.py +0 -0
  38. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/json.py +0 -0
  39. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/export/md.py +0 -0
  40. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/extract/__init__.py +0 -0
  41. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/extract/ast.py +0 -0
  42. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/freshness.py +0 -0
  43. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/graph.py +0 -0
  44. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/graph_io.py +0 -0
  45. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/health.py +0 -0
  46. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hook_entry.py +0 -0
  47. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hookinstall.py +0 -0
  48. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/hookshim.py +0 -0
  49. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/incident_ledger.py +0 -0
  50. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ingest.py +0 -0
  51. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/init.py +0 -0
  52. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/io.py +0 -0
  53. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/listing.py +0 -0
  54. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/llm.py +0 -0
  55. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/llm_probe.py +0 -0
  56. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/mcp.py +0 -0
  57. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/mcp_server.py +0 -0
  58. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/natural_query.py +0 -0
  59. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/overlays.py +0 -0
  60. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/probe_process.py +0 -0
  61. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/probe_workspace.py +0 -0
  62. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/process_contracts.py +0 -0
  63. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/provider_observer.py +0 -0
  64. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/query.py +0 -0
  65. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/query_plan.py +0 -0
  66. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/replacement_audit.py +0 -0
  67. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/resolve.py +0 -0
  68. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/review.py +0 -0
  69. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/__init__.py +0 -0
  70. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/approval.py +0 -0
  71. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/classifier.py +0 -0
  72. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/claude_executor.py +0 -0
  73. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/claude_probe.py +0 -0
  74. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/cli_identity.py +0 -0
  75. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/codex_executor.py +0 -0
  76. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/codex_probe.py +0 -0
  77. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/context_builder.py +0 -0
  78. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/contracts.py +0 -0
  79. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/diff_policy.py +0 -0
  80. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/edit_apply.py +0 -0
  81. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/effort.py +0 -0
  82. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle.py +0 -0
  83. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_operator.py +0 -0
  84. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_service.py +0 -0
  85. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_storage.py +0 -0
  86. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/ollama_executor.py +0 -0
  87. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/ollama_probe.py +0 -0
  88. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/openrouter_executor.py +0 -0
  89. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/openrouter_probe.py +0 -0
  90. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/policy.py +0 -0
  91. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/probe_runner.py +0 -0
  92. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/process_runner.py +0 -0
  93. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/profiles.py +0 -0
  94. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/prompt.py +0 -0
  95. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/registry.py +0 -0
  96. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/route_pool.py +0 -0
  97. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/route_pool_execution.py +0 -0
  98. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/schema_validation.py +0 -0
  99. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/service.py +0 -0
  100. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/settings.py +0 -0
  101. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/shadow.py +0 -0
  102. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/storage.py +0 -0
  103. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/telemetry.py +0 -0
  104. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/worktree.py +0 -0
  105. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_edit.py +0 -0
  106. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_executor.py +0 -0
  107. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/routing/zai_probe.py +0 -0
  108. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/savings.py +0 -0
  109. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ts_bridge.py +0 -0
  110. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/ts_resolver.mjs +0 -0
  111. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/typescript_activation.py +0 -0
  112. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/usage_ledger.py +0 -0
  113. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/validation.py +0 -0
  114. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/watch.py +0 -0
  115. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_job.py +0 -0
  116. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_startup.py +0 -0
  117. {graphite_code-0.5.2 → graphite_code-0.5.3}/src/graphite/windows_task.py +0 -0
  118. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/conftest.py +0 -0
  119. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/data/sqloracle/blindspots.py.txt +0 -0
  120. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/data/sqloracle/round69.py.txt +0 -0
  121. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fake_clis/fake_cli.py +0 -0
  122. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
  123. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
  124. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
  125. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
  126. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_activation.py +0 -0
  127. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_activation_backstop.py +0 -0
  128. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_hook_activation.py +0 -0
  129. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_hooks.py +0 -0
  130. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_agent_settings.py +0 -0
  131. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_answer_contract.py +0 -0
  132. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_arrow_and_constructor_binding.py +0 -0
  133. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_atomic_write.py +0 -0
  134. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_bootstrap.py +0 -0
  135. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_build_detach.py +0 -0
  136. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_buildlock.py +0 -0
  137. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_engine_identity.py +0 -0
  138. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_file_set.py +0 -0
  139. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cache_pruning.py +0 -0
  140. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_call_graph.py +0 -0
  141. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_cli.py +0 -0
  142. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_core.py +0 -0
  143. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_lock.py +0 -0
  144. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_mcp.py +0 -0
  145. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_register.py +0 -0
  146. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_report.py +0 -0
  147. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_channel_status.py +0 -0
  148. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_class_field_arrow_binding.py +0 -0
  149. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cli_channel.py +0 -0
  150. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cli_version.py +0 -0
  151. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_context.py +0 -0
  152. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_cwd_relative_config.py +0 -0
  153. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon.py +0 -0
  154. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_activation.py +0 -0
  155. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_build_lock.py +0 -0
  156. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_child_lock.py +0 -0
  157. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_engine_staleness.py +0 -0
  158. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_health.py +0 -0
  159. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_daemon_health_activation.py +0 -0
  160. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_debt.py +0 -0
  161. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_destructured_binding.py +0 -0
  162. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_determinism.py +0 -0
  163. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_dispatch_evidence.py +0 -0
  164. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor.py +0 -0
  165. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_agent_hooks.py +0 -0
  166. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_hooks.py +0 -0
  167. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_doctor_managed_docs.py +0 -0
  168. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_documentation.py +0 -0
  169. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_edit_apply.py +0 -0
  170. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_engine_identity.py +0 -0
  171. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_external_calls.py +0 -0
  172. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_go_rust.py +0 -0
  173. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_graph_io.py +0 -0
  174. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_graph_provider_isolation.py +0 -0
  175. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hardening.py +0 -0
  176. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_health.py +0 -0
  177. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hook_entry.py +0 -0
  178. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hook_template.py +0 -0
  179. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hookinstall.py +0 -0
  180. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_hookshim.py +0 -0
  181. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_html_security.py +0 -0
  182. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_incident_ledger.py +0 -0
  183. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init.py +0 -0
  184. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_activation_doctrine.py +0 -0
  185. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_hooks.py +0 -0
  186. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_init_validation_exit.py +0 -0
  187. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_lifecycle_operator.py +0 -0
  188. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_listing.py +0 -0
  189. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_listing_surfaces.py +0 -0
  190. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_llm.py +0 -0
  191. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_mcp.py +0 -0
  192. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_method_dispatch_scope.py +0 -0
  193. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_monorepo.py +0 -0
  194. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_natural_query.py +0 -0
  195. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_node_identity.py +0 -0
  196. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_overlays.py +0 -0
  197. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_path_leak_fixture.py +0 -0
  198. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_probe_diagnostics.py +0 -0
  199. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_probe_workspace.py +0 -0
  200. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_claude_probe.py +0 -0
  201. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_codex_probe.py +0 -0
  202. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle.py +0 -0
  203. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle_service.py +0 -0
  204. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_lifecycle_storage.py +0 -0
  205. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_observer.py +0 -0
  206. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_ollama_probe.py +0 -0
  207. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_openrouter_probe.py +0 -0
  208. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_provider_probe_runner.py +0 -0
  209. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_public_surface.py +0 -0
  210. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_published_schemas.py +0 -0
  211. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_python_resolver.py +0 -0
  212. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_query_plan.py +0 -0
  213. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_reliability.py +0 -0
  214. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_replacement_audit.py +0 -0
  215. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_resolve.py +0 -0
  216. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_review.py +0 -0
  217. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_route_pool.py +0 -0
  218. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_approval.py +0 -0
  219. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_benchmark.py +0 -0
  220. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_classifier.py +0 -0
  221. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_claude_executor.py +0 -0
  222. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli.py +0 -0
  223. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli_contracts.py +0 -0
  224. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_cli_recovery.py +0 -0
  225. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_codex_executor.py +0 -0
  226. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_context.py +0 -0
  227. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_contracts.py +0 -0
  228. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_diff_policy.py +0 -0
  229. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_executor.py +0 -0
  230. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_openrouter_executor.py +0 -0
  231. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_policy.py +0 -0
  232. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_process_runner.py +0 -0
  233. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_profiles.py +0 -0
  234. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_registry.py +0 -0
  235. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_schema_validation.py +0 -0
  236. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_security.py +0 -0
  237. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_service.py +0 -0
  238. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_shadow.py +0 -0
  239. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_storage.py +0 -0
  240. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_telemetry.py +0 -0
  241. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_worktree.py +0 -0
  242. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_zai_executor.py +0 -0
  243. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_routing_zai_probe.py +0 -0
  244. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_savings.py +0 -0
  245. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_search.py +0 -0
  246. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_smoke.py +0 -0
  247. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_sqloracle.py +0 -0
  248. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_typescript_activation.py +0 -0
  249. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_typescript_resolver.py +0 -0
  250. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_usage_ledger.py +0 -0
  251. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_verify_artifact.py +0 -0
  252. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_verify_published_release.py +0 -0
  253. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_watch.py +0 -0
  254. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_windows_startup.py +0 -0
  255. {graphite_code-0.5.2 → graphite_code-0.5.3}/tests/test_windows_task.py +0 -0
  256. {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.2
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.2"
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 inside `_GIT_VERSION_TIMEOUT_SECONDS`, or it could not be
128
- launched at all. Both then widen into `git_unavailable` upstream, which is
129
- how graphite#37 got a CI log saying an installed, working Git was
130
- unavailable.
131
-
132
- The probe's budget is two seconds for one process spawn, and `_version` is
133
- cached per RUNNER -- `collect_diff_evidence`, `create_task_worktree` and
134
- `accept` each build their own -- so a single routing operation pays that
135
- race several times over. On a loaded Windows runner that is a plausible
136
- intermittent failure, and `reason` is what lets the next sighting say so
137
- instead of blaming the Git version.
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=_GIT_VERSION_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 took longer than two
201
- # seconds" from "spawn was refused".
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 today it is unfalsifiable.
813
+ """The likeliest reading of graphite#37, and before this it was unfalsifiable.
814
814
 
815
- `_ensure_supported_version` spends at most `_GIT_VERSION_TIMEOUT_SECONDS`
816
- (2.0) on `git --version`, and folds GitTimeoutError, GitLaunchError and
817
- GitOutputLimitError into `GitUnsupportedVersionError` -- which `_run_git`
818
- then buckets into `git_unavailable`. So "this runner was too slow to spawn a
819
- process for two seconds" and "this machine has Git 2.20" arrive as the same
820
- string, and the first is exactly what a loaded Windows CI runner produces
821
- intermittently while every earlier Git call in the same test succeeded.
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