sidegraph 0.5.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (405) hide show
  1. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/workflows/ci.yml +0 -39
  2. sidegraph-0.7.0/.github/workflows/session-link-gate.yml +76 -0
  3. {sidegraph-0.5.0 → sidegraph-0.7.0}/.gitleaks.toml +1 -0
  4. {sidegraph-0.5.0 → sidegraph-0.7.0}/.pre-commit-config.yaml +13 -12
  5. {sidegraph-0.5.0 → sidegraph-0.7.0}/CHANGELOG.md +434 -0
  6. {sidegraph-0.5.0 → sidegraph-0.7.0}/CLAUDE.md +6 -5
  7. {sidegraph-0.5.0 → sidegraph-0.7.0}/PKG-INFO +2 -2
  8. {sidegraph-0.5.0 → sidegraph-0.7.0}/README.md +1 -1
  9. {sidegraph-0.5.0 → sidegraph-0.7.0}/SECURITY.md +13 -5
  10. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/concepts/anchoring.md +53 -17
  11. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/concepts/data-model.md +3 -2
  12. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/concepts/mind-model.md +7 -7
  13. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/concepts/retrieval.md +59 -25
  14. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/getting-started/bootstrap.md +5 -1
  15. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/getting-started/claude-code-setup.md +13 -6
  16. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/getting-started/codex-setup.md +10 -2
  17. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/capturing-decisions.md +21 -8
  18. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/retrieval-in-sessions.md +15 -5
  19. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/semantic-docs.md +5 -4
  20. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/surviving-refactors.md +58 -13
  21. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/verifying-your-setup.md +3 -2
  22. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/integrations/claude-code.md +72 -24
  23. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/integrations/codex.md +53 -6
  24. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/integrations/graphify.md +75 -11
  25. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/cli.md +144 -58
  26. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/configuration.md +62 -17
  27. sidegraph-0.7.0/docs/reference/hooks.md +454 -0
  28. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/mcp-tools.md +111 -21
  29. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/operations.md +1 -1
  30. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/store-format.md +73 -4
  31. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/.claude-plugin/plugin.json +1 -1
  32. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/.codex-plugin/plugin.json +1 -1
  33. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/codex/hooks.json +2 -2
  34. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/hooks/hooks.json +3 -3
  35. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/heal-anchors/SKILL.md +4 -2
  36. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/import-adrs/SKILL.md +16 -5
  37. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/record-decision/SKILL.md +12 -8
  38. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/record-fact/SKILL.md +9 -5
  39. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/stats/SKILL.md +6 -5
  40. {sidegraph-0.5.0 → sidegraph-0.7.0}/pyproject.toml +1 -1
  41. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/__init__.py +1 -1
  42. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/anchoring.py +3 -20
  43. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/catalog.py +44 -9
  44. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/cli.py +68 -29
  45. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/integrations.py +23 -5
  46. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/capture.py +532 -303
  47. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/cli.py +237 -126
  48. sidegraph-0.7.0/src/sidegraph/config.py +533 -0
  49. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/doc_import.py +179 -37
  50. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/doctor.py +41 -3
  51. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/domains.py +2 -1
  52. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/engine/reader.py +334 -6
  53. sidegraph-0.7.0/src/sidegraph/freshness.py +59 -0
  54. sidegraph-0.7.0/src/sidegraph/gitenv.py +41 -0
  55. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/gitio.py +2 -1
  56. sidegraph-0.7.0/src/sidegraph/host/claude_settings.py +244 -0
  57. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/host/hooks.py +462 -94
  58. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/importer.py +15 -3
  59. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/okf.py +260 -23
  60. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/retrieval.py +157 -71
  61. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/schema.py +23 -1
  62. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/server.py +378 -64
  63. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/stats/model.py +23 -2
  64. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/stats/render.py +23 -3
  65. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/store.py +599 -67
  66. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/sync.py +685 -93
  67. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/verify.py +73 -3
  68. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/conftest.py +25 -0
  69. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/auto_policy/parity_goldens.json +1 -1
  70. sidegraph-0.7.0/tests/fixtures/member_names_python_graph.json +109 -0
  71. sidegraph-0.7.0/tests/fixtures/member_names_swift_graph.json +77 -0
  72. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_anchoring.py +2 -14
  73. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_catalog.py +91 -0
  74. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_cli.py +257 -0
  75. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_capture_auto_accept.py +0 -8
  76. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_capture_facts.py +0 -14
  77. sidegraph-0.7.0/tests/test_capture_initiative.py +185 -0
  78. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_capture_neighbors.py +0 -7
  79. sidegraph-0.7.0/tests/test_capture_propose.py +802 -0
  80. sidegraph-0.7.0/tests/test_capture_redact.py +184 -0
  81. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_domains.py +39 -0
  82. sidegraph-0.7.0/tests/test_cli_graph_paths.py +535 -0
  83. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_import.py +217 -25
  84. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_init.py +113 -0
  85. sidegraph-0.7.0/tests/test_cli_okf.py +819 -0
  86. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_stats.py +16 -0
  87. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_sync.py +19 -4
  88. sidegraph-0.7.0/tests/test_cli_unreadable_paths.py +261 -0
  89. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_config.py +45 -0
  90. sidegraph-0.7.0/tests/test_config_ancestor_lookup.py +265 -0
  91. sidegraph-0.7.0/tests/test_config_borrowed_graph.py +279 -0
  92. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_digest_integrity.py +23 -0
  93. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doc_corpus_integration.py +0 -7
  94. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doc_import.py +429 -6
  95. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_docs_claims.py +33 -0
  96. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor.py +102 -0
  97. sidegraph-0.7.0/tests/test_doctor_graph_stale.py +90 -0
  98. sidegraph-0.7.0/tests/test_git_env.py +138 -0
  99. sidegraph-0.7.0/tests/test_graph_freshness.py +552 -0
  100. sidegraph-0.7.0/tests/test_hook_spawn_guard.py +291 -0
  101. sidegraph-0.7.0/tests/test_host_agent_state.py +300 -0
  102. sidegraph-0.7.0/tests/test_host_borrowed_graph.py +288 -0
  103. sidegraph-0.7.0/tests/test_host_claude_settings.py +554 -0
  104. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_host_pretool.py +6 -6
  105. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_host_session_start.py +211 -6
  106. sidegraph-0.7.0/tests/test_host_session_start_concurrent.py +151 -0
  107. sidegraph-0.7.0/tests/test_host_stop.py +1471 -0
  108. sidegraph-0.7.0/tests/test_host_subdirectory_launch.py +282 -0
  109. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_host_touch_events.py +1 -1
  110. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_importer.py +42 -0
  111. sidegraph-0.7.0/tests/test_member_anchor_wiring.py +320 -0
  112. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_okf.py +29 -1
  113. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_ratify_policy.py +32 -41
  114. sidegraph-0.7.0/tests/test_reader_member_names.py +369 -0
  115. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_repoint_integration.py +0 -7
  116. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_toc.py +180 -3
  117. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_schema_descriptor.py +34 -0
  118. sidegraph-0.7.0/tests/test_server_borrowed_graph.py +543 -0
  119. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_capture.py +115 -0
  120. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_domains.py +40 -0
  121. sidegraph-0.7.0/tests/test_server_graph_freshness.py +373 -0
  122. sidegraph-0.7.0/tests/test_server_graph_path.py +269 -0
  123. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_render_events.py +1 -1
  124. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_telemetry.py +20 -0
  125. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_stats_graph.py +47 -0
  126. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_stats_model.py +17 -0
  127. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_stats_render.py +97 -0
  128. sidegraph-0.7.0/tests/test_store_agent_state.py +282 -0
  129. sidegraph-0.7.0/tests/test_store_binding_index.py +91 -0
  130. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_meta.py +12 -0
  131. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_migration.py +404 -0
  132. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_mutation_guard.py +25 -1
  133. sidegraph-0.7.0/tests/test_store_record_identity.py +407 -0
  134. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_stamping_marker.py +6 -4
  135. sidegraph-0.7.0/tests/test_store_symlinks.py +79 -0
  136. sidegraph-0.7.0/tests/test_store_update_meta_if.py +60 -0
  137. sidegraph-0.7.0/tests/test_sync_canonical_writes.py +171 -0
  138. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_clean.py +11 -17
  139. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_fresh_clone.py +0 -7
  140. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_integration.py +10 -14
  141. sidegraph-0.7.0/tests/test_sync_moved_adoption.py +708 -0
  142. sidegraph-0.7.0/tests/test_sync_rebind.py +1319 -0
  143. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_repoint.py +170 -0
  144. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_run.py +11 -8
  145. sidegraph-0.7.0/tests/test_sync_toc_cache.py +251 -0
  146. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_verify_snapshot.py +109 -0
  147. sidegraph-0.7.0/tools/check_no_session_links.py +167 -0
  148. {sidegraph-0.5.0 → sidegraph-0.7.0}/uv.lock +1 -1
  149. sidegraph-0.5.0/docs/reference/hooks.md +0 -292
  150. sidegraph-0.5.0/src/sidegraph/config.py +0 -156
  151. sidegraph-0.5.0/src/sidegraph/host/claude_settings.py +0 -130
  152. sidegraph-0.5.0/tests/test_capture_propose.py +0 -417
  153. sidegraph-0.5.0/tests/test_capture_redact.py +0 -58
  154. sidegraph-0.5.0/tests/test_cli_okf.py +0 -230
  155. sidegraph-0.5.0/tests/test_host_claude_settings.py +0 -141
  156. sidegraph-0.5.0/tests/test_host_stop.py +0 -738
  157. sidegraph-0.5.0/tests/test_sync_rebind.py +0 -457
  158. sidegraph-0.5.0/tests/test_sync_toc_cache.py +0 -125
  159. {sidegraph-0.5.0 → sidegraph-0.7.0}/.agents/plugins/marketplace.json +0 -0
  160. {sidegraph-0.5.0 → sidegraph-0.7.0}/.claude-plugin/marketplace.json +0 -0
  161. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/CODEOWNERS +0 -0
  162. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  163. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  164. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  165. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  166. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/secret_scanning.yml +0 -0
  167. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/workflows/publish.yml +0 -0
  168. {sidegraph-0.5.0 → sidegraph-0.7.0}/.github/workflows/scorecard.yml +0 -0
  169. {sidegraph-0.5.0 → sidegraph-0.7.0}/.gitignore +0 -0
  170. {sidegraph-0.5.0 → sidegraph-0.7.0}/.python-version +0 -0
  171. {sidegraph-0.5.0 → sidegraph-0.7.0}/AGENTS.md +0 -0
  172. {sidegraph-0.5.0 → sidegraph-0.7.0}/CODE_OF_CONDUCT.md +0 -0
  173. {sidegraph-0.5.0 → sidegraph-0.7.0}/CONTRIBUTING.md +0 -0
  174. {sidegraph-0.5.0 → sidegraph-0.7.0}/LICENSE +0 -0
  175. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/README.md +0 -0
  176. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/concepts/decision-memory.md +0 -0
  177. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/getting-started/installation.md +0 -0
  178. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/getting-started/quickstart.md +0 -0
  179. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/ci-cd-maintenance.md +0 -0
  180. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/naming-your-domains.md +0 -0
  181. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/guides/team-workflow.md +0 -0
  182. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/llms.txt +0 -0
  183. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/pilot-kit/README.md +0 -0
  184. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/pilot-kit/corpus_fit.py +0 -0
  185. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/pilot-kit/judge-prompt.md +0 -0
  186. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/pilot-kit/questions-prompt.md +0 -0
  187. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/pilot-kit/rubric-template.md +0 -0
  188. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/git-bindings.md +0 -0
  189. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/releasing.md +0 -0
  190. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/reference/stability.md +0 -0
  191. {sidegraph-0.5.0 → sidegraph-0.7.0}/docs/whitepaper/index.md +0 -0
  192. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/.mcp.json +0 -0
  193. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/codex/mcp.json +0 -0
  194. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/check-plan/SKILL.md +0 -0
  195. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/check-plan/agents/openai.yaml +0 -0
  196. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/explain-why/SKILL.md +0 -0
  197. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/explain-why/agents/openai.yaml +0 -0
  198. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/heal-anchors/agents/openai.yaml +0 -0
  199. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/import-adrs/agents/openai.yaml +0 -0
  200. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/manage-domains/SKILL.md +0 -0
  201. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/manage-domains/agents/openai.yaml +0 -0
  202. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/name-domains/SKILL.md +0 -0
  203. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/name-domains/agents/openai.yaml +0 -0
  204. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/ratify-decisions/SKILL.md +0 -0
  205. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/ratify-decisions/agents/openai.yaml +0 -0
  206. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/record-decision/agents/openai.yaml +0 -0
  207. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/record-fact/agents/openai.yaml +0 -0
  208. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/setup/SKILL.md +0 -0
  209. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/setup/agents/openai.yaml +0 -0
  210. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/stats/agents/openai.yaml +0 -0
  211. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/triage-drift/SKILL.md +0 -0
  212. {sidegraph-0.5.0 → sidegraph-0.7.0}/plugin/sidegraph/skills/triage-drift/agents/openai.yaml +0 -0
  213. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/__init__.py +0 -0
  214. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/apply.py +0 -0
  215. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/model.py +0 -0
  216. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/planner.py +0 -0
  217. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/proof.py +0 -0
  218. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/review.py +0 -0
  219. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/bootstrap/scan.py +0 -0
  220. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/engine/__init__.py +0 -0
  221. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/host/__init__.py +0 -0
  222. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/profiles.py +0 -0
  223. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/stats/__init__.py +0 -0
  224. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/viz/__init__.py +0 -0
  225. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/viz/assets/vis-network.min.js +0 -0
  226. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/viz/model.py +0 -0
  227. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/viz/render.py +0 -0
  228. {sidegraph-0.5.0 → sidegraph-0.7.0}/src/sidegraph/viz/template.html +0 -0
  229. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/__init__.py +0 -0
  230. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bitfinex_slice.json +0 -0
  231. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/flows/bmad/_bmad-output/planning-artifacts/architecture/cache/ARCHITECTURE-SPINE.md +0 -0
  232. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/flows/generic-adr/docs/adr/001-retry.md +0 -0
  233. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/flows/genkovich-sdd/docs/features/cache/adr/001.md +0 -0
  234. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/flows/spec-kit/specs/cache/plan.md +0 -0
  235. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/flows/superpowers/docs/superpowers/specs/2026-07-01-cache-design.md +0 -0
  236. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/graph.json +0 -0
  237. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/hosts/claude/.claude/settings.json +0 -0
  238. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/hosts/claude/.mcp.json +0 -0
  239. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/hosts/codex/.codex/config.toml +0 -0
  240. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/hosts/codex/.codex/hooks/hooks.json +0 -0
  241. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/bootstrap/scan/docs/adr/001-safe.md +0 -0
  242. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/PUBLIC_CORPORA.txt +0 -0
  243. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/openspec/_provenance.json +0 -0
  244. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/openspec/graph.json +0 -0
  245. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/self-corpus/_provenance.json +0 -0
  246. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/self-corpus/expected/retrieval-engine-reader.md +0 -0
  247. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/corpus/self-corpus/graph.json +0 -0
  248. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/adr/0001-use-sessions.md +0 -0
  249. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/bmad/ARCHITECTURE-SPINE.md +0 -0
  250. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/architecture/architecture-payments-2026-07-30/.memlog.md +0 -0
  251. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/architecture/architecture-payments-2026-07-30/ARCHITECTURE-SPINE.md +0 -0
  252. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/prds/prd-payments-2026-07-30/prd.md +0 -0
  253. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/genkovich/0001-queue-backpressure.md +0 -0
  254. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/genkovich/sad.md +0 -0
  255. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/genkovich/tree/docs/features/payments/adr/0001-queue-backpressure.md +0 -0
  256. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/genkovich/tree/docs/features/payments/sad.md +0 -0
  257. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/genkovich/tree/docs/features/payments/spec.md +0 -0
  258. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/design-empty.md +0 -0
  259. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/design-h3-split.md +0 -0
  260. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/design-with-summary.md +0 -0
  261. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/design.md +0 -0
  262. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/proposal-alternatives.md +0 -0
  263. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/proposal.md +0 -0
  264. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/design.md +0 -0
  265. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/proposal.md +0 -0
  266. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/specs/cap/spec.md +0 -0
  267. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/tasks.md +0 -0
  268. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/archive/2026-01-01-add-thing/design.md +0 -0
  269. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/changes/archive/2026-01-01-add-thing/proposal.md +0 -0
  270. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/config.yaml +0 -0
  271. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/openspec/tree/openspec/specs/cap/spec.md +0 -0
  272. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/spec-kit/plan.md +0 -0
  273. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/spec-kit/tree/specs/003-payment-retries/plan.md +0 -0
  274. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/spec-kit/tree/specs/003-payment-retries/spec.md +0 -0
  275. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/superpowers/2026-07-01-example-design.md +0 -0
  276. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/flows/superpowers/2026-07-01-thin-design.md +0 -0
  277. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/fixtures/mini_graph.json +0 -0
  278. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_anchoring_mapping_refresh.py +0 -0
  279. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_apply.py +0 -0
  280. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_integrations.py +0 -0
  281. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_model.py +0 -0
  282. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_planner.py +0 -0
  283. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_proof.py +0 -0
  284. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_review.py +0 -0
  285. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_bootstrap_scan.py +0 -0
  286. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_capture_integration.py +0 -0
  287. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_compact.py +0 -0
  288. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_doctor.py +0 -0
  289. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_ratify.py +0 -0
  290. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_ratify_facts.py +0 -0
  291. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_sync_check.py +0 -0
  292. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_cli_viz.py +0 -0
  293. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_codex_plugin.py +0 -0
  294. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_community_baseline.py +0 -0
  295. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_corpus_expected_renders.py +0 -0
  296. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_corpus_self_corpus.py +0 -0
  297. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_coverage_telemetry_e2e.py +0 -0
  298. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_auto_share.py +0 -0
  299. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_code_drift.py +0 -0
  300. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_dangling_supports.py +0 -0
  301. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_duplicate_entity.py +0 -0
  302. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_graph_root_mismatch.py +0 -0
  303. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_never_surfaced.py +0 -0
  304. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_scan.py +0 -0
  305. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_stale_instructions.py +0 -0
  306. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_doctor_unratified_accept.py +0 -0
  307. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_domains.py +0 -0
  308. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_entity_duplicate_resolution.py +0 -0
  309. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_entity_get_or_create_race.py +0 -0
  310. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_env_isolation.py +0 -0
  311. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_fact_reachability_gate.py +0 -0
  312. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_flow_profile.py +0 -0
  313. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_git_bindings_blame.py +0 -0
  314. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_git_bindings_hook.py +0 -0
  315. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_git_bindings_provenance.py +0 -0
  316. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_host_drift_nudge.py +0 -0
  317. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_host_session_key.py +0 -0
  318. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_mind_model_additive_fields.py +0 -0
  319. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_openspec_profile.py +0 -0
  320. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_pathless_descriptor_adoption.py +0 -0
  321. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_pilot_kit_corpus_fit.py +0 -0
  322. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_proposal_lifecycle.py +0 -0
  323. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_ratify_listing_gone_dark.py +0 -0
  324. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_community_labels.py +0 -0
  325. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_doc_nodes.py +0 -0
  326. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_graph.py +0 -0
  327. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_integration.py +0 -0
  328. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_nodes_in_file.py +0 -0
  329. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_perf.py +0 -0
  330. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_rationale.py +0 -0
  331. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_read.py +0 -0
  332. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_resolve.py +0 -0
  333. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_subdir_mismatch.py +0 -0
  334. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_reader_version.py +0 -0
  335. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_redaction_seeded.py +0 -0
  336. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_budget_counters.py +0 -0
  337. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_context.py +0 -0
  338. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_drift_marker.py +0 -0
  339. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_drilldown.py +0 -0
  340. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_facts.py +0 -0
  341. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_ids.py +0 -0
  342. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_integration.py +0 -0
  343. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_rank.py +0 -0
  344. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_seeds.py +0 -0
  345. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_shown_ids.py +0 -0
  346. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_terminal_evidence.py +0 -0
  347. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_thin_tools.py +0 -0
  348. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_toptier.py +0 -0
  349. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_retrieval_unratified.py +0 -0
  350. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sandbox_hygiene.py +0 -0
  351. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_schema_domain.py +0 -0
  352. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_schema_fact.py +0 -0
  353. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_add_anchors.py +0 -0
  354. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_anchoring.py +0 -0
  355. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_coverage_events.py +0 -0
  356. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_drilldown.py +0 -0
  357. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_facts.py +0 -0
  358. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_find_entity.py +0 -0
  359. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_get_store.py +0 -0
  360. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_get_task_context.py +0 -0
  361. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_import.py +0 -0
  362. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_mcp_smoke.py +0 -0
  363. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_prewrite_anchor_validation.py +0 -0
  364. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_ratify_facts.py +0 -0
  365. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_redaction.py +0 -0
  366. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_supersede.py +0 -0
  367. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_sync_anchors.py +0 -0
  368. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_thin_tools.py +0 -0
  369. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_server_verify.py +0 -0
  370. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_stats_skill.py +0 -0
  371. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_stats_snapshot.py +0 -0
  372. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store.py +0 -0
  373. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_atomic_write_tmp_names.py +0 -0
  374. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_canonical_stat.py +0 -0
  375. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_compact.py +0 -0
  376. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_compact_review.py +0 -0
  377. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_concurrent_open.py +0 -0
  378. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_coverage_telemetry.py +0 -0
  379. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_derived_community.py +0 -0
  380. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_domains.py +0 -0
  381. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_entities.py +0 -0
  382. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_fact_cascade.py +0 -0
  383. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_facts.py +0 -0
  384. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_mutation_immediate.py +0 -0
  385. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_opens_with_merged_duplicate.py +0 -0
  386. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_persistence.py +0 -0
  387. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_ratification.py +0 -0
  388. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_rebuild_atomicity.py +0 -0
  389. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_render_events.py +0 -0
  390. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_retrieval.py +0 -0
  391. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_slug_conflicts.py +0 -0
  392. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_telemetry.py +0 -0
  393. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_threading.py +0 -0
  394. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_store_tmp_sweep_age.py +0 -0
  395. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_domains.py +0 -0
  396. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_drift_cache.py +0 -0
  397. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_report_has_findings.py +0 -0
  398. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_volatile_heal.py +0 -0
  399. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_sync_wiring.py +0 -0
  400. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_telemetry_retention.py +0 -0
  401. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_verify_transitions.py +0 -0
  402. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_viz_asset_packaged.py +0 -0
  403. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_viz_model.py +0 -0
  404. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_viz_render_html.py +0 -0
  405. {sidegraph-0.5.0 → sidegraph-0.7.0}/tests/test_viz_render_json.py +0 -0
@@ -108,45 +108,6 @@ jobs:
108
108
  base="$(git merge-base "origin/$GITHUB_BASE_REF" HEAD)"
109
109
  uv run sidegraph-verify --against "$base" --json
110
110
 
111
- # A commit-msg hook (see .pre-commit-config.yaml's `no-session-links`) cannot see a pull
112
- # request's description, so this is the PR-body half of the same owner ruling: never
113
- # publish an external session link. Shares tools/check_no_session_links.py's pattern list
114
- # with that hook, rather than a second copy, so the rule cannot drift between the two.
115
- # `if: github.event_name == 'pull_request'` matters here specifically: this workflow is
116
- # also invoked via `workflow_call` by publish.yml on a tag push, which carries no PR body.
117
- # Lives in ci.yml, not its own workflow file: it is a lint-shaped gate exactly like the
118
- # local corpus-leak/public-twins/shipped-links checkers, ci.yml already hosts other
119
- # `pull_request`-only jobs (store-lint, anchor-health) with the identical self-guard shape,
120
- # and a fourth workflow file would buy nothing a job here doesn't already give.
121
- # Self-guarded like those checkers: tools/ is not in the public repo's release ALLOWLIST,
122
- # so this exits 0 cleanly on an external contributor's PR there instead of failing on a
123
- # checker that by design does not exist in that snapshot.
124
- pr-description-link-gate:
125
- if: github.event_name == 'pull_request'
126
- runs-on: ubuntu-latest
127
- timeout-minutes: 5
128
- steps:
129
- # zizmor artipacked: this job never pushes; do not persist git credentials past checkout.
130
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
131
- with:
132
- persist-credentials: false
133
-
134
- - name: Check PR description for forbidden session links
135
- # The PR body is untrusted (attacker-controlled on a fork PR), so it goes through an
136
- # env var rather than being interpolated into the script text via `${{ }}` — that
137
- # would be a script-injection hole. `github.event.pull_request.body` is `null` for an
138
- # empty description; GitHub renders that as an empty env var, and `printf '%s'` on an
139
- # empty string just produces an empty file, which the checker reports as clean.
140
- env:
141
- PR_BODY: ${{ github.event.pull_request.body }}
142
- run: |
143
- if [ ! -f tools/check_no_session_links.py ]; then
144
- echo "tools/check_no_session_links.py not present (public snapshot) — skipping"
145
- exit 0
146
- fi
147
- printf '%s' "$PR_BODY" > "$RUNNER_TEMP/pr-body.txt"
148
- python3 tools/check_no_session_links.py "$RUNNER_TEMP/pr-body.txt"
149
-
150
111
  # Recipe 1 self-applied: rebuild the graph from scratch and fail on attention findings
151
112
  # (stale decisions, empty/overbroad domains, slug conflicts, refresh failures). A
152
113
  # cache-less rebuild was verified label-identical to the local cached graph and the
@@ -0,0 +1,76 @@
1
+ # The PR half of the owner ruling "never publish an external session link", shared with the
2
+ # `no-session-links` commit-msg hook (.pre-commit-config.yaml) through
3
+ # tools/check_no_session_links.py, so the rule cannot drift between them. A commit-msg hook
4
+ # cannot see a pull request's title or description, and a commit made without the hook never
5
+ # passes through it, so this checks all three places text gets published:
6
+ # - the PR title and description, verbatim (lines starting with `#` are markdown headings
7
+ # there, not comments), and the title again because the default merge commit carries it;
8
+ # - the PR's recorded commit messages, exactly as they sit in history.
9
+ # Its own workflow file, not a job in ci.yml, so `edited` can re-run it without re-running
10
+ # the whole CI on every description edit. Every event for an open PR runs both steps: an
11
+ # `edited` run that skipped the commit check would go green on the same head SHA and replace
12
+ # a red run in the checks view. Edits to a closed or merged PR skip the commit check, so old
13
+ # history is not re-checked. No `concurrency` block: with one, a later run could cancel an
14
+ # in-flight `synchronize` run and leave the commits unchecked. The job takes seconds.
15
+ # Fails closed: the checker ships in the public snapshot too, and a run without it fails
16
+ # instead of skipping, so deleting or moving it cannot turn the gate green.
17
+ # Actions are pinned to commit SHAs (the tag comment records the version).
18
+ name: session-link-gate
19
+
20
+ on:
21
+ pull_request:
22
+ types: [opened, edited, reopened, synchronize]
23
+
24
+ permissions:
25
+ contents: read
26
+
27
+ jobs:
28
+ pr-description-link-gate:
29
+ runs-on: ubuntu-latest
30
+ timeout-minutes: 5
31
+ steps:
32
+ # zizmor artipacked: this job never pushes; do not persist git credentials past checkout.
33
+ # fetch-depth 0: the commit step needs the whole base..head range.
34
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
35
+ with:
36
+ persist-credentials: false
37
+ fetch-depth: 0
38
+
39
+ - name: Check PR title and description for forbidden session links
40
+ # Title and body are untrusted (attacker-controlled on a fork PR), so they go through
41
+ # env vars rather than `${{ }}` in the script text, which would be a script-injection
42
+ # hole. `github.event.pull_request.body` is `null` for an empty description; GitHub
43
+ # renders that as an empty env var. Reported line numbers run two higher than in the
44
+ # body: the title and a blank line come first.
45
+ env:
46
+ PR_TITLE: ${{ github.event.pull_request.title }}
47
+ PR_BODY: ${{ github.event.pull_request.body }}
48
+ run: |
49
+ if [ ! -f tools/check_no_session_links.py ]; then
50
+ echo "::error::tools/check_no_session_links.py is missing; the session-link gate cannot run"
51
+ exit 1
52
+ fi
53
+ printf '%s\n\n%s\n' "$PR_TITLE" "$PR_BODY" > "$RUNNER_TEMP/pr-text.txt"
54
+ python3 tools/check_no_session_links.py --published "$RUNNER_TEMP/pr-text.txt"
55
+
56
+ - name: Check the PR's commit messages for forbidden session links
57
+ # Runs on every event for an open PR, description edits included: a green run with
58
+ # this step skipped would replace a red one on the same head SHA. A closed or merged
59
+ # PR (its commits predate this gate) is not re-checked. A SHA matches no pattern, so
60
+ # each reported line points into the commit named above it; on failure the step lists
61
+ # the `commit` start lines (SHAs and line numbers only, never the offending text).
62
+ if: github.event.pull_request.state == 'open'
63
+ env:
64
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
65
+ HEAD_SHA: ${{ github.event.pull_request.head.sha }}
66
+ run: |
67
+ if [ ! -f tools/check_no_session_links.py ]; then
68
+ echo "::error::tools/check_no_session_links.py is missing; the session-link gate cannot run"
69
+ exit 1
70
+ fi
71
+ git log --format='commit %H%n%B' "$BASE_SHA..$HEAD_SHA" > "$RUNNER_TEMP/pr-commits.txt"
72
+ python3 tools/check_no_session_links.py --published "$RUNNER_TEMP/pr-commits.txt" || {
73
+ echo "commit start lines in the checked log:"
74
+ grep -n '^commit ' "$RUNNER_TEMP/pr-commits.txt"
75
+ exit 1
76
+ }
@@ -28,5 +28,6 @@ paths = [
28
28
  '''^tests/test_server_redaction\.py$''',
29
29
  '''^design/superpowers/plans/2026-07-06-capture-ratification\.md$''',
30
30
  '''^design/superpowers/plans/2026-07-10-facts-layer\.md$''',
31
+ '''^design/superpowers/reviews/2026-09-28-grok-whole-repo-review\.md$''',
31
32
  '''^src/sidegraph/viz/assets/vis-network\.min\.js$''',
32
33
  ]
@@ -115,10 +115,11 @@ repos:
115
115
  # nothing and would couple the gate to uv project discovery — which fails outright in a
116
116
  # tree whose pyproject uv cannot parse (the release script's own test fixtures).
117
117
  # The `test -f` guard exists because THIS FILE SHIPS: .pre-commit-config.yaml is in the
118
- # release ALLOWLIST while tools/ is not, and the release script verifies the snapshot by
119
- # running `pre-commit run --all-files` inside it. Without the guard, an always_run hook
120
- # would look for a checker that by design does not exist there and fail every release,
121
- # the public repo's CI, and every public contributor's first commit.
118
+ # release ALLOWLIST while tools/ ships only the session-link checker, and the release
119
+ # script verifies the snapshot by running `pre-commit run --all-files` inside it.
120
+ # Without the guard, an always_run hook would look for a checker that by design does
121
+ # not exist there and fail every release, the public repo's CI, and every public
122
+ # contributor's first commit.
122
123
  entry: bash -c 'test ! -f tools/corpus_leak.py || exec python3 tools/corpus_leak.py'
123
124
  language: system
124
125
  pass_filenames: false
@@ -139,8 +140,8 @@ repos:
139
140
  # AGENTS.public.md) with no base counterpart, or a plugin manifest that still points
140
141
  # at the working tree instead of the released package, would otherwise ship broken
141
142
  # and surface only when a consumer's install fails. Self-guarded like
142
- # corpus-leak-gate: tools/ is not in the release ALLOWLIST, so this checker does not
143
- # exist in the public snapshot or its CI.
143
+ # corpus-leak-gate: tools/ ships only the session-link checker, so this checker does
144
+ # not exist in the public snapshot or its CI.
144
145
  entry: bash -c 'test ! -f tools/check_public_twins.py || exec python3 tools/check_public_twins.py'
145
146
  language: system
146
147
  pass_filenames: false
@@ -150,8 +151,8 @@ repos:
150
151
  name: shipped-docs link check
151
152
  # A relative Markdown link that resolves in THIS repo can still 404 once the release
152
153
  # mapping is applied (design/whitepaper/draft.md -> docs/whitepaper/index.md, `.public.`
153
- # twins renamed onto their base names, design/ and tools/ absent) — this catches that
154
- # before the commit lands. Self-guarded: tools/ is not in the release ALLOWLIST.
154
+ # twins renamed onto their base names, design/ absent, tools/ reduced to the
155
+ # session-link checker) — this catches that before the commit lands. Self-guarded: tools/ ships only the session-link checker.
155
156
  entry: bash -c 'test ! -f tools/check_shipped_links.py || exec python3 tools/check_shipped_links.py'
156
157
  language: system
157
158
  pass_filenames: false
@@ -161,15 +162,15 @@ repos:
161
162
  name: no session links in commit message
162
163
  # Reads the commit message file git passes a commit-msg hook, never the changed
163
164
  # files — the forbidden patterns are tools/check_no_session_links.py's four
164
- # session-link shapes, the same ones .github/workflows/ci.yml's
165
- # `pr-description-link-gate` job checks against a PR body.
165
+ # session-link shapes, the same ones .github/workflows/session-link-gate.yml
166
+ # checks against a PR's title, body and recorded commit messages.
166
167
  # `stages: [commit-msg]` is load-bearing, not decoration: a hook with no explicit
167
168
  # `stages` inherits EVERY stage, and `pre-commit run --all-files` (CI's lint job, and
168
169
  # a developer's own habit) defaults to `--hook-stage pre-commit` — without this pin,
169
170
  # that plain run would try to execute this hook anyway, with no COMMIT_EDITMSG file
170
171
  # to check, and fail every lint run for a reason that has nothing to do with lint.
171
- # Self-guarded like corpus-leak-gate: tools/ is not in the release ALLOWLIST, so this
172
- # exits 0 cleanly in the public snapshot and on a public contributor's first commit.
172
+ # Self-guarded like corpus-leak-gate, though the checker does ship: the guard only covers a
173
+ # deleted checker, and the session-link-gate workflow is the gate that fails then.
173
174
  entry: bash -c 'test ! -f tools/check_no_session_links.py || exec python3 tools/check_no_session_links.py "$@"' --
174
175
  language: system
175
176
  stages: [commit-msg]
@@ -7,6 +7,440 @@ interfaces, exactly, and what each one promises: [`docs/reference/stability.md`]
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] — 2026-10-02
11
+
12
+ ### Changed
13
+
14
+ - **The hooks and the MCP server look a missing relative store up inside the repository.** The
15
+ precedence between `--db`, `SIDEGRAPH_DIR`, `SIDEGRAPH_DB` and the default is unchanged, and a
16
+ store that exists where its relative path is anchored still wins. What is new: when a relative
17
+ `SIDEGRAPH_DIR` (or the default `.sidegraph`) does not exist there, the three hooks and the MCP
18
+ server visit the parent directories, nearest first, up to and including the repository root (the
19
+ nearest directory holding a `.git` entry, a directory or a file), and use the first store found.
20
+ The lookup never leaves the repository (a `.git` entry at your home directory or above it is not
21
+ a repository root, so a dotfiles repository does not turn `~/.sidegraph` into every project's
22
+ store) and does not run for `--db`, an absolute `SIDEGRAPH_DIR`, `SIDEGRAPH_DB`, a value with a
23
+ `..` part, or an anchor that is a symlink. The CLI, `sidegraph-init`
24
+ and `sidegraph-bootstrap` are unchanged: from a subdirectory they still need `--db`. To keep the
25
+ old outcome on a host surface, pass an absolute `SIDEGRAPH_DIR`.
26
+
27
+ ### Fixed
28
+
29
+ - **A SessionStart hook registered twice on one host no longer injects the map twice.** Two
30
+ copies firing for one session at once both read the old duplicate-check ledger and both emitted;
31
+ the check now decides and stamps inside one write transaction, and a duplicate still answers
32
+ without waiting for a lock. The ledger keeps one row, so a repeat is still let through when
33
+ another session starts in between, or when two sessions with doubled hooks start together.
34
+ - **Sync's moved rung adopts only a real move.** When an anchor's file is gone, sync looks the
35
+ name up across the whole graph and follows a unique hit to its new file. That lookup ignores
36
+ case and decoration, and the check behind it (the old path is out of `HEAD`, the new one is in
37
+ it) did not ask whether the new path was there before. A type deleted together with its file
38
+ could therefore be re-anchored onto an unrelated file that held an old member of the same name:
39
+ a deleted `Priority` followed `.priority` into another file, silently rewriting the entity's
40
+ committed `descriptor.file_path`. Two rules now close it. The hit must be the same name once
41
+ the call decoration (`()`, a leading `.`) is stripped from both sides, with case kept. And git
42
+ must show the new path arriving in the change that removed the old one: the mainline commit that
43
+ deleted the old path (a branch merged with `--no-ff` counts as one change) must have a first
44
+ parent without the new path and must hold it itself. With `SIDEGRAPH_TRUST_DIRTY_TREE=on` and the
45
+ old path still in `HEAD`, the new path must be absent from `HEAD`. Every git failure refuses, as
46
+ does a history with no deletion in it, so a move out of a path git never held (a gitignored
47
+ directory) and a move that a shallow clone cannot prove now end `orphaned`, which
48
+ `sidegraph:heal-anchors` repairs, instead of being adopted. An uncommitted delete onto a path
49
+ that is already in `HEAD` is `orphaned` too, not remembered as a move waiting for a commit: no
50
+ commit can make it one. The search matches the old path literally (a path such as
51
+ `app/[id]/view.tsx` is not a glob) and ignores `log.showSignature`.
52
+
53
+ Some real moves are refused as well, because git's history alone does not show them as one
54
+ change. Each ends `orphaned` and `sidegraph:heal-anchors` re-anchors it:
55
+ - the new file added in one commit and the old one deleted in another on the first-parent line,
56
+ including a branch merged fast-forward or rebase-merged;
57
+ - a second move before any sync ran (`A` to `B` to `C` while the descriptor still names `A`);
58
+ - an old path that was re-added and then deleted again.
59
+
60
+ To check what an earlier release adopted, list the descriptor rewrites:
61
+ `git log -p --diff-filter=M -- .sidegraph/entities/ | grep -E '^(commit |[-+]\s+"file_path")'`.
62
+ A rewrite is a real move only if the new path was added by the commit that deleted the old one
63
+ (`git log --first-parent -m -1 --diff-filter=D -- <old path>` finds that commit; the new path
64
+ must be missing from its first parent and present in it). Re-anchor a wrong one by superseding
65
+ the record with fresh anchors.
66
+
67
+ - **The `SessionStart` instruction names a call the tool accepts, and a domain's mistake count
68
+ counts what the domain holds.** The standing line told the agent to call
69
+ `get_task_context(seeds)`, but the tool takes `files` and `entities` and rejects anything else,
70
+ so an agent that followed it made a call that failed validation. It now says
71
+ `get_task_context(files=[…])` with repo-relative paths, points at the check-plan skill before a
72
+ non-trivial change when it is available, and says to load the tool first if the host lists it
73
+ only by name. Separately, the per-domain count in the `SessionStart` map read "0 mistake(s)"
74
+ over a domain whose gotchas were anchored to its own code, because it counted only decisions
75
+ tagged to the domain itself. It now counts the accepted `gotcha`, `lesson` and `constraint`
76
+ decisions that `drill_down` serves for the domain, so the two show one number. The map's cache
77
+ records the store's digest, so a retrieval call on an unchanged store no longer rebuilds it, and
78
+ `SessionStart` reads the unratified list without building the whole map. The bindings table gains
79
+ an index by entity (an existing store gets it on its next open), which takes a rebuild of the map
80
+ from about 0.1 s to under 0.03 s on a real store, so the cost of a session start is what it was
81
+ before the count changed, also right after a store change and in a linked worktree. A worktree
82
+ builds its map with the main checkout's graph reader, so it counts the same decisions the main
83
+ checkout does. A map written by a path that has no graph reader (ratify, capture) leaves out
84
+ decisions anchored to a whole document until the next sync.
85
+
86
+ - **A Claude Code subagent gets its own read nudges, and its touches are told apart.** A
87
+ subagent's hook payload carries its parent's session id plus an `agent_id` of its own, and
88
+ the `PreToolUse` nudge keys were per session: once the main agent had been nudged, every
89
+ subagent it started read anchored files blind. Each agent, the session's own and every
90
+ subagent, now gets one generic and one path-specific nudge. The
91
+ keys are claimed in a single statement, so a subagent's parallel opening reads cannot both
92
+ nudge, and `SessionStart` expires keys older than 30 days. The `retrieval_events` journal
93
+ gains a nullable `agent` column, added to an existing index on its next open, that records
94
+ which subagent made a touch; the row stays under the parent's session, so `sidegraph-stats`
95
+ counts the same sessions as before. Only `agent_id` counts, never `agent_type`: a main
96
+ session started with `claude --agent <name>` is still the session's own agent.
97
+
98
+ - **An anchor written `Type.member` now resolves to the member.** Graphify labels a method
99
+ `.playClip()` and links it to its type, an agent writes `AudioPlayback.playClip`, and the two
100
+ never met: the anchor was born orphaned, and a seed naming it never reached the record, which
101
+ surfaced only through its community, as an unratified proposal. With a `file_path`, a name
102
+ with no exact match now falls back to a member of the named type in that file. It is for code
103
+ identifiers only (prose, a numbered heading or a hyphenated file name never reads as a
104
+ member). The name is split at the last `.`, `::` or `#` and the member is compared with its
105
+ case kept. A candidate that an edge ties to a different type is refused, and the answer stays
106
+ orphaned, never guessed, when several remain or when the file holds a case-only twin of the
107
+ member (a struct `Message` beside a method `.message()`, which the store treats as one
108
+ anchor). Without a file, and for a path-qualified name (`src/pkg/mod.py`), nothing changes.
109
+ On the read path a seed that names a stored anchor, and every node a seed resolves to, now
110
+ map to their store entities by the engine mapping, in the neighbour walk as well, so such a
111
+ record ranks as a mistake or decision again. The first `sidegraph-sync` after the upgrade
112
+ reruns once on its own (the sync stamp now carries a resolver revision, which a report does
113
+ not show) and heals the orphans this left behind. The skills and guides no longer say
114
+ `Type.member` names never resolve; the bare name with its file stays the preferred form.
115
+
116
+ - **A hook command that cannot start no longer blocks or loops the host.** On `Stop`, both hosts
117
+ feed a hook's stderr back when the hook exits 2: Codex continues the turn, and Claude Code
118
+ continues the conversation, and Claude Code also blocks the tool call on `PreToolUse`. `uv`
119
+ exits 2 on some of its own errors (a project it cannot find, a cache it cannot write) and `dash`
120
+ exits 2 when the `cd` fails, so a hook command that never reached Python could do exactly that,
121
+ over and over in a headless `codex exec` run. Every shipped hook command, in both plugins and in
122
+ the manual recipes in the docs, now ends with a guard: `Stop` and `PreToolUse` answer `{}`, and
123
+ `SessionStart` answers a one-line `systemMessage` that says the hook could not start and to run
124
+ the hook command in a terminal to see the error. A command that starts Python behaves as
125
+ before. **Codex users: approve the two hooks again once after updating.** Codex records trust
126
+ per hook definition and the definition includes its command, so the changed commands do not run
127
+ until you approve them in `/hooks` or at the next interactive session's trust prompt. **If you
128
+ wired the hooks by hand**, append the guard to your own commands in `.claude/settings.json` or
129
+ `.codex/hooks.json`; the recipes in the docs show it. The Codex page also now says how to run a
130
+ headless review without Sidegraph's hooks.
131
+ - **The capture nudge now arms on Codex.** The Stop hook's substance gate understood only Claude
132
+ Code transcripts, so on a Codex rollout it counted zero prompts and never nudged: every Codex
133
+ session ended without the capture reminder. The gate now reads a rollout too. A person's prompt
134
+ is a user message that is not text Codex wrote itself (the project instructions and environment
135
+ blocks, plugin and skill blocks, an aborted-turn note, a Stop hook's own block reason fed back);
136
+ nor does an answer to the agent's question, which arrives mid-turn, count as one. Each prompt
137
+ counts once although Codex mirrors it as an event. A thread arms after two real prompts, never
138
+ on tool calls. Subagent threads, Codex's automatic reviewer and headless `codex exec` runs, including
139
+ ones started through the Codex TypeScript SDK, never arm, so a review panel's `-o` output is
140
+ never replaced by a continuation. The nudge text, the once-per-session ledger and the hook
141
+ definitions are unchanged, so Codex's trust in the installed hooks stays valid. Claude Code
142
+ sessions are counted exactly as before.
143
+ - **A session started in a subdirectory no longer opens a second, empty store.** Claude Code sets
144
+ `CLAUDE_PROJECT_DIR` to the directory it was launched in, so a launch in `repo/pkg` with the
145
+ plugin active created `repo/pkg/.sidegraph` beside the repository's own store, and the session
146
+ saw no memory. The hooks and the MCP server now use `repo/.sidegraph`, record touches relative
147
+ to it (`pkg/a.py`, so they join the anchors) and keep the nested-store case (`.config/sidegraph`)
148
+ repo-relative. The hooks also read the graph the store's project holds, as the CLI and the MCP
149
+ server do, so a store in a nested directory finds its own `graphify-out/graph.json`; a relative
150
+ `SIDEGRAPH_GRAPH` is no longer looked up under `$CLAUDE_PROJECT_DIR`. A store the old behaviour
151
+ already created is not touched: when the store a session uses is empty and the repository's
152
+ store above it holds records, `SessionStart` adds one line naming both. Remove the empty
153
+ `<subdirectory>/.sidegraph` to use the repository's. A stray store that holds any record (one
154
+ proposed decision from an old capture is enough) is not reported and keeps hiding the
155
+ repository's: review it with `sidegraph-ratify --db <subdirectory>/.sidegraph`, record what
156
+ matters again in the repository's store, then remove the stray directory.
157
+
158
+ - **A code graph that never caught up with `HEAD` now says so.** Nothing compared the commit
159
+ `graph.json` was built at (`built_at_commit`) with `HEAD`, so a graph stuck at an old commit
160
+ looked up to date for good, and every `get_task_context` call seeded with a file added since
161
+ returned a bare `No context found.` The comparison now runs in the engine reader and counts a
162
+ graph as stale only when a file it should hold changed or appeared since the build (a commit
163
+ touching only file types the graph does not hold does not, and a graph built from a dirty tree
164
+ and committed afterwards does not). It surfaces in four places:
165
+ - `SessionStart` adds one line when the graph is stale, with the rebuild command
166
+ (`graphify update .` from the repository root);
167
+ - `get_task_context` appends a `## Not in the code graph` block after its answer when a seed is
168
+ not a file the graph holds, saying whether the graph is stale, shows no committed change since
169
+ its build (the file may be newer than the build, or one the engine skips) or could not be
170
+ compared, or whether the path is a directory, missing or not a normalized repo-relative path
171
+ (an absolute path, `./x`). Seeds the graph holds leave the answer byte-identical and cost no git call;
172
+ - `sidegraph-doctor` reports a new advisory finding, `graph-stale`. **`sidegraph-doctor --check`
173
+ now exits `2` on a stale graph**; a CI job that rebuilds the graph before running doctor is
174
+ unaffected;
175
+ - `sidegraph-stats` adds a `stale:` continuation line under the GRAPH counts, and its `--json`
176
+ gains `graph.freshness`, `built_at`, `commits_behind` and `stale_files`.
177
+
178
+ The docs no longer call a missed refresh "self-healing": the lazy check re-syncs a graph that
179
+ was rebuilt, and only a rebuild fixes one that never was.
180
+
181
+ - **A linked worktree reads the main checkout's code graph, and a missing graph is said.**
182
+ `graphify-out/` is gitignored, so a `git worktree add` checkout had the tracked store and no
183
+ graph, and `get_task_context` resolved nothing there. When the store's own graph is missing and
184
+ its repository is a linked worktree of a main checkout, the read tools (`get_task_context`,
185
+ `query_structure`, `query_decisions`, `drill_down`) and `SessionStart` now open the main
186
+ checkout's graph, found from the worktree's `.git` file alone (no git call). That graph is synced
187
+ index-only: a worktree's index starts cold, and without the derived state (domain communities,
188
+ community bindings, engine mappings) `drill_down` lost most of a domain's decisions and
189
+ `get_task_context` its `## Related` section. The sync never rewrites a tracked file (its moved
190
+ rung, the one step that can, abstains), so the worktree's store stays as git checked it out.
191
+ `SessionStart` builds the domain map in memory from the store, adds a line saying whose graph it
192
+ reads, and names the main checkout in its stale-graph line. `get_task_context` tells a file that
193
+ exists only on the branch apart from one the main checkout's graph is stale for. A file the
194
+ branch changed that the main checkout also has is described as it is in the main checkout (its
195
+ symbols and the edges between them), and nothing warns about it.
196
+ `sync_anchors`, `list_domain_candidates`, every write tool and every CLI default keep reading the
197
+ store's own graph. A bare repository (also one cloned into `x/.git`), a git directory that is
198
+ separate and not itself named `.git`, a submodule and a plain `git clone` have no main checkout
199
+ to borrow from.
200
+ - **`get_task_context` says when there is no code graph at all.** With no reader and at least one
201
+ seed, the answer ends with a `## No code graph` block naming the path that was looked at and
202
+ how to build it, instead of an answer that looked like a search with no hits. A graph that is
203
+ there and cannot be read is reported as not readable, not as missing.
204
+
205
+ ## [0.6.0] — 2026-10-01
206
+
207
+ ### Added
208
+
209
+ - **`sidegraph-verify` reports `unsafe-record-id`.** A record file, `bindings/` file or
210
+ archive line whose id is not a single safe path segment is now a finding, and a
211
+ non-string id in a record or archive file no longer crashes the run with `unhashable type`.
212
+ - **`sidegraph-verify` reports a symlinked store entry as `symlinked-store-entry`.** One
213
+ violation per store-owned directory or file that is a symlink, so a committed link fails the
214
+ CI gate; `sidegraph-doctor` inherits it.
215
+
216
+ ### Changed
217
+
218
+ - **A `--graph` typed as a relative path resolves against the shell in `sidegraph-ratify`
219
+ and `sidegraph-stats`.** It used to resolve against the store's project. The default and
220
+ `$SIDEGRAPH_GRAPH` still follow the store. The same holds in every command that reads a
221
+ graph, so the copy-and-sync workflow works with `--graph graphify-out/graph.json` typed from
222
+ the repository.
223
+ - **A store in a nested directory needs an absolute `SIDEGRAPH_GRAPH`.** With
224
+ `SIDEGRAPH_DIR=.config/sidegraph` and a relative `SIDEGRAPH_GRAPH`, the CLI now looks for the
225
+ graph under `.config/` (the store's project) instead of using the shell's copy. A command
226
+ that needs the graph fails with a hint; `init`, `ratify`, `doctor` and `stats`, for which it
227
+ is optional, continue and print the hint (`stats` reports its graph metrics as unavailable). Set an absolute `SIDEGRAPH_GRAPH` or pass `--graph`. The MCP server now
228
+ follows the same rule (next entry); the hooks are unaffected.
229
+ - **The MCP server reads the graph that belongs to its store.** A relative `SIDEGRAPH_GRAPH`
230
+ (or the default `graphify-out/graph.json`) used to resolve against the server's working
231
+ directory, so a store reached by an absolute `SIDEGRAPH_DIR`, or a store in a nested directory,
232
+ could be synced against one project's graph by the CLI and another's by `sync_anchors` and the
233
+ retrieval tools, and the store's graph version flipped back and forth. It now resolves against
234
+ the store's project, the same rule the CLI uses, and an empty `SIDEGRAPH_GRAPH` counts as unset.
235
+ With the default layout (`.sidegraph` in the project, the server started there) nothing changes.
236
+ A nested store needs an absolute `SIDEGRAPH_GRAPH`; `sync_anchors` reports `graph not readable`
237
+ with the path and names the graph it found beside the working directory, when there is one.
238
+ - **A document is imported again once, if its `provenance.ref` changes.** A document
239
+ imported before this release from a subdirectory or by an absolute path is imported
240
+ again under its repository path. The old record stays. A leftover that is still `proposed` can be dropped with
241
+ `sidegraph-ratify --drop <id>`. An `accepted` leftover has no one-step retirement: leave
242
+ it, or supersede it by hand with `supersede_decision`, which writes a new record.
243
+ - **`sidegraph-import --path` (and domain `--paths`) match on directory boundaries.**
244
+ `--path payments` no longer imports `payments_v2/b.py`, and a partial-name prefix such as
245
+ `--path docs/adr/00` matches nothing; a prefix matches a file under that directory or
246
+ that exact file. `--path ""` still matches everything, and mixed with a real prefix it is
247
+ ignored. The domain `--paths` help already behaved this way and now says so.
248
+ - **The Stop hook skips the transcript of a session that is already captured.** It now peeks
249
+ at the capture ledger read-only before parsing the transcript, so every Stop after the
250
+ capturing one no longer re-reads the whole file.
251
+
252
+ ### Fixed
253
+
254
+ - **The derived initiative names the store's repository branch.** It used to come from the
255
+ branch of whatever directory the MCP server or CLI ran in. An inherited `GIT_DIR` or
256
+ `GIT_WORK_TREE` no longer redirects either the derived initiative or the captured commit.
257
+ - **A timestamp in the future no longer counts as fresh.** The capture session-id fallback and
258
+ the session attribution of retrieval telemetry treated a marker stamped ahead of the clock
259
+ as current; they now ignore it. The SessionStart dedupe still treats a same-session stamp
260
+ less than 60 seconds ahead as a duplicate (a parallel hook can write one), but a stamp
261
+ further ahead no longer suppresses the map until the clock catches up.
262
+ - **Every CLI command that takes a store and a `--graph` pairs the store with its own
263
+ project's graph by default.** `sidegraph-sync`, `sidegraph-import` (both modes),
264
+ `sidegraph-domains bootstrap`, `sidegraph-doctor` and `sidegraph-init` (whose found/missing
265
+ line used the shell's path) read the default graph relative to the
266
+ shell, so `--db A/.sidegraph` run from project B stamped A's store with B's graph version
267
+ and could rewrite A's anchors, import decisions, or bootstrap domains from B's graph. The
268
+ default and `$SIDEGRAPH_GRAPH` (an empty value counts as unset) now resolve against the
269
+ store's project, as `sidegraph-ratify` and `sidegraph-stats` already did; a store reached
270
+ through a symlinked `.sidegraph` keeps the link's project. When the store's project has no
271
+ graph but the same path exists beside the shell (a store copied elsewhere), one stderr hint
272
+ names `--graph <path>`; when both exist, a note says which was used. Error lines name the
273
+ resolved path.
274
+ - **`SIDEGRAPH_DB` naming a missing path no longer scaffolds its parent.** A missing
275
+ `SIDEGRAPH_DB=/proj/.sidegraph`, or a dangling link, resolved to `/proj` and a store was
276
+ created in the project root. Only a path ending in `.db` is rescued to its parent now; any
277
+ other missing path is used as given, and a dangling link fails to open without creating
278
+ anything.
279
+ - **`sidegraph-sync --check` documents domain-refresh failures.** The help and the module
280
+ docstring omitted the finding that already makes `--check` exit 2.
281
+ - **A move left `moved_uncommitted` is now re-verified after you commit it, even when the
282
+ graph was not rebuilt.** Committing a rename does not change `graph.json`, so the version
283
+ gate skipped every later sync and the leaf kept its old path until `--force`. Sync now
284
+ remembers such entities with the git `HEAD` it saw, and the first sync after `HEAD` moves
285
+ re-verifies just them (a narrow pass that leaves domain membership alone). The comment that
286
+ promised the next sync would heal it was wrong, and is corrected.
287
+ - **A decision with two leaves in one community no longer loses that community's binding when
288
+ one leaf leaves it.** Both leaves share one Tier-1 `community:*` row, and a renumber that
289
+ moved one leaf orphaned the row the other still held, so the decision stopped surfacing for
290
+ that community. Sync now settles a record's community rows after every leaf has been
291
+ rebound, and a new row carries the moved leaf's relation instead of `affects`. Damage from
292
+ earlier syncs is repaired when a later repoint touches the record, or when the index is
293
+ next rebuilt from the committed files.
294
+ - **Secret redaction covers quoted values and quoted keys.** `password: "one two"`,
295
+ `` token: `abc def` `` and `password = 'a b c'` were cut at the first space, leaving the rest
296
+ of the secret in the store, and `{"password": "hunter2 two"}` was not matched at all. A
297
+ quoted value is now taken whole, with any text glued to its closing quote, and a quoted
298
+ key matches too. JSON keys such as `"token_count"` now redact like the unquoted
299
+ `token_count:` already did. An escaped quote (`"alpha\" beta"`) does not end a quoted
300
+ value, and a quoted key stops at the next JSON field, so `{"password":"x y","reason":"z"}`
301
+ keeps `reason`.
302
+ - **A decision whose attached fact failed is left proposed under an auto-ratify policy,** and
303
+ an auto-accepted fact's write-guard message points to `add_anchors` instead of a drop that
304
+ the store refuses.
305
+ - **An initiative name is redacted before it becomes an entity, on every write path.** A
306
+ secret in `initiative`, or in a branch name the propose path derives one from, used to land
307
+ in the canonical `initiative:<name>` entity file. A blank or all-secret initiative now binds
308
+ nothing, and a padded name is trimmed (`" proj "` keys as `initiative:proj`).
309
+ - **`add_decision` binds its initiative with no graph or no anchors.** The Tier-0 binding was
310
+ made only inside the per-anchor loop, so a call without a reader or without an anchor
311
+ dropped it silently.
312
+ - **`add_domain`, `supersede_domain` and `sidegraph-domains add` redact the title and
313
+ summary.** Only `propose_domains` and the bootstrap did. The MCP results now carry
314
+ `redactions`, and the CLI prints a count line when it redacted something.
315
+ - **`propose_decisions` dedups a decision on its redacted title.** A title that held a secret
316
+ was compared raw against the stored, redacted one, so proposing it twice wrote it twice.
317
+ - **One failing draft no longer aborts a propose batch.** A step after the write (anchors,
318
+ initiative, tags, attached facts, auto-ratify) now leaves the result `written` with a
319
+ `reason`; an error before the write makes that draft `rejected`; each attached fact and each
320
+ domain is isolated the same way, and a failed TOC rebuild after `propose_domains` is
321
+ reported as a `toc:` warning. `KeyboardInterrupt` still propagates.
322
+ - **A record id can no longer become a path outside the store.** Every canonical writer built
323
+ `<dir>/<id>.json` from the id as given, so an id like `../../x` wrote outside the store.
324
+ The store now refuses to write an id that is not a single path segment, and the OKF export
325
+ skips such a decision, fact or entity with a warning.
326
+ - **A canonical file whose JSON id does not match its filename is skipped on reload, with a
327
+ warning on every open.** A file with a crafted id was indexed under that id, so one later
328
+ ratify could write outside the store. Duplicate ids let the later file silently win, and a
329
+ file with no id got a fresh ULID on every rebuild. Such files are now left out of the index
330
+ and named in a warning until they are fixed or removed. An existing index reloads once to
331
+ apply the rule. An archive line with an unsafe or non-string id is skipped instead of
332
+ making `Store()` fail.
333
+ - **An interrupted legacy migration no longer loses its staged work.** The legacy file is
334
+ renamed to its backup only after the staged directories have moved in, so an interruption
335
+ leaves it in place and the next open migrates again. A bare-file migration, which has to
336
+ rename first, keeps its staging directory and leaves a sentinel so the next open says what
337
+ to do. A sentinel younger than 60 seconds means a migration is running now: the open
338
+ refuses with "retry in a minute" and touches nothing, and deleting that sentinel early is
339
+ unsafe. A legacy row with an unsafe id fails the migration before anything is written, and
340
+ a row whose JSON omits its id takes its SQL primary key instead of a fresh one per retry.
341
+ - **The bootstrap catalog applies the same identity rule.** A record file with no id was
342
+ given a fresh ULID on every load, so the catalog fingerprint changed between two loads of
343
+ one store. Such files are now skipped with a warning.
344
+ - **The store refuses a symlinked directory or store file inside itself.** A symlinked
345
+ `decisions/` sent every record write, from the MCP server, the hooks and bootstrap alike, to
346
+ the link's target, and a symlinked `index.db` made SQLite write there. `Store()` now raises
347
+ before any migration or write, naming the entry, and `sidegraph-bootstrap` refuses before
348
+ the review prompts. A symlinked store root stays allowed. Bootstrap's action summary now
349
+ names the store path and any symlink between the repository root and it.
350
+ - **`sidegraph-bootstrap --report` no longer overwrites a file it is hard-linked to, and
351
+ protects the Codex hooks file the verifier really reads.** The guard compared resolved
352
+ paths, so a hard link to a host config passed it and the report truncated the shared file.
353
+ It also protected only the legacy `.codex/hooks/hooks.json`, not `.codex/hooks.json`. The
354
+ report is now published by replace, and one list of host-config paths feeds both the
355
+ verifier and the guard. The guard covers every host's config file, whichever `--host` is
356
+ selected.
357
+ - **`sidegraph-import --docs` keys a document inside the repository by its repository path,
358
+ whatever directory it runs from.** Run from a subdirectory or given an absolute path, a
359
+ document used to miss its file node in the graph, skip as unanchorable, and get a
360
+ different `provenance.ref` from the same document imported at the root. Profile discovery
361
+ also finds the profile's documents from any directory in the repository, and the
362
+ unanchorable warning now fires only outside a git work tree, where the current directory
363
+ stands in for the root. Build the graph from the repository root: a graph built from a
364
+ subdirectory leaves documents unanchorable.
365
+ - **`--docs` refuses a markdown file that is a symlink to a target outside the repository.**
366
+ It used to read the target under `--any-doc`. The document is counted as `refused: a symlink
367
+ pointing outside the repository`, and so is a profile-discovery hit that resolves outside
368
+ the repository (for example through a symlinked directory). A symlinked directory inside
369
+ the repository that points inside it imports under the path you named, and one that points
370
+ outside the repository is refused. A symlink to a file inside the repository imports under
371
+ its link path.
372
+ - **A re-import repairs a record that has no anchors.** A document whose record was written
373
+ but whose bindings never landed (a run that stopped in between, leaving no anchor other
374
+ than `tag:` bindings) used to be skipped as existing for good. It is now bound on the next import and reported as `had their anchors
375
+ repaired`.
376
+ - **The `import_docs` docstring describes what it does:** the five compared fields, the
377
+ statuses it matches, the repair and the refusal.
378
+ - **`sidegraph-init` no longer writes `.claude/settings.json` through a symlink, and no
379
+ longer prints a traceback when the write fails.** A symlinked `.claude/` or `settings.json`
380
+ (live or dangling) is left untouched and the `env` line to add by hand is printed. A merge
381
+ into an existing file is now published by replacing it atomically, so an interruption
382
+ cannot leave a truncated file, and any write failure (a read-only `.claude/`, for example)
383
+ is reported the same way instead of raising. An `env` block that is `null` or not an
384
+ object, and a settings file that changes while init runs, are skipped the same way, not
385
+ raised, and a link swapped in just before the write is refused. A write-protected file is
386
+ respected when init runs as root too.
387
+ - **`sidegraph-doctor`, the drift refresh the session hooks run, and `sidegraph-stats` now
388
+ open the index correctly when the store's path contains `#`, `?`, or `%` followed by two
389
+ hex digits.** Their read-only SQLite URI was built from the unquoted path.
390
+ **Doctor reported its index checks as skipped**, blaming a missing index and suggesting
391
+ `sidegraph-sync`, which could not help. **The session drift refresh silently stopped
392
+ excluding orphaned bindings.** **Stats failed.** For `#` and `?`, an empty file was also
393
+ created at the store path cut short at that character, and an unrelated database there
394
+ could be read instead.
395
+ - **The session-link gate checks every line that gets published.** Lines starting with `#` in
396
+ a PR description, and in commit messages made with `git commit -m`/`-F`, which git records,
397
+ are now checked. The PR title and the PR's recorded commit messages are checked too. The
398
+ check re-runs when a PR description is edited. The public repository runs the check too:
399
+ the release snapshot ships the checker, and the workflow fails when the checker is missing
400
+ instead of skipping.
401
+ - **`sidegraph-export-okf` refuses a symlinked `--out`, and a failed export no longer
402
+ destroys the previous one.** A symlinked output directory used to be written through, or
403
+ cleared, wherever it pointed, and a write that failed midway left a partial bundle after
404
+ the old export was already deleted. The new bundle is now built beside `--out` and
405
+ swapped in only when complete, except for a mount point, a `--out` that is the current
406
+ directory, an unwritable or non-directory parent, or a previous export that cannot be
407
+ renamed aside, which are written in place as before (a write failure there can leave a
408
+ partial export). The in-place write goes to the validated, resolved directory.
409
+ - **An unreadable store or graph directory no longer ends in a traceback.** On Python 3.13 a store or
410
+ graph whose directory could not be read (permission denied) made `sidegraph-sync`,
411
+ `sidegraph-import`, `sidegraph-domains bootstrap`, `sidegraph-init`, `sidegraph-stats` and
412
+ `sidegraph-ratify` (on a domain accept) exit with an uncaught `PermissionError`. An unreadable
413
+ store is now reported on the command's error line (exit 1; 2 for `sidegraph-stats`). An
414
+ unreadable graph is treated as a missing one: `sidegraph-sync`, `sidegraph-import` and
415
+ `sidegraph-domains bootstrap` stop with `graph not readable`, and the other commands carry on
416
+ without a graph.
417
+ A working directory that cannot be read skips the graph hint and the `sync_anchors` hint instead of
418
+ raising; other code that resolves a relative path against it may still raise.
419
+ - **A retried Tier-1 reconcile that could not run is no longer reported as done.** A
420
+ remembered community reconcile whose record still has a live or degraded Tier-2 anchor
421
+ with no recorded community kept being treated as a success: the key was cleared, the sync
422
+ said `moved`, and the stale row stayed live. It is now kept, and retried silently on every
423
+ sync.
424
+ - **Sync, verify and doctor ask git about the repository their own files are in.**
425
+ `sidegraph-sync` (the graph's directory), `sidegraph-verify --against` and
426
+ `sidegraph-doctor` (the store's, and its graph-root check's) no longer inherit an ambient `GIT_DIR` or
427
+ `GIT_WORK_TREE`, which could make sync read another repository's `HEAD` and adopt a rename
428
+ that was never committed. The lazy sync run by `SessionStart` and retrieval, and the
429
+ `SessionStart` drift cache, are fixed too. `sidegraph-init` and `sidegraph-import` resolve
430
+ the repository root from the current directory the same way. A work tree whose repository
431
+ is found only through `GIT_DIR` now needs a `.git` file containing `gitdir: <path>`, and
432
+ `core.bare=false` in that repository.
433
+ - **The sync docs list every condition that prevents a skip.** A remembered Tier-1
434
+ reconcile that is repaired or fails again also makes a plain sync report instead of
435
+ skipping.
436
+ - **Documentation and help text match what the code does.** The PreToolUse docs name the
437
+ real `Read|Grep|Edit|Write` matcher and the two nudge forms, each at most once per session.
438
+ The `add_decision`, `supersede_decision`, `add_fact`, `supersede_fact` and
439
+ `propose_decisions` tool descriptions list `anchors_orphaned`. `sidegraph-ratify --help`
440
+ says `--all` also accepts standalone facts, and `--help` for `sidegraph-verify`,
441
+ `-doctor` and `-blame` no longer promises a legacy `*.db` migration they never perform.
442
+ `SECURITY.md` states local retrieval telemetry and the output paths commands write to.
443
+
10
444
  ## [0.5.0] — 2026-09-23
11
445
 
12
446
  ### Changed