Skip to content

feat(scanner): support variable Ribbon geometries#36

Merged
TriForMine merged 2 commits into
mainfrom
scanner-variable-symbol-size
May 30, 2026
Merged

feat(scanner): support variable Ribbon geometries#36
TriForMine merged 2 commits into
mainfrom
scanner-variable-symbol-size

Conversation

@TriForMine

@TriForMine TriForMine commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Refactor

    • Enhanced core decoding algorithm with improved candidate evaluation and geometry search capabilities, now supporting variable ribbon geometry configurations.
  • Tests

    • Added test coverage for variable-size ribbon geometry decoding.
  • Chores

    • Updated development environment configuration.

Review Change Stack

Copilot AI review requested due to automatic review settings May 30, 2026 07:35
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The PR refactors glyphnet-scanner's ribbon decoding to support variable geometry. It introduces a RibbonGeometry abstraction, replaces fixed symbol dimensions with geometry-driven searches across candidate geometries, dynamically generates module_px candidates, and simplifies the main decode flow by removing the coarse-grid path.

Changes

Variable Geometry Ribbon Decoding

Layer / File(s) Summary
RibbonGeometry abstraction and helpers
crates/glyphnet-scanner/src/decode_paths.rs
RibbonGeometry struct and helpers (fractional_ribbon_geometry_candidates, reference_ribbon_geometry, gcd_u32, ribbon_module_px_candidates) enable dynamic candidate generation. fractional_header_precheck refactored to accept RibbonGeometry and use its symbol dimensions.
Exact ribbon candidate with module_px search
crates/glyphnet-scanner/src/decode_paths.rs
decode_exact_ribbon_candidate now iterates over dynamically generated module_px candidates from ribbon_module_px_candidates helper, attempting exact decoding for each candidate instead of validating a single derived value.
Fractional ribbon geometry search and parameterized decoding
crates/glyphnet-scanner/src/decode_paths.rs
decode_fractional_ribbon_candidate searches across candidate geometries, tests fits with geometry-dependent symbol width/height, runs header prechecks with geometry, and decodes via decode_fractional_with_params. decode_fractional_with_params refactored to accept RibbonGeometry and build SymbolMatrix using geometry-provided dimensions.
Simplified decode_candidate flow
crates/glyphnet-scanner/src/decode_paths.rs
Removes the signature-window/coarse-grid path that resized input before exact ribbon decode, streamlining flow to direct exact-ribbon followed by fractional-ribbon decoding.
Variable geometry ribbon decoding test
crates/glyphnet-scanner/src/lib.rs
New test decode_candidate_accepts_variable_size_ribbon_geometry renders a RibbonWeave symbol with non-reference geometry, constructs a ScanCandidate with actual dimensions, and validates successful decoding and layout hint reporting.
Build artifact exclusion
.gitignore
Adds .serena/ entry to exclude that directory from version control.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 The ribbons now dance with geometry free,
No fixed dimensions binding thee!
Candidates bloom where shapes align,
Decode with grace at every sign. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(scanner): support variable Ribbon geometries' directly and clearly describes the main change: enabling the scanner to handle variable Ribbon geometries instead of fixed ones, which is confirmed by the substantial refactoring in decode_paths.rs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch scanner-variable-symbol-size

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown

Burst reliability (loss sweep)

PR gate status: PASS

  • Gating rows: 4 pass / 0 fail
  • Non-gating rows: none
Drop rate Gating PR success Base success Delta PR median frames Base median frames
10% Yes 100.0% 100.0% 0.0pp 14 14
20% Yes 100.0% 100.0% 0.0pp 16 16
30% Yes 100.0% 100.0% 0.0pp 19 19
40% Yes 50.0% 50.0% 0.0pp 18 18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions

github-actions Bot commented May 30, 2026

Copy link
Copy Markdown

Scanner perf (ribbon + matrix fixtures)

PR gate status: PASS

  • Ribbon budget: 25.000 ms (allowed 75.000 ms)
  • Matrix budget: 20.000 ms (allowed 60.000 ms)
  • Tolerance: 200.0%
  • Ribbon gating benches: 3 pass / 0 fail
  • Matrix gating benches: 1 pass / 0 fail
Benchmark Gating PR median (ms) Base median (ms) Delta (ms) Delta %
scan_generated_ribbon_canvas_small (RibbonPrint) Yes 44.789 44.729 0.060 0.13%
scan_generated_ribbon_canvas_medium (RibbonPrint) Yes 6.681 6.668 0.013 0.19%
scan_generated_ribbon_canvas_large (RibbonPrint) Yes 23.790 23.731 0.059 0.25%
scan_generated_matrix_roi (MatrixCompat) Yes 2.923 2.903 0.020 0.69%
scan_generated_matrix_canvas (MatrixCompat) No 281.115 175.087 106.028 60.56%
scan_real_debugger_screenshot (RibbonPrint) No 284.638 259.124 25.515 9.85%

Matrix subset

Benchmark Gating PR median (ms) Base median (ms) Delta (ms) Delta %
scan_generated_matrix_roi (MatrixCompat) Yes 2.923 2.903 0.020 0.69%
scan_generated_matrix_canvas (MatrixCompat) No 281.115 175.087 106.028 60.56%

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@crates/glyphnet-scanner/src/decode_paths.rs`:
- Around line 234-249: The fractional_ribbon_geometry_candidates function
currently always returns DEFAULT_PRINT_RIBBON (96x36); instead, compute
candidate RibbonGeometry values from the observed image_width and image_height
by deriving a scale = image_width / DEFAULT_PRINT_RIBBON.total_width_modules()
and/or using both scale_x and scale_y (via total_width_modules() and
total_height_modules()) to compute symbol_width and symbol_height, round or
floor/ceil to nearby integer module sizes, and produce a Vec of plausible
RibbonGeometry variants around that scale (e.g., exact rounded, +/-1 module
sizes, and swapped scale fits) rather than the hard-coded DEFAULT_PRINT_RIBBON;
update fractional_ribbon_geometry_candidates to return those computed candidates
(referencing DEFAULT_PRINT_RIBBON, fractional_ribbon_geometry_candidates,
total_width_modules(), total_height_modules()) so the fractional path can
explore non-reference ribbon sizes.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a3ddf23a-d87a-44d2-bfcb-d689fd011796

📥 Commits

Reviewing files that changed from the base of the PR and between a482d29 and 9b3a8a1.

📒 Files selected for processing (3)
  • .gitignore
  • crates/glyphnet-scanner/src/decode_paths.rs
  • crates/glyphnet-scanner/src/lib.rs

Comment on lines +234 to +249
fn fractional_ribbon_geometry_candidates(
image_width: u32,
image_height: u32,
) -> Vec<RibbonGeometry> {
const DEFAULT_PRINT_RIBBON: RibbonGeometry = RibbonGeometry {
symbol_width: 96,
symbol_height: 36,
};

let scale_x = image_width as f32 / DEFAULT_PRINT_RIBBON.total_width_modules() as f32;
let scale_y = image_height as f32 / DEFAULT_PRINT_RIBBON.total_height_modules() as f32;
if scale_x >= 1.0 && scale_y >= 1.0 && (0.6..=1.7).contains(&(scale_x / scale_y)) {
vec![DEFAULT_PRINT_RIBBON]
} else {
Vec::new()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Fractional decoding is still pinned to the reference geometry.

fractional_ribbon_geometry_candidates() only ever returns DEFAULT_PRINT_RIBBON, so the fractional path never explores the non-reference ribbon sizes this PR is introducing. That means any variable-geometry ribbon that needs the fractional fallback will still end up at AutoDetectFailed even though the exact path was generalized.

Please generate candidate RibbonGeometry values from the observed image dimensions instead of hard-coding 96x36 here.

🤖 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 `@crates/glyphnet-scanner/src/decode_paths.rs` around lines 234 - 249, The
fractional_ribbon_geometry_candidates function currently always returns
DEFAULT_PRINT_RIBBON (96x36); instead, compute candidate RibbonGeometry values
from the observed image_width and image_height by deriving a scale = image_width
/ DEFAULT_PRINT_RIBBON.total_width_modules() and/or using both scale_x and
scale_y (via total_width_modules() and total_height_modules()) to compute
symbol_width and symbol_height, round or floor/ceil to nearby integer module
sizes, and produce a Vec of plausible RibbonGeometry variants around that scale
(e.g., exact rounded, +/-1 module sizes, and swapped scale fits) rather than the
hard-coded DEFAULT_PRINT_RIBBON; update fractional_ribbon_geometry_candidates to
return those computed candidates (referencing DEFAULT_PRINT_RIBBON,
fractional_ribbon_geometry_candidates, total_width_modules(),
total_height_modules()) so the fractional path can explore non-reference ribbon
sizes.

@TriForMine TriForMine merged commit 79cf00e into main May 30, 2026
11 checks passed
@TriForMine TriForMine deleted the scanner-variable-symbol-size branch May 30, 2026 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants