Skip to content

fix(export): guard texture serialization + pause timers during GUI export (3.3.1)#693

Merged
fernandotonon merged 4 commits into
masterfrom
fix/gui-export-crashes
May 28, 2026
Merged

fix(export): guard texture serialization + pause timers during GUI export (3.3.1)#693
fernandotonon merged 4 commits into
masterfrom
fix/gui-export-crashes

Conversation

@fernandotonon
Copy link
Copy Markdown
Owner

@fernandotonon fernandotonon commented May 28, 2026

Summary

Fixes the GUI File → Export Selected crash on Ogre .mesh and every Assimp-backed format (.gltf, .glb, .obj, .dae, .stl, .ply, .3ds, .x, .assbin). FBX and PS1 (.tmd / .rsd) survived because their custom exporters snapshot inputs up front; the rest walk the live mesh and tripped one of two bugs.

Bumps version to 3.3.1 and re-runs scripts/sync-doc-versions-from-cmake.sh per CLAUDE.md so README + website hook stay aligned.

Root cause

MeshImporterExporter::exportTextures called Ogre::Texture::convertToImage() unconditionally. When a material's TUS references a texture that isn't GPU-resident — null _getTexturePtr, isLoaded() == false, or zero-size from a placeholder TUS — convertToImage reads from a null buffer and SIGSEGVs inside Ogre (Ogre::Texture::convertToImage + 116, confirmed via printf trace to /tmp/qtmesh_export_trace.log since stderr is consumed by macOS .app bundle launchd).

[export] before MeshSerializer::exportMesh
[export] after MeshSerializer::exportMesh
[export] before exportMaterial         ← crash happens after this line

Fix 1 — Texture guards

exportTextures now:

  • Skips null TexturePtr, non-2D types, zero-size textures
  • Attempts tex->load() when not loaded (some imports defer GPU upload until first render)
  • Wraps convertToImage + img.save() in catch-all so one bad texture can't take down the export — errors logged via Ogre::LogManager

Fix 2 — Timer-pause during the action

The QFileDialog in the export path opens a nested event loop. Without pausing timers, queued timer callbacks fire inside the dialog AND mid-export:

  • MainWindow::m_pTimer calls renderOneFrame() → serializer reads a mesh that the renderer is currently writing
  • AnimationControlController::m_pollTimer (60 fps) advances the SkeletonInstance's animation time position → same race against the serializer

Added AnimationControlController::suspendPollTimer / resumePollTimer and called both around the whole on_actionExport_Selected_triggered action. Render timer paused too. Viewport freezes during the dialog and the export call but resumes cleanly after.

Bonus

MeshImporterExporter::exporter(node) now takes an optional QWidget* parent so the file dialog is anchored to MainWindow instead of nullptr (cleaner modal cycle on macOS).

Test plan

  • CLI qtmesh convert ... -o /tmp/x.mesh still works (unchanged path)
  • CLI export for every format (.mesh, .gltf, .glb, .obj, .dae, .stl, .ply, .3ds, .x, .assbin, .mesh.xml, .fbx) — all OK
  • GUI File → Export Selected → .mesh — no longer crashes (verified by user on Hip Hop Dancing.fbx)
  • CI green on Linux / macOS / Windows
  • CodeRabbit review

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved export stability with more robust texture handling and error reporting to avoid crashes.
    • Fixed modal dialog and export lifecycle on macOS by ensuring render/animation polling is paused/resumed correctly during exports.
  • New Features

    • Added suspend/resume controls for animation polling during long-running operations.
    • Export dialog now anchors to the application window to ensure deterministic modal behavior.
  • Chores

    • Bumped project version to 3.3.1 and updated CI examples and documentation version pins.

Review Change Stack

…port (3.3.1)

Two coupled fixes for the GUI "File → Export Selected" crash that
reproduced on Ogre .mesh + every Assimp-backed format (glTF, OBJ,
Collada, STL, PLY, 3DS, X, Assimp Binary). FBX and PS1 (.tmd /
.rsd) survived because their custom exporters snapshot inputs up
front; the others walk the live mesh.

* Root cause: `MeshImporterExporter::exportTextures` called
  `Ogre::Texture::convertToImage()` unconditionally. When a
  material's TUS references a texture that isn't GPU-resident
  (null `_getTexturePtr`, `isLoaded()=false`, or zero-size from
  a placeholder TUS), `convertToImage` reads from a null buffer
  and SIGSEGVs inside Ogre (`Ogre::Texture::convertToImage + 116`).
  Now guard with `!tex || !TEX_TYPE_2D || !isLoaded() || zero
  size`, attempt a `load()` first, and wrap the actual save in
  catch-all so a single bad texture can't take down the export.
  Errors are logged to Ogre LogManager; the rest of the export
  continues.

* Secondary: pause render-loop and animation-poll timers for the
  whole `on_actionExport_Selected_triggered` action. The
  QFileDialog opens a nested event loop; without pausing,
  queued timer callbacks fire inside the dialog AND mid-export.
  `MainWindow::m_pTimer` calls `renderOneFrame()` while the
  serializer walks the mesh, and
  `AnimationControlController::m_pollTimer` (60fps) advances
  the SkeletonInstance time position — both could mutate the
  data the serializer is reading. Added
  `AnimationControlController::suspendPollTimer/resumePollTimer`,
  called around the export. Render timer paused too.

* `MeshImporterExporter::exporter(node)` now takes an optional
  `QWidget* parent` so the file dialog is anchored to MainWindow
  instead of nullptr (cleaner modal cycle on macOS). Callers
  unchanged because the param defaults to nullptr.

Bumps version to 3.3.1. Per CLAUDE.md ran
`scripts/sync-doc-versions-from-cmake.sh` so README + website
hook stay aligned with the CMake project version.

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

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 937ff1d6-da6d-4ebb-91d4-cfcfafb8d6a7

📥 Commits

Reviewing files that changed from the base of the PR and between e38e8ba and 1164b82.

📒 Files selected for processing (1)
  • scripts/sync-doc-versions-from-cmake.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/sync-doc-versions-from-cmake.sh

📝 Walkthrough

Walkthrough

This PR releases 3.3.1: it adds AnimationControlController suspend/resume APIs to pause 60fps polling, hardens MeshImporterExporter (parent-anchored dialogs, early validation, safer texture export, adjusted exception handling), updates MainWindow export flow to suspend/resume timers, and bumps doc/CI version pins and sync script to 3.3.1.

Changes

Export crash prevention (issue #681)

Layer / File(s) Summary
Version updates
CMakeLists.txt, README.md, website/src/hooks/useQtmeshActionRef.js, scripts/sync-doc-versions-from-cmake.sh
Release version bumped from 3.3.0 to 3.3.1 in build config and examples; README and website fallback constant updated; sync script now verifies and rewrites image-tag pins as well as action-ref pins.
Animation poll timer suspension API
src/AnimationControlController.h, src/AnimationControlController.cpp
AnimationControlController adds Q_INVOKABLE suspendPollTimer() and resumePollTimer() and an m_pollSuspended flag to pause/resume the 60fps polling timer with Sentry breadcrumbs.
Export dialog parent widget & core validation
src/MeshImporterExporter.h, src/MeshImporterExporter.cpp
MeshImporterExporter::exporter(...) now accepts optional QWidget* parent for modal/dialog determinism; entrypoint uses parent for warnings and file chooser; exporter adds early null/URI/entity checks and tightens exception handling.
Texture export robustness
src/MeshImporterExporter.cpp
Texture export path adds null/2D/type/loaded/zero-dimension guards, explicit load() attempts, per-texture exception handling and logging, and a debug trace for the #681 repro.
Export flow integration
src/mainwindow.cpp
MainWindow export handler stops render/animation timers before export, passes this into exporter, and ensures timers are resumed in both success and exception paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I pause the poll, the meshes rest,
Dialogs anchored, textures pressed,
Exports march without a fright,
Version bumped and tests in sight,
Happy rabbit hops—builds succeed tonight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 Title clearly and concisely summarizes the main fix (guarding texture serialization and pausing timers during GUI export) and includes the version bump (3.3.1).
Description check ✅ Passed Description provides comprehensive summary, technical details, root cause analysis, explicit fixes with code explanations, test plan, and bonus improvements, well exceeding template requirements.
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 fix/gui-export-crashes

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.

Copy link
Copy Markdown

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

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: f9b65adf6e

ℹ️ 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".

file.setFile(_uri);

if(!Manager::getSingleton()->getSceneMgr()->hasEntity(_sn->getName())) return -1;
if(!Manager::getSingleton()->getSceneMgr()->hasEntity(_sn->getName())) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore the null scene-node guard

When the non-dialog exporter is called with a null scene node, this line now dereferences _sn before any validation. The public API previously returned -1 for this case (and the repo has MeshImporterExporterStandaloneTest.Exporter_NullSceneNode_ReturnMinusOne covering exporter(nullptr, "", "")), so invalid CLI/MCP/test inputs can now crash the process instead of failing cleanly. Keep the early _sn guard before accessing _sn->getName().

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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/MeshImporterExporter.cpp (1)

2335-2353: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add breadcrumbs for the user-triggered export dialog flow.

This UI path is user-facing and significant, but Line 2344 and the cancel path at Line 2348 are currently untracked.

💡 Suggested fix
 QString MeshImporterExporter::exporter(const Ogre::SceneNode *_sn, QWidget* parent)
 {
     if(!_sn)
     {
         QMessageBox::warning(parent,"No object","Which object are you trying to export?",QMessageBox::Ok);
         return QString();
     }
 
+    SentryReporter::addBreadcrumb(
+        "ui.action",
+        QStringLiteral("Opened Export Selected dialog"));
+
     QString filter = "Ogre Mesh (*.mesh)";
     QString fileName = QFileDialog::getSaveFileName(parent, QObject::tr("Export Mesh"),
                                                     _sn->getName().data(),
                                                     exportFileDialogFilter(),&filter,
                                                     QFileDialog::DontUseNativeDialog);
-    if(fileName.isEmpty()) return QString();
+    if(fileName.isEmpty()) {
+        SentryReporter::addBreadcrumb("ui.action", QStringLiteral("Export Selected canceled"));
+        return QString();
+    }
 
     QString uri = formatFileURI(fileName, filter);
+    SentryReporter::addBreadcrumb("file.export", QStringLiteral("Export Selected started: %1").arg(uri));
 
     exporter(_sn, uri, filter);
     return uri;
 }

As per coding guidelines, "All user-facing actions and significant operations must be tracked with SentryReporter::addBreadcrumb(category, message) using categories like 'ui.action', 'ai.tool_call', 'file.import', 'file.export'."

🤖 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/MeshImporterExporter.cpp` around lines 2335 - 2353, In
MeshImporterExporter::exporter add SentryReporter::addBreadcrumb calls to track
the user export flow: record a 'ui.action' breadcrumb just before showing the
save dialog with a message including the node name (use _sn->getName()), record
a 'file.export' breadcrumb if the user cancels (when fileName.isEmpty()) with a
clear "export canceled" message, and record a 'file.export' breadcrumb
immediately before calling exporter(_sn, uri, filter) indicating the export
started (include the URI and filter); use the same helper symbols already
present (formatFileURI, exportFileDialogFilter) to build messages so breadcrumbs
reflect the dialog open, cancel, and start-export events.
🤖 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 `@README.md`:
- Around line 54-57: The README shows the action ref set to
fernandotonon/QtMeshEditor@3.3.1 but still pins image-tag: "3.1.0"; update all
image-tag values to "3.3.1" and any adjacent “current version” text to match the
bumped action ref (look for the snippet containing
fernandotonon/QtMeshEditor@3.3.1 and the image-tag field, and other repeated
occurrences in the file), then run ./scripts/sync-doc-versions-from-cmake.sh to
propagate the CMake VERSION change to README and
website/src/hooks/useQtmeshActionRef.js so docs remain synchronized.

In `@src/AnimationControlController.cpp`:
- Around line 79-95: Replace the direct stderr prints in
AnimationControlController::suspendPollTimer and
AnimationControlController::resumePollTimer with SentryReporter::addBreadcrumb
calls: remove fprintf(stderr, ...) and instead call
SentryReporter::addBreadcrumb("ui.action", "[anim] suspendPollTimer") when
stopping the timer in suspendPollTimer and
SentryReporter::addBreadcrumb("ui.action", "[anim] resumePollTimer") when
starting the timer in resumePollTimer, leaving the existing checks for
m_pollTimer/m_pollSuspended and the m_pollTimer->stop()/start(16) and
m_pollSuspended toggles intact.

In `@src/MeshImporterExporter.cpp`:
- Around line 206-223: The code ignores the boolean result of img.save(...)
leading to silent texture export failures; update the block around img.save to
check its return value and handle failures explicitly: call img.save(...) into a
bool saved variable (using the same path built from file.path() + "/" +
exportTextureName(QString::fromStdString(tex->getName()))), and if saved is
false log an error via Ogre::LogManager::getSingleton().logError including
texture id (tex->getName()) and full path, then either mark the export as failed
(set a failure flag/return false from the surrounding export function) or throw
an exception so callers know the export did not fully succeed; keep existing
catch blocks for exceptions but ensure non-exception failures are treated the
same way.
- Around line 2368-2371: The code dereferences _sn via _sn->getName() before
checking that _sn is non-null; update the overload to first check if _sn is
nullptr (e.g., if (!_sn) return -1 or appropriate error) before calling
_sn->getName(), so the subsequent calls to
Manager::getSingleton()->getSceneMgr()->hasEntity(...) and getEntity(...) are
safe; apply this null guard at the start of the block that uses _sn to prevent
null-pointer crashes.

---

Outside diff comments:
In `@src/MeshImporterExporter.cpp`:
- Around line 2335-2353: In MeshImporterExporter::exporter add
SentryReporter::addBreadcrumb calls to track the user export flow: record a
'ui.action' breadcrumb just before showing the save dialog with a message
including the node name (use _sn->getName()), record a 'file.export' breadcrumb
if the user cancels (when fileName.isEmpty()) with a clear "export canceled"
message, and record a 'file.export' breadcrumb immediately before calling
exporter(_sn, uri, filter) indicating the export started (include the URI and
filter); use the same helper symbols already present (formatFileURI,
exportFileDialogFilter) to build messages so breadcrumbs reflect the dialog
open, cancel, and start-export events.
🪄 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: b45af125-7db4-43e4-bbf1-8ec322bc0445

📥 Commits

Reviewing files that changed from the base of the PR and between 6407313 and f9b65ad.

📒 Files selected for processing (8)
  • CMakeLists.txt
  • README.md
  • src/AnimationControlController.cpp
  • src/AnimationControlController.h
  • src/MeshImporterExporter.cpp
  • src/MeshImporterExporter.h
  • src/mainwindow.cpp
  • website/src/hooks/useQtmeshActionRef.js

Comment thread README.md Outdated
Comment thread src/AnimationControlController.cpp
Comment thread src/MeshImporterExporter.cpp Outdated
Comment thread src/MeshImporterExporter.cpp
fernandotonon and others added 2 commits May 28, 2026 03:00
* Restore the `!_sn` and `_uri.isEmpty()` early-returns in
  `MeshImporterExporter::exporter(SceneNode, uri, format, ...)`.
  They were dropped when I stripped the printf traces — Codex P1
  flagged that
  `MeshImporterExporterStandaloneTest.Exporter_NullSceneNode_ReturnMinusOne`
  exercises this exact case and would crash without the guard.
  Also re-add the `!e` guard after `getEntity`.

* `AnimationControlController::suspendPollTimer / resumePollTimer`
  now emit `SentryReporter::addBreadcrumb("ui.action", …)` instead
  of `fprintf(stderr)`. Matches CLAUDE.md guidance that user-facing
  / significant operations need structured breadcrumbs.

* `exportTextures` cleans up the texture-save block per CodeRabbit
  feedback: pulls the output path into a named local, adds a
  comment explaining why we don't bool-check `Ogre::Image::save`
  (it returns void and throws on failure; the existing
  catch-all chain already logs).

* README + sync-doc script: `image-tag: "X.Y.Z"` pins now bump
  alongside the action ref. The earlier 3.3.1 bump left the
  pinned image tags at 3.1.0; CodeRabbit caught the mismatch.
  `sync-doc-versions-from-cmake.sh` learns to update + verify
  the `image-tag` field so this can't drift again.

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

SonarCloud flagged `exportTextures` for cognitive complexity 49 > 25
(rule cpp:S3776) and nested-control-flow > 3 levels (rule cpp:S134)
because the texture export sat at the bottom of a 4-deep
`technique → pass → TUS → try` nest. Also caught the `catch(...)`
arm (rule cpp:S1181) and a separate `catch(...)` in sceneExporter
(cpp:S2738).

Refactor into three small anonymous-namespace helpers:

* `isTextureSerializable(tex)` — every null/load/size guard,
  early-returns. Replaces the inline `if (!tex) continue; if (!tex
  ->isLoaded()) ...` chain.
* `saveTextureAsImage(tex, file)` — the convertToImage + img.save
  block, with `Ogre::Exception` + `std::exception` catch arms.
  Dropped the bare `catch(...)` per Sonar — those two together
  cover every throw the export path can emit (Ogre throws Ogre::
  Exception, file-system code throws std::system_error which
  is std::exception). If anything else escapes the export
  legitimately wants to crash, which matches how the rest of the
  pipeline handles unknown exceptions.
* `forEachNamedTexture(material, fn)` — flattens the
  technique → pass → TUS triple loop into one function so the
  outer call site is a one-liner.

Same fix applied to `sceneExporter`'s catch chain — `catch(...)`
removed; the `std::exception` arm already covers everything
worth catching.

`exportTextures` is now 4 lines and has zero nesting.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@scripts/sync-doc-versions-from-cmake.sh`:
- Around line 76-82: The caller currently only invokes apply_perl_replace() for
files matching an action-ref pin (e.g., fernandotonon/QtMeshEditor@X.Y.Z), so
files that only contain image-tag: "X.Y.Z" never get their image-tag updated;
update the caller logic to also run the image-tag replacement (the block that
sets QTMESH_DOC_VERSION and invokes perl with
s/(image-tag:\s*")(\d+\.\d+\.\d+)(")/...) for files that contain an image-tag
even if they lack the action-ref pin — either by removing the action-ref-only
guard and always calling apply_perl_replace(), or by adding an additional
condition that detects /image-tag:\s*"\d+\.\d+\.\d+"/ and runs the image-tag
perl replacement (refer to apply_perl_replace and the image-tag perl
substitution block).
- Around line 55-58: The current grep regex in the imgtags extraction
(imgtags="$(grep -ohE 'image-tag:[[:space:]]*"[0-9]+\.[0-9]+\.[0-9]+"' "$f" ...
)") will match backtick-wrapped examples; change the extraction to only match
occurrences not preceded by a backtick by using a negative-lookbehind-capable
tool (e.g., replace the grep with a Perl one-liner like perl -nle 'print $& if
/(?<!`)image-tag:\s*"[0-9]+\.[0-9]+\.[0-9]+"/' "$f"') and apply the same change
to the other occurrence noted (the block around lines 76-82) so examples wrapped
in backticks are ignored.
🪄 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: ca0ead79-bcd1-4d2f-9e13-a6719f22f358

📥 Commits

Reviewing files that changed from the base of the PR and between f9b65ad and e38e8ba.

📒 Files selected for processing (4)
  • README.md
  • scripts/sync-doc-versions-from-cmake.sh
  • src/AnimationControlController.cpp
  • src/MeshImporterExporter.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.md
  • src/AnimationControlController.cpp

Comment thread scripts/sync-doc-versions-from-cmake.sh Outdated
Comment thread scripts/sync-doc-versions-from-cmake.sh
CodeRabbit review on PR #693:

* The previous regex matched `image-tag: "X.Y.Z"` regardless of
  surrounding backticks, so inline-code examples in markdown
  (`` `image-tag: "9.9.9"` ``) would get silently rewritten on
  every bump. The comment claimed they were skipped but the regex
  didn't enforce it. Added `(?<!\`)` / `(?!\`)` lookarounds to
  both the apply-side perl substitution and the verify-side
  scanner. BSD grep doesn't have lookaround support, so the
  scanner drops to perl too.

* The apply-side caller previously gated `apply_perl_replace`
  on the file containing an action-ref pin
  (`fernandotonon/QtMeshEditor@X.Y.Z`). A doc file containing
  only `image-tag: "X.Y.Z"` would never get rewritten.
  Caller now matches either pattern.

Tested with a synthetic file containing one backticked
`image-tag` (preserved) and one unbacked pin (rewritten);
`./scripts/sync-doc-versions-from-cmake.sh --check` against the
repo continues to pass.

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

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@fernandotonon fernandotonon merged commit 5d537b5 into master May 28, 2026
16 checks passed
@fernandotonon fernandotonon deleted the fix/gui-export-crashes branch May 28, 2026 19:53
@sonarqubecloud
Copy link
Copy Markdown

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