gitgrip 2.0.0a6__tar.gz → 2.0.0a7__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 (366) hide show
  1. gitgrip-2.0.0a7/PKG-INFO +252 -0
  2. gitgrip-2.0.0a7/README.md +236 -0
  3. gitgrip-2.0.0a7/gitgrip.egg-info/PKG-INFO +252 -0
  4. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gitgrip.egg-info/SOURCES.txt +150 -68
  5. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/api_core.py +4 -4
  6. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/concurrent_event_stress.py +3 -3
  7. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/lane_workspace_prototype.py +150 -54
  8. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/real_git_playground.py +2 -1
  9. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/app.py +1345 -270
  10. gitgrip-2.0.0a7/gr2/python_cli/approval_schema.py +38 -0
  11. gitgrip-2.0.0a7/gr2/python_cli/check_records.py +265 -0
  12. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/commit.py +4 -6
  13. gitgrip-2.0.0a7/gr2/python_cli/context.py +206 -0
  14. gitgrip-2.0.0a7/gr2/python_cli/defaults.py +141 -0
  15. gitgrip-2.0.0a7/gr2/python_cli/ecosystems_python.py +58 -0
  16. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/events.py +10 -0
  17. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/execops.py +1 -1
  18. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/gitinclude.py +35 -8
  19. gitgrip-2.0.0a7/gr2/python_cli/gr_resolver.py +102 -0
  20. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/grip.py +971 -191
  21. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/grip_cli.py +271 -109
  22. gitgrip-2.0.0a7/gr2/python_cli/lane_defaults.py +109 -0
  23. gitgrip-2.0.0a7/gr2/python_cli/lane_downstream.py +267 -0
  24. gitgrip-2.0.0a7/gr2/python_cli/lane_graph.py +472 -0
  25. gitgrip-2.0.0a7/gr2/python_cli/lane_plugins.py +140 -0
  26. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/launch_exec.py +41 -9
  27. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/layout.py +12 -0
  28. gitgrip-2.0.0a7/gr2/python_cli/merge_gate.py +277 -0
  29. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/open_gr_review.py +189 -40
  30. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/platform.py +69 -2
  31. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/pr.py +27 -2
  32. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/project_review.py +22 -14
  33. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review.py +68 -18
  34. gitgrip-2.0.0a7/gr2/python_cli/review_allocation.py +237 -0
  35. gitgrip-2.0.0a7/gr2/python_cli/review_field_tree.py +442 -0
  36. gitgrip-2.0.0a7/gr2/python_cli/review_members.py +78 -0
  37. gitgrip-2.0.0a7/gr2/python_cli/review_records.py +522 -0
  38. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review_run.py +406 -25
  39. gitgrip-2.0.0a7/gr2/python_cli/root_option.py +417 -0
  40. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/spec_apply.py +1 -1
  41. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/syncops.py +1 -1
  42. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/workspace_snapshot.py +7 -4
  43. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.approval.v1alpha1/approval.proto +33 -0
  44. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.approval.v1alpha1/descriptor_set.pb +0 -0
  45. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.check.v1alpha1/check.proto +27 -0
  46. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.check.v1alpha1/descriptor_set.pb +0 -0
  47. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.merge.v1alpha1/descriptor_set.pb +0 -0
  48. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.merge.v1alpha1/merge.proto +51 -0
  49. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.review.v1alpha1/descriptor_set.pb +34 -0
  50. gitgrip-2.0.0a7/gr2/schemas/dev.synapt.grip.review.v1alpha1/review.proto +39 -0
  51. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/pyproject.toml +5 -6
  52. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_api_dump.py +209 -15
  53. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_app_event_outcomes.py +8 -1
  54. gitgrip-2.0.0a7/tests/test_approval_schema.py +33 -0
  55. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_cli_shape_witnesses.py +33 -0
  56. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_commit.py +6 -5
  57. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_config_overlay.py +3 -3
  58. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_conftest_git_isolation.py +9 -3
  59. gitgrip-2.0.0a7/tests/test_context_resolver.py +246 -0
  60. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_contribution_protocol.py +1 -1
  61. gitgrip-2.0.0a7/tests/test_defaults_from_repo.py +213 -0
  62. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_deprecation_registry.py +2 -2
  63. gitgrip-2.0.0a7/tests/test_ecosystems_python.py +239 -0
  64. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_event_log_integrity.py +11 -18
  65. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_event_outcome_policy.py +7 -1
  66. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_events.py +11 -2
  67. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_events_torn_line.py +1 -1
  68. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_execops.py +1 -0
  69. gitgrip-2.0.0a7/tests/test_field_tree_name.py +60 -0
  70. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_git_review.py +2 -2
  71. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_gitinclude_compiler.py +1 -1
  72. gitgrip-2.0.0a7/tests/test_gr_resolver_conformance.py +188 -0
  73. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_grip_cli.py +33 -33
  74. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_grip_hardening.py +2 -2
  75. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_grip_snapshot.py +2 -2
  76. gitgrip-2.0.0a7/tests/test_lane_checkout_root.py +133 -0
  77. gitgrip-2.0.0a7/tests/test_lane_create_defaults.py +420 -0
  78. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_create_fork_base_cli.py +33 -14
  79. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_create_refusal_leaves_nothing.py +4 -1
  80. gitgrip-2.0.0a7/tests/test_lane_downstream.py +212 -0
  81. gitgrip-2.0.0a7/tests/test_lane_downstream_run.py +191 -0
  82. gitgrip-2.0.0a7/tests/test_lane_exit_keeps_dirty_work.py +217 -0
  83. gitgrip-2.0.0a7/tests/test_lane_graph.py +247 -0
  84. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_lifecycle_safety.py +31 -12
  85. gitgrip-2.0.0a7/tests/test_lane_plugins.py +443 -0
  86. gitgrip-2.0.0a7/tests/test_lane_probe.py +163 -0
  87. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_repo_paths_and_all_skipped.py +7 -6
  88. gitgrip-2.0.0a7/tests/test_lane_roles.py +62 -0
  89. gitgrip-2.0.0a7/tests/test_lane_store_path_pins.py +235 -0
  90. gitgrip-2.0.0a7/tests/test_layout_census.py +305 -0
  91. gitgrip-2.0.0a7/tests/test_linked_review_receipts.py +676 -0
  92. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_materialize_pin.py +4 -5
  93. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_member_working_root_checkout_materialize.py +30 -139
  94. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_migration.py +3 -2
  95. gitgrip-2.0.0a7/tests/test_native_store_gitinclude.py +173 -0
  96. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_native_store_review_record_probes.py +64 -90
  97. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_no_bare_python_cli_imports.py +1 -1
  98. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_null_current_lane_refusal.py +3 -3
  99. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_open_gr_enter.py +18 -4
  100. gitgrip-2.0.0a7/tests/test_platform_adapter_plugins.py +329 -0
  101. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_merge_head_pin.py +30 -0
  102. gitgrip-2.0.0a7/tests/test_pr_review_subject.py +298 -0
  103. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_project_review_range_reconstruction.py +11 -9
  104. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_project_review_three_repo.py +16 -12
  105. gitgrip-2.0.0a7/tests/test_python_group_install.py +127 -0
  106. gitgrip-2.0.0a7/tests/test_record_schema_copies.py +77 -0
  107. gitgrip-2.0.0a7/tests/test_remote_check_records.py +322 -0
  108. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_repo_path_read_through.py +1 -1
  109. gitgrip-2.0.0a7/tests/test_review_a4.py +194 -0
  110. gitgrip-2.0.0a7/tests/test_review_a4_v2.py +200 -0
  111. gitgrip-2.0.0a7/tests/test_review_a4_v3.py +95 -0
  112. gitgrip-2.0.0a7/tests/test_review_allocation_recovery.py +144 -0
  113. gitgrip-2.0.0a7/tests/test_review_ansi_parse.py +95 -0
  114. gitgrip-2.0.0a7/tests/test_review_b3_reader_alignment.py +305 -0
  115. gitgrip-2.0.0a7/tests/test_review_bind_author.py +68 -0
  116. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_bind_fork_base.py +7 -7
  117. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_bind_from_range.py +5 -3
  118. gitgrip-2.0.0a7/tests/test_review_bind_migration.py +188 -0
  119. gitgrip-2.0.0a7/tests/test_review_bind_native_store.py +412 -0
  120. gitgrip-2.0.0a7/tests/test_review_bind_root_refs.py +88 -0
  121. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_bind_verify.py +21 -40
  122. gitgrip-2.0.0a7/tests/test_review_check_name.py +76 -0
  123. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_cli.py +68 -39
  124. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_close_gr.py +17 -15
  125. gitgrip-2.0.0a7/tests/test_review_close_keeps_local_work.py +292 -0
  126. gitgrip-2.0.0a7/tests/test_review_context_defaults.py +198 -0
  127. gitgrip-2.0.0a7/tests/test_review_context_witnesses.py +113 -0
  128. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_dispatch.py +15 -6
  129. gitgrip-2.0.0a7/tests/test_review_events.py +190 -0
  130. gitgrip-2.0.0a7/tests/test_review_field_tree.py +364 -0
  131. gitgrip-2.0.0a7/tests/test_review_field_tree_reader_edges.py +268 -0
  132. gitgrip-2.0.0a7/tests/test_review_field_tree_readers.py +267 -0
  133. gitgrip-2.0.0a7/tests/test_review_install_hint.py +98 -0
  134. gitgrip-2.0.0a7/tests/test_review_merge_gate.py +227 -0
  135. gitgrip-2.0.0a7/tests/test_review_merge_gate_lost_ack.py +449 -0
  136. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_open_lane.py +119 -39
  137. gitgrip-2.0.0a7/tests/test_review_pr_marker_context.py +115 -0
  138. gitgrip-2.0.0a7/tests/test_review_reader_defaults.py +75 -0
  139. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_rebind.py +1 -1
  140. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_receipt_cleanup.py +29 -17
  141. gitgrip-2.0.0a7/tests/test_review_ref_v1_migration.py +432 -0
  142. gitgrip-2.0.0a7/tests/test_review_ref_v1_reader.py +134 -0
  143. gitgrip-2.0.0a7/tests/test_review_ref_v1_writer.py +232 -0
  144. gitgrip-2.0.0a7/tests/test_review_remote_safety.py +284 -0
  145. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_run.py +57 -0
  146. gitgrip-2.0.0a7/tests/test_review_run_context.py +82 -0
  147. gitgrip-2.0.0a7/tests/test_review_run_dependency_order.py +311 -0
  148. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_run_import_isolation.py +4 -1
  149. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_run_multi_repo.py +20 -6
  150. gitgrip-2.0.0a7/tests/test_review_run_plugin_order.py +109 -0
  151. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_runners.py +8 -8
  152. gitgrip-2.0.0a7/tests/test_review_subject.py +84 -0
  153. gitgrip-2.0.0a7/tests/test_review_transport.py +335 -0
  154. gitgrip-2.0.0a7/tests/test_review_v1_format_guard.py +56 -0
  155. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_verify_inside.py +7 -5
  156. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_rmtree_or_refuse.py +14 -2
  157. gitgrip-2.0.0a7/tests/test_root_option_verbs.py +575 -0
  158. gitgrip-2.0.0a7/tests/test_selected_workspace_commit.py +199 -0
  159. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sprint21_sync_platform.py +9 -9
  160. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_break_attempts.py +20 -15
  161. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_checkout_atomicity.py +19 -119
  162. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_log_adoption_boundary.py +1 -1
  163. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_member_path_hygiene.py +2 -2
  164. gitgrip-2.0.0a7/tests/test_store_moved_workspace_guard.py +84 -0
  165. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_verb_rename.py +47 -1
  166. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_verb_witnesses.py +13 -8
  167. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_tmux_launch_runtime.py +161 -6
  168. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_version_static.py +3 -3
  169. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_identity_boundary.py +1 -1
  170. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_init_from_topology.py +1 -1
  171. gitgrip-2.0.0a7/tests/test_workspace_root_nearest_marker.py +126 -0
  172. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_snapshot.py +17 -17
  173. gitgrip-2.0.0a6/PKG-INFO +0 -129
  174. gitgrip-2.0.0a6/README.md +0 -113
  175. gitgrip-2.0.0a6/gitgrip.egg-info/PKG-INFO +0 -129
  176. gitgrip-2.0.0a6/python_cli/review_records.py +0 -143
  177. gitgrip-2.0.0a6/tests/test_layout_census.py +0 -180
  178. gitgrip-2.0.0a6/tests/test_review_bind_native_store.py +0 -293
  179. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gitgrip.egg-info/dependency_links.txt +0 -0
  180. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gitgrip.egg-info/entry_points.txt +0 -0
  181. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gitgrip.egg-info/requires.txt +0 -0
  182. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gitgrip.egg-info/top_level.txt +0 -0
  183. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/__init__.py +0 -0
  184. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/__init__.py +0 -0
  185. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/activate.py +0 -0
  186. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/agent_manifest.py +0 -0
  187. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/cli.py +0 -0
  188. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/cross_repo.py +0 -0
  189. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/drivers.py +0 -0
  190. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/introspection.py +0 -0
  191. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/language_drivers.py +0 -0
  192. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/objects.py +0 -0
  193. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/perf.py +0 -0
  194. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/refs.py +0 -0
  195. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/trust.py +0 -0
  196. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/types.py +0 -0
  197. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/units.py +0 -0
  198. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/overlay/workspace_spec.py +0 -0
  199. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/__init__.py +0 -0
  200. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/cache_materialization_probe.py +0 -0
  201. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/concurrent_lease_stress.py +0 -0
  202. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/concurrent_workspace_cap_stress.py +0 -0
  203. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/contribution_protocol.py +0 -0
  204. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/cross_mode_lane_stress.py +0 -0
  205. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/jsonl_store.py +0 -0
  206. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/layout_model_probe.py +0 -0
  207. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/propagation_daemon.py +0 -0
  208. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/propagation_state_machine.py +0 -0
  209. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/python_exec_playground.py +0 -0
  210. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/python_hook_runtime_playground.py +0 -0
  211. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/python_migration_playground.py +0 -0
  212. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/python_review_checkout_playground.py +0 -0
  213. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/python_spec_apply_playground.py +0 -0
  214. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/real_git_lane_materialization.py +0 -0
  215. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/recall_lane_history.py +0 -0
  216. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/repo_maintenance_prototype.py +0 -0
  217. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/prototypes/repo_transport_probe.py +0 -0
  218. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/__init__.py +0 -0
  219. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/__main__.py +0 -0
  220. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/add.py +0 -0
  221. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/branch.py +0 -0
  222. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/channel_bridge.py +0 -0
  223. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/clone_exec.py +0 -0
  224. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/config.py +0 -0
  225. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/consent.py +0 -0
  226. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/env_exec.py +0 -0
  227. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/exit_codes.py +0 -0
  228. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/failures.py +0 -0
  229. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/file_exec.py +0 -0
  230. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/git_review.py +0 -0
  231. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/gitops.py +0 -0
  232. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/hooks.py +0 -0
  233. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/merge_verification.py +0 -0
  234. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/migration.py +0 -0
  235. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/prune.py +0 -0
  236. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/push.py +0 -0
  237. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review_dispatch.py +0 -0
  238. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review_ephemeral.py +0 -0
  239. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review_rebind.py +0 -0
  240. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/review_runners.py +0 -0
  241. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/staging_cleanup.py +0 -0
  242. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/target.py +0 -0
  243. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/version.py +0 -0
  244. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7/gr2}/python_cli/workspace_guidance.py +0 -0
  245. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/schemas/gr2-materialization-plan-v1.schema.json +0 -0
  246. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2/schemas/gr2-workspace-spec-v1.schema.json +0 -0
  247. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/gr2_overlay/__init__.py +0 -0
  248. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/setup.cfg +0 -0
  249. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_add.py +0 -0
  250. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_agent_manifest_overlay_source.py +0 -0
  251. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_api_core_seam.py +0 -0
  252. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_apply_convergence.py +0 -0
  253. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_apply_gr1_sibling_adoption.py +0 -0
  254. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_branch.py +0 -0
  255. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_break_17_unit_path_containment.py +0 -0
  256. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_break_18_gr1_sibling_units.py +0 -0
  257. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_channel_bridge.py +0 -0
  258. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_cli_adapter_error_boundary.py +0 -0
  259. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_clone_materialization.py +0 -0
  260. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_config_base_path_guard.py +0 -0
  261. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_ensure_lane_checkout_reference_clone.py +0 -0
  262. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_env_materialization.py +0 -0
  263. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_exec_apostrophe_and_oserror.py +0 -0
  264. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_exec_single_string_and_materialize_plan.py +0 -0
  265. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_failure_event_outcome.py +0 -0
  266. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_first_five_minutes.py +0 -0
  267. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_foreground_launch_runtime.py +0 -0
  268. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_gr1_first_run_guidance.py +0 -0
  269. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_gr2_packaging.py +0 -0
  270. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_gr2_review_receipt.py +0 -0
  271. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_grip_toml_schema_v1.py +0 -0
  272. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_hook_events.py +0 -0
  273. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_hook_hardening.py +0 -0
  274. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_hooks_consent.py +0 -0
  275. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_hooks_group_names.py +0 -0
  276. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_jsonl_store.py +0 -0
  277. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_create_refuses_own_branch.py +0 -0
  278. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_enter_hook_warnings.py +0 -0
  279. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_lease_show_json.py +0 -0
  280. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_show_name.py +0 -0
  281. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_lane_toml_serialization.py +0 -0
  282. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_launch_primitive.py +0 -0
  283. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_m2_overlay_hindsight.py +0 -0
  284. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_m2_overlay_mem0.py +0 -0
  285. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_m2_overlay_zep.py +0 -0
  286. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_materialization_plan_contract.py +0 -0
  287. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_merge_evidence.py +0 -0
  288. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_merge_parent_verification.py +0 -0
  289. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_migration_overlay_compatibility.py +0 -0
  290. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_migration_unadopted_notice.py +0 -0
  291. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_open_project_refusal_reason_cli.py +0 -0
  292. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_outbox_ack_after_effect.py +0 -0
  293. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_acceptance.py +0 -0
  294. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_activate.py +0 -0
  295. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_cli.py +0 -0
  296. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_cli_wiring.py +0 -0
  297. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_composition_merge.py +0 -0
  298. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_cross_repo_atomic_apply.py +0 -0
  299. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_cross_repo_perf_gate.py +0 -0
  300. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_cross_repo_rollback.py +0 -0
  301. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_driver_registry.py +0 -0
  302. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_introspection.py +0 -0
  303. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_multi_stack.py +0 -0
  304. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_object_encoding.py +0 -0
  305. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_perf_gates.py +0 -0
  306. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_python_driver.py +0 -0
  307. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_tier_b_encoding.py +0 -0
  308. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_tier_b_perf_gates.py +0 -0
  309. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_tier_b_repo_state.py +0 -0
  310. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_tier_b_staging_discipline.py +0 -0
  311. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_trust_model.py +0 -0
  312. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_overlay_workspace_spec.py +0 -0
  313. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_events.py +0 -0
  314. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_group_legibility.py +0 -0
  315. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_merge_method.py +0 -0
  316. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_merge_missing_target.py +0 -0
  317. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_merge_partial_failure.py +0 -0
  318. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_pr_view.py +0 -0
  319. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_project_file_materialization.py +0 -0
  320. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_projection_tracked_dest.py +0 -0
  321. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_propagation_contribution.py +0 -0
  322. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_propagation_daemon.py +0 -0
  323. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_propagation_state_machine.py +0 -0
  324. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_prune.py +0 -0
  325. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_push.py +0 -0
  326. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_readme_verbs_exist.py +0 -0
  327. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_repo_status_linked_worktree.py +0 -0
  328. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_repo_status_schema_version.py +0 -0
  329. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_repo_status_symlinked_git_dir.py +0 -0
  330. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_create_project_cli.py +0 -0
  331. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_ephemeral.py +0 -0
  332. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_run_integrity_recheck.py +0 -0
  333. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_review_run_rerun_and_refusal_receipt.py +0 -0
  334. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_single_repo_cwd_refusal.py +0 -0
  335. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_snapshot_id_prefix_resolution.py +0 -0
  336. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_spec_apply_event_outcomes.py +0 -0
  337. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_spec_declaration_ref_pin.py +0 -0
  338. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_staging_cleanup.py +0 -0
  339. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_commit_noop.py +0 -0
  340. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_declared_members.py +0 -0
  341. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_git_native_smoke.py +0 -0
  342. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_init_branch_inference.py +0 -0
  343. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_member_state.py +0 -0
  344. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_migrate_branch_inference.py +0 -0
  345. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_store_status_values.py +0 -0
  346. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_submodule_member_predicate.py +0 -0
  347. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_superproject_import.py +0 -0
  348. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_event_outcomes.py +0 -0
  349. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_fast_forward.py +0 -0
  350. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_fetch.py +0 -0
  351. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_seed_local.py +0 -0
  352. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_ssh_rewrite.py +0 -0
  353. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_sync_status_probe.py +0 -0
  354. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_target.py +0 -0
  355. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_abort.py +0 -0
  356. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_apply.py +0 -0
  357. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_apply_dry_run.py +0 -0
  358. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_manifest_schema.py +0 -0
  359. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_propose.py +0 -0
  360. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_unit_topological_apply.py +0 -0
  361. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_validate_repo_path_conflict.py +0 -0
  362. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_version_identity.py +0 -0
  363. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_convert_clone.py +0 -0
  364. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_edit_lease_cap.py +0 -0
  365. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_init_local_repos.py +0 -0
  366. {gitgrip-2.0.0a6 → gitgrip-2.0.0a7}/tests/test_workspace_root_defaults.py +0 -0
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitgrip
3
+ Version: 2.0.0a7
4
+ Summary: Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: typer>=0.9
8
+ Requires-Dist: tomli_w>=1.0
9
+ Requires-Dist: pyyaml>=6.0
10
+ Requires-Dist: toml>=0.10
11
+ Requires-Dist: jsonschema>=4.18
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest>=8.0; extra == "dev"
14
+ Requires-Dist: ruff>=0.4; extra == "dev"
15
+ Requires-Dist: packaging>=22; extra == "dev"
16
+
17
+ # gr2
18
+
19
+ **gr2 is the workspace layer for multi-repo work.** One repository is just git; when a change spans repositories — a feature slice, a release, several agents touching several repos — gr2 gives you a workspace over them, isolated lanes to work in, and one grouped review/PR set for the slice. It is the Python successor to the Rust `gr` (1.x, called gr1 below); both ship from this repository, and `gr2` is the command for the workspace and the slice.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ uv tool install --pre gitgrip # the PyPI package is "gitgrip"; the command is "gr2"
25
+ gr2 --version
26
+ ```
27
+
28
+ Without uv, a venv and pip do the same:
29
+
30
+ ```bash
31
+ python3 -m venv ~/gr2-venv && source ~/gr2-venv/bin/activate
32
+ pip install --pre gitgrip
33
+ gr2 --version
34
+ ```
35
+
36
+ `--pre` is required while every gr2 release is an alpha: 1.5.0 and 1.5.1 were pre-alpha builds and are yanked, so without `--pre` there is nothing to install.
37
+
38
+ Already installed 1.5.0 or 1.5.1? The install commands above leave it in place, because an installed version already satisfies them. Upgrade explicitly: `uv tool upgrade --prerelease allow gitgrip`, or `pip install --pre -U gitgrip`. To run unreleased development code instead, install from a checkout: `pip install -e gr2/` from the repository root.
39
+
40
+ The Rust `gr` (gr1, 1.x) installs with `brew install synapt-dev/tap/gitgrip` or `cargo install gitgrip`. The two do not collide; you can have both installed.
41
+
42
+ ## First five minutes
43
+
44
+ Every command below was run, in this order, in a clean virtualenv against a throwaway workspace of two repositories. Put two clones side by side in one folder, say `~/ws/repo-a` and `~/ws/repo-b`.
45
+
46
+ ```bash
47
+ cd ~/ws
48
+ gr2 workspace init ~/ws # scans the folder; writes .grip/workspace_spec.toml
49
+ gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
50
+ gr2 workspace status ~/ws # what kind of workspace this is
51
+ gr2 store init ~/ws # the workspace snapshot store (needed before review)
52
+ ```
53
+
54
+ A **unit** is one worker — you, or one agent — and `default` is created for you. A **lane** is one piece of work spanning repos, with its own clones, so two lanes never step on each other:
55
+
56
+ ```bash
57
+ gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
58
+ gr2 lane enter ~/ws default feat-x --actor human:you
59
+ ```
60
+
61
+ Both commands print, per repo, the absolute directory you work in:
62
+
63
+ ```
64
+ repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
65
+ repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
66
+ ```
67
+
68
+ Edit there — not in your original clones. Stage and commit across the lane's repos:
69
+
70
+ ```bash
71
+ gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
72
+ gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
73
+ ```
74
+
75
+ `commit` with the lane flags commits every lane repo that has staged changes and names the repos it skipped. If every repo was skipped it exits non-zero with one sentence naming where it looked — and, when it can see them, where your staged changes actually are. Run one command across every lane repo, then turn the lane into one reviewable object:
76
+
77
+ ```bash
78
+ gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
79
+ gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
80
+ gr2 lane show ~/ws default # where am I?
81
+ gr2 lane exit ~/ws default --actor human:you
82
+ ```
83
+
84
+ `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
85
+
86
+ ## What works today, and what is not there yet
87
+
88
+ Alpha 2 is a working local workspace layer. Verified by running the walk above:
89
+
90
+ - `workspace` (init, materialize, status, migrate-gr1 from a gr1 gripspace), `lane` (create, enter, exit, current, lease), `store` (init, commit, log, diff, checkout), `exec run`, `repo status`, `sync status`, `review create-project`.
91
+ - Lanes are independent clones: two lanes, or two agents, never share refs, an index, or a working tree.
92
+ - A lane commit that commits nothing anywhere refuses loudly instead of reporting success.
93
+
94
+ Not there yet:
95
+
96
+ - The full walk with **remote** PRs (`gr2 push`, `gr2 pr create`) is documented in `--help` but was not exercised in a clean environment for this README; treat those two as alpha.
97
+ - `gr2 --help` and some verb output still say "prototype" in places; the wording is being cleaned up as verbs land.
98
+ - The Rust `gr` (gr1) still owns `spawn`, `fleet`, and `manifest` until their gr2 ports land. Everything else — workspace sync, lanes, the multi-repo slice, its review — is gr2's job; if a verb is missing or wrong there, that is a bug worth reporting, not a reason to reach for gr1.
99
+
100
+ ## Commands
101
+
102
+ | Group | Verbs |
103
+ |---|---|
104
+ | `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, migrate-lane-state, bootstrap-gr1, gitinclude |
105
+ | `spec` | show, validate |
106
+ | `lane` | create, enter, exit, show, resolve, bind, lease |
107
+ | (top level) | branch, add, commit, push, prune, status, plan, apply |
108
+ | `sync` | status, run |
109
+ | `pr` | create, status, checks, merge, view |
110
+ | `check` | run, show |
111
+ | `review` | open, close, checkout-pr, run, check, bind, publish, receive, verify, show, merge, rebind, create-project |
112
+ | `exec` | status, run |
113
+ | `repo` | status, projection-run |
114
+ | `hooks` | trust, revoke, status, show, run |
115
+ | `store` | init, commit, check, push, status, log, diff, checkout, materialize, migrate, migrate-reviews |
116
+ | `target`, `config` | stored PR target; config overlays |
117
+
118
+ ## Overlay substrate
119
+
120
+ gr2 also carries the config-overlay substrate (capture, compose, and materialize configuration layers over a workspace): see [docs/OVERLAY-SUBSTRATE.md](docs/OVERLAY-SUBSTRATE.md).
121
+
122
+ ## Development
123
+
124
+ ```bash
125
+ pip install -e "gr2[dev]" # from the repository root
126
+ cd gr2 && pytest # the gr2 suite (tests + overlay tests)
127
+ cd gr2 && ruff check . # lint, same config as CI
128
+ ```
129
+
130
+ The Rust development binary is **`gr2-dev`** — built by `cargo build -p gr2-cli --release`, `publish = false`, and not shipped with `cargo install gitgrip`. It answered to the name `gr2` until 2026-09-30, so a branch written before that rename goes red on `cargo test -p gr2-cli` with `CARGO_BIN_EXE_gr2 is unset`; the repair is `cargo_bin("gr2-dev")`, from which Cargo derives `CARGO_BIN_EXE_gr2-dev`.
131
+
132
+ Migration: use `gr2 review check` for compiled review requirements. `review requirements`
133
+ remains a hidden alias with a warning on stderr until beta. Both report `satisfied`
134
+ in the same JSON payload, and a missing reviewer remains a reported status with exit 0.
135
+
136
+ A bare `gr2 review open <workspace>` uses the workspace's sole review bind. Its default directory is `<workspace>.review/<sha8>` in the workspace's parent directory, and the command announces that path on stderr. Give `--lane-dir` to choose another location.
137
+
138
+ New review binds record the binder's Git `user.name` from the workspace root.
139
+ Set it with `git config user.name 'Your Name'` there if Git has no configured name.
140
+ `review show --json` and `review verify --json` include this author; older binds
141
+ remain readable without an author field, and reading them does not invent one.
142
+
143
+
144
+ ## Transfer a native review
145
+
146
+ Publish an existing bound review and receive it in another native workspace:
147
+
148
+ ```bash
149
+ gr2 review publish gr:<full-review-id> --remote https://example.org/workspace.git
150
+ gr2 review receive gr:<full-review-id> --remote https://example.org/workspace.git
151
+ gr2 review show gr:<full-review-id>
152
+ gr2 review verify gr:<full-review-id>
153
+ gr2 review open gr:<full-review-id> --lane-dir /absolute/fresh-review
154
+ ```
155
+
156
+ The root defaults to the current workspace. Use `-C /absolute/workspace` to override
157
+ it. Transport requires an independently supplied full 40-character lowercase
158
+ review ID and an explicit HTTPS URL or absolute local remote path. It does not
159
+ infer the expected ID from the remote. A review is published at
160
+ `refs/dev.synapt.grip/__reviews__/v1/<full-review-id>`; `--ref`, when supplied, must be
161
+ exactly that, or the older `refs/dev.synapt.grip/__reviews__/<full-review-id>`. Invalid explicit input is
162
+ refused without falling back to context.
163
+
164
+ Publish transfers only that review ref and confirms its returned target. Receive
165
+ compares both the advertised and actual fetched raw target with the expected ID,
166
+ requires a commit and recomputable review content, then creates the canonical
167
+ local bind ref. A valid same-ID receive is idempotent. A conflicting existing ref
168
+ is refused. Object downloads may remain after refusal. The owned temporary ref
169
+ is removed separately, and cleanup failure is reported without replacing a
170
+ primary failure.
171
+
172
+ The review commit carries its trees, blobs and range patches. It does not make
173
+ its recorded base or original member head reachable as Git parents. Keep each
174
+ member's base reachable at its recorded remote for reconstruction. `verify`
175
+ checks content consistency, not current remote state, provenance or approval.
176
+ `open` checks reconstructed member trees. Commit identity can differ from the
177
+ original head. Receiving content grants no local approval, allocation, selection
178
+ or cleanup authority. Opening a reconstruction remains a separate operation.
179
+
180
+
181
+ ## External PR adapters
182
+
183
+ External packages can expose a zero-argument factory through the
184
+ `gr2.platform_adapters` entry-point group. See [the adapter contract](docs/PR-LIFECYCLE.md#51-adapter-protocol-and-capabilities)
185
+ for registration, optional operation capabilities and merge head-pin requirements.
186
+ Select the installed adapter with `gr2 pr create ... --platform NAME` on a
187
+ materialized lane. The bound-lane path currently pushes and returns its receipt.
188
+
189
+ PRs start as drafts by default. `--draft` is explicit draft creation, while
190
+ `--no-draft` explicitly creates non-drafts. The same default applies to
191
+ `CreatePRRequest` and `create_pr_group`. Existing Python callers can retain
192
+ non-draft creation with `draft=False`. Plugins execute trusted Python from the
193
+ existing environment. The CLI never installs or downloads them.
194
+
195
+ ## Checks on a plain Git remote
196
+
197
+ Run a command at an exact full commit id in a disposable checkout, then publish
198
+ its exit status to the repository's remote:
199
+
200
+ ```sh
201
+ gr2 check run ./repo -- python -m pytest
202
+ gr2 check show ./repo --json
203
+ ```
204
+
205
+ With no flags, the remote is the current branch's upstream (else `origin`) and the head is `HEAD`,
206
+ as a full commit id. gr2 prints what it resolved on stderr. `--remote` (a URL, an absolute path or a
207
+ remote's name), `--head` and `--name` override them. With no upstream and no `origin`, it refuses and
208
+ asks for `--remote`.
209
+
210
+ Absolute paths to local bare remotes also work. Observations live at
211
+ `refs/dev.synapt.grip/__checks__/v1`, keyed by commit id. `check show` fetches a
212
+ fresh snapshot; a different commit has no check even when its tree is identical.
213
+ Supplied `--require` names replace the default `test` requirement. For both
214
+ checks, use `--require test --require lint`.
215
+
216
+ The read JSON contains `status`, `record_id` (the head's record-set blob id or
217
+ null), `snapshot_oid`, `head`, `member_key`, `records`, and `reason`. Each
218
+ observation retains its fields and adds a SHA-256 `observation_id`.
219
+
220
+ A failed command is recorded and `check run` exits 1. Publication or execution
221
+ refusals exit 2. `check show` returns `pass`, `fail` or `absent` in its JSON;
222
+ failed or unmeasurable reads exit 2. Conflicting pass and fail observations both
223
+ survive and refuse readiness. Rerunning a check does not erase its earlier
224
+ failure at that commit. Concurrent writes union observations with bounded
225
+ compare-and-swap retries. An unmeasurable push acknowledgement is reported as
226
+ indeterminate unless a fresh remote read confirms the observation.
227
+
228
+ ## Merge a bound review into plain Git remotes
229
+
230
+ ```sh
231
+ gr2 review merge
232
+ ```
233
+
234
+ This merges the review bound at the members' current heads, from their current branch, into the
235
+ branch on each remote that still sits at the reviewed base, and prints what it resolved. If several
236
+ branches sit there, it asks for `--into`. It merges only if every member's remote feature
237
+ branch is still the reviewed head, the target is still the reviewed base, and the exact-head check
238
+ passes. If any member fails that preflight, nothing is pushed. Merges are separate pushes, not atomic
239
+ across repos: a member that moves after an earlier member was pushed is refused, and the run exits 4.
240
+
241
+ Exit codes:
242
+ - 0: all merged;
243
+ - 3: none merged (refused);
244
+ - 4: partial or unknown.
245
+
246
+ A review id, `--from` and `--into` override the defaults. Zero or several matching binds, or members on
247
+ different branches, refuse and name the value to pass.
248
+
249
+ These records are attestations by writers trusted with remote access, not signed
250
+ proof against a writer who can forge Git objects. Test output and environment
251
+ contents are not uploaded. Read this custom ref through gr2; plain `git notes`
252
+ cannot read notes outside `refs/notes/`.
@@ -0,0 +1,236 @@
1
+ # gr2
2
+
3
+ **gr2 is the workspace layer for multi-repo work.** One repository is just git; when a change spans repositories — a feature slice, a release, several agents touching several repos — gr2 gives you a workspace over them, isolated lanes to work in, and one grouped review/PR set for the slice. It is the Python successor to the Rust `gr` (1.x, called gr1 below); both ship from this repository, and `gr2` is the command for the workspace and the slice.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ uv tool install --pre gitgrip # the PyPI package is "gitgrip"; the command is "gr2"
9
+ gr2 --version
10
+ ```
11
+
12
+ Without uv, a venv and pip do the same:
13
+
14
+ ```bash
15
+ python3 -m venv ~/gr2-venv && source ~/gr2-venv/bin/activate
16
+ pip install --pre gitgrip
17
+ gr2 --version
18
+ ```
19
+
20
+ `--pre` is required while every gr2 release is an alpha: 1.5.0 and 1.5.1 were pre-alpha builds and are yanked, so without `--pre` there is nothing to install.
21
+
22
+ Already installed 1.5.0 or 1.5.1? The install commands above leave it in place, because an installed version already satisfies them. Upgrade explicitly: `uv tool upgrade --prerelease allow gitgrip`, or `pip install --pre -U gitgrip`. To run unreleased development code instead, install from a checkout: `pip install -e gr2/` from the repository root.
23
+
24
+ The Rust `gr` (gr1, 1.x) installs with `brew install synapt-dev/tap/gitgrip` or `cargo install gitgrip`. The two do not collide; you can have both installed.
25
+
26
+ ## First five minutes
27
+
28
+ Every command below was run, in this order, in a clean virtualenv against a throwaway workspace of two repositories. Put two clones side by side in one folder, say `~/ws/repo-a` and `~/ws/repo-b`.
29
+
30
+ ```bash
31
+ cd ~/ws
32
+ gr2 workspace init ~/ws # scans the folder; writes .grip/workspace_spec.toml
33
+ gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
34
+ gr2 workspace status ~/ws # what kind of workspace this is
35
+ gr2 store init ~/ws # the workspace snapshot store (needed before review)
36
+ ```
37
+
38
+ A **unit** is one worker — you, or one agent — and `default` is created for you. A **lane** is one piece of work spanning repos, with its own clones, so two lanes never step on each other:
39
+
40
+ ```bash
41
+ gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
42
+ gr2 lane enter ~/ws default feat-x --actor human:you
43
+ ```
44
+
45
+ Both commands print, per repo, the absolute directory you work in:
46
+
47
+ ```
48
+ repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
49
+ repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
50
+ ```
51
+
52
+ Edit there — not in your original clones. Stage and commit across the lane's repos:
53
+
54
+ ```bash
55
+ gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
56
+ gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
57
+ ```
58
+
59
+ `commit` with the lane flags commits every lane repo that has staged changes and names the repos it skipped. If every repo was skipped it exits non-zero with one sentence naming where it looked — and, when it can see them, where your staged changes actually are. Run one command across every lane repo, then turn the lane into one reviewable object:
60
+
61
+ ```bash
62
+ gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
63
+ gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
64
+ gr2 lane show ~/ws default # where am I?
65
+ gr2 lane exit ~/ws default --actor human:you
66
+ ```
67
+
68
+ `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
69
+
70
+ ## What works today, and what is not there yet
71
+
72
+ Alpha 2 is a working local workspace layer. Verified by running the walk above:
73
+
74
+ - `workspace` (init, materialize, status, migrate-gr1 from a gr1 gripspace), `lane` (create, enter, exit, current, lease), `store` (init, commit, log, diff, checkout), `exec run`, `repo status`, `sync status`, `review create-project`.
75
+ - Lanes are independent clones: two lanes, or two agents, never share refs, an index, or a working tree.
76
+ - A lane commit that commits nothing anywhere refuses loudly instead of reporting success.
77
+
78
+ Not there yet:
79
+
80
+ - The full walk with **remote** PRs (`gr2 push`, `gr2 pr create`) is documented in `--help` but was not exercised in a clean environment for this README; treat those two as alpha.
81
+ - `gr2 --help` and some verb output still say "prototype" in places; the wording is being cleaned up as verbs land.
82
+ - The Rust `gr` (gr1) still owns `spawn`, `fleet`, and `manifest` until their gr2 ports land. Everything else — workspace sync, lanes, the multi-repo slice, its review — is gr2's job; if a verb is missing or wrong there, that is a bug worth reporting, not a reason to reach for gr1.
83
+
84
+ ## Commands
85
+
86
+ | Group | Verbs |
87
+ |---|---|
88
+ | `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, migrate-lane-state, bootstrap-gr1, gitinclude |
89
+ | `spec` | show, validate |
90
+ | `lane` | create, enter, exit, show, resolve, bind, lease |
91
+ | (top level) | branch, add, commit, push, prune, status, plan, apply |
92
+ | `sync` | status, run |
93
+ | `pr` | create, status, checks, merge, view |
94
+ | `check` | run, show |
95
+ | `review` | open, close, checkout-pr, run, check, bind, publish, receive, verify, show, merge, rebind, create-project |
96
+ | `exec` | status, run |
97
+ | `repo` | status, projection-run |
98
+ | `hooks` | trust, revoke, status, show, run |
99
+ | `store` | init, commit, check, push, status, log, diff, checkout, materialize, migrate, migrate-reviews |
100
+ | `target`, `config` | stored PR target; config overlays |
101
+
102
+ ## Overlay substrate
103
+
104
+ gr2 also carries the config-overlay substrate (capture, compose, and materialize configuration layers over a workspace): see [docs/OVERLAY-SUBSTRATE.md](docs/OVERLAY-SUBSTRATE.md).
105
+
106
+ ## Development
107
+
108
+ ```bash
109
+ pip install -e "gr2[dev]" # from the repository root
110
+ cd gr2 && pytest # the gr2 suite (tests + overlay tests)
111
+ cd gr2 && ruff check . # lint, same config as CI
112
+ ```
113
+
114
+ The Rust development binary is **`gr2-dev`** — built by `cargo build -p gr2-cli --release`, `publish = false`, and not shipped with `cargo install gitgrip`. It answered to the name `gr2` until 2026-09-30, so a branch written before that rename goes red on `cargo test -p gr2-cli` with `CARGO_BIN_EXE_gr2 is unset`; the repair is `cargo_bin("gr2-dev")`, from which Cargo derives `CARGO_BIN_EXE_gr2-dev`.
115
+
116
+ Migration: use `gr2 review check` for compiled review requirements. `review requirements`
117
+ remains a hidden alias with a warning on stderr until beta. Both report `satisfied`
118
+ in the same JSON payload, and a missing reviewer remains a reported status with exit 0.
119
+
120
+ A bare `gr2 review open <workspace>` uses the workspace's sole review bind. Its default directory is `<workspace>.review/<sha8>` in the workspace's parent directory, and the command announces that path on stderr. Give `--lane-dir` to choose another location.
121
+
122
+ New review binds record the binder's Git `user.name` from the workspace root.
123
+ Set it with `git config user.name 'Your Name'` there if Git has no configured name.
124
+ `review show --json` and `review verify --json` include this author; older binds
125
+ remain readable without an author field, and reading them does not invent one.
126
+
127
+
128
+ ## Transfer a native review
129
+
130
+ Publish an existing bound review and receive it in another native workspace:
131
+
132
+ ```bash
133
+ gr2 review publish gr:<full-review-id> --remote https://example.org/workspace.git
134
+ gr2 review receive gr:<full-review-id> --remote https://example.org/workspace.git
135
+ gr2 review show gr:<full-review-id>
136
+ gr2 review verify gr:<full-review-id>
137
+ gr2 review open gr:<full-review-id> --lane-dir /absolute/fresh-review
138
+ ```
139
+
140
+ The root defaults to the current workspace. Use `-C /absolute/workspace` to override
141
+ it. Transport requires an independently supplied full 40-character lowercase
142
+ review ID and an explicit HTTPS URL or absolute local remote path. It does not
143
+ infer the expected ID from the remote. A review is published at
144
+ `refs/dev.synapt.grip/__reviews__/v1/<full-review-id>`; `--ref`, when supplied, must be
145
+ exactly that, or the older `refs/dev.synapt.grip/__reviews__/<full-review-id>`. Invalid explicit input is
146
+ refused without falling back to context.
147
+
148
+ Publish transfers only that review ref and confirms its returned target. Receive
149
+ compares both the advertised and actual fetched raw target with the expected ID,
150
+ requires a commit and recomputable review content, then creates the canonical
151
+ local bind ref. A valid same-ID receive is idempotent. A conflicting existing ref
152
+ is refused. Object downloads may remain after refusal. The owned temporary ref
153
+ is removed separately, and cleanup failure is reported without replacing a
154
+ primary failure.
155
+
156
+ The review commit carries its trees, blobs and range patches. It does not make
157
+ its recorded base or original member head reachable as Git parents. Keep each
158
+ member's base reachable at its recorded remote for reconstruction. `verify`
159
+ checks content consistency, not current remote state, provenance or approval.
160
+ `open` checks reconstructed member trees. Commit identity can differ from the
161
+ original head. Receiving content grants no local approval, allocation, selection
162
+ or cleanup authority. Opening a reconstruction remains a separate operation.
163
+
164
+
165
+ ## External PR adapters
166
+
167
+ External packages can expose a zero-argument factory through the
168
+ `gr2.platform_adapters` entry-point group. See [the adapter contract](docs/PR-LIFECYCLE.md#51-adapter-protocol-and-capabilities)
169
+ for registration, optional operation capabilities and merge head-pin requirements.
170
+ Select the installed adapter with `gr2 pr create ... --platform NAME` on a
171
+ materialized lane. The bound-lane path currently pushes and returns its receipt.
172
+
173
+ PRs start as drafts by default. `--draft` is explicit draft creation, while
174
+ `--no-draft` explicitly creates non-drafts. The same default applies to
175
+ `CreatePRRequest` and `create_pr_group`. Existing Python callers can retain
176
+ non-draft creation with `draft=False`. Plugins execute trusted Python from the
177
+ existing environment. The CLI never installs or downloads them.
178
+
179
+ ## Checks on a plain Git remote
180
+
181
+ Run a command at an exact full commit id in a disposable checkout, then publish
182
+ its exit status to the repository's remote:
183
+
184
+ ```sh
185
+ gr2 check run ./repo -- python -m pytest
186
+ gr2 check show ./repo --json
187
+ ```
188
+
189
+ With no flags, the remote is the current branch's upstream (else `origin`) and the head is `HEAD`,
190
+ as a full commit id. gr2 prints what it resolved on stderr. `--remote` (a URL, an absolute path or a
191
+ remote's name), `--head` and `--name` override them. With no upstream and no `origin`, it refuses and
192
+ asks for `--remote`.
193
+
194
+ Absolute paths to local bare remotes also work. Observations live at
195
+ `refs/dev.synapt.grip/__checks__/v1`, keyed by commit id. `check show` fetches a
196
+ fresh snapshot; a different commit has no check even when its tree is identical.
197
+ Supplied `--require` names replace the default `test` requirement. For both
198
+ checks, use `--require test --require lint`.
199
+
200
+ The read JSON contains `status`, `record_id` (the head's record-set blob id or
201
+ null), `snapshot_oid`, `head`, `member_key`, `records`, and `reason`. Each
202
+ observation retains its fields and adds a SHA-256 `observation_id`.
203
+
204
+ A failed command is recorded and `check run` exits 1. Publication or execution
205
+ refusals exit 2. `check show` returns `pass`, `fail` or `absent` in its JSON;
206
+ failed or unmeasurable reads exit 2. Conflicting pass and fail observations both
207
+ survive and refuse readiness. Rerunning a check does not erase its earlier
208
+ failure at that commit. Concurrent writes union observations with bounded
209
+ compare-and-swap retries. An unmeasurable push acknowledgement is reported as
210
+ indeterminate unless a fresh remote read confirms the observation.
211
+
212
+ ## Merge a bound review into plain Git remotes
213
+
214
+ ```sh
215
+ gr2 review merge
216
+ ```
217
+
218
+ This merges the review bound at the members' current heads, from their current branch, into the
219
+ branch on each remote that still sits at the reviewed base, and prints what it resolved. If several
220
+ branches sit there, it asks for `--into`. It merges only if every member's remote feature
221
+ branch is still the reviewed head, the target is still the reviewed base, and the exact-head check
222
+ passes. If any member fails that preflight, nothing is pushed. Merges are separate pushes, not atomic
223
+ across repos: a member that moves after an earlier member was pushed is refused, and the run exits 4.
224
+
225
+ Exit codes:
226
+ - 0: all merged;
227
+ - 3: none merged (refused);
228
+ - 4: partial or unknown.
229
+
230
+ A review id, `--from` and `--into` override the defaults. Zero or several matching binds, or members on
231
+ different branches, refuse and name the value to pass.
232
+
233
+ These records are attestations by writers trusted with remote access, not signed
234
+ proof against a writer who can forge Git objects. Test output and environment
235
+ contents are not uploaded. Read this custom ref through gr2; plain `git notes`
236
+ cannot read notes outside `refs/notes/`.