chore(goldens): gate --deferred on RIVE_CANVAS, not scripting (#13902) ec359aee6a

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index e54968d..56f4161 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-f0c2d52b31981b709abcb03d156887638a58e5a7
+ec359aee6a0dd15454165be16cad99ddcf2ecbd1
diff --git a/tests/check_golds.sh b/tests/check_golds.sh
index e7d91a4..1d0a475 100755
--- a/tests/check_golds.sh
+++ b/tests/check_golds.sh
@@ -30,6 +30,12 @@
             TESTS="gms"
             shift
         ;;
+        --deferred)
+            # Goldens only; gms has no deferred mode. Output must match the
+            # same baseline, so no separate gold dir.
+            ARGS="$ARGS --deferred"
+            shift
+        ;;
         -u)
             TARGET="unreal"
             if [[ "$OSTYPE" == "darwin"* ]]; then
@@ -69,7 +75,7 @@
             DEFAULT_BACKEND=gl
             SERIAL="$(adb get-serialno | sed 's/[:.]/_/g')"
             if [[ "$1" == "-a32" ]]; then
-                ARGS="--android-arch arm"
+                ARGS="$ARGS --android-arch arm"
             fi
             shift
         ;;
diff --git a/tests/deploy_tests.py b/tests/deploy_tests.py
index 957130d..cdbc6d6 100644
--- a/tests/deploy_tests.py
+++ b/tests/deploy_tests.py
@@ -99,6 +99,11 @@
                     type=int,
                     default=1,
                     help="number of columns in the goldens grid")
+parser.add_argument("--deferred",
+                    action='store_true',
+                    help="record goldens through a deferred session and replay "\
+                         "synchronously; output must match immediate mode "\
+                         "(needs a --with_rive_canvas build)")
 parser.add_argument("-m", "--match",
                     type=str,
                     default=None,
@@ -662,6 +667,8 @@
                      "-p%i" % args.png_threads]
     if args.verbose:
         cmd = cmd + ["--verbose"]
+    if args.deferred:
+        cmd = cmd + ["--deferred"]
     cmd = update_cmd_to_deploy_on_target(cmd, test_harness_server, env)
 
     procs = [CheckProcess(cmd, env) for i in range(0, args.jobs_per_tool)]
diff --git a/tests/goldens/goldens.cpp b/tests/goldens/goldens.cpp
index ac8a2ba..f4a28aa 100644
--- a/tests/goldens/goldens.cpp
+++ b/tests/goldens/goldens.cpp
@@ -93,7 +93,7 @@
         const double frameDuration = duration / frames;
         const rive::AABB cellBounds = rive::AABB(0, 0, cellSize, cellSize);
 
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
         // Deferred mode records the screen and Ore through the session, then
         // replays synchronously per grid cell. The cadence mirrors the
         // immediate path below so the output must be byte identical.
@@ -252,7 +252,7 @@
     }
 
     std::vector<uint8_t> bytes(std::istreambuf_iterator<char>(stream), {});
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
     if (const char* n = goldens_getenv("RIVE_GOLDENS_BENCH"))
     {
         int iters = atoi(n);
@@ -356,6 +356,25 @@
     TestingWindow::Get()->resize(m_cellSize * s_args.cols(),
                                  m_cellSize * s_args.rows());
 
+    // A build or backend that can't record silently draws immediate, which
+    // reports a pass for a mode that never ran. Say so, like the player does.
+    if (s_args.deferred())
+    {
+#ifdef RIVE_CANVAS
+        auto* rc = TestingWindow::Get()->renderContext();
+        if (rc == nullptr || rc->getOreContext() == nullptr)
+        {
+            fprintf(stderr,
+                    "goldens: --deferred unavailable on this backend, "
+                    "drawing immediate\n");
+        }
+#else
+        fprintf(stderr,
+                "goldens: --deferred requires a RIVE_CANVAS build "
+                "(--with_rive_canvas), drawing immediate\n");
+#endif
+    }
+
     // The .rivs either stream in from the harness, or we walk them off disk.
     m_fromTestHarness = TestHarness::Instance().hasTCPConnection();
     if (m_fromTestHarness)
diff --git a/tests/goldens/goldens_bench.cpp b/tests/goldens/goldens_bench.cpp
index ff8c2fe..f8acf21 100644
--- a/tests/goldens/goldens_bench.cpp
+++ b/tests/goldens/goldens_bench.cpp
@@ -10,7 +10,7 @@
 
 #include "goldens_shared.hpp"
 
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
 
 #include <algorithm>
 #include <chrono>
@@ -724,6 +724,6 @@
     printf("=======================================================\n\n");
 }
 
-#endif // WITH_RIVE_SCRIPTING && RIVE_CANVAS
+#endif // RIVE_CANVAS
 
 #endif // TESTING
diff --git a/tests/goldens/goldens_shared.hpp b/tests/goldens/goldens_shared.hpp
index 0913fc5..0690c1c 100644
--- a/tests/goldens/goldens_shared.hpp
+++ b/tests/goldens/goldens_shared.hpp
@@ -23,7 +23,7 @@
 #include "rive/lua/scripting_vm.hpp"
 #include "rive/lua/rive_lua_libs.hpp"
 #endif
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
 // RIVE_GOLDENS_DEFER_ORE records through a DeferredOreContext and replays on
 // the real context in the same frame, single threaded.
 #include "common/testing_window_sink.hpp"
@@ -58,7 +58,7 @@
                      int windowHeight,
                      std::vector<uint8_t> pixels);
 
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
 // Goldens frames present on a white background.
 inline TestingWindowFrameSink goldensFrameSink(bool doClear = true)
 {
@@ -95,7 +95,7 @@
               DeferMode mode = DeferMode::Auto)
     {
         rive::Factory* importFactory = TestingWindow::Get()->factory();
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
         // Importing through the DeferredSession makes the artboard's own 2D
         // resources deferred objects with ids so drawInternal can record.
         bool wantDeferred =
@@ -168,7 +168,7 @@
     // Null when deferred mode is off.
     rive::cmd::DeferredSession* deferredSession() const
     {
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
         return m_session.get();
 #else
         return nullptr;
@@ -178,7 +178,7 @@
 private:
     // Destroyed last since deferred resources held by the file record their
     // destruction into the session, so it must outlive them.
-#if defined(WITH_RIVE_SCRIPTING) && defined(RIVE_CANVAS)
+#ifdef RIVE_CANVAS
     std::unique_ptr<rive::cmd::DeferredSession> m_session;
 #endif
     rive::rcp<rive::File> m_file;
diff --git a/tests/premake5.lua b/tests/premake5.lua
index c20f6d5..8bbacb9 100644
--- a/tests/premake5.lua
+++ b/tests/premake5.lua
@@ -113,6 +113,17 @@
     do
         files({ 'goldens/goldens.html' })
     end
+    -- prospero turns RuntimeTypeInfo on whenever exceptions are enabled, and it
+    -- overrides an explicit rtti('Off'). That leaves goldens the only -frtti
+    -- target in an otherwise -fno-rtti build, so the deferred render types emit
+    -- typeinfo referencing bases that librive.a never defines. AdditionalOptions
+    -- land after the toolset flag, so this wins. Every other target, host
+    -- included, already builds goldens -fno-rtti.
+    filter('system:prospero')
+    do
+        buildoptions({ '-fno-rtti' })
+    end
+    filter({})
 end
 
 -- Headless collector validation on device targets; a plain executable so it