Repository: exercism/julia
Pull request #869: Inventory management
Author: login: colinleach
Created: 2025-04-05T00:00:13Z | Merged: 2025-04-05T15:29:56Z

This currently uses a new UUID. Should we instead try to recycle one, such as `old-annalyns-infiltration`? I'm undecided.

It will probably fail linting, because the `pairs-and-dicts` concept is not yet merged.


Diff:
diff --git a/config.json b/config.json
index fccf6b271..7bd33aeb4 100644
--- a/config.json
+++ b/config.json
@@ -129,6 +129,18 @@
         ],
         "status": "wip"
       },
+      {
+        "slug": "inventory-management",
+        "name": "Inventory Management",
+        "uuid": "53e333ee-4aad-4c1e-9347-4cc17abacad3",
+        "concepts": [
+          "pairs-and-dicts"
+        ],
+        "prerequisites": [
+          "loops"
+        ],
+        "status": "wip"
+      },
       {
         "slug": "high-school-sweetheart",
         "name": "High School Sweetheart",
@@ -137,7 +149,7 @@
           "function-composition"
         ],
         "prerequisites": [
-          "functions"
+          "loops"
         ],
         "status": "wip"
       },
diff --git a/exercises/concept/inventory-management/.docs/hints.md b/exercises/concept/inventory-management/.docs/hints.md
new file mode 100644
index 000000000..b6cab4b77
--- /dev/null
+++ b/exercises/concept/inventory-management/.docs/hints.md
@@ -0,0 +1,34 @@
+# Hints
+
+## 1. Create an inventory based on a vector
+
+- It may help to look at Task 2 before starting this.
+
+## 2. Add items from a vector to an existing dictionary
+
+- The simplest approach is to loop over the input vector one item at a time.
+- The [`haskey(dict, key)`][haskey] function will be useful.
+
+## 3. Decrement items from the inventory
+
+- The code is quite similar to Task 2, with a sign change.
+- Remember not to let the item count fall below zero.
+- `if...else` logic works, but the [`max()`][max] function allows concise and idiomatic code.
+
+## 4. Remove an entry entirely from the inventory
+
+Julia has a function to do exactly this: read the Introduction.
+
+## 5. Return the entire content of the inventory
+
+- Remember to remove items with zero count.
+- Beginners may find it easiest to loop over the items and [`push!()`][push] if appropriate.
+- A Python-style list comprehension is much more concise, and adding an `if` clause at the end is permitted.
+- Though requiring knowledge of later Concepts, students familiar with functional programming may want to investigate the [`filter()`][filter] function.
+- A sorted list is required, and [`sort()`][sort] defaults to sorting by the first part of a pair.
+
+[max]: https://docs.julialang.org/en/v1/base/math/#Base.max
+[filter]: https://docs.julialang.org/en/v1/base/collections/#Base.filter
+[haskey]: https://docs.julialang.org/en/v1/base/collections/#Base.haskey
+[push]: https://docs.julialang.org/en/v1/base/collections/#Base.push!
+[sort]: https://docs.julialang.org/en/v1/base/sort/#Base.sort
diff --git a/exercises/concept/inventory-management/.docs/instructions.md b/exercises/concept/inventory-management/.docs/instructions.md
new file mode 100644
index 000000000..3ffdef6ca
--- /dev/null
+++ b/exercises/concept/inventory-management/.docs/instructions.md
@@ -0,0 +1,77 @@
+# Instructions
+
+In this exercise, you will be managing an inventory system.
+
+The inventory should be organized by the item name and it should keep track of the number of items available.
+
+You will have to handle adding items to an inventory.
+Each time an item appears in a given vector, the item's quantity should be increased by `1` in the inventory.
+You will also have to handle deleting items from an inventory by decreasing quantities by `1` when requested.
+
+Finally, you will need to implement a function that will return all the key-value pairs in a given inventory as a `vector` of `pair`s.
+
+
+## 1. Create an inventory based on a vector
+
+Implement the `create_inventory(<input vector>)` function that creates an "inventory" from an input vector of items.
+It should return a `dict` containing each item name paired with their respective quantity.
+
+```julia-repl
+julia> create_inventory(["coal", "wood", "wood", "diamond", "diamond", "diamond"])
+Dict("coal" => 1, "wood" => 2, "diamond" => 3)
+```
+
+## 2. Add items from a vector to an existing dictionary
+
+Implement the `add_items(<inventory dict>, <item vector>)` function that adds a vector of items to the passed-in inventory:
+
+```julia-repl
+julia> add_items(Dict("coal" => 1), ["wood", "iron", "coal", "wood"])
+Dict("coal" => 2, "wood" => 2, "iron" => 1)
+```
+
+## 3. Decrement items from the inventory
+
+Implement the `decrement_items(<inventory dict>, <items vector>)` function that takes a `vector` of items.
+Your function should remove `1` from an item count for each time that item appears on the `vector`:
+
+```julia-repl
+julia> decrement_items(Dict("coal" => 3, "diamond" => 1, "iron" => 5), ["diamond", "coal", "iron", "iron"])
+Dict("coal" => 2, "diamond" => 0, "iron" => 3)
+```
+
+Item counts in the inventory should not be allowed to fall below 0.
+If the number of times an item appears on the input `vector` exceeds the count available, the quantity listed for that item should remain at 0.
+Additional requests for removing counts should be ignored once the count falls to zero.
+
+```julia-repl
+julia> decrement_items(Dict("coal" => 2, "wood" => 1, "diamond" => 2), ["coal", "coal", "wood", "wood", "diamond"])
+Dict("coal" => 0, "wood" => 0, "diamond" => 1)
+```
+
+## 4. Remove an entry entirely from the inventory
+
+Implement the `remove_item(<inventory dict>, <item>)` function that removes an item and its count entirely from an inventory:
+
+```julia-repl
+julia> remove_item(Dict("coal" => 2, "wood" => 1, "diamond" => 2), "coal")
+Dict("wood" => 1, "diamond" => 2)
+```
+
+If the item is not found in the inventory, the function should return the original inventory unchanged.
+
+```julia-repl
+julia> remove_item(Dict("coal" => 2, "wood" => 1, "diamond" => 2), "gold")
+Dict("coal" => 2, "wood" => 1, "diamond" => 2)
+```
+
+## 5. Return the entire content of the inventory
+
+Implement the `list_inventory(<inventory dict>)` function that takes an inventory and returns a vector of `(item, quantity)` pairs.
+
+The vector should only include the _available_ items (_with a quantity greater than zero_), and should be sorted in alphabetical order of items:
+
+```julia-repl
+julia> list_inventory(Dict("coal" => 7, "wood" => 11, "diamond" => 2, "iron" => 7, "silver" => 0))
+["coal" => 7, "diamond" => 2, "iron" => 7, "wood" => 11]
+```
diff --git a/exercises/concept/inventory-management/.docs/introduction.md b/exercises/concept/inventory-management/.docs/introduction.md
new file mode 100644
index 000000000..89bace506
--- /dev/null
+++ b/exercises/concept/inventory-management/.docs/introduction.md
@@ -0,0 +1,143 @@
+# Introduction
+
+## Pairs
+
+A `Pair` is just two items joined together.
+The items are then imaginatively called `first` and `second`.
+
+Create them either with the `=>` operator or the `Pair()` constructor.
+
+```julia-repl
+julia> p1 = "k" => 2
+"k" => 2
+
+julia> p2 = Pair("k", 2)
+"k" => 2
+
+# Both forms of syntax give the same result
+julia> p1 == p2
+true
+
+# Each component has its own separate type
+julia> dump(p1)
+Pair{String, Int64}
+  first: String "k"
+  second: Int64 2
+
+# Get a component using dot syntax
+julia> p1.first
+"k"
+
+julia> p1.second
+2
+```
+
+## Dicts
+
+A `Vector` of Pairs is like any other array: ordered, homogeneous in type, and stored consecutively in memory.
+
+```julia-repl
+julia> pv = ['a' => 1, 'b' => 2, 'c' => 3]
+3-element Vector{Pair{Char, Int64}}:
+ 'a' => 1
+ 'b' => 2
+ 'c' => 3
+
+# Each pair is a single entry
+julia> length(pv)
+3
+```
+
+A `Dict` is superficially similar, but storage is now implemented in a way that allows fast retrieval by key, even when the number of entries grows large.
+
+```julia-repl
+julia> pd = Dict('a' => 1, 'b' => 2, 'c' => 3)
+Dict{Char, Int64} with 3 entries:
+  'a' => 1
+  'c' => 3
+  'b' => 2
+
+julia> pd['b']
+2
+
+# Key must exist
+julia> pd['d']
+ERROR: KeyError: key 'd' not found
+
+# Generators are accepted in the constructor (and note the unordered output)
+julia> Dict(x => x^2 for x in 1:5)
+julia> Dict(x => 1 / x for x in 1:5)
+Dict{Int64, Float64} with 5 entries:
+  5 => 0.2
+  4 => 0.25
+  2 => 0.5
+  3 => 0.333333
+  1 => 1.0
+  ```
+
+In other languages, something very similar to a `Dict` might be called a dictionary (Python), a Hash (Ruby) or a HashMap (Java).
+
+For Pairs, whether in isolation or in a Vector, there are few constraints on the type of each component.
+
+To be valid in a `Dict`, the `Pair` must be a `key => value` pair, where the `key` is "hashable".
+Most importantly, this means the `key` must be _immutable_, so `Char`, `Int`, `String`, `Symbol`, and `Tuple` are all fine, but `Vector` is not allowed.
+
+### Modifying a Dict
+
+Entries can be added, with a new key, or overwritten, with an existing key.
+
+```julia-repl
+julia> pd
+Dict{Char, Int64} with 3 entries:
+  'a' => 1
+  'c' => 3
+  'b' => 2
+
+# Add
+julia> pd['d'] = 4
+4
+
+# Overwrite
+julia> pd['a'] = 42
+42
+
+julia> pd
+Dict{Char, Int64} with 4 entries:
+  'a' => 42
+  'c' => 3
+  'd' => 4
+  'b' => 2
+```
+
+To remove an entry, use the `delete!()` function, which will change the Dict if the key exists and silently do nothing otherwise.
+
+```julia-repl
+julia> delete!(pd, 'd')
+Dict{Char, Int64} with 3 entries:
+  'a' => 42
+  'c' => 3
+  'b' => 2
+```
+
+### Checking if a key or value exists
+
+There are different approaches.
+To check a key, there is a `haskey()` function:
+
+```julia-repl
+julia> haskey(pd, 'b')
+true
+```
+
+Alternatively, search either the keys or the values:
+
+```julia-repl
+julia> 'b' in keys(pd)
+true
+
+julia> 43 in values(pd)
+false
+
+julia> 42 ∈ values(pd)
+true
+```
diff --git a/exercises/concept/inventory-management/.meta/config.json b/exercises/concept/inventory-management/.meta/config.json
new file mode 100644
index 000000000..1ef4176f2
--- /dev/null
+++ b/exercises/concept/inventory-management/.meta/config.json
@@ -0,0 +1,20 @@
+{
+  "authors": [
+    "colinleach"
+  ],
+  "files": {
+    "solution": [
+      "inventory-management.jl"
+    ],
+    "test": [
+      "runtests.jl"
+    ],
+    "exemplar": [
+      ".meta/exemplar.jl"
+    ]
+  },
+  "forked_from": [
+    "python/inventory-management"
+  ],
+  "blurb": "Learn about Dicts by managing warehouse inventory."
+}
diff --git a/exercises/concept/inventory-management/.meta/design.md b/exercises/concept/inventory-management/.meta/design.md
new file mode 100644
index 000000000..ca248f426
--- /dev/null
+++ b/exercises/concept/inventory-management/.meta/design.md
@@ -0,0 +1,25 @@
+# Design
+
+## Goal
+
+The goal of this exercise is to introduce the student to pairs and dicts in Julia.
+
+## Learning objectives
+
+- Understand what a pair is and how it can be used.
+- Understand comething about the value and limitations of Dicts.
+- Become familiar with a basic subset of Dict functions, such as deletion.
+
+## Out of scope
+
+- More advanced dictionary functions such as `get()` will be convered in a later Concept.
+
+## Concepts
+
+The Concepts this exercise unlocks are:
+
+- `pairs-and-dicts`
+
+## Prerequisites
+
+- `loops`
diff --git a/exercises/concept/inventory-management/.meta/exemplar.jl b/exercises/concept/inventory-management/.meta/exemplar.jl
new file mode 100644
index 000000000..55ca65b98
--- /dev/null
+++ b/exercises/concept/inventory-management/.meta/exemplar.jl
@@ -0,0 +1,21 @@
+create_inventory(items) = add_items(Dict(), items)
+
+function add_items(inventory, items)
+    for item in items
+        inventory[item] = haskey(inventory, item) ? inventory[item] + 1 : 1
+    end
+    inventory
+end
+
+function decrement_items(inventory, items)
+    for item in items
+        if haskey(inventory, item)
+            inventory[item] = max(inventory[item] - 1, 0)
+        end
+    end
+    inventory
+end
+
+remove_item(inventory, item) = delete!(inventory, item)
+
+list_inventory(inventory) = sort([item for item in inventory if item.second > 0])
diff --git a/exercises/concept/inventory-management/inventory-management.jl b/exercises/concept/inventory-management/inventory-management.jl
new file mode 100644
index 000000000..a04244a08
--- /dev/null
+++ b/exercises/concept/inventory-management/inventory-management.jl
@@ -0,0 +1,19 @@
+function create_inventory(items)
+
+end
+
+function add_items(inventory, items)
+
+end
+
+function decrement_items(inventory, items)
+
+end
+
+function remove_item(inventory, item)
+
+end
+
+function list_inventory(inventory)
+    
+end
diff --git a/exercises/concept/inventory-management/runtests.jl b/exercises/concept/inventory-management/runtests.jl
new file mode 100644
index 000000000..e62778adf
--- /dev/null
+++ b/exercises/concept/inventory-management/runtests.jl
@@ -0,0 +1,80 @@
+using Test 
+
+include("inventory-management.jl")
+
+@testset verbose = true "tests" begin
+    @testset "1. create_inventory" begin
+        @testset "Create an inventory from a vector" begin
+            expected = Dict("wood" => 1, "iron" => 2, "diamond" => 2)
+            @test create_inventory(["wood", "iron", "iron", "diamond", "diamond"]) == expected
+        end
+    end
+
+    @testset "2. add_items" begin
+        @testset "test_add_one_item" begin
+            expected = Dict("wood" => 4, "iron" => 4)
+            @test add_items(Dict("wood" => 4, "iron" => 2), ["iron", "iron"]) == expected
+        end
+
+        @testset "test_add_multiple_items" begin
+            inventory = Dict("wood" => 2, "gold" => 1, "diamond" => 3)
+            expected = Dict("wood" => 3, "gold" => 3, "diamond" => 3)
+            @test add_items(inventory, ["wood", "gold", "gold"]) == expected
+        end
+
+        @testset "test_add_new_item" begin
+            inventory = Dict("iron" => 1, "diamond" => 2)
+            expected = Dict("iron" => 2, "diamond" => 2, "wood" => 2)
+            @test add_items(inventory, ["iron", "wood", "wood"]) == expected
+        end
+
+        @testset "test_add_from_empty_dict" begin
+            inventory = Dict()
+            expected = Dict("iron" => 2, "diamond" => 1)
+            @test add_items(inventory, ["iron", "iron", "diamond"]) == expected
+        end
+    end
+
+    @testset "3. decrement_items" begin
+        @testset "test_decrement_items" begin
+            inventory = Dict("iron" => 3, "diamond" => 4, "gold" => 2)
+            expected = Dict("iron" => 1, "diamond" => 3, "gold" => 0)
+            @test decrement_items(inventory, ["iron", "iron", "diamond", "gold", "gold"]) == expected
+        end
+        
+        @testset "test_decrement_items" begin
+            inventory = Dict("wood" => 2, "iron" => 3, "diamond" => 1)
+            expected = Dict("wood" => 0, "iron" => 2, "diamond" => 0)
+            @test decrement_items(inventory, ["wood", "wood", "wood", "iron", "diamond", "diamond"]) == expected
+        end
+        
+        @testset "test_decrement_items_not_in_inventory" begin
+            inventory = Dict("iron" => 3, "gold" => 2)
+            expected = Dict("iron" => 1, "gold" => 2)
+            @test decrement_items(inventory, ["iron", "wood", "iron", "diamond"]) == expected
+        end
+        
+    end
+
+    @testset "4. remove_item" begin
+        @testset "test_remove_item" begin
+            inventory = Dict("iron" => 1, "diamond" => 2, "gold" => 1)
+            expected = Dict("iron" => 1, "gold" => 1)
+            @test remove_item(inventory, "diamond") == expected
+        end
+
+        @testset "test_remove_item_not_in_inventory" begin
+            inventory = Dict("iron" => 1, "diamond" => 2, "gold" => 1)
+            expected = Dict("iron" => 1, "gold" => 1, "diamond" => 2)
+            @test remove_item(inventory, "wood") == expected
+        end
+    end
+
+    @testset "5. list_inventory" begin
+        @testset "list_inventory" begin
+            inventory = Dict("coal" => 15, "diamond" => 3, "wood" => 67, "silver" => 0)
+            expected = ["coal" => 15, "diamond" => 3, "wood" => 67]
+            @test list_inventory(inventory) == expected
+        end
+    end
+end


Reviews:
user: login: depial
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-05T15:06:17Z

Review comments:
diff_hunk: @@ -0,0 +1,77 @@
+# Instructions
+
+In this exercise, you will be managing an inventory system.
+
+The inventory should be organized by the item name and it should keep track of the number of items available.
+
+You will have to handle adding items to an inventory.
+Each time an item appears in a given vector, the item's quantity should be increased by `1` in the inventory.
+You will also have to handle deleting items from an inventory by decreasing quantities by `1` when requested.
+
+Finally, you will need to implement a function that will return all the key-value pairs in a given inventory as a `vector` of `pair`s.
+
+
+## 1. Create an inventory based on a vector
+
+Implement the `create_inventory(<input vector>)` function that creates an "inventory" from an input vector of items.
+It should return a `dict` containing each item name paired with their respective quantity.
+
+```julia-repl
+julia> create_inventory(["coal", "wood", "wood", "diamond", "diamond", "diamond"])
+Dict("coal" => 1, "wood" => 2, "diamond" => 3)
+```
+
+## 2. Add items from a vector to an existing dictionary
+
+Implement the `add_items(<inventory dict>, <item vector>)` function that adds a vector of items to the passed-in inventory:
+
+```julia-repl
+julia> add_items(Dict("coal" => 1), ["wood", "iron", "coal", "wood"])
+Dict("coal" => 2, "wood" => 2, "iron" => 1)
+```
+
+## 3. Decrement items from the inventory
+
+Implement the `decrement_items(<inventory dict>, <items vector>)` function that takes a `vector` of items.
+Your function should remove `1` from an item count for each time that item appears on the `vector`:
+
+```julia-repl
+julia> decrement_items(Dict("coal" => 3, "diamond" => 1, "iron" => 5), ["diamond", "coal", "iron", "iron"])
+Dict("coal" => 2, "diamond" => 0, "iron" => 3)
+```
+
+Item counts in the inventory should not be allowed to fall below 0.
+ If the number of times an item appears on the input `vector` exceeds the count available, the quantity listed for that item should remain at 0.
+ Additional requests for removing counts should be ignored once the count falls to zero.
path: exercises/concept/inventory-management/.docs/instructions.md
user: login: depial
body: Appears to be extra white space at the beginning of these sentences.
created_at: 2025-04-05T14:46:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,27 @@
+# Hints
+
+## 1. Create an inventory based on a vector
+
+- It may help to look at Task 2 before starting this.
+
+## 2. Add items from a vector to an existing dictionary
+
+- The simplest approach is to loop over the input vector one item at a time.
+- The `haskey(dict, key)` function will be useful.
+
+## 3. Decrement items from the inventory
+
+- The code is quite similar to Task 2, with a sign change.
+- Remember not to let the item count fall below zero.
+- `if...else` logic works, but the `max()` function allows concise and idiomatic code.
+
+## 4. Remove an entry entirely from the inventory
+
+Julia has a function to do exactly this: read the Introduction.
+
+## 5. Return the entire content of the inventory
+
+- Remember to remove items with zero count.
+- Beginners may find it easiest to loop over the items and `push!()` if appropriate.
+- A Python-style list comprehension is much more concise, and adding an `if` clause at the end is permitted.
path: exercises/concept/inventory-management/.docs/hints.md
user: login: depial
body: I would be tempted to mention the `filter` method, since it is more idiomatic than the Python list comprehension + if clause. However, that may be too advanced at this point in the syllabus since I think it requires knowledge of anonymous functions. For example:

```julia
collect(filter(x -> 0 < x.second, inventory_dict))
```
created_at: 2025-04-05T15:03:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,137 @@
+# Introduction
+
+## Pairs
+
+A `Pair` is just two items joined together.
+The items are then imaginatively called `first` and `second`.
+
+Create them either with the `=>` operator or the `Pair()` constructor.
+
+```julia-repl
+julia> p1 = "k" => 2
+"k" => 2
+
+julia> p2 = Pair("k", 2)
+"k" => 2
+
+# Both forms of syntax give the same result
+julia> p1 == p2
+true
+
+# Each component has its own separate type
+julia> dump(p1)
+Pair{String, Int64}
+  first: String "k"
+  second: Int64 2
+
+# Get a component using dot syntax
+julia> p1.first
+"k"
+
+julia> p1.second
+2
+```
+
+## Dicts
+
+A `Vector` of Pairs is like any other array: ordered, homogeneous in type, and stored consecutively in memory.
+
+```julia-repl
+julia> pv = ['a' => 1, 'b' => 2, 'c' => 3]
+3-element Vector{Pair{Char, Int64}}:
+ 'a' => 1
+ 'b' => 2
+ 'c' => 3
+
+# Each pair is a single entry
+julia> length(pv)
+3
+```
+
+A `Dict` is superficially similar, but storage is now implemented in a way that allows fast retrieval by key, even when the number of entries grows large.
+
+```julia-repl
+julia> pd = Dict(pv)
+Dict{Char, Int64} with 3 entries:
+  'a' => 1
+  'c' => 3
+  'b' => 2
+
+julia> pd['b']
+2
+
+# Key must exist
+julia> pd['d']
+ERROR: KeyError: key 'd' not found
+
+# Generators are accepted in the constructor (and note the unordered output)
+julia> Dict(x => x^2 for x in 1:5)
+julia> Dict(x => 1 / x for x in 1:5)
+Dict{Int64, Float64} with 5 entries:
+  5 => 0.2
+  4 => 0.25
+  2 => 0.5
+  3 => 0.333333
+  1 => 1.0
+  ```
+
+In other languages, something very similar to a `Dict` might be called a dictionary (Python), a Hash (Ruby) or a HashMap (Java).
+
+For Pairs, whether in isolation or in a Vector, there are few constraints on the type of each component.
+
+To be valid in a `Dict`, the `Pair` must be a `key => value` pair, where the `key` is "hashable".
+Most importantly, this means the `key` must be _immutable_, so `Char`, `Int`, `String`, `Symbol`, and `Tuple` are all fine, but `Vector` is not allowed.
+
+### Modifying a Dict
+
+Entries can be added with a new key or overwritten with an existing key.
+
+```julia-repl
+# Add
+julia> pd['d'] = 4
+4
+
+# Overwrite
+julia> pd['a'] = 42
+42
+
+julia> pd
+Dict{Char, Int64} with 4 entries:
+  'a' => 42
+  'c' => 3
+  'd' => 4
+  'b' => 2
+```
path: exercises/concept/inventory-management/.docs/introduction.md
user: login: depial
body: This should probably be synced with any changes from the concept.
created_at: 2025-04-05T15:05:10Z
author_association: CONTRIBUTOR

PR comments:
user: login: colinleach
created_at: 2025-04-05T00:05:28Z
body: I don't know why it's complaining about `loops` as a prereq. It has Mixed Juices already merged.
author_association: CONTRIBUTOR
user: login: depial
created_at: 2025-04-05T12:44:42Z
body: > I don't know why it's complaining about loops as a prereq.

This is especially strange considering `cater-water` also has `loops` as a prereq and it works just fine. Maybe this will resolve itself after `pairs-and-dicts` is merged?
author_association: CONTRIBUTOR
user: login: colinleach
created_at: 2025-04-05T15:10:43Z
body: I figured out where I messed up the config.json: I forgot to add a  "status": "wip" entry, so configlet treated it as not student-facing.

I'll make the other changes you suggest.
author_association: CONTRIBUTOR
user: login: colinleach
created_at: 2025-04-05T15:36:09Z
body: Both `inventory-management` and `high-school-sweetheart` are now linked into to syllabus tree, which makes me happy.

No change to the duplicated Booleans, or the locked Vectors. Is it time to think about merging #867 to try and remove the 'annalyns-infiltration` duplicate?
author_association: CONTRIBUTOR
user: login: depial
created_at: 2025-04-05T16:06:36Z
body: > Both `inventory-management` and `high-school-sweetheart` are now linked into to syllabus tree, which makes me happy.

It's good to see some things coming together! I also had no issues doing the exercise `inventory-management` so we seem set there.

> Is it time to think about merging https://github.com/exercism/julia/pull/867 to try and remove the 'annalyns-infiltration` duplicate?

I'll give this a closer look now and comment there.
author_association: CONTRIBUTOR