graphite-code 0.5.1__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 (257) hide show
  1. {graphite_code-0.5.1 → graphite_code-0.5.3}/CHANGELOG.md +52 -0
  2. {graphite_code-0.5.1 → graphite_code-0.5.3}/PKG-INFO +1 -1
  3. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/__init__.py +1 -1
  4. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/buildlock.py +53 -3
  5. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/cli.py +3055 -3053
  6. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/daemon.py +782 -745
  7. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/git.py +24 -17
  8. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_build_detach.py +15 -6
  9. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_buildlock.py +52 -1
  10. graphite_code-0.5.3/tests/test_daemon_build_lock.py +158 -0
  11. graphite_code-0.5.3/tests/test_daemon_child_lock.py +104 -0
  12. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_git_security.py +41 -8
  13. graphite_code-0.5.1/tests/test_daemon_build_lock.py +0 -83
  14. {graphite_code-0.5.1 → graphite_code-0.5.3}/.gitignore +0 -0
  15. {graphite_code-0.5.1 → graphite_code-0.5.3}/ARCHITECTURE.md +0 -0
  16. {graphite_code-0.5.1 → graphite_code-0.5.3}/CONTRIBUTING.md +0 -0
  17. {graphite_code-0.5.1 → graphite_code-0.5.3}/LICENSE +0 -0
  18. {graphite_code-0.5.1 → graphite_code-0.5.3}/README.md +0 -0
  19. {graphite_code-0.5.1 → graphite_code-0.5.3}/RELEASING.md +0 -0
  20. {graphite_code-0.5.1 → graphite_code-0.5.3}/pyproject.toml +0 -0
  21. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/__main__.py +0 -0
  22. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/_cleanup_worker.py +0 -0
  23. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/activation.py +0 -0
  24. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/agent_hooks.py +0 -0
  25. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/agent_settings.py +0 -0
  26. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/analyze.py +0 -0
  27. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/answer_contract.py +0 -0
  28. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/bootstrap.py +0 -0
  29. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/cache.py +0 -0
  30. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/channel.py +0 -0
  31. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/cluster.py +0 -0
  32. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/config.py +0 -0
  33. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/context.py +0 -0
  34. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/daemon_health.py +0 -0
  35. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/debt.py +0 -0
  36. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/dependency_install.py +0 -0
  37. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/detach.py +0 -0
  38. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/doctor.py +0 -0
  39. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/doctor_probes.py +0 -0
  40. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/engine_identity.py +0 -0
  41. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/export/__init__.py +0 -0
  42. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/export/html.py +0 -0
  43. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/export/json.py +0 -0
  44. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/export/md.py +0 -0
  45. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/extract/__init__.py +0 -0
  46. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/extract/ast.py +0 -0
  47. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/freshness.py +0 -0
  48. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/graph.py +0 -0
  49. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/graph_io.py +0 -0
  50. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/health.py +0 -0
  51. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/hook_entry.py +0 -0
  52. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/hookinstall.py +0 -0
  53. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/hookshim.py +0 -0
  54. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/incident_ledger.py +0 -0
  55. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/ingest.py +0 -0
  56. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/init.py +0 -0
  57. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/io.py +0 -0
  58. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/listing.py +0 -0
  59. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/llm.py +0 -0
  60. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/llm_probe.py +0 -0
  61. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/mcp.py +0 -0
  62. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/mcp_server.py +0 -0
  63. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/natural_query.py +0 -0
  64. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/overlays.py +0 -0
  65. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/probe_process.py +0 -0
  66. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/probe_workspace.py +0 -0
  67. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/process_contracts.py +0 -0
  68. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/provider_observer.py +0 -0
  69. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/query.py +0 -0
  70. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/query_plan.py +0 -0
  71. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/replacement_audit.py +0 -0
  72. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/resolve.py +0 -0
  73. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/review.py +0 -0
  74. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/__init__.py +0 -0
  75. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/approval.py +0 -0
  76. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/classifier.py +0 -0
  77. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/claude_executor.py +0 -0
  78. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/claude_probe.py +0 -0
  79. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/cli_identity.py +0 -0
  80. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/codex_executor.py +0 -0
  81. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/codex_probe.py +0 -0
  82. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/context_builder.py +0 -0
  83. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/contracts.py +0 -0
  84. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/diff_policy.py +0 -0
  85. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/edit_apply.py +0 -0
  86. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/effort.py +0 -0
  87. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/lifecycle.py +0 -0
  88. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_operator.py +0 -0
  89. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_service.py +0 -0
  90. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/lifecycle_storage.py +0 -0
  91. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/ollama_executor.py +0 -0
  92. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/ollama_probe.py +0 -0
  93. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/openrouter_executor.py +0 -0
  94. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/openrouter_probe.py +0 -0
  95. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/policy.py +0 -0
  96. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/probe_runner.py +0 -0
  97. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/process_runner.py +0 -0
  98. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/profiles.py +0 -0
  99. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/prompt.py +0 -0
  100. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/registry.py +0 -0
  101. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/route_pool.py +0 -0
  102. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/route_pool_execution.py +0 -0
  103. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/schema_validation.py +0 -0
  104. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/service.py +0 -0
  105. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/settings.py +0 -0
  106. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/shadow.py +0 -0
  107. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/storage.py +0 -0
  108. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/telemetry.py +0 -0
  109. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/worktree.py +0 -0
  110. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/zai_edit.py +0 -0
  111. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/zai_executor.py +0 -0
  112. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/routing/zai_probe.py +0 -0
  113. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/savings.py +0 -0
  114. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/ts_bridge.py +0 -0
  115. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/ts_resolver.mjs +0 -0
  116. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/typescript_activation.py +0 -0
  117. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/usage_ledger.py +0 -0
  118. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/validation.py +0 -0
  119. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/watch.py +0 -0
  120. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/windows_job.py +0 -0
  121. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/windows_startup.py +0 -0
  122. {graphite_code-0.5.1 → graphite_code-0.5.3}/src/graphite/windows_task.py +0 -0
  123. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/conftest.py +0 -0
  124. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/data/sqloracle/blindspots.py.txt +0 -0
  125. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/data/sqloracle/round69.py.txt +0 -0
  126. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/fake_clis/fake_cli.py +0 -0
  127. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
  128. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
  129. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
  130. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
  131. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_activation.py +0 -0
  132. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_activation_backstop.py +0 -0
  133. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_agent_hook_activation.py +0 -0
  134. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_agent_hooks.py +0 -0
  135. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_agent_settings.py +0 -0
  136. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_answer_contract.py +0 -0
  137. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_arrow_and_constructor_binding.py +0 -0
  138. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_atomic_write.py +0 -0
  139. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_bootstrap.py +0 -0
  140. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cache_engine_identity.py +0 -0
  141. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cache_file_set.py +0 -0
  142. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cache_pruning.py +0 -0
  143. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_call_graph.py +0 -0
  144. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_cli.py +0 -0
  145. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_core.py +0 -0
  146. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_lock.py +0 -0
  147. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_mcp.py +0 -0
  148. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_register.py +0 -0
  149. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_report.py +0 -0
  150. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_channel_status.py +0 -0
  151. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_class_field_arrow_binding.py +0 -0
  152. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cli_channel.py +0 -0
  153. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cli_version.py +0 -0
  154. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_context.py +0 -0
  155. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_cwd_relative_config.py +0 -0
  156. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_daemon.py +0 -0
  157. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_daemon_activation.py +0 -0
  158. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_daemon_engine_staleness.py +0 -0
  159. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_daemon_health.py +0 -0
  160. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_daemon_health_activation.py +0 -0
  161. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_debt.py +0 -0
  162. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_destructured_binding.py +0 -0
  163. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_determinism.py +0 -0
  164. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_dispatch_evidence.py +0 -0
  165. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_doctor.py +0 -0
  166. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_doctor_agent_hooks.py +0 -0
  167. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_doctor_hooks.py +0 -0
  168. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_doctor_managed_docs.py +0 -0
  169. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_documentation.py +0 -0
  170. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_edit_apply.py +0 -0
  171. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_engine_identity.py +0 -0
  172. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_external_calls.py +0 -0
  173. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_go_rust.py +0 -0
  174. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_graph_io.py +0 -0
  175. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_graph_provider_isolation.py +0 -0
  176. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_hardening.py +0 -0
  177. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_health.py +0 -0
  178. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_hook_entry.py +0 -0
  179. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_hook_template.py +0 -0
  180. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_hookinstall.py +0 -0
  181. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_hookshim.py +0 -0
  182. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_html_security.py +0 -0
  183. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_incident_ledger.py +0 -0
  184. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_init.py +0 -0
  185. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_init_activation_doctrine.py +0 -0
  186. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_init_hooks.py +0 -0
  187. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_init_validation_exit.py +0 -0
  188. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_lifecycle_operator.py +0 -0
  189. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_listing.py +0 -0
  190. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_listing_surfaces.py +0 -0
  191. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_llm.py +0 -0
  192. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_mcp.py +0 -0
  193. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_method_dispatch_scope.py +0 -0
  194. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_monorepo.py +0 -0
  195. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_natural_query.py +0 -0
  196. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_node_identity.py +0 -0
  197. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_overlays.py +0 -0
  198. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_path_leak_fixture.py +0 -0
  199. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_probe_diagnostics.py +0 -0
  200. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_probe_workspace.py +0 -0
  201. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_claude_probe.py +0 -0
  202. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_codex_probe.py +0 -0
  203. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_lifecycle.py +0 -0
  204. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_lifecycle_service.py +0 -0
  205. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_lifecycle_storage.py +0 -0
  206. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_observer.py +0 -0
  207. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_ollama_probe.py +0 -0
  208. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_openrouter_probe.py +0 -0
  209. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_provider_probe_runner.py +0 -0
  210. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_public_surface.py +0 -0
  211. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_published_schemas.py +0 -0
  212. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_python_resolver.py +0 -0
  213. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_query_plan.py +0 -0
  214. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_reliability.py +0 -0
  215. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_replacement_audit.py +0 -0
  216. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_resolve.py +0 -0
  217. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_review.py +0 -0
  218. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_route_pool.py +0 -0
  219. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_approval.py +0 -0
  220. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_benchmark.py +0 -0
  221. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_classifier.py +0 -0
  222. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_claude_executor.py +0 -0
  223. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_cli.py +0 -0
  224. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_cli_contracts.py +0 -0
  225. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_cli_recovery.py +0 -0
  226. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_codex_executor.py +0 -0
  227. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_context.py +0 -0
  228. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_contracts.py +0 -0
  229. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_diff_policy.py +0 -0
  230. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_executor.py +0 -0
  231. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_openrouter_executor.py +0 -0
  232. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_policy.py +0 -0
  233. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_process_runner.py +0 -0
  234. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_profiles.py +0 -0
  235. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_registry.py +0 -0
  236. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_schema_validation.py +0 -0
  237. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_security.py +0 -0
  238. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_service.py +0 -0
  239. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_shadow.py +0 -0
  240. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_storage.py +0 -0
  241. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_telemetry.py +0 -0
  242. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_worktree.py +0 -0
  243. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_zai_executor.py +0 -0
  244. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_routing_zai_probe.py +0 -0
  245. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_savings.py +0 -0
  246. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_search.py +0 -0
  247. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_smoke.py +0 -0
  248. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_sqloracle.py +0 -0
  249. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_typescript_activation.py +0 -0
  250. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_typescript_resolver.py +0 -0
  251. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_usage_ledger.py +0 -0
  252. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_verify_artifact.py +0 -0
  253. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_verify_published_release.py +0 -0
  254. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_watch.py +0 -0
  255. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_windows_startup.py +0 -0
  256. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_windows_task.py +0 -0
  257. {graphite_code-0.5.1 → graphite_code-0.5.3}/tests/test_zai_edit.py +0 -0
@@ -12,6 +12,58 @@ 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
+
38
+ ## [0.5.2] — 2026-08-28
39
+
40
+ ### Fixed
41
+
42
+ **Force-stopping the daemon mid-build no longer wedges its successor for the
43
+ lock TTL** (#60). The build lock was held by the daemon on its child's behalf
44
+ (`ENV_LOCK_HELD` told the child not to contend), so `Stop-Process -Force` --
45
+ the documented post-install restart, which runs no `finally` -- left
46
+ `.build.lock` on disk naming a dead pid while the orphaned child kept writing
47
+ `graph-out/`. The successor could neither trust "holder dead" (the writer was
48
+ still alive) nor see "writer done", so it logged `build_skipped_locked` every
49
+ cycle and `daemon-health` warned for up to 600 s over a graph that was already
50
+ correct. A pid-liveness probe would not have helped and would have raced the
51
+ orphan in the very incident that filed the issue.
52
+
53
+ The lock now follows the writer: the daemon's child takes it itself, exactly
54
+ as a hook or manual `graphite build` does, and a killed daemon leaves no lock
55
+ at all. `build_skipped_locked` is therefore true for as long as a build is
56
+ really running and not a second longer. Two consequences are handled. The
57
+ child answers a refusal with exit status 75 (`EX_TEMPFAIL`) when the daemon
58
+ asks for it via `GRAPHITE_BUILD_LOCK_REPORT_REFUSAL`, so the cycle can book
59
+ "another builder owns the repo" as a skip and not a failed build; a human or a
60
+ hook still gets exit 0. And because the daemon's timeout kill now kills the
61
+ holder, the daemon releases the lock its dead child left -- by pid match only,
62
+ never by guessing. Under a Windows venv launcher `Popen.pid` is the launcher,
63
+ not the writer, so there the timeout path falls back to the TTL instead of
64
+ retrying next cycle: conservative by design, and noted here so nobody reads it
65
+ as a hang. `GRAPHITE_BUILD_LOCK_HELD` is gone; nothing outside the daemon set it.
66
+
15
67
  ## [0.5.1] — 2026-08-27
16
68
 
17
69
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: graphite-code
3
- Version: 0.5.1
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.1"
41
+ __version__ = "0.5.3"
@@ -9,6 +9,14 @@ Staleness is TTL-only, deliberately. `os.kill(pid, 0)` is the obvious liveness
9
9
  idiom and is WRONG here: on Windows, Python's `os.kill` ignores signal 0 and
10
10
  calls TerminateProcess, so the portable-looking probe would kill the very
11
11
  process it was checking.
12
+
13
+ The holder must be the process that writes (#60). The daemon used to take the
14
+ lock and hand its child an escape hatch; force-stopping the daemon then left
15
+ the record on disk with a dead pid while the orphaned child kept writing
16
+ graph-out/, and the successor could neither trust "holder dead" nor see
17
+ "writer done" -- so it skipped the repo for the whole TTL. Liveness probing
18
+ would not have helped: the recorded pid was dead while the writer was alive.
19
+ With the writer as holder, its death and its writes end together.
12
20
  """
13
21
  from __future__ import annotations
14
22
 
@@ -24,9 +32,13 @@ from typing import Any, Callable, Iterator
24
32
  # holding the lock past double the daemon's give-up point is dead by definition.
25
33
  DEFAULT_TTL_SECONDS = 600.0
26
34
 
27
- # Set by a parent that already holds the lock, so its child does not deadlock
28
- # against it. Mirrors the existing GRAPHITE_DAEMON_CHILD convention.
29
- ENV_LOCK_HELD = "GRAPHITE_BUILD_LOCK_HELD"
35
+ # A builder that cannot take the lock exits 0: a skipped build is a normal
36
+ # outcome for a human or a git hook, not a failure. The daemon needs more --
37
+ # "another builder owns the repo" must not be booked as a failed build -- so
38
+ # it sets this in its child's environment, and the child answers a refusal
39
+ # with REFUSED_EXIT_STATUS instead. Mirrors the GRAPHITE_DAEMON_CHILD convention.
40
+ ENV_REPORT_REFUSAL = "GRAPHITE_BUILD_LOCK_REPORT_REFUSAL"
41
+ REFUSED_EXIT_STATUS = 75 # sysexits.h EX_TEMPFAIL: try again later
30
42
 
31
43
 
32
44
  def lock_path(cache_dir: Path) -> Path:
@@ -50,6 +62,44 @@ def _is_stale(record: dict[str, Any] | None, now: float, ttl_seconds: float) ->
50
62
  return (now - float(started)) > ttl_seconds
51
63
 
52
64
 
65
+ def is_held(
66
+ cache_dir: Path,
67
+ *,
68
+ ttl_seconds: float = DEFAULT_TTL_SECONDS,
69
+ clock: Callable[[], float] = time.time,
70
+ ) -> bool:
71
+ """Advisory: would a builder be refused right now?
72
+
73
+ Reads only -- never acquires, never unlinks, never steals. The answer can
74
+ be stale by the time the caller acts on it, so correctness still rests on
75
+ the acquirer's own `build_lock`. The daemon uses it to avoid spawning a
76
+ child every cycle only to have it refused.
77
+ """
78
+ path = lock_path(cache_dir)
79
+ if not path.exists():
80
+ return False
81
+ return not _is_stale(_read_record(path), clock(), ttl_seconds)
82
+
83
+
84
+ def release_if_held_by(cache_dir: Path, *, pid: int) -> bool:
85
+ """Unlink the lock if its record names `pid`; True if it did.
86
+
87
+ For a parent that has just killed `pid`: the child died without its
88
+ `finally`, and no other process can hold a record carrying its pid, so this
89
+ releases on the dead child's behalf rather than stealing. It is NOT a
90
+ liveness probe -- the caller must already know the process is dead.
91
+ """
92
+ path = lock_path(cache_dir)
93
+ record = _read_record(path)
94
+ if record is None or record.get("pid") != pid:
95
+ return False
96
+ try:
97
+ path.unlink()
98
+ except OSError:
99
+ return False
100
+ return True
101
+
102
+
53
103
  def _create_exclusive(path: Path, now: float) -> bool:
54
104
  """Atomically create the lock file. False if someone else already has it."""
55
105
  try: