git 5.0.0.beta.3 → 5.0.0.beta.4
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.
- checksums.yaml +4 -4
- data/.dockerignore +27 -0
- data/.github/copilot-instructions.md +3 -8
- data/.github/hooks/bin-setup-on-worktree.json +11 -0
- data/.github/hooks/run-bin-setup-once.sh +14 -0
- data/.github/skills/breaking-change-analysis/SKILL.md +6 -9
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +2 -2
- data/.github/skills/command-implementation/REFERENCE.md +34 -33
- data/.github/skills/command-implementation/SKILL.md +5 -4
- data/.github/skills/command-test-conventions/SKILL.md +13 -9
- data/.github/skills/command-yard-documentation/SKILL.md +14 -6
- data/.github/skills/development-workflow/SKILL.md +20 -14
- data/.github/skills/facade-implementation/REFERENCE.md +19 -22
- data/.github/skills/facade-implementation/SKILL.md +0 -5
- data/.github/skills/facade-test-conventions/SKILL.md +4 -7
- data/.github/skills/facade-yard-documentation/SKILL.md +8 -2
- data/.github/skills/make-skill-template/SKILL.md +53 -3
- data/.github/skills/pr-readiness-review/SKILL.md +22 -2
- data/.github/skills/project-context/SKILL.md +16 -23
- data/.github/skills/pull-request-review/SKILL.md +2 -2
- data/.github/skills/rebase/SKILL.md +148 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +1 -1
- data/.github/skills/resolve-feedback/SKILL.md +288 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +3 -3
- data/.github/skills/reviewing-skills/SKILL.md +28 -3
- data/.github/skills/test-debugging/SKILL.md +20 -19
- data/.github/skills/yard-documentation/SKILL.md +671 -483
- data/.github/skills/yard-documentation/element-rules.md +162 -0
- data/.github/skills-deprecated/README.md +21 -0
- data/.github/{skills → skills-deprecated}/extract-command-from-lib/SKILL.md +9 -9
- data/.github/{skills → skills-deprecated}/extract-facade-from-base-lib/SKILL.md +12 -12
- data/.github/workflows/continuous_integration.yml +3 -2
- data/.rubocop.yml +7 -39
- data/.yard-lint.yml +75 -0
- data/CONTRIBUTING.md +186 -174
- data/Gemfile +17 -0
- data/README.md +47 -12
- data/Rakefile +3 -21
- data/UPGRADING.md +219 -70
- data/docker/test/Dockerfile +32 -0
- data/docker/test/docker-compose.yml +0 -0
- data/git.gemspec +3 -4
- data/lib/git/author.rb +20 -1
- data/lib/git/branch.rb +26 -6
- data/lib/git/branch_delete_failure.rb +3 -0
- data/lib/git/branch_delete_result.rb +6 -3
- data/lib/git/branch_info.rb +6 -6
- data/lib/git/command_line/base.rb +6 -13
- data/lib/git/command_line/capturing.rb +67 -10
- data/lib/git/command_line/result.rb +0 -8
- data/lib/git/command_line/streaming.rb +45 -5
- data/lib/git/command_line.rb +4 -3
- data/lib/git/commands/add.rb +61 -53
- data/lib/git/commands/am/abort.rb +2 -2
- data/lib/git/commands/am/apply.rb +109 -98
- data/lib/git/commands/am/continue.rb +2 -2
- data/lib/git/commands/am/quit.rb +2 -2
- data/lib/git/commands/am/retry.rb +4 -2
- data/lib/git/commands/am/show_current_patch.rb +1 -1
- data/lib/git/commands/am/skip.rb +2 -2
- data/lib/git/commands/am.rb +2 -2
- data/lib/git/commands/apply.rb +7 -2
- data/lib/git/commands/archive/list_formats.rb +3 -3
- data/lib/git/commands/archive.rb +7 -2
- data/lib/git/commands/arguments.rb +1370 -359
- data/lib/git/commands/base.rb +111 -13
- data/lib/git/commands/branch/copy.rb +29 -21
- data/lib/git/commands/branch/create.rb +72 -68
- data/lib/git/commands/branch/delete.rb +25 -17
- data/lib/git/commands/branch/list.rb +76 -60
- data/lib/git/commands/branch/move.rb +29 -21
- data/lib/git/commands/branch/set_upstream.rb +8 -8
- data/lib/git/commands/branch/show_current.rb +3 -3
- data/lib/git/commands/branch/unset_upstream.rb +4 -8
- data/lib/git/commands/branch.rb +2 -2
- data/lib/git/commands/cat_file/batch.rb +36 -20
- data/lib/git/commands/cat_file/filtered.rb +12 -12
- data/lib/git/commands/cat_file/raw.rb +13 -13
- data/lib/git/commands/cat_file.rb +4 -4
- data/lib/git/commands/checkout/branch.rb +7 -5
- data/lib/git/commands/checkout/files.rb +5 -4
- data/lib/git/commands/checkout.rb +4 -4
- data/lib/git/commands/checkout_index.rb +5 -4
- data/lib/git/commands/clean.rb +6 -4
- data/lib/git/commands/clone.rb +5 -4
- data/lib/git/commands/commit.rb +5 -4
- data/lib/git/commands/commit_tree.rb +5 -4
- data/lib/git/commands/config_option_syntax/add.rb +7 -4
- data/lib/git/commands/config_option_syntax/get.rb +9 -5
- data/lib/git/commands/config_option_syntax/get_all.rb +7 -4
- data/lib/git/commands/config_option_syntax/get_color.rb +8 -4
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +7 -4
- data/lib/git/commands/config_option_syntax/get_regexp.rb +8 -4
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +8 -4
- data/lib/git/commands/config_option_syntax/list.rb +8 -4
- data/lib/git/commands/config_option_syntax/remove_section.rb +7 -2
- data/lib/git/commands/config_option_syntax/rename_section.rb +7 -2
- data/lib/git/commands/config_option_syntax/replace_all.rb +7 -2
- data/lib/git/commands/config_option_syntax/set.rb +7 -2
- data/lib/git/commands/config_option_syntax/unset.rb +7 -4
- data/lib/git/commands/config_option_syntax/unset_all.rb +7 -2
- data/lib/git/commands/describe.rb +5 -4
- data/lib/git/commands/diff.rb +13 -12
- data/lib/git/commands/diff_files.rb +7 -6
- data/lib/git/commands/diff_index.rb +10 -7
- data/lib/git/commands/fetch.rb +6 -4
- data/lib/git/commands/fsck.rb +6 -4
- data/lib/git/commands/gc.rb +6 -4
- data/lib/git/commands/grep.rb +6 -5
- data/lib/git/commands/init.rb +6 -4
- data/lib/git/commands/log.rb +287 -285
- data/lib/git/commands/ls_files.rb +69 -65
- data/lib/git/commands/ls_remote.rb +62 -56
- data/lib/git/commands/ls_tree.rb +50 -46
- data/lib/git/commands/maintenance/register.rb +25 -23
- data/lib/git/commands/maintenance/run.rb +7 -2
- data/lib/git/commands/maintenance/start.rb +7 -2
- data/lib/git/commands/maintenance/stop.rb +7 -2
- data/lib/git/commands/maintenance/unregister.rb +7 -2
- data/lib/git/commands/merge/abort.rb +2 -2
- data/lib/git/commands/merge/continue.rb +2 -2
- data/lib/git/commands/merge/quit.rb +2 -2
- data/lib/git/commands/merge/start.rb +7 -2
- data/lib/git/commands/merge.rb +2 -2
- data/lib/git/commands/merge_base.rb +7 -2
- data/lib/git/commands/mv.rb +7 -2
- data/lib/git/commands/name_rev.rb +7 -2
- data/lib/git/commands/pull.rb +7 -2
- data/lib/git/commands/push.rb +7 -2
- data/lib/git/commands/read_tree.rb +7 -2
- data/lib/git/commands/remote/add.rb +7 -2
- data/lib/git/commands/remote/get_url.rb +4 -2
- data/lib/git/commands/remote/list.rb +4 -2
- data/lib/git/commands/remote/prune.rb +4 -2
- data/lib/git/commands/remote/remove.rb +4 -2
- data/lib/git/commands/remote/rename.rb +4 -2
- data/lib/git/commands/remote/set_branches.rb +9 -2
- data/lib/git/commands/remote/set_head.rb +12 -5
- data/lib/git/commands/remote/set_url.rb +9 -2
- data/lib/git/commands/remote/set_url_add.rb +11 -2
- data/lib/git/commands/remote/set_url_delete.rb +9 -2
- data/lib/git/commands/remote/show.rb +18 -12
- data/lib/git/commands/remote/update.rb +19 -12
- data/lib/git/commands/remote.rb +2 -2
- data/lib/git/commands/repack.rb +67 -63
- data/lib/git/commands/reset.rb +51 -44
- data/lib/git/commands/rev_parse.rb +135 -128
- data/lib/git/commands/revert/abort.rb +2 -2
- data/lib/git/commands/revert/continue.rb +7 -2
- data/lib/git/commands/revert/quit.rb +2 -2
- data/lib/git/commands/revert/skip.rb +2 -2
- data/lib/git/commands/revert/start.rb +7 -2
- data/lib/git/commands/revert.rb +2 -2
- data/lib/git/commands/rm.rb +35 -36
- data/lib/git/commands/show.rb +1 -1
- data/lib/git/commands/show_ref/exclude_existing.rb +3 -4
- data/lib/git/commands/show_ref/exists.rb +15 -13
- data/lib/git/commands/show_ref/list.rb +39 -35
- data/lib/git/commands/show_ref/verify.rb +29 -27
- data/lib/git/commands/show_ref.rb +4 -4
- data/lib/git/commands/stash/apply.rb +31 -25
- data/lib/git/commands/stash/branch.rb +10 -8
- data/lib/git/commands/stash/clear.rb +7 -5
- data/lib/git/commands/stash/create.rb +10 -8
- data/lib/git/commands/stash/drop.rb +15 -9
- data/lib/git/commands/stash/list.rb +9 -5
- data/lib/git/commands/stash/pop.rb +21 -12
- data/lib/git/commands/stash/push.rb +20 -11
- data/lib/git/commands/stash/show.rb +21 -12
- data/lib/git/commands/stash/store.rb +19 -10
- data/lib/git/commands/stash.rb +2 -2
- data/lib/git/commands/status.rb +7 -2
- data/lib/git/commands/symbolic_ref/delete.rb +18 -14
- data/lib/git/commands/symbolic_ref/read.rb +24 -20
- data/lib/git/commands/symbolic_ref/update.rb +20 -17
- data/lib/git/commands/symbolic_ref.rb +4 -4
- data/lib/git/commands/tag/create.rb +45 -42
- data/lib/git/commands/tag/delete.rb +5 -3
- data/lib/git/commands/tag/list.rb +47 -44
- data/lib/git/commands/tag/verify.rb +12 -12
- data/lib/git/commands/tag.rb +2 -2
- data/lib/git/commands/update_ref/batch.rb +6 -1
- data/lib/git/commands/update_ref/delete.rb +19 -21
- data/lib/git/commands/update_ref/update.rb +22 -25
- data/lib/git/commands/update_ref.rb +4 -4
- data/lib/git/commands/version.rb +14 -11
- data/lib/git/commands/worktree/add.rb +50 -51
- data/lib/git/commands/worktree/list.rb +17 -17
- data/lib/git/commands/worktree/lock.rb +12 -12
- data/lib/git/commands/worktree/move.rb +16 -16
- data/lib/git/commands/worktree/prune.rb +2 -2
- data/lib/git/commands/worktree/remove.rb +2 -2
- data/lib/git/commands/worktree/repair.rb +2 -2
- data/lib/git/commands/worktree/unlock.rb +2 -2
- data/lib/git/commands/write_tree.rb +2 -2
- data/lib/git/commands.rb +4 -3
- data/lib/git/config.rb +47 -1
- data/lib/git/configuring.rb +89 -15
- data/lib/git/detached_head_info.rb +4 -1
- data/lib/git/diff.rb +2 -5
- data/lib/git/diff_file_numstat_info.rb +3 -1
- data/lib/git/diff_file_patch_info.rb +3 -1
- data/lib/git/diff_file_raw_info.rb +3 -1
- data/lib/git/diff_info.rb +8 -15
- data/lib/git/diff_path_status.rb +16 -3
- data/lib/git/diff_result.rb +3 -1
- data/lib/git/diff_stats.rb +15 -0
- data/lib/git/dirstat_info.rb +24 -8
- data/lib/git/encoding_utils.rb +32 -1
- data/lib/git/errors.rb +19 -9
- data/lib/git/escaped_path.rb +55 -3
- data/lib/git/execution_context/repository.rb +15 -0
- data/lib/git/execution_context.rb +76 -74
- data/lib/git/file_ref.rb +6 -3
- data/lib/git/fsck_object.rb +8 -0
- data/lib/git/fsck_result.rb +26 -15
- data/lib/git/log.rb +152 -5
- data/lib/git/object.rb +284 -8
- data/lib/git/parsers/branch.rb +18 -0
- data/lib/git/parsers/cat_file.rb +2 -2
- data/lib/git/parsers/diff.rb +213 -5
- data/lib/git/parsers/fsck.rb +11 -0
- data/lib/git/parsers/ls_remote.rb +1 -1
- data/lib/git/parsers/stash.rb +51 -0
- data/lib/git/parsers/tag.rb +38 -0
- data/lib/git/remote.rb +34 -2
- data/lib/git/repository/branching.rb +23 -21
- data/lib/git/repository/committing.rb +46 -6
- data/lib/git/repository/context_helpers.rb +45 -16
- data/lib/git/repository/diffing.rb +32 -23
- data/lib/git/repository/factories.rb +153 -28
- data/lib/git/repository/inspecting.rb +1 -1
- data/lib/git/repository/logging.rb +169 -30
- data/lib/git/repository/maintenance.rb +1 -1
- data/lib/git/repository/merging.rb +3 -3
- data/lib/git/repository/object_operations.rb +108 -14
- data/lib/git/repository/remote_operations.rb +150 -171
- data/lib/git/repository/shared_private.rb +7 -5
- data/lib/git/repository/staging.rb +36 -12
- data/lib/git/repository/stashing.rb +16 -16
- data/lib/git/repository/status_operations.rb +1 -1
- data/lib/git/repository/worktree_operations.rb +1 -1
- data/lib/git/repository.rb +123 -63
- data/lib/git/stash.rb +16 -21
- data/lib/git/stash_info.rb +4 -4
- data/lib/git/stashes.rb +20 -26
- data/lib/git/status.rb +21 -7
- data/lib/git/tag_delete_failure.rb +3 -0
- data/lib/git/tag_delete_result.rb +6 -3
- data/lib/git/tag_info.rb +1 -0
- data/lib/git/url.rb +12 -5
- data/lib/git/version.rb +6 -4
- data/lib/git/version_constraint.rb +4 -0
- data/lib/git.rb +398 -314
- data/redesign/3_architecture_implementation.md +59 -29
- data/redesign/Phase 4 - Step B.md +921 -0
- data/redesign/Phase 4 - Step C.md +833 -0
- data/redesign/c1a-public-api-scope.tsv +256 -0
- data/redesign/phase-4-step-b-test-audit.tsv +485 -0
- data/tasks/yard.rake +24 -17
- metadata +24 -57
- data/commitlint.test +0 -4
- data/lib/git/args_builder.rb +0 -103
- data/lib/git/command_line_result.rb +0 -8
- data/lib/git/deprecation.rb +0 -9
- data/tasks/test.rake +0 -25
- /data/.github/{skills → skills-deprecated}/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -0
- /data/.github/{skills → skills-deprecated}/review-backward-compatibility/SKILL.md +0 -0
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
# Phase 4 / Step B — Finalize Test Suite: Execution Plan
|
|
2
|
+
|
|
3
|
+
> **✅ Status: Complete.** W1 (the legacy-test audit) is **complete and verified**;
|
|
4
|
+
> its results are captured below and in the companion data file
|
|
5
|
+
> [`phase-4-step-b-test-audit.tsv`](phase-4-step-b-test-audit.tsv). **W1.5 (matrix
|
|
6
|
+
> enrichment) is complete and signed off** — the TSV now carries `disposition`,
|
|
7
|
+
> `target_spec`, and `port_status`; results are summarized in
|
|
8
|
+
> [W1.5 enrichment results](#w15-enrichment-results-for-sign-off). The one-time human
|
|
9
|
+
> sign-off that gates W2 has been **given**. Execution decisions are
|
|
10
|
+
> **resolved** (see [Resolved Decisions](#resolved-decisions)). **W-Doc (documentation
|
|
11
|
+
> salvage) is complete and merged** — the 4 `test_archive.rb` content cases were salvaged
|
|
12
|
+
> as YARD examples on `Git::Object#archive` / `Git::Branch#archive`. **W2 (port) is
|
|
13
|
+
> complete:** all **159 PORT rows** (down from the planned 192 after dedup) have been
|
|
14
|
+
> ported and merged across batches U1–U21 (final batch PR #1501) — see
|
|
15
|
+
> [W2 progress](#w2-progress). **W3** (remove Test::Unit infrastructure) **is merged** —
|
|
16
|
+
> PR #1502 removed `tests/units/`, tooling, and the `test-unit` gem dependency; PR #1503
|
|
17
|
+
> followed up with the `tests/files/` fixture deletion deferred from W3 due to the
|
|
18
|
+
> 300-file review limit. **W4a** (deprecate `extract-*` skills) **is merged** — PR #1504.
|
|
19
|
+
> **W4b** (remove Test::Unit documentation references) **is merged** — PR #1505. The
|
|
20
|
+
> **W6 plan** (remove stale `Git::Base`/`Git::Lib` skill references) **is merged** —
|
|
21
|
+
> PR #1506. **W5** (verify & finalize) is complete — gate is green: 5668 unit + 893 integration examples, 0 failures. **W6 execution** (remove stale `Git::Base`/`Git::Lib` skill references) is merged — [PR #1509](https://github.com/ruby-git/ruby-git/pull/1509).
|
|
22
|
+
|
|
23
|
+
## Goal
|
|
24
|
+
|
|
25
|
+
Make RSpec the **sole** test framework for the gem. Port every still-valuable
|
|
26
|
+
Test::Unit test in `tests/units/` to RSpec, then remove the legacy Test::Unit
|
|
27
|
+
suite, its tooling, its gem dependency, and all documentation references to it.
|
|
28
|
+
|
|
29
|
+
Source of truth in the implementation tracker:
|
|
30
|
+
[`3_architecture_implementation.md`](3_architecture_implementation.md) →
|
|
31
|
+
"Phase 4 → Step B — Finalize test suite".
|
|
32
|
+
|
|
33
|
+
This is the second half of Phase 4. [Step A](Phase%204%20-%20Step%20A.md) removed
|
|
34
|
+
the old `Git::Base` / `Git::Lib` code; Step B removes the old test framework that
|
|
35
|
+
those classes were originally written against.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Done-When Criteria
|
|
40
|
+
|
|
41
|
+
- The `tests/` directory is removed.
|
|
42
|
+
- `test-unit` is no longer a dependency in `git.gemspec`.
|
|
43
|
+
- RSpec is the sole test framework: no `test` / `test-all` Rake tasks, and
|
|
44
|
+
`rake default` is green without a Test::Unit step.
|
|
45
|
+
- No surviving runtime/tooling references to `bin/test*`, `tests/units`, or
|
|
46
|
+
`Test::Unit`. Historical/reference mentions are allowed only in `CHANGELOG.md`,
|
|
47
|
+
redesign historical docs, and `.github/skills-deprecated/`.
|
|
48
|
+
- All **unique** behavioral coverage from `tests/units/` now lives in `spec/`,
|
|
49
|
+
placed in the correct layer (logic in `spec/unit/`, real-git wiring in
|
|
50
|
+
`spec/integration/`), except rows explicitly classified as `intentional_drop`,
|
|
51
|
+
`document`, or `obsolete` in the enriched audit matrix (`document` rows are preserved
|
|
52
|
+
as documentation rather than specs).
|
|
53
|
+
- Full quality gate green: `bundle exec rake default:parallel`
|
|
54
|
+
(RSpec unit + integration + RuboCop + YARD + build).
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Testing Philosophy (governs the port)
|
|
59
|
+
|
|
60
|
+
Per the `rspec-unit-testing-standards` skill and the project's layering:
|
|
61
|
+
|
|
62
|
+
- **`spec/unit/`** — pure logic with **no external dependencies** (no real git,
|
|
63
|
+
no subprocesses). Externals are stubbed. Must achieve **100% branch coverage**.
|
|
64
|
+
This is where option/argument building, output parsing, value-object behavior,
|
|
65
|
+
error mapping, and deprecation-warning emission belong.
|
|
66
|
+
- **`spec/integration/`** — **minimal** checks that the layers are wired together
|
|
67
|
+
correctly against real git. These exist only to prove the facade → command →
|
|
68
|
+
subprocess path is connected; they do not re-test logic already covered by unit
|
|
69
|
+
specs, and they do not recreate the legacy exhaustive matrices.
|
|
70
|
+
|
|
71
|
+
The W1 audit assigns every PORT case a `target_layer` according to this philosophy,
|
|
72
|
+
so the bulk of legacy "integration-style" assertions collapse into unit specs, with
|
|
73
|
+
only a thin residue remaining as true integration checks.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## W1 — Audit & Categorize (✅ complete, verified)
|
|
78
|
+
|
|
79
|
+
Every legacy test was classified at **per-test-method granularity**, not per file: a
|
|
80
|
+
file-level verdict would hide the common case where a file mixes already-covered
|
|
81
|
+
methods with one or two methods carrying unique coverage — and a file is only safe to
|
|
82
|
+
delete if *every* method in it is covered.
|
|
83
|
+
|
|
84
|
+
All **484 individual test cases** (307 `def test_*` methods + 177 declarative
|
|
85
|
+
`test '...' do` macros, across 70 files) received their own verdict. The full matrix
|
|
86
|
+
is persisted as [`phase-4-step-b-test-audit.tsv`](phase-4-step-b-test-audit.tsv).
|
|
87
|
+
The **W1 baseline** carried 10 columns (`file, line, style, test_name,
|
|
88
|
+
initial_verdict, final_verdict, target_layer, spec_coverage, verify_notes, behavior`);
|
|
89
|
+
**W1.5 enrichment appended three more** (`disposition, target_spec, port_status`), so the
|
|
90
|
+
file on disk is now the enriched **13-column** version — see
|
|
91
|
+
[W1.5 enrichment results](#w15-enrichment-results-for-sign-off).
|
|
92
|
+
|
|
93
|
+
The audit ran in two passes:
|
|
94
|
+
|
|
95
|
+
1. **First pass** — each case classified REDUNDANT (covered by existing specs, or
|
|
96
|
+
intentionally dropped/obsolete) or PORT (unique coverage). When a single existing spec
|
|
97
|
+
cleanly covers a REDUNDANT case, that spec is cited in `spec_coverage`; when coverage
|
|
98
|
+
is **diffuse across multiple specs**, or the case is an **intentional drop / obsolete**,
|
|
99
|
+
`spec_coverage` is `none` and the citation or rationale lives in `verify_notes`. W1.5's
|
|
100
|
+
`disposition` column formalizes the covered / intentional_drop / obsolete distinction.
|
|
101
|
+
2. **Layer-aware verification pass** — re-checked every verdict against the testing
|
|
102
|
+
philosophy above, assigning each PORT a `target_layer` (`unit` vs `integration`)
|
|
103
|
+
and correcting verdicts that the first pass got wrong.
|
|
104
|
+
|
|
105
|
+
### Verified totals
|
|
106
|
+
|
|
107
|
+
These are the **W1** outputs (first pass + verification). W1.5 enrichment later reconciled
|
|
108
|
+
them to **292 REDUNDANT / 192 PORT** (4 archive cases flipped PORT → `document`) — see
|
|
109
|
+
[W1.5 enrichment results](#w15-enrichment-results-for-sign-off).
|
|
110
|
+
|
|
111
|
+
| Verdict | Count | Meaning |
|
|
112
|
+
| --- | ---: | --- |
|
|
113
|
+
| **REDUNDANT** | **288** | Already covered, intentionally dropped, or obsolete → classify with `disposition` before deleting |
|
|
114
|
+
| **PORT → unit** | **158** | Unique logic → add a mocked `spec/unit/` example |
|
|
115
|
+
| **PORT → integration** | **38** | Genuinely needs real git/process → add a *minimal* `spec/integration/` example |
|
|
116
|
+
| **PORT (total)** | **196** | |
|
|
117
|
+
|
|
118
|
+
### Verification corrected 56 verdicts vs. the first pass
|
|
119
|
+
|
|
120
|
+
- **49 PORT → REDUNDANT** — the first pass over-counted; the logic is already
|
|
121
|
+
unit-covered by command/parser/value-object specs, so no heavy end-to-end port is
|
|
122
|
+
warranted.
|
|
123
|
+
- **7 REDUNDANT → PORT** — real coverage gaps the first pass would have **silently
|
|
124
|
+
deleted**:
|
|
125
|
+
- `test_fsck_result.rb:6,36,49` — `Git::FsckResult#initialize` defaults, `#empty?`,
|
|
126
|
+
and `#any_issues?` have no direct unit spec.
|
|
127
|
+
- `test_log.rb:153`, `test_log_execute.rb:134` — `Git::Log#merges` lacks unit
|
|
128
|
+
coverage.
|
|
129
|
+
- `test_status.rb:155,172` — `Git::Status#untracked` collection logic is only
|
|
130
|
+
touched by integration, with no unit coverage.
|
|
131
|
+
|
|
132
|
+
All seven target the **unit** layer and should be prioritized in W2 because they
|
|
133
|
+
close genuine holes.
|
|
134
|
+
|
|
135
|
+
### Files deletable outright
|
|
136
|
+
|
|
137
|
+
**20 files are 100% REDUNDANT** — every case in them is already covered, so they can
|
|
138
|
+
be deleted with no porting:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
test_checkout_index.rb test_ignored_files_with_escaped_path.rb
|
|
142
|
+
test_command_line_result.rb test_index_ops.rb
|
|
143
|
+
test_command_raises_on_failure.rb test_ls_files_with_escaped_path.rb
|
|
144
|
+
test_describe.rb test_ls_tree.rb
|
|
145
|
+
test_each_conflict.rb test_merge.rb
|
|
146
|
+
test_git_binary_version.rb test_merge_base.rb
|
|
147
|
+
test_git_clone.rb test_pull.rb
|
|
148
|
+
test_git_default_branch.rb test_repack.rb
|
|
149
|
+
test_git_path.rb test_show.rb
|
|
150
|
+
test_tags.rb
|
|
151
|
+
test_tree_ops.rb
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Per-file verdict roll-up
|
|
155
|
+
|
|
156
|
+
Counts are the **post-W1.5 enriched** `REDUNDANT / PORT-unit / PORT-integration / total`.
|
|
157
|
+
Use the TSV for the exact line numbers, behaviors, and verification notes behind each
|
|
158
|
+
count.
|
|
159
|
+
|
|
160
|
+
| File | Red | Unit | Integ | Total |
|
|
161
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
162
|
+
| test_archive.rb | 7 | 1 | 0 | 8 |
|
|
163
|
+
| test_bare.rb | 0 | 0 | 1 | 1 |
|
|
164
|
+
| test_branch.rb | 18 | 0 | 2 | 20 |
|
|
165
|
+
| test_checkout.rb | 8 | 1 | 1 | 10 |
|
|
166
|
+
| test_checkout_index.rb | 8 | 0 | 0 | 8 |
|
|
167
|
+
| test_command_line.rb | 8 | 4 | 5 | 17 |
|
|
168
|
+
| test_command_line_env_overrides.rb | 0 | 14 | 0 | 14 |
|
|
169
|
+
| test_command_line_error.rb | 0 | 2 | 0 | 2 |
|
|
170
|
+
| test_command_line_result.rb | 1 | 0 | 0 | 1 |
|
|
171
|
+
| test_command_raises_on_failure.rb | 4 | 0 | 0 | 4 |
|
|
172
|
+
| test_commit_with_empty_message.rb | 0 | 0 | 2 | 2 |
|
|
173
|
+
| test_commit_with_gpg.rb | 3 | 1 | 0 | 4 |
|
|
174
|
+
| test_config.rb | 4 | 0 | 1 | 5 |
|
|
175
|
+
| test_deprecations.rb | 9 | 10 | 0 | 19 |
|
|
176
|
+
| test_describe.rb | 2 | 0 | 0 | 2 |
|
|
177
|
+
| test_diff.rb | 6 | 11 | 1 | 18 |
|
|
178
|
+
| test_diff_non_default_encoding.rb | 0 | 0 | 2 | 2 |
|
|
179
|
+
| test_diff_path_status.rb | 7 | 1 | 0 | 8 |
|
|
180
|
+
| test_diff_stats.rb | 6 | 1 | 0 | 7 |
|
|
181
|
+
| test_diff_with_escaped_path.rb | 0 | 1 | 0 | 1 |
|
|
182
|
+
| test_each_conflict.rb | 3 | 0 | 0 | 3 |
|
|
183
|
+
| test_escaped_path.rb | 2 | 3 | 0 | 5 |
|
|
184
|
+
| test_failed_error.rb | 0 | 2 | 0 | 2 |
|
|
185
|
+
| test_fsck.rb | 27 | 3 | 0 | 30 |
|
|
186
|
+
| test_fsck_object.rb | 1 | 3 | 0 | 4 |
|
|
187
|
+
| test_fsck_result.rb | 0 | 10 | 0 | 10 |
|
|
188
|
+
| test_git_alt_uri.rb | 0 | 3 | 0 | 3 |
|
|
189
|
+
| test_git_binary_version.rb | 3 | 0 | 0 | 3 |
|
|
190
|
+
| test_git_clone.rb | 7 | 0 | 0 | 7 |
|
|
191
|
+
| test_git_default_branch.rb | 2 | 0 | 0 | 2 |
|
|
192
|
+
| test_git_dir.rb | 1 | 1 | 1 | 3 |
|
|
193
|
+
| test_git_path.rb | 5 | 0 | 0 | 5 |
|
|
194
|
+
| test_ignored_files_with_escaped_path.rb | 1 | 0 | 0 | 1 |
|
|
195
|
+
| test_index_ops.rb | 7 | 0 | 0 | 7 |
|
|
196
|
+
| test_init.rb | 16 | 1 | 0 | 17 |
|
|
197
|
+
| test_log.rb | 5 | 14 | 0 | 19 |
|
|
198
|
+
| test_log_execute.rb | 5 | 16 | 0 | 21 |
|
|
199
|
+
| test_logger.rb | 0 | 2 | 0 | 2 |
|
|
200
|
+
| test_ls_files_with_escaped_path.rb | 1 | 0 | 0 | 1 |
|
|
201
|
+
| test_ls_tree.rb | 1 | 0 | 0 | 1 |
|
|
202
|
+
| test_merge.rb | 5 | 0 | 0 | 5 |
|
|
203
|
+
| test_merge_base.rb | 6 | 0 | 0 | 6 |
|
|
204
|
+
| test_object.rb | 10 | 1 | 0 | 11 |
|
|
205
|
+
| test_object_new.rb | 1 | 2 | 0 | 3 |
|
|
206
|
+
| test_per_instance_config.rb | 2 | 1 | 0 | 3 |
|
|
207
|
+
| test_pull.rb | 6 | 0 | 0 | 6 |
|
|
208
|
+
| test_push.rb | 18 | 0 | 2 | 20 |
|
|
209
|
+
| test_remotes.rb | 21 | 1 | 0 | 22 |
|
|
210
|
+
| test_repack.rb | 1 | 0 | 0 | 1 |
|
|
211
|
+
| test_rm.rb | 8 | 0 | 1 | 9 |
|
|
212
|
+
| test_set_index.rb | 3 | 1 | 1 | 5 |
|
|
213
|
+
| test_set_working.rb | 3 | 1 | 0 | 4 |
|
|
214
|
+
| test_show.rb | 1 | 0 | 0 | 1 |
|
|
215
|
+
| test_signaled_error.rb | 0 | 2 | 0 | 2 |
|
|
216
|
+
| test_signed_commits.rb | 0 | 0 | 1 | 1 |
|
|
217
|
+
| test_stash_list.rb | 6 | 0 | 1 | 7 |
|
|
218
|
+
| test_stash_save.rb | 2 | 0 | 1 | 3 |
|
|
219
|
+
| test_stashes.rb | 4 | 0 | 1 | 5 |
|
|
220
|
+
| test_status.rb | 2 | 10 | 2 | 14 |
|
|
221
|
+
| test_status_object.rb | 0 | 12 | 0 | 12 |
|
|
222
|
+
| test_status_object_empty_repo.rb | 0 | 12 | 0 | 12 |
|
|
223
|
+
| test_submodule.rb | 0 | 0 | 2 | 2 |
|
|
224
|
+
| test_tags.rb | 2 | 0 | 0 | 2 |
|
|
225
|
+
| test_thread_safety.rb | 0 | 0 | 1 | 1 |
|
|
226
|
+
| test_timeout_error.rb | 0 | 2 | 0 | 2 |
|
|
227
|
+
| test_tree_ops.rb | 8 | 0 | 0 | 8 |
|
|
228
|
+
| test_url_clone_to.rb | 0 | 4 | 0 | 4 |
|
|
229
|
+
| test_url_parse.rb | 0 | 3 | 0 | 3 |
|
|
230
|
+
| test_windows_cmd_escaping.rb | 0 | 1 | 0 | 1 |
|
|
231
|
+
| test_worktree.rb | 5 | 0 | 5 | 10 |
|
|
232
|
+
| **Total** | **292** | **158** | **34** | **484** |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Current State (audit findings)
|
|
237
|
+
|
|
238
|
+
- **70** Test::Unit files remain in `tests/units/` (~8,300 lines total).
|
|
239
|
+
- `spec/` already has ~361 spec files; earlier Step A PRs (3a/3b) already deleted the
|
|
240
|
+
`Git::Base` / `Git::Lib`-only Test::Unit files and patched incidental references.
|
|
241
|
+
- **RSpec does NOT depend on `tests/files/` fixtures** — no spec references those
|
|
242
|
+
paths (only stale *comments* point at `tests/units/...`). `tests/files/` can be
|
|
243
|
+
deleted once porting is done.
|
|
244
|
+
- **5 spec files explicitly defer integration coverage to Test::Unit** (high-priority
|
|
245
|
+
porting targets; their comments say "full integration is covered by
|
|
246
|
+
tests/units/..."):
|
|
247
|
+
- `spec/unit/git/object_spec.rb` → `tests/units/test_object.rb`
|
|
248
|
+
- `spec/unit/git/stash_spec.rb`, `spec/unit/git/stashes_spec.rb` → `test_stashes.rb`
|
|
249
|
+
- `spec/unit/git/repository/diffing_spec.rb` +
|
|
250
|
+
`spec/integration/.../diffing_spec.rb` → `test_diff_path_status.rb`,
|
|
251
|
+
`test_diff_stats.rb`
|
|
252
|
+
- `bin/command_line_test` is a fixture script used **only** by
|
|
253
|
+
`tests/units/test_command_line.rb`; its fate is decided when that test is ported.
|
|
254
|
+
|
|
255
|
+
### Infrastructure / tooling inventory to remove or update
|
|
256
|
+
|
|
257
|
+
| Item | Action |
|
|
258
|
+
| --- | --- |
|
|
259
|
+
| `tests/units/` (70 files) | Port unique coverage, pass pre-delete verification, then delete |
|
|
260
|
+
| `tests/files/` (fixtures) | Delete (RSpec doesn't use them — verify per-fixture) |
|
|
261
|
+
| `tests/Dockerfile`, `tests/docker-compose.yml` | Move to `docker/test/Dockerfile` and `docker/test/docker-compose.yml`; repoint at RSpec |
|
|
262
|
+
| `bin/test`, `bin/test-verbose` | Delete |
|
|
263
|
+
| `bin/test-in-docker` | Rename to `bin/spec-in-docker`; repoint at RSpec entrypoint |
|
|
264
|
+
| `bin/command_line_test` | Relocate into the RSpec support tree (kept as a real shell-out fixture) |
|
|
265
|
+
| `tasks/test.rake` (`test`, `test:parallel`) | Delete |
|
|
266
|
+
| `Rakefile` (`test-all`, `test-all:parallel`, default task lists) | Update to drop `test` |
|
|
267
|
+
| `git.gemspec` (`test-unit ~> 3.7`) | Remove |
|
|
268
|
+
| `.github/copilot-instructions.md` (commands table, suite description) | Update |
|
|
269
|
+
| `CONTRIBUTING.md` (Test::Unit sections, `bin/test` usage) | Update |
|
|
270
|
+
| Skills referencing Test::Unit / `bin/test` / `tests/units` | Update |
|
|
271
|
+
| `.github/workflows/*` | Verify `rake default` still green; no direct `bin/test` calls (currently none) |
|
|
272
|
+
|
|
273
|
+
Skills with Test::Unit references to reconcile: `extract-command-from-lib`,
|
|
274
|
+
`extract-facade-from-base-lib`, `project-context`, `test-debugging`,
|
|
275
|
+
`development-workflow`, `ci-cd-troubleshooting`, `command-test-conventions`.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Workstreams & Sequencing
|
|
280
|
+
|
|
281
|
+
```mermaid
|
|
282
|
+
flowchart LR
|
|
283
|
+
W1["W1 (audit ✅)"] --> W15["W1.5 (enrich matrix ✅)"]
|
|
284
|
+
W15 --> W2["W2 (port ✅)"]
|
|
285
|
+
W15 --> WDoc["W-Doc (documentation salvage ✅)"]
|
|
286
|
+
W2 --> W3["W3 (remove infra ✅)"]
|
|
287
|
+
WDoc --> W3
|
|
288
|
+
W3 --> W4b["W4b (TU docs ✅)"]
|
|
289
|
+
W4b --> W5["W5 (verify/finalize ✅)"]
|
|
290
|
+
W4a["W4a (deprecate extract-* skills ✅)"] --> W5
|
|
291
|
+
W6["W6 (plan ✅ / exec ✅)"]
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
- **W1.5 → W2** is a hard one-time gate: the human signs off the enriched matrix once
|
|
295
|
+
before any porting starts.
|
|
296
|
+
- **W2 → W3 → W4b → W5** run in order (W4b's doc claims only become true after W3
|
|
297
|
+
deletes `tests/`).
|
|
298
|
+
- **W-Doc** (documentation salvage of `disposition = document` rows) is gated by the same
|
|
299
|
+
W1.5 sign-off and may run in parallel with W2, but **must merge before W3** — W3 deletes
|
|
300
|
+
`tests/units/`, so the source examples must already be relocated to docs.
|
|
301
|
+
- **W4a** (retiring the finished `extract-*` skills) is independent of W2/W3 and may
|
|
302
|
+
land at any time; W5 waits on W4a as well so the final verification sees the retired
|
|
303
|
+
skills.
|
|
304
|
+
|
|
305
|
+
### W1.5 — Enrich audit matrix for execution (before W2)
|
|
306
|
+
|
|
307
|
+
Before any W2 porting starts, extend the audit matrix so an agent can execute without
|
|
308
|
+
guessing and the human reviewer can validate each case quickly.
|
|
309
|
+
|
|
310
|
+
- Add a **`disposition`** column for non-ported rows. Keep `final_verdict` stable unless
|
|
311
|
+
the W1.5 sign-off explicitly approves a verdict flip (as it did for the 4 archive
|
|
312
|
+
`document` rows), and distinguish why a REDUNDANT row is safe to delete:
|
|
313
|
+
- `covered` — behavior is already covered by an existing cited spec.
|
|
314
|
+
- `intentional_drop` — behavior is deliberately not ported because it is flaky,
|
|
315
|
+
obsolete, an exhaustive real-git matrix, or otherwise outside the RSpec testing
|
|
316
|
+
philosophy, **and** the example carries no residual user value.
|
|
317
|
+
- `document` — the case is **not** kept as a spec, but its *usage example* has
|
|
318
|
+
user-facing value, so it is converted into documentation (a YARD `@example` or a
|
|
319
|
+
README usage section) instead of being discarded. This is an `intentional_drop` whose
|
|
320
|
+
"how" is worth preserving; W-Doc relocates it.
|
|
321
|
+
- `obsolete` — behavior no longer applies after the architectural redesign.
|
|
322
|
+
PORT rows may use `port` or leave `disposition` blank.
|
|
323
|
+
|
|
324
|
+
**Pass-through vs. parse rule (when content checks become `intentional_drop` /
|
|
325
|
+
`document`).** A legacy test that asserts on the *content* git produces is testing
|
|
326
|
+
**git**, not the gem, when the gem is a pure **pass-through** — it forwards options as
|
|
327
|
+
CLI flags and hands back git's bytes without inspecting them (e.g. `archive` writes a
|
|
328
|
+
tar/tgz the gem never parses). Once that gem's option→flag forwarding is unit-covered
|
|
329
|
+
and its byte-capture-to-file is integration-covered, the residual content assertion adds
|
|
330
|
+
no gem coverage → classify it `intentional_drop`, or `document` when the example teaches
|
|
331
|
+
the user something. When the gem instead **parses or transforms** git output into Ruby
|
|
332
|
+
objects (diff, status, log, branch/tag metadata, encoding, fsck), the content assertion
|
|
333
|
+
exercises the gem's parser → keep it as **PORT**. Flag any PORT→REDUNDANT flip this rule
|
|
334
|
+
produces for the one-time enriched-matrix sign-off.
|
|
335
|
+
- Add a **`target_spec`** column naming the **destination** for every actionable row. For
|
|
336
|
+
PORT rows it is a spec path — prefer extending an existing spec file that mirrors the
|
|
337
|
+
source under test; only create a new spec file when no suitable target exists. For
|
|
338
|
+
`document` rows it is the **doc destination** instead, written as `yard:<Class>#<method>`
|
|
339
|
+
(add/extend a YARD `@example`) or `readme:<section>` (a README usage section). The
|
|
340
|
+
`disposition` value disambiguates how to read the column, so no separate doc column is
|
|
341
|
+
needed. This is required before W2 so placement is deterministic and reviewable.
|
|
342
|
+
- **Split rows by destination, not by individual example.** The unit of work is a
|
|
343
|
+
**destination** — one `(target_layer, target_spec)` pair — and a single row may produce
|
|
344
|
+
**multiple `it` examples** in that one spec (porting a legacy test is rarely 1:1 with a
|
|
345
|
+
single example; those examples are reviewed, committed, and tracked together as one row).
|
|
346
|
+
Split a legacy test into multiple rows **only when it maps to more than one
|
|
347
|
+
destination**:
|
|
348
|
+
- **Multiple specs, same layer** (e.g. its examples belong in two different `spec/unit/`
|
|
349
|
+
files) → one row per `target_spec`.
|
|
350
|
+
- **Multiple layers** — a single legacy test can exercise both logic (→ a mocked
|
|
351
|
+
`spec/unit/` example) and real-git wiring (→ a minimal `spec/integration/` example) →
|
|
352
|
+
one row per layer. The layer-aware W1 pass already assigned PORT to the one layer with
|
|
353
|
+
a genuine gap and marked the other layer's behavior as already-covered, so the 196
|
|
354
|
+
starting rows each carry a single `target_layer`; this is the escape hatch if
|
|
355
|
+
enrichment or W2 finds a case that truly needs both.
|
|
356
|
+
|
|
357
|
+
To split, **add one matrix row per `(target_layer, target_spec)`** — duplicate `file`,
|
|
358
|
+
`line`, and `test_name`, give each row its own `target_layer` / `target_spec` /
|
|
359
|
+
`port_status`, and cross-reference the siblings in `verify_notes`. This preserves the
|
|
360
|
+
core invariant that **one row = one destination (`target_layer` + `target_spec`) = one
|
|
361
|
+
review gate = one commit = one `port_status`** (the mirror image of the dedup/`grouped`
|
|
362
|
+
rule, which merges rows). A single row never spans more than one destination.
|
|
363
|
+
- Add a **`port_status`** column — the single, authoritative progress tracker for every
|
|
364
|
+
actionable row (PORT rows in W2, and `document` rows in W-Doc). It lives **only** in
|
|
365
|
+
this TSV; the prose plans (this document and the session plan) describe the protocol but
|
|
366
|
+
never maintain their own per-row status, so there is exactly one source of truth.
|
|
367
|
+
Initialize it during W1.5:
|
|
368
|
+
- PORT and `document` rows → `pending`.
|
|
369
|
+
- `covered` / `intentional_drop` / `obsolete` rows → leave blank (their fate is governed
|
|
370
|
+
by `disposition`; no further action follows).
|
|
371
|
+
See [W2](#w2--port-unique-coverage-to-rspec-batched-prs) and
|
|
372
|
+
[W-Doc](#w-doc--documentation-salvage-disposition--document) for exactly when the agent
|
|
373
|
+
advances each value.
|
|
374
|
+
- Define W2 PR batches from `target_spec` / component groupings. A batch must contain
|
|
375
|
+
**no more than 10 matrix rows** (the cap counts *work items / examples*, i.e. enriched
|
|
376
|
+
matrix rows after any splits and approved merges — not original legacy tests). If a
|
|
377
|
+
target spec has more than 10 rows, split it into multiple PRs by method/context so each
|
|
378
|
+
review remains small.
|
|
379
|
+
- For integration rows, pre-identify likely deduplication groups where multiple legacy
|
|
380
|
+
rows can be satisfied by one minimal wiring example. These groups are proposals only;
|
|
381
|
+
W2 still requires explicit reviewer approval before grouping rows.
|
|
382
|
+
|
|
383
|
+
**Done-when (hard gate before any W2 porting begins):**
|
|
384
|
+
|
|
385
|
+
- Every PORT row has a non-empty `target_spec`, and any case needing more than one layer
|
|
386
|
+
has been split into one row per `(target_layer, target_spec)`.
|
|
387
|
+
- Every non-PORT row has a `disposition` (`covered`, `intentional_drop`, `document`, or
|
|
388
|
+
`obsolete`); every `document` row has a `target_spec` doc destination.
|
|
389
|
+
- Every PORT row and every `document` row has `port_status = pending`; proposed dedup
|
|
390
|
+
groups are recorded.
|
|
391
|
+
- The proposed W2 batches (≤ 10 matrix rows each) are listed, and the final PORT
|
|
392
|
+
work-item count (after splits/merges) is reconciled in the TSV — the 196 figure is the
|
|
393
|
+
W1 starting count and may shift during enrichment.
|
|
394
|
+
- **The human reviewer approves the enrichment once, before W2 starts — reviewing a
|
|
395
|
+
generated review summary, not the raw 484-row TSV.** A line-by-line read of the matrix
|
|
396
|
+
is not an effective review, so the gate artifact is a concise summary
|
|
397
|
+
([W1.5 enrichment results](#w15-enrichment-results-for-sign-off)) that surfaces only the
|
|
398
|
+
decisions that carry risk: every PORT→REDUNDANT verdict flip, every `intentional_drop`
|
|
399
|
+
and `obsolete` row, every `document` row and its doc target, and every **new** spec file
|
|
400
|
+
the ports will create. The bulk `covered` and ordinary `port` rows are summarized in
|
|
401
|
+
aggregate, not individually. This front-loads the placement/disposition decisions into a
|
|
402
|
+
single review so they are not re-litigated at the per-case gates. W2 MUST NOT begin
|
|
403
|
+
until this approval is given.
|
|
404
|
+
|
|
405
|
+
#### W1.5 enrichment results (for sign-off)
|
|
406
|
+
|
|
407
|
+
The full pass is complete; the enriched TSV has 13 columns (`disposition`, `target_spec`,
|
|
408
|
+
`port_status` appended). Reconciled totals:
|
|
409
|
+
|
|
410
|
+
| Metric | W1 start | After W1.5 |
|
|
411
|
+
| --- | ---: | ---: |
|
|
412
|
+
| PORT | 196 | **192** |
|
|
413
|
+
| REDUNDANT | 288 | **292** |
|
|
414
|
+
| — of which `covered` | — | 287 |
|
|
415
|
+
| — of which `document` | — | 4 |
|
|
416
|
+
| — of which `intentional_drop` | — | 1 |
|
|
417
|
+
| Rows with `port_status = pending` (PORT + document) | — | 196 |
|
|
418
|
+
|
|
419
|
+
**Verdict flips to review (the risk surface):**
|
|
420
|
+
|
|
421
|
+
- **4 PORT → REDUNDANT/`document`** — all `test_archive.rb` content-validation cases, by
|
|
422
|
+
the pass-through rule (the gem forwards `--format`/`--prefix` and hands back git's bytes
|
|
423
|
+
it never inspects; forwarding is unit-covered, byte-capture is integration-covered).
|
|
424
|
+
Salvaged as YARD examples: L41/62/80 → `yard:Git::Object#archive`, L93 →
|
|
425
|
+
`yard:Git::Branch#archive`.
|
|
426
|
+
- **1 `intentional_drop`** — `test_git_clone.rb:15` (flaky real-clone global-timeout test;
|
|
427
|
+
timeout plumbing is unit-covered by the ExecutionContext/CommandLine specs).
|
|
428
|
+
- **0 `obsolete`.**
|
|
429
|
+
|
|
430
|
+
**New spec files the ports will create** (no existing mirror; all error/cross-cutting):
|
|
431
|
+
`spec/unit/git/command_line_error_spec.rb` (2 rows),
|
|
432
|
+
`spec/unit/git/escaped_path_spec.rb` (3), `spec/unit/git/failed_error_spec.rb` (2),
|
|
433
|
+
`spec/unit/git/signaled_error_spec.rb` (2), `spec/unit/git/timeout_error_spec.rb` (2),
|
|
434
|
+
`spec/integration/git/thread_safety_spec.rb` (1). All other 180 PORT rows extend an
|
|
435
|
+
existing spec.
|
|
436
|
+
|
|
437
|
+
**Proposed dedup group (needs reviewer approval in W2):** `test_log.rb` and
|
|
438
|
+
`test_log_execute.rb` carry the same 14 query-builder test names, both targeting
|
|
439
|
+
`spec/unit/git/log_spec.rb`; they are near-duplicate sources that likely collapse to one
|
|
440
|
+
set of examples (`test_log_execute.rb` adds 2 unique `#execute` snapshot/empty-repo cases).
|
|
441
|
+
Recorded as a proposal; rows are not pre-merged.
|
|
442
|
+
|
|
443
|
+
**Initial W2 batch plan** (all row counts are enriched matrix rows before deduplication
|
|
444
|
+
is approved by a reviewer; each batch stays at or below the 10-row cap):
|
|
445
|
+
|
|
446
|
+
| Batch | Scope | Rows | Status |
|
|
447
|
+
| --- | --- | ---: | --- |
|
|
448
|
+
| U1 | CommandLine base/capturing/error rows | 9 | ✅ merged |
|
|
449
|
+
| U2 | Git error objects (`FailedError`, `SignaledError`, `TimeoutError`) | 6 | ✅ merged |
|
|
450
|
+
| U3 | `Diff` unit rows, first chunk | 10 | ✅ merged |
|
|
451
|
+
| U4 | `Diff` remainder plus path/status/stats/escaped-path rows | 7 | ✅ merged |
|
|
452
|
+
| U5 | `ExecutionContext` environment override rows, first chunk | 7 | ✅ merged |
|
|
453
|
+
| U6 | `ExecutionContext` remainder plus config/init/path-resolver rows | 10 | ✅ merged |
|
|
454
|
+
| U7 | Git remote URL utilities | 10 | ✅ merged |
|
|
455
|
+
| U8 | `Log` deprecation rows plus first `test_log.rb` chunk | 10 | ✅ merged |
|
|
456
|
+
| U9 | `Log` remaining `test_log.rb` rows | 10 | ✅ merged |
|
|
457
|
+
| U10 | `Log#execute` snapshot/empty-repo rows (deduped against `test_log.rb`) | 10 | ✅ merged |
|
|
458
|
+
| U11 | `Log#execute` remainder | 6 | ➖ folded into U10 (dedup) |
|
|
459
|
+
| U12 | Object/repository/remote miscellaneous rows | 10 | ✅ merged |
|
|
460
|
+
| U13 | Repository staging/committing rows | 3 | ✅ merged |
|
|
461
|
+
| U14 | `Fsck` parser rows, first chunk | 10 | ✅ merged |
|
|
462
|
+
| U15 | `Fsck` parser remainder | 6 | ✅ merged |
|
|
463
|
+
| U16 | `Status` facade rows plus ignore-case rows | 10 | ✅ merged |
|
|
464
|
+
| U17 | `StatusFile` rows, first chunk | 10 | ✅ merged |
|
|
465
|
+
| U18 | `StatusFile` remainder plus empty-repo first chunk | 10 | ✅ merged |
|
|
466
|
+
| U19 | `StatusFile` empty-repo remainder | 4 | ✅ merged |
|
|
467
|
+
| U20 | Signed-commits, stash, status, submodule integration rows | 9 | ✅ merged |
|
|
468
|
+
| U21 | Thread-safety, worktree integration rows (final batch) | 14 | ✅ merged (PR #1501) |
|
|
469
|
+
| I1 | Command-line subprocess integration rows | 5 | ✅ merged (folded into U batches) |
|
|
470
|
+
| I2 | Branch/checkout integration rows | 3 | ✅ merged (folded into U batches) |
|
|
471
|
+
| I3 | Commit/config/remote integration rows | 7 | ✅ merged (folded into U batches) |
|
|
472
|
+
| I4 | Diff/status/staging integration rows | 7 | ✅ merged (folded into U batches) |
|
|
473
|
+
| I5 | Object/stash/submodule integration rows | 6 | ✅ merged (folded into U batches) |
|
|
474
|
+
| I6 | Worktree/thread-safety integration rows | 6 | ✅ merged (folded into U batches) |
|
|
475
|
+
|
|
476
|
+
### W2 — Port unique coverage to RSpec (batched PRs)
|
|
477
|
+
|
|
478
|
+
#### W2 progress
|
|
479
|
+
|
|
480
|
+
Snapshot from the authoritative `port_status` column in
|
|
481
|
+
[`phase-4-step-b-test-audit.tsv`](phase-4-step-b-test-audit.tsv):
|
|
482
|
+
|
|
483
|
+
| Metric | Rows |
|
|
484
|
+
| --- | ---: |
|
|
485
|
+
| **Total PORT rows** (current, after dedups) | **159** |
|
|
486
|
+
| — unit (`target_layer = unit`) | 123 |
|
|
487
|
+
| — integration (`target_layer = integration`) | 36 |
|
|
488
|
+
| **Complete** (`ported`) | **159** (123 unit + 36 integration) |
|
|
489
|
+
| **Remaining** (`pending`) | **0** |
|
|
490
|
+
| **Percent complete** | **100%** (159 / 159) |
|
|
491
|
+
|
|
492
|
+
Batches **U1–U21** are all merged. U11 was folded into U10 during the `test_log.rb` /
|
|
493
|
+
`test_log_execute.rb` dedup. The PORT total dropped from the W1.5 figure of **192** to
|
|
494
|
+
**159** because ~33 rows were reclassified PORT → REDUNDANT (`covered`) as in-flight
|
|
495
|
+
dedups confirmed the behavior was already covered by an existing or sibling-batch spec.
|
|
496
|
+
All 159 PORT rows have `port_status = ported` in the TSV. Note: `ported` became the de
|
|
497
|
+
facto terminal state for PORT rows in this project — merged batches were not
|
|
498
|
+
systematically bumped through `reviewed` → `merged` in the TSV, so `ported` represents
|
|
499
|
+
done. W2 is **complete**.
|
|
500
|
+
|
|
501
|
+
Drive W2 entirely from the enriched audit matrix; port only the **PORT** cases (159 after
|
|
502
|
+
dedup; 192 at W1.5 sign-off), honoring each row's `target_layer` and `target_spec`.
|
|
503
|
+
|
|
504
|
+
**Execution protocol — one test at a time, with review gates.** Each W2 **batch** (not
|
|
505
|
+
all of W2) is delivered as **one PR** with no more than 10 matrix rows; W3–W5 follow
|
|
506
|
+
their own workstream-level PR rules below. The per-case work happens on the topic branch
|
|
507
|
+
*before* that batch PR is opened: the agent advances one discrete item at a time and
|
|
508
|
+
**stops for human review** after each, only continuing on an explicit go-ahead. The
|
|
509
|
+
per-step review gates and the single-batch-PR delivery are not in tension — the branch
|
|
510
|
+
accumulates locally-reviewed commits, and the PR is opened **once, at the end of the
|
|
511
|
+
batch**, as a single ready unit (see [Branch & PR lifecycle](#branch--pr-lifecycle)
|
|
512
|
+
below). For W2, the discrete item is **exactly one legacy audit row**. Multiple audit
|
|
513
|
+
rows may be grouped only when the agent first proposes the grouping and the reviewer
|
|
514
|
+
explicitly approves it. Concretely, per case:
|
|
515
|
+
|
|
516
|
+
1. Announce the case (file:line, behavior, `target_layer`, `target_spec`) about to be
|
|
517
|
+
ported.
|
|
518
|
+
2. Write/extend the RSpec example(s) for that destination row (a row may produce more
|
|
519
|
+
than one `it`; plus any minimal support).
|
|
520
|
+
- **2a. Self-check against `rspec-unit-testing-standards` before reporting green.**
|
|
521
|
+
Confirm the example conforms to the skill: for unit rows — externals stubbed, **no
|
|
522
|
+
real git / no subprocesses**, deterministic (no time/network/filesystem ordering
|
|
523
|
+
dependencies), one behavior per example, project naming/structure conventions, and
|
|
524
|
+
100% branch coverage for the touched logic; for integration rows — minimal real-git
|
|
525
|
+
wiring only, no exhaustive matrices. RuboCop does **not** enforce most of these, so
|
|
526
|
+
this is a manual conformance step, not a lint pass.
|
|
527
|
+
3. Run just that spec (and coverage for the touched file/class) to show it green, then
|
|
528
|
+
set `port_status = ported` for the row in the audit TSV.
|
|
529
|
+
4. **Pause** and present the handoff below; wait for "continue" before the next case.
|
|
530
|
+
When the reviewer approves the case, set `port_status = reviewed`.
|
|
531
|
+
|
|
532
|
+
**`port_status` state machine (agent updates the audit TSV — the only tracker):**
|
|
533
|
+
|
|
534
|
+
- `pending` → `ported` — after step 3 (example written and green locally).
|
|
535
|
+
- `ported` → `reviewed` — after the reviewer approves the case at its gate (step 4).
|
|
536
|
+
- `reviewed` → `merged` — after the PR containing the case merges.
|
|
537
|
+
- any → `grouped` — when a row is folded into another row's example under an
|
|
538
|
+
approved dedup group; record the surviving row's `file:line` in `verify_notes` so the
|
|
539
|
+
fold-in is traceable. A `grouped` row needs no example of its own.
|
|
540
|
+
|
|
541
|
+
Update `port_status` **only** in the audit TSV. Do not restate per-row status in this
|
|
542
|
+
document or the session plan — they describe the protocol, the TSV holds the state.
|
|
543
|
+
|
|
544
|
+
#### Branch & PR lifecycle
|
|
545
|
+
|
|
546
|
+
The per-case "review" gates above are **local, in-session** reviews on the topic branch;
|
|
547
|
+
they are distinct from the eventual GitHub PR review. The git mechanics for each batch:
|
|
548
|
+
|
|
549
|
+
1. **Before the first case:** confirm the working branch is a topic branch, not `main`
|
|
550
|
+
or `4.x` (`git branch --show-current`); if not, `git switch -c <type>/<short-desc>`
|
|
551
|
+
first. One topic branch per batch.
|
|
552
|
+
2. **Per approved case:** after the reviewer says "continue" and `port_status` is set to
|
|
553
|
+
`reviewed`, commit that case as **one Conventional-Commits commit** (e.g.
|
|
554
|
+
`test: port <area> <behavior> to RSpec`). One commit per reviewed case keeps the
|
|
555
|
+
branch history mirroring the review loop and keeps work safe.
|
|
556
|
+
3. **At end of batch (all cases `reviewed`):** run the PR-exit gate (cumulative 100%
|
|
557
|
+
branch coverage + RuboCop + specs green), then open **one** ready PR for the batch.
|
|
558
|
+
Do **not** open the PR mid-batch.
|
|
559
|
+
4. **After merge:** set `port_status = merged` for every row in the batch.
|
|
560
|
+
|
|
561
|
+
W3–W5 follow the same branch-then-one-PR pattern (W3 additionally ships its steps as a
|
|
562
|
+
single atomic PR — see W3).
|
|
563
|
+
|
|
564
|
+
Per-case handoff template:
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
Legacy case: <file:line> <test_name>
|
|
568
|
+
Behavior: <behavior>
|
|
569
|
+
Target layer: <unit|integration>
|
|
570
|
+
Target spec: <path>
|
|
571
|
+
Examples changed: <brief list>
|
|
572
|
+
Standards: conforms to `rspec-unit-testing-standards` — <rules self-checked: stubbed
|
|
573
|
+
externals / no real git / deterministic / one-behavior-per-example / naming &
|
|
574
|
+
structure / coverage>
|
|
575
|
+
Commands run: <commands + results>
|
|
576
|
+
Coverage: <line/branch result for touched class/file>
|
|
577
|
+
Port status: <pending|ported|reviewed|merged|grouped>
|
|
578
|
+
Diff summary: <files changed + intent>
|
|
579
|
+
Status: waiting for review; say "continue" to proceed
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
This keeps each review small and lets the reviewer catch convention drift early.
|
|
583
|
+
|
|
584
|
+
- **`target_layer = unit`** (123 now; 158 at W1.5 sign-off) → write/extend `spec/unit/`
|
|
585
|
+
specs with stubbed externals (no real git), preserving 100% branch coverage. This is the
|
|
586
|
+
bulk of the work and where logic coverage belongs.
|
|
587
|
+
- **`target_layer = integration`** (36 now; 34 at W1.5 sign-off) → add only **minimal**
|
|
588
|
+
`spec/integration/` examples that prove the facade ↔ command wiring against real git; do
|
|
589
|
+
not recreate the legacy exhaustive matrices.
|
|
590
|
+
- **Integration deduplication rule:** before adding an integration example, check
|
|
591
|
+
whether a minimal wiring example for the same path already exists or is proposed in
|
|
592
|
+
the current batch. Folding multiple audit rows into one integration example is allowed
|
|
593
|
+
only after the agent proposes the grouping and the reviewer explicitly approves it.
|
|
594
|
+
- Follow `facade-test-conventions` / `command-test-conventions` /
|
|
595
|
+
`rspec-unit-testing-standards`. Query the matrix per file/area for exact line
|
|
596
|
+
numbers, behaviors, `verify_notes`, `target_spec`, and `disposition`.
|
|
597
|
+
- Remove the now-satisfied "covered by tests/units/..." deferral comments from the
|
|
598
|
+
5 spec files as their coverage lands.
|
|
599
|
+
- Special handling:
|
|
600
|
+
- `test_command_line.rb` lines 69, 126, 186, 212, 269 + `test_thread_safety.rb:22`
|
|
601
|
+
are the 6 integration cases that exercise real subprocess timeout/signal/IO via
|
|
602
|
+
`bin/command_line_test`. **Decision (Q4):** keep a real shell-out and **relocate**
|
|
603
|
+
the fixture into the RSpec support tree (see W3) — do *not* collapse it into an
|
|
604
|
+
inline `ruby -e` one-liner.
|
|
605
|
+
- The 7 coverage-gap cases (FsckResult helpers, `Git::Log#merges`,
|
|
606
|
+
`Git::Status#untracked`) are unit ports that close real gaps — prioritize them.
|
|
607
|
+
- encoding / escaped-path tests — port fixtures or construct repos in-spec.
|
|
608
|
+
- Coverage expectations — distinguish the two checkpoints so the agent does not chase
|
|
609
|
+
100% on a single case or get blocked mid-batch:
|
|
610
|
+
- **Per case (informational):** report the line/branch coverage for each touched
|
|
611
|
+
class/file in the handoff. A single ported case is not expected to reach 100% on
|
|
612
|
+
its own; the number is feedback, not a gate.
|
|
613
|
+
- **PR exit (the gate):** the batch's cumulative coverage must be 100% branch
|
|
614
|
+
coverage before the PR is opened, with RuboCop clean and all touched specs green.
|
|
615
|
+
Because SimpleCov does not yet strictly fail on low coverage, the agent must verify
|
|
616
|
+
and state the final cumulative coverage explicitly at PR exit.
|
|
617
|
+
- **Standards conformance is a per-case acceptance criterion, separate from coverage and
|
|
618
|
+
RuboCop.** Every ported case must pass the step 2a self-check against
|
|
619
|
+
`rspec-unit-testing-standards`, and the handoff must record which rules were checked, so
|
|
620
|
+
the reviewer can confirm conformance at the gate. Green specs + clean RuboCop are
|
|
621
|
+
necessary but **not sufficient** — RuboCop does not enforce the stub-don't-shell-out,
|
|
622
|
+
determinism, one-behavior-per-example, or unit-vs-integration boundary rules.
|
|
623
|
+
|
|
624
|
+
### W-Doc — Documentation salvage (`disposition = document`)
|
|
625
|
+
|
|
626
|
+
Independent of the spec porting in W2, but gated by the same W1.5 sign-off and **must
|
|
627
|
+
merge before W3** (which deletes `tests/units/`, the source of these examples). Delivered
|
|
628
|
+
as one docs-only PR under the same one-at-a-time review cadence as W2.
|
|
629
|
+
|
|
630
|
+
- Process every row with `disposition = document`. The `target_spec` column names the
|
|
631
|
+
destination: `yard:<Class>#<method>` (add/extend a YARD `@example` on that method) or
|
|
632
|
+
`readme:<section>` (a usage section in `README.md`).
|
|
633
|
+
- Per row: (1) announce file:line and the `target_spec` doc destination; (2) write the
|
|
634
|
+
documentation example, derived from the legacy test's usage (the *how*, not its content
|
|
635
|
+
assertions); (3) confirm it renders/builds (YARD example blocks must be valid Ruby;
|
|
636
|
+
`bundle exec rake yard` clean), then set `port_status = ported`; (4) pause for review,
|
|
637
|
+
setting `port_status = reviewed` on approval. After the PR merges, set
|
|
638
|
+
`port_status = merged`.
|
|
639
|
+
- Examples must be runnable and accurate — prefer the minimal, idiomatic gem call the
|
|
640
|
+
legacy test demonstrated (e.g. `git.object('HEAD').archive('out.tgz', format: 'tgz',
|
|
641
|
+
prefix: 'release/')`), not the git-content assertions that motivated the drop.
|
|
642
|
+
- Gate: `bundle exec rake yard build` clean; every processed row is `reviewed`; no
|
|
643
|
+
`document` row is left `pending` before W3's pre-delete gate runs.
|
|
644
|
+
|
|
645
|
+
### W3 — Remove Test::Unit infrastructure (single atomic PR, after W2)
|
|
646
|
+
|
|
647
|
+
**Status: MERGED.** Infrastructure removal done across two PRs: PR #1502
|
|
648
|
+
(`test/phase-4-step-b-w3-remove-infra` branch: removed `tests/units/`, `bin/test`,
|
|
649
|
+
`bin/test-verbose`, `tasks/test.rake`, the `test-unit` gem dependency, and introduced
|
|
650
|
+
`bin/spec-in-docker` and `docker/test/Dockerfile`) and PR #1503
|
|
651
|
+
(`chore/remove-tests-files-fixtures` branch: deleted the 545 `tests/files/` fixture
|
|
652
|
+
files deferred from W3 due to the Copilot 300-file review limit).
|
|
653
|
+
|
|
654
|
+
W3 follows the same per-step review cadence as W2 (the agent pauses for review after
|
|
655
|
+
each discrete change below), but all of the deletions/relocations ship together as one
|
|
656
|
+
atomic PR — the repository must never be left in a half-removed state on the branch tip.
|
|
657
|
+
|
|
658
|
+
- Delete `tests/units/` and `tests/files/`.
|
|
659
|
+
- Delete `bin/test`, `bin/test-verbose`.
|
|
660
|
+
- Delete `tasks/test.rake`.
|
|
661
|
+
- Update `Rakefile`: remove `test-all` + `test-all:parallel` tasks; drop `test` /
|
|
662
|
+
`test:parallel` from `default_tasks` / `default_tasks_parallel`.
|
|
663
|
+
- Remove `test-unit` from `git.gemspec`; `bundle install` to update `Gemfile.lock`.
|
|
664
|
+
- **Pre-delete verification gate:** before deleting `tests/units/`, re-check the
|
|
665
|
+
non-ported rows from the enriched audit matrix:
|
|
666
|
+
- automated check that every `disposition = covered` row **whose `spec_coverage` cites a
|
|
667
|
+
single spec path** points at a spec file that still exists (202 rows);
|
|
668
|
+
- automated check that every `disposition = covered` row **whose `spec_coverage` cites
|
|
669
|
+
multiple semicolon-separated spec paths** points only at spec files that still exist
|
|
670
|
+
(37 rows);
|
|
671
|
+
- **full** manual review of every `disposition = covered` row whose `spec_coverage` is
|
|
672
|
+
`none` — these are diffusely covered across multiple specs (the citation lives in
|
|
673
|
+
`verify_notes`, so the automated single-path check cannot reach them; 48 rows);
|
|
674
|
+
- manual review of every `disposition = intentional_drop` row (1 row);
|
|
675
|
+
- confirmation that every `disposition = document` row has been relocated to its
|
|
676
|
+
`target_spec` doc destination (W-Doc merged), so deleting the legacy test loses no
|
|
677
|
+
example (4 rows);
|
|
678
|
+
- explicit confirmation that any `obsolete` row is obsolete because of the redesign.
|
|
679
|
+
Do not delete the legacy suite until this gate passes.
|
|
680
|
+
- **Relocate the `command_line_test` fixture (Q4).** The 6 subprocess integration
|
|
681
|
+
cases genuinely shell out of the Ruby process, so the fixture script is kept as a
|
|
682
|
+
real executable but moved out of `bin/` into the RSpec support tree (e.g.
|
|
683
|
+
`spec/support/fixtures/command_line_test`), and the ported specs invoke it via a
|
|
684
|
+
real child process (`ruby <fixture> --stdout=… --signal=9 --duration=… …`). Delete
|
|
685
|
+
the original `bin/command_line_test` once the specs reference the relocated copy.
|
|
686
|
+
- **Preserve an RSpec-based Docker equivalent (Q3).** Do *not* simply delete the
|
|
687
|
+
container tooling. Move `tests/Dockerfile` and `tests/docker-compose.yml` to
|
|
688
|
+
`docker/test/Dockerfile` and `docker/test/docker-compose.yml`, and repoint them at the
|
|
689
|
+
RSpec suite — the container entrypoint runs `bundle exec rake default` (or
|
|
690
|
+
`bundle exec rake spec:parallel`) instead of the Test::Unit `bin/test`. Rename
|
|
691
|
+
`bin/test-in-docker` to **`bin/spec-in-docker`** so the "run the suite in a clean
|
|
692
|
+
container" workflow survives the migration without preserving the old Test::Unit
|
|
693
|
+
name.
|
|
694
|
+
- Gate: `bundle exec rake default:parallel` green;
|
|
695
|
+
repo-wide reference cleanup passes under the scope defined in W4b.
|
|
696
|
+
|
|
697
|
+
### W4a — Deprecate the finished `extract-*` skills (independent docs-only PR)
|
|
698
|
+
|
|
699
|
+
**Status: MERGED.** PR #1504, `chore/deprecate-extract-skills` branch.
|
|
700
|
+
|
|
701
|
+
This workstream has **no dependency on W2/W3** — the Base/Lib extraction these two
|
|
702
|
+
skills describe is already complete, so they can be retired at any time and this PR may
|
|
703
|
+
land early.
|
|
704
|
+
|
|
705
|
+
- **Deprecate the now-finished `extract-*` skills (Q2).** They should stop loading into
|
|
706
|
+
agent context while remaining available for historical reference. Create a new
|
|
707
|
+
**`.github/skills-deprecated/`** directory (outside the auto-discovered
|
|
708
|
+
`.github/skills/` tree) and `git mv` both skills into it:
|
|
709
|
+
- `.github/skills/extract-command-from-lib/` → `.github/skills-deprecated/extract-command-from-lib/`
|
|
710
|
+
- `.github/skills/extract-facade-from-base-lib/` → `.github/skills-deprecated/extract-facade-from-base-lib/`
|
|
711
|
+
|
|
712
|
+
Add a short `.github/skills-deprecated/README.md` explaining the directory holds
|
|
713
|
+
retired skills kept only for reference (not auto-loaded). Then fix the now-dangling
|
|
714
|
+
inbound "Related skills" links in the **active** skills that point at them:
|
|
715
|
+
- `command-implementation/REFERENCE.md`
|
|
716
|
+
- `facade-implementation/SKILL.md`
|
|
717
|
+
- `development-workflow/SKILL.md`
|
|
718
|
+
- `project-context/SKILL.md`
|
|
719
|
+
|
|
720
|
+
Either drop those bullet links or re-point them at the deprecated location with a
|
|
721
|
+
"(retired)" note. The two skills' *internal* cross-links to each other move together,
|
|
722
|
+
so they keep working.
|
|
723
|
+
- **Re-grep the whole repo after the move.** The four inbound links above are the
|
|
724
|
+
*known* references; before opening the PR, search the entire repository for the two
|
|
725
|
+
skill names (`extract-command-from-lib`, `extract-facade-from-base-lib`) and reconcile
|
|
726
|
+
every hit — not just the four. Any surviving mention outside
|
|
727
|
+
`.github/skills-deprecated/` (and the allowed historical scopes) must be updated to a
|
|
728
|
+
"(retired)" pointer or removed.
|
|
729
|
+
- Gate: the repo-wide grep for both skill names returns only intended hits (the
|
|
730
|
+
relocated skills, deliberate "(retired)" pointers, and allowed historical docs).
|
|
731
|
+
|
|
732
|
+
### W4b — Remove Test::Unit documentation references (docs-only PR, after W3)
|
|
733
|
+
|
|
734
|
+
**Status: MERGED.** PR #1505, `chore/remove-test-unit-docs` branch.
|
|
735
|
+
|
|
736
|
+
This workstream **depends on W3**: the docs only become true once `tests/` and the
|
|
737
|
+
Test::Unit tooling are actually gone, so it lands after the W3 removal PR merges.
|
|
738
|
+
|
|
739
|
+
- `.github/copilot-instructions.md` — remove Test::Unit rows from the commands table;
|
|
740
|
+
rewrite the "Test suites" paragraph to state RSpec is the sole suite. Update any
|
|
741
|
+
Docker-run command to the relocated RSpec entrypoint.
|
|
742
|
+
- `CONTRIBUTING.md` — remove Test::Unit / `bin/test` sections; keep RSpec guidance;
|
|
743
|
+
point the Docker workflow at the relocated equivalent.
|
|
744
|
+
- Other skills with Test::Unit references to reconcile (update, not deprecate):
|
|
745
|
+
`test-debugging`, `ci-cd-troubleshooting`, `command-test-conventions`.
|
|
746
|
+
- Gate: no live references remain outside the allowed historical/reference scopes:
|
|
747
|
+
`CHANGELOG.md`, redesign historical docs, and `.github/skills-deprecated/`. Active
|
|
748
|
+
code, active docs, active skills, `bin/`, `tasks/`, `spec/`, and `.github/workflows/`
|
|
749
|
+
must not retain live `tests/units`, `bin/test*`, or `Test::Unit` references, except
|
|
750
|
+
deliberate "(retired)" pointers into `.github/skills-deprecated/`.
|
|
751
|
+
|
|
752
|
+
### W5 — Verify & finalize (after W3, W4a, and W4b)
|
|
753
|
+
|
|
754
|
+
**Status: ✅ Complete.** W3, W4a, and W4b have all merged; full quality gate passed.
|
|
755
|
+
|
|
756
|
+
- Full local gate: `bundle exec rake default:parallel` (and a serial `rake default`
|
|
757
|
+
smoke for JRuby parity if feasible).
|
|
758
|
+
- Confirm W3, W4a, and W4b have all merged so the verification reflects the final
|
|
759
|
+
state (no `tests/` suite, retired `extract-*` skills, Test::Unit-free docs).
|
|
760
|
+
- Confirm CI (`rake default`, `rake test:gem`) is green — `test:gem` is independent of
|
|
761
|
+
Test::Unit and stays.
|
|
762
|
+
- Update [`3_architecture_implementation.md`](3_architecture_implementation.md)
|
|
763
|
+
progress tracker: mark Step B ✅ and bump the Phase 4 percentage.
|
|
764
|
+
|
|
765
|
+
### W6 — Remove stale `Git::Base`/`Git::Lib` references from active skills (independent docs-only PR)
|
|
766
|
+
|
|
767
|
+
**Status: ✅ Plan merged** (PR #1506) **and execution merged** (PR #1509, `docs/w6-remove-stale-base-lib-skill-refs` branch).
|
|
768
|
+
|
|
769
|
+
This workstream has **no dependency on W2/W3/W4a/W4b/W5** — it is not gated by,
|
|
770
|
+
and does not gate, the Test::Unit removal work above. It exists because Phase 4
|
|
771
|
+
**Step A** (the atomic `Git::Base`/`Git::Lib` removal, PR #1456) only required
|
|
772
|
+
`lib/` source to be clean of live references; `.github/skills/` was never audited
|
|
773
|
+
and still describes those two classes as though they currently exist and are the
|
|
774
|
+
live facade layer.
|
|
775
|
+
|
|
776
|
+
> **Note:** The following is historical context from execution planning. This work was completed in PR #1509.
|
|
777
|
+
|
|
778
|
+
The execution PR for this workstream should be branched from
|
|
779
|
+
`main` after PRs #1504 and #1505 merge, as both touch files in the list below
|
|
780
|
+
and would conflict with concurrent edits.
|
|
781
|
+
|
|
782
|
+
- **Audit every active skill under `.github/skills/`** for `Git::Base` / `Git::Lib`
|
|
783
|
+
mentions that describe them as *current* — as opposed to mentions that are correctly
|
|
784
|
+
historical/contextual (e.g., explaining what the redesign replaced). The following
|
|
785
|
+
files have at least one stale "current" reference and need review/rewrite
|
|
786
|
+
(verified by grep after PRs #1504 and #1505 merged, which cleaned up
|
|
787
|
+
`facade-implementation/SKILL.md` and `development-workflow/SKILL.md`):
|
|
788
|
+
- `command-implementation/SKILL.md`
|
|
789
|
+
- `command-implementation/REFERENCE.md`
|
|
790
|
+
- `command-test-conventions/SKILL.md`
|
|
791
|
+
- `facade-implementation/REFERENCE.md`
|
|
792
|
+
- `facade-test-conventions/SKILL.md`
|
|
793
|
+
- `yard-documentation/SKILL.md`
|
|
794
|
+
- `breaking-change-analysis/SKILL.md`
|
|
795
|
+
- `review-backward-compatibility/SKILL.md`
|
|
796
|
+
- `review-arguments-dsl/CHECKLIST.md`
|
|
797
|
+
- `refactor-command-to-commandlineresult/SKILL.md`
|
|
798
|
+
- **Rewrite each stale reference** to describe the current architecture: `Git::Lib`
|
|
799
|
+
facade-delegation examples (e.g. the now-deleted `lib/git/lib.rb` and
|
|
800
|
+
`spec/unit/git/lib_command_spec.rb`) become `Git::Repository::*` facade examples
|
|
801
|
+
(`lib/git/repository/<topic>.rb`, `spec/unit/git/repository/<topic>_spec.rb`);
|
|
802
|
+
`Git::Base` becomes `Git::Repository`.
|
|
803
|
+
Where a skill's own code example depends on the deleted classes (not just prose),
|
|
804
|
+
rewrite the example against a real current class, following the same approach used
|
|
805
|
+
for the stale TDD-cycle example fixed in W4b.
|
|
806
|
+
- **Do not touch** `redesign/1_architecture_existing.md` and
|
|
807
|
+
`redesign/2_architecture_redesign.md` — those documents intentionally describe the
|
|
808
|
+
pre-redesign architecture as history, and `.github/skills-deprecated/*` — already
|
|
809
|
+
scoped as retired reference material in W4a.
|
|
810
|
+
- Gate: a grep for `Git::Base` and `Git::Lib` across `.github/skills/` returns
|
|
811
|
+
only mentions that are unambiguously historical/contextual, not descriptions
|
|
812
|
+
of current behavior.
|
|
813
|
+
|
|
814
|
+
---
|
|
815
|
+
|
|
816
|
+
## Resolved Decisions
|
|
817
|
+
|
|
818
|
+
These were the open questions for Step B; all are now decided and folded into the
|
|
819
|
+
workstreams above.
|
|
820
|
+
|
|
821
|
+
1. **PR decomposition** → **Batched PRs for W2**, grouped by `target_spec` / component
|
|
822
|
+
with **no more than 10 legacy audit rows per PR**. Within each W2 PR, the agent ports
|
|
823
|
+
one legacy audit row at a time and stops for human review before moving on (the
|
|
824
|
+
per-test review-loop protocol in W2). W3–W5 follow the workstream-specific PR rules
|
|
825
|
+
above.
|
|
826
|
+
2. **Fate of the `extract-*` skills** → **Deprecate by relocation.** Move both
|
|
827
|
+
completed migration skills to a new `.github/skills-deprecated/` directory (outside
|
|
828
|
+
the auto-discovered `.github/skills/` tree) so they no longer load into agent
|
|
829
|
+
context but remain on disk for reference, with a README marking the directory as
|
|
830
|
+
retired. Inbound "Related skills" links in active skills are dropped or re-pointed
|
|
831
|
+
with a "(retired)" note. (W4a)
|
|
832
|
+
3. **Docker test tooling** → **Preserve an RSpec-based equivalent.** Relocate the
|
|
833
|
+
Dockerfile / compose file out of `tests/` and repoint the container entrypoint at
|
|
834
|
+
the RSpec suite (`bundle exec rake default` / `spec:parallel`); keep a
|
|
835
|
+
`*-in-docker` runner. (W3)
|
|
836
|
+
4. **`bin/command_line_test` fixture** → **Keep the real shell-out; relocate the
|
|
837
|
+
fixture.** The subprocess integration cases must genuinely leave the Ruby process
|
|
838
|
+
(to exercise real timeout/signal/exit-status/IO behavior), so an inline `ruby -e`
|
|
839
|
+
one-liner is the wrong fit. Keep the fixture as a real executable script and move it
|
|
840
|
+
into the RSpec support tree; the ported specs invoke it as a child process. (W2/W3)
|
|
841
|
+
|
|
842
|
+
> *On "inline equivalent":* that phrase meant constructing the child program inline
|
|
843
|
+
> in the spec via `ruby -e '<program text>'` instead of shipping a separate script
|
|
844
|
+
> file. It still spawns a genuine subprocess — but because this fixture handles
|
|
845
|
+
> stdout, stderr, exit status, signals, sleep/duration, and file redirection, an
|
|
846
|
+
> inline one-liner would be unreadable. Relocating the real script is cleaner and
|
|
847
|
+
> preserves the genuine shell-out.
|
|
848
|
+
5. **Non-ported REDUNDANT classification** → keep `final_verdict` stable unless the W1.5
|
|
849
|
+
sign-off explicitly approves a verdict flip; add a `disposition` column (`covered`,
|
|
850
|
+
`intentional_drop`, `document`, `obsolete`) before W2/W3 so deletion decisions are
|
|
851
|
+
auditable.
|
|
852
|
+
6. **PORT placement** → add a `target_spec` column for every PORT row before W2 so the
|
|
853
|
+
agent does not infer destination files during conversion.
|
|
854
|
+
7. **One-at-a-time strictness and integration deduplication** → default to one audit row
|
|
855
|
+
per review gate. Group rows only when the agent proposes the grouping and the
|
|
856
|
+
reviewer explicitly approves it; this especially applies to minimal integration
|
|
857
|
+
examples that may satisfy multiple rows.
|
|
858
|
+
8. **Pre-delete REDUNDANT verification** → automated citation/path checks for `covered`
|
|
859
|
+
rows that cite a single spec path (202) or multiple semicolon-separated spec paths
|
|
860
|
+
(37), **full** manual review for the diffusely covered rows whose `spec_coverage` is
|
|
861
|
+
`none` (48, citation in `verify_notes`), manual review for all `intentional_drop` rows
|
|
862
|
+
(1), confirmation that every `document` row has been relocated to docs (W-Doc merged,
|
|
863
|
+
4), and explicit confirmation for `obsolete` rows before W3 deletes `tests/units/`.
|
|
864
|
+
9. **Repo-wide reference cleanup scope** → allow historical/reference mentions only in
|
|
865
|
+
`CHANGELOG.md`, redesign historical docs, and `.github/skills-deprecated/`; clean
|
|
866
|
+
all live references elsewhere.
|
|
867
|
+
10. **Docker runner naming/location** → relocate container files to `docker/test/` and
|
|
868
|
+
rename the runner to `bin/spec-in-docker`.
|
|
869
|
+
11. **W2 progress tracking** → add a `port_status` column to the audit TSV
|
|
870
|
+
(`pending → ported → reviewed → merged`, plus `grouped` for rows folded into an
|
|
871
|
+
approved dedup group). The TSV is the **single source of truth** for per-row status;
|
|
872
|
+
the prose plans describe the protocol and the state machine but never maintain a
|
|
873
|
+
parallel per-row status list, so updates are never duplicated across files.
|
|
874
|
+
12. **W4 split** → W4 is delivered as two independent PRs: **W4a** retires the finished
|
|
875
|
+
`extract-*` skills (no dependency on W2/W3, may land early) and **W4b** removes
|
|
876
|
+
Test::Unit documentation references (depends on W3, since the docs only become true
|
|
877
|
+
once `tests/` is deleted). A repo-wide grep for the two retired skill names is part
|
|
878
|
+
of the W4a gate.
|
|
879
|
+
13. **PR open timing** → within each W2 batch, all per-case work is reviewed **locally**
|
|
880
|
+
on the topic branch first; the GitHub PR is opened **once, at the end of the batch**,
|
|
881
|
+
after the cumulative coverage gate passes — not incrementally during the loop. Each
|
|
882
|
+
approved case is its own Conventional-Commits commit. W3–W5 follow the same
|
|
883
|
+
branch-then-one-PR pattern. See [Branch & PR lifecycle](#branch--pr-lifecycle).
|
|
884
|
+
14. **Splitting one legacy test into multiple specs** → the unit of work is a
|
|
885
|
+
**destination** = one `(target_layer, target_spec)` pair. A single row may produce
|
|
886
|
+
**multiple `it` examples** in that one spec (porting is rarely 1:1 with a single
|
|
887
|
+
example); those examples share one review gate, one commit, and one `port_status`.
|
|
888
|
+
Split a legacy test into multiple rows **only when it maps to more than one
|
|
889
|
+
destination** — multiple target specs on the same layer, or multiple layers — adding
|
|
890
|
+
one matrix row per `(target_layer, target_spec)` (shared file/line/test_name;
|
|
891
|
+
independent `target_spec` / `port_status`; siblings cross-referenced in
|
|
892
|
+
`verify_notes`). A row never spans more than one destination. This keeps the invariant
|
|
893
|
+
**one row = one destination = one gate = one commit = one status**, and is the mirror
|
|
894
|
+
image of the dedup/`grouped` merge rule. Consequently the batch cap counts **matrix
|
|
895
|
+
rows (work items)**, not original legacy tests or individual examples, and the 196
|
|
896
|
+
PORT figure is the W1 starting count that may shift as enrichment splits or merges
|
|
897
|
+
rows.
|
|
898
|
+
15. **Documentation salvage (`document` disposition)** → a legacy case whose behavior is
|
|
899
|
+
not kept as a spec but whose *usage example* has user value is classified
|
|
900
|
+
`disposition = document` (not `intentional_drop`), and its example is converted to
|
|
901
|
+
documentation. This is driven by the **pass-through vs. parse rule**: content
|
|
902
|
+
assertions against git output the gem never inspects (pure pass-through, e.g.
|
|
903
|
+
`archive`) become `intentional_drop` / `document` once forwarding + byte-capture are
|
|
904
|
+
covered; content assertions against output the gem parses into Ruby objects (diff,
|
|
905
|
+
status, log, metadata, encoding, fsck) stay PORT. The doc destination is recorded by
|
|
906
|
+
**reusing the `target_spec` column** (`yard:<Class>#<method>` or `readme:<section>`),
|
|
907
|
+
disambiguated by the `disposition` value, so no extra column is added. These rows are
|
|
908
|
+
delivered by **W-Doc**, a dedicated documentation-only PR that runs under the same
|
|
909
|
+
one-at-a-time gate, is gated by the W1.5 sign-off, and **must merge before W3** so the
|
|
910
|
+
source examples are relocated before the legacy suite is deleted.
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
## Companion Data
|
|
915
|
+
|
|
916
|
+
- [`phase-4-step-b-test-audit.tsv`](phase-4-step-b-test-audit.tsv) — the authoritative
|
|
917
|
+
per-test-case audit matrix (484 rows). W1.5 enriched it into the executable
|
|
918
|
+
work-breakdown input **and** the single per-row progress tracker for W2/W-Doc/W3.
|
|
919
|
+
The file uses `|`-separated fields despite the historical `.tsv` extension. Current
|
|
920
|
+
columns: `file, line, style, test_name, initial_verdict, final_verdict, target_layer,
|
|
921
|
+
spec_coverage, verify_notes, behavior, disposition, target_spec, port_status`.
|