Here's the scenario that can produce bad empty namespace LCAs: ```deletes of v4 j1: ... - v1 - v2 - v3 - v4 - v4a - v5 - v6 - v7 / - v5a adds of unrelated j2: ... - v1 - v2 - v3 - v4 - x0 - x1 - x2 - x3 / - z1 ``` So `j1` and `j2` have common history up through `v4`, then `j1` deletes some definitions while `j2` adds some definitions via shallow merges. These shallow merges then result in the LCA being the empty namespace rather than `v4`. First, we create some common history before a fork: ```ucm ☝️ The namespace .a is empty. .a> alias.term .builtin.Nat.+ delete1 Done. .a> alias.term .builtin.Nat.* delete2 Done. .a> alias.term .builtin.Nat.drop delete3 Done. .a> alias.type .builtin.Nat Delete4 Done. ``` Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previously and then adding one unrelated term via a merge with little history. It's this short history merge which will become a bad LCA of the empty namespace. ```ucm .> fork a a2 Done. .a> delete.term delete1 Name changes: Original Changes 1. a.delete1 ┐ 2. a.delete1 (removed) 3. a2.delete1 │ 4. builtin.Nat.+ ┘ Tip: You can use `undo` or `reflog` to undo this change. .a> delete.term delete2 Name changes: Original Changes 1. a.delete2 ┐ 2. a.delete2 (removed) 3. a2.delete2 │ 4. builtin.Nat.* ┘ Tip: You can use `undo` or `reflog` to undo this change. .a> delete.term delete3 Name changes: Original Changes 1. a.delete3 ┐ 2. a.delete3 (removed) 3. a2.delete3 │ 4. builtin.Nat.drop ┘ Tip: You can use `undo` or `reflog` to undo this change. .a> delete.type Delete4 Name changes: Original Changes 1. a.Delete4 ┐ 2. a.Delete4 (removed) 3. a2.Delete4 │ 4. builtin.Nat ┘ Tip: You can use `undo` or `reflog` to undo this change. ☝️ The namespace .newbranchA is empty. .newbranchA> alias.term .builtin.Float.+ dontDelete Done. .> merge newbranchA a Here's what's changed in a after the merge: Added definitions: 1. dontDelete : Float -> Float -> Float Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you can use `undo` or `reflog` to undo the results of this merge. .a> find 1. dontDelete : Float -> Float -> Float ``` Meanwhile, `a2` adds some other unrelated terms, some via merging in namespaces with little history. When merging `a2` back into `a`, the deletes from their common history should be respected. ```ucm .a2> alias.term .builtin.Text.take keep1 Done. .a2> alias.term .builtin.Text.take keep2 Done. .a2> alias.term .builtin.Text.take keep3 Done. .a2> alias.term .builtin.Text.take keep4 Done. .a2> alias.term .builtin.Text.take keep5 Done. ☝️ The namespace .newbranchA2 is empty. .newbranchA2> alias.term .builtin.Text.take keep6 Done. .> merge newbranchA2 a2 Here's what's changed in a2 after the merge: Name changes: Original Changes 1. keep1 ┐ 2. keep6 (added) 3. keep2 │ 4. keep3 │ 5. keep4 │ 6. keep5 ┘ Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you can use `undo` or `reflog` to undo the results of this merge. .a2> find 1. delete1 : Delete4 -> Delete4 -> Delete4 2. delete2 : Delete4 -> Delete4 -> Delete4 3. delete3 : Delete4 -> Delete4 -> Delete4 4. builtin type Delete4 5. keep1 : Delete4 -> Text -> Text 6. keep2 : Delete4 -> Text -> Text 7. keep3 : Delete4 -> Text -> Text 8. keep4 : Delete4 -> Text -> Text 9. keep5 : Delete4 -> Text -> Text 10. keep6 : Delete4 -> Text -> Text ``` ```ucm .> fork a asquash Done. .> merge a2 a Here's what's changed in a after the merge: Added definitions: 1. ┌ keep1 : Delete4 -> Text -> Text 2. │ keep2 : Delete4 -> Text -> Text 3. │ keep3 : Delete4 -> Text -> Text 4. │ keep4 : Delete4 -> Text -> Text 5. │ keep5 : Delete4 -> Text -> Text 6. └ keep6 : Delete4 -> Text -> Text Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you can use `undo` or `reflog` to undo the results of this merge. .> squash a2 asquash Here's what's changed in asquash after the merge: Added definitions: 1. ┌ keep1 : Delete4 -> Text -> Text 2. │ keep2 : Delete4 -> Text -> Text 3. │ keep3 : Delete4 -> Text -> Text 4. │ keep4 : Delete4 -> Text -> Text 5. │ keep5 : Delete4 -> Text -> Text 6. └ keep6 : Delete4 -> Text -> Text Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you can use `undo` or `reflog` to undo the results of this merge. ``` At this point, all the things that `a` has deleted (`delete1`, `delete2`, etc) should be deleted in both the merged and squashed results. Let's verify this: ```ucm .a> find 1. dontDelete : Float -> Float -> Float 2. keep1 : Delete4 -> Text -> Text 3. keep2 : Delete4 -> Text -> Text 4. keep3 : Delete4 -> Text -> Text 5. keep4 : Delete4 -> Text -> Text 6. keep5 : Delete4 -> Text -> Text 7. keep6 : Delete4 -> Text -> Text .asquash> find 1. dontDelete : Float -> Float -> Float 2. keep1 : Delete4 -> Text -> Text 3. keep2 : Delete4 -> Text -> Text 4. keep3 : Delete4 -> Text -> Text 5. keep4 : Delete4 -> Text -> Text 6. keep5 : Delete4 -> Text -> Text 7. keep6 : Delete4 -> Text -> Text ``` ```ucm .> view a.Delete4 ⚠️ The following names were not found in the codebase. Check your spelling. a.Delete4 ``` ```ucm .> view asquash.delete1 ⚠️ The following names were not found in the codebase. Check your spelling. asquash.delete1 ```