Repository navigation
Conversation
Lane: openRepoProject-2 Drop the `from tests import clean_support` fallback and keep a plain `import clean_support`. A dotted run's fallback loaded a second clean_support module with its own load_project() cache; the module runs alone through discovery, which puts tests/ on sys.path (lead ruling R-38; rule 3 as R-50 (g) words it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Remove the sys.path insert, its comment and the `import sys` it alone used; the module keeps its bare-name `from clean_support import load_project`. It runs alone through discovery, which puts tests/ on sys.path, so the insert was a second idiom (lead ruling R-38; rule 3 as R-50 (g) words it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Fill the Tests column of all 101 rows from the tests merged at 941443f, each name as `def NAME` finds it in a tests/test_*.py module and built by rule 1 from the scenario's title. Two tests that only share a title prefix or a topic with a clean scenario are left out: the status test of a submodule checkout and the status and doctor test of Git older than 2.36. No other column, row order or text changes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Remove the sys.path insert, its comment and the `sys` and `Path` imports it alone used; the module keeps its bare-name `from clean_support import load_project`. It runs alone through discovery, which puts tests/ on sys.path, so the insert was a second idiom (lead ruling R-38; rule 3 as R-50 (g) words it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t handoff Lane: openRepoProject-2 The Tasks line under "Speckit Handoff" read "(reserved; created by /speckit.tasks)"; it now reads "(created by /speckit.tasks)", as lane openRepoProject-1's archived changes record theirs. No other line of the file changes, and no box is ticked. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 timing_repo() goes; its two callers use CleanCase.repo(), which makes the same repository: one empty commit on main at self.base/repo. FAKE_STATUS_GIT goes; interrupted_status() puts the counting wrapper first on PATH over the status-hangs-in fake (lifetime 10 s, as the old fake's sleep). The status child's pid and parent's pid come from the wrapper's first `status` record, and project's process group is read with os.getpgid() while project runs. Method names, assertions and expected values are unchanged (lead ruling R-38; rule 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 R-34 names the list: default_branch(), ancestor(), cleanup_report(), print_clean_report() and matching_worktree() have no caller in project or tests/ since T076 rewrote push_or_delete() and require_unchanged_cleanup_state(). cleanup_signature() still has its caller and stays. inspect_repository()'s docstring no longer says cleanup_report() is live code. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s 1 to 3 Lane: openRepoProject-2 Item 1 (R-91 M-1): T093 and research.md R6 say a rendering fault is dropped by best_effort() with no change of stage and no exit, a fill of the delta's pcl:938-941 and :1020-1024; the list of exceptions that make a target `unknown` with `internal-error` loses "the record's rendering". T093 also gains "after exit 0" for the rescan-read rule (item 5, its T093 part). Item 2 (R-91 M-2, R-89 (a)): data-model.md says revalidation now sees a twin made after planning (registry_twin(), R-81 (a)) and its step table gains the twin check and the deadline cut; T098 names tests/test_clean_bounds tests for the cut rescan and the twin, and T099 states the floor before each revalidation, the cut revalidation and registry_twin(). The verifies of ticked T098 and T099 gain those names; both pass. Item 3 (R-91 LOW A): interim rows 1, 3, 4, 6 and 7 are marked CLOSED with their tasks, and the PR gate's tasks (T084, T085, T092, T093, T099) landed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Item 4 (R-91 LOW C): T091, T094 and the contract name the TEXT key `branches_not_confirmed` beside the words `Branches not confirmed: B2.`. Item 5 (R-91 LOW D): FR-036 and data-model.md's signal table add that a child killed at the ceiling keeps `removal-ceiling` after an abandoned rescan, and T087 says its fake's child exits 0 (T093's part is in the previous commit). Item 6 (R-91 LOW E): T085 cites BA:521-523 for a gone-but-unreconciled child and BA:520-521 for a failed registry listing, beside BA:518-526, all at da33d92; data-model.md's first overlap is the reading. Item 7 (R-91 LOW F): T049, T075, the contract and data-model.md name "an undecided P exempts no entry from the cap" a fill of FR-013 and of the delta's spec.md:262-263. Item 8 (R-91 LOW H, R-85 (d)): T128 says an empty discover exits 0 on Python 3.10, so its module count is checked. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… 11 items 9, 10 and 12 Lane: openRepoProject-2 Item 9 (R-92 (d), R-80 P-13): the contract says steps 3 and 4 order the refusals, not the reads; the delta asks only "before any plan or digest" (pcl:1067-1069), and the code reads the manifest and rows 4, 6 and 7 in its one inspect_repository() call before it checks root and common_dir. Item 10 (R-92 (d), P-8): T113's verify chain adds test_status_doctor_update.py, and its text says so; the new verify of ticked T113 passes (22 modules OK). Item 12 (R-92 (c)): the contract's refusal text records discover()'s two raw-path messages as PENDING, to be escaped by resolve_clean_target() in a final fixes lane. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Retires the five helpers that lost their callers when the push lane landed: cleanup_report(), matching_worktree(), ancestor(), default_branch() and print_clean_report() (R-80 P-15). cleanup_signature() stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 traceability.md names each of the 101 scenarios' tests (T126); the change's tasks.md points at feature 004's tasks (T133). Nothing archived. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 R-91's items from lane 3's delta read of doc rounds 9 and 10, and R-92(d): T093 and research R6 follow the contract on best_effort(); US6 as built in data-model.md; interim rows 1, 3, 4, 6 and 7 closed with their tasks; T098 and T099 name their tests; T113's chain gains test_status_doctor_update.py; the contract's step-order note. Item 11 waits for the test-hygiene lane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 test_clean_scrub, test_clean_escaping and test_clean_parsers import clean_support by its bare name with no sys.path insert; test_clean_timing.py builds on CleanCase.repo(), install_fake_git() and install_counting_git(). No assertion changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-92 (c), feature 004) Lane: openRepoProject-2 discover() names the user's own argument raw in `Directory does not exist: PATH` and `No project found at PATH; supply a path or name.`, which clean reports as repository-not-found. resolve_clean_target() now prints the PATH of each through human_path(), so a bare name holding U+202E or the byte 0xFF reaches the terminal and the JSON document escaped. discover() is unchanged, since status, doctor and update share it. The JSON refusal keeps its two fields, code and message; it never carried a path. Tests in tests/test_clean_paths.py: one per message for U+202E, the same for 0xFF on Linux, and the fallback where discover() codes neither message. They fail on 41971d9 (5 subtests across 2 tests) and pass here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 build_plan() now gates P's rows (gates 1 to 7, gate 8 with P alone, gates 9 and 10) right after match_target() builds them, before worktree_rows() inspects the other rows, the order of design D13 and pcl:262 (lead ruling R-93 (d)). No gate reads another row to decide P. With no deadline the plan is unchanged: only P's gate children move ahead of the other rows' status probes. A work deadline reached among the other rows now leaves P's row decided. The docstring states the new order and drops the retired cleanup_report(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 - tests/test_clean_paths.py: delete the unused local root_form. - project, print_plan()'s docstring (region preview): it said print_plan() replaces print_clean_report(), which T125 retired; it now says the function replaced it and that T125 then retired it. No code changed. - tests/test_clean_timing.py: the comment on os.killpg() said a status child is left in project's group. Every Git child of `project status` leads its own group, so the call reaps project's own group alone; the comment says so. No code changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Lead ruling R-93 (e), LOW-1: during the apply phase the first signal stops scheduling, so that no further probe starts (pcl:931-933). In region apply, revalidation_difference() now reads the signal slot (slot_set()) before each read it starts, its Git children and its filesystem steps alike. A set slot ends the revalidation as the seam before the spawn does: the target is not-attempted with interrupted and no reconciliation, later targets follow, and the exit stays 130, 143 or 129. The rescan of a removal already spawned is unchanged. Test: test_clean_a_signal_during_a_removal_sigint_during_a_revalidation (lane 3's sig-reval-INT), with a new fake kind, status-slow-again-in, in tests/clean_support.py. At 41971d9 it fails: the hidden-state probe started after SIGINT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 test_clean_single_target_a_deadline_among_other_rows_leaves_p_decided follows lane 3's single-deadline-note run: P and a merged worktree whose status probe hangs, through the launcher with deadline 3 s and reserve 1 s. P's status probe and ls-files run before the other rows' status probes; the plan is complete with the note deadline-exceeded naming P; P is not-attempted with deadline-exceeded, exit 1, in the human result, the JSON plan and the JSON result record; nothing is removed. At 41971d9 it fails: exit 2, inspection-incomplete, P excluded reflog-unavailable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Lead ruling R-93 (e), LOW-2: nothing pinned R-80 P-2's revalidation deadline cut. Two tests beside T098's, both through the launcher, with a new fake kind, ls-files-stuck-again-in, whose second ls-files in a path ignores SIGTERM and sleeps: - a revalidation read cut at the deadline (deadline 8 s, reserve 2 s, probe budget 30 s, grace 1 s): both targets not-attempted with deadline-exceeded, records null, nothing removed, exit 1; - the same read cut at a 1 s probe budget: the first target refused with hidden-local-state, exit 2, a timeout staying a difference. Both pass at 41971d9. With read_cut() and work_spent() returning False (lane 3's mutant), the first fails with exit 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 resolve_clean_target() prints the PATH of discover()'s two bare-name repository-not-found messages through human_path(), with U+202E and 0xFF tests in tests/test_clean_paths.py; discover() is unchanged. The three nits: an unused local, print_plan()'s docstring and a comment in tests/test_clean_timing.py (lead rulings R-92 (c) and (e), R-93 (c)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 When match_target() leaves P's match undecided (lead rulings R-73 (d) and R-78 (b)), build_plan() records none of single mode's non-blocking notes inspection-incomplete, inspect-cap and deadline-exceeded: each says the rows do not block P beside the plan's refusal of P, and the inspect-cap note counted P among the rows past the cap. The refusal, inspection-incomplete, speaks alone (lead ruling R-93 (e)). New test_clean_single_target_an_undecided_match_has_no_non_blocking_note, lane 3's r78b.py shape in process (the single cap patched to 4; P's own realpath, then another entry's, unread): inspection-incomplete, exit 2, no note; at 41971d9 it fails with the inspect-cap note. The one existing assertion that pinned that note in test_clean_single_target_p_s_own_realpath_unread_keeps_the_cap now expects no note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 Lead ruling R-93 (e), LOW-3: registry_twin() skipped a listed entry whose lstat or realpath could not be read, so a twin spelled through an unsearchable directory went uncaught (lane 3's twin-unreadable). Now such an entry, failing other than with ENOENT or ENOTDIR (absence, R-36), gives identity-changed (rs:92-93), as planning fails closed (R-78 (b)). One entry is exempt: a row the plan read with present null whose lstat fails again, null in the plan and null again (rs:89-92), so that single mode's non-blocking inspection-error row does not refuse P (pcl:258-262, pinned in test_clean_single.py). The docstring's "as in planning" is corrected. Test: test_clean_admin_registration_changed_a_twin_spelled_through_an_unsearchable_directory. At 41971d9 five of its seven subtests fail: the target is removed, exit 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 test_clean_single_target_an_undecided_match_has_no_non_blocking_note patched the single-mode row cap down to 4, which tasks.md's rule 6 for new tests forbids (caps are never scaled, R11). LOW-5 stays pinned at the real cap of 128 by the assertion in test_clean_single_target_p_s_own_realpath_unread_keeps_the_cap, which expects no note. No helper or import was used by that test alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 In a named removal, build_plan() runs P's gates on P's rows right after match_target() and before worktree_rows() inspects any other row, as design D13 orders, so a work deadline among the other rows leaves P decided beside the note deadline-exceeded (lead ruling R-93 (d)). With P's match undecided, single mode's non-blocking notes are left out and the refusal speaks alone (R-93 (e)). Tests in tests/test_clean_single.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 The final writer of the test-hygiene lane merges the integration branch first, so that R-81 (b)'s and R-82 (d)'s tests run against the code as it stands: US8, the polish wave, and final-fixes lanes A and C. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 R-90's R-81 (b) item. In process, the counting wrapper is the only git on PATH; after the full re-inspection runs through it as built, the wrapper is made not executable, or removed. The delegate's spawn then fails, and the run refuses with the baseline's `Cannot run git: ...`, exit 2, prints the plan and nothing relayed, and attempts no other child: subprocess.Popen sees the delegate alone after the re-inspection, and the branch is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoProject-2 A revalidation reads the signal slot before each read it starts and ends with interrupted, so no probe starts after a signal (pcl:931-933). The revalidation deadline cut and its budget contrast are pinned. The twin check refuses identity-changed on an entry whose lstat or realpath cannot be read, except one the plan also read as failed (rs:89-93; pcl:258-262). Two fake kinds are added to tests/clean_support.py (lead rulings R-93 (e) and R-95). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…robe (R-82 (d)) Lane: openRepoProject-2 R-90's R-82 (d) item, as R-93 (a) corrects it. Between Git's exit 0 and the rescan, a post-remove hook replaces a parent by a file: the target's own parent reads path_present false and the target `removed`, exit 0; the repository root's parent loses the identity, every field null, `unknown` with `unconfirmed-removal`, exit 1; the contrast, the parent made mode 000 (EACCES), is `reconciliation-incomplete`, exit 1. A second test cuts the rescan's identity probe at its budget while the root is still there: the marked all-null record gives `reconciliation-incomplete`, exit 1, and no later rescan read runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing change 1's tasks.md (R-377, L1) Item 1, R-365 (ruled by Brett Heap on 2026-10-23, "Yes, warn (Recommended)" for F-1's (b), "Yes, add T9 (Recommended)" for T9; lead R-365). Beside a row whose path could not be read, the ceiling's prune note is TEXT partial_removal_note_prune_unread (print_result() passes unread_paths(plan) into partial_removal_text()), and repo_state()'s stale recommendation ends with the no-prune warning (status, doctor and update share it). Both texts are copied from project at d8724e2 by script (texts.py), and the three new tests are listed in T089, T091 and T115 and in traceability's tail. Sites: README's (b) paragraph; the contract's D18 note row, its "known residual" (now split: the omitted unlocking stays a residual, the missing warning is an accepted departure from FR-064) and a pointer in "The unread forms"; data-model's R-320/R-324 enumeration, the Classification text on status, the note selection and the status-state section; spec FR-028 and FR-064 take dated notes; T011, T085, T089, T091, T094, T115 and T117; traceability's tail and its head sentence at d8724e2; hand-runs.md's dated note names R-365 and the shortstat at d8724e2 (711 insertions, 118 deletions). Item 2, L1 (lead R-377; wave 22 triage, section 5): openspec/changes/add-project-clean-all-safe/tasks.md restored to origin/main's copy (blob 8a87a4d; git diff origin/main on it is empty). Path Conventions, plan.md and quickstart.md say that PR #19's round (p) carries 004's four hunks and T133's Tasks line, taking analyze M8's first option in place of R-42's merge. T133 is rewritten: its verify passes on main's copy and on the copy that carries #19's Tasks line (blob 44c9101), and fails when this branch has changed the file. T131's verify no longer allows that file among the branch's changes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…373, R-374); checkpoint at the account swap One commit for items 1 to 7 of the brief, with their tests, made at the lead's account-swap checkpoint instead of one commit per item. - T7 (sr-evidence M-2, M-3): _fs() and _direct() also catch ValueError (a NUL byte in a `.git` or `commondir` file) and raise an `os-error` EvidenceError with no errno, so the row is inspection-error and status exits 0; head() of resolve_merge_target() and narrowed_ref_patterns() read a name with a lone surrogate as no local branch. - T10: a `detached` flag from `record["branch"] is None` (WorktreeRow.detached), read by classify() and the delete-branch holders check, not the text `detached`. The push path keeps its baseline text match (test P3 pins it). - T19 (W121 MEDIUM-2, R-374): a failed row 7 gives each present row on a branch row 7's error, as row 6's does, so it is inspection-error and never review-required (pcl:178-179); the pin in test_clean_evidence.py is updated. - T14 (W120 L-1): unsupported-path-bytes' next step names git worktree move, or mv then git worktree repair NEWPATH. - T15 (W115 LOW-2, LOW-3): row 116's test runs --all-safe --apply --yes; row 111 gets a real-Git core.bare=true case with two targets. - T16: the comment on TEXT partial_removal_note_locked cites "F-2: yes" (R-263). - LOW-5 (W121): the above-128 report's excluded list, and --expect-plan above 128. - Optional T17: not added; test_clean_an_unread_row_beside_a_redirected_row already pins a registration-mismatch P refused as inspection-incomplete with the unread remedy beside an unread sibling. Verifies run (all pass): test_clean_evidence, test_clean_push, test_clean_paths, test_clean_scrub and test_clean_bounds on Python 3.12, on Python 3.10 and on Git 2.36.6; test_clean_gates, test_clean_resolution, test_clean_revalidation, test_clean_harness, test_project and test_status_doctor_update on 3.12; T131 (before this commit); the verifies of T012, T027 to T029, T031, T032, T051, T052. The new behaviour tests fail against d8724e2's project (run in a copy). NOT RUN at this commit: T030, T043, T072 to T074 and T127 verifies (the run was stopped at the swap); T131 and the mutation checks against this commit; the doc-site list for the next doc round. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s Q1, lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T1 (sr-classification H-2, sr-evidence H-1 and H-2, sr-removal F1). - project: STATUS_PINS gains "-c", "core.ignoreCase=false", after core.checkStat=default, so the status probe, the hidden-state probe and the removal child carry it (GIT_KINDS). Under core.ignoreCase=true on a case-sensitive file system Git left out of the status records an untracked file whose name differs only in case from a tracked one, and `git worktree remove PATH` resolved PATH to the first worktree whose path matched it ignoring case. Two docstrings name STATUS_PINS instead of "the two status pins". - tests: every transcription of the pins gains the fifth status pin (test_clean_evidence, _apply, _result, _runner, _scrub with design D9's removal vector, _revalidation and test_status_doctor_update). Two new real-Git tests in test_clean_scrub's PinnedStatusTests: test_status_a_case_variant_untracked_file (the setting in the repository's config, and in GIT_CONFIG_GLOBAL alone: the row is dirty, nothing selected, the apply keeps the file) and test_clean_two_worktree_paths_that_differ_only_in_case (the eligible WT-X removed; the excluded wt-x, first in readdir order, and its HEAD-reflog-only commit remain). Both fail against e702a65's project and pass here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gistration-mismatch (Brett Heap's Q2, lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T2 (sr-classification H-1, sr-evidence H-3). Git's directory walk skips every entry named .git and recurses into a directory the index tracks without asking whether it holds a repository, so such an entry showed in no status record, passed Git's own check, and the removal deleted it. - Q2 (1): enclosing_rows(), a pure function of values already read: a present linked row whose raw path or realpath is the common directory, the main worktree, another registry entry's raw path or another built row's realpath, or an ancestor of one, is registration-mismatch, unprobed, as a shared path is (worktree_rows()). Its row is inspection-error, so the plan is incomplete and nothing is removed. - Q2 (2): HiddenStateParser keeps `directories`, every directory above an entry read before the bound (the top level aside); hidden_state_probe(), after a gitlink and before the hidden flags (gate 9 before gate 10), runs nested_git_check(): one fs_call() through _fs(), OPERATION lstat, counted in the filesystem budget, an lstat of <dir>/.git per directory in byte order (nested_git_entry()). An entry of any type is contains-submodule; a failure other than ENOENT or ENOTDIR, or the call cut, is the row's error, so it is inspection-error. Being inside hidden_state_probe(), the check also runs at revalidation step 7 (a failed read there is state-changed, a cut one deadline-exceeded). The parser's result dict is unchanged. - tests (each fails against e702a65's project and passes here): test_clean_gates: a repository nested in tracked tools/, a docs/.git directory and an a/.git file over a/b/c.txt, each contains-submodule beside a removed control, the inner commit kept; the nested lstat meeting PermissionError and a timeout in process; the main worktree inside W's tracked data/ (sr-evidence's mkcata): W registration-mismatch, batch and single apply refused, the repository whole; enclosing_rows() on literal values. test_clean_apply: a repository nested after the plan refuses its target at revalidation as contains-submodule. test_clean_parsers: the parser's `directories`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… warn of the dry run (Brett Heap's Q3, lead R-380)
Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380).
Lane 2's wave 22 triage T3 (sr-removal F2, sr-evidence M-1). git worktree
prune acts on the whole repository with an expiry of now: it deletes the
administrative directory, and with it the HEAD reflog, of every unlocked
entry whose path is missing, a worktree moved or on a drive not mounted
included.
- Q3 (a): the ceiling's partial_removal_note_prune is "Probable partial
removal: inspect, then delete {PATH} and its administrative directory
{ADMIN} by hand." in every mode and beside any row, ADMIN being
<common_dir>/worktrees/<admin_id> in the command form
(partial_removal_admin(), from the target's identity and row; "unknown"
where a plain dict carries neither). It supersedes R-365's
partial_removal_note_prune_unread, which is removed with its selection:
partial_removal_text(target) takes the target alone.
- Q3 (b): PRUNE_DRY_RUN, "; git worktree prune also deletes the entry, and
so the HEAD reflog, of every other worktree whose path is missing, one
moved or on an unmounted drive included, so run git worktree prune
--dry-run first and remount or repair any it lists that still exists",
ends the plain forms: the registration-mismatch and inspection-error next
steps, both inspection-incomplete remedies, the inspect-cap remedy, and the
stale row's recommendation (new TEXT key recommendation_stale_worktree,
which row_evidence() and next_step() give a stale row; RECOMMENDATIONS
keeps the baseline's text, which classify() still returns) and its locked
form, each recommendation ending in ".". The forms beside a row whose path
could not be read are unchanged.
- tests (each fails against e702a65's project and passes here; run 37,
failures 24, errors 13 there): test_clean_stop's ceiling note on literal
targets, ADMIN printed and "unknown" for a plain dict, the second note the
same beside any row; test_clean_result's recovery on real Git following
the new note beside a moved sibling whose commit lives only in its HEAD
reflog, prune --dry-run naming the sibling and the commit surviving, and
the second note beside an unread sibling naming no prune;
test_clean_evidence, test_clean_gates, test_clean_bounds, test_clean_batch
and test_clean_harness on the suffixed texts. tests/clean_support.py's
fixtures keep step (item 8).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brettheap
pushed a commit
that referenced
this pull request
Oct 23, 2026
…pository name that begins with a dot, such as .github, among the names the shared identity rule refuses though GitHub allows them (RC2-2); D5's paragraph on the two texts says that amendment A1 refuses the overview for the same four variables (W118's LOW-2, applied with change in that form, C-81); D5's lookup-failure paragraph says that the test of the three configuration variables is made first even when the lookup falls due past the deadline (RC2-1, C-81); D11's counting git wrapper scopes each control, change 2's hold among them, to a chosen argv in a chosen repository, the -C directory it records (RC's L1); Risks' Git 2.36 floor entry names feature 004's git-floor job and its -k list (RE-8's last sentence); Migration Plan step 3 names every job the tests workflow then runs, git-floor at PR #33's d8724e2 included (RE-8). The three edits before D7 keep their paragraphs' line counts (10, 25 and 16), so D5's residual 574-601 and D7 954-989 are cmp-identical to a529310; design.md 1560 to 1575 lines, all added after D7; no spec edit in this commit Lane: openRepoProject-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…texts keep submodule commits (Brett Heap's Q4, lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T4 (sr-removal F3, F4, F5; sr-classification M-3). Texts copied byte for byte from #19's round (q) at 818311a, design.md D18. - Q4 (a) and (b): D4's report-row note judges the status records read, so work past the 4,096-record bound or an ignored file left it showing --force. Every detection rule stays; the note now names the check that shows such work: partial_removal_note "Probable partial removal: check that git -C {PATH} status --short --ignored lists only deleted files, then git worktree remove --force {PATH} by hand." and partial_removal_note_locked "... lists only deleted files, unlock it, then git worktree remove --force {PATH} by hand.". - The ceiling's own --force text stays, as the new key partial_removal_note_ceiling ("Probable partial removal: inspect, then git worktree remove --force {PATH} by hand."), which partial_removal_text() now returns where the rescan shows the .git file and the entry present. - Q4 (c): contains-submodule's step "push or otherwise keep each submodule's commits first, since --force deletes its repository with this worktree's git directory, then git worktree remove --force yourself", and gate 7's two parentheticals "(--force if it holds a submodule, once its commits are kept)". - tests (fail against e702a65's project, pass here; 13 run there, 14 failures, 13 errors): test_clean_stop's new test_clean_the_partial_removal_note_names_its_check_first (SC5: 4,100 deletions, a modified and an untracked file past the bound; F4: one deletion beside an ignored local.env; the note printed, the check showing the work, the apply removing neither); the intact-deletion and locked notes with their check run first (only " D " lines); test_clean_gates's submodule row following its step (the commit pushed, then --force deleting modules/); and the tests that print the gate-7 and submodule steps. tests/clean_support.py's fixtures keep step (item 8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in line defers to each group (Brett Heap's Q5, lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T5 (sr-classification M-2, sr-removal F6). Texts copied byte for byte from #19's round (q) at 818311a, design.md D18. - unstarted-branch: "no commit was made on this branch here since it was created; its later gates did not run, so check git log -g HEAD, git ls-files -v and git status there, then git worktree remove yourself (--force if it holds a submodule, once its commits are kept)", and reflog-unavailable the same after "the branch's reflog is missing, expired or undecidable; ". Gate 7 precedes gates 9 to 12, which do not run for its rows, and "review, then git worktree remove yourself", followed literally, deleted a HEAD-reflog-only commit or an assume-unchanged edit. - non_drain_line: " these deferred rows will not drain while the 16 rows ahead of them are {REASONS}; follow each group's next step for those worktrees", where it had told the person to remove the 16 rows that gates 10 to 12 excluded for holding work. - tests (fail against e702a65's project, pass here; 6 run there, 7 failures): test_clean_reflog's new test_clean_gate_7_s_step_names_the_checks_of_the_gates_that_did_not_run (M-2's detached commit and an assume-unchanged edit, both unstarted-branch: the new step printed, the single removals refused, and git log -g HEAD and git ls-files -v showing each); test_clean_bounds's mixed seventeen-row drain (F6's shape) printing the new line beside each group's own step; the steps' other printers. tests/clean_support.py's fixtures keep step (item 8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ule words it (Brett Heap's Q8, lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T9 (W115 MEDIUM-1, W121). #19's round (q) at 818311a states the rule in project-command: a probe that exits 0 having written to standard error any line other than Git's advice lines (`hint:` alone or `hint: TEXT`), or more than the 4 KiB kept, fails; so a repository holding refs/heads/HEAD has every row inspection-error. - Checked against that rule, status_warned() differed in one case: it skipped blank lines. A blank line is a line other than an advice line, so it now fails the probe; only the empty text after the last line end, or no output at all, is no line. The 4 KiB clause was already the rule. - tests: test_clean_evidence's test_clean_evidence_the_status_warning_rule_counts_every_line, on literal outcomes (three blank-line cases fail against e702a65's project and pass here; the rest pin the advice forms, the 4 KiB edge, a line of spaces, `hint:a`, and Git's ambiguous-refname warning), and test_clean_evidence_refs_heads_head_makes_every_row_inspection_error, on real Git: the warning on standard error with exit 0, every row inspection-error with probe-failed, the plan incomplete, and nothing removed by --all-safe or by name. That consequence already held at e702a65, so this second test passes there too: it pins the rule's consequence and is no behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n-mismatch (Brett Heap's Q9 (b), lead R-380) Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). Lane 2's wave 22 triage T12 (sr-removal F7); #19's round (q) at 818311a adds "or whose registered path is a symbolic link" to registration-mismatch (project-clean-review-safety). - _read_row(): a linked row whose registered path lstats as a symbolic link takes the verdict a shared path takes, registered false with no admin id, from the lstat already made; its realpath is still read. So the row is unprobed, inspection-error and excluded as registration-mismatch, and the plan is incomplete. Before, its registration agreed through the link, it was selected, and Git emptied the link's target, failed to remove the link (exit 255) and still deleted the administrative directory. The main worktree's row is unchanged. - tests: test_clean_gates's test_clean_a_registered_path_that_is_a_symbolic_link (F7's fixture: a merged, pushed worktree moved by hand and a link left at its registered path, its status printing nothing): registration-mismatch, inspection-error with dirty null, the plan incomplete, and nothing removed by --all-safe or by name, the link, its target's files, the administrative directory and the control kept. It fails against e702a65's project (the preview exited 0 with the row selected) and passes here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rett Heap's Q2 (2), lead R-380) The lead asked whether clean's revalidation re-runs gate 10's listing for the target, and whether Q2 (2)'s nested .git lstats ride it. They do: revalidation_difference()'s step 7 calls hidden_state_probe(), which runs the listing again and then nested_git_check() over its directories, one fs_call() through _fs() under the same per-call budget. 5eeaedd tested a repository nested after the plan (contains-submodule); this adds the other outcomes, no code change. - tests: test_clean_apply's test_clean_revalidate_a_nested_git_lstat_that_fails_or_is_cut, in process: the call raising PermissionError or cut at its budget gives state-changed (R-195), cut by the work deadline deadline-exceeded; the call made once, naming the target's one directory; the target kept. It errors against e702a65's project (no nested_git_entry) and passes here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…502d (R-373, R-374, R-380, R-385) Merged impl/004-q-build (da5502d; merge commit ff12f47, no rebase). Every text is copied from project at da5502d by script. Part A, the A-items (e702a65; lead R-373, R-374, R-385): T14, the unsupported-path-bytes step now "move it to a valid UTF-8 path with git worktree move, or mv it and then git worktree repair NEWPATH" (README, contract, quickstart, spec FR-028, T110); T7, an os-error for a NUL byte in a .git or commondir file (Python's own text, no errno) and a lone-surrogate tracking_branch read as no local branch; T10, the detached flag; T19, a failed row 7 makes each present row on a branch inspection-error, never review-required; T15, the rows 111 and 116 arms; LOW-5, the two arms of the plain-report test above 128 rows. Each new test is in its task and in traceability's tail. Part B, Q1 to Q3 (ruled by Brett Heap on 2026-10-23T13:30:27Z, "yes, recommended for Q1-Q9"; lead R-380; 9d5c2fb, 5eeaedd, da5502d). Q1: core.ignoreCase=false is a fifth status pin (the removal's sixth) on the status, hidden-state and removal children. Q2 (1): a present linked row that is, or holds, the common directory, the main worktree or another row is registration-mismatch (enclosing_rows). Q2 (2): gate 9 lstats <dir>/.git in each directory that holds an index entry, one fs_call, and again at revalidation step 7 (nested_git_check). Q3 (a): the ceiling's second note is "Probable partial removal: inspect, then delete {PATH} and its administrative directory {ADMIN} by hand." in every mode; it supersedes R-365's partial_removal_note_prune_unread, whose records stay, marked superseded, and partial_removal_text() takes the target alone again. Q3 (b): the dry-run warning ends the plain prune texts (the two inspection-incomplete remedies, the inspect-cap remedy, the registration-mismatch and inspection-error next steps, the stale recommendation and its locked form); the unread forms are unchanged. Dated notes on FR-007, FR-011, FR-018, FR-023, FR-028, FR-050, FR-054, FR-055 and FR-064. Tasks: T002, T011 to T015, T028 to T032, T038, T045, T049, T052, T061, T063, T067, T073, T082, T084, T085, T089, T091, T094, T096, T097, T101, T110, T115, T116 and T126. Traceability: round (q)'s five scenarios (PR #19 at 818311a) are rows 118 to 122 (122 rows; T002 and T126 verifies count them), the gap notes for rows 111 and 116 name their new arms, and the tail lists every new and changed test; the head sentence reads da5502d. hand-runs.md's dated note names the changes (git diff --shortstat e69f6ef da5502d -- project: 960 insertions, 165 deletions). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… (doc round 26, Part C)
… lstat tests documented at 703b58c (R-380, R-393) Merged origin/impl/004-q-build at 703b58c (merge commit c81b948, no rebase). Every text is copied from project at 703b58c by script. Brett Heap's words, "yes, recommended for Q1-Q9" (2026-10-23T13:30:27Z; lead R-380), are cited in each dated note. Q4 (c6daebc): a report or preview row's partial-removal note names its check first ("check that git -C PATH status --short --ignored lists only deleted files, then git worktree remove --force PATH by hand", and the locked form with "unlock it"); the ceiling's first note keeps its text under the new key partial_removal_note_ceiling; contains-submodule's step keeps the submodule's commits first, and gate 7's parentheticals read "(--force if it holds a submodule, once its commits are kept)". Q5 (c28c9ea): gate 7's two steps name the later gates' checks (git log -g HEAD, git ls-files -v, git status), and the non-drain line defers to each group's next step. Q8 (70345ee): a blank line counts as a line of the status probe's standard error, with the refs/heads/HEAD consequence. Q9 (b) (338edb0): a linked row whose registered path is a symbolic link is registration-mismatch. Q2 (2) (703b58c): the tests of step 7's failed and cut nested-.git lstat. Sites: README (items 3 and 4, the next-step table, the non-drain sentence, the registration-mismatch scope and remedy sentences, the partial-removal paragraph); the contract (the non-drain row, the D18 partial-removal note row, the Codes variant sentence, gate 7's and gate 9's texts, the status-probe rule, a new Q9 (b) paragraph); data-model (D4's note text, gate 3, the status-warning sentence, the ceiling's note selection); dated notes on FR-009, FR-020, FR-028, FR-032, FR-055 and FR-057; hand-runs.md's note (shortstat e69f6ef..703b58c). Tasks: T011, T030, T031, T045, T052, T060, T061, T063, T084, T089, T091, T094, T097, T100 and T127. T127's verify tuple X exempts the two old gate 7 spans that main's design.md D18 still quotes, as doc round 18 did for the old drain line; the verify's static text check passes at 30 spans, and T127 itself was not run. Traceability: the new tests are listed in the tail, no scenario is added (122 rows), and the head sentence reads 703b58c. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s, and round (r)'s two scenarios are rows 123 and 124 (R-391, R-395, R-396) Documented at project 703b58c, unchanged (git diff 703b58c HEAD -- project tests is empty). The wording of PR #19's round (r) (4512441) is copied by script from its project-clean-review-safety delta (spec.md:110-112 and :131-132): "the hidden-state probe, with the `lstat` of `<dir>/.git` for every directory that its listing shows holding an index entry" and "`contains-submodule` for a new gitlink, `modules` entry or `.git` entry"; the two scenario titles and their requirement titles are copied by script too. Revalidation (lane 3's W133 MEDIUM-2; lead R-391 and R-395): step 7 (project:6550-6558) calls hidden_state_probe(), which runs gate 10's listing again (project:5590, the step's one Git child) and then nested_git_check() (project:5595), one fs_call() of the lstat of <dir>/.git for every directory the listing shows holding an index entry, counted in the filesystem budget and no Git child, so the six, seven, nine and ten children stand. A .git entry made after the plan refuses the target as contains-submodule; an lstat that fails, or hits its own budget, gives state-changed; one cut by the work deadline gives deadline-exceeded. Sites: README (the contains-submodule paragraph and "What is guaranteed"); the contract (the hidden-state row of the Git children table and the gate 9 paragraph); data-model (gate 9's row and its paragraph, step 7's row, a new paragraph after the steps table, the filesystem-calls sentence); spec.md (dated notes on FR-046 and FR-047); tasks (T084, T067). Traceability: rows 123 ("A nested repository made after the plan", US4) and 124 ("A stale entry's recommendation", US2), each a named gap, 124 rows; the intro, the "twenty-four" and "Six of PR #19's scenarios" sentences, two gap bullets naming the covering tests, and a tail paragraph. T002's and T126's texts and verifies count 124 and list both titles; T126's gap list gains both. The nested-repository scenario has no test that runs it through --apply: its covering tests are in process (T045), and the exit status and the later target's not-attempted are pinned for contains-submodule only by test_clean_submodules_after_confirmation (a modules directory). No test is added; the head sentence stays 703b58c. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…A-items Brett Heap, 2026-10-23T13:30:27Z: "yes, recommended for Q1-Q9" (lead R-380). - Q1: core.ignoreCase=false joins the status, hidden-state and removal pins. - Q2: (1) an enclosing row is registration-mismatch; (2) an lstat-found <dir>/.git in a directory holding an index entry is contains-submodule, counted in the filesystem budget, at planning and again at revalidation. - Q3: (a) the ceiling's note names the administrative directory, superseding R-365's prune-unread text; (b) plain prune texts warn of the dry run. - Q4, Q5: the --force checks first; gate 7's steps and the non-drain line. - Q8: status_warned() counts a blank line; Q9 (b): a symbolic-link registered path is registration-mismatch. The A-items (T7, T10, T19, T14, T15, T16, LOW-5; lead R-385) ride along from e702a65. Lead acceptance: R-385, R-395, R-398. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Doc round 25 (ecd0a7e; lead R-379): R-365's docs, and change 1's tasks.md restored to main's copy (L1, R-377). Doc round 26 (8e90096, 8abd901, 497f5a3; lead R-393, R-394, R-397): the A-items, Brett Heap's Q1 to Q5, Q8 and Q9 (b), revalidation's nested .git checks, and traceability rows 118 to 124 for #19's rounds (q) and (r). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y run (R-397) test_clean_a_nested_repository_made_after_the_plan, in tests/test_clean_revalidation.py: a batch whose first target tracks tools/run.sh; at the confirmation question the hook runs `git init` in that tracked directory, and the run stops at the first target as contains-submodule (exit 2, the later target batch-stopped), no removal child runs, and every tree, the nested repository's .git included, is still there. It pins Brett Heap's Q2 (2) (lead R-380) through a real --apply run, as lead R-397 asks; before it, only two in-process tests in tests/test_clean_apply.py pinned the revalidation step. The batch() fixture takes an optional setup(tree), passed to merged_worktree(). The test fails against project at e702a65 (both targets removed) and passes at 41759a4. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…w 123, and W140's items (R-394, R-405, R-406, R-407) Docs only (specs/004-project-clean-all-safe/). No code and no test change; the branch is first fast-forwarded to c0841aa, which adds R-397's test. T127 (W140 MEDIUM-1): its static check failed on the tree 004 has once #19 lands (git merge-tree --write-tree of c0841aa and 4512441, git archive into an empty directory): 129 D14 and D18 spans, 32 with no literal in tests/clean_support.py. Each is classed in T127's text. (a) 26 are not a text 004 prints and go into tuple X: 14 Git and project commands, 4 messages of Git's own, 5 words of Brett Heap's, 2 cites (R-284's letter, the parity rule) and 1 superseded text quoted as history. (b) 1, ADMIN, joins the placeholder list. (c) 5 are printed texts that project holds outside TEXT and NEXT_STEPS (project:7308, :551, :2426, :7464-7466 at c0841aa), each pinned by a test with its own literal; widening the source to TEXT and NEXT_STEPS would find none, so they are entries of X with that reason. The check passes on both trees (30 spans on the branch's own, 98 on the merged one) and still fails on a changed D18 string. LOW-1: data-model.md step 7's paragraph and traceability's row 123 note carry R-406's measured residual (one _fs() call under min(5 s, the work remaining); warm at 1,000, 10,000 and 50,000 tracked directories; cold cache and deep nesting unmeasured, both fail closed). LOW-3: the Q8 notes (spec.md FR-057, the contract, data-model.md) say "under Git's default `core.warnAmbiguousRefs`", copied by script from #19 at 4512441 (project-command spec.md:268-271), and that with the setting false the probe exits 0 with empty standard error, so no row is inspection-error on that account. OBS: spec.md's Q3 (b) note on status is the lane's reading under R-380, and M1 is still open; the three project-command cites (data-model.md, tasks.md, plan.md) are labelled as the ratified copy's lines at 0050f3e, with 4512441's. R-397's test (R-405): traceability row 123 names test_clean_a_nested_repository_made_after_the_plan (T083), so the named gaps go from six to five; T126's text and verify, T083, T084, the gap list and the tail say so, and the head sentence reads c0841aa. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… MEDIUM-1, R-409) Lane 3's W139 MEDIUM-1: enclosing_rows() (Q2 (1)) and _read_row()'s symbolic-link branch (Q9 (b)) sat in the shared worktree_rows(), which repo_state() uses, so status, doctor and update reported an enclosing worktree and a symlinked registered path as inspection-error with dirty null, and doctor exited 1, where f3724fc read both rows and exited 0. Both rules are clean's review safety (rs:13-16 at 4512441); pc states neither, so its parity rule (pc:311-312) keeps the report commands at the baseline's values. Lead call R-409: confine both to clean's plan. - worktree_rows() and _read_row() take for_clean (default false). Only clean sets it: match_target() and build_plan() (planning, and the re-plan of push and delete-branch through build_plan()), and registry_twin(), revalidation's step 5 re-read, so clean's behaviour is unchanged. repo_state() leaves it false. - R-67 (c)'s shared-path and twin rows stay in every command, as at f3724fc: shared_paths() and shared_identities() are not gated. - tests/test_status_doctor_update.py: a new test on W139's fixture (wt-a moved with a symbolic link left at its registered path; w1 holding w1/sub/w2) asserts f3724fc's entries for every row in status, doctor and update --json (report only), doctor exit 0, and that clean --all-safe --json still excludes both rows as registration-mismatch. It fails at c0841aa (status, doctor and update subtests) and passes with f3724fc's project for those three; report_env() puts recording owner tools first on PATH and XDG_CONFIG_HOME and TMPDIR in the fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… R-409) Lane 3's W139 LOW-2: pc:391-395, "A stale entry beside a worktree whose path cannot be read", names project status --json, project doctor --json and project update --json, and the test looped over status and doctor only. It now reads update's report as well (no --apply), with exit 0 in every state, under report_env(): recording owner tools first on PATH, XDG_CONFIG_HOME and TMPDIR in the fixture, and none of the tools run. W139 found update conforming on Git 2.43.0 and 2.36.6; the test passes on both. Test only; project is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…W140 LOW-2, R-409) Lane 3's W140 LOW-2: main's review-safety requirement "Cleanup protects the process worktree" names the current worktree from the working directory "including a directory nested within it", and no test ran clean from such a directory; every clean cwd= in the suite was a worktree's top level. The code was right (row_evidence()'s `current`, active.startswith(tree + b"/")). The new case in tests/test_clean_single.py, not tests/test_project.py (FR-066, R-32), runs from sub/deeper inside a merged, clean, published worktree: the report shows it current and merged-current, --all-safe selects nothing and excludes it as merged-current, and the explicit removal refuses with "Cannot remove the current worktree.", exit 2, in human and JSON output, removing nothing. On a scratch mutant without the nested branch of `current` it fails: (False, 'merged-removable') != (True, 'merged-current'). Test only; project is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OW-4, R-409) Lane 3's W140 LOW-4: the comment over TEXT_FIXTURES's partial_removal_note_locked in tests/clean_support.py still said the note "waits on Brett Heap's word". He ruled it on 2026-10-22, "F-2: yes" (the lead's R-263; traceability.md:307-308), and T16 already fixed the same sentence in project. The comment now says so. Comment only; no fixture text or behaviour changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or shares another (R-413) Brett Heap ruled on 2026-10-23, "yes, recommended for M1 and M3" (lead R-413). M1 needs no code. M3 (a): a row clean excludes as registration-mismatch because its path is, or holds, the main worktree, the common directory or another row (Q2 (1)), or because it shares its path with another row, printed the class's next step, whose "or remove the row by hand" deletes what it holds (lane 3's W133 MEDIUM-3). - TEXT "next_step_registration_mismatch_holds", beside next_step_registration_mismatch_unread, byte for byte #19's M3 (a) at 4512441 (197 characters). It names no git worktree prune, so it has no PRUNE_DRY_RUN and no unread form; it is the same in every mode. - WorktreeRow.holds, never serialized: worktree_rows() sets it for a row in enclosing_rows() (clean's plan alone), shared_identities() (R-67 (c)) or shared_paths() (R-57 L3). - excluded_groups() gives those registration-mismatch rows a group of their own, first, with the new step; the reason's other rows (the core.worktree and core.bare redirect, Q9 (b)'s symbolic-link row) keep the class's step, and its unread form where a path was unread. - Tests (tests/test_clean_gates.py): a new test with w1 holding w1/sub/w2, a path listed twice (R-57 L3), a worktree under two spellings (R-67 (c)) and a symbolic-link row (Q9 (b)) checks both groups in the --all-safe preview, in --all-safe --apply --json's human text on standard error, in single mode naming w1, and beside an unread row; test_clean_the_main_worktree_inside_a_linked_worktree now checks W's step in batch and single mode and that no line says "remove the row by hand". Both fail at c0841aa, where all such rows print the class's step. tests/clean_support.py gains the fixture key. - Not changed, for the lead: such a row is counted toward inspection-incomplete, whose remedy_inspection_incomplete_redirect (and its _unread form) still says "or remove the row by hand after review". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rett Heap's M3 (a) next step (R-409, R-413, R-416)
…eap's M1 and M3, and T127 on #19's 54e869b (R-409, R-413, R-415, R-416) Docs only (README.md and specs/004-project-clean-all-safe/). The branch first merges impl/004-q-build at d640539 (the code round, c0841aa..d640539), with no rebase. The code round (R-409, R-416). W139 MEDIUM-1: Q2 (1) and Q9 (b) apply in clean's plan alone (worktree_rows and _read_row take for_clean), so status, doctor and update report those rows as the baseline does. FR-055's two notes, the contract, the data model, T031 and the README now say so, with a corrective note citing R-409 and #19's design.md:591-598 at 54e869b (the brief's :588-596 are dab8a64's lines); T031's verify names the new worktree_rows signature. M3 (a)'s step, next_step_registration_mismatch_holds (197 characters, copied from project by script), is in the README's next-step table and preview text, the contract's next-step paragraph and preview layout, the data model's next steps, FR-028's note, and T011, T052 and T061. The code round's tests are listed in their tasks (T061, T071, T115) and in traceability's tail. Brett Heap's M1 (a) and M3 (a) are RULED (R-413, 2026-10-23T21:10:31Z, "yes, recommended for M1 and M3"). FR-064's Q3 (b) note and the contract's matching paragraph record M1 in his words with the time; FR-028's note records M3. W146's items (R-415): contracts/project-clean.md's note that #19 does not carry F-6 and F-10 says #19 now states both (project-clean spec.md:207-214 and :216-240, scenarios :296 and :308, at 54e869b); the cites of #19's revalidation sentence and reason list are spec.md:112-114 and :133-134 at 54e869b, with round (s)'s wording quoted (the contract, data-model.md, FR-046, FR-047, T084; W146's :113-116 and :133-135 are off by a line, checked by script). T127 passes on this branch's own tree (30 spans) and on the tree that git merge-tree makes with #19's 54e869b (102 spans of 139), and still fails on a changed D18 string. Three spans had no literal: (a) the label "The main worktree's recommendation", a scenario title; (c) the two baseline recommendations round (s) quotes as the main row's former text, which project still prints for every other row (RECOMMENDATIONS, project:2451-2452) and tests pin with their own literals (the lead's R-412 called them (a)); all three are entries of tuple X. M3's step needs no entry: its fixture is a literal in tests/clean_support.py, and at c0841aa it would have been a fourth missing span. Traceability gains rows 125 ("The main worktree's recommendation", round (s)) and 126 ("A worktree whose path holds the main worktree", round (t)), titles copied by script, each a named gap with its covering tests; T002 and T126 count 126 rows and seven gaps; the head sentence reads d640539. Not done: the stale cite at project:775-776 (traceability.md:253-255) is in project's own comment, outside this round's files, as is tests/clean_support.py:647's (traceability.md:307-308). M4 is not documented. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… Heap's M3 (a), and four small items - W139 MEDIUM-1 (lead R-409): Brett Heap's Q2 (1) and Q9 (b) apply only in clean's plan (worktree_rows and _read_row take for_clean); status, doctor and update report those rows as the baseline does, doctor exiting 0. - Brett Heap, 2026-10-23T21:10:31Z, "yes, recommended for M1 and M3" (lead R-413): an enclosing or shared-path row prints next_step_registration_mismatch_holds in its own group. - R-397's --apply test for a .git made after the plan; update --json in the T9 test; clean from a nested directory; the T16 comment. Accepted as R-405 and R-419: the full suite gives 520 OK (skipped=1) at d640539. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Doc round 27 (22cddaa; lead R-407, R-411, R-412): W140's items, T127 on the landing tree, R-406's measured residual, and row 123 covered. Doc round 28 (e3c10c6; lead R-409, R-413, R-415, R-416): Q2 (1) and Q9 (b) as clean's alone, M3's step, Brett Heap's M1 and M3 rulings, W146's items, T127 against #19's 54e869b (102 spans, none missing), and traceability rows 125 and 126. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Lane: openRepoProject-2
Closes #9
Realizes the ratified OpenSpec change
add-project-clean-all-safe(PR #11, landed as 0050f3e on Brett Heap's word "ratify, merge #11 and run the runbook", 2026-10-09) as Speckit feature004-project-clean-all-safe.What changes
git-floorjob in.github/workflows/tests.yml(T003) builds Git 2.36.6 from kernel.org's tarball, checks its sha256 and runs-k test_clean_ -k test_status_ -k test_doctor_; thetestjob is unchanged.projectgains named regions (T004) for the timing table, the bounded runner (child handle, one-wide driver, scoped signal handlers), the five incremental parsers, the 31-name environment scrub (17 names and the 14 trace names of Q9 B, R-99 (b)) with the protocol and status pins, path escaping, the evidence model, and theinternal-errorguard.project clean ROOT --all-safepreviews one plan, the selected worktrees first, then the excluded rows grouped by reason with each group's next step; with--applyit builds, prints and confirms its own fresh plan with one default-No question (Remove N worktrees, keeping N branches? [yes/N]), removes the selected worktrees in canonical order and keeps every local branch at its planned SHA.--yesskips the question;--expect-plan DIGESTrefuses withplan-digest-mismatchwhen the fresh plan's digest differs; no terminal and no--yesrefusesconfirmation-required; bad flag combinations refuseinvalid-arguments. Code:clean()as a fixed pipeline (T047) and its stages (T048 to T057).hidden-local-state,contains-submodule,unstarted-branch,reflog-unavailable). Code: T066 and T067.--apply --action remove --worktree Pbecomes a one-item batch with the same plan, gates, stages, refusal codes and exit statuses; it removes P beside a row it cannot read, among seventeen eligible rows and past the row cap, and removes a merged worktree whose upstream was deleted (Brett Heap's ruling of 2026-10-09). Push anddelete-branchkeep their flags; push refuses a branch whose upstream was deleted (remote-gone) and an incomplete inspection; both print their paths escaped and neither child is signalled (the push child's pins are LQ-3 below). Code: single mode inbuild_plan()(T075),push_or_delete()(T076),execute()andrun_bounded()(T077).extensions.worktreeConfigtrue, and nine or ten where the path of the root or of the common directory holds a line feed (RI-3, below), compares the identities and evidence recorded at planning and refuses at the first difference; the rescan after a removal re-establishes the repository first and reports a branch race without losing a commit. No lock is claimed: the confirmation and the result each state the residual window in one line. Code: T084 and T085.removedonly on rescan evidence. A started removal is never interrupted (5 s floor, 300 s ceiling, a wait line); the result names what was removed, what was not attempted, every branch kept and the next command (the stop block). Code: the removal stages (T091 to T094), with a tick hook inrun_bounded()(R-83 P-1).min(5 s, work remaining), row caps (128, and 256 for the plain report) and a limit of 16 targets per run; a plan that meets the deadline, a budget or a row cap is incomplete, says so and blocks apply, and plainproject cleannow exits 1 when its report is incomplete. Rows past the sixteenth are deferred to the next run (deferred-target-cap) with the plan complete. Code: T099 to T102.cleanmode resolves its argument Git-first to one repository and its main worktree, and refuses what is not a repository root withtarget-not-repository-root(today an absolute path can be redirected to a family holder or a manifest ancestor, and a bare repository's worktrees can be removed). The merge target is found in a fixed, recorded order, with the manifest read bounded at 1 MiB. Code: T107 and T031.$'...'form in text,path_valid_utf8in JSON) or excluded asunsupported-path-bytes, never misread and never passed to a removal. Everyclean --jsonrun but a usage error or an interruption before the apply phase prints one versioned document, and with--applythe human plan and question go to standard error. Code:json_path()andhuman_path()(T017).cleanrefuses an old or missing Git;status,doctorand theupdatereport show aninspection-errorrow instead of refusing; a shape or benchupdaterefuses adirtythat is not exactly false. Code: T117 to T120.README.mdandAGENTS.md(T122, T123): the "Clean up Git worktrees" section opens with the five behaviour changes users will notice (plainproject cleanexits 1 on an incomplete report;cleanrefuses below Git 2.36;--worktree Prefuses a freshly created merged worktree asunstarted-branchand one whose reflog keeps no decisive entry asreflog-unavailable;--worktree Premoves a merged worktree whose upstream was deleted, keeping its branch), then the preview and apply, the gates, the 16-per-run deferral, the result record and recovery; Install states Git 2.36; the exit-code line gainsclean's 1, 143 and 129.AGENTS.mdgains Git 2.36, the clean tests and a section, "Cleaning up worktrees for a person".default_branch(),ancestor(),cleanup_report(),print_clean_report()andmatching_worktree()are removed as baseline helpers that no caller reaches, the list lead ruling R-34 names.cleanup_signature()keeps its caller and stays.tasks.md(L1, R-377; doc round 25, ecd0a7e): 004 no longer editsopenspec/changes/add-project-clean-all-safe/tasks.md; its copy equals main's (15504f1). Three of 004's four hunks there lay on lines OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 rewrote, so the PRs conflicted at landing (R-366, R-368); OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's round (p) carries the four, and 004'stasks.mdrecords it in its Path Conventions (:109-121) and T133's rewritten verify. The landing, the archive and PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's ruling belong to the change's own governance record.registration-mismatchnames the repository's config and the worktree'sconfig.worktree. F-4, F-5, F-6 and F-10 have their texts under Departures. F-7, F-8 and G-4 add--forcefor a worktree that holds a submodule (Q4 (c) adds what to keep first, below); F-9 with G-5 adds--quitwhere--abortfails for a marker with nothing in progress. F-2, in its own commit 64ad453: a locked row's partial-removal note says to unlock it first.tests/test_clean_revalidation.py..gitby onelstat, and the note saysinspect, then git worktree prune and delete PATH by hand, the--forceform where the registry entry and.gitare both present, or, where.gitcannot be read, a third note that says not to prune ("R-284: yes", R-290; "R-324: yes", R-343). O-1: a gate-7 reflog read that the work deadline cuts ends the plandeadline-exceeded, in single mode too (R-283, R-295).operation-in-progress's andinspection-incomplete's steps gain what to delete or unset by hand (R-287 (a)). R-365's build and the Q-build change these notes' texts, below.core.worktreeorcore.bareis refused at resolution with a message that says to unset both in the repository's config, or in the main worktree's config.worktree, then run again (the old message told the person to pass the repository root, R-271); five tests, and W81's three (1061dd7, merged as 769215d, R-302).registration-mismatchunderextensions.worktreeConfigtrue.git worktree prune,git worktree removeof that row and, after three months,git gcdelete the administrative directory of a worktree whose path Git cannot read, so while any plan row's path could not be read every next step that named prune drops it or warns against it, endingdo not run git worktree prune, git worktree remove or git gc until it can(nineTEXTentries). Built in e569564, dfc2baa and e8dda2a (R-312, R-327, R-343), with real-Git subtests for rows 4c and 4b (2057c31, R-344). Q3 (b) adds the dry-run suffix to the plain forms.project:6600, R-322; 42454cb, R-326): an--apply --jsonrun with standard output closed at startup removed worktrees and exited 0 with no JSON; it now refusesinternal-error, exit 2, before any removal. Six tests (R-331)..gitcounts as unread, so R-284's third note prints; rows 4b and 4c read an exit 1 as unset only when Git printed nothing, as OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 D7 says; 7 tests.Probable partial removal: inspect, then delete PATH by hand; a row's path could not be read, so do not run git worktree prune, git worktree remove or git gc until it can.(one newTEXTkey, none changed). T9:status's stale recommendation (repo_state(), shared bydoctorandupdate) ends with the same warning beside an unread row. Three new tests fail at f3724fc and pass here; CI green (run 39953390038); the suite at d8724e2 gives 494 OK. Q3 (a) later replaced (b)'s text; T9 stands..gitfile or admincommondir, or a lone surrogate as a manifest'stracking_branch, endedstatusin a traceback and refused everycleaninternal-error; now the row isinspection-errorand the name no local branch. T10: a branch nameddetachedis classified by its upstream. T19: a failed row 7 makes the rowinspection-error, as pcl:178-179 says, notreview-required. T14:unsupported-path-bytes' step ismove it to a valid UTF-8 path with git worktree move, or mv it and then git worktree repair NEWPATH. T15, T16 and the LOW-5 tests are tests and one comment; T17 was already pinned.projectand six test files,TEXTunchanged; every behaviour test fails at d8724e2 and passes at e702a65.-c core.ignoreCase=falsejoins the status pins and the removal, so that undercore.ignoreCase=truea file that differs only in case from a tracked one is no longer hidden, andgit worktree removeno longer resolves a path to another worktree that differs only in case.registration-mismatch;contains-submoduletakes an entry named.gitthat onelstatfinds in any directory holding an index entry, counted in the filesystem budget and run again at revalidation (step 7,nested_git_check()).Probable partial removal: inspect, then delete PATH and its administrative directory ADMIN by hand., in every mode, superseding R-365's text (T9 stands); (b) every plain text that namesgit worktree pruneends; git worktree prune also deletes the entry, and so the HEAD reflog, of every other worktree whose path is missing, one moved or on an unmounted drive included, so run git worktree prune --dry-run first and remount or repair any it lists that still exists.--forcenotes name their check first (check that git -C PATH status --short --ignored lists only deleted files, then git worktree remove --force PATH by hand; the ceiling's own note keepsinspect), andcontains-submodule's step says to keep each submodule's commits first.git log -g HEAD, git ls-files -v and git status), and the non-drain line defers to each group's next step.hint:lines, or with more than the 4 KiB kept, isprobe-failed, so a repository holdingrefs/heads/HEADhas every rowinspection-error..gitchecks and round (r)'s two scenarios, rows 123 and 124 (Part D).projectandtests/at 41759a4 equal 1579c22's.specs/004-project-clean-all-safe/:spec.md,plan.md,research.md,data-model.md,contracts/project-clean.md,quickstart.md,tasks.md,checklists/requirements.md,traceability.md(124 rows, one per scenario of the three deltas: 100 on main and 24 of OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's), andhand-runs.md(T132's record, 0570efd).change/amend-clean-all-safe-push-pins), and what it brings into this build. OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 is at 4512441, its round (r) (R-395, R-396), and is not merged. Until OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 lands, 004 departs from main's copy of the change wherever OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 amends it; 004's strings equal OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's where OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 states them (R-391, R-396). OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 holds 73, 25 and 26 scenarios in its three deltas, andopenspec validate --all --strictpasses 9 of 9 at 4512441 (R-396). OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 brings in:operation-in-progress(LQ-14), and gate 12,worktree-only-commits(LQ-13). Gate 11 followshidden-local-state, and gate 12 is the last gate. Both run again at revalidation (R-121, R-124, R-127).GIT_TRACE2,GIT_TRACE2_EVENTandGIT_TRACE2_PERFare set to 0 on every Git child, and the scrub grows from 17 to 31 names with 14GIT_TRACEnames that Git 2.36.6 to 2.43.7 read alike (R-99 (d), R-103). Merged into 004 as ab10102 (R-123).state-changedwhatever its step; a decided value keeps its step's reason (a work-tree probe that names another toplevel isidentity-changed;ENOENTorENOTDIRdecides that a path is absent); a read the deadline cuts leaves the targetnot-attemptedwithdeadline-exceeded.contains-submoduleoroperation-in-progressoutranksidentity-changed(R-198). A target's check is at most six Git children, seven where row 4c readsextensions.worktreeConfigtrue (R-168, R-201), and nine or ten where the path of the root or of the common directory holds a line feed (RI-3, above).deferred-target-capare excluded by a gate after it, the preview saysthese deferred rows will not drain while the 16 rows ahead of them are REASONS; follow each group's next step for those worktrees, REASONS naming those gates' reasons, each once, in gate order. It named onlycontains-submodulebefore (R-146 L-f; 310f97d, R-201), and then saidreview those worktrees, then remove them yourself (--force for any that holds a submodule), until Q5 (c28c9ea).~HOME refusal (LQ-15, R-205). Before any Git child,git --versionincluded,clean,status,doctorandupdatetestHOMEandXDG_CONFIG_HOMEfor a non-empty value whose first byte is not/.cleanrefuses withrelative-config-path, exit 2, and the others report it as they report a Git below the floor. AHOMEthat begins with~fails the test, and nothing is read or expanded against it. R-205's two accepted departures are under "Departures for Brett Heap's word" below.GIT_CONFIG_GLOBALandGIT_CONFIG_SYSTEMare the lead's extension, which he kept (O10 (A), R-370; see the residuals below).tasks.mdhunks. (q), 818311a: Q1 to Q9 and aproject-commandclause for T9, so that the parity rule (pc:289-290: baseline values stay, except where a requirement states a change) holds. (r), 4512441: revalidation re-runs Q2 (2)'s<dir>/.gitlstats, a stating requirement for clean's stale recommendations, and M1 and M3 in Open Questions until Brett Heap answers. Round (s) owes the D7 phrasean entry found being a new .git entry, the Open Questions copy of M1 that says "parity rule FR-064" (to become pc:289-290's), and his M1 and M3 (R-396).README.mdandspecs/004-project-clean-all-safe/follow all of this (doc rounds 13 to 26, the last 497f5a3, above).Departures for Brett Heap's word
R-numbers are the lane's lead rulings, cited as in
specs/004-project-clean-all-safe/;rulings:Nis line N of the lead's rulings file,lead-rulings-alignment.md, which is the lead's working file and is not in this repository; the R-numbers and the quoted texts are enough to follow each question, and therulings:Npointers are for the lead. Where the change's text and the build differ, the change's text is given as path:line.rulings:201); R-32a to R-32c (rulings:202-204).openspec/changes/add-project-clean-all-safe/design.md:971(Migration Plan step 6, "Tests intests/test_project.py: one per delta scenario, named after it") andopenspec/changes/add-project-clean-all-safe/proposal.md:625(Impact, "tests/test_project.py: each ADDED and MODIFIED requirement has a test named after its scenario").tests/test_clean_<lane>.pyand intests/test_status_doctor_update.py, with helpers intests/clean_support.pyand the launcher intests/launch_project.py;tests/test_project.pychanges in one method (T046,test_clean_revalidates_a_worktree_after_confirmation) and one loader line (T009, thesys.modulesregistration). Stated atspecs/004-project-clean-all-safe/tasks.md:48-53,plan.md:348-356andresearch.md:664-700.tests/test_project.pybefore the merge.AGENTS.md(T123), outside the proposal's Impact.rulings:201: plan.md, research R15 and quickstart follow tasks.md onAGENTS.md(T123)).openspec/changes/add-project-clean-all-safe/proposal.md:598,:612and:625, the Impact bullets forproject,README.mdandtests/test_project.py; nothing in the change namesAGENTS.md. Stated atspecs/004-project-clean-all-safe/tasks.md:54-56andplan.md:352-354.AGENTS.mdgains Git 2.36 and the clean tests with their commands under "Runtime and verification", and the section "Cleaning up worktrees for a person"; theOPENSPEC-SPECKIT-GLOBALblock andCLAUDE.mdare untouched.AGENTS.mdhunk (T123) is dropped before the merge (the lead's proposed fallback).rulings:208) and R-46 (rulings:239).openspec/changes/add-project-clean-all-safe/proposal.md:651-652("on Linux and macOS with Python 3.10 and 3.12, as CI runs";:648anddesign.md:55also name macOS). The change text stays as written, since ci: run the test suite on Linux only #32 leaves historical records underopenspec/andspecs/alone.testmatrix runs onubuntu-latestonly, and the feature's text counts no jobs (R-46); thegit-floorjob runs onubuntu-latestwith Python 3.10 and Git 2.36.6.specs/004-project-clean-all-safe/tasks.md:58-64,plan.md:357-362).probesandoperationscount.rulings:185), read by R-57 L4 (rulings:325) and R-59 D10 (rulings:347);specs/004-project-clean-all-safe/research.md:368-406andspec.md:1805-1815.openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md:868(scenario "Bounded revalidation work": "the record'sprobes.performedequals the wrapper's count"), which read literally includes the three removals.probes.performedcounts every Git child other than a removal child andoperations.performedcounts the removal children (3 in that scenario), each child once, as the packet counts them (ideation/brainstorm/project-maintenance-batch-cleanup.md:816-830at da33d92). It awaits his word through draft PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's commitcecb4fc, "State which count holds the removals".probes.performedcounts the removals too, and the counters and the assertions of T096 to T098 and T102 follow.status'sworktrees(LQ-9, widened below, which T117 now calls two departures).GIT_INTERNAL_SUPER_PREFIXadded to the scrub (openspec/changes/add-project-clean-all-safe/proposal.md:766-776, a departure from task 2.2's rule that the floor is raised to the lowest version verified), and the bounded runner (proposal.md:795, a departure fromBA:1212-1213): both stand in the proposal's departures list, which Brett Heap ratified with OpenSpec: add-project-clean-all-safe (batch worktree cleanup from the maintenance design packet) #11's merge. The build keeps both as the change states them.~target refuses under aHOMEthat fails the relative-path test (lane 3's W30 M-1 found the crash, R-202).rulings:1576), on R-202 M-1 (rulings:1563); lane H's addendum 1 at 22f95d1, merged as 0b7dd94 (R-206, R-209;rulings:1587-1588).status,doctorandupdatereport a failed configuration-path test as they report a Git below the floor (design.md:845-848, andproposal.md:317-322, at f0bf538), which names no target argument that needs~expanded; and the baseline, whereHOME=~orHOME=~/xcrashedstatus,doctorandupdatewithRuntimeError: Could not determine home directory.(rulings:1563).~expanded,~alone or~/..., refuses withrelative-config-pathand the message aboutHOME, exit 2, with no Git child;~useris read from the user database and expands as before. AHOMEof~,~/xor~userfails the test like any relative value, and nothing is read or expanded against it (home_directory(),expand_user();contracts/project-clean.md:728-729at 4f921f8).newrefuses under aHOMEthat fails the test.rulings:1577): "newis outside LQ-15; a defensive refusal is safer. Record it in Add project clean --all-safe, a safe batch worktree cleanup (feature 004-project-clean-all-safe) #33's body for Brett."clean,status,doctorandupdate(proposal.md:957-983); and the baseline, wherenewraised a traceback or created the project under a relativeh/projects.newwith no parent argument, no--intoand noPROJECTS_DIR, under aHOMEthat fails the test, has no default parent and refuses with the message aboutHOME, exit 2 (contracts/project-clean.md:747-751at 4f921f8).newis as at the baseline, a traceback or a project under a relativeh/projects.new --into ~/xunder a~HOMEstill raises a traceback. It is outside LQ-15 (R-205's LOW follow-up,rulings:1578;contracts/project-clean.md:752-753records it).rulings:1719-1722), verbatim "F-2: yes; F-1: prune-then-delete; O-1: deadline-exceeded"; he added "R-284: yes" for F-1's note on an unreadable.git(R-290,rulings:1869).0050f3etext of theproject-cleandelta (openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md, pcl): pcl:135-138 (F-2), pcl:253-256 and pcl:922-926 (F-1), pcl:606-608 (O-1). OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's round (h) at b3228bb lists the three under "Amendments of ratified text" (proposal.md:1152-1184, R-270).--indelete-branch, declared in the contract (W65's LOW-2, R-269,rulings:1742-1746; R-259,rulings:1701).BA:424-425, "pushanddelete-branchkeep their behavior apart from argument resolution"; neither the packet nor OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 states the--(OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's D18 notes it,design.md:1309).git -C ROOT branch -d -- BRANCH, so--branch=-fdeletesrefs/heads/-f, where the baseline'sbranch -d -ffails (exit 128); theCleanup action:line prints the--(contracts/project-clean.md:676,:680-689at 7164d7f).--leaves the argv and its test; a branch whose name begins with-cannot be deleted bydelete-branch.rulings:1669; W59's G-2, R-253,rulings:1681-1683; R-258,rulings:1694-1696).BA:424-425and the baseline's message for any holder,Remove the linked worktree first; branch deletion is a separate action.(15504f1:project:730), which for the main worktree names a removal that Git refuses. OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 lists it among the departures that take effect only when he ratifies OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 (proposal.md:875-883).Branch B is checked out in the main worktree; detach HEAD there, or check out T there, then retry., T the merge target; trigger, exit status and every other message stay the baseline's (contracts/project-clean.md:300). If he declines: the baseline's message returns for every holder.rulings:1701; "not stated in OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 and are 004-only", R-251,rulings:1676).proposal.md:1858-1860):15504f1:project:607and:610for the main worktree's merged rows ("may be removed explicitly", "switch away before removal") and:568for a lockedstale-worktreerow ("Review and prune stale worktree metadata manually.").row_evidence()replaces the advice after the ladder, the class unchanged:The main worktree is never removed by project clean., andReview, unlock it, then prune stale worktree metadata manually., sincegit worktree prunekeeps a locked entry (contracts/project-clean.md:402-409); Q3 (b) later adds the dry-run suffix to both stale recommendations. If he declines: the baseline texts return.proposal.md:1243at 173d83c, and quotes RI-3's departure at:1167, R-293).rulings:1701), where the path of the root or of the common directory holds a line feed (git rev-parsehas no NUL form): a revalidation spawns up to nine children (ten withextensions.worktreeConfigtrue) and the final rescan up to six, againstBA:679(at most five children),BA:726-727andBA:743(three for the final rescan); it is W70's one new DEPARTS. F-7 and F-8 (R-248, R-252) change ratified next-step texts to add--force.rulings:2125): through the question tool, answered 2026-10-23T11:49:16Z, "Yes, warn (Recommended)" for F-1's (b) and "Yes, add T9 (Recommended)" for T9.specs/004-project-clean-all-safe/spec.md:1863-1886at 497f5a3, its dated notes; R-399), which keeps baseline functions unchanged, and OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's parity rule (pc:289-290: baseline values stay, except where a requirement states a change); F-1's (b) amends the ratified F-1 text (pcl:253-256, pcl:922-926), under the F-1 entry above.status,doctorandupdateend the stale-entry recommendation, "Review the stale worktree metadata before pruning it manually.", with; a row's path could not be read, so do not run git worktree prune, git worktree remove or git gc until it can.beside an unread row; with every path readable it is the baseline's text byte for byte (7a20789; declared incontracts/project-clean.md; stated in OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's round (q), R-380). Q3 (a) later replaced F-1's (b) text; T9 stands. If he declines: not applicable, he ruled.rulings:2161). Each of the nine stated a lean (wave22/outputs/triage.md, section 3), so each is taken as recommended. They amend ratified text of theproject-clean,project-commandandproject-clean-review-safetydeltas, as OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's round (q) restates it; none is a departure from OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19.specs/004-project-clean-all-safe/spec.mdrecords each changed behaviour in a dated note under FR-054 and FR-011 (Q1), FR-055 (Q2 (1), Q9 (b)), FR-023, FR-046 and FR-047 (Q2 (2)), FR-028 (Q3, and Q4 (c)'s and Q5's texts), FR-009 (Q4 (a), (b)), FR-020 (Q5, Q4 (c)), FR-032 (Q5) and FR-057 (Q8); FR-064's note records that Q3 (b)'s warning is not given tostatus(M1, below). If he declines: not applicable, he ruled.BA:271-272; a revalidation read or child that the work deadline cuts counts as no difference,proposal.md:1113-1126) and 19-11 (BA:424-425; push refuses a wider set of upstream mappings with the baseline's message,proposal.md:1127-1135). 004 builds both as OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 states them, and with F-5 they take effect only when he ratifies OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 (R-258).Ratified with #11 and not reopened here: V1, V4, V5, V10, OQ-23, OQ-24, R-4, R-8, R-9, R-21 and the runner (the departures record,
rulings:183).Open questions for Brett Heap
git cherryor patch IDs against the merge target) count a squash-merged branch as merged? The build now: ancestry alone proves a branch merged, so a squash-merged branch is never selected and a squash-merging repository's batch selects little (specs/004-project-clean-all-safe/spec.md:780-786, EC-001;:1780-1788). Recommendation: a local patch-equivalence proof as a follow-on change, not in this feature (openspec/changes/add-project-clean-all-safe/design.md:999-1001;proposal.md:1001-1005). Rulings: V1 to V3 (rulings:104), the naming note (rulings:181), the departures record (rulings:183).openspec/changes/add-project-clean-all-safe/specs/project-command/spec.md:113-117; design D11), but the retained push needs its child to reach a remote, and a pinned push endsfatal: transport 'file' not allowed, exit 128; so (a) amend the unarchived change by draft PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 (branchchange/amend-clean-all-safe-push-pins), or (b) a follow-up change after the archive? The build now: the push child runs throughexecute()with none of the seven pins, inproject's own process group, unbounded, never signalled and waited for, and keeps the caller'sGIT_ALLOW_PROTOCOL; the other 30 of the 31 scrubbed names stay removed from it, and it carries the three trace2 pins at 0; every other Git child, thedelete-branchchild included, keeps the 31-name scrub and the pins (specs/004-project-clean-all-safe/research.md:32-101;contracts/project-clean.md:601-603). Recommendation: (a). If he rules (b), only the push child's treatment moves: T074, T077 and the push halves of T076 and T073 (specs/004-project-clean-all-safe/tasks.md:4216-4219). Rulings: R-28, R-31, R-80 (P-9 to P-11 and P-14; no ruling), R-81 (b). PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 is an open draft at 4512441.openspec/changes/add-project-clean-all-safe/specs/project-clean-review-safety/spec.md:94-96; scenario "New worktree and pre-removal changes",:134-141) also cover a later target's per-worktree ignored-file state and classification before the first removal, which the child budgets of D7 (at most five per target in main's copy, six, or seven where row 4c reads true, in OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's) do not provide? The build now: the first target's revalidation compares every selected target's registration, lock, filesystem identity, branch tip and upstream object, and the merge-target SHA; a difference on any target refuses the FIRST target with the matching reason, removes nothing and leaves later targetsnot-attemptedwithbatch-stopped, and the refusal does not name the differing path; ignored-file state and classification are checked in each target's own revalidation before its own removal (specs/004-project-clean-all-safe/research.md:702-755). Recommendation: none given; the build follows R-41's reading. Rulings: R-41 (rulings:214,:227), R-77, R-80 (P-9 to P-11 and P-14; no ruling), R-82.git worktree prune,git worktree repairor removing the offending row by hand "as the cause fits" (openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md:649-651) let a cause that no repair fixes name its own remedy? The build now: D18'sdeadline-exceededremedy, "the run ran out of time; remove worktrees explicitly or re-run", names none of the three and stands (specs/004-project-clean-all-safe/contracts/project-clean.md:340-345). Recommendation: none given; R-45 (7) keeps the reading. Rulings: R-45 (7) and R-80 (P-9 to P-11 and P-14; no ruling).ghchild), or do OpenSpec: add-project-clean-branch-retirement (opt-in paired retirement of a removed worktree's local branch) #26 and OpenSpec: add-project-overview-remote-merge-status (opt-in exact-head GitHub pull-request evidence in project overview --remote) #29 carry their own MODIFIED blocks? The build now: this feature builds nothing for it and PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's text is not widened; OpenSpec: add-project-clean-branch-retirement (opt-in paired retirement of a removed worktree's local branch) #26's block is 16051d1 and OpenSpec: add-project-overview-remote-merge-status (opt-in exact-head GitHub pull-request evidence in project overview --remote) #29's is f66ed58, both written against PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's text at c462d87 and both still in their PRs (open drafts), and whichever archives second re-bases. Recommendation: none beyond the ruling, which keeps the two blocks separate unless he prefers that PR OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 absorb them. Rulings: LQ-6 (rulings:238) and the LQ-6 record (rulings:279).project-cleandelta (openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md) that disagree,:940-941(an unexpected exception before the apply phase refusesinternal-error, exit 2) and:958-960(a preview or report exits 2 only for a refusal raised before a plan is built); which governs, and should an internal error after the apply phase begins print its exception's type on standard error? The build now (R-55): before the apply phase the write failure isinternal-error, exit 2, nothing mutated; the first failed write points that stream at/dev/null; a recorded signal outranks it (130, 143 or 129 withCancelled.); after the apply phase begins writes are best-effort and D19 decides the exit; with standard output closed,--action pushexits 2 withREFUSED: BrokenPipeError: [Errno 32] Broken pipeand starts no child, and an--apply --jsonrun with it closed at startup refusesinternal-error, exit 2, before any removal (R-322, R-326); an unwritable question isinternal-error, notcancelled; after the apply phase begins no exception type or text is printed (specs/004-project-clean-all-safe/contracts/project-clean.md:326-338). Recommendation: R-55's reading stands until he rules; none given on printing the type. Rulings: R-55, R-59 (D1 to D3), R-74 (c) (3), R-76 (g), R-80 (P-9 to P-11 and P-14; no ruling), R-81 (b), R-87 (c), R-91.\xHH, which every shell with$'...'reads alike in any locale, while the display form keeps\uand\U? The build now: it implements the delta as written (openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md:1061-1066),\xHH,\uXXXXand\UXXXXXXXXin text and commands alike, and documents the limit: the command needs bash, zsh, ksh93 or a POSIX.1-2024 shell, not dash, and a\uor\Uescape needs a UTF-8 locale, since in a C locale it can name a different path or branch (specs/004-project-clean-all-safe/contracts/project-clean.md:378-395;quickstart.md:228-231). Recommendation: the\xHHamendment, not applied (R-61 (a)). Rulings: R-60, R-61 (a), R-80 (P-9 to P-11 and P-14; no ruling), R-83 (P-2), R-92 (a).status'sworktrees. Question: does theproject-cleandelta's "the common directory SHALL never be probed as a worktree row" (openspec/changes/add-project-clean-all-safe/specs/project-clean/spec.md:478) coverstatus'sworktrees, so that leaving a bare repository's registry entry out is a fill, or is it a departure from theproject-commanddelta's "Values SHALL equal those of the inspection this model replaces, except where a requirement states a change" (openspec/changes/add-project-clean-all-safe/specs/project-command/spec.md:196-197) that needs his word? Lane 3's F5 M-2 widened it (R-101 (e),rulings:960,:1012): for a gitfile layout, a separate git directory or a submodule's checkout, the git directory's record becomes the checkout's row, with itsdirtyandignored_filesread there, false and 0 where they were null; the lead accepted that as a fill too. The build now: T117 leaves a bare repository's registry entry out ofworktrees(specs/004-project-clean-all-safe/tasks.md:3804-3820;plan.md:419-433). Recommendation: a fill, which the lead and lane 3 recommend, since:478anddata-model.md:18both say the common directory is never a worktree row. Rulings: R-75 (a), R-81 (d), R-101 (e).rulings:1042-1064): "LQ-15: yes, refuse relative HOME like OpenSpec: add-project-overview-remote-merge-status (opt-in exact-head GitHub pull-request evidence in project overview --remote) #29" in this lane's session (rulings:1043); "yes to all six recommendations, LQ-10 to LQ-15" in lane 3's (rulings:1044). Each is OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's text now, so none is a departure (R-102 (c) 5): the stat pins (LQ-10, ab10102), a redirected work tree read asregistration-mismatch(LQ-11, 91552e3), update's owner tools run with the push child's scrub (LQ-12, 2439838),worktree-only-commits(LQ-13, 93a3ae9),operation-in-progress(LQ-14, e0c589a) andrelative-config-path(LQ-15, 5794f91, with addendum 1 for a~HOME, 0b7dd94).includeIfor a submodule) runs inside every read-only status probe: report, preview,status,doctor, revalidation, and a fresh clone alike. That is user code in a "read-only" probe. Should those probes neutralize every configured clean and process filter? Lane 3's reader RA checked the fix, an empty-c filter.<x>.clean=for each configured filter. It fails safe: a filtered file whose stat changed then shows as modified and the worktree is kept (R-105 H2,rulings:1092-1093). The build now: nothing; the probes run configured filters as Git does. The exposure stays under an absoluteHOME(R-107,rulings:1120; R-125 L2,rulings:1238). Recommendation: yes, in the read-only probes only. The removal child keeps the user's own filters, since it is a confirmed mutation once LQ-15 holds (R-105 (b),rulings:1098).git statuswrites the index and firespost-index-change, andbranch -dfiresreference-transaction. Should the removal and branch children run with-c core.hooksPath=/dev/null, as RA's checked fix has it (R-105 H3,rulings:1094-1095)? The build now: nothing; both children run the repository's own hooks, as Git does and as the baseline did (e45155a:project:719and:734, R-105 (b)), with nocore.hooksPathpin. Recommendation: AGAINST suppressing hooks. Areference-transactionhook can veto a ref deletion and may be the user's guard on a branch, so suppressing it would bypass a protection, andpost-index-changeonly informs.--no-follow-tagsand--recurse-submodules=no, so that the push does only what the plan shows? A configuredpush.followTagsorpush.recurseSubmoduleswould make it do more (R-108 (b),rulings:1127; R-130,rulings:1275). The build now: neither flag is passed, and the push child follows the repository's configuration asgit pushwould; they are not built until he rules. Recommendation: yes, pass both.GIT_EXEC_PATHmadeworktree removerun a plantedgit, exit 0, which the amendment writer reported at its checkpoint (R-114,rulings:1174). Should LQ-15's relative-path test cover it? APATHwith an empty or relative entry is the same class, not recommended. The build now: nothing; the test coversHOME,XDG_CONFIG_HOME,GIT_CONFIG_GLOBALandGIT_CONFIG_SYSTEMonly, and OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 says other relative paths in the environment are outside it (design.md:850-852at f0bf538). Recommendation: addGIT_EXEC_PATHto the test. It goes to him with R-132's question onupdate, in the residuals below.rev-listover 9,940 commits 160.3 ms, with the margin; the cap test passes, the 16th removal spawning at 30.0 s with 20.0 s left. OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's round (f) records it (662be89, R-247).rulings:1719-1722); "R-284: yes" (R-290,rulings:1869), for the third note where Git cannot stat.git, which his F-1 question had not covered (W73 M-1); "R-307: yes; R-310: yes" (R-319,rulings:1976) for T1 to T5; "R-320: yes" (R-321,rulings:1987) for T6 to T8; and "R-324: yes" (R-343,rulings:2084), which extends them: every no-prune warning ends "do not run git worktree prune, git worktree remove or git gc until it can", sincegit worktree removeandgit gcalso delete an unread row's administrative directory. OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 carries the texts in round (n) (R-345), 004 in e8dda2a.rulings:2125): "Yes, warn (Recommended)" for F-1's (b), where a ceiling-cut P sits beside an unreadable sibling, and "Yes, add T9 (Recommended)" forstatus's stale-entry advice beside an unread row (the questions of R-310, R-324 and R-327). Built in 7a20789; Q3 (a) later replaced (b)'s text, and T9 stands (R-380).inspection-incompleteat seven sites. Lane 4 brings it to him, (A) mirror O-1, which lane 4 recommends and lane 2 supports, or (B) keepinspection-incompletewith a difference in D12 (R-273,rulings:1768).design.md:493-496andproposal.md:1657-1661at f0bf538). Question: R-208 readsBA:271-276, "a value that cannot be re-read, including a filesystem call that times out, counts as a mismatch", this way: a read that fails decides no identity difference, so its mismatch is the packet's "any other" difference,state-changed, for a Git child and for a filesystem read alike. Does he confirm it? The build now: it builds that reading (73d8888, merged as 9ab996e, R-218). The rules are under What changes (R-208, R-212).wave23/brett-questions-w133.md). Question: dostatus,doctorandupdate, with no row's path unread, take Q3 (b)'s dry-run warning on their plain stale advice, "Review the stale worktree metadata before pruning it manually."? It names no command, so Q3 (b) did not reach it; lane 3 calls it a gap that needs his word, not a departure. The build now: the baseline text stays (FR-064's note, R-380). Recommended (a): no. It names no command and already says to review first; the warning matters most in clean, where the prune advice sits beside one row and reads as about that row alone; and keeping it adds no second departure, across three commands, from the parity rule (pc:289-290) and no change to the status rules lane 4's 005 reads. (b) Yes: all three end it with Q3 (b)'s dry-run warning (Q3 above). That is a second departure from the parity rule, and changes 004's code and tests, OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's pc:308-309, :394 and D18, lane 4's pin and lane 5's OpenSpec: add-project-overview-remote-merge-status (opt-in exact-head GitHub pull-request evidence in project overview --remote) #29 block.registration-mismatch, and prints that class's next step, which ends "... or remove the row by hand". Followed literally for such a row, that step deletes the main worktree and the repository, or the other worktree (confirmed on plain Git, triage T2). Should such a row get its own step? The build now: the class's step, (c). Recommended (a): yes, "its path is or holds the main worktree, the common directory or another worktree, so do not delete it by hand or with git worktree remove; review its registration with git worktree list --porcelain" (197 characters, inside lane 4's 200-character rule; a row that shares its path with another row takes it too, R-67 (c)); a new next-step text in 004 (code and tests) and OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's D18. (b) No next step for such a row, and D18 says why: simpler, but no guidance. (c) Keep the class's step: not recommended, unsafe as worded.Also open from #11, and known residuals
openspec/changes/add-project-clean-all-safe/design.md:906-912; R-24). Under heavy load a plan reaches the deadline and goes incomplete withdeadline-exceeded; it is never unsafe.GIT_CONFIG_GLOBALandGIT_CONFIG_SYSTEM(R-102 (c) 3,rulings:1054-1055). The two are the lead's extension of his ruling, Git's own config-path variables, and he ruled to keep them: O10 (A), "yes, recommended for O3, O5, O8-O11 and D5 clause 2" in lane 4's session (2026-10-23T12:19:11Z; R-370). OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 states them in one separate sentence (design.md:803-828at f0bf538; R-115 L2,rulings:1179).update's scope under LQ-15, to be put with LQ-19 (rulings:1284-1292). The build follows OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's D16 (R-131 (a),rulings:1279): under a badHOME,update --applyrefusesshapeandbenchonly, andworkflowandtoolsstill run. Lane 3, as packet owner, recommends thatupdaterefuse every component withrelative-config-path, exit 2, before any child, owner tools included, with no substituteHOME: an owner tool'sgit -C <repo>reads the planted configuration, OpenSpec: add-project-overview-remote-merge-status (opt-in exact-head GitHub pull-request evidence in project overview --remote) #29's C-44 refuses up front, a substituteHOMEwould change what the tools read, and the cost is one re-run with an absoluteHOME. Until he rules, 004 builds OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19's text as written.allow=alwaysin the repository's configuration still runs its helper fromPATH, which the protocol pins cannot stop. It is R-25's accepted residual (OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19, Decisions), rated LOW. The rulings hold it "to be read and put to Brett Heap with the other LQs" (R-116,rulings:1188); no LQ number records it yet.tasks.md:123-127at 173d83c) is unticked: the push-child exception ratified by his word on OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19, with his words and the link still to fill. It waits for LQ-3. His words on Q9 B, on LQ-10 to LQ-15, on LQ-20 and on F-2, F-1, O-1 and R-284 are recorded in task 1.2, which is ticked. 004 plans under the exception until he rules (specs/004-project-clean-all-safe/spec.md:1801and:1879).update'stoolscomponent reaches the host'sworkBenchesfrom any root (R-202,rulings:1568). An ad hocupdate <fixture> --apply --component tools --yesran the host's realsetup.shonce, writing two gitignored files. This is existing behaviour, outside 004's scope; tests must put fake owner tools first onPATH.refs/heads/HEADmakes every rowinspection-error, not only that branch's (R-116,rulings:1184-1186). Git warnsrefname 'HEAD' is ambiguous.on standard error in every worktree's status probe, and a status probe whose standard error holds anything but Git'shint:lines isprobe-failedwithunparseable output. It fails closed (R-61 (b),rulings:358-361), and Brett Heap's Q8 puts the rule into OpenSpec: amend add-project-clean-all-safe so the push child reaches its remote #19 with this consequence (R-380).branch.B.remotethat is a path or a URL reads as unpublished, and a push then re-points the upstream toorigin, as the baseline does (R-108 (d),rulings:1129). Recorded for a later evidence ruling; no change now.git-floorjob and passes since c9103ba, with four S8714 issues left open on purpose (R-99 (a), R-100 (f), R-106).rulings:1747), a baseline function, left as a follow-on:repo_state()'s advice for a stale entry, "Review the stale worktree metadata before pruning it manually." (project:6806at 7164d7f; baseline15504f1:project:501), omits unlocking for a locked entry, whichgit worktree prunekeeps; FR-064 keeps baseline functions unchanged. The no-prune warning beside an unread row is T9, ruled (R-365).status's text (R-380; M1 above)..gitlstats of Q2 (2) are not measured on a worktree with very many tracked directories (R-398). They fail closed: a call over budget makes the rowinspection-errorat planning orstate-changedat revalidation..gitmade after the plan through--apply(R-397); the exit 2 and the later target'sbatch-stoppedare pinned forcontains-submoduleonly with amodulesdirectory (test_clean_submodules_after_confirmation). It is for the next code round, with M3's step.core.worktreewhose target is missing gets the plain message, a submodule's redirect takes the variant, and a main checkout whose.gitis a symlink gets the plain refusal, as before (W81 O-3).Gate
R-76 (b) says this PR opens only when every task of feature 004 has landed, T084, T085, T092, T093 and T099 among them, and that its body names this gate. Tasks ticked: 133 of 133 at 41759a4, the head. The final gates ran at 4f921f8; the rows below are restated at later heads where a ruling gives them. The code merge the suite runs at is 1579c22 (703b58c, the Q-build, on the A-items e702a65, on d8724e2, R-365's build on f3724fc); 41759a4 adds doc rounds 25 and 26 (497f5a3), docs only.
merge-treeof 41759a4 with #19's 4512441 is clean, and change 1'stasks.mdequals main's copy (L1, R-377). Lane 3's sweep at d6bac50 is done (R-358, R-360); its batched read of 41759a4 and 4512441 is pending. Merges to main wait on Brett Heap's word, and so do the OPEN questions above, M1 and M3. Landing steps still owed: main (15504f1) merged into 004, with no rebase; the hand runs (T132) walked again at the landing head, by the lead through tmux or by Brett Heap (R-50, R-360); and his word. #19 lands first. Line cites tospecs/004are at 4f921f8 and to #19 at b3228bb, unless a cite names another sha.origin/main(e45155a) was merged into the branch as 05e6218, never rebased; it now reads 15504f1, with #21 (b233333) and #28 (15504f1) after e45155a, both OpenSpec changes only, and is not yet merged here.Verification
tests/test_*.pycount andtests/test_project.pyunchanged but the one method and the loader linetests/test_project.pydiffers from main in the loader line and T046's method onlygit version 2.36.6; the 14 touched modules, 299 tests OK (R-398);test_status_the_sixteenth_scrubbed_name_on_git_2_36ran and passed, not skipped (4f921f8); every earlier round's modules passed on 2.36.6 too (R-274 to R-352), and T129 passes at d6bac50 (R-360)/usr/bin/openspec validate --all --strict(T130)parser()changed undercleanonly;requirements.txtunchanged. Exit 0 at every head a ruling gives, e69f6ef to d6bac50 (R-202 to R-360), and at 7a20789 (R-372), e702a65 (R-385), 8e90096 and 8abd901 (R-393, R-394, R-398; non-ASCII 0, unlisted [])hand-runs.md)projectat e69f6ef, 41 of 41 MATCH (R-250, R-255; 0570efd); three runs walked again at d764c26, all MATCH (R-259); T132's verify exit 0 at f6e3d4b (R-272). Not re-walked since, and owed again at the landing head (R-50, R-360); T132 stays tickedtraceability.md); T002 and T126 passtestjobs andgit-floor)Lane 3's packet-fidelity and delta reads of this feature and of #19, with counts as the rulings record them (H, M, L are HIGH, MEDIUM, LOW):
Landing
Draft until the gate is met and the independent re-verification is posted here. Lands by squash only on Brett Heap's word for this PR, naming lane, PR and head, after #19 lands; the hand runs (T132) are walked again at that head first (R-360). If main moves (15504f1 now), main is merged in, with no rebase and no force push. After landing comes the archive PR for
add-project-clean-all-safe(runbook step 3), on Brett Heap's word.🤖 Generated with Claude Code