fix(scan): recognize current inventory icons - #24
Conversation
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
🏁 CodeAnt Quality Gate ResultsCommit: ✅ Overall Status: PASSEDQuality Gate Details
|
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/ScanEngine/Processing/Icon.cs`:
- Around line 358-417: The VerifyLowConfidenceTemplateMatchWithOcr method must
contain exception handling around its OpenCV/Tesseract OCR operations so
failures do not escape Item, DetectionConfidence, or ItemPosition accessors.
Reuse the existing IsRecoverableIconLoadException policy and logging behavior
from IconManager, while preserving the finally block’s disposal of ocrIcon and
allowing successful OCR verification to remain unchanged.
- Around line 19-21: Unify OCR sanitization by extracting the existing regex
used in OCR() into the shared OcrShortNameSanitizer symbol, then reuse it in
both the full-OCR and verification paths. Remove the divergent Unicode-aware
pattern so both paths apply identical normalization rules.
- Around line 363-366: Extract the trained-data path construction and existence
check from the current low-confidence flow and GetTesseractEngine() into a
shared helper such as TryGetTrainedDataPath. Update both call sites to reuse
that helper, preserving the existing language-code resolution and early-return
behavior while eliminating duplicate path logic and File.Exists checks.
- Around line 404-410: When OCR verification replaces the low-confidence match
in the verification block, recompute or reset _itemPosition for the new
verifiedItem so ItemPosition no longer uses the discarded candidate’s position.
Update the same assignment section that sets _item, _itemExtraInfo,
_detectionConfidence, and _rotated, preserving the existing position calculation
behavior used elsewhere for verified items.
In `@src/ScanEngine/Processing/Inventory.cs`:
- Around line 258-297: The AddContourIconsFromNormalGrid method should add debug
visualization consistent with DetectInventoryGridNormal,
ParseInventoryGridHighlighted, and LocateIcon. Under Config.LogDebug, log the
contour source mask and relevant candidate or padded rectangles through the
existing Logger.LogDebugMat pattern, preserving the current detection behavior
and avoiding logging when debug mode is disabled.
- Around line 258-297: Extract the shared padding calculation currently
duplicated in AddContourIconsFromNormalGrid and TryAddIcon into a reusable
helper. Have both methods call that helper for the top-left and size
adjustments, preserving the existing padding behavior and ensuring future
heuristic changes apply consistently.
- Around line 264-267: Update the FindContoursAsArray call in the contour
processing flow to use RetrievalModes.External instead of RetrievalModes.List,
while preserving the existing ContourApproximationModes.ApproxSimple setting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f4f25a23-858f-415f-994c-f371d31b80e6
📒 Files selected for processing (6)
src/ScanEngine/IconManager.cssrc/ScanEngine/Processing/Icon.cssrc/ScanEngine/Processing/Inventory.cstests/RatScanner.Tests/OpenCvPipelineTests.cstests/RatScanner.Tests/PresentationServicesTests.cstests/RatScanner.Tests/RatEyeCacheTests.cs
| private const float OcrVerificationThreshold = 0.7f; | ||
| private static readonly Regex OcrShortNameSanitizer = new(@"[^\p{L}\p{N} \-.]"); | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Two divergent OCR sanitizer regexes.
OcrShortNameSanitizer ([^\p{L}\p{N} \-.], Unicode-aware) duplicates the intent of the existing ASCII-only regex in OCR() (line 345, "[^a-zA-Z0-9 -\\."]). Having two slightly different sanitization rules for OCR text risks inconsistent normalization between the full-OCR path and this new verification path. Consider reusing one shared sanitizer.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Icon.cs` around lines 19 - 21, Unify OCR
sanitization by extracting the existing regex used in OCR() into the shared
OcrShortNameSanitizer symbol, then reuse it in both the full-OCR and
verification paths. Remove the divergent Unicode-aware pattern so both paths
apply identical normalization rules.
| private void VerifyLowConfidenceTemplateMatchWithOcr() | ||
| { | ||
| if (_detectionConfidence >= OcrVerificationThreshold) | ||
| return; | ||
|
|
||
| var langCode = ProcessingConfig.Language.ToISO3Code(); | ||
| var trainedDataPath = System.IO.Path.Combine(PathConfig.TrainedData, $"{langCode}.traineddata"); | ||
| if (!System.IO.File.Exists(trainedDataPath)) | ||
| return; | ||
|
|
||
| Bitmap ocrIcon = _icon.Rescale(ProcessingConfig.InverseScale * 2); | ||
| try | ||
| { | ||
| var titleHeight = Math.Min( | ||
| ocrIcon.Height, | ||
| (int)Math.Round(ProcessingConfig.BaseSlotSize * (40f / 63f)) | ||
| ); | ||
| var titleLeft = Math.Min(ocrIcon.Width - 1, (int)Math.Floor(ocrIcon.Width * 0.55f)); | ||
| using var title = ocrIcon.Crop(titleLeft, 0, ocrIcon.Width - titleLeft, titleHeight); | ||
| using var titleMat = title.ToMat(); | ||
| using var gray = | ||
| titleMat.Channels() == 1 ? titleMat.Clone() : titleMat.CvtColor(ColorConversionCodes.BGR2GRAY); | ||
| using var binary = gray.Threshold(110, 255, ThresholdTypes.Binary); | ||
| Cv2.BitwiseNot(binary, binary); | ||
| using var enlarged = binary.Resize(new OpenCvSharp.Size(), 3, 3, InterpolationFlags.Cubic); | ||
| using var filteredBitmap = enlarged.ToBitmap(); | ||
| using var pix = PixConverter.ToPix(filteredBitmap); | ||
|
|
||
| string text; | ||
| var tesseractEngine = GetTesseractEngine(); | ||
| lock (tesseractEngine) | ||
| { | ||
| using var result = tesseractEngine.Process(pix, PageSegMode.SingleLine); | ||
| text = result.GetText(); | ||
| } | ||
|
|
||
| var slotSize = IconSlotSize(); | ||
| var items = _config.RatStashDB.GetItems(item => | ||
| { | ||
| var size = new Vector2(item.GetSlotSize()); | ||
| return size == slotSize || size == slotSize.Flipped; | ||
| }); | ||
| var verifiedItem = FindUniqueExactShortName(items, text); | ||
| if (verifiedItem == null) | ||
| return; | ||
|
|
||
| _item = verifiedItem; | ||
| _itemExtraInfo = null; | ||
| _detectionConfidence = 1; | ||
| _rotated = new Vector2(verifiedItem.GetSlotSize()) != slotSize; | ||
| Logger.LogDebug( | ||
| $"Verified low-confidence template match as '{verifiedItem.ShortName}' using icon title OCR." | ||
| ); | ||
| } | ||
| finally | ||
| { | ||
| if (!ReferenceEquals(ocrIcon, _icon)) | ||
| ocrIcon.Dispose(); | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
No exception handling around the new OCR verification path.
Unlike icon loading in IconManager (which wraps OpenCV/Tesseract/IO failures via IsRecoverableIconLoadException), VerifyLowConfidenceTemplateMatchWithOcr has no try/catch. Previously, TemplateMatching mode had zero runtime dependency on Tesseract; now every low-confidence match opportunistically runs OCR, so any native/Tesseract failure (corrupt traineddata, native crash, malformed pix) will propagate unguarded out of Item/DetectionConfidence/ItemPosition getters and can crash a scan that previously never touched OCR.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Icon.cs` around lines 358 - 417, The
VerifyLowConfidenceTemplateMatchWithOcr method must contain exception handling
around its OpenCV/Tesseract OCR operations so failures do not escape Item,
DetectionConfidence, or ItemPosition accessors. Reuse the existing
IsRecoverableIconLoadException policy and logging behavior from IconManager,
while preserving the finally block’s disposal of ocrIcon and allowing successful
OCR verification to remain unchanged.
| var langCode = ProcessingConfig.Language.ToISO3Code(); | ||
| var trainedDataPath = System.IO.Path.Combine(PathConfig.TrainedData, $"{langCode}.traineddata"); | ||
| if (!System.IO.File.Exists(trainedDataPath)) | ||
| return; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Duplicated trained-data path resolution/existence check.
This re-derives and re-checks the trained-data path that GetTesseractEngine() (line ~483) already builds and checks independently, using a different construction strategy (Path.Combine here vs. manual "\\" concatenation there). Functionally equivalent on Windows, but it's duplicated logic and a duplicate File.Exists syscall on every low-confidence match; consider extracting a single helper (e.g. TryGetTrainedDataPath) used by both call sites.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Icon.cs` around lines 363 - 366, Extract the
trained-data path construction and existence check from the current
low-confidence flow and GetTesseractEngine() into a shared helper such as
TryGetTrainedDataPath. Update both call sites to reuse that helper, preserving
the existing language-code resolution and early-return behavior while
eliminating duplicate path logic and File.Exists checks.
| _item = verifiedItem; | ||
| _itemExtraInfo = null; | ||
| _detectionConfidence = 1; | ||
| _rotated = new Vector2(verifiedItem.GetSlotSize()) != slotSize; | ||
| Logger.LogDebug( | ||
| $"Verified low-confidence template match as '{verifiedItem.ShortName}' using icon title OCR." | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
_itemPosition goes stale when OCR overrides the item.
When OCR verification swaps in a different verifiedItem, _itemPosition still holds the position computed for the discarded, low-confidence template match — which was for a different (likely wrong) item entirely. _rotated is correctly recomputed for the new item, but the position isn't, so ItemPosition will report a misleading location tied to the wrong candidate's match.
🐛 Proposed fix
_item = verifiedItem;
_itemExtraInfo = null;
_detectionConfidence = 1;
+ _itemPosition = Vector2.Zero;
_rotated = new Vector2(verifiedItem.GetSlotSize()) != slotSize;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| _item = verifiedItem; | |
| _itemExtraInfo = null; | |
| _detectionConfidence = 1; | |
| _rotated = new Vector2(verifiedItem.GetSlotSize()) != slotSize; | |
| Logger.LogDebug( | |
| $"Verified low-confidence template match as '{verifiedItem.ShortName}' using icon title OCR." | |
| ); | |
| _item = verifiedItem; | |
| _itemExtraInfo = null; | |
| _detectionConfidence = 1; | |
| _itemPosition = Vector2.Zero; | |
| _rotated = new Vector2(verifiedItem.GetSlotSize()) != slotSize; | |
| Logger.LogDebug( | |
| $"Verified low-confidence template match as '{verifiedItem.ShortName}' using icon title OCR." | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Icon.cs` around lines 404 - 410, When OCR
verification replaces the low-confidence match in the verification block,
recompute or reset _itemPosition for the new verifiedItem so ItemPosition no
longer uses the discarded candidate’s position. Update the same assignment
section that sets _item, _itemExtraInfo, _detectionConfidence, and _rotated,
preserving the existing position calculation behavior used elsewhere for
verified items.
| private void AddContourIconsFromNormalGrid() | ||
| { | ||
| if (_normalGridMask == null || _normalGridMask.Empty()) | ||
| return; | ||
|
|
||
| using var contourSource = _normalGridMask.Clone(); | ||
| var contours = contourSource.FindContoursAsArray( | ||
| RetrievalModes.List, | ||
| ContourApproximationModes.ApproxSimple | ||
| ); | ||
| var scaledSlotSize = (int)ProcessingConfig.ScaledSlotSize; | ||
| var tolerance = Math.Max(3, (int)Math.Ceiling(scaledSlotSize * 0.08)); | ||
| var imageBounds = new Rect(0, 0, _image.Width, _image.Height); | ||
|
|
||
| using var image = _image.ToBitmap(); | ||
| foreach (var contour in contours) | ||
| { | ||
| var rect = Cv2.BoundingRect(contour); | ||
| if ( | ||
| !IsSlotAlignedDimension(rect.Width, scaledSlotSize, tolerance) | ||
| || !IsSlotAlignedDimension(rect.Height, scaledSlotSize, tolerance) | ||
| ) | ||
| continue; | ||
|
|
||
| var scaledSlotSizeVec = new Vector2(scaledSlotSize, scaledSlotSize); | ||
| var topLeft = new Vector2(rect.Location) - scaledSlotSizeVec / 8; | ||
| var size = new Vector2(rect.Size) + scaledSlotSizeVec / 4; | ||
| var paddedRect = new Rect(topLeft, size).Intersect(imageBounds); | ||
| if (paddedRect.Width <= 0 || paddedRect.Height <= 0) | ||
| continue; | ||
|
|
||
| topLeft = new Vector2(paddedRect.Location); | ||
| size = new Vector2(paddedRect.Size); | ||
| if (_icons.Any(icon => icon.Position == topLeft && icon.Size == size)) | ||
| continue; | ||
|
|
||
| var iconImage = image.Crop(topLeft.X, topLeft.Y, size.X, size.Y); | ||
| _icons.Add(new Icon(iconImage, topLeft, size, _config)); | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Add debug logging consistent with sibling detection methods.
Every other detection path in this class (DetectInventoryGridNormal, ParseInventoryGridHighlighted, LocateIcon) logs intermediate masks/candidate rectangles via Logger.LogDebugMat under Config.LogDebug. This new contour-fallback path adds no equivalent visualization, making it harder to diagnose accuracy issues (e.g., over/under-detection, alignment tolerance tuning) in the field. As per coding guidelines, "Log through existing engine logger patterns."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Inventory.cs` around lines 258 - 297, The
AddContourIconsFromNormalGrid method should add debug visualization consistent
with DetectInventoryGridNormal, ParseInventoryGridHighlighted, and LocateIcon.
Under Config.LogDebug, log the contour source mask and relevant candidate or
padded rectangles through the existing Logger.LogDebugMat pattern, preserving
the current detection behavior and avoiding logging when debug mode is disabled.
Source: Coding guidelines
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Extract shared padding logic instead of duplicating TryAddIcon's formula.
The padding computation (topLeft -= scaledSlotSizeVec/8; size += scaledSlotSizeVec/4;) is copy-pasted verbatim from TryAddIcon (Lines 497-500). If the padding heuristic is ever tuned for one path, the other will silently diverge, causing inconsistent icon crop sizes between grid-detected and contour-detected icons.
♻️ Proposed extraction
+ private Rect PadIconRect(Rect rect, int scaledSlotSize)
+ {
+ var scaledSlotSizeVec = new Vector2(scaledSlotSize, scaledSlotSize);
+ var topLeft = new Vector2(rect.Location) - scaledSlotSizeVec / 8;
+ var size = new Vector2(rect.Size) + scaledSlotSizeVec / 4;
+ return new Rect(topLeft, size);
+ }Then call it from both AddContourIconsFromNormalGrid and TryAddIcon.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Inventory.cs` around lines 258 - 297, Extract the
shared padding calculation currently duplicated in AddContourIconsFromNormalGrid
and TryAddIcon into a reusable helper. Have both methods call that helper for
the top-left and size adjustments, preserving the existing padding behavior and
ensuring future heuristic changes apply consistently.
| var contours = contourSource.FindContoursAsArray( | ||
| RetrievalModes.List, | ||
| ContourApproximationModes.ApproxSimple | ||
| ); |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
OpenCvSharp FindContoursAsArray RetrievalModes.External behavior for closed shape with hole
💡 Result:
In OpenCvSharp, using the RetrievalModes.External mode with the FindContoursAsArray method retrieves only the "extreme outer" contours of shapes in a binary image [1][2][3]. When applied to a closed shape containing a hole, this mode will ignore the inner contour (the hole) entirely [4]. Only the outermost boundary of the object will be detected and returned as a contour [1][5][6]. This behavior is consistent across all implementations of OpenCV's findContours function because RetrievalModes.External is specifically designed to ignore nested structures and hierarchy [7][6][8]. The function also sets the hierarchy information for the detected outer contour to indicate it has no parent or child relationships (hierarchy[i][2] = hierarchy[i][7] = -1) [1][7][9].
Citations:
- 1: https://shimat.github.io/opencvsharp/api/OpenCvSharp.RetrievalModes.html
- 2: https://shimat.github.io/opencvsharp_docs/html/7ea5a50b-3842-ae88-ed1c-cc3a555ed0d3.htm
- 3: https://shimat.github.io/opencvsharp_docs/html/8a94c406-7abb-d96f-6108-442b415bd170.htm
- 4: https://stackoverflow.com/questions/73564238/opencv-findcontours-and-drawcontours-show-hollow-contours
- 5: https://vovkos.github.io/doxyrest-showcase/opencv/sphinx_rtd_theme/enum_cv_RetrievalModes.html
- 6: https://docs.opencv.org/4.10.0/d3/dc0/group__imgproc__shape.html
- 7: https://github.com/shimat/opencvsharp/blob/main/src/OpenCvSharp/Modules/imgproc/Enum/RetrievalModes.cs
- 8: https://docs.opencv.org/3.1.0/d3/dc0/group__imgproc__shape.html
- 9: https://shimat.github.io/opencvsharp_docs/html/d31db5d9-079e-05e9-ff62-7a9fbddce5fb.htm
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the relevant file and nearby logic.
FILE="src/ScanEngine/Processing/Inventory.cs"
echo "== Line count =="
wc -l "$FILE"
echo
echo "== Relevant range around contour handling =="
sed -n '180,320p' "$FILE"
echo
echo "== Search for contour / overlap / slot alignment helpers in the file =="
rg -n "FindContoursAsArray|RetrievalModes|IsSlotAlignedDimension|overlap|prun|contour|Bitmap|Icon" "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 8952
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/ScanEngine/Processing/Inventory.cs"
wc -l "$FILE"
sed -n '180,320p' "$FILE"
rg -n "FindContoursAsArray|RetrievalModes|IsSlotAlignedDimension|overlap|prun|contour|Bitmap|Icon" "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 8816
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/ScanEngine/Processing/Inventory.cs"
echo "== line count =="
wc -l "$FILE"
echo "== relevant range =="
sed -n '180,320p' "$FILE"
echo "== matches =="
rg -n "FindContoursAsArray|RetrievalModes|IsSlotAlignedDimension|overlap|prun|contour|Bitmap|Icon" "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 8868
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/ScanEngine/Processing/Inventory.cs"
wc -l "$FILE"
sed -n '200,300p' "$FILE"
rg -n "FindContoursAsArray|RetrievalModes|IsSlotAlignedDimension|overlap|prun|contour|Bitmap|Icon" "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 6840
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Trying to inspect repository files..."
git ls-files | rg '^src/ScanEngine/Processing/Inventory\.cs$|^src/ScanEngine/Processing/'Repository: tarkovtracker-org/RatScanner
Length of output: 362
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/ScanEngine/Processing/Inventory.cs"
echo "== _normalGridMask references =="
rg -n "_normalGridMask|normalGridMask|FindContoursAsArray|RetrievalModes" "$FILE"
echo
echo "== section around mask construction / assignment =="
sed -n '80,180p' "$FILE"
echo
echo "== section around any other contour handling =="
sed -n '320,430p' "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 10135
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/ScanEngine/Processing/Inventory.cs"
echo "== lines 80-180 =="
sed -n '80,180p' "$FILE"
echo
echo "== lines 430-620 =="
sed -n '430,620p' "$FILE"Repository: tarkovtracker-org/RatScanner
Length of output: 11580
Switch this contour retrieval to RetrievalModes.External
RetrievalModes.List returns both sides of the closed 1px slot border, so each cell produces duplicate contour crops that are only removed later. External keeps the outer contour and avoids that extra work.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/ScanEngine/Processing/Inventory.cs` around lines 264 - 267, Update the
FindContoursAsArray call in the contour processing flow to use
RetrievalModes.External instead of RetrievalModes.List, while preserving the
existing ContourApproximationModes.ApproxSimple setting.
|
Closing as superseded by the standalone RatEye implementation merged in tarkovtracker-org/RatEye#1 and consumed by RatScanner PR #22. The inventory-recognition methods and regression coverage now live in the RatEye submodule, preserving the repository boundary. |
What changed
Why
The current game UI can render one-pixel inventory borders that the legacy erosion-based grid walker loses. Transparent placeholder PNGs can also become misleading templates, while FIR/wishlist decoration can dominate low-confidence whole-cell template scores.
This ports the validated recognition behavior from the experimental RatEye branch into RatScanner's authoritative in-tree
src/ScanEnginearchitecture. It does not reintroduce a submodule.Impact
Current inventory cells are localized again, stale generated templates are invalidated when their source changes, and low-confidence matches can be corrected only when OCR resolves one unique exact catalog short name. Missing OCR traineddata leaves template matching operational.
Validation
dotnet csharpier check .Accuracy-sensitive real-game smoke evidence originated from the controlled four-case replay used for the source fix; the copyrighted fixture corpus remains local and is not committed.
Summary by cubic
Restores reliable inventory icon detection in the current UI by handling 1‑px cell borders and preventing bad templates, with OCR-based verification for low-confidence matches and cache keys that track source changes. Current cells are found again and stale generated icons are replaced automatically.
Bug Fixes
New Features
Written for commit afd87f1. Summary will update on new commits.