git 4.3.2 → 5.0.0.beta.2

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 (297) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +73 -2705
  3. data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +188 -0
  4. data/.github/pull_request_template.md +3 -1
  5. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  6. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  7. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  8. data/.github/skills/command-implementation/SKILL.md +229 -0
  9. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  10. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  11. data/.github/skills/dependency-management/SKILL.md +72 -0
  12. data/.github/skills/development-workflow/SKILL.md +506 -0
  13. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  14. data/.github/skills/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +22 -0
  15. data/.github/skills/extract-facade-from-base-lib/SKILL.md +600 -0
  16. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  17. data/.github/skills/facade-implementation/SKILL.md +274 -0
  18. data/.github/skills/facade-test-conventions/SKILL.md +394 -0
  19. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  20. data/.github/skills/make-skill-template/SKILL.md +176 -0
  21. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  22. data/.github/skills/project-context/SKILL.md +313 -0
  23. data/.github/skills/pull-request-review/SKILL.md +168 -0
  24. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  25. data/.github/skills/release-management/SKILL.md +125 -0
  26. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  27. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  28. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  29. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  30. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  31. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  32. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  33. data/.github/skills/test-debugging/SKILL.md +160 -0
  34. data/.github/skills/yard-documentation/SKILL.md +793 -0
  35. data/.github/workflows/continuous_integration.yml +3 -2
  36. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  37. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  38. data/.github/workflows/release.yml +3 -4
  39. data/.gitignore +8 -0
  40. data/.husky/pre-commit +13 -0
  41. data/.release-please-manifest.json +1 -1
  42. data/.rspec +3 -0
  43. data/.rubocop.yml +12 -3
  44. data/.rubocop_todo.yml +23 -5
  45. data/.yardopts +1 -0
  46. data/CHANGELOG.md +0 -40
  47. data/CONTRIBUTING.md +694 -53
  48. data/README.md +67 -15
  49. data/Rakefile +61 -9
  50. data/UPGRADING.md +141 -0
  51. data/commitlint.test +4 -0
  52. data/git.gemspec +18 -7
  53. data/lib/git/args_builder.rb +0 -8
  54. data/lib/git/branch.rb +369 -43
  55. data/lib/git/branch_delete_failure.rb +31 -0
  56. data/lib/git/branch_delete_result.rb +63 -0
  57. data/lib/git/branch_info.rb +178 -0
  58. data/lib/git/branches.rb +122 -24
  59. data/lib/git/command_line/base.rb +255 -0
  60. data/lib/git/command_line/capturing.rb +251 -0
  61. data/lib/git/command_line/result.rb +96 -0
  62. data/lib/git/command_line/streaming.rb +196 -0
  63. data/lib/git/command_line.rb +43 -322
  64. data/lib/git/command_line_result.rb +4 -88
  65. data/lib/git/commands/add.rb +131 -0
  66. data/lib/git/commands/am/abort.rb +43 -0
  67. data/lib/git/commands/am/apply.rb +252 -0
  68. data/lib/git/commands/am/continue.rb +43 -0
  69. data/lib/git/commands/am/quit.rb +43 -0
  70. data/lib/git/commands/am/retry.rb +47 -0
  71. data/lib/git/commands/am/show_current_patch.rb +64 -0
  72. data/lib/git/commands/am/skip.rb +42 -0
  73. data/lib/git/commands/am.rb +33 -0
  74. data/lib/git/commands/apply.rb +237 -0
  75. data/lib/git/commands/archive/list_formats.rb +46 -0
  76. data/lib/git/commands/archive.rb +140 -0
  77. data/lib/git/commands/arguments.rb +3510 -0
  78. data/lib/git/commands/base.rb +404 -0
  79. data/lib/git/commands/branch/copy.rb +94 -0
  80. data/lib/git/commands/branch/create.rb +173 -0
  81. data/lib/git/commands/branch/delete.rb +80 -0
  82. data/lib/git/commands/branch/list.rb +162 -0
  83. data/lib/git/commands/branch/move.rb +94 -0
  84. data/lib/git/commands/branch/set_upstream.rb +86 -0
  85. data/lib/git/commands/branch/show_current.rb +49 -0
  86. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  87. data/lib/git/commands/branch.rb +34 -0
  88. data/lib/git/commands/cat_file/batch.rb +369 -0
  89. data/lib/git/commands/cat_file/filtered.rb +105 -0
  90. data/lib/git/commands/cat_file/raw.rb +216 -0
  91. data/lib/git/commands/cat_file.rb +49 -0
  92. data/lib/git/commands/checkout/branch.rb +151 -0
  93. data/lib/git/commands/checkout/files.rb +115 -0
  94. data/lib/git/commands/checkout.rb +38 -0
  95. data/lib/git/commands/checkout_index.rb +105 -0
  96. data/lib/git/commands/clean.rb +100 -0
  97. data/lib/git/commands/clone.rb +240 -0
  98. data/lib/git/commands/commit.rb +272 -0
  99. data/lib/git/commands/commit_tree.rb +100 -0
  100. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  101. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  102. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  103. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  104. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  105. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  106. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +107 -0
  107. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  108. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  109. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  110. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  111. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  112. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  113. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  114. data/lib/git/commands/config_option_syntax.rb +56 -0
  115. data/lib/git/commands/describe.rb +155 -0
  116. data/lib/git/commands/diff.rb +656 -0
  117. data/lib/git/commands/diff_files.rb +518 -0
  118. data/lib/git/commands/diff_index.rb +496 -0
  119. data/lib/git/commands/fetch.rb +352 -0
  120. data/lib/git/commands/fsck.rb +136 -0
  121. data/lib/git/commands/gc.rb +132 -0
  122. data/lib/git/commands/grep.rb +338 -0
  123. data/lib/git/commands/init.rb +99 -0
  124. data/lib/git/commands/log.rb +632 -0
  125. data/lib/git/commands/ls_files.rb +191 -0
  126. data/lib/git/commands/ls_remote.rb +155 -0
  127. data/lib/git/commands/ls_tree.rb +131 -0
  128. data/lib/git/commands/maintenance/register.rb +75 -0
  129. data/lib/git/commands/maintenance/run.rb +104 -0
  130. data/lib/git/commands/maintenance/start.rb +66 -0
  131. data/lib/git/commands/maintenance/stop.rb +55 -0
  132. data/lib/git/commands/maintenance/unregister.rb +79 -0
  133. data/lib/git/commands/maintenance.rb +31 -0
  134. data/lib/git/commands/merge/abort.rb +44 -0
  135. data/lib/git/commands/merge/continue.rb +44 -0
  136. data/lib/git/commands/merge/quit.rb +46 -0
  137. data/lib/git/commands/merge/start.rb +245 -0
  138. data/lib/git/commands/merge.rb +28 -0
  139. data/lib/git/commands/merge_base.rb +86 -0
  140. data/lib/git/commands/mv.rb +77 -0
  141. data/lib/git/commands/name_rev.rb +114 -0
  142. data/lib/git/commands/pull.rb +377 -0
  143. data/lib/git/commands/push.rb +246 -0
  144. data/lib/git/commands/read_tree.rb +149 -0
  145. data/lib/git/commands/remote/add.rb +91 -0
  146. data/lib/git/commands/remote/get_url.rb +66 -0
  147. data/lib/git/commands/remote/list.rb +54 -0
  148. data/lib/git/commands/remote/prune.rb +61 -0
  149. data/lib/git/commands/remote/remove.rb +52 -0
  150. data/lib/git/commands/remote/rename.rb +69 -0
  151. data/lib/git/commands/remote/set_branches.rb +63 -0
  152. data/lib/git/commands/remote/set_head.rb +82 -0
  153. data/lib/git/commands/remote/set_url.rb +71 -0
  154. data/lib/git/commands/remote/set_url_add.rb +61 -0
  155. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  156. data/lib/git/commands/remote/show.rb +71 -0
  157. data/lib/git/commands/remote/update.rb +72 -0
  158. data/lib/git/commands/remote.rb +42 -0
  159. data/lib/git/commands/repack.rb +277 -0
  160. data/lib/git/commands/reset.rb +147 -0
  161. data/lib/git/commands/rev_parse.rb +297 -0
  162. data/lib/git/commands/revert/abort.rb +45 -0
  163. data/lib/git/commands/revert/continue.rb +57 -0
  164. data/lib/git/commands/revert/quit.rb +47 -0
  165. data/lib/git/commands/revert/skip.rb +44 -0
  166. data/lib/git/commands/revert/start.rb +153 -0
  167. data/lib/git/commands/revert.rb +29 -0
  168. data/lib/git/commands/rm.rb +114 -0
  169. data/lib/git/commands/show.rb +632 -0
  170. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  171. data/lib/git/commands/show_ref/exists.rb +78 -0
  172. data/lib/git/commands/show_ref/list.rb +145 -0
  173. data/lib/git/commands/show_ref/verify.rb +120 -0
  174. data/lib/git/commands/show_ref.rb +42 -0
  175. data/lib/git/commands/stash/apply.rb +75 -0
  176. data/lib/git/commands/stash/branch.rb +65 -0
  177. data/lib/git/commands/stash/clear.rb +41 -0
  178. data/lib/git/commands/stash/create.rb +58 -0
  179. data/lib/git/commands/stash/drop.rb +67 -0
  180. data/lib/git/commands/stash/list.rb +39 -0
  181. data/lib/git/commands/stash/pop.rb +78 -0
  182. data/lib/git/commands/stash/push.rb +103 -0
  183. data/lib/git/commands/stash/show.rb +149 -0
  184. data/lib/git/commands/stash/store.rb +63 -0
  185. data/lib/git/commands/stash.rb +38 -0
  186. data/lib/git/commands/status.rb +169 -0
  187. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  188. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  189. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  190. data/lib/git/commands/symbolic_ref.rb +38 -0
  191. data/lib/git/commands/tag/create.rb +139 -0
  192. data/lib/git/commands/tag/delete.rb +55 -0
  193. data/lib/git/commands/tag/list.rb +143 -0
  194. data/lib/git/commands/tag/verify.rb +71 -0
  195. data/lib/git/commands/tag.rb +26 -0
  196. data/lib/git/commands/update_ref/batch.rb +140 -0
  197. data/lib/git/commands/update_ref/delete.rb +92 -0
  198. data/lib/git/commands/update_ref/update.rb +106 -0
  199. data/lib/git/commands/update_ref.rb +42 -0
  200. data/lib/git/commands/version.rb +57 -0
  201. data/lib/git/commands/worktree/add.rb +140 -0
  202. data/lib/git/commands/worktree/list.rb +64 -0
  203. data/lib/git/commands/worktree/lock.rb +58 -0
  204. data/lib/git/commands/worktree/management_base.rb +51 -0
  205. data/lib/git/commands/worktree/move.rb +66 -0
  206. data/lib/git/commands/worktree/prune.rb +67 -0
  207. data/lib/git/commands/worktree/remove.rb +63 -0
  208. data/lib/git/commands/worktree/repair.rb +76 -0
  209. data/lib/git/commands/worktree/unlock.rb +47 -0
  210. data/lib/git/commands/worktree.rb +43 -0
  211. data/lib/git/commands/write_tree.rb +68 -0
  212. data/lib/git/commands.rb +87 -0
  213. data/lib/git/config.rb +17 -0
  214. data/lib/git/config_entry_info.rb +106 -0
  215. data/lib/git/configuring.rb +665 -0
  216. data/lib/git/deprecation.rb +9 -0
  217. data/lib/git/detached_head_info.rb +54 -0
  218. data/lib/git/diff.rb +293 -7
  219. data/lib/git/diff_file_numstat_info.rb +29 -0
  220. data/lib/git/diff_file_patch_info.rb +134 -0
  221. data/lib/git/diff_file_raw_info.rb +127 -0
  222. data/lib/git/diff_info.rb +169 -0
  223. data/lib/git/diff_path_status.rb +67 -19
  224. data/lib/git/diff_result.rb +32 -0
  225. data/lib/git/diff_stats.rb +51 -14
  226. data/lib/git/dirstat_info.rb +86 -0
  227. data/lib/git/errors.rb +65 -2
  228. data/lib/git/execution_context/global.rb +31 -0
  229. data/lib/git/execution_context/repository.rb +136 -0
  230. data/lib/git/execution_context.rb +501 -0
  231. data/lib/git/file_ref.rb +74 -0
  232. data/lib/git/fsck_object.rb +9 -9
  233. data/lib/git/fsck_result.rb +1 -1
  234. data/lib/git/log.rb +9 -2
  235. data/lib/git/object.rb +90 -27
  236. data/lib/git/parsers/branch.rb +224 -0
  237. data/lib/git/parsers/cat_file.rb +111 -0
  238. data/lib/git/parsers/config_entry.rb +110 -0
  239. data/lib/git/parsers/diff.rb +585 -0
  240. data/lib/git/parsers/fsck.rb +133 -0
  241. data/lib/git/parsers/grep.rb +42 -0
  242. data/lib/git/parsers/ls_remote.rb +79 -0
  243. data/lib/git/parsers/ls_tree.rb +58 -0
  244. data/lib/git/parsers/stash.rb +208 -0
  245. data/lib/git/parsers/tag.rb +257 -0
  246. data/lib/git/remote.rb +120 -9
  247. data/lib/git/repository/branching.rb +743 -0
  248. data/lib/git/repository/committing.rb +187 -0
  249. data/lib/git/repository/configuring.rb +351 -0
  250. data/lib/git/repository/context_helpers.rb +264 -0
  251. data/lib/git/repository/diffing.rb +775 -0
  252. data/lib/git/repository/factories.rb +682 -0
  253. data/lib/git/repository/inspecting.rb +252 -0
  254. data/lib/git/repository/logging.rb +247 -0
  255. data/lib/git/repository/maintenance.rb +65 -0
  256. data/lib/git/repository/merging.rb +357 -0
  257. data/lib/git/repository/object_operations.rb +1199 -0
  258. data/lib/git/repository/path_resolver.rb +207 -0
  259. data/lib/git/repository/remote_operations.rb +898 -0
  260. data/lib/git/repository/shared_private.rb +51 -0
  261. data/lib/git/repository/staging.rb +554 -0
  262. data/lib/git/repository/stashing.rb +143 -0
  263. data/lib/git/repository/status_operations.rb +201 -0
  264. data/lib/git/repository/worktree_operations.rb +159 -0
  265. data/lib/git/repository.rb +203 -1
  266. data/lib/git/stash.rb +78 -4
  267. data/lib/git/stash_info.rb +104 -0
  268. data/lib/git/stashes.rb +125 -13
  269. data/lib/git/status.rb +215 -18
  270. data/lib/git/tag_delete_failure.rb +31 -0
  271. data/lib/git/tag_delete_result.rb +63 -0
  272. data/lib/git/tag_info.rb +105 -0
  273. data/lib/git/version.rb +109 -2
  274. data/lib/git/version_constraint.rb +81 -0
  275. data/lib/git/worktree.rb +108 -6
  276. data/lib/git/worktrees.rb +94 -7
  277. data/lib/git.rb +260 -61
  278. data/redesign/1_architecture_existing.md +54 -18
  279. data/redesign/2_architecture_redesign.md +365 -46
  280. data/redesign/3_architecture_implementation.md +1497 -63
  281. data/redesign/Phase 4 - Step A.md +360 -0
  282. data/redesign/beta_release.md +107 -0
  283. data/redesign/c1c2_audit.md +566 -0
  284. data/redesign/c1c2_bucket6_lib_orphans.md +626 -0
  285. data/redesign/config_design.rb +501 -0
  286. data/tasks/gem_tasks.rake +4 -0
  287. data/tasks/npm_tasks.rake +7 -0
  288. data/tasks/rspec.rake +48 -0
  289. data/tasks/test.rake +13 -1
  290. data/tasks/yard.rake +34 -7
  291. metadata +365 -22
  292. data/lib/git/base.rb +0 -1128
  293. data/lib/git/index.rb +0 -6
  294. data/lib/git/lib.rb +0 -2277
  295. data/lib/git/path.rb +0 -38
  296. data/lib/git/working_directory.rb +0 -6
  297. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -0,0 +1,274 @@
1
+ ---
2
+ name: facade-implementation
3
+ description: "Scaffolds new and reviews existing Git::Repository facade methods (organized into Git::Repository::* topic modules) with unit tests, integration tests, and YARD docs. Use when adding a new facade method to Git::Repository, updating an existing facade method, choosing or creating a topic module under lib/git/repository/, or reviewing a facade method for correctness."
4
+ ---
5
+
6
+ # Facade Implementation
7
+
8
+ Scaffold new and review existing facade methods on `Git::Repository`. Facade methods
9
+ live in topic modules under `lib/git/repository/<topic>.rb` (e.g.
10
+ {Git::Repository::Staging}) and are included into the `Git::Repository` class.
11
+
12
+ A facade method is the public-API entry point that orchestrates one or more
13
+ `Git::Commands::*` calls, optional argument pre-processing, and optional output
14
+ parsing into rich Ruby return values. See
15
+ [redesign/2_architecture_redesign.md §2.1](../../../redesign/2_architecture_redesign.md)
16
+ for the five facade responsibilities this layer is designed around.
17
+
18
+ ## Contents
19
+
20
+ - [How to use this skill](#how-to-use-this-skill)
21
+ - [Related skills](#related-skills)
22
+ - [Input](#input)
23
+ - [Existing facade source](#existing-facade-source)
24
+ - [Existing facade tests](#existing-facade-tests)
25
+ - [Underlying command class(es)](#underlying-command-classes)
26
+ - [Underlying parsers (if any)](#underlying-parsers-if-any)
27
+ - [Reference](#reference)
28
+ - [Workflow](#workflow)
29
+ - [Output](#output)
30
+
31
+ ## How to use this skill
32
+
33
+ Attach this file to your Copilot Chat context, then invoke with the facade method
34
+ to scaffold, update, or review. Examples:
35
+
36
+ ```text
37
+ Using the Facade Implementation skill, scaffold Git::Repository::Staging#add.
38
+ ```
39
+
40
+ ```text
41
+ Facade Implementation review: Git::Repository::Committing#commit.
42
+ ```
43
+
44
+ ## Related skills
45
+
46
+ - [Facade Test Conventions](../facade-test-conventions/SKILL.md) — unit and
47
+ integration test conventions for facade methods (load when scaffolding or
48
+ reviewing tests)
49
+ - [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) — facade-specific
50
+ YARD rules for module-level and method-level docs
51
+ - [Extract Facade from Base/Lib](../extract-facade-from-base-lib/SKILL.md) — when a
52
+ new facade method is migrated from `Git::Base` or `Git::Lib`, the extraction
53
+ workflow drives this skill in scaffold/update mode
54
+ - [Command Implementation](../command-implementation/SKILL.md) — the underlying
55
+ `Git::Commands::*` classes a facade method calls. Scaffold any missing command
56
+ class first.
57
+ - [YARD Documentation](../yard-documentation/SKILL.md) — baseline YARD formatting
58
+ rules
59
+ - [RSpec Unit Testing Standards](../rspec-unit-testing-standards/SKILL.md) — baseline
60
+ RSpec rules
61
+ - [Project Context](../project-context/SKILL.md) — three-layer architecture overview
62
+
63
+ ## Input
64
+
65
+ The user provides:
66
+
67
+ 1. **Method name** — the public Ruby method name (e.g. `add`, `branches_all`,
68
+ `commit`).
69
+ 2. **Git operation(s)** — which `Git::Commands::*` class(es) the method orchestrates.
70
+ If the relevant command class does not exist yet, scaffold it first via
71
+ [Command Implementation](../command-implementation/SKILL.md).
72
+ 3. **Optional context** — the source `Git::Lib` / `Git::Base` method when migrating
73
+ (handled by [Extract Facade from Base/Lib](../extract-facade-from-base-lib/SKILL.md)).
74
+
75
+ > **Note:** `Git::Repository` is intentionally empty during early phases of the
76
+ > redesign. Its `initialize(execution_context:)` constructor is introduced
77
+ > alongside the first facade method extraction; subsequent extractions only
78
+ > add new topic modules and `include` lines.
79
+
80
+ The agent then gathers:
81
+
82
+ ### Existing facade source
83
+
84
+ Read `lib/git/repository.rb` to see the `include Git::Repository::<Topic>` lines and
85
+ which topic modules exist. List `lib/git/repository/` to see all current topic
86
+ modules and the facade methods they already define.
87
+
88
+ Skip when scaffolding into a brand-new topic module.
89
+
90
+ ### Existing facade tests
91
+
92
+ Read `spec/unit/git/repository/<topic>_spec.rb` and
93
+ `spec/integration/git/repository/<topic>_spec.rb` (if present). Use as supplemental
94
+ evidence of the existing test style before extending or reviewing.
95
+
96
+ ### Underlying command class(es)
97
+
98
+ Read `lib/git/commands/<command>.rb` for each command the facade method calls.
99
+ The command's `arguments do` block defines the option keys the facade may forward,
100
+ and the YARD `@!method call` block documents what each option does. The facade must
101
+ not pass option keys the command does not declare.
102
+
103
+ ### Underlying parsers (if any)
104
+
105
+ Read `lib/git/parsers/<parser>.rb` for any parser the facade uses to transform
106
+ command stdout into structured data.
107
+
108
+ ## Reference
109
+
110
+ See [REFERENCE.md](REFERENCE.md) for the full reference covering:
111
+
112
+ - Files to generate
113
+ - Topic module selection (existing modules + decision rules for creating a new module)
114
+ - Designing a facade method (return type, signature, body shape)
115
+ - Topic module skeleton (file layout)
116
+ - The five facade responsibilities as a checklist
117
+ - Argument pre-processing patterns (path normalization, option whitelisting via
118
+ `SharedPrivate.assert_valid_opts!` + `private_constant`,
119
+ deprecation handling, defaults)
120
+ - Internal helpers and encapsulation (sibling `module_function` modules under
121
+ `lib/git/repository/` instead of private methods on `Git::Repository`;
122
+ bare-noun naming; growth path from `SharedPrivate` to responsibility-named
123
+ modules)
124
+ - When to call multiple commands (orchestration sequences)
125
+ - When to use a parser vs. raw stdout
126
+ - When to use a result-class factory method
127
+ - Common failures (one-line delegation when orchestration is needed; leaking
128
+ command-class types into the public API; bypassing the execution context;
129
+ hardcoding policy options the caller cannot override)
130
+
131
+ Subagents load REFERENCE.md directly during the workflow steps that need it.
132
+
133
+ ## Workflow
134
+
135
+ This skill supports three modes. Determine which mode applies before starting:
136
+
137
+ - **Scaffold** — adding a new facade method (and possibly a new topic module).
138
+ Follow all steps.
139
+ - **Update** — modifying an existing facade method (e.g. adding a new option to
140
+ forward). Skip step 2 (module selection); steps 3a–3c are extending existing files
141
+ rather than creating them.
142
+ - **Review** — auditing an existing facade method (no changes). Follow all steps but
143
+ produce findings instead of code.
144
+
145
+ 1. **Gather input** — collect the method name, target git operation(s), and any
146
+ migration source per [Input](#input). Read the underlying command class(es) and
147
+ parser(s) the method will call.
148
+
149
+ 2. **Choose the topic module** — load
150
+ [REFERENCE.md](REFERENCE.md) and apply [Topic module
151
+ selection](REFERENCE.md#topic-module-selection):
152
+
153
+ - Prefer extending an existing module under `lib/git/repository/`.
154
+ - Create a new module only when the topic is recognizable — preferably
155
+ matching a git-scm category (<https://git-scm.com/docs>) — and the methods
156
+ would be awkward to place in any existing module. The deciding factor is
157
+ topic fit, not method count; a single method that is genuinely distinct
158
+ can start its own module.
159
+ - New module names follow the two-tier convention: gerund (`Staging`, `Logging`,
160
+ `Diffing`) for single-action modules; `Noun + Operations` (`RemoteOperations`,
161
+ `ObjectOperations`) for mixed-bag modules. See
162
+ [REFERENCE.md §Naming a new topic module](REFERENCE.md#naming-a-new-topic-module).
163
+
164
+ 3. **For the facade method**, repeat steps 3a–3e:
165
+
166
+ a. **Scaffold the facade method (subagent)** *(scaffold/update modes only)* —
167
+ delegate to a subagent: load [REFERENCE.md](REFERENCE.md) and the
168
+ [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) skill,
169
+ then create or extend `lib/git/repository/<topic>.rb` using the [Designing
170
+ a facade method](REFERENCE.md#designing-a-facade-method) section and
171
+ [Topic module skeleton](REFERENCE.md#topic-module-skeleton). For new topic
172
+ modules, also add the `require` and `include` lines to
173
+ `lib/git/repository.rb`.
174
+
175
+ Steps 3b and 3c may run **in parallel** (they produce independent files).
176
+
177
+ b. **Scaffold unit tests (subagent)** *(scaffold/update modes only)* — delegate
178
+ to a subagent: load **[Facade Test
179
+ Conventions](../facade-test-conventions/SKILL.md)** (which loads [RSpec Unit
180
+ Testing Standards](../rspec-unit-testing-standards/SKILL.md)), then create or
181
+ extend `spec/unit/git/repository/<topic>_spec.rb` following the unit
182
+ conventions (stub `Git::Commands::*` and `Git::Parsers::*` via
183
+ `instance_double`; assert delegation contracts; cover each pre-processing
184
+ branch).
185
+
186
+ c. **Scaffold integration tests (subagent)** *(scaffold/update modes only)* —
187
+ delegate to a subagent: load **[Facade Test
188
+ Conventions](../facade-test-conventions/SKILL.md)**, then create or extend
189
+ `spec/integration/git/repository/<topic>_spec.rb` following the integration
190
+ conventions (real git in a temp repository; assert end-to-end Ruby return
191
+ value, not intermediate command results). Skip integration tests for true
192
+ one-line delegators that add no orchestration on top of the underlying
193
+ command — the command's own integration tests already cover that path.
194
+
195
+ Steps 3d and 3e may run **in parallel** (they review independent file sets).
196
+
197
+ d. **Review Facade Tests (subagent)** — delegate to a subagent: load and apply
198
+ **[Facade Test Conventions](../facade-test-conventions/SKILL.md)** against the
199
+ unit and integration spec files. In *scaffold/update* modes, fix all findings
200
+ and repeat until clean. In *review* mode, record findings only.
201
+
202
+ e. **Review YARD Documentation (subagent)** — delegate to a subagent: load and
203
+ apply **[Facade YARD Documentation](../facade-yard-documentation/SKILL.md)**
204
+ against the topic module file. In *scaffold/update* modes, fix all findings
205
+ and repeat until clean. In *review* mode, record findings only.
206
+
207
+ 4. **Review facade shape and orchestration** — load
208
+ [REFERENCE.md](REFERENCE.md) and verify against the [Five facade
209
+ responsibilities checklist](REFERENCE.md#the-five-facade-responsibilities-checklist),
210
+ the [Designing a facade method](REFERENCE.md#designing-a-facade-method) section, and
211
+ [Common failures](REFERENCE.md#common-failures). Confirm the method:
212
+
213
+ - delegates to a `Git::Commands::*` class via `@execution_context` (never
214
+ constructs commands with `self` or builds CLI argv directly)
215
+ - does not return a `Git::CommandLineResult` from the public contract unless
216
+ that is the documented return type for the entire topic module
217
+ - whitelists forwarded options when the caller's hash is opaque
218
+ (per-method `<METHOD>_ALLOWED_OPTS` constant +
219
+ `SharedPrivate.assert_valid_opts!(allowed, **)` — do **not**
220
+ also `slice`; see [Option
221
+ whitelisting](REFERENCE.md#option-whitelisting-preventing-api-expansion))
222
+ - places each `<METHOD>_ALLOWED_OPTS` constant **immediately before** the
223
+ method that uses it (not grouped at the top of the module)
224
+ - handles defaults and deprecations explicitly, not by relying on command
225
+ internals
226
+ - is explicitly classified as `legacy-contract` (legacy predecessor exists)
227
+ or `5.x-native` (new facade API), and signature shape matches that
228
+ classification
229
+ - has tests that verify call-shape compatibility when classification is
230
+ `legacy-contract` (positional hash and/or keyword-arg / `**opts` forms where required)
231
+
232
+ 5. **Run quality gates** — discover the prerequisite tasks for `default:parallel`
233
+ and run them sequentially, fixing failures before advancing:
234
+
235
+ ```bash
236
+ bundle exec ruby -e "require 'rake'; load 'Rakefile'; puts Rake::Task['default:parallel'].prerequisites"
237
+ ```
238
+
239
+ Run each listed task **individually** in order via `bundle exec rake <task>`
240
+ (one task per invocation). On failure, fix the issue and re-run that same task.
241
+ Continue until every task passes on its first attempt with no fixes needed.
242
+
243
+ ## Output
244
+
245
+ For **scaffold** and **update** modes, produce:
246
+
247
+ 1. **Topic module** — `lib/git/repository/<topic>.rb` (created or extended)
248
+ 2. **Facade wiring** — `lib/git/repository.rb` updated with `require` and `include`
249
+ when a new topic module was created
250
+ 3. **Unit tests** — `spec/unit/git/repository/<topic>_spec.rb`
251
+ 4. **Integration tests** — `spec/integration/git/repository/<topic>_spec.rb`
252
+ (omit only for true one-line delegators)
253
+ 5. **All quality gates pass** — rspec, minitest, rubocop, and yard all green
254
+
255
+ For **review** mode, produce:
256
+
257
+ | Check | Status | Issue |
258
+ | --- | --- | --- |
259
+ | Topic module placement | Pass/Fail | ... |
260
+ | Orchestration via `@execution_context` | Pass/Fail | ... |
261
+ | Argument pre-processing complete | Pass/Fail | ... |
262
+ | Option whitelisting (where required) | Pass/Fail | ... |
263
+ | `*_ALLOWED_OPTS` placed immediately before its method | Pass/Fail | ... |
264
+ | Signature classification documented | Pass/Fail | ... |
265
+ | Signature shape matches classification | Pass/Fail | ... |
266
+ | Return value matches documented contract | Pass/Fail | ... |
267
+ | Parser/result-class wiring correct | Pass/Fail | ... |
268
+ | YARD docs complete | Pass/Fail | ... |
269
+ | Unit + integration coverage | Pass/Fail | ... |
270
+
271
+ Then list required fixes.
272
+ > **Branch workflow:** Implement scaffolding or updates on a feature branch.
273
+ > Never commit or push directly to `main` — open a pull request when changes
274
+ > are ready to merge.
@@ -0,0 +1,394 @@
1
+ ---
2
+ name: facade-test-conventions
3
+ description: "Conventions for writing and reviewing unit and integration tests for Git::Repository facade methods (modules under lib/git/repository/). Use when scaffolding new facade tests or auditing existing ones in spec/unit/git/repository/ and spec/integration/git/repository/."
4
+ ---
5
+
6
+ # Facade Test Conventions
7
+
8
+ Conventions for writing and reviewing unit and integration tests for facade
9
+ methods on `Git::Repository::*` modules.
10
+
11
+ ## Contents
12
+
13
+ - [How to use this skill](#how-to-use-this-skill)
14
+ - [Related skills](#related-skills)
15
+ - [Input](#input)
16
+ - [Reference](#reference)
17
+ - [Unit tests](#unit-tests)
18
+ - [Setup pattern](#setup-pattern)
19
+ - [Cover these cases](#cover-these-cases)
20
+ - [Expectations for command invocation](#expectations-for-command-invocation)
21
+ - [What not to test](#what-not-to-test)
22
+ - [Unit test grouping](#unit-test-grouping)
23
+ - [Integration tests](#integration-tests)
24
+ - [When to write integration tests](#when-to-write-integration-tests)
25
+ - [When to skip integration tests](#when-to-skip-integration-tests)
26
+ - [Integration test grouping](#integration-test-grouping)
27
+ - [What integration tests assert](#what-integration-tests-assert)
28
+ - [What integration tests do not assert](#what-integration-tests-do-not-assert)
29
+ - [Workflow](#workflow)
30
+ - [Output](#output)
31
+ - [When writing new facade tests](#when-writing-new-facade-tests)
32
+ - [When reviewing existing facade tests](#when-reviewing-existing-facade-tests)
33
+
34
+ ## How to use this skill
35
+
36
+ Attach this file to your Copilot Chat context, then invoke with the spec file(s)
37
+ to write or review. Include the corresponding facade module for context. Examples:
38
+
39
+ ```text
40
+ Using the Facade Test Conventions skill, scaffold tests for Git::Repository::Staging.
41
+ ```
42
+
43
+ ```text
44
+ Facade Test Conventions review: spec/unit/git/repository/committing_spec.rb.
45
+ ```
46
+
47
+ ## Related skills
48
+
49
+ - [RSpec Unit Testing Standards](../rspec-unit-testing-standards/SKILL.md) — baseline
50
+ RSpec rules that govern all unit test structure, naming, setup, stubbing, and
51
+ coverage; this skill adds facade-specific conventions on top
52
+ - [Facade Implementation](../facade-implementation/SKILL.md) — facade module
53
+ structure and orchestration patterns
54
+ - [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) — YARD docs
55
+ for facade modules and methods
56
+ - [Command Test Conventions](../command-test-conventions/SKILL.md) — sibling skill
57
+ that tests the underlying `Git::Commands::*` classes the facade calls
58
+
59
+ ## Input
60
+
61
+ The invocation needs the unit and/or integration spec file(s) to review. Including
62
+ the corresponding facade module file (`lib/git/repository/<topic>.rb`) provides
63
+ useful context for verifying delegation contracts and option forwarding.
64
+
65
+ **Prerequisite:** Read the **entire** [RSpec Unit Testing
66
+ Standards](../rspec-unit-testing-standards/SKILL.md) skill (line 1 through EOF)
67
+ before beginning. It defines the baseline Rules 1–28 that this skill extends.
68
+
69
+ ## Reference
70
+
71
+ ### Unit tests
72
+
73
+ Facade unit tests verify the **orchestration contract** between the facade method
74
+ and the components it calls (`Git::Commands::*`, `Git::Parsers::*`,
75
+ `Git::ExecutionContext::Repository`). They do not run real git.
76
+
77
+ The collaborators (commands, parsers) are stubbed via `instance_double`. The unit
78
+ test asserts:
79
+
80
+ 1. The facade constructs each command class with the injected
81
+ `@execution_context`.
82
+ 2. Each command's `#call` is invoked with the expected positional and keyword
83
+ arguments (verifying argument pre-processing).
84
+ 3. For multi-command sequences, the calls happen in the documented order.
85
+ 4. The parser/result-class is invoked with the command's stdout (when applicable).
86
+ 5. The facade returns the value its public contract documents.
87
+
88
+ #### Setup pattern
89
+
90
+ ```ruby
91
+ RSpec.describe Git::Repository::Staging do
92
+ let(:execution_context) { instance_double(Git::ExecutionContext::Repository) }
93
+ let(:described_instance) { Git::Repository.new(execution_context: execution_context) }
94
+ let(:command_result) { instance_double(Git::CommandLineResult, stdout: '') }
95
+ let(:add_command) { instance_double(Git::Commands::Add) }
96
+ let(:add_result) { command_result }
97
+
98
+ before do
99
+ allow(Git::Commands::Add).to receive(:new).with(execution_context).and_return(add_command)
100
+ end
101
+
102
+ describe '#add' do
103
+ # ...
104
+ end
105
+ end
106
+ ```
107
+
108
+ The shared `command_result` `let` provides a default empty-stdout result; each
109
+ per-command alias (`add_result`, `branch_list_result`, ...) lets individual
110
+ tests override stdout in isolation — e.g.
111
+ `let(:add_result) { instance_double(Git::CommandLineResult, stdout: 'fixture output') }`
112
+ in a nested `context` — without affecting other tests in the file.
113
+
114
+ Setup invariants:
115
+
116
+ - The subject is an instance of `Git::Repository`, **not** the module itself.
117
+ Modules are mixed into the class; tests must exercise the class to reflect
118
+ real call sites.
119
+ - `execution_context` is an `instance_double(Git::ExecutionContext::Repository)`
120
+ — never a `double('ExecutionContext')` and never a real context.
121
+ - Each command class is stubbed with `allow(Klass).to receive(:new).with(execution_context).and_return(...)`
122
+ so the facade's command construction (with the right execution context) is
123
+ verified by the stub.
124
+
125
+ #### Cover these cases
126
+
127
+ - **Default invocation** — facade called with no arguments (or only required
128
+ positional args) delegates with the documented defaults. Assert the return
129
+ value once per facade method to verify pass-through.
130
+ - **Each positional argument variation** — single value, array, nil where
131
+ applicable.
132
+ - **Each option the facade exposes** — including aliases, deprecated keys, and
133
+ policy defaults the facade applies (`no_edit: true`, etc.).
134
+ - **Multi-command sequences** — when the facade calls more than one command,
135
+ use `expect ... receive(:call).with(...).ordered` to assert ordering and
136
+ intermediate-result wiring.
137
+ - **Parser invocation** — when the facade uses a `Git::Parsers::*` class,
138
+ stub the parser and assert it is called with the command's stdout. Assert the
139
+ facade returns what the parser returned.
140
+ - **Raw `CommandLineResult` return** — when the facade's contract is to
141
+ return the command's `Git::CommandLineResult` directly (not `.stdout` and
142
+ not a parser output), assert `eq(<command>_result)` to verify pass-through.
143
+ - **Option whitelisting** — when the facade defines a `<METHOD>_ALLOWED_OPTS`
144
+ constant and calls `Git::Repository::Internal.assert_valid_opts!`, test that
145
+ an unknown key raises `ArgumentError` and a known key is forwarded.
146
+ - **Deprecation handling** — when the facade rewrites or warns on deprecated
147
+ keys, test that the deprecation warning is emitted and the new key is
148
+ forwarded.
149
+ - **Signature compatibility call shapes** — when a facade method preserves a
150
+ legacy public contract, include tests for each call shape the 4.x public API
151
+ used (positional hash and/or keyword-arg / `**opts` where applicable).
152
+
153
+ #### Expectations for command invocation
154
+
155
+ Use the standard rspec-mocks form (no command-specific helper exists for the
156
+ facade layer):
157
+
158
+ ```ruby
159
+ it 'delegates to Git::Commands::Add#call with the given path' do
160
+ expect(add_command).to receive(:call).with('path/to/file.rb').and_return(add_result)
161
+ described_instance.add('path/to/file.rb')
162
+ end
163
+ ```
164
+
165
+ For command + parser orchestration (single command whose stdout is fed to a
166
+ parser), use `.ordered` to assert the call sequence:
167
+
168
+ ```ruby
169
+ it 'lists branches then parses the output' do
170
+ expect(branch_list_command).to(
171
+ receive(:call)
172
+ .with(all: true, format: Git::Parsers::Branch::FORMAT_STRING)
173
+ .and_return(branch_list_result)
174
+ .ordered
175
+ )
176
+
177
+ expect(Git::Parsers::Branch).to(
178
+ receive(:parse_list)
179
+ .with(branch_list_result.stdout)
180
+ .and_return(parsed_branches)
181
+ .ordered
182
+ )
183
+
184
+ expect(described_instance.branches_all).to eq(parsed_branches)
185
+ end
186
+ ```
187
+
188
+ For genuinely multi-command orchestration (the facade calls more than one
189
+ command), chain `.ordered` across each command's `#call`, wiring intermediate
190
+ results through as needed:
191
+
192
+ ```ruby
193
+ it 'saves the stash then lists stashes' do
194
+ expect(stash_save_command).to(
195
+ receive(:call).with(message: 'wip').and_return(stash_save_result).ordered
196
+ )
197
+
198
+ expect(stash_list_command).to(
199
+ receive(:call).and_return(stash_list_result).ordered
200
+ )
201
+
202
+ expect(described_instance.stash_save_and_list(message: 'wip')).to eq(parsed_stashes)
203
+ end
204
+ ```
205
+
206
+ #### What not to test
207
+
208
+ - **Command argv building.** That is the command class's contract and is covered
209
+ by `spec/unit/git/commands/<command>_spec.rb`. The facade unit test should
210
+ stub `#call` and assert the keyword arguments the facade passes — not assert
211
+ on the CLI tokens that reach git.
212
+ - **Parser internals.** Stub the parser class method and assert the facade calls
213
+ it with the right input. Parser parsing is covered by `spec/unit/git/parsers/`.
214
+ - **Real command execution.** Facade unit tests must not exercise
215
+ `Git::ExecutionContext::Repository` for real. Use `instance_double`.
216
+ - **Multiple input strings exercising the same code path** — one test per
217
+ argument type is sufficient (string vs. array vs. nil), not one per value.
218
+ - **`#initialize` of the facade module.** The module is mixed into
219
+ `Git::Repository`; constructor coverage belongs to `repository_spec.rb`.
220
+
221
+ #### Unit test grouping
222
+
223
+ One `describe '#<method_name>'` block per facade method. Inside, use flat
224
+ `context` blocks per argument variation. Optional sections at the end (in order)
225
+ when present:
226
+
227
+ - `context 'option whitelisting'` —
228
+ `Git::Repository::Internal.assert_valid_opts!` raises on unknown keys and
229
+ forwards known keys unchanged (no `slice` — the assertion is the only
230
+ enforcement mechanism)
231
+ - `context 'deprecation handling'` — `Git::Deprecation.warn` assertions and
232
+ key-rewrite tests
233
+ - `context 'input validation'` — `ArgumentError` raised by the facade itself
234
+ (not by the command)
235
+ - `context 'signature compatibility'` — for legacy-contract methods, exercises
236
+ required call shapes (legacy positional hash and/or keyword-arg / `**opts` forms)
237
+
238
+ The exit code section that command specs use does **not** apply to facade specs
239
+ — exit-status handling is the command's concern; the facade's tests assume the
240
+ command either returns a result or raises.
241
+
242
+ ### Integration tests
243
+
244
+ Facade integration tests run real git in a temp repository and verify the
245
+ **end-to-end Ruby return value** of the facade method.
246
+
247
+ Each integration spec file tests **one facade module** (one
248
+ `spec/integration/git/repository/<topic>_spec.rb`). Inside, group by facade
249
+ method.
250
+
251
+ #### When to write integration tests
252
+
253
+ Facade integration tests are the **exception, not the default**. Most facade
254
+ behavior is already covered end-to-end by the underlying command's own
255
+ integration tests; re-running real git through the facade re-exercises the
256
+ same code path without adding signal.
257
+
258
+ Write a facade integration test only when the facade adds behavior that is
259
+ **not** exercised by any single command's integration tests:
260
+
261
+ - **Multi-command orchestration** — the facade calls more than one command
262
+ and the integration test confirms the documented end-to-end value emerges
263
+ from the sequence against real git.
264
+ - **Facade-owned post-processing of real git output** — the facade itself
265
+ (not the command) parses, aggregates, or transforms raw command output
266
+ before returning. A real git invocation proves the post-processing handles
267
+ actual output rather than a mocked string.
268
+
269
+ #### When to skip integration tests
270
+
271
+ Skip for everything else, including:
272
+
273
+ - **One-line delegators** that pass arguments through to a single command
274
+ with no pre/post-processing (e.g. `Git::Repository::Staging#add`,
275
+ `#reset`).
276
+ - **Single-command facade methods that delegate parsing to a parser or
277
+ result-class factory** — the command's own integration test already
278
+ exercises that command + parser against real git.
279
+ - **Argument pre-processing** (path normalization, deprecation key rewrites,
280
+ option whitelisting) — these are pure-Ruby transforms with no git
281
+ involvement; unit tests prove them and real git adds no signal.
282
+ - **Error-path assertions** (`raise_error(Git::FailedError)`) — these test
283
+ the command's error wrapping, not the facade.
284
+
285
+ When skipping, document why with a code comment in the spec file or a `#`
286
+ header in `spec/integration/git/repository/<topic>_spec.rb` explaining which
287
+ methods are covered exclusively by command integration tests.
288
+
289
+ #### Integration test grouping
290
+
291
+ Mirror the [Command Test Conventions](../command-test-conventions/SKILL.md)
292
+ integration grouping. Use a multi-command or post-processing facade method —
293
+ single-command delegators do not warrant integration tests (see [When to skip
294
+ integration tests](#when-to-skip-integration-tests)):
295
+
296
+ The shared context (e.g. `'in an empty repository'`) provides `repo` and
297
+ `repo_dir` helpers. Facade integration specs must override `execution_context`
298
+ to a `Git::ExecutionContext::Repository` (the shared context's default is
299
+ `repo.lib`, a `Git::Lib`). Stage any required repository state in a `before`
300
+ block inside the spec itself.
301
+
302
+ ```ruby
303
+ RSpec.describe Git::Repository::Stashing, :integration do
304
+ include_context 'in an empty repository' # provides repo and repo_dir helpers
305
+
306
+ let(:execution_context) { Git::ExecutionContext::Repository.from_base(repo) }
307
+ let(:described_instance) { Git::Repository.new(execution_context: execution_context) }
308
+
309
+ before do
310
+ write_file('README.md', 'initial')
311
+ repo.add('README.md')
312
+ repo.commit('Initial commit')
313
+ write_file('README.md', 'work in progress')
314
+ repo.add('README.md')
315
+ end
316
+
317
+ describe '#stash_save_and_list' do
318
+ it 'returns the new stash entry after saving' do
319
+ result = described_instance.stash_save_and_list(message: 'wip')
320
+ expect(result).to all(be_a(Git::Stash))
321
+ expect(result.first.message).to include('wip')
322
+ end
323
+ end
324
+ end
325
+ ```
326
+
327
+ One `context 'when the command succeeds'` block (or just `it` blocks directly
328
+ under `describe`) per facade method, with one or more variations that exercise
329
+ the orchestration sequence or post-processing. Do **not** add a `context 'when
330
+ the command fails'` block — error wrapping is the command's concern and is
331
+ covered by command integration tests.
332
+
333
+ #### What integration tests assert
334
+
335
+ - The Ruby return value's **structure and key fields** (e.g., classes,
336
+ required attributes, presence of expected entries).
337
+ - Multi-command orchestration produces the documented end-to-end value, not
338
+ intermediate command results.
339
+ - For signature-compatibility behavior that is user-visible at runtime,
340
+ integration coverage may assert that legacy call shapes are accepted.
341
+
342
+ #### Review checks for signature policy
343
+
344
+ When reviewing existing facade tests, add these checks:
345
+
346
+ 1. If the method is `legacy-contract`, unit tests cover required call shapes.
347
+ 2. Test expectations validate public contract behavior, not only command
348
+ delegation internals.
349
+
350
+ #### What integration tests do not assert
351
+
352
+ - Specific CLI tokens reaching git (covered by command unit tests).
353
+ - Specific git output formatting (testing git, not the facade).
354
+ - Edge cases that vary between git versions in immaterial ways. Anchor
355
+ assertions on stable inputs (paths, ref names) the test controls — not on git
356
+ message phrasing.
357
+
358
+ ## Workflow
359
+
360
+ 1. Load the [RSpec Unit Testing
361
+ Standards](../rspec-unit-testing-standards/SKILL.md) skill (line 1 through
362
+ EOF).
363
+ 2. Read the spec file(s) under review and the corresponding facade module
364
+ (`lib/git/repository/<topic>.rb`) plus the underlying `Git::Commands::*` and
365
+ `Git::Parsers::*` files the facade calls.
366
+ 3. Audit each spec against the rules in [Reference](#reference), checking unit
367
+ and integration tests separately.
368
+ 4. Produce the [Output](#output).
369
+
370
+ ## Output
371
+
372
+ ### When writing new facade tests
373
+
374
+ Produce the unit and (when applicable) integration spec files following the
375
+ patterns above. Then self-verify by running every checklist item in the
376
+ [Reference](#reference) section against your output.
377
+
378
+ ### When reviewing existing facade tests
379
+
380
+ Provide:
381
+
382
+ 1. issue table
383
+
384
+ | Check | Status | Issue |
385
+ | --- | --- | --- |
386
+
387
+ 2. corrected snippets for failing checks
388
+
389
+ 3. **Self-verify before concluding** — re-run the reference against your proposed
390
+ snippets until all checks pass.
391
+
392
+ > **Branch workflow:** Implement any new or updated tests on a feature branch.
393
+ > Never commit or push directly to `main` — open a pull request when changes are
394
+ > ready to merge.