Skip to content

feat(scan): finish-line — Ogre-only --fix path + 5 new quality rules (Phase 6 slice C4) - #504

Merged
fernandotonon merged 3 commits into
masterfrom
feat/phase6-slice-c4-finish-scan
May 13, 2026
Merged

feat(scan): finish-line — Ogre-only --fix path + 5 new quality rules (Phase 6 slice C4)#504
fernandotonon merged 3 commits into
masterfrom
feat/phase6-slice-c4-finish-scan

Conversation

@fernandotonon

@fernandotonon fernandotonon commented May 13, 2026

Copy link
Copy Markdown
Owner

Summary

Closes out the scan-side Assimp retirement thread started in C2/C3 and adds the production-grade quality rules the C3 audit flagged as missing.

Fix path consolidation

C2 routed the redundant_keyframes_pct fix through AnimationMerger::simplifyAnimation for FBX only. Non-FBX formats went through Assimp::Importer + a scan-specific stripRedundantAnimKeys (consecutive-duplicate stripping per channel) + Assimp::Exporter. C4 unifies them: every supported format (FBX / glTF / glb / DAE / OBJ / PLY / STL / .mesh) now loads via MeshImporterExporter, simplifies via AnimationMerger::simplifyAnimation under the configured tolerances, and re-exports via MeshImporterExporter::exporter.

Drops ~220 LoC: vecApproxEqualAssimp, quatApproxEqualAssimp, compactVectorTrackInPlace, compactQuatTrackInPlace, stripRedundantAnimKeys, totalAnimKeysForScene, assimpExportFormatIdForAssetPath, and the <assimp/Exporter.hpp> include. The only remaining Assimp::Importer site in scan is the metadata-only ReadFile that enumerates texture references for require_textures_exist.

New rules (all opt-in)

rule severity what it catches
max_texture_resolution warning largest bound-texture pixel dim above cap
require_uv_channels warning submesh with fewer UV sets than required (lightmap workflows)
detect_zero_weight_bones info Mixamo bloat — bones with no vertex weights
detect_overlapping_uvs_pct warning UV0 AABB sweep — lightmap-unsafe stacked unwraps
detect_non_manifold_edges_pct warning edges shared by != 2 faces (boolean / printing safety)

All five live inside the same Ogre scene walk C3 already runs — no extra import per asset when they're off.

Verification

Manual scan of media/models/Rumba Dancing.fbx with all C4 rules enabled:

zeroWeightBones: 15           # Mixamo carries 70 bones, 15 unused
overlappingUvsRatio: 1.00     # Mixamo's stacked UV islands
nonManifoldEdgesRatio: 0.32   # open clothing edges

All three rules fire as expected. Default scan against media/models still passes clean (0 warnings) because the new rules ship disabled in the bundled qtmesh.yml.

What changed in the surface

  • src/ScanEngine.cpp — fixed path unified; new collectors maxTextureDimensionForEntities, minUvChannelCountForEntities, zeroWeightBonesForEntities, overlappingUvsRatioForEntities, nonManifoldEdgesRatioForEntities; rule evaluators for each.
  • src/ScanConfig.h/cpp — new fields + YAML/JSON parsers + scope override pickup.
  • src/ScanEngine.hAssetInfo carries the new data fields.
  • src/CLIPipeline.cpp — new "Quality rules (config only)" section in qtmesh scan --help.
  • qtmesh.yml — example commented-out block for the new rules with a note that they're opt-in.
  • website/src/DocsApp.jsx — full RuleCard reference for the new rules + a new "Animation Simplification" section documenting redundant_keyframes_pct and its three tolerance knobs (previously undocumented).
  • CLAUDE.mdScanEngine description updated to reflect the unified Ogre fix path and the new rule set.

Tests

13 new gtest cases in ScanEngine_test.cpp:

  • 9 evaluator tests (positive + boundary per rule, plus a "default-disabled" regression).
  • 2 ScanConfig parser tests covering the new YAML keys and scope override pickup.

The unified fix path's analyzer side is exercised by the pre-existing redundant_keyframes_pct tests; the FBX export side stays covered by the existing scan-fix tests.

What's NOT in this PR

  • Cloud webapp form fields for the 5 new rules in fernandotonon/qtmesh-cloud/web/app.js. The qtmesh-cloud config UI has a per-rule HTML input; adding the 5 new ones is a small frontend change in a different repo and is captured as a follow-up.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added five configurable quality rules: max texture resolution, required UV channels, zero-weight bone detection, overlapping-UVs threshold, and non-manifold-edges threshold.
    • Extended asset inspection and reporting to include texture/UV/geometry metrics; animation simplification now re-exports across supported formats with size-growth guards.
  • Documentation

    • Updated config examples, help text, rules reference, and auto-fix docs with the new quality rules and animation simplification behavior.
  • Tests

    • Added unit tests covering parsing and evaluation of the new quality rules.

Review Change Stack

…(Phase 6 slice C4)

Closes out the scan-side Assimp retirement thread and adds the
production-grade quality rules that the C3 doc audit flagged as missing.

## Fix path

Slice C2 routed the redundant_keyframes_pct --fix through
AnimationMerger::simplifyAnimation only for .fbx/.fbxa. Non-FBX formats
still went through Assimp::Importer + a scan-specific
stripRedundantAnimKeys + Assimp::Exporter, which:
  - used a weaker analyzer than what `qtmesh anim --simplify` runs;
  - was the only remaining Assimp::Exporter site in scan.

C4 unifies the fix path: every supported extension (FBX / glTF / glb /
DAE / OBJ / PLY / STL / .mesh) loads via MeshImporterExporter,
simplifies via AnimationMerger::simplifyAnimation under the configured
tolerances, then re-exports via MeshImporterExporter::exporter against
the matching format descriptor. Drops ~220 LoC of vecApproxEqualAssimp /
quatApproxEqualAssimp / compactVectorTrackInPlace / stripRedundantAnimKeys /
totalAnimKeysForScene / assimpExportFormatIdForAssetPath and the
<assimp/Exporter.hpp> include. Assimp's role in scan is now narrowly
limited to a metadata-only ReadFile for texture-reference enumeration
(needed by require_textures_exist when the texture file is missing).

## New quality rules

All five new rules are opt-in (zero default = disabled) and consume data
collected in the same Ogre scene walk that C3 already runs — no extra
import cost when they're off.

- max_texture_resolution (warn): largest single-axis pixel dimension of
  any bound texture exceeds the configured cap. Walks each TUS's
  resolved Ogre::Texture and checks max(width, height).

- require_uv_channels (warn): per-submesh minimum count of
  VES_TEXTURE_COORDINATES elements. Takes the minimum across submeshes
  so any one submesh missing its lightmap UV trips the rule.

- detect_zero_weight_bones (info): set of bones with no
  VertexBoneAssignment on any submesh. Common Mixamo bloat. Info-level
  by design — stripping unused bones needs a DCC round-trip rather than
  an auto-fix.

- detect_overlapping_uvs_pct (warn): fraction of triangles whose UV0
  AABB overlaps another triangle's. O(n log n) sweep on xmin-sorted
  bboxes, cheap upper bound on true UV overlap. Catches the common
  cases — Mixamo body / clothing UV islands stacked at the same
  0-1 range, mirrored geometry on a shared lightmap unwrap, etc.

- detect_non_manifold_edges_pct (warn): fraction of edges shared by
  != 2 triangulated faces. Boundary edges count too — catches
  open-bottom clothing meshes that break boolean ops / fluid sims /
  3D printing.

## Surfaces

Wired into:
- ScanConfig parser (YAML & JSON), applyRuleOverrides for scoped
  overrides, and JSON asset report (writes maxTextureDimension,
  minUvChannelCount, zeroWeightBones, overlappingUvsRatio,
  nonManifoldEdgesRatio when populated).
- ScanEngine ruleDescriptions for SARIF / cloud schema export.
- CLI help: new "Quality rules (config only)" section in
  `qtmesh scan --help` listing every new rule with its key form and
  example threshold.
- bundled qtmesh.yml: example commented-out block with the rules and a
  note that they're opt-in.
- website DocsApp.jsx: new "Quality Rules (Slice C4)" section under
  the rule reference with a RuleCard for each, plus a
  "Animation Simplification" section documenting redundant_keyframes_pct
  and its three tolerance knobs. The walkthrough yaml snippet shows all
  rules at once.
- CLAUDE.md ScanEngine description: updated to reflect the unified
  Ogre fix path and the new rule set.

## Verification

Manual scan of media/models against the bundled config with all C4
rules enabled (against Rumba Dancing.fbx):

  zeroWeightBones: 15        # Mixamo carries 70 bones, 15 unused
  overlappingUvsRatio: 1.0   # Mixamo's stacked UV islands
  nonManifoldEdgesRatio: 0.319  # open clothing edges

All three rules fire as expected. The default qtmesh.yml in this repo
still scans clean (0 warnings) because the new rules ship disabled.

## Tests

13 new gtest cases:
- 9 evaluator tests (one positive + one boundary case per new rule,
  plus a regression that confirms all five are silent when disabled).
- 2 ScanConfig parser tests covering the new YAML keys + scope override
  pickup.
- The existing redundant_keyframes_pct rule tests cover the unified
  fix path's analyzer side; the FBX export side stays exercised by the
  pre-existing scan-fix tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: faeb20fb-649d-4d04-9476-3eef3e420618

📥 Commits

Reviewing files that changed from the base of the PR and between cea7231 and 4a65210.

📒 Files selected for processing (3)
  • src/ScanEngine.cpp
  • src/ScanEngine_test.cpp
  • website/src/DocsApp.jsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • website/src/DocsApp.jsx
  • src/ScanEngine_test.cpp
  • src/ScanEngine.cpp

📝 Walkthrough

Walkthrough

Adds Phase 6 "C4" quality-rule scanning: new ScanConfig fields, AssetInfo extensions, Ogre-based collectors to compute texture/UV/topology metrics, evaluateRules checks that emit findings, JSON/SARIF reporting, tests, docs, and an Ogre-based redundant-keyframes auto-fix pipeline.

Changes

C4 Quality Rules Integration

Layer / File(s) Summary
Configuration Contract and Parsing
src/ScanConfig.h, src/ScanConfig.cpp, src/CLIPipeline.cpp, qtmesh.yml, website/src/DocsApp.jsx
Adds new ScanConfig fields for C4 rules (max_texture_resolution, require_uv_channels, detect_zero_weight_bones, detect_overlapping_uvs_pct, detect_non_manifold_edges_pct), parses them from YAML/VariantMap, supports scope overrides, updates CLI help, and adds commented qtmesh.yml and website examples.
Asset Quality Metrics Data Model
src/ScanEngine.h
Extends AssetInfo with maxTextureDimension, minUvChannelCount, zeroWeightBoneNames, overlappingUvsRatio, nonManifoldEdgesRatio.
Quality Metric Collectors and Inspection Integration
src/ScanEngine.cpp
Adds Ogre-based collectors that compute largest texture dimension, UV channel coverage, zero-weight bones, UV0 overlap upper-bound, and non-manifold edge ratio; inspectAssetViaOgre and inspectAsset populate these fields.
C4 Rule Evaluation Logic
src/ScanEngine.cpp
evaluateRules implements checks for the five C4 rules and emits findings when thresholds are exceeded (with skip conditions for disabled/sentinel values).
Redundant Keyframes Fix Path Rewrite
src/ScanEngine.cpp
Removes Assimp exporter rewrite; implements an Ogre + MeshImporterExporter pipeline that imports, selects skeletons, simplifies animations via AnimationMerger::simplifyAnimation, exports via editor exporter, applies size-growth guards, and reports fix metadata.
JSON and SARIF Output Integration
src/ScanEngine.cpp, src/ScanEngine.h
scanReportToJsonObject conditionally includes C4 fields when populated; SARIF ruleDescriptions added for all new C4 rule IDs.
Configuration, Inspection, and Rule Evaluation Tests
src/ScanEngine_test.cpp
Tests for YAML parsing of C4 keys, scope override behavior, and evaluateRules correctness (fire/skip, disabled-by-default, message/severity assertions).
Pipeline Documentation and Configuration Examples
CLAUDE.md, qtmesh.yml, website/src/DocsApp.jsx
Updated CLAUDE.md, commented qtmesh.yml placeholders, website docs/rule cards, and Auto-Fix table describing the new redundant-keyframes fix and re-export behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through meshes, counted UVs and bones,

I chased stray keys and mended broken zones.
Ogre lent me tools to tidy frame and face,
Exports kept small, no unwelcome space—
A rabbit's tidy scan, all neat in place.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.29% 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
Title check ✅ Passed The title directly and clearly describes the main change: unifying the fix path to be Ogre-only and adding 5 new quality rules as Phase 6 slice C4.
Description check ✅ Passed The description provides comprehensive coverage of both the fix path consolidation and new rules, with clear technical details, verification steps, and test coverage. It follows the template structure with summary and technical details.
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 feat/phase6-slice-c4-finish-scan

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cea7231ecb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ScanEngine.cpp Outdated
Comment on lines +498 to +500
const auto& assignments = sub->getBoneAssignments();
for (const auto& [vertexIdx, vba] : assignments)
usedHandles.insert(vba.boneIndex);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include shared-geometry weights before flagging zero-weight bones

This detector only reads sub->getBoneAssignments(), but Ogre stores skin weights for shared-vertex meshes in mesh->getBoneAssignments(). For assets using useSharedVertices, usedHandles stays incomplete and valid weighted bones are incorrectly reported as zero-weight, producing false info findings for common rig layouts.

Useful? React with 👍 / 👎.

Comment thread src/ScanEngine.cpp Outdated
Comment on lines +628 to +631
uint32_t a = idx[t + k];
uint32_t b = idx[t + ((k + 1) % 3)];
if (a > b) std::swap(a, b);
edges[{a, b}]++;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Disambiguate edge keys across submeshes in non-manifold metric

The non-manifold collector hashes edges using only raw index pairs, but index buffers are local to each non-shared submesh (and can restart at 0 per submesh/entity). This merges unrelated edges like (0,1) from different submeshes into one bucket, corrupting incidence counts and causing both false positives and false negatives in detect_non_manifold_edges.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ScanEngine.cpp (1)

1071-1096: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

RSD path drops all newly collected C4 metrics.

In the RSD wrapper branch, the copy from inner omits maxTextureDimension, minUvChannelCount, zeroWeightBoneNames, overlappingUvsRatio, and nonManifoldEdgesRatio, so C4 rules silently won’t evaluate for .rsd assets.

Proposed fix
         info.redundantKeyframes = inner.redundantKeyframes;
+        info.maxTextureDimension = inner.maxTextureDimension;
+        info.minUvChannelCount = inner.minUvChannelCount;
+        info.zeroWeightBoneNames = inner.zeroWeightBoneNames;
+        info.overlappingUvsRatio = inner.overlappingUvsRatio;
+        info.nonManifoldEdgesRatio = inner.nonManifoldEdgesRatio;
🤖 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.cpp` around lines 1071 - 1096, The RSD wrapper branch copies
many fields from the local AssetInfo named inner into info but omits C4 metric
fields (maxTextureDimension, minUvChannelCount, zeroWeightBoneNames,
overlappingUvsRatio, nonManifoldEdgesRatio), causing RSD assets to lose these
metrics; update the copy block in ScanEngine (where AssetInfo inner =
ScanEngine::inspectAsset(...) is used) to assign those missing fields (e.g.,
info.maxTextureDimension = inner.maxTextureDimension; info.minUvChannelCount =
inner.minUvChannelCount; info.zeroWeightBoneNames = inner.zeroWeightBoneNames;
info.overlappingUvsRatio = inner.overlappingUvsRatio; info.nonManifoldEdgesRatio
= inner.nonManifoldEdgesRatio) so the info returned preserves all C4 metrics for
.rsd assets.
🤖 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.cpp`:
- Around line 1371-1390: The emitted finding rule IDs (the string literals
passed to findings.append: "detect_overlapping_uvs" and
"detect_non_manifold_edges") must be changed to match the config/documentation
keys with the "_pct" suffix ("detect_overlapping_uvs_pct" and
"detect_non_manifold_edges_pct"); update those string IDs in the ScanEngine.cpp
instances that build these findings (the block checking
config.detectOverlappingUvsPct / asset.overlappingUvsRatio and the analogous
block checking config.detectNonManifoldEdgesPct / asset.nonManifoldEdgesRatio)
and also update the other occurrence mentioned (the similar findings emitted
later) so all emitted rule IDs consistently include the "_pct" suffix.
- Around line 1632-1635: The call to MeshImporterExporter::importer is unguarded
and can throw, so wrap the call (the sequence around
clearOgreSceneForScanImport(); QList<Ogre::SkeletonPtr> animOnlySkeletons;
MeshImporterExporter::importer({asset.filePath}, 0, &animOnlySkeletons);) in a
try/catch block that catches std::exception& and a catch-all, logs the error
(include exception.what() when available) and cleans up the Ogre scene state,
then skip/continue processing this file instead of letting the exception
propagate and abort the scan/fix run; do not rethrow the exception.
- Around line 605-642: The non-manifold calculation wrongly collides edges from
different meshes/submeshes because edges are keyed only by local vertex indices;
change the map key to include mesh/submesh identity so edges are unique per
source. Define a composite key (e.g., struct EdgeKey { const void* meshPtr;
unsigned submeshIndex; uint32_t a,b; } with equality and hash) or include the
entity pointer and submesh index in the key, keep the existing a>b swap, and
when inserting/incrementing use EdgeKey{mesh.get(), s, a, b} (or Entity pointer
+ s) instead of std::pair<uint32_t,uint32_t>; update the unordered_map type and
iteration accordingly so nonManifold counts are computed per mesh/submesh
correctly.

In `@website/src/DocsApp.jsx`:
- Around line 941-954: The docs claim the "redundant_keyframes_pct" rule is
fixable but the Auto-Fix table lacks that entry; update the Auto-Fix
table/component to include redundant_keyframes_pct (referencing the RuleCard
name="redundant_keyframes_pct") as a fixable rule, show the example config keys
(redundant_keyframes_pct and the three tolerance keys) and the fix command
(qtmesh scan ... --fix re-export behavior) so the table matches the RuleCard
text and example.

---

Outside diff comments:
In `@src/ScanEngine.cpp`:
- Around line 1071-1096: The RSD wrapper branch copies many fields from the
local AssetInfo named inner into info but omits C4 metric fields
(maxTextureDimension, minUvChannelCount, zeroWeightBoneNames,
overlappingUvsRatio, nonManifoldEdgesRatio), causing RSD assets to lose these
metrics; update the copy block in ScanEngine (where AssetInfo inner =
ScanEngine::inspectAsset(...) is used) to assign those missing fields (e.g.,
info.maxTextureDimension = inner.maxTextureDimension; info.minUvChannelCount =
inner.minUvChannelCount; info.zeroWeightBoneNames = inner.zeroWeightBoneNames;
info.overlappingUvsRatio = inner.overlappingUvsRatio; info.nonManifoldEdgesRatio
= inner.nonManifoldEdgesRatio) so the info returned preserves all C4 metrics for
.rsd assets.
🪄 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: cbf7e8e5-19b2-4b7a-a4af-7fa36534d6c4

📥 Commits

Reviewing files that changed from the base of the PR and between 58dc4bb and cea7231.

📒 Files selected for processing (9)
  • CLAUDE.md
  • qtmesh.yml
  • src/CLIPipeline.cpp
  • src/ScanConfig.cpp
  • src/ScanConfig.h
  • src/ScanEngine.cpp
  • src/ScanEngine.h
  • src/ScanEngine_test.cpp
  • website/src/DocsApp.jsx

Comment thread src/ScanEngine.cpp
Comment thread src/ScanEngine.cpp Outdated
Comment thread src/ScanEngine.cpp
Comment thread website/src/DocsApp.jsx
fernandotonon and others added 2 commits May 13, 2026 02:06
CodeRabbit + Codex flagged 6 issues. All real; all fixed.

1) detect_zero_weight_bones missed shared-vertex skin weights.
   Ogre stores per-vertex bone assignments at the *mesh* level when
   submeshes share a single vertex pool (typical Mixamo / FBX layout);
   the C4 collector only walked sub->getBoneAssignments(). Result:
   every bone got flagged as zero-weight on shared-vertex skinned
   meshes — a false-positive flood. Now reads both
   mesh->getBoneAssignments() and sub->getBoneAssignments() into the
   same used-handles set. (Codex P1)

2) detect_non_manifold_edges collided edges across submeshes/entities.
   The edge key was just std::pair<a,b>, but index buffers are local
   to each non-shared submesh and restart at 0, so unrelated edges
   like (0,1) from different submeshes shared a bucket and corrupted
   the incidence count. Key now carries the vertex-pool pointer
   (mesh->sharedVertexData when useSharedVertices, sub->vertexData
   otherwise) so edges are unique per source. (Codex P1, CodeRabbit
   major)

3) Finding rule IDs didn't match config keys.
   Config exposed detect_overlapping_uvs_pct / detect_non_manifold_edges_pct
   but findings/SARIF emitted detect_overlapping_uvs /
   detect_non_manifold_edges (no _pct suffix). Aligned in
   evaluateRules emit sites, ruleDescriptions, and the unit-test
   asserts so config + findings + SARIF + docs all speak the same
   names. (CodeRabbit minor)

4) MeshImporterExporter::importer in --fix path was unguarded.
   A throw from a malformed asset (e.g. missing-texture
   MaterialProcessor crash) would abort the whole scan/fix run
   mid-pass. Now wrapped in try/catch with separate Ogre::Exception
   and std::exception arms; reports the failure on the per-finding
   message and continues to the next file. Matches the analogous
   guard around inspectAssetViaOgre's loader call. (CodeRabbit major)

5) RSD wrapper branch dropped the new C4 AssetInfo fields.
   inspectAsset's .rsd handler delegates to the geometry's inspect
   and copies fields one by one — the new C4 fields
   (maxTextureDimension, minUvChannelCount, zeroWeightBoneNames,
   overlappingUvsRatio, nonManifoldEdgesRatio) weren't in the
   copy block, so C4 rules silently no-op'd on .rsd assets. Added
   the missing assignments. (CodeRabbit outside-diff major)

6) Auto-Fix docs table didn't list redundant_keyframes_pct.
   The DocsApp RuleCard already says the rule is fixable, but the
   Auto-Fix overview table only listed file_name_case. Added a row
   covering the C2/C4 simplify re-export across every supported
   format. (CodeRabbit minor)

Local smoke test: Rumba Dancing.fbx under all three detect_* rules
now emits 1 info + 2 warnings (zero_weight_bones, overlapping_uvs_pct,
non_manifold_edges_pct) — matches expectation. Build + tests clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub Actions Linux runner stalled on the aqt Install Qt step for >24
minutes on the previous workflow run, blocking the build-linux status
check. All other CI passed (build-macos, build-windows, unit-tests-linux,
SonarCloud, scan-assets-qtmesh, verify-doc-versions). No code change —
push an empty commit to retrigger CI from scratch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 1dc91d9 into master May 13, 2026
20 checks passed
@fernandotonon
fernandotonon deleted the feat/phase6-slice-c4-finish-scan branch May 13, 2026 12:54
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.

1 participant