Akil Fernando

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

PILLAR I

BSc in Computer Science

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

PILLAR II

Game Industry Experience

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

PILLAR III

Developer Toolchain Automation

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.

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.

godot_triage_engine.exe · Terminal Output
SYNTHETIC FIXTURE DEMO · ARCHITECTURAL PROOF
===========================================================================
    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
===========================================================================