<!-- SOLIDABILITY-WORLD · part 21 -->
scene-container').innerHTML =
      '<div style="color:#ff6666;padding:40px;font-family:monospace">Failed to load world data: ' + err.message + '</div>';
  });
</script>
</body>
</html>


===== FILE: public/solidability-world/js/sw-diagnose.js =====
// Solidability World — Diagnostic Evidence Engine
// Architecture integrity checks, problem locator, change impact analysis.
// Evidence-driven, not speculative. Verified vs untested labeled clearly.

const SWDiagnose = (() => {
  let findings = null;
  let investigationHistory = [];

  // Run integrity checks against the loaded map
  async function runIntegrityCheck() {
    const layout = SWWorld.getLayout();
    if (!layout) return null;

    const checks = {
      timestamp: new Date().toISOString(),
      sourceIntegrity: checkSourceIntegrity(layout),
      spatialIntegrity: checkSpatialIntegrity(layout),
      interactionIntegrity: { status: 'untested', note: 'Requires live navigation test' },
    };

    findings = checks;
    logInvestigation('integrity-check', 'Ran architecture integrity check', checks);
    return checks;
  }

  function checkSourceIntegrity(layout) {
    const issues = [];
    const rooms = layout.rooms || [];

    // Every room must map to a real file
    rooms.forEach(room => {
      if (!room.filePath) {
        issues.push({ type: 'orphan', room: room.label, severity: 'medium' });
      }
    });

    // Check for duplicate route definitions (from map data)
    // This would come from server-side analysis
    return {
      status: issues.length ? 'issues-found' : 'verified',
      roomsChecked: rooms.length,
      issues,
      note: issues.length
        ? `${issues.length} rooms lack source mapping`
        : `All ${rooms.length} rooms map to real source files`,
    };
  }

  function checkSpatialIntegrity(layout) {
    const issues = [];
    const rooms = layout.rooms || [];

    // Building overlaps
    for (let i = 0; i < rooms.length; i++) {
      for (let j = i + 1; j < rooms.length; j++) {
        const a = rooms[i], b = rooms[j];
        if (Math.abs((a.position.y || 0) - (b.position.y || 0)) > 5) continue;
        const dist = Math.hypot(a.position.x - b.position.x, a.position.z - b.position.z);
        const minDist = (a.size.width + b.size.width) / 2 + 1;
        if (dist < minDist) {
          issues.push({
            type: 'overlap',
            rooms: [a.label, b.label],
            severity: 'high',
          });
          if (issues.length >= 5) break;
        }
      }
      if (issues.length >= 5) break;
    }

    return {
      status: issues.length ? 'issues-found' : 'verified',
      roomsChecked: rooms.length,
      issues: issues.slice(0, 5),
      note: issues.length
        ? `${issues.length}+ building overlaps detected`
        : `No building overlaps in ${rooms.length} rooms`,
    };
  }

  // Evidence states (per GPT-6 directive 2026-10-08)
  // Separate from severity: a HIGH severity issue can be UNTESTED
  const EVIDENCE_STATES = {
    OBSERVED:  { label: 'OBSERVED',  color: '#00ffcc', desc: 'Directly seen in source or runtime' },
    INFERRED:  { label: 'INFERRED',  color: '#ffaa44', desc: 'Deduced from patterns, not directly seen' },
    UNTESTED:  { label: 'UNTESTED',  color: '#888888', desc: 'Claimed but not verified' },
    VERIFIED:  { label: 'VERIFIED',  color: '#66ff99', desc: 'Confirmed by test or inspection' },
    DISPROVEN: { label: 'DISPROVEN', color: '#ff6666', desc: 'Tested and found false' },
    STALE:     { label: 'STALE',     color: '#666666', desc: 'Was true, may no longer apply' },
  };

  function evidenceBadge(state) {
    const s = EVIDENCE_STATES[state] || EVIDENCE_STATES.UNTESTED;
    return `<span class="evidence-badge" style="color:${s.color};border-color:${s.color}" title="${s.desc}">${s.label}</span>`;
  }

  // Problem locator with evidence states
  function locateProblem(symptom) {
    const layout = SWWorld.getLayout();
    if (!layout) return null;
    const s = symptom.toLowerCase();
    const candidates = [];

    // Pattern: slowness → high complexity files
    // Evidence: INFERRED (complexity correlates with slowness, not measured)
    if (/slow|lag|performance|freeze|hang/.test(s)) {
      const sorted = [...layout.rooms]
        .filter(r => r.complexity)
        .sort((a, b) => b.complexity - a.complexity)
        .slice(0, 5);
      sorted.forEach((room, idx) => {
        // Show path to distinguish duplicate filenames
        const displayName = room.filePath && room.filePath !== room.label
          ? `${room.label} (${room.filePath})` : room.label;
        candidates.push({
          room: displayName,
          file: room.filePath,
          evidence: `Complexity ${room.complexity} — ranked #${idx + 1} in world.`,
          evidenceState: 'INFERRED',
          evidenceNote: 'High complexity correlates with slow execution, but no runtime profiling performed.',
          key: room.key,
          // Lower priorit