gitgrip 2.0.0a9__tar.gz → 2.0.0a10__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 (508) hide show
  1. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/PKG-INFO +59 -11
  2. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/README.md +57 -10
  3. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/PKG-INFO +59 -11
  4. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/SOURCES.txt +72 -3
  5. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/requires.txt +1 -0
  6. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/PLATFORM_ADAPTER_CHANGELOG.md +16 -0
  7. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/lane_workspace_prototype.py +25 -3
  8. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/repo_maintenance_prototype.py +5 -21
  9. gitgrip-2.0.0a10/gr2/python_cli/_build.json +1 -0
  10. gitgrip-2.0.0a10/gr2/python_cli/add.py +104 -0
  11. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/app.py +746 -125
  12. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/approvals.py +222 -12
  13. gitgrip-2.0.0a10/gr2/python_cli/arbon.py +123 -0
  14. gitgrip-2.0.0a10/gr2/python_cli/branch_update.py +115 -0
  15. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/clone_exec.py +75 -1
  16. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/consent.py +20 -17
  17. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/defaults.py +21 -0
  18. gitgrip-2.0.0a10/gr2/python_cli/delete.py +62 -0
  19. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/gitops.py +41 -4
  20. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/grip.py +461 -25
  21. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/grip_cli.py +833 -71
  22. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/lane_downstream.py +53 -8
  23. gitgrip-2.0.0a10/gr2/python_cli/leased_push.py +79 -0
  24. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/merge_gate.py +216 -14
  25. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/migration.py +118 -215
  26. gitgrip-2.0.0a10/gr2/python_cli/next_steps.py +215 -0
  27. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/open_gr_review.py +3 -17
  28. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/platform.py +51 -0
  29. gitgrip-2.0.0a10/gr2/python_cli/proto_json.py +122 -0
  30. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review.py +55 -0
  31. gitgrip-2.0.0a10/gr2/python_cli/review_diff.py +88 -0
  32. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_ephemeral.py +34 -6
  33. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_field_tree.py +7 -3
  34. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_rebind.py +12 -0
  35. gitgrip-2.0.0a10/gr2/python_cli/review_update.py +176 -0
  36. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/set_check.py +36 -2
  37. gitgrip-2.0.0a10/gr2/python_cli/shadow.py +190 -0
  38. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/spec_apply.py +66 -9
  39. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/store_hooks.py +29 -12
  40. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/syncops.py +11 -6
  41. gitgrip-2.0.0a10/gr2/python_cli/tracking.py +54 -0
  42. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/version.py +54 -7
  43. gitgrip-2.0.0a10/gr2/python_cli/workspace_guidance.py +74 -0
  44. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.review.v1alpha1/descriptor_set.pb +4 -3
  45. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.review.v1alpha1/review.proto +1 -0
  46. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/pyproject.toml +4 -1
  47. gitgrip-2.0.0a10/setup.py +123 -0
  48. gitgrip-2.0.0a10/tests/test_add.py +276 -0
  49. gitgrip-2.0.0a10/tests/test_add_lane_from_a_subdirectory.py +87 -0
  50. gitgrip-2.0.0a10/tests/test_arbon.py +230 -0
  51. gitgrip-2.0.0a10/tests/test_bind_merge_head_refusals.py +116 -0
  52. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_break_18_gr1_sibling_units.py +45 -30
  53. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_clone_materialization.py +130 -0
  54. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_declared_sets.py +1 -1
  55. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_defaults_from_repo.py +55 -18
  56. gitgrip-2.0.0a10/tests/test_delete.py +157 -0
  57. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_event_outcome_policy.py +2 -1
  58. gitgrip-2.0.0a10/tests/test_fetch_refmap.py +70 -0
  59. gitgrip-2.0.0a10/tests/test_fetch_refmap_pr_base.py +84 -0
  60. gitgrip-2.0.0a10/tests/test_gitops_locating_env.py +109 -0
  61. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gitops_shared.py +7 -3
  62. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr_installed_wheel.py +9 -3
  63. gitgrip-2.0.0a10/tests/test_init_advice_never_nests.py +191 -0
  64. gitgrip-2.0.0a10/tests/test_lane_cache_keyed_by_member_name.py +144 -0
  65. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_create_defaults.py +104 -5
  66. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_exit_keeps_dirty_work.py +53 -0
  67. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_remove.py +131 -0
  68. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_store_path_pins.py +16 -14
  69. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_layout_census.py +1 -1
  70. gitgrip-2.0.0a10/tests/test_leased_push.py +166 -0
  71. gitgrip-2.0.0a10/tests/test_merge_credential_remotes.py +84 -0
  72. gitgrip-2.0.0a10/tests/test_migrate_gr1_one_root.py +247 -0
  73. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_migration.py +3 -1
  74. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_np_bench_contract_scenario.py +1 -1
  75. gitgrip-2.0.0a10/tests/test_one_pin_record.py +399 -0
  76. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_out_of_set_hint.py +3 -3
  77. gitgrip-2.0.0a10/tests/test_outside_names_as_git_options.py +272 -0
  78. gitgrip-2.0.0a10/tests/test_pr_create_pins_itself.py +279 -0
  79. gitgrip-2.0.0a10/tests/test_proto_json.py +145 -0
  80. gitgrip-2.0.0a10/tests/test_readme_walk.py +169 -0
  81. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_record_schema_copies.py +4 -4
  82. gitgrip-2.0.0a10/tests/test_refusal_names_the_cause.py +138 -0
  83. gitgrip-2.0.0a10/tests/test_repo_maintenance_gitops.py +109 -0
  84. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_a4_v3.py +17 -5
  85. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_approvals.py +216 -15
  86. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_verify.py +8 -5
  87. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_cli.py +5 -4
  88. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_close_keeps_local_work.py +3 -1
  89. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_field_tree.py +1 -1
  90. gitgrip-2.0.0a10/tests/test_review_json_refusals.py +74 -0
  91. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_merge_gate.py +26 -10
  92. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_merge_gate_lost_ack.py +8 -5
  93. gitgrip-2.0.0a10/tests/test_review_merge_platform.py +344 -0
  94. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_merge_receipt.py +6 -3
  95. gitgrip-2.0.0a10/tests/test_review_merge_set_alone.py +197 -0
  96. gitgrip-2.0.0a10/tests/test_review_merge_set_required.py +244 -0
  97. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_merge_updates_tracking_ref.py +2 -2
  98. gitgrip-2.0.0a10/tests/test_review_named_refusals.py +53 -0
  99. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_open_lane.py +262 -0
  100. gitgrip-2.0.0a10/tests/test_review_open_reader_lane.py +179 -0
  101. gitgrip-2.0.0a10/tests/test_review_pin_after_push.py +266 -0
  102. gitgrip-2.0.0a10/tests/test_review_pin_ratified.py +126 -0
  103. gitgrip-2.0.0a10/tests/test_review_pin_rows_json_help.py +27 -0
  104. gitgrip-2.0.0a10/tests/test_review_pinned_target.py +207 -0
  105. gitgrip-2.0.0a10/tests/test_review_publish_all.py +292 -0
  106. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_reader_defaults.py +1 -1
  107. gitgrip-2.0.0a10/tests/test_review_receive_no_migrate.py +61 -0
  108. gitgrip-2.0.0a10/tests/test_review_show_diff.py +464 -0
  109. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_transport.py +156 -1
  110. gitgrip-2.0.0a10/tests/test_review_update.py +378 -0
  111. gitgrip-2.0.0a10/tests/test_review_verify_json_refusals.py +97 -0
  112. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_root_option_verbs.py +1 -1
  113. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_set_check.py +66 -5
  114. gitgrip-2.0.0a10/tests/test_set_check_credential_remote.py +34 -0
  115. gitgrip-2.0.0a10/tests/test_set_check_merge_head.py +138 -0
  116. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_set_check_remote_heads.py +7 -5
  117. gitgrip-2.0.0a10/tests/test_shadow.py +163 -0
  118. gitgrip-2.0.0a10/tests/test_shadow_lease.py +178 -0
  119. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_skill_dump.py +4 -3
  120. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_break_attempts.py +3 -0
  121. gitgrip-2.0.0a10/tests/test_store_check_undeclared_gitlink.py +121 -0
  122. gitgrip-2.0.0a10/tests/test_store_commit_compat_next_step.py +139 -0
  123. gitgrip-2.0.0a10/tests/test_store_fence_no_pin.py +61 -0
  124. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_full_mode_carrier.py +4 -1
  125. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_full_mode_layers.py +7 -3
  126. gitgrip-2.0.0a10/tests/test_store_init_derived_spec.py +170 -0
  127. gitgrip-2.0.0a10/tests/test_store_init_slot_pointer.py +127 -0
  128. gitgrip-2.0.0a10/tests/test_store_init_slot_write_error.py +78 -0
  129. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_member_state.py +6 -1
  130. gitgrip-2.0.0a10/tests/test_store_push_landed_by_another.py +64 -0
  131. gitgrip-2.0.0a10/tests/test_store_push_member_refs.py +166 -0
  132. gitgrip-2.0.0a10/tests/test_store_push_s2.py +176 -0
  133. gitgrip-2.0.0a10/tests/test_store_push_s3a.py +246 -0
  134. gitgrip-2.0.0a10/tests/test_store_push_s3b.py +295 -0
  135. gitgrip-2.0.0a10/tests/test_store_refusal_names_both_exits.py +76 -0
  136. gitgrip-2.0.0a10/tests/test_store_shadow_fence.py +175 -0
  137. gitgrip-2.0.0a10/tests/test_store_shadow_s1.py +142 -0
  138. gitgrip-2.0.0a10/tests/test_store_status_push_undeclared_gitlink.py +92 -0
  139. gitgrip-2.0.0a10/tests/test_store_untracked_member.py +99 -0
  140. gitgrip-2.0.0a10/tests/test_store_verbs_name_their_root.py +236 -0
  141. gitgrip-2.0.0a10/tests/test_subdir_cwd_review_verbs.py +79 -0
  142. gitgrip-2.0.0a10/tests/test_subdir_cwd_verbs.py +91 -0
  143. gitgrip-2.0.0a10/tests/test_tracking.py +144 -0
  144. gitgrip-2.0.0a10/tests/test_update.py +385 -0
  145. gitgrip-2.0.0a10/tests/test_version_build_stamp.py +393 -0
  146. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_version_identity.py +35 -3
  147. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_version_static.py +8 -4
  148. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_identity_boundary.py +9 -7
  149. gitgrip-2.0.0a10/tests/test_workspace_spec_missing.py +118 -0
  150. gitgrip-2.0.0a9/gr2/python_cli/add.py +0 -51
  151. gitgrip-2.0.0a9/gr2/python_cli/next_steps.py +0 -101
  152. gitgrip-2.0.0a9/gr2/python_cli/workspace_guidance.py +0 -22
  153. gitgrip-2.0.0a9/tests/test_add.py +0 -129
  154. gitgrip-2.0.0a9/tests/test_migration_desk_state.py +0 -512
  155. gitgrip-2.0.0a9/tests/test_migration_unadopted_notice.py +0 -134
  156. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/dependency_links.txt +0 -0
  157. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/entry_points.txt +0 -0
  158. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gitgrip.egg-info/top_level.txt +0 -0
  159. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/__init__.py +0 -0
  160. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/api_core.py +0 -0
  161. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/__init__.py +0 -0
  162. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/activate.py +0 -0
  163. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/agent_manifest.py +0 -0
  164. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/cli.py +0 -0
  165. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/cross_repo.py +0 -0
  166. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/drivers.py +0 -0
  167. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/introspection.py +0 -0
  168. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/language_drivers.py +0 -0
  169. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/objects.py +0 -0
  170. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/perf.py +0 -0
  171. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/refs.py +0 -0
  172. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/trust.py +0 -0
  173. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/types.py +0 -0
  174. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/units.py +0 -0
  175. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/overlay/workspace_spec.py +0 -0
  176. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/__init__.py +0 -0
  177. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/cache_materialization_probe.py +0 -0
  178. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/concurrent_event_stress.py +0 -0
  179. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/concurrent_lease_stress.py +0 -0
  180. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/concurrent_workspace_cap_stress.py +0 -0
  181. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/contribution_protocol.py +0 -0
  182. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/cross_mode_lane_stress.py +0 -0
  183. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/jsonl_store.py +0 -0
  184. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/layout_model_probe.py +0 -0
  185. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/propagation_daemon.py +0 -0
  186. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/propagation_state_machine.py +0 -0
  187. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/python_exec_playground.py +0 -0
  188. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/python_hook_runtime_playground.py +0 -0
  189. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/python_migration_playground.py +0 -0
  190. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/python_review_checkout_playground.py +0 -0
  191. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/python_spec_apply_playground.py +0 -0
  192. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/real_git_lane_materialization.py +0 -0
  193. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/real_git_playground.py +0 -0
  194. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/recall_lane_history.py +0 -0
  195. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/prototypes/repo_transport_probe.py +0 -0
  196. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/__init__.py +0 -0
  197. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/__main__.py +0 -0
  198. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/agent_record.py +0 -0
  199. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/approval_schema.py +0 -0
  200. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/branch.py +0 -0
  201. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/channel_bridge.py +0 -0
  202. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/check_records.py +0 -0
  203. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/commit.py +0 -0
  204. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/config.py +0 -0
  205. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/context.py +0 -0
  206. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/declared_sets.py +0 -0
  207. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/ecosystems_python.py +0 -0
  208. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/env_exec.py +0 -0
  209. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/events.py +0 -0
  210. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/execops.py +0 -0
  211. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/exit_codes.py +0 -0
  212. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/failures.py +0 -0
  213. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/file_exec.py +0 -0
  214. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/git_review.py +0 -0
  215. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/gitinclude.py +0 -0
  216. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/gr_resolver.py +0 -0
  217. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/gr_shadow.py +0 -0
  218. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/hooks.py +0 -0
  219. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/lane_defaults.py +0 -0
  220. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/lane_graph.py +0 -0
  221. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/lane_plugins.py +0 -0
  222. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/launch_exec.py +0 -0
  223. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/layout.py +0 -0
  224. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/member_field_tree.py +0 -0
  225. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/merge_receipts.py +0 -0
  226. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/merge_verification.py +0 -0
  227. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/names.py +0 -0
  228. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/pr.py +0 -0
  229. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/project_review.py +0 -0
  230. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/prune.py +0 -0
  231. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/push.py +0 -0
  232. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_allocation.py +0 -0
  233. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_dispatch.py +0 -0
  234. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_members.py +0 -0
  235. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_records.py +0 -0
  236. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_run.py +0 -0
  237. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/review_runners.py +0 -0
  238. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/root_option.py +0 -0
  239. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/set_hints.py +0 -0
  240. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/staging_cleanup.py +0 -0
  241. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/target.py +0 -0
  242. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/workspace_mode.py +0 -0
  243. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/python_cli/workspace_snapshot.py +0 -0
  244. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.approval.v1alpha1/approval.proto +0 -0
  245. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.approval.v1alpha1/descriptor_set.pb +0 -0
  246. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.check.v1alpha1/check.proto +0 -0
  247. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.check.v1alpha1/descriptor_set.pb +0 -0
  248. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.merge.v1alpha1/descriptor_set.pb +0 -0
  249. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/dev.synapt.grip.merge.v1alpha1/merge.proto +0 -0
  250. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/gr2-materialization-plan-v1.schema.json +0 -0
  251. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2/schemas/gr2-workspace-spec-v1.schema.json +0 -0
  252. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/gr2_overlay/__init__.py +0 -0
  253. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/setup.cfg +0 -0
  254. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_agent_manifest_overlay_source.py +0 -0
  255. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_agent_record_append.py +0 -0
  256. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_agent_record_fold.py +0 -0
  257. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_agent_record_stamps.py +0 -0
  258. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_api_core_seam.py +0 -0
  259. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_api_dump.py +0 -0
  260. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_app_event_outcomes.py +0 -0
  261. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_apply_convergence.py +0 -0
  262. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_apply_gr1_sibling_adoption.py +0 -0
  263. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_approval_schema.py +0 -0
  264. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_branch.py +0 -0
  265. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_break_17_unit_path_containment.py +0 -0
  266. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_channel_bridge.py +0 -0
  267. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_cli_adapter_error_boundary.py +0 -0
  268. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_cli_shape_witnesses.py +0 -0
  269. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_commit.py +0 -0
  270. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_config_base_path_guard.py +0 -0
  271. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_config_overlay.py +0 -0
  272. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_conftest_git_isolation.py +0 -0
  273. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_consent_key_paths.py +0 -0
  274. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_context_resolver.py +0 -0
  275. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_contribution_protocol.py +0 -0
  276. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_declared_set_pins.py +0 -0
  277. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_deprecation_registry.py +0 -0
  278. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_ecosystems_python.py +0 -0
  279. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_ensure_lane_checkout_reference_clone.py +0 -0
  280. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_env_materialization.py +0 -0
  281. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_event_log_integrity.py +0 -0
  282. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_events.py +0 -0
  283. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_events_torn_line.py +0 -0
  284. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_exec_apostrophe_and_oserror.py +0 -0
  285. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_exec_run_names_what_did_not_run.py +0 -0
  286. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_exec_single_string_and_materialize_plan.py +0 -0
  287. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_execops.py +0 -0
  288. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_failure_event_outcome.py +0 -0
  289. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_field_tree_name.py +0 -0
  290. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_field_tree_schema_reader.py +0 -0
  291. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_files_compose.py +0 -0
  292. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_first_five_minutes.py +0 -0
  293. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_foreground_launch_runtime.py +0 -0
  294. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_git_review.py +0 -0
  295. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_git_transport_allow_list.py +0 -0
  296. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gitinclude_compiler.py +0 -0
  297. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr1_first_run_guidance.py +0 -0
  298. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr2_packaging.py +0 -0
  299. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr2_review_receipt.py +0 -0
  300. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr_resolved_cleared.py +0 -0
  301. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr_resolver_conformance.py +0 -0
  302. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_gr_shadow.py +0 -0
  303. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_grip_cli.py +0 -0
  304. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_grip_hardening.py +0 -0
  305. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_grip_snapshot.py +0 -0
  306. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_grip_toml_literals.py +0 -0
  307. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_grip_toml_schema_v1.py +0 -0
  308. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hook_events.py +0 -0
  309. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hook_hardening.py +0 -0
  310. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hooks_consent.py +0 -0
  311. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hooks_group_names.py +0 -0
  312. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hostile_names.py +0 -0
  313. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_hostile_names_helper.py +0 -0
  314. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_jsonl_store.py +0 -0
  315. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_checkout_root.py +0 -0
  316. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_create_fork_base_cli.py +0 -0
  317. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_create_refusal_leaves_nothing.py +0 -0
  318. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_create_refuses_own_branch.py +0 -0
  319. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_downstream.py +0 -0
  320. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_downstream_run.py +0 -0
  321. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_enter_hook_warnings.py +0 -0
  322. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_graph.py +0 -0
  323. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_lease_show_json.py +0 -0
  324. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_lifecycle_safety.py +0 -0
  325. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_plugins.py +0 -0
  326. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_probe.py +0 -0
  327. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_probe_batch.py +0 -0
  328. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_push.py +0 -0
  329. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_repo_paths_and_all_skipped.py +0 -0
  330. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_roles.py +0 -0
  331. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_show_name.py +0 -0
  332. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_lane_toml_serialization.py +0 -0
  333. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_launch_primitive.py +0 -0
  334. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_linked_review_receipts.py +0 -0
  335. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_m2_overlay_hindsight.py +0 -0
  336. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_m2_overlay_mem0.py +0 -0
  337. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_m2_overlay_zep.py +0 -0
  338. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_malformed_remote_refusal.py +0 -0
  339. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_materialization_plan_contract.py +0 -0
  340. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_materialize_pin.py +0 -0
  341. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_member_working_root_checkout_materialize.py +0 -0
  342. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_merge_evidence.py +0 -0
  343. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_merge_parent_verification.py +0 -0
  344. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_migration_overlay_compatibility.py +0 -0
  345. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_names.py +0 -0
  346. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_native_store_gitinclude.py +0 -0
  347. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_native_store_review_record_probes.py +0 -0
  348. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_no_bare_python_cli_imports.py +0 -0
  349. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_null_current_lane_refusal.py +0 -0
  350. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_open_gr_enter.py +0 -0
  351. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_open_project_refusal_reason_cli.py +0 -0
  352. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_outbox_ack_after_effect.py +0 -0
  353. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_acceptance.py +0 -0
  354. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_activate.py +0 -0
  355. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_cli.py +0 -0
  356. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_cli_wiring.py +0 -0
  357. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_composition_merge.py +0 -0
  358. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_cross_repo_atomic_apply.py +0 -0
  359. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_cross_repo_perf_gate.py +0 -0
  360. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_cross_repo_rollback.py +0 -0
  361. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_driver_registry.py +0 -0
  362. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_introspection.py +0 -0
  363. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_multi_stack.py +0 -0
  364. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_object_encoding.py +0 -0
  365. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_perf_gates.py +0 -0
  366. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_python_driver.py +0 -0
  367. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_tier_b_encoding.py +0 -0
  368. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_tier_b_perf_gates.py +0 -0
  369. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_tier_b_repo_state.py +0 -0
  370. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_tier_b_staging_discipline.py +0 -0
  371. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_trust_model.py +0 -0
  372. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_overlay_workspace_spec.py +0 -0
  373. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_platform_adapter_changelog.py +0 -0
  374. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_platform_adapter_plugins.py +0 -0
  375. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_adapter_v2_target.py +0 -0
  376. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_events.py +0 -0
  377. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_group_legibility.py +0 -0
  378. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_merge_head_pin.py +0 -0
  379. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_merge_method.py +0 -0
  380. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_merge_missing_target.py +0 -0
  381. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_merge_partial_failure.py +0 -0
  382. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_review_subject.py +0 -0
  383. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_pr_view.py +0 -0
  384. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_project_file_materialization.py +0 -0
  385. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_project_review_range_reconstruction.py +0 -0
  386. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_project_review_three_repo.py +0 -0
  387. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_projection_tracked_dest.py +0 -0
  388. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_propagation_contribution.py +0 -0
  389. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_propagation_daemon.py +0 -0
  390. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_propagation_state_machine.py +0 -0
  391. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_prune.py +0 -0
  392. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_push.py +0 -0
  393. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_python_group_install.py +0 -0
  394. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_readme_verbs_exist.py +0 -0
  395. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_remote_check_records.py +0 -0
  396. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_repo_path_read_through.py +0 -0
  397. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_repo_status_linked_worktree.py +0 -0
  398. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_repo_status_schema_version.py +0 -0
  399. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_repo_status_symlinked_git_dir.py +0 -0
  400. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_retire_gr1.py +0 -0
  401. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_a4.py +0 -0
  402. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_a4_v2.py +0 -0
  403. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_allocation_recovery.py +0 -0
  404. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_ansi_parse.py +0 -0
  405. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_b3_reader_alignment.py +0 -0
  406. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_author.py +0 -0
  407. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_fork_base.py +0 -0
  408. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_from_range.py +0 -0
  409. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_migration.py +0 -0
  410. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_native_store.py +0 -0
  411. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_bind_root_refs.py +0 -0
  412. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_check_name.py +0 -0
  413. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_close_gr.py +0 -0
  414. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_context_defaults.py +0 -0
  415. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_context_witnesses.py +0 -0
  416. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_create_project_cli.py +0 -0
  417. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_dispatch.py +0 -0
  418. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_ephemeral.py +0 -0
  419. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_events.py +0 -0
  420. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_field_tree_reader_edges.py +0 -0
  421. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_field_tree_readers.py +0 -0
  422. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_install_hint.py +0 -0
  423. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_pin_stamp_names.py +0 -0
  424. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_pr_marker_context.py +0 -0
  425. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_rebind.py +0 -0
  426. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_receipt_cleanup.py +0 -0
  427. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_ref_v1_migration.py +0 -0
  428. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_ref_v1_reader.py +0 -0
  429. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_ref_v1_writer.py +0 -0
  430. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_remote_safety.py +0 -0
  431. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run.py +0 -0
  432. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_context.py +0 -0
  433. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_deleted_cwd.py +0 -0
  434. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_dependency_order.py +0 -0
  435. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_import_isolation.py +0 -0
  436. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_integrity_recheck.py +0 -0
  437. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_multi_repo.py +0 -0
  438. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_package_name.py +0 -0
  439. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_plugin_order.py +0 -0
  440. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_rerun_and_refusal_receipt.py +0 -0
  441. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_run_venv_and_refusal_identity.py +0 -0
  442. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_runners.py +0 -0
  443. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_subject.py +0 -0
  444. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_v1_format_guard.py +0 -0
  445. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_verify_inside.py +0 -0
  446. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_review_vocabulary.py +0 -0
  447. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_rmtree_or_refuse.py +0 -0
  448. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_selected_workspace_commit.py +0 -0
  449. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_single_repo_cwd_refusal.py +0 -0
  450. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_snapshot_id_prefix_resolution.py +0 -0
  451. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_spec_apply_event_outcomes.py +0 -0
  452. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_spec_declaration_ref_pin.py +0 -0
  453. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_spec_show_native_root.py +0 -0
  454. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sprint21_sync_platform.py +0 -0
  455. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_staging_cleanup.py +0 -0
  456. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_checkout_atomicity.py +0 -0
  457. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_commit_follows_branch.py +0 -0
  458. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_commit_keeps_record.py +0 -0
  459. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_commit_noop.py +0 -0
  460. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_commit_refuses_rewind.py +0 -0
  461. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_declared_members.py +0 -0
  462. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_full_mode_coverage.py +0 -0
  463. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_full_mode_records.py +0 -0
  464. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_git_hooks.py +0 -0
  465. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_git_native_smoke.py +0 -0
  466. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_gitmodules.py +0 -0
  467. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_gitmodules_branch.py +0 -0
  468. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_hook_takes_verb_coverage.py +0 -0
  469. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_init_branch_inference.py +0 -0
  470. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_init_clone.py +0 -0
  471. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_log_adoption_boundary.py +0 -0
  472. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_materialize_branch.py +0 -0
  473. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_materialize_fetches_new_pin.py +0 -0
  474. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_materialize_installs_hooks.py +0 -0
  475. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_member_path_hygiene.py +0 -0
  476. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_migrate_branch_inference.py +0 -0
  477. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_moved_workspace_guard.py +0 -0
  478. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_status_inspection.py +0 -0
  479. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_status_values.py +0 -0
  480. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_submodule_init.py +0 -0
  481. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_submodule_update_merge.py +0 -0
  482. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_verb_rename.py +0 -0
  483. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_store_verb_witnesses.py +0 -0
  484. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_submodule_member_predicate.py +0 -0
  485. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_superproject_import.py +0 -0
  486. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_event_outcomes.py +0 -0
  487. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_fast_forward.py +0 -0
  488. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_fetch.py +0 -0
  489. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_seed_local.py +0 -0
  490. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_ssh_rewrite.py +0 -0
  491. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_sync_status_probe.py +0 -0
  492. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_target.py +0 -0
  493. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_tmux_launch_runtime.py +0 -0
  494. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_abort.py +0 -0
  495. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_apply.py +0 -0
  496. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_apply_dry_run.py +0 -0
  497. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_manifest_schema.py +0 -0
  498. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_propose.py +0 -0
  499. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_unit_topological_apply.py +0 -0
  500. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_validate_repo_path_conflict.py +0 -0
  501. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_vocabulary.py +0 -0
  502. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_convert_clone.py +0 -0
  503. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_edit_lease_cap.py +0 -0
  504. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_init_from_topology.py +0 -0
  505. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_init_local_repos.py +0 -0
  506. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_root_defaults.py +0 -0
  507. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_root_nearest_marker.py +0 -0
  508. {gitgrip-2.0.0a9 → gitgrip-2.0.0a10}/tests/test_workspace_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitgrip
3
- Version: 2.0.0a9
3
+ Version: 2.0.0a10
4
4
  Summary: Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -13,6 +13,7 @@ Provides-Extra: dev
13
13
  Requires-Dist: pytest>=8.0; extra == "dev"
14
14
  Requires-Dist: ruff>=0.4; extra == "dev"
15
15
  Requires-Dist: packaging>=22; extra == "dev"
16
+ Requires-Dist: setuptools>=68.0; extra == "dev"
16
17
 
17
18
  # gr2
18
19
 
@@ -51,8 +52,11 @@ gr2 workspace init ~/ws # scans the folder; writes .grip/workspa
51
52
  gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
52
53
  gr2 workspace status ~/ws # what kind of workspace this is
53
54
  gr2 store init ~/ws # the workspace snapshot store (needed before review)
55
+ gr2 store commit -m "first snapshot" # record the workspace once; lanes start from a recorded snapshot
54
56
  ```
55
57
 
58
+ `store commit` reads the workspace from the current directory, which is why the walk starts with `cd ~/ws`; from anywhere else, name it: `gr2 store commit -C ~/ws -m "..."`. It prints nothing on success; each repo it records for the first time gets one note on stderr.
59
+
56
60
  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:
57
61
 
58
62
  ```bash
@@ -60,24 +64,25 @@ gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
60
64
  gr2 lane enter ~/ws default feat-x --actor human:you
61
65
  ```
62
66
 
63
- Both commands print, per repo, the absolute directory you work in:
67
+ `lane create` prints the lane's record, then, per repo, the absolute directory you work in (`lane enter` prints the same directories as `repo_paths`):
64
68
 
65
69
  ```
66
- repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
67
- repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
70
+ ~/ws/.grip/state/lanes/default/feat-x/lane.toml
71
+ repo-a: ~/ws/agents/default/lanes/feat-x/repo-a
72
+ repo-b: ~/ws/agents/default/lanes/feat-x/repo-b
68
73
  ```
69
74
 
70
75
  Edit there — not in your original clones. Stage and commit across the lane's repos:
71
76
 
72
77
  ```bash
73
- gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
78
+ gr2 add . --repo-path ~/ws/agents/default/lanes/feat-x/repo-a
74
79
  gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
75
80
  ```
76
81
 
77
82
  `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:
78
83
 
79
84
  ```bash
80
- gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
85
+ gr2 exec run ~/ws default --actor human:you -- git status --short # one command, every lane repo
81
86
  gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
82
87
  gr2 lane push ~/ws default feat-x # push every lane repo, each verified on its remote
83
88
  gr2 lane show ~/ws default # where am I?
@@ -86,7 +91,7 @@ gr2 lane list ~/ws # each lane: removabl
86
91
  gr2 lane remove ~/ws default feat-x # end it: its clones and record go
87
92
  ```
88
93
 
89
- `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
94
+ `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` runs whatever follows `--` in each lane repo, with your own `PATH`: a test runner works there only if it is installed where your shell finds it. `review create-project` refuses a lane repo holding any uncommitted or untracked file, so whatever a command leaves behind (`__pycache__/` after a pytest run, say) has to be in the repo's `.gitignore`. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
90
95
 
91
96
  ## What works today, and what is not there yet
92
97
 
@@ -109,17 +114,20 @@ Not there yet:
109
114
  | `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, retire-gr1, migrate-lane-state, bootstrap-gr1, gitinclude |
110
115
  | `spec` | show, validate |
111
116
  | `lane` | create, enter, exit, show, resolve, bind, lease, list, push, remove |
112
- | (top level) | branch, add, commit, push, prune, status, plan, apply |
117
+ | (top level) | branch, add, commit, push, prune, status, plan, apply, update |
113
118
  | `sync` | status, run |
114
119
  | `pr` | create, status, checks, merge, view |
115
120
  | `check` | run, show, set |
116
- | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, repin, create-project, bind, approve, rebind |
121
+ | `proto` | json |
122
+ | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, update, repin, create-project, bind, approve, rebind |
117
123
  | `exec` | status, run |
118
124
  | `repo` | status, projection-run |
119
125
  | `hooks` | trust, revoke, status, show, run |
120
126
  | `store` | init, commit, check, push, status, log, diff, checkout, materialize, migrate, migrate-reviews |
121
127
  | `target`, `config` | stored PR target; config overlays |
122
128
 
129
+ Every `store` verb names its workspace with `-C/--root <root>`, else reads the current directory.
130
+
123
131
  `review bind`, `review approve` and `review rebind` remain as aliases of `pin`, `stamp` and `repin`.
124
132
 
125
133
  The words these commands use (lane, pin, stamp, repin, gate, review) are defined in [docs/GLOSSARY.md](docs/GLOSSARY.md).
@@ -134,6 +142,18 @@ gr2 review stamp
134
142
  gr2 review merge
135
143
  ```
136
144
 
145
+ A reviewer whose own workspace does not hold the reviewed repos (another team's
146
+ gripspace) receives the review, opens a lane, and stamps from the lane (or from one
147
+ repo directory in it). The stamp uses the store of the workspace the lane was opened
148
+ from and the repos checked out in the lane, and records the git `user.name` of that
149
+ workspace, not of the lane:
150
+
151
+ ```bash
152
+ gr2 review receive <their-workspace> gr:<id> --remote <member-remote>
153
+ gr2 review open <their-workspace> gr:<id> --lane-dir <lane>
154
+ gr2 review stamp <lane>
155
+ ```
156
+
137
157
  The author recorded by the pin, and anyone who authored a commit in its range,
138
158
  cannot stamp it. A stamp records an approval; approver names are self-declared and receipts say `signed: false`.
139
159
  Repeated stamps by the same name count once. A moved head needs a new pin
@@ -177,6 +197,18 @@ Set it with `git config user.name 'Your Name'` there if Git has no configured na
177
197
  `review show --json` and `review verify --json` include this author; older pinned reviews
178
198
  remain readable without an author field, and reading them does not invent one.
179
199
 
200
+ ## Run a review's tests
201
+
202
+ `gr2 review run` runs the reviewed tree's tests inside the review's lane, and only after it proves the lane equals the pinned tree. What to install and what to test comes from the reviewed repo itself: a tracked `.review-install` file at the repo root, read whenever the flags are left out. For a Python repo tested with pytest it needs two lines: the package the run must import from inside the lane, and an install that brings pytest:
203
+
204
+ ```
205
+ # .review-install
206
+ package = mypkg
207
+ install = {venv} -m pip install -e {lane} pytest
208
+ ```
209
+
210
+ `{venv}` is the lane venv's Python executable, not its directory, and `{lane}` is the lane's checkout of the repo; both are filled in per token. Without an `install` line the run uses `<lane venv python> -m pip install -e <lane>`, which installs your package and no test runner, so a pytest repo without the line refuses (`pytest_not_installed`). Either way the repo must be pip-installable (a `pyproject.toml` or `setup.py` declaring that package). For another language, declare the runner and its command instead, for example `runner = cargo` and `test = cargo test`. The recognised keys are `install`, `package`, `runner`, `test` and `reports`; any other key is refused (`bad_hint`). A repo with no `.review-install` must pass `--package` and/or `--install`, and with neither the run refuses (`no_package`). `gr2 review run --help` has the full list.
211
+
180
212
 
181
213
  ## Transfer a native review
182
214
 
@@ -206,6 +238,13 @@ is refused. Object downloads may remain after refusal. The owned temporary ref
206
238
  is removed separately, and cleanup failure is reported without replacing a
207
239
  primary failure.
208
240
 
241
+ Receive also fetches each member's pinned head from the remote it read the review
242
+ from, one `heads` row per member. A member whose recorded remote is another one
243
+ (a review published to a staging remote) is `not_this_remote`. `gr2 review open`
244
+ builds the lane from the range the review carries, and the row's `next` names that
245
+ command. `gr2 review show --diff` and `gr2 review stamp` still need the head: they
246
+ refuse until the author pushes it to the member's own remote and it is fetched.
247
+
209
248
  The review commit carries its trees, blobs and range patches. It does not make
210
249
  its recorded base or original member head reachable as Git parents. Keep each
211
250
  member's base reachable at its recorded remote for reconstruction. `verify`
@@ -260,8 +299,17 @@ observation retains its fields and adds a SHA-256 `observation_id`.
260
299
  A review over several members is checked as one set. `gr2 check set <workspace> <review> -- <command>`
261
300
  reconstructs every member at its pinned head side by side (`GR2_SET_ROOT`, `GR2_REVIEW_ID` and `GR2_SET_MEMBERS`
262
301
  name them), runs the command once, and publishes one `set` observation per member remote, carrying the review and the
263
- identity of the set. `gr2 review merge` requires that record on a multi-member review (`--no-set` says otherwise),
264
- and `check show --require set --review <id>` reads a `set` record for another review as stale.
302
+ identity of the set. With no `--check`, `gr2 review merge` on a multi-member review requires that record AND each
303
+ member's `test` at its head: a member whose recorded `test` is red is refused and nothing lands, and a member with no
304
+ `test` record of its own is decided by the passing set (members that import each other cannot pass a test alone), so
305
+ one `check set` and the approvals are enough to merge. `--check test` names `test` explicitly and only a `test` record
306
+ decides it (one that `check set --name test` wrote for this review counts); its refusal prints that `check set`. On a
307
+ one-member review the default `test` is also decided by a passing `set` record for this review at that head. A `set`
308
+ record for another review or other heads never counts. The requirement comes from the
309
+ review, not from the person merging: on a multi-member review `--no-set` is refused, and so is any `--check` name other
310
+ than `test` and `set`. `review pin` refuses a multi-member review whose rows do not each carry a `source` or a `range`,
311
+ because `check set` could never run on it. `check show --require set --review <id>` reads a `set` record for another
312
+ review as stale.
265
313
 
266
314
  A failed command is recorded and `check run` exits 1. Publication or execution
267
315
  refusals exit 2. `check show` returns `pass`, `fail` or `absent` in its JSON;
@@ -35,8 +35,11 @@ gr2 workspace init ~/ws # scans the folder; writes .grip/workspa
35
35
  gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
36
36
  gr2 workspace status ~/ws # what kind of workspace this is
37
37
  gr2 store init ~/ws # the workspace snapshot store (needed before review)
38
+ gr2 store commit -m "first snapshot" # record the workspace once; lanes start from a recorded snapshot
38
39
  ```
39
40
 
41
+ `store commit` reads the workspace from the current directory, which is why the walk starts with `cd ~/ws`; from anywhere else, name it: `gr2 store commit -C ~/ws -m "..."`. It prints nothing on success; each repo it records for the first time gets one note on stderr.
42
+
40
43
  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:
41
44
 
42
45
  ```bash
@@ -44,24 +47,25 @@ gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
44
47
  gr2 lane enter ~/ws default feat-x --actor human:you
45
48
  ```
46
49
 
47
- Both commands print, per repo, the absolute directory you work in:
50
+ `lane create` prints the lane's record, then, per repo, the absolute directory you work in (`lane enter` prints the same directories as `repo_paths`):
48
51
 
49
52
  ```
50
- repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
51
- repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
53
+ ~/ws/.grip/state/lanes/default/feat-x/lane.toml
54
+ repo-a: ~/ws/agents/default/lanes/feat-x/repo-a
55
+ repo-b: ~/ws/agents/default/lanes/feat-x/repo-b
52
56
  ```
53
57
 
54
58
  Edit there — not in your original clones. Stage and commit across the lane's repos:
55
59
 
56
60
  ```bash
57
- gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
61
+ gr2 add . --repo-path ~/ws/agents/default/lanes/feat-x/repo-a
58
62
  gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
59
63
  ```
60
64
 
61
65
  `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:
62
66
 
63
67
  ```bash
64
- gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
68
+ gr2 exec run ~/ws default --actor human:you -- git status --short # one command, every lane repo
65
69
  gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
66
70
  gr2 lane push ~/ws default feat-x # push every lane repo, each verified on its remote
67
71
  gr2 lane show ~/ws default # where am I?
@@ -70,7 +74,7 @@ gr2 lane list ~/ws # each lane: removabl
70
74
  gr2 lane remove ~/ws default feat-x # end it: its clones and record go
71
75
  ```
72
76
 
73
- `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
77
+ `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` runs whatever follows `--` in each lane repo, with your own `PATH`: a test runner works there only if it is installed where your shell finds it. `review create-project` refuses a lane repo holding any uncommitted or untracked file, so whatever a command leaves behind (`__pycache__/` after a pytest run, say) has to be in the repo's `.gitignore`. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
74
78
 
75
79
  ## What works today, and what is not there yet
76
80
 
@@ -93,17 +97,20 @@ Not there yet:
93
97
  | `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, retire-gr1, migrate-lane-state, bootstrap-gr1, gitinclude |
94
98
  | `spec` | show, validate |
95
99
  | `lane` | create, enter, exit, show, resolve, bind, lease, list, push, remove |
96
- | (top level) | branch, add, commit, push, prune, status, plan, apply |
100
+ | (top level) | branch, add, commit, push, prune, status, plan, apply, update |
97
101
  | `sync` | status, run |
98
102
  | `pr` | create, status, checks, merge, view |
99
103
  | `check` | run, show, set |
100
- | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, repin, create-project, bind, approve, rebind |
104
+ | `proto` | json |
105
+ | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, update, repin, create-project, bind, approve, rebind |
101
106
  | `exec` | status, run |
102
107
  | `repo` | status, projection-run |
103
108
  | `hooks` | trust, revoke, status, show, run |
104
109
  | `store` | init, commit, check, push, status, log, diff, checkout, materialize, migrate, migrate-reviews |
105
110
  | `target`, `config` | stored PR target; config overlays |
106
111
 
112
+ Every `store` verb names its workspace with `-C/--root <root>`, else reads the current directory.
113
+
107
114
  `review bind`, `review approve` and `review rebind` remain as aliases of `pin`, `stamp` and `repin`.
108
115
 
109
116
  The words these commands use (lane, pin, stamp, repin, gate, review) are defined in [docs/GLOSSARY.md](docs/GLOSSARY.md).
@@ -118,6 +125,18 @@ gr2 review stamp
118
125
  gr2 review merge
119
126
  ```
120
127
 
128
+ A reviewer whose own workspace does not hold the reviewed repos (another team's
129
+ gripspace) receives the review, opens a lane, and stamps from the lane (or from one
130
+ repo directory in it). The stamp uses the store of the workspace the lane was opened
131
+ from and the repos checked out in the lane, and records the git `user.name` of that
132
+ workspace, not of the lane:
133
+
134
+ ```bash
135
+ gr2 review receive <their-workspace> gr:<id> --remote <member-remote>
136
+ gr2 review open <their-workspace> gr:<id> --lane-dir <lane>
137
+ gr2 review stamp <lane>
138
+ ```
139
+
121
140
  The author recorded by the pin, and anyone who authored a commit in its range,
122
141
  cannot stamp it. A stamp records an approval; approver names are self-declared and receipts say `signed: false`.
123
142
  Repeated stamps by the same name count once. A moved head needs a new pin
@@ -161,6 +180,18 @@ Set it with `git config user.name 'Your Name'` there if Git has no configured na
161
180
  `review show --json` and `review verify --json` include this author; older pinned reviews
162
181
  remain readable without an author field, and reading them does not invent one.
163
182
 
183
+ ## Run a review's tests
184
+
185
+ `gr2 review run` runs the reviewed tree's tests inside the review's lane, and only after it proves the lane equals the pinned tree. What to install and what to test comes from the reviewed repo itself: a tracked `.review-install` file at the repo root, read whenever the flags are left out. For a Python repo tested with pytest it needs two lines: the package the run must import from inside the lane, and an install that brings pytest:
186
+
187
+ ```
188
+ # .review-install
189
+ package = mypkg
190
+ install = {venv} -m pip install -e {lane} pytest
191
+ ```
192
+
193
+ `{venv}` is the lane venv's Python executable, not its directory, and `{lane}` is the lane's checkout of the repo; both are filled in per token. Without an `install` line the run uses `<lane venv python> -m pip install -e <lane>`, which installs your package and no test runner, so a pytest repo without the line refuses (`pytest_not_installed`). Either way the repo must be pip-installable (a `pyproject.toml` or `setup.py` declaring that package). For another language, declare the runner and its command instead, for example `runner = cargo` and `test = cargo test`. The recognised keys are `install`, `package`, `runner`, `test` and `reports`; any other key is refused (`bad_hint`). A repo with no `.review-install` must pass `--package` and/or `--install`, and with neither the run refuses (`no_package`). `gr2 review run --help` has the full list.
194
+
164
195
 
165
196
  ## Transfer a native review
166
197
 
@@ -190,6 +221,13 @@ is refused. Object downloads may remain after refusal. The owned temporary ref
190
221
  is removed separately, and cleanup failure is reported without replacing a
191
222
  primary failure.
192
223
 
224
+ Receive also fetches each member's pinned head from the remote it read the review
225
+ from, one `heads` row per member. A member whose recorded remote is another one
226
+ (a review published to a staging remote) is `not_this_remote`. `gr2 review open`
227
+ builds the lane from the range the review carries, and the row's `next` names that
228
+ command. `gr2 review show --diff` and `gr2 review stamp` still need the head: they
229
+ refuse until the author pushes it to the member's own remote and it is fetched.
230
+
193
231
  The review commit carries its trees, blobs and range patches. It does not make
194
232
  its recorded base or original member head reachable as Git parents. Keep each
195
233
  member's base reachable at its recorded remote for reconstruction. `verify`
@@ -244,8 +282,17 @@ observation retains its fields and adds a SHA-256 `observation_id`.
244
282
  A review over several members is checked as one set. `gr2 check set <workspace> <review> -- <command>`
245
283
  reconstructs every member at its pinned head side by side (`GR2_SET_ROOT`, `GR2_REVIEW_ID` and `GR2_SET_MEMBERS`
246
284
  name them), runs the command once, and publishes one `set` observation per member remote, carrying the review and the
247
- identity of the set. `gr2 review merge` requires that record on a multi-member review (`--no-set` says otherwise),
248
- and `check show --require set --review <id>` reads a `set` record for another review as stale.
285
+ identity of the set. With no `--check`, `gr2 review merge` on a multi-member review requires that record AND each
286
+ member's `test` at its head: a member whose recorded `test` is red is refused and nothing lands, and a member with no
287
+ `test` record of its own is decided by the passing set (members that import each other cannot pass a test alone), so
288
+ one `check set` and the approvals are enough to merge. `--check test` names `test` explicitly and only a `test` record
289
+ decides it (one that `check set --name test` wrote for this review counts); its refusal prints that `check set`. On a
290
+ one-member review the default `test` is also decided by a passing `set` record for this review at that head. A `set`
291
+ record for another review or other heads never counts. The requirement comes from the
292
+ review, not from the person merging: on a multi-member review `--no-set` is refused, and so is any `--check` name other
293
+ than `test` and `set`. `review pin` refuses a multi-member review whose rows do not each carry a `source` or a `range`,
294
+ because `check set` could never run on it. `check show --require set --review <id>` reads a `set` record for another
295
+ review as stale.
249
296
 
250
297
  A failed command is recorded and `check run` exits 1. Publication or execution
251
298
  refusals exit 2. `check show` returns `pass`, `fail` or `absent` in its JSON;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitgrip
3
- Version: 2.0.0a9
3
+ Version: 2.0.0a10
4
4
  Summary: Workspace layer for multi-repo work: workspaces, isolated lanes, and one grouped review per slice
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -13,6 +13,7 @@ Provides-Extra: dev
13
13
  Requires-Dist: pytest>=8.0; extra == "dev"
14
14
  Requires-Dist: ruff>=0.4; extra == "dev"
15
15
  Requires-Dist: packaging>=22; extra == "dev"
16
+ Requires-Dist: setuptools>=68.0; extra == "dev"
16
17
 
17
18
  # gr2
18
19
 
@@ -51,8 +52,11 @@ gr2 workspace init ~/ws # scans the folder; writes .grip/workspa
51
52
  gr2 workspace materialize ~/ws --yes # builds the .grip layout and a default unit
52
53
  gr2 workspace status ~/ws # what kind of workspace this is
53
54
  gr2 store init ~/ws # the workspace snapshot store (needed before review)
55
+ gr2 store commit -m "first snapshot" # record the workspace once; lanes start from a recorded snapshot
54
56
  ```
55
57
 
58
+ `store commit` reads the workspace from the current directory, which is why the walk starts with `cd ~/ws`; from anywhere else, name it: `gr2 store commit -C ~/ws -m "..."`. It prints nothing on success; each repo it records for the first time gets one note on stderr.
59
+
56
60
  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:
57
61
 
58
62
  ```bash
@@ -60,24 +64,25 @@ gr2 lane create ~/ws default feat-x --repos repo-a,repo-b --branch feat/x
60
64
  gr2 lane enter ~/ws default feat-x --actor human:you
61
65
  ```
62
66
 
63
- Both commands print, per repo, the absolute directory you work in:
67
+ `lane create` prints the lane's record, then, per repo, the absolute directory you work in (`lane enter` prints the same directories as `repo_paths`):
64
68
 
65
69
  ```
66
- repo-a: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
67
- repo-b: ~/ws/.grip/state/lanes/default/feat-x/repos/repo-b
70
+ ~/ws/.grip/state/lanes/default/feat-x/lane.toml
71
+ repo-a: ~/ws/agents/default/lanes/feat-x/repo-a
72
+ repo-b: ~/ws/agents/default/lanes/feat-x/repo-b
68
73
  ```
69
74
 
70
75
  Edit there — not in your original clones. Stage and commit across the lane's repos:
71
76
 
72
77
  ```bash
73
- gr2 add . --repo-path ~/ws/.grip/state/lanes/default/feat-x/repos/repo-a
78
+ gr2 add . --repo-path ~/ws/agents/default/lanes/feat-x/repo-a
74
79
  gr2 commit -m "my change" --workspace-root ~/ws --owner-unit default
75
80
  ```
76
81
 
77
82
  `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:
78
83
 
79
84
  ```bash
80
- gr2 exec run ~/ws default --actor human:you -- pytest -q # one command, every lane repo
85
+ gr2 exec run ~/ws default --actor human:you -- git status --short # one command, every lane repo
81
86
  gr2 review create-project ~/ws default feat-x # prints gr:<sha>: one object to review
82
87
  gr2 lane push ~/ws default feat-x # push every lane repo, each verified on its remote
83
88
  gr2 lane show ~/ws default # where am I?
@@ -86,7 +91,7 @@ gr2 lane list ~/ws # each lane: removabl
86
91
  gr2 lane remove ~/ws default feat-x # end it: its clones and record go
87
92
  ```
88
93
 
89
- `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
94
+ `lane remove` refuses while the lane is entered or leased, or was made by `lane bind`, while any of its repos holds uncommitted work, a stash, or a commit no remote has (on any branch or tag), or while its checkout holds anything that is not one of its repos; it names each one and removes nothing. `exec run` runs whatever follows `--` in each lane repo, with your own `PATH`: a test runner works there only if it is installed where your shell finds it. `review create-project` refuses a lane repo holding any uncommitted or untracked file, so whatever a command leaves behind (`__pycache__/` after a pytest run, say) has to be in the repo's `.gitignore`. `exec run` and `lane exit` require `--actor`. Every group and verb takes `--help`; `gr2 --help` lists them all.
90
95
 
91
96
  ## What works today, and what is not there yet
92
97
 
@@ -109,17 +114,20 @@ Not there yet:
109
114
  | `workspace` | init, init-from-topology, materialize, status, convert-clone, detect-gr1, migrate-gr1, retire-gr1, migrate-lane-state, bootstrap-gr1, gitinclude |
110
115
  | `spec` | show, validate |
111
116
  | `lane` | create, enter, exit, show, resolve, bind, lease, list, push, remove |
112
- | (top level) | branch, add, commit, push, prune, status, plan, apply |
117
+ | (top level) | branch, add, commit, push, prune, status, plan, apply, update |
113
118
  | `sync` | status, run |
114
119
  | `pr` | create, status, checks, merge, view |
115
120
  | `check` | run, show, set |
116
- | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, repin, create-project, bind, approve, rebind |
121
+ | `proto` | json |
122
+ | `review` | open, close, checkout-pr, run, check, pin, publish, receive, verify, show, stamp, merge, update, repin, create-project, bind, approve, rebind |
117
123
  | `exec` | status, run |
118
124
  | `repo` | status, projection-run |
119
125
  | `hooks` | trust, revoke, status, show, run |
120
126
  | `store` | init, commit, check, push, status, log, diff, checkout, materialize, migrate, migrate-reviews |
121
127
  | `target`, `config` | stored PR target; config overlays |
122
128
 
129
+ Every `store` verb names its workspace with `-C/--root <root>`, else reads the current directory.
130
+
123
131
  `review bind`, `review approve` and `review rebind` remain as aliases of `pin`, `stamp` and `repin`.
124
132
 
125
133
  The words these commands use (lane, pin, stamp, repin, gate, review) are defined in [docs/GLOSSARY.md](docs/GLOSSARY.md).
@@ -134,6 +142,18 @@ gr2 review stamp
134
142
  gr2 review merge
135
143
  ```
136
144
 
145
+ A reviewer whose own workspace does not hold the reviewed repos (another team's
146
+ gripspace) receives the review, opens a lane, and stamps from the lane (or from one
147
+ repo directory in it). The stamp uses the store of the workspace the lane was opened
148
+ from and the repos checked out in the lane, and records the git `user.name` of that
149
+ workspace, not of the lane:
150
+
151
+ ```bash
152
+ gr2 review receive <their-workspace> gr:<id> --remote <member-remote>
153
+ gr2 review open <their-workspace> gr:<id> --lane-dir <lane>
154
+ gr2 review stamp <lane>
155
+ ```
156
+
137
157
  The author recorded by the pin, and anyone who authored a commit in its range,
138
158
  cannot stamp it. A stamp records an approval; approver names are self-declared and receipts say `signed: false`.
139
159
  Repeated stamps by the same name count once. A moved head needs a new pin
@@ -177,6 +197,18 @@ Set it with `git config user.name 'Your Name'` there if Git has no configured na
177
197
  `review show --json` and `review verify --json` include this author; older pinned reviews
178
198
  remain readable without an author field, and reading them does not invent one.
179
199
 
200
+ ## Run a review's tests
201
+
202
+ `gr2 review run` runs the reviewed tree's tests inside the review's lane, and only after it proves the lane equals the pinned tree. What to install and what to test comes from the reviewed repo itself: a tracked `.review-install` file at the repo root, read whenever the flags are left out. For a Python repo tested with pytest it needs two lines: the package the run must import from inside the lane, and an install that brings pytest:
203
+
204
+ ```
205
+ # .review-install
206
+ package = mypkg
207
+ install = {venv} -m pip install -e {lane} pytest
208
+ ```
209
+
210
+ `{venv}` is the lane venv's Python executable, not its directory, and `{lane}` is the lane's checkout of the repo; both are filled in per token. Without an `install` line the run uses `<lane venv python> -m pip install -e <lane>`, which installs your package and no test runner, so a pytest repo without the line refuses (`pytest_not_installed`). Either way the repo must be pip-installable (a `pyproject.toml` or `setup.py` declaring that package). For another language, declare the runner and its command instead, for example `runner = cargo` and `test = cargo test`. The recognised keys are `install`, `package`, `runner`, `test` and `reports`; any other key is refused (`bad_hint`). A repo with no `.review-install` must pass `--package` and/or `--install`, and with neither the run refuses (`no_package`). `gr2 review run --help` has the full list.
211
+
180
212
 
181
213
  ## Transfer a native review
182
214
 
@@ -206,6 +238,13 @@ is refused. Object downloads may remain after refusal. The owned temporary ref
206
238
  is removed separately, and cleanup failure is reported without replacing a
207
239
  primary failure.
208
240
 
241
+ Receive also fetches each member's pinned head from the remote it read the review
242
+ from, one `heads` row per member. A member whose recorded remote is another one
243
+ (a review published to a staging remote) is `not_this_remote`. `gr2 review open`
244
+ builds the lane from the range the review carries, and the row's `next` names that
245
+ command. `gr2 review show --diff` and `gr2 review stamp` still need the head: they
246
+ refuse until the author pushes it to the member's own remote and it is fetched.
247
+
209
248
  The review commit carries its trees, blobs and range patches. It does not make
210
249
  its recorded base or original member head reachable as Git parents. Keep each
211
250
  member's base reachable at its recorded remote for reconstruction. `verify`
@@ -260,8 +299,17 @@ observation retains its fields and adds a SHA-256 `observation_id`.
260
299
  A review over several members is checked as one set. `gr2 check set <workspace> <review> -- <command>`
261
300
  reconstructs every member at its pinned head side by side (`GR2_SET_ROOT`, `GR2_REVIEW_ID` and `GR2_SET_MEMBERS`
262
301
  name them), runs the command once, and publishes one `set` observation per member remote, carrying the review and the
263
- identity of the set. `gr2 review merge` requires that record on a multi-member review (`--no-set` says otherwise),
264
- and `check show --require set --review <id>` reads a `set` record for another review as stale.
302
+ identity of the set. With no `--check`, `gr2 review merge` on a multi-member review requires that record AND each
303
+ member's `test` at its head: a member whose recorded `test` is red is refused and nothing lands, and a member with no
304
+ `test` record of its own is decided by the passing set (members that import each other cannot pass a test alone), so
305
+ one `check set` and the approvals are enough to merge. `--check test` names `test` explicitly and only a `test` record
306
+ decides it (one that `check set --name test` wrote for this review counts); its refusal prints that `check set`. On a
307
+ one-member review the default `test` is also decided by a passing `set` record for this review at that head. A `set`
308
+ record for another review or other heads never counts. The requirement comes from the
309
+ review, not from the person merging: on a multi-member review `--no-set` is refused, and so is any `--check` name other
310
+ than `test` and `set`. `review pin` refuses a multi-member review whose rows do not each carry a `source` or a `range`,
311
+ because `check set` could never run on it. `check show --require set --review <id>` reads a `set` record for another
312
+ review as stale.
265
313
 
266
314
  A failed command is recorded and `check run` exits 1. Publication or execution
267
315
  refusals exit 2. `check show` returns `pass`, `fail` or `absent` in its JSON;