Developer Tooling · Exploratory Prototypes
CI Diagnostics & Crash Triage Tooling
Exploratory developer tooling and pipeline experiments
Two exploratory developer tooling prototypes built to investigate common engineering bottlenecks: analyzing build phase durations and continuous integration timeouts in game pipelines, and automating stack trace normalization for engine crash triage. Both prototypes were evaluated on synthetic data fixtures to validate the processing pipelines and algorithms.
Prototype Context
These tools are proof-of-concept prototypes evaluated on synthetic data fixtures to test log parsing, stack normalization, and fault localization heuristics. They represent exploratory engineering tooling, not published academic studies.
01 / Background & Engineering Context
CS Degree · Ubisoft Game Dev · Toolchain Automation
Graduated from Dalhousie University (GPA 3.92, Sexton Scholar, Dean's List) with certificates in Cybersecurity and Web/Mobile Systems. Grounded in software architecture, algorithm design, empirical methods, and systems engineering.
- Dalhousie University
- GPA 3.92
- Sexton Scholar
- Systems Architecture
Former Gameplay Programmer at Ubisoft Halifax working on production C# and Unity pipelines, Cinemachine camera systems, and AI behavior trees. First-hand domain insight into multi-gigabyte binary asset baking, build durations, and cross-language runtime debugging.
- Ubisoft Halifax
- Unity & C#
- Asset Pipelines
- Engine Debugging
Hands-on development of automated workflows in Python and .NET 8: log parsing pipelines, stack frame normalizers, AST fault localization heuristics, and diagnostic tooling to accelerate developer triage.
- Python & .NET 8
- Log Ingestion
- AST Analysis
- CI Automation
02 / Prototype: CI Build Duration & Timeout Analyzer
Python · scikit-learn · Log Segmentation
What was built
A Python prototype for parsing unstructured continuous integration build logs, segmenting execution phases (asset cooking, shader compilation, C++ compilation, and Link-Time Optimization), and evaluating how phase durations and asset delta volumes correlate with pipeline timeouts using Random Forest regression.
Synthetic data used
Simulated build telemetry generating varying asset diff volumes, shader cache miss rates, and dependency graph depths across hundreds of mock pipeline runs to stress-test phase segmentation and model fitting.
What I was trying to learn
Whether multi-stage build logs can be segmented reliably without custom build-system hooks, and whether early-phase duration spikes (e.g., asset cooking or shader compilation) serve as dependable early-warning predictors for downstream job timeouts before long compiler links run.
What I would want real data for
Production CI telemetry from open-source game engines (like Godot) or large C++ repositories to test model accuracy against real-world runner contention, distributed cache hit variance, flaky network steps, and heterogeneous worker hardware.
- Log phase segmentation for asset baking, compilation, and linking stages.
- Feature extraction on asset delta volume and dependency graph modifications.
- Threshold-based early warning heuristics for pipeline timeouts.
03 / Prototype: Game Engine Crash Log Triage
.NET 8 (C#) · Stack Normalization · Fault Localization
What was built
A high-throughput .NET 8 CLI tool that ingests raw game engine crash logs, strips volatile dynamic memory pointers and thread identifiers, normalizes call stack frames into canonical SHA-256 cluster signatures for deduplication, and applies deterministic heuristic rules to map stack frames to recent Git commit changes.
Synthetic data used
A suite of 50 synthetic crash logs spanning 6 common game engine failure archetypes: NodePath resolution breaks after scene reparenting, null physics body states during asynchronous raycasts, shader uniform buffer binding mismatches, cross-thread object disposal race conditions during scene unload, signal emissions to deleted UI elements, and navigation waypoint array index overflows.
What I was trying to learn
How cleanly pointer-stripped normalization clusters noisy engine crashes across repeated runs, and whether simple heuristic commit mapping (matching modified methods in recent commits to top-of-stack frames) can accurately isolate the introducing change in simulated regressions.
What I would want real data for
Real issue tracker dumps and crash reports from open-source game engines (such as Godot GitHub issues) to evaluate real-world stack trace noise, inlined compiler frames, multi-threaded inter-leaved logs, and complex multi-commit regressions.
- Memory-independent stack frame normalization (stripping dynamic pointers to canonical cluster hashes).
- Automated deduplication clustering across raw crash log collections (88% reduction on test fixtures).
- Deterministic heuristic mapping from call stack frames to suspect Git commits and AST changes.
===========================================================================
EXPLORATORY GAME ENGINE CRASH LOG TRIAGE & FAULT LOCALIZATION ENGINE
Synthetic Fixture Pipeline & Stack NormalIZATION Demo
===========================================================================
[Step 1/4] Ingesting raw C# crash log fixtures (simulated game-engine failure modes)...
→ Ingested 50 synthetic crash logs with dynamic memory addresses and timestamps.
[Step 2/4] Executing memory-independent stack frame normalization & SHA-256 deduplication...
→ Formed 6 unique crash clusters from 50 raw logs.
→ Normalized dynamic pointers across all frames into canonical cluster hashes.
[Step 3/4] Running heuristic fault localization & Git commit mapping on simulated fixtures...
* [CLUSTER_01] NodePath Resolution Failure (Scene Reparenting)
- Exception : System.NullReferenceException
- Occurrences: 9 logs (18.0%)
- Suspect Commit: a3f89b1c7d... ("refactor(scene): move WeaponHolder node under CharacterRig hierarchy")
- File & Method : Source/Combat/WeaponController.cs → GameEngine.Core.Combat.WeaponController._Ready()
- Root Cause : Stale NodePath string literal in WeaponController._Ready(). Hierarchy was refactored, moving WeaponHolder under CharacterRig without updating the path constant.
* [CLUSTER_02] Null PhysicsDirectBodyState3D Reference in _PhysicsProcess
- Exception : System.NullReferenceException
- Occurrences: 9 logs (18.0%)
- Suspect Commit: c4d7e2a9b8... ("feat(physics): implement asynchronous raycast sweep for character movement")
- File & Method : Source/Physics/PlayerCharacter3D.cs → GameEngine.Core.Physics.PlayerCharacter3D._PhysicsProcess(Double delta)
- Root Cause : Missing null check on KinematicCollision3D.GetCollider(). Asynchronous raycasts and concurrent body despawns leave the collider reference null upon slide resolution.
* [CLUSTER_03] Shader Uniform Buffer Layout Binding Mismatch
- Exception : Engine.GraphicsException
- Occurrences: 8 logs (16.0%)
- Suspect Commit: f9a8b7c6d5... ("feat(rendering): add chromatic aberration and vignette compute shader")
- File & Method : Source/Rendering/CustomPostProcessPipeline.cs → GameEngine.Rendering.CustomPostProcessPipeline.CreateComputePipeline()
- Root Cause : UniformSet layout descriptor mismatch at binding index 2. Compute shader was updated to require a new uniform buffer, but UniformSetCreate was passed an outdated descriptor array.
* [CLUSTER_04] Multi-Threaded RenderingServer Race Condition on Scene Unload
- Exception : System.ObjectDisposedException
- Occurrences: 8 logs (16.0%)
- Suspect Commit: e1f2a3b4c5... ("perf(world): offload voxel chunk mesh generation to background Task workers")
- File & Method : Source/World/ChunkRenderer.cs → GameEngine.World.ChunkRenderer.AsyncMeshUpdateWorker()
- Root Cause : Cross-thread Object disposal race condition. ChunkRenderer dispatches async background Task workers that access engine pointers while the main thread frees chunks during scene unloading.
* [CLUSTER_05] Signal Emission to Disposed UI Callable Target
- Exception : Engine.SignalException
- Occurrences: 8 logs (16.0%)
- Suspect Commit: b2c3d4e5f6... ("ui(hud): recreate player health bar widget on scene respawn")
- File & Method : Source/Gameplay/HealthComponent.cs → GameEngine.Gameplay.HealthComponent.ApplyDamage(Single amount)
- Root Cause : Signal emission to a stale Callable on a disposed UI instance. HealthComponent emits HealthChanged to a widget queued for deletion without unhooking signal handlers.
* [CLUSTER_06] NavigationAgent3D Empty Path Waypoint Index Overflow
- Exception : System.IndexOutOfRangeException
- Occurrences: 8 logs (16.0%)
- Suspect Commit: d8e9f01a2b... ("ai(navigation): optimize waypoint path stepping for patrol agents")
- File & Method : Source/AI/EnemyNavigationController.cs → GameEngine.AI.EnemyNavigationController.GetNextSteeringVector()
- Root Cause : IndexOutOfRangeException in EnemyNavigationController. Path query returned an empty Vector3 array during dynamic navigation mesh rebaking, causing an unchecked index [0] access.
[Step 4/4] Exporting structured triage results to JSON artifact...
→ Structured triage results saved to: 'triage_engine_results.json'
===========================================================================
TRIAGE ENGINE EXECUTION COMPLETE
===========================================================================
Total Simulated Logs Processed : 50
Unique Crash Clusters Isolated : 6
Deduplication Normalization Rate: 88.0%
Heuristic Commit Matches : 6/6 archetypes localized
Generated Output Artifact : triage_engine_results.json
===========================================================================