<!-- HONEYCOMB-TEST · part 11 -->
: W, h: H, d: D }, design: 'open-no-walls' });
  }

  // ── PUBLIC API ──
  return {
    init,
    setupInput,
    setupTactical,
    // Set spawn: save current position, respawn here on refresh
    setSpawn: () => {
      if (!player) return;
      const pos = {
        x: player.position.x,
        y: player.position.y,
        z: player.position.z,
        camYaw, camPitch
      };
      try {
        localStorage.setItem('honeycomb-spawn', JSON.stringify(pos));
        observe('spawn.set', pos);
        return true;
      } catch(e) { return false; }
    },
    // Load spawn on init
    loadSpawn: () => {
      try {
        const s = localStorage.getItem('honeycomb-spawn');
        return s ? JSON.parse(s) : null;
      } catch(e) { return null; }
    },
    clearSpawn: () => {
      try { localStorage.removeItem('honeycomb-spawn'); } catch(e) {}
    },
    getPerformanceStats,
    buildHoneycomb,
    createHexRoom,
    addBuilding,
    checkCollision,
    getScene: () => scene,
    getPlayer: () => player,
    getCamera: () => camera,
    getBuildings: () => buildings,
    createVideoPanel,
    createControlRoom,
    getVideoPanel,
    getColliders: () => colliders
  };
})();

/* ═══════════════════════════════════════════════════════════════════
   EPISTEMOLOGY MODULE — Phase 1 Staging
   Read-only observation of 3D world. Never modifies 3D. Never breaks 3D.
   Persona of Articulation governs disposition. PostgreSQL is authoritative.
   ═══════════════════════════════════════════════════════════════════ */
const Epistemology = (function() {
  'use strict';

  const API_BASE = '/api/solidivism/epistemology';
  const CACHE_KEY = 'solidivism.epistemology.pending';
  const SESSION_ID = 'sess-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9);

  // ── In-memory runtime index (NOT authoritative) ──
  const registry = new Map();
  const ledgerCache = [];

  // ── Health (separate from 3D, diagnosable) ──
  const Health = {
    observations: { attempted: 0, succeeded: 0, failed: 0 },
    lastError: null,
    lastSuccess: null,
    recordAttempt() { this.observations.attempted++; },
    recordSuccess() {
      this.observations.succeeded++;
      this.lastSuccess = new Date().toISOString();
    },
    recordFailure(err) {
      this.observations.failed++;
      this.lastError = { time: new Date().toISOString(), message: String(err && err.message || err) };
    },
    report() {
      return {
        observations: Object.assign({}, this.observations),
        lastError: this.lastError,
        lastSuccess: this.lastSuccess,
        pendingSync: getPendingCount(),
        session: SESSION_ID
      };
    }
  };

  // ── Local cache (write buffer ONLY, not authoritative) ──
  function getPending() {
    try {
      return JSON.parse(localStorage.getItem(CACHE_KEY) || '[]');
    } catch (e) { return []; }
  }
  function getPendingCount() { return getPending().length; }
  function addToPending(event) {
    try {
      const pending = getPending();
      pending.push(event);
      // Circular buffer: keep most recent 5000
      while (pending.length > 5000) pending.shift();
      localStorage.setItem(CACHE_KEY, JSON.stringify(pending));
    } catch (e) {
      Health.recordFailure(new Error('localStorage full or unavailable'));
    }
  }

  // ── Event recording ──
  function recordEvent(action, data) {
    data = data || {};
    const event = {
      idempotency_key: 'evt-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9),
      event_time: new Date().toISOString(),
      actor_id: data.actor || 'solidivism:agent:solid:v1',
      action: action,
      target_id: data.target || null,
      inquiry: data.inquiry || {},
      confidence: data.confidence || 'medium',
      gaps: data.gaps || [],
      session_id: SESSION_ID,
      source: 'browser',
      checksum: 'pending-server'  // computed server-side
    };
    // Add to local cache immediately
    addToPending(event);
    // Attempt sync (non-blocking)
    syncToServer();
    return event;
  }

  // ── Server sync ──
  let syncInFlight = false;
  function syncToServer() {
    if (syncInFlight) return;
    const pending = getPending();
    if (!pending.length) return;
    syncInFlight = true;
    fetch(API_BASE + '/events', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ events: pending })
    }).then(function(res) {
      if (!res.ok) throw new Error('HTTP ' + res.status);
      return res.json();
    }).then(function(data) {
      // Remove accepted events from cache
      const accepted = new Set(data.accepted || []);
      const remaining = getPending().filter(function(e) {
        return !accepted.has(e.idempotency_key);
      });
      try { localStorage.setItem(CACHE_KEY, JSON.stringify(remaining)); } catch (e) {}
      syncInFlight = false;
    }).catch(function(err) {
      Health.recordFailure(err);
      syncInFlight = false;
      