jj-stack 0.1.4__tar.gz → 0.1.6__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 (252) hide show
  1. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/workflows/ci.yml +24 -3
  2. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/workflows/release.yml +3 -3
  3. {jj_stack-0.1.4 → jj_stack-0.1.6}/CONTRIBUTING.md +11 -9
  4. {jj_stack-0.1.4 → jj_stack-0.1.6}/PKG-INFO +6 -5
  5. {jj_stack-0.1.4 → jj_stack-0.1.6}/README.md +5 -4
  6. {jj_stack-0.1.4 → jj_stack-0.1.6}/check.py +2 -2
  7. {jj_stack-0.1.4 → jj_stack-0.1.6}/complexity-budget.toml +2 -2
  8. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/close-or-separate.md +4 -3
  9. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/merge-and-sync.md +42 -21
  10. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/review-a-stack.md +6 -5
  11. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/submit-and-update.md +4 -3
  12. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/working-on-github.md +4 -0
  13. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/README.md +2 -0
  14. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/design.md +66 -34
  15. jj_stack-0.1.6/docs/internals/property-testing.md +35 -0
  16. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/releasing.md +4 -4
  17. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/testing-philosophy.md +2 -1
  18. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/json-output.schema.json +185 -1
  19. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/mental-model.md +7 -11
  20. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/quick-start.md +7 -10
  21. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/automation.md +6 -0
  22. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/bookmarks-and-selection.md +4 -4
  23. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/configuration.md +10 -4
  24. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/json-output.md +74 -5
  25. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/tool-comparison.md +8 -8
  26. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/troubleshooting.md +36 -28
  27. {jj_stack-0.1.4 → jj_stack-0.1.6}/justfile +1 -0
  28. {jj_stack-0.1.4 → jj_stack-0.1.6}/pyproject.toml +3 -9
  29. jj_stack-0.1.6/release-notes/v0.1.5.md +28 -0
  30. jj_stack-0.1.6/release-notes/v0.1.6.md +14 -0
  31. {jj_stack-0.1.4 → jj_stack-0.1.6}/scripts/describe_with_claude.py +0 -2
  32. {jj_stack-0.1.4 → jj_stack-0.1.6}/scripts/describe_with_codex.py +0 -2
  33. {jj_stack-0.1.4 → jj_stack-0.1.6}/scripts/describe_with_editor.py +0 -8
  34. {jj_stack-0.1.4 → jj_stack-0.1.6}/scripts/describe_with_prompt.py +0 -2
  35. {jj_stack-0.1.4 → jj_stack-0.1.6}/skills/jj-stack/SKILL.md +9 -6
  36. {jj_stack-0.1.4 → jj_stack-0.1.6}/skills/jj-stack/references/recovery.md +25 -12
  37. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/bootstrap.py +11 -6
  38. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/cli.py +127 -161
  39. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/cli_help.py +6 -7
  40. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/_json_status.py +11 -11
  41. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/checkout.py +15 -25
  42. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/cleanup/actions.py +17 -37
  43. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/cleanup/command.py +81 -48
  44. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/doctor.py +5 -7
  45. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/list_.py +32 -56
  46. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/merge/command.py +132 -86
  47. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/merge/github_stack.py +107 -119
  48. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/merge/plan.py +16 -37
  49. jj_stack-0.1.6/src/jj_stack/commands/merge/wait.py +202 -0
  50. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/relink.py +7 -8
  51. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/auto_close.py +1 -18
  52. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/changes.py +74 -23
  53. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/command.py +329 -232
  54. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/descriptions.py +9 -8
  55. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/editor.py +35 -38
  56. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/github_stack.py +8 -8
  57. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/inputs.py +4 -10
  58. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/models.py +1 -11
  59. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/prs.py +3 -5
  60. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/publication.py +2 -3
  61. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/sync.py +93 -21
  62. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/sync_apply.py +14 -18
  63. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/sync_prs.py +1 -1
  64. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/unstack.py +18 -31
  65. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/view.py +41 -51
  66. jj_stack-0.1.6/src/jj_stack/commands/view_details.py +85 -0
  67. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/completion.py +17 -38
  68. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/config.py +12 -31
  69. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/console.py +134 -120
  70. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/errors.py +1 -7
  71. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/formatting.py +2 -20
  72. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/auth.py +9 -6
  73. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/client.py +399 -159
  74. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/error_messages.py +8 -53
  75. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/identifiers.py +15 -0
  76. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/jj/client.py +134 -63
  77. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/jj/settings.py +12 -8
  78. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/models/github.py +21 -3
  79. jj_stack-0.1.6/src/jj_stack/models/github_details.py +97 -0
  80. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/models/tracking.py +1 -9
  81. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/change_state.py +49 -60
  82. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/convergence.py +86 -61
  83. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/convergence_models.py +2 -4
  84. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/github_stack_safety.py +19 -1
  85. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/global_convergence.py +35 -32
  86. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/pr_branches.py +5 -4
  87. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/pr_facts.py +13 -34
  88. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/repo.py +14 -6
  89. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/reporting.py +36 -0
  90. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/selected.py +13 -12
  91. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/selection.py +5 -3
  92. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/status.py +46 -9
  93. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/state/migrations.py +2 -1
  94. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/state/operation_lock.py +6 -11
  95. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/state/store.py +26 -40
  96. jj_stack-0.1.6/src/jj_stack/timing.py +63 -0
  97. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/ui.py +5 -24
  98. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/conftest.py +2 -2
  99. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_checkout_command.py +20 -30
  100. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_cleanup_command.py +0 -52
  101. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_jj_stack.py +20 -24
  102. jj_stack-0.1.6/tests/integration/test_jsonl_output.py +38 -0
  103. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_list_command.py +100 -46
  104. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_merge_command.py +190 -53
  105. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_submit_command.py +157 -21
  106. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_sync_command.py +160 -8
  107. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_unstack_command.py +1 -1
  108. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_view_command.py +85 -3
  109. jj_stack-0.1.6/tests/property/test_submit_property_scenarios.py +152 -0
  110. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/run_submit_property_scenarios.py +42 -20
  111. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/fake_github.py +475 -161
  112. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/integration_helpers.py +6 -18
  113. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/json_schema.py +21 -9
  114. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/output_assertions.py +0 -10
  115. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/pytest_concurrency.py +1 -14
  116. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/stack_edit_scenarios.py +0 -2
  117. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/stack_machine.py +317 -102
  118. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/submit_faults.py +12 -1
  119. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_change_state.py +2 -2
  120. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_cli.py +3 -18
  121. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_cli_dispatch.py +48 -1
  122. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_completion.py +1 -16
  123. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_describe_with_prompt_script.py +0 -20
  124. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_errors.py +0 -14
  125. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_client.py +213 -65
  126. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_models.py +3 -17
  127. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_resolution.py +2 -14
  128. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_stack_planning.py +0 -27
  129. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_jj_client.py +17 -94
  130. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_merge.py +0 -55
  131. jj_stack-0.1.6/tests/unit/test_merge_wait.py +101 -0
  132. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_operation_lock.py +0 -21
  133. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_pr_branches.py +9 -20
  134. jj_stack-0.1.6/tests/unit/test_pr_refs.py +34 -0
  135. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_property_runner.py +20 -0
  136. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_relink.py +10 -8
  137. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_stack_path.py +0 -8
  138. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_submit.py +7 -9
  139. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_submit_descriptions.py +21 -0
  140. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_submit_editor.py +3 -45
  141. jj_stack-0.1.6/tests/unit/test_timing.py +27 -0
  142. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_ui.py +26 -15
  143. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_view.py +73 -8
  144. {jj_stack-0.1.4 → jj_stack-0.1.6}/tools/check_jj_release_updates.py +6 -10
  145. jj_stack-0.1.6/uv.lock +740 -0
  146. jj_stack-0.1.4/docs/internals/property-testing.md +0 -14
  147. jj_stack-0.1.4/tests/property/test_submit_property_scenarios.py +0 -105
  148. jj_stack-0.1.4/tests/unit/test_cleanup.py +0 -20
  149. jj_stack-0.1.4/tests/unit/test_divergence.py +0 -15
  150. jj_stack-0.1.4/tests/unit/test_pr_refs.py +0 -51
  151. jj_stack-0.1.4/uv.lock +0 -915
  152. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  153. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  154. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  155. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/SECURITY.md +0 -0
  156. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/dependabot.yml +0 -0
  157. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/pull_request_template.md +0 -0
  158. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/workflows/block-pr-base-merges.yml +0 -0
  159. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/workflows/check-jj-release-updates.yml +0 -0
  160. {jj_stack-0.1.4 → jj_stack-0.1.6}/.github/workflows/codeql.yml +0 -0
  161. {jj_stack-0.1.4 → jj_stack-0.1.6}/.gitignore +0 -0
  162. {jj_stack-0.1.4 → jj_stack-0.1.6}/AGENTS.md +0 -0
  163. {jj_stack-0.1.4 → jj_stack-0.1.6}/CLAUDE.md +0 -0
  164. {jj_stack-0.1.4 → jj_stack-0.1.6}/LICENSE +0 -0
  165. {jj_stack-0.1.4 → jj_stack-0.1.6}/NOTICE +0 -0
  166. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/AGENTS.md +0 -0
  167. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/README.md +0 -0
  168. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/continue-a-stack.md +0 -0
  169. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/multiple-stacks.md +0 -0
  170. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/guides/revise.md +0 -0
  171. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/AGENTS.md +0 -0
  172. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/internals/code-reviews.md +0 -0
  173. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/commands.md +0 -0
  174. {jj_stack-0.1.4 → jj_stack-0.1.6}/docs/reference/descriptions.md +0 -0
  175. {jj_stack-0.1.4 → jj_stack-0.1.6}/evals/jj-stack-skill.md +0 -0
  176. {jj_stack-0.1.4 → jj_stack-0.1.6}/release-notes/v0.1.2.md +0 -0
  177. {jj_stack-0.1.4 → jj_stack-0.1.6}/release-notes/v0.1.3.md +0 -0
  178. {jj_stack-0.1.4 → jj_stack-0.1.6}/release-notes/v0.1.4.md +0 -0
  179. {jj_stack-0.1.4 → jj_stack-0.1.6}/scripts/README.md +0 -0
  180. {jj_stack-0.1.4 → jj_stack-0.1.6}/skills/jj-stack/agents/openai.yaml +0 -0
  181. {jj_stack-0.1.4 → jj_stack-0.1.6}/skills/jj-stack/references/multi-stack.md +0 -0
  182. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/__init__.py +0 -0
  183. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/__main__.py +0 -0
  184. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/__init__.py +0 -0
  185. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/in_use.py +0 -0
  186. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/merge/__init__.py +0 -0
  187. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/__init__.py +0 -0
  188. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/default_pr_text.py +0 -0
  189. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/managed_comments.py +0 -0
  190. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/overview_comments.py +0 -0
  191. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/render.py +0 -0
  192. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/commands/submit/revision_comments.py +0 -0
  193. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/concurrency.py +0 -0
  194. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/__init__.py +0 -0
  195. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/overview_comments.py +0 -0
  196. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/pr_refs.py +0 -0
  197. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/resolution.py +0 -0
  198. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/github/stack_availability.py +0 -0
  199. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/jj/__init__.py +0 -0
  200. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/jj/cli_args.py +0 -0
  201. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/jj/colors.py +0 -0
  202. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/models/__init__.py +0 -0
  203. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/models/git.py +0 -0
  204. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/models/stack.py +0 -0
  205. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/pr_branch_namespace.py +0 -0
  206. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/__init__.py +0 -0
  207. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/convergence_observation.py +0 -0
  208. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/divergence.py +0 -0
  209. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/observation.py +0 -0
  210. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/path.py +0 -0
  211. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/preparation.py +0 -0
  212. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/trunk.py +0 -0
  213. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/stack/trunk_evidence.py +0 -0
  214. {jj_stack-0.1.4 → jj_stack-0.1.6}/src/jj_stack/state/__init__.py +0 -0
  215. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/__init__.py +0 -0
  216. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/__init__.py +0 -0
  217. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/conftest.py +0 -0
  218. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/submit_command_helpers.py +0 -0
  219. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_boundary_conditions.py +0 -0
  220. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_doctor_command.py +0 -0
  221. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_fake_github_contracts.py +0 -0
  222. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/integration/test_relink_command.py +0 -0
  223. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/run_live_github.py +0 -0
  224. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/__init__.py +0 -0
  225. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/change_helpers.py +0 -0
  226. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/contexts.py +0 -0
  227. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/support/tracking.py +0 -0
  228. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/__init__.py +0 -0
  229. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_bootstrap.py +0 -0
  230. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_check_script.py +0 -0
  231. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_checkout.py +0 -0
  232. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_concurrency.py +0 -0
  233. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_config.py +0 -0
  234. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_default_pr_text.py +0 -0
  235. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_describe_with_editor_script.py +0 -0
  236. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_auth.py +0 -0
  237. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_github_error_messages.py +0 -0
  238. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_in_use_command.py +0 -0
  239. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_jj_settings.py +0 -0
  240. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_live_github_runner.py +0 -0
  241. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_pr_facts.py +0 -0
  242. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_property_scenarios.py +0 -0
  243. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_selected.py +0 -0
  244. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_stack_status.py +0 -0
  245. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_store.py +0 -0
  246. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_sync.py +0 -0
  247. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_trunk_evidence.py +0 -0
  248. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_unstack.py +0 -0
  249. {jj_stack-0.1.4 → jj_stack-0.1.6}/tests/unit/test_view_entrypoint.py +0 -0
  250. {jj_stack-0.1.4 → jj_stack-0.1.6}/tools/check_complexity.py +0 -0
  251. {jj_stack-0.1.4 → jj_stack-0.1.6}/tools/check_release_artifacts.py +0 -0
  252. {jj_stack-0.1.4 → jj_stack-0.1.6}/tools/install-jj-release.sh +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
19
 
20
20
  - name: Set up uv
21
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
21
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
22
22
  with:
23
23
  python-version: "3.14"
24
24
 
@@ -52,7 +52,7 @@ jobs:
52
52
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
53
53
 
54
54
  - name: Set up uv
55
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
55
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
56
56
  with:
57
57
  python-version: ${{ matrix.python-version }}
58
58
 
@@ -65,6 +65,27 @@ jobs:
65
65
  fi
66
66
  printf '%s\n' "$install_dir" >> "$GITHUB_PATH"
67
67
 
68
+ - name: Install current Git
69
+ if: runner.os == 'macOS'
70
+ # The runner image's formula list can predate the current Git release.
71
+ run: |
72
+ brew update
73
+ brew install git
74
+
75
+ - name: Check Git version
76
+ shell: bash
77
+ run: |
78
+ git --version
79
+ # Git 2.56 changed which refs a push by URL updates. Other runners keep their own
80
+ # Git so older versions stay covered, but this one must run the newer behavior.
81
+ if [[ "$RUNNER_OS" == macOS ]]; then
82
+ IFS=. read -r major minor _ <<< "$(git --version | awk '{print $3}')"
83
+ if (( major < 2 || (major == 2 && minor < 56) )); then
84
+ echo "::error::The macOS job needs Git 2.56 or newer; found $(git --version)."
85
+ exit 1
86
+ fi
87
+ fi
88
+
68
89
  - name: Run local verification suite
69
90
  shell: bash
70
91
  run: ./check.py
@@ -79,7 +100,7 @@ jobs:
79
100
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
80
101
 
81
102
  - name: Set up uv
82
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
103
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
83
104
  with:
84
105
  python-version: "3.14"
85
106
 
@@ -34,7 +34,7 @@ jobs:
34
34
  ref: ${{ inputs.release_tag || github.ref }}
35
35
 
36
36
  - name: Set up uv
37
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
37
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
38
38
  with:
39
39
  python-version: "3.14"
40
40
 
@@ -94,7 +94,7 @@ jobs:
94
94
 
95
95
  steps:
96
96
  - name: Set up uv
97
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
97
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
98
98
  with:
99
99
  python-version: "3.14"
100
100
 
@@ -127,7 +127,7 @@ jobs:
127
127
 
128
128
  steps:
129
129
  - name: Set up uv
130
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
130
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
131
131
  with:
132
132
  python-version: "3.14"
133
133
 
@@ -39,20 +39,22 @@ just check
39
39
  ```
40
40
 
41
41
  Pyrefly is the default type checker, including a second pass targeting Windows. To select ty
42
- or mypy for the current platform instead, use `--type-checker` or its short form, `-t`:
42
+ for the current platform instead, use `--type-checker` or its short form, `-t`:
43
43
 
44
44
  ```console
45
45
  just check -t ty
46
- just check -t mypy
47
46
  ```
48
47
 
49
- Repeat the option to run several in the given order, for example
50
- `just check -t pyrefly -t ty -t mypy`. The runner installs the selected checkers from the lockfile,
51
- checks `src`, `tests`, `tools`, and `check.py`, and runs the usual Ruff and pytest checks. It stops
52
- at the first failed check. ty and mypy are optional during development and can report issues
53
- that Pyrefly does not; their failures are reported normally. Plain `just check` and CI continue
54
- to use Pyrefly. Before a release, follow the
55
- [requirement for all three type checkers to pass](docs/internals/releasing.md#qualify-the-candidate).
48
+ Repeat the option to run several in the given order, for example `just check -t pyrefly -t ty`.
49
+ The runner installs the selected checkers from the lockfile, checks `src`, `tests`, `tools`, and
50
+ `check.py`, and runs the usual Ruff and pytest checks. It stops at the first failed check. ty is
51
+ optional during development and can report issues that Pyrefly does not; its failures are
52
+ reported normally. Plain `just check` and CI continue to use Pyrefly. Before a release, follow the
53
+ [requirement for both type checkers to pass](docs/internals/releasing.md#qualify-the-candidate).
54
+
55
+ mypy is deliberately not part of the toolchain. It fixes a variable's type at its first
56
+ assignment and rejects a later assignment of another type, which Pyrefly and ty accept, so
57
+ keeping it green required annotations whose only purpose was to satisfy mypy.
56
58
 
57
59
  Run focused tests while you iterate:
58
60
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: jj-stack
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Stacked GitHub pull requests for Jujutsu
5
5
  Project-URL: Homepage, https://www.serpentine.com/software/jj-stack/
6
6
  Project-URL: Documentation, https://www.serpentine.com/software/jj-stack/
@@ -99,10 +99,11 @@ your edit.
99
99
  2. Run `jj-stack submit`.
100
100
  3. Revise, add, remove, or reorder the changes locally as reviews come in.
101
101
  4. Run `jj-stack submit` again to refresh GitHub.
102
- 5. Run `jj-stack merge --pull-request <last-pr-to-merge> --method squash` when the bottom
103
- portion is ready. Choose a merge method your repo allows. Queues choose their own method.
104
- 6. After a queued merge or a merge made through GitHub finishes, run
105
- `jj-stack sync <head-change-id>`.
102
+ 5. Run `jj-stack merge` when the PRs at the bottom are ready. Pass `--pull-request <pr>` to
103
+ stop at an earlier PR, and `--method` to choose a merge method your repo allows. The command
104
+ waits for GitHub, including its merge queue, then updates your local stack and remaining PRs.
105
+ 6. If you used `--no-wait`, interrupted the wait, or merged through GitHub, run
106
+ `jj-stack sync <head-change-id>` after GitHub finishes.
106
107
 
107
108
  `view`, `submit`, `merge`, and `sync` accept a change ID when you need to select a stack other
108
109
  than the one ending at the working copy.
@@ -71,10 +71,11 @@ your edit.
71
71
  2. Run `jj-stack submit`.
72
72
  3. Revise, add, remove, or reorder the changes locally as reviews come in.
73
73
  4. Run `jj-stack submit` again to refresh GitHub.
74
- 5. Run `jj-stack merge --pull-request <last-pr-to-merge> --method squash` when the bottom
75
- portion is ready. Choose a merge method your repo allows. Queues choose their own method.
76
- 6. After a queued merge or a merge made through GitHub finishes, run
77
- `jj-stack sync <head-change-id>`.
74
+ 5. Run `jj-stack merge` when the PRs at the bottom are ready. Pass `--pull-request <pr>` to
75
+ stop at an earlier PR, and `--method` to choose a merge method your repo allows. The command
76
+ waits for GitHub, including its merge queue, then updates your local stack and remaining PRs.
77
+ 6. If you used `--no-wait`, interrupted the wait, or merged through GitHub, run
78
+ `jj-stack sync <head-change-id>` after GitHub finishes.
78
79
 
79
80
  `view`, `submit`, `merge`, and `sync` accept a change ID when you need to select a stack other
80
81
  than the one ending at the working copy.
@@ -20,7 +20,7 @@ VENV_PYTHON = (
20
20
  )
21
21
  PytestJobs = int | Literal["auto"]
22
22
  _TYPE_CHECK_TARGETS = ("src", "tests", "tools", "check.py")
23
- _TYPE_CHECKERS = ("pyrefly", "ty", "mypy")
23
+ _TYPE_CHECKERS = ("pyrefly", "ty")
24
24
  _FRAGILE_TEST_OUTPUT_PATTERNS: tuple[tuple[str, re.Pattern[str]], ...] = (
25
25
  (
26
26
  "use output assertion helpers instead of exact captured output equality",
@@ -79,7 +79,7 @@ def _build_checks(
79
79
  )
80
80
  type_checks: list[tuple[str, tuple[str, ...]]] = []
81
81
  for checker in type_checkers:
82
- command = ("-m", checker) if checker == "mypy" else ("-m", checker, "check")
82
+ command = ("-m", checker, "check")
83
83
  type_checks.append((checker, (*command, *_TYPE_CHECK_TARGETS)))
84
84
  if checker == "pyrefly":
85
85
  type_checks.append(
@@ -12,8 +12,8 @@ c901 = 16
12
12
  governed_c901 = 0
13
13
 
14
14
  [pytest]
15
- fixed_property = 9
16
- merge_recovery = 60
15
+ fixed_property = 11
16
+ merge_recovery = 67
17
17
 
18
18
  [labels]
19
19
  production = "Production"
@@ -57,9 +57,10 @@ jj-stack cleanup <head-change-id>
57
57
 
58
58
  ### If cleanup keeps a branch
59
59
 
60
- Cleanup keeps a PR branch while another open or reopenable closed PR uses it as its base. The
61
- message names the dependent PR. Retarget an open PR to trunk. For a closed PR, either reopen and
62
- retarget it or delete its head branch if you no longer need to reopen it. Then rerun cleanup.
60
+ Cleanup keeps a PR branch while another PR still uses it as its base: an open PR, or a closed PR
61
+ that GitHub could still reopen. The message names that PR. Retarget an open PR to trunk. For a
62
+ closed PR, either reopen and retarget it, or delete its head branch if you no longer need to
63
+ reopen it. Then rerun cleanup.
63
64
 
64
65
  A branch also stays while an unmerged PR in a GitHub stack needs it. Remove that stack with
65
66
  `jj-stack unstack` before retrying cleanup.
@@ -11,8 +11,8 @@ stack. Once the PRs have merged, `jj-stack sync` updates your local stack and an
11
11
  pull requests.
12
12
 
13
13
  GitHub can perform the merge immediately or put it through a merge queue. An immediate merge
14
- is called a **direct merge**, and `jj-stack merge` runs the sync automatically in this case.
15
- For a queued merge, you run `sync` yourself after GitHub finishes.
14
+ is called a **direct merge**. In both cases, `jj-stack merge` waits for completion and runs
15
+ the sync automatically.
16
16
 
17
17
  ## Before merging
18
18
 
@@ -28,11 +28,22 @@ jj-stack merge <head-change-id>
28
28
  that their PR branches and pull requests have not moved unexpectedly. GitHub decides whether
29
29
  checks, approvals, conflicts, and repo rules allow the merge.
30
30
 
31
+ `jj-stack list` and `jj-stack view` show review decisions, checks, and specific merge warnings.
32
+ `needs review` means GitHub still requires a review.
33
+
34
+ To inspect unresolved review threads and failed or pending checks, including links, run:
35
+
36
+ ```console
37
+ jj-stack view --verbose <head-change-id>
38
+ ```
39
+
40
+ Verbose output includes thread excerpts, even for outdated threads.
41
+
31
42
  ## Choose a merge method
32
43
 
33
- Direct merges happen immediately on GitHub. If your repo allows only one merge method, `merge`
34
- uses it automatically. With several allowed methods and an unsigned stack, it prefers rebase,
35
- then squash, then a merge commit. Choose an allowed method with `--method`, or set a default once:
44
+ For a direct merge, `merge` uses your repo's only allowed merge method if there is just one.
45
+ With several allowed methods and an unsigned stack, it prefers rebase, then squash, then a merge
46
+ commit. Choose an allowed method with `--method`, or set a default once:
36
47
 
37
48
  ```console
38
49
  jj config set --repo jj-stack.merge_method squash
@@ -64,7 +75,7 @@ For example, in A → B → C, suppose the PRs are #1, #2, and #3. To merge only
64
75
  jj-stack merge --pull-request 1 --method squash
65
76
  ```
66
77
 
67
- After a direct merge, PR #1 is merged, PR #2 targets `main`, and PR #3 still targets PR #2's
78
+ After the command finishes, PR #1 is merged, PR #2 targets `main`, and PR #3 still targets PR #2's
68
79
  branch. Both remaining PRs keep their numbers and discussions:
69
80
 
70
81
  ```mermaid
@@ -83,7 +94,8 @@ proceed because all three PRs belong to the same GitHub stack.
83
94
 
84
95
  After GitHub merges some or all of your pull requests, `sync` fetches the updated trunk and
85
96
  rebases your remaining changes onto it. It removes any obsolete local copies of the merged
86
- changes, updates the remaining PRs, and deletes PR branches that are no longer needed.
97
+ changes, updates the remaining PRs, and deletes PR branches that are no longer needed. If your
98
+ working copy is on a merged change, `sync` first moves it to a new empty change on trunk.
87
99
 
88
100
  Select the stack by its head change ID or by any linked pull request:
89
101
 
@@ -95,8 +107,8 @@ jj-stack sync --pull-request <pr>
95
107
  `sync --pull-request` updates the complete local stack containing the named PR, including
96
108
  changes above it. The selected PR can already be merged.
97
109
 
98
- For a PR outside a GitHub stack, `sync` can also close the PR and clean up after its submitted
99
- commit reaches trunk through an external fast-forward push.
110
+ If someone pushes a PR's submitted commit straight to trunk instead of merging the PR, `sync`
111
+ closes that PR and cleans up, provided the PR is not part of a GitHub stack.
100
112
 
101
113
  If no PR has merged, no submitted commit has reached trunk, and GitHub has not rebased the stack,
102
114
  `sync` leaves the pull requests unchanged. Run `jj-stack submit` explicitly when you want to
@@ -107,19 +119,25 @@ changes may still depend on the original local changes. `sync` rebases that work
107
119
  squashed result and removes the old copies. Other merge methods also need `sync` to update
108
120
  the remaining PRs and remove unused branches.
109
121
 
110
- ### Direct merges
122
+ ### Merge queues
111
123
 
112
- For a direct merge, `merge` waits for GitHub to finish and runs `sync` before it returns.
113
- Your local stack and remaining PRs are then ready for you to keep working.
124
+ GitHub tests each queued PR on a temporary merge commit that combines it with the PRs ahead of
125
+ it, so those checks appear on that commit rather than on the PR's own Checks tab. While waiting,
126
+ `merge` shows each PR's queue position and the state of those checks.
114
127
 
115
- ### Merge queues
128
+ If GitHub removes a PR from the queue, `merge` stops, reports GitHub's reason, links to the
129
+ checks on that commit, and names the next step. See [queue removal recovery][queue-removal].
116
130
 
117
- When a merge queue is in use, `merge` returns once GitHub accepts the PRs into the queue.
118
- They may still be waiting to merge at that point. Wait until GitHub reports that the merge
119
- has finished, then run `sync` for that stack.
131
+ [queue-removal]: ../troubleshooting.md#a-stack-was-removed-from-the-merge-queue
120
132
 
121
133
  While any selected pull request is queued, `jj-stack submit` refuses to update the stack and
122
- `jj-stack sync` leaves it unchanged.
134
+ `jj-stack sync` leaves it unchanged; rerun `jj-stack merge` to resume waiting.
135
+
136
+ ### Leaving before GitHub finishes
137
+
138
+ Use `--no-wait` to return as soon as GitHub accepts the request, or press Ctrl-C to stop
139
+ waiting. Neither cancels the request. Rerun the same `jj-stack merge` to keep watching it, or run
140
+ `jj-stack sync <head-change-id>` once GitHub finishes.
123
141
 
124
142
  ### Merges outside jj-stack
125
143
 
@@ -163,19 +181,22 @@ jj-stack sync <head-change-id>
163
181
  ```
164
182
 
165
183
  If only cleanup failed, run the `jj-stack cleanup --pull-request <pr>` commands in the hint.
166
- The local changes may already be gone, so their former head cannot select the remaining cleanup.
184
+ The hint names each PR because the merged local changes may already be gone.
167
185
 
168
186
  Your pull requests are already merged, so do not retry `jj-stack merge`.
169
187
 
170
188
  ## When trunk moves without one of your pull requests merging
171
189
 
172
- `sync` handles completed GitHub merges and stack rebases. If trunk merely advanced, fetch it,
173
- rebase your changes with `jj` if needed, then submit the rewritten changes:
190
+ `jj-stack sync` handles completed GitHub merges and stack rebases. If trunk merely advanced,
191
+ fetch it, rebase your changes with `jj` if needed, then submit the rewritten changes:
174
192
 
175
193
  ```console
176
194
  jj git fetch
177
- jj rebase -s '<bottom-change-id>' -o 'trunk()'
195
+ jj rebase -b '<change-id>' -o 'trunk()'
178
196
  jj-stack submit <head-change-id>
179
197
  ```
180
198
 
199
+ Use any change in the stack with `-b`; jj finds its base and moves the whole stack, including
200
+ forks. You can even omit `-b` to use jj's default of `@`.
201
+
181
202
  Rebase when your work needs the latest trunk or GitHub requires it before merging.
@@ -29,7 +29,7 @@ version appears first and is marked **current**. Use **Changes from previous ver
29
29
  what changed in that update. Use **Submitted commit** to inspect the exact commit published for
30
30
  that version.
31
31
 
32
- The comment lists recent available versions. If you missed several updates, follow their diff
32
+ The comment lists the most recent versions. If you missed several updates, follow their diff
33
33
  links in order; use the PR's **Files changed** tab to review the current layer as a whole.
34
34
 
35
35
  ## Review and merge in order
@@ -58,10 +58,11 @@ each PR.
58
58
 
59
59
  ## Merge queues
60
60
 
61
- GitHub adds a stack's pull requests to the queue in dependency order. Removing or ejecting a PR
62
- also removes every PR above it. Resolve the cause, then add the stack to the queue again. Wait
63
- until the merge completes before running `jj-stack sync`. See GitHub's
64
- [merge queue guidance][github-queue].
61
+ GitHub adds a stack's pull requests to the queue in dependency order. If GitHub removes a PR, it
62
+ also removes every PR above it; `jj-stack merge` stops, reports the reason, and names the next
63
+ step. Fix the cause and rerun the same `jj-stack merge` command. See
64
+ [queue removal recovery](../troubleshooting.md#a-stack-was-removed-from-the-merge-queue) and
65
+ GitHub's [merge queue guidance][github-queue].
65
66
 
66
67
  [github-review]: https://docs.github.com/en/pull-requests/how-tos/review-pull-requests/reviewing-stacked-pull-requests
67
68
  [github-merge]: https://docs.github.com/en/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests
@@ -87,10 +87,11 @@ look again:
87
87
  jj-stack submit --re-request
88
88
  ```
89
89
 
90
- ## PR history
90
+ ## Revision history
91
91
 
92
- After updates, jj-stack maintains a comment on each PR listing its recent versions with links
93
- to the diffs. Reviewers can use it to see what changed since their last review.
92
+ After updates, jj-stack maintains a **Revision history** comment on each PR. It lists the PR's
93
+ recent versions with links to the diff between each version and the next, so reviewers can see
94
+ what changed since their last review.
94
95
 
95
96
  For edits made directly on GitHub, see [work with a stack on GitHub](working-on-github.md).
96
97
  If you move changes between stacks, follow
@@ -52,5 +52,9 @@ both from the local `jj` history. To change the base or order, make that change
52
52
  submit again. To remove the GitHub stack while leaving the PRs open, see
53
53
  [separate a stack](close-or-separate.md#remove-a-github-stack).
54
54
 
55
+ Do not enable auto-merge, shown as **Merge when ready** with a merge queue, on a pull request
56
+ you will stack more changes on. GitHub refuses to add such a PR to a stack, so the next submit
57
+ stops until you disable it.
58
+
55
59
  For reviewer and repo configuration guidance, see
56
60
  [review and merge a stack on GitHub](review-a-stack.md).
@@ -43,3 +43,5 @@ describe current behavior and rationale; commit history records how the design c
43
43
  - [jj/client.py](../../src/jj_stack/jj/client.py) provides jj queries and mutations;
44
44
  [github/client.py](../../src/jj_stack/github/client.py) handles GitHub requests.
45
45
  [state/store.py](../../src/jj_stack/state/store.py) reads and writes tracking data.
46
+ - [timing.py](../../src/jj_stack/timing.py) records the per-call durations that `--time-output`
47
+ reports. Start a performance investigation by running the slow command with that flag.
@@ -128,7 +128,9 @@ rewrite is not mistaken for a local copy. Two untracked remote bookmarks pointin
128
128
  commit prevent this exception, even if both are in the reserved namespace. Trunk, tags, and
129
129
  bookmarks outside the namespace still make their targets immutable. If the submitted commit and
130
130
  one local rewrite are both visible, the submitted commit is treated as the submitted snapshot
131
- rather than a second local candidate.
131
+ rather than a second local candidate. Rewrites that a command has already planned run with jj's
132
+ immutability check disabled: an immutability revset that names a namespace bookmark would
133
+ resurrect the hidden commit it points at when jj rewrites that commit's ancestor.
132
134
 
133
135
  An unknown or mismatched bookmark creates no ownership. It remains untouched and does not block an
134
136
  independent stack. `submit` refuses to claim a colliding visible name for a new PR, while remote
@@ -175,7 +177,7 @@ through a merge queue.
175
177
  | `submit` | Create PRs and refresh the selected stack; only this command publishes new changes. |
176
178
  | `sync` | Update a local stack after a merge or native GitHub stack rebase. |
177
179
  | `sync --all` | Sync stacks after merges and finish eligible PRs without local copies. |
178
- | `merge` | Request a GitHub merge; run sync after a direct merge completes. |
180
+ | `merge` | Request a GitHub merge; wait for completion and run sync unless `--no-wait` is used. |
179
181
  | `unstack` | Remove a GitHub stack; `--local` instead forgets local tracking. |
180
182
  | `cleanup` | Remove eligible artifacts and links; optionally close explicitly selected PRs. |
181
183
  | `checkout` | Adopt existing PRs and edit the selected change in the current workspace. |
@@ -186,7 +188,7 @@ through a merge queue.
186
188
 
187
189
  `jj` owns general history editing. There is no standalone `jj-stack rebase` command.
188
190
 
189
- `sync` and `merge` fetch before planning, including during `--dry-run`. A direct merge fetches
191
+ `sync` and `merge` fetch before planning, including during `--dry-run`. A merge that waits fetches
190
192
  again after GitHub completes it. `checkout --pull-request` fetches when the selected PR's head
191
193
  commit is not already local. Other commands do not fetch. Commands evaluate `trunk()` after any
192
194
  fetch they perform; without a fetch, they use the locally available trunk.
@@ -245,10 +247,11 @@ removed, so `in-use` continues to report adoption. `view`, `list`, and `in-use`
245
247
  An unreadable or invalid file blocks commands that load it and names the path to move aside before
246
248
  using `checkout` or `relink` to restore links. A newer unsupported schema requires an upgrade.
247
249
 
248
- Mutating commands serialize per repo. An interruption can leave completed external effects even
249
- if the command reports failure. A retry computes what remains from current observations; it never
250
- replays a saved plan or selector. The submitted baseline records an acknowledged commit, not
251
- pending work.
250
+ Mutating commands serialize per repo while they observe and mutate. A command that waits for
251
+ GitHub, an editor, or a describe helper releases that serialization while it waits and observes
252
+ again before it mutates. An interruption can leave completed external effects even if the command
253
+ reports failure. A retry computes what remains from current observations; it never replays a
254
+ saved plan or selector. The submitted baseline records an acknowledged commit, not pending work.
252
255
 
253
256
  ## Policies
254
257
 
@@ -368,15 +371,27 @@ queue object or a `MERGE_QUEUE` branch rule. If that lookup fails, `merge` stops
368
371
  error before requesting anything. It sends the explicit action `merge_queue` when a queue is
369
372
  found and `direct_merge` otherwise.
370
373
 
371
- A `merged` result means a direct merge completed; `merge` then fetches and syncs the whole
372
- selected stack before returning, including changes above the last merged PR and commits GitHub
373
- rewrote. An `enqueued` result means GitHub accepted the selected PRs into the queue. The command
374
- succeeds, but the user must wait for the queued merge to finish before running `sync`. A rejection
375
- leaves local changes unchanged.
374
+ `merge` waits for completion by default, then fetches and syncs the whole selected stack before
375
+ returning, including changes above the last merged PR and commits GitHub rewrote. An `enqueued`
376
+ result means GitHub accepted the PRs into the queue; waiting continues by observing every selected
377
+ PR until all report merged. Observations must still match the planned PR identities and submitted
378
+ heads. Queue progress is shown but never determines merge eligibility. GitHub removes a queue
379
+ entry before it records the merge, so an open, unqueued PR with no recorded non-merge reason
380
+ still counts as merging until that state persists; a recorded reason other than a merge is a
381
+ removal. A removal stops the wait without local changes, reports the recorded reason and the
382
+ temporary merge commit, and names the next step: `sync` when a lower PR already merged, otherwise
383
+ the same `merge` again.
384
+
385
+ `--no-wait` returns after GitHub accepts the request; the user runs `sync` once GitHub merges.
386
+ Interrupting a wait does not cancel the request. Rerunning `merge` for the same action and
387
+ expected head resumes waiting; a different action or expected head stops. A queue request's merge
388
+ method is not part of that identity because the queue chooses it. Queue waiting has no deadline;
389
+ polling a direct merge request does. A rejection leaves local changes unchanged.
376
390
 
377
391
  Automatic reconciliation identifies the containing stack by the full change ID of the head
378
- resolved before the merge request. It does not reinterpret the original revset
379
- after fetching the changed trunk.
392
+ resolved before the merge request. It does not reinterpret the original revset after fetching
393
+ the changed trunk. If the fetch leaves that head with no visible commit, the local copies are
394
+ already gone, and the follow-up runs only cleanup for the merged PRs.
380
395
 
381
396
  GitHub merge success and local reconciliation are separate outcomes. If GitHub completes the
382
397
  merge but the automatic sync stops, `merge` returns the sync failure status and says that the
@@ -416,8 +431,8 @@ routing for the trunk branch, it does not preflight approvals, checks, conflicts
416
431
  state across the repo. GitHub applies those rules to the requested GitHub stack or
417
432
  single-PR mutation, and `jj-stack` reports the result.
418
433
 
419
- A rejected merge must explain what the user can do next: rebase onto trunk, resolve, and submit
420
- again for a conflict; address the failing check or repo rule on GitHub otherwise.
434
+ A rejected merge preserves GitHub's reason and says what to do next: rebase onto trunk, resolve,
435
+ and submit again for a conflict; address the reported issue on GitHub and retry otherwise.
421
436
 
422
437
  ### Trunk evidence and sync
423
438
 
@@ -435,8 +450,11 @@ work reached this repo's trunk:
435
450
  `sync` may use either result. `sync --all` uses each rewritten merge result to select and
436
451
  reconcile its affected local paths; it does not apply one PR's evidence to unrelated work. It
437
452
  continues with independent stacks when one is blocked. If no local copy remains, it uses that
438
- evidence only for ordinary cleanup. A native GitHub stack rebase without a merge requires `sync`
439
- for that stack; `sync --all` discovers work from merge evidence.
453
+ evidence only for ordinary cleanup, or syncs the local stack still holding the open PRs of the
454
+ same GitHub stack, which cleans up the merged PR itself. A `sync` whose selected change has a
455
+ saved link but no visible commit after the fetch runs only cleanup for the merged PRs of that
456
+ change's GitHub stack. A native GitHub stack rebase without a merge requires `sync` for that
457
+ stack; `sync --all` discovers work from merge evidence.
440
458
 
441
459
  When an unmerged local change sits below a submitted change whose submitted commit or merge result
442
460
  is on trunk, `sync` stops without mutation. Rebasing would silently decide whether that local
@@ -469,9 +487,10 @@ It rebases surviving changes onto trunk even when they contain conflicts. If a s
469
487
  change remains conflicted, the local rebase stays in place but its PR is not updated. The
470
488
  user resolves the conflict with `jj` and runs `submit` for the remaining stack.
471
489
 
472
- If a workspace directly has an obsolete merged change checked out, `sync` does not remove that
490
+ If another workspace has an obsolete merged change checked out, `sync` does not remove that
473
491
  change. Its diagnostic identifies the workspace and gives commands to move it to trunk or forget
474
- it and move its directory to the trash. A workspace on a surviving child does not block its
492
+ it and move its directory to the trash. The current workspace moves to a new empty change on
493
+ trunk before its merged change is removed. A workspace on a surviving child does not block its
475
494
  ordinary rebase.
476
495
 
477
496
  If another local path still depends on a merged change after the rebase, `sync` leaves the
@@ -488,13 +507,15 @@ merges. A matching full change ID on trunk identifies the successor rather than
488
507
  an arbitrary visible side copy. When trunk has no matching change ID, `sync` removes the
489
508
  old local change without relabeling that commit.
490
509
 
491
- When GitHub merges part of a stack and rewrites the remaining PRs, GitHub's rewrite of
492
- each remaining change starts from its submitted baseline. If every remaining local change is still
493
- at its baseline, `sync` uses the commits GitHub reports rather than replaying equivalent
494
- diffs; if any remaining change has local edits, `sync` adopts none, rebases the remaining changes
495
- onto trunk, records GitHub's reported heads as their baselines, and republishes them. It
496
- accepts those heads and bases only while a merged PR in the same GitHub stack matches its saved
497
- record and its merge result is on trunk.
510
+ When GitHub merges part of a stack, each remaining PR is either rewritten from its submitted
511
+ baseline or left at its submitted commit. `sync` uses the commits GitHub reports, rather than
512
+ replaying equivalent diffs, only if every remaining local change is still at its baseline and
513
+ GitHub rewrote every remaining PR. Otherwise it adopts none, rebases the remaining changes onto
514
+ trunk, records GitHub's reported heads as their baselines, and republishes them. It accepts those
515
+ heads and bases only while a merged PR in the same GitHub stack matches its saved record and its
516
+ merge result is on trunk. GitHub roots the rewritten PRs on trunk's tip at the time of the
517
+ rewrite, which may be past the merge result, so the rewritten chain's base must be on trunk at or
518
+ after that merge result rather than exactly at it.
498
519
 
499
520
  #### Native GitHub stack rebase
500
521
 
@@ -551,8 +572,9 @@ they do not block the mutation because they are no longer active.
551
572
  ### Derived artifacts
552
573
 
553
574
  A subsequent submit refreshes a PR description only if it still matches the last automated PR
554
- description. Otherwise it is preserved; explicitly supplied text still takes effect. See
555
- [pull request descriptions](../reference/descriptions.md).
575
+ description. Otherwise it is preserved; explicitly supplied text still takes effect. A saved
576
+ baseline this repo never held leaves nothing to compare, so the description follows the change.
577
+ See [pull request descriptions](../reference/descriptions.md).
556
578
 
557
579
  When a submit supplies no stack overview, the existing overview text is preserved and moves to
558
580
  the current head PR if the stack grows. An explicitly supplied overview replaces it. A lone PR has
@@ -674,7 +696,13 @@ changes that explicit submit boundaries placed in several native GitHub stacks.
674
696
  not segment the path by GitHub resource or infer an omitted submit boundary.
675
697
 
676
698
  Both report whether an open PR has a merge-queue entry; position and intermediate queue phases
677
- are not modeled.
699
+ are not shown.
700
+
701
+ Both report specific merge warnings alongside reviews and checks, omitting GitHub's generic
702
+ `BLOCKED` label. Blocked PRs receive a batched lookup of applicable rules, review threads, and
703
+ checks; `view --verbose` includes other open PRs. Drafts, queued PRs, and changes with a reported
704
+ problem are excluded. Details are discarded if the PR head or base changes during the lookup.
705
+ GitHub computes merge state lazily, so an unknown state is not reported or polled.
678
706
 
679
707
  Neither command guesses. A change with no saved PR identity is reported as not submitted,
680
708
  even if a PR happens to use the branch name that change would generate. A saved PR is always
@@ -689,10 +717,10 @@ Empty, undescribed, conflicted, and merge changes produce warnings, but do not b
689
717
  a report incomplete. A merge warning states that only the first-parent path is shown.
690
718
 
691
719
  `view` and `list` share the rule for incomplete reports: an unmerged divergent change, ambiguous
692
- PR, failed PR lookup, broken saved link, or unobserved saved PR state makes the report incomplete.
693
- A per-change lookup failure affects only its row; a failure before rows can be built returns its
694
- own error code. When several local changes claim one branch, `list` warns and skips live
695
- inspection for that branch. These incomplete reports exit 10.
720
+ PR, failed PR or detail lookup, broken saved link, or unobserved saved PR state makes the report
721
+ incomplete. A per-change lookup failure affects only its row; a failure before rows can be built
722
+ returns its own error code. When several local changes claim one branch, `list` warns and skips
723
+ live inspection for that branch. These incomplete reports exit 10.
696
724
 
697
725
  `view` and `submit` render stack rows through the user's `jj log` formatting. `--json`
698
726
  follows [`docs/json-output.schema.json`](../json-output.schema.json) and exposes no cache state,
@@ -727,6 +755,10 @@ and HTML body of the website's CLI reference page.
727
755
 
728
756
  Running the executable without a subcommand is equivalent to `view` without arguments.
729
757
 
758
+ `--output=jsonl` is a renderer, not a second interface: it writes the same messages, activity
759
+ updates, and `--json` payloads as one JSON object per line on standard output, and command code
760
+ never branches on it.
761
+
730
762
  ### Exit codes
731
763
 
732
764
  Exit codes are a public interface; their table lives in
@@ -0,0 +1,35 @@
1
+ # Generated integration testing
2
+
3
+ These constraints supplement the [testing philosophy](testing-philosophy.md):
4
+
5
+ - In `StackMachine`, keep server events and recovery as separate actions. A server merge must
6
+ leave room for local edits before sync; an interrupted submit must leave room for edits or
7
+ remote changes before retry. Combining these actions would hide the inconsistent states the
8
+ harness exists to test.
9
+ - An external stack merge may leave the survivors' rewrite pending, and `server_rewrite`
10
+ completes it later, rooted on trunk's tip at that time as GitHub does, optionally after
11
+ advancing trunk itself. Keep the merge and the rewrite separate actions so local work and
12
+ other server events can happen between them.
13
+ - `interrupt_sync` fails a sync after it has rewritten the local stack and updated the
14
+ surviving PRs but before it cleans up the merged ones, the state a crashed or interrupted sync
15
+ leaves behind. Recovery must come from a later `sync`, `sync --all`, or `cleanup`, so keep the
16
+ interruption separate from those actions.
17
+ - Shared-file edits use single-line replacements, and generated moves preserve the relative order
18
+ of changes that edit the same file. These restrictions let the harness predict conflicts without
19
+ implementing `jj`'s merge algorithm; broadening the edits requires revisiting that assumption.
20
+ - Each independent seeded search (shard) in the property tests has its own Hypothesis example
21
+ database. Sharing a database would spend parallel search time replaying and shrinking the same
22
+ saved failure.
23
+ - The generated search runs through `just property` and CI's smoke job; `just check` runs only
24
+ the fixed scenarios in `tests/property`. The runner ends by listing the rules the sequences
25
+ fired and the rules none reached. Treat an unreached rule as a search problem, not as missing
26
+ coverage: give it a richer starting state or fix its precondition.
27
+ - A rule is eligible only when it has work to do; compute its candidates in a helper that its
28
+ precondition shares. Hypothesis picks uniformly among eligible rules, so a rule that finds
29
+ nothing wastes a step and a model check.
30
+ - Server drift and injected faults are capped per sequence, and some sequences start after an
31
+ external merge of the bottom PR. Each disturbance pushes the state into a stop that later
32
+ commands only confirm, and every recovery rule needs a merged PR first; without both, a short
33
+ walk never reaches recovery.
34
+ - `check_contents` skips a change whose commit and expected contents it already verified. A new
35
+ content check that depends on anything else must extend that key.