<!-- SAGA-STAGING · part 108 -->
if(window.WORLD_REGISTRY) window.WORLD_REGISTRY.register(this.mesh, 'ai-actor');
      if(typeof say === 'function') say('AI actor ready');
    },
    start: function(){
      this.active = true;
      window.RaceManager.startRace(this.id);
      this.nextCheckpoint();
      this.run();
    },
    nextCheckpoint: function(){
      var cps = window.MapAdapter.getCheckpoints();
      var racer = window.RaceManager.racers[this.id];
      var nextIdx = racer ? racer.checkpoints.length : 0;
      if(nextIdx < cps.length){
        this.target = cps[nextIdx];
      } else {
        this.target = null;
        this.active = false;
      }
    },
    run: function(){
      var self = this;
      if(!this.active) return;
      
      var interval = setInterval(function(){
        if(!self.active || !self.target){
          clearInterval(interval);
          return;
        }
        
        // Move toward target (same physics: velocity * delta)
        var dx = self.target.x - self.pos.x;
        var dz = self.target.z - self.pos.z;
        var dist = Math.sqrt(dx*dx + dz*dz);
        
        if(dist < 1){
          // Reached, check in and get next
          window.RaceManager.checkPosition(self.id, self.pos.x, self.pos.z);
          self.nextCheckpoint();
          if(!self.target){
            clearInterval(interval);
          }
          return;
        }
        
        // Normalize and move (V219-style: speed * 0.16 per frame at 60fps)
        var vx = (dx / dist) * self.speed * 0.16;
        var vz = (dz / dist) * self.speed * 0.16;
        self.pos.x += vx;
        self.pos.z += vz;
        
        // Ground height
        self.pos.y = window.MapAdapter.getHeight(self.pos.x, self.pos.z) + 2;
        self.mesh.position.set(self.pos.x, self.pos.y, self.pos.z);
        
        // Check checkpoint
        window.RaceManager.checkPosition(self.id, self.pos.x, self.pos.z);
      }, 16); // ~60fps
    },
    stop: function(){
      this.active = false;
      if(typeof say === 'function') say('AI actor stopped');
    }
  };
  
  // Build race course after world is ready
  setTimeout(function(){
    if(typeof scene !== 'undefined' && window.location.pathname.indexOf('saga-staging') >= 0){
      window.RaceManager.init();
      window.AIActor.init();
    }
  }, 7000);
  
  // Register commands
  setTimeout(function(){
    if(typeof CODES !== 'undefined'){
      CODES['race'] = {cat:'Race', desc:'Start race (human)', fn:function(){
        window.RaceManager.startRace('human');
        // Track human position
        var trackInterval = setInterval(function(){
          if(typeof kingPos !== 'undefined'){
            window.RaceManager.checkPosition('human', kingPos.x, kingPos.z);
          }
          var r = window.RaceManager.racers['human'];
          if(r && r.finished) clearInterval(trackInterval);
        }, 100);
      }};
      CODES['airace'] = {cat:'Race', desc:'AI runs the course', fn:function(){
        window.AIActor.start();
      }};
      CODES['racestop'] = {cat:'Race', desc:'Stop AI', fn:function(){
        window.AIActor.stop();
      }};
      CODES['raceresults'] = {cat:'Race', desc:'Show results', fn:function(){
        var r = window.RaceManager.getResults();
        var out = [];
        for(var id in r){
          var racer = r[id];
          out.push(id + ': ' + racer.checkpoints.length + '/3 checkpoints' + 
            (racer.finished ? ' FINISHED in ' + racer.totalTime.toFixed(1) + 's' : ''));
        }
        if(typeof say === 'function') say(out.join(' | ') || 'No racers yet');
      }};
    }
  }, 8000);
})();

/* ===== LABORATORY — staged observable test. King's order 2026-10-07 ===== */
/* Stage 1: labtest → create + register + activate, PAUSE with cube visible */
/* Stage 2: labmove → update position */
/* Stage 3: labremove → remove + unregister + verify clean */
window.LAB = {
  cube: null,
  testId: null,
  create: function(){
    try {
      if(this.cube){ if(typeof say==='function') say('Lab: cube already exists. Use labremove first.'); return; }
      var geo = new THREE.BoxGeometry(5, 5, 5);
      var mat = new THREE.MeshStandardMaterial({color: 0x00ff00, roughness: 0.5});
      var cube = new THREE.Mesh(geo, mat);
      cube.position.set(kingPos.x + 10, 5, kingPos.z + 10);
      scene.add(cube);
      var id = window.WORLD_REGISTRY.register(cube, 'lab-test');
      this.cube = cube;
      this.testId = id;
      var count = window.WORLD_REGISTRY.countByType('lab-test');
      if(typeof say==='function') say('Lab CREATE: green cube at +10,+10. Registry id=' + id + '. Count=' + count + '. Cube is VISIBLE. Type eyeshot to capture.');
    } catch(e){ if(typeof say==='function') say('Lab CREATE failed: ' + e.message); }
  },
  move: function(){
    try {
      if(!this.cube){ if(typeof say==='function') say('Lab: no cube. Use labtest first.'); return; }
      this.cube.position.x += 10;
      this.cube.position.y = 10;
      if(typeof say===