Brief
You have inherited the inventory system of the Gilded Rose, a small inn that buys and
sells goods. The previous developer (Leeroy, now off on adventures) left behind a single
tangle of nested conditionals that updates every item's sellIn and quality once per
day. It has no tests, the names lie, and the innkeeper has just sold the shop on a new
product line: conjured items. Your job is to add that feature — but the code as it
stands will fight you every step. Rescue it first.
Instructions
The update rules (current behavior — preserve exactly)
Every item has a sellIn (days left to sell it) and a quality (how valuable it is).
At the end of each day the system lowers both for every item, with these twists:
- Ordinary items lose 1 quality per day; once the sell-by date has passed
(
sellInbelow 0), they degrade twice as fast (−2 per day). - Quality is never negative, and never rises above 50 — except Sulfuras.
- Aged Brie does the opposite: its quality increases the older it gets (+1 per day, +2 once the sell-by date has passed, still capped at 50).
- Sulfuras, Hand of Ragnaros is legendary: it is never sold, its
sellInnever moves, and its quality is fixed at 80. - Backstage passes rise in quality as the concert approaches: +1 per day normally,
+2 when 10 days or fewer remain, +3 when 5 days or fewer remain — and drop
to 0 the moment the concert is over (
sellInbelow 0).
The feature request
- Conjured items degrade in quality twice as fast as ordinary items (−2 per day, −4 once the sell-by date has passed; the 0 floor still applies).
The assignment
- Clone the kata repo in your language of choice; read the code and the requirements, and write down the smells you find before changing anything.
- Pin the current behavior with characterization tests — a golden-master simulation of ~30 days across every item type and every edge (sell-in at 0, quality at 0 and 50). Verify branch coverage; close the gaps.
- Clean up mechanically under a green bar: rename, extract, flatten the conditionals.
- Replace the item-type conditional with one update strategy per item kind.
- TDD the conjured-items rule onto the new structure.
- Mutation-test the suite and kill every surviving mutant.
Examples
One day's update, before → after:
| Item | sellIn | quality | sellIn | quality | |
|---|---|---|---|---|---|
| +5 Dexterity Vest | 10 | 20 | → | 9 | 19 |
| Elixir of the Mongoose | −1 | 6 | → | −2 | 4 |
| Aged Brie | 2 | 0 | → | 1 | 1 |
| Aged Brie | 0 | 10 | → | −1 | 12 |
| Sulfuras, Hand of Ragnaros | 0 | 80 | → | 0 | 80 |
| Backstage passes | 15 | 20 | → | 14 | 21 |
| Backstage passes | 10 | 25 | → | 9 | 27 |
| Backstage passes | 5 | 40 | → | 4 | 43 |
| Backstage passes | 0 | 30 | → | −1 | 0 |
| Conjured Mana Cake (after the feature ships) | 3 | 6 | → | 2 | 4 |
Constraints
- Do not modify the
Itemclass or theitemsproperty — the goblin in the corner owns them and insta-rages. Wrap, subclass elsewhere, or route around; never edit. - Refactor only under a green bar. No structural change before the characterization tests pass; no behavior change while refactoring. Commit every few minutes.
- The conjured-items feature is written test-first, and only after the structural refactor — the point is to feel what the clean design buys.
Acceptance
Mapped to the exercise's milestones:
- A written smell list exists (and names the goblin's trap) before the first edit.
- The golden-master suite reproduces the table above, covers all item types over ~30 simulated days, and branch coverage shows no untested branch in the update logic.
- After cleanup, every commit in the history passes the full suite; behavior byte-identical.
- Adding a hypothetical new item type touches no existing conditional — one new strategy, one registration.
- Conjured items degrade at double rate on both sides of the sell-by date, floor at 0, with tests written before the implementation.
- The mutation-testing report shows zero surviving mutants in the update logic.
Related
- Gilded Rose — legacy rescue — the exercise this is the subject of.
- Emily Bache's GildedRose-Refactoring-Kata — the multi-language starting code this statement is adapted from (originally by Terry Hughes).