--- /home/yeff/public_html/devon/docs/index.html.loaddocsource_restore.20260329_182101	2026-03-29 18:16:02.371550263 -0300
+++ /home/yeff/public_html/devon/docs/index.html	2026-04-10 22:02:24.032902725 -0300
@@ -1,3 +1,4 @@
+<?php require_once __DIR__ . "/../auth_guard.php"; ?>
 <!DOCTYPE html>
 <html lang="en">
 <head>
@@ -75,6 +76,25 @@
         min-width:0;
     }
 
+    .sidebar,
+    .rail{
+      scrollbar-width:thin;
+      scrollbar-color:rgba(138,167,255,.22) transparent;
+    }
+    .sidebar::-webkit-scrollbar,
+    .rail::-webkit-scrollbar{
+      width:10px;
+    }
+    .sidebar::-webkit-scrollbar-track,
+    .rail::-webkit-scrollbar-track{
+      background:transparent;
+    }
+    .sidebar::-webkit-scrollbar-thumb,
+    .rail::-webkit-scrollbar-thumb{
+      background:rgba(138,167,255,.22);
+      border-radius:999px;
+    }
+
     .brand{
       display:flex;
       flex-direction:column;
@@ -404,7 +424,7 @@
 
     .workspace{
       display:grid;
-      grid-template-columns:1.12fr .88fr;
+      grid-template-columns:1.2fr .8fr;
       gap:18px;
     }
 
@@ -656,7 +676,7 @@
         <div class="hero-actions">
           <a class="btn" href="../panel/" target="_blank" rel="noopener noreferrer">Open Panel</a>
           <a class="btn" href="../panel/data/panel_manifest.json" target="_blank" rel="noopener noreferrer">Manifest JSON</a>
-          <a class="btn" href="../panel/data/devon_panel_chat_checkpoint.md" target="_blank" rel="noopener noreferrer">Checkpoint MD</a>
+          <a class="btn" href="../panel/data/devon_continuity.md" target="_blank" rel="noopener noreferrer">Continuity MD</a>
         </div>
       </header>
 
@@ -707,13 +727,14 @@
             </div>
 
             <div class="doc-shell">
+              <div id="doc-map" class="doc-map"></div>
+
               <div class="viewer-actions">
                 <button id="btn-view-architecture" class="btn" type="button">View Architecture</button>
                 <button id="btn-view-contract" class="btn" type="button">View Contract</button>
                 <button id="btn-view-source" class="btn" type="button">View Canon Source</button>
               </div>
 
-              <div id="doc-map" class="doc-map"></div>
               <pre id="doc-viewer">Select a document in the Architecture Tree.</pre>
             </div>
           </article>
@@ -745,6 +766,8 @@
               <span class="chip">read-only canon</span>
               <span class="chip">no fake status</span>
               <span class="chip">docs as architecture</span>
+              <span class="chip">doc audit only</span>
+              <span class="chip">runtime in operator panel</span>
             </div>
           </article>
         </aside>
@@ -758,6 +781,11 @@
       </section>
 
       <section class="rail-card">
+        <h3>Audit split</h3>
+        <p>Documentation Hub audits canonical definition, category coverage, authority ownership, phase and layer binding, dependencies and documentation completion gaps. Operator Panel audits real implementation state, runtime evidence, health, telemetry, pipeline execution and server-side materialization.</p>
+      </section>
+
+      <section class="rail-card">
         <h3>Legend</h3>
         <div class="legend">
           <div class="legend-row"><div class="swatch"></div><span>control and structure layers</span></div>
@@ -769,13 +797,19 @@
       </section>
 
       <section class="rail-card">
+        <h3>Documentation structural coverage</h3>
+        <p id="doc-completeness-summary">Waiting for structural coverage analysis.</p>
+        <div id="doc-completeness-list" class="mini-list"></div>
+      </section>
+
+      <section class="rail-card">
         <h3>Canonical sources</h3>
         <div class="source-grid">
           <div class="source-item">../panel/data/master_architecture_index.md</div>
           <div class="source-item">../panel/data/panel_manifest.json</div>
           <div class="source-item">../panel/data/panel_content_index.json</div>
           <div class="source-item">../panel/data/project_scope_canonical.json</div>
-          <div class="source-item">../panel/data/devon_panel_chat_checkpoint.md</div>
+          <div class="source-item">../panel/data/devon_continuity.md</div>
 
           <div class="source-item">../panel/data/cas.md</div>
           <div class="source-item">../panel/data/cgs.md</div>
@@ -834,12 +868,30 @@
 let HUB = null;
 
 async function loadHub() {
-  const res = await fetch('../panel/data/hub_index.json');
-  if (!res.ok) throw new Error('hub load fail');
-  HUB = await res.json();
+  if (HUB) return HUB;
+
+  const [hubRes, treeRes] = await Promise.all([
+    fetch('../panel/data/hub_index.json', { cache: 'no-store' }),
+    fetch('../panel/data/panel_canonical_tree.json', { cache: 'no-store' })
+  ]);
+
+  if (!hubRes.ok) throw new Error('hub load fail');
+  if (!treeRes.ok) throw new Error('canonical tree load fail');
+
+  const [hubIndex, canonicalTree] = await Promise.all([
+    hubRes.json(),
+    treeRes.json()
+  ]);
+
+  HUB = {
+    index: hubIndex,
+    tree: canonicalTree
+  };
+
+  return HUB;
 }
 
-let state = { phaseId: null, categoryId: null, docId: null, mode: "architecture" };
+let state = { phaseId: null, categoryId: null, docId: null, selectedSubcategory: null, mode: "architecture" };
 
     const treeRoot = document.getElementById("tree-root");
     const phaseStrip = document.getElementById("phase-strip");
@@ -857,37 +909,138 @@
     const docMap = document.getElementById("doc-map");
     const docViewer = document.getElementById("doc-viewer");
     const relationMap = document.getElementById("relation-map");
+    const docCompletenessSummary = document.getElementById("doc-completeness-summary");
+    const docCompletenessList = document.getElementById("doc-completeness-list");
 
     const btnViewArchitecture = document.getElementById("btn-view-architecture");
     const btnViewContract = document.getElementById("btn-view-contract");
     const btnViewSource = document.getElementById("btn-view-source");
+      function hubIndex(){
+        return HUB && HUB.index ? HUB.index : { phases: [], categories: [] };
+      }
 
-    function getCategory(categoryId){
-      return HUB.categories.find(c => c.id === categoryId);
-    }
+      function hubTree(){
+        return HUB && HUB.tree ? HUB.tree : { phases: [] };
+      }
 
-    function getDoc(categoryId, docId){
-      const category = getCategory(categoryId);
-      return category ? category.docs.find(d => d.id === docId) : null;
-    }
+      function getCategory(categoryId){
+        return (hubIndex().categories || []).find(c => c.id === categoryId) || null;
+      }
+
+      function getDoc(categoryId, docId){
+        const category = getCategory(categoryId);
+        return category ? ((category.docs || []).find(d => d.id === docId) || null) : null;
+      }
+
+      function getPhase(phaseId){
+        return (hubIndex().phases || []).find(p => p.id === phaseId) || null;
+      }
+
+      function getTreePhase(phaseId){
+        return (hubTree().phases || []).find(p => p.id === phaseId) || null;
+      }
+
+      function getTreeCategory(phaseId, categoryId){
+        const phase = getTreePhase(phaseId);
+        return phase ? ((phase.categories || []).find(c => c.id === categoryId) || null) : null;
+      }
+
+      function getSubcategories(phaseId, categoryId){
+        const category = getTreeCategory(phaseId, categoryId);
+        return category && Array.isArray(category.subcategories) ? category.subcategories : [];
+      }
+
+      function getSelectedSubcategory(){
+        const subcategories = getSubcategories(state.phaseId, state.categoryId);
+        if (!subcategories.length) return null;
+        if (state.selectedSubcategory) {
+          const hit = subcategories.find(s => s.id === state.selectedSubcategory);
+          if (hit) return hit;
+        }
+        return subcategories[0];
+      }
 
-    function getPhase(phaseId){
-      return HUB.phases.find(p => p.id === phaseId);
-    }
 
     function metricData(){
-      const totalCategories = HUB.categories.length;
-      const totalDocs = HUB.categories.reduce((acc, cat) => acc + cat.docs.length, 0);
-      const totalPhases = HUB.phases.length;
+      const totalCategories = hubIndex().categories.length;
+      const totalDocs = hubIndex().categories.reduce((acc, cat) => acc + ((cat.docs || []).length), 0);
+      const totalPhases = hubIndex().phases.length;
       const totalSources = totalDocs;
+      const categoriesWithGaps = hubIndex().categories.filter(cat => !Array.isArray(cat.docs) || !cat.docs.length).length;
       return [
         { value: totalPhases, label: "Phases", note: "macro build stages" },
         { value: totalCategories, label: "Categories", note: "navigation domains" },
         { value: totalDocs, label: "Documents", note: "canonical source set" },
-        { value: totalSources, label: "Mapped Sources", note: "doc-to-source bindings" }
+        { value: totalSources, label: "Mapped Sources", note: "doc-to-source bindings" },
+        { value: totalCategories - categoriesWithGaps, label: "Ready Categories", note: "categories with mapped docs" }
       ];
     }
 
+    function documentationCompletenessSnapshot(){
+      const categories = Array.isArray(hubIndex().categories) ? hubIndex().categories : [];
+      const phases = Array.isArray(hubIndex().phases) ? hubIndex().phases : [];
+      const docs = categories.reduce((acc, cat) => acc + (Array.isArray(cat.docs) ? cat.docs.length : 0), 0);
+
+      const categoriesWithDocs = categories.filter(cat => Array.isArray(cat.docs) && cat.docs.length > 0);
+      const missingCategoryDocs = categories.filter(cat => !Array.isArray(cat.docs) || cat.docs.length === 0);
+
+      const docsMissingPhase = [];
+      const docsMissingDepends = [];
+      const docsMissingUsedBy = [];
+
+      categories.forEach(cat => {
+        (Array.isArray(cat.docs) ? cat.docs : []).forEach(doc => {
+          if (!doc.phase) docsMissingPhase.push(doc.label || doc.id || "unnamed-doc");
+          if (!Array.isArray(doc.depends_on) || doc.depends_on.length === 0) docsMissingDepends.push(doc.label || doc.id || "unnamed-doc");
+          if (!Array.isArray(doc.used_by) || doc.used_by.length === 0) docsMissingUsedBy.push(doc.label || doc.id || "unnamed-doc");
+        });
+      });
+
+      return {
+        totalPhases: phases.length,
+        totalCategories: categories.length,
+        totalDocs: docs,
+        categoriesWithDocs: categoriesWithDocs.length,
+        missingCategoryDocs,
+        docsMissingPhase,
+        docsMissingDepends,
+        docsMissingUsedBy
+      };
+    }
+
+    function buildDocumentationCompleteness(){
+      if (!docCompletenessSummary || !docCompletenessList) return;
+
+      const snap = documentationCompletenessSnapshot();
+      const categoriesWithoutDocs = snap.missingCategoryDocs.length;
+      const docsMissingPhase = snap.docsMissingPhase.length;
+      const docsMissingDepends = snap.docsMissingDepends.length;
+      const docsMissingUsedBy = snap.docsMissingUsedBy.length;
+
+      const categoriesReady = snap.totalCategories - categoriesWithoutDocs;
+      const totalGapCount = categoriesWithoutDocs + docsMissingPhase + docsMissingDepends + docsMissingUsedBy;
+
+      docCompletenessSummary.textContent =
+        totalGapCount === 0
+          ? "Structural coverage is complete for the current Hub surface."
+          : "Structural coverage is active, but mapped gaps still exist and are listed below.";
+
+      docCompletenessList.innerHTML = "";
+
+      [
+        { title: "Covered categories", text: `${categoriesReady} / ${snap.totalCategories} categories with mapped docs.` },
+        { title: "Category gaps", text: categoriesWithoutDocs ? `${categoriesWithoutDocs} categories still have no mapped docs.` : "No category-level doc gaps detected." },
+        { title: "Phase binding gaps", text: docsMissingPhase ? `${docsMissingPhase} docs still have no explicit phase binding.` : "No phase-binding gaps detected." },
+        { title: "Dependency gaps", text: docsMissingDepends ? `${docsMissingDepends} docs still have no depends_on mapping.` : "No depends_on gaps detected." },
+        { title: "Usage gaps", text: docsMissingUsedBy ? `${docsMissingUsedBy} docs still have no used_by mapping.` : "No used_by gaps detected." }
+      ].forEach(item => {
+        const el = document.createElement("div");
+        el.className = "mini-item";
+        el.innerHTML = `<strong>${item.title}</strong><span>${item.text}</span>`;
+        docCompletenessList.appendChild(el);
+      });
+    }
+
     function buildMetrics(){
       metricGrid.innerHTML = "";
       metricData().forEach(item => {
@@ -901,10 +1054,9 @@
         metricGrid.appendChild(el);
       });
     }
-
     function buildPhases(){
       phaseStrip.innerHTML = "";
-      HUB.phases.forEach(phase => {
+      (hubIndex().phases || []).forEach(phase => {
         const btn = document.createElement("button");
         btn.type = "button";
         btn.className = "phase" + (phase.id === state.phaseId ? " active" : "");
@@ -916,68 +1068,86 @@
         btn.title = phase.summary;
         btn.addEventListener("click", () => {
           state.phaseId = phase.id;
-          const matchingCategory = HUB.categories.find(cat => cat.docs.some(doc => doc.phase === phase.id));
-          if (matchingCategory) {
-            state.categoryId = matchingCategory.id;
-            state.docId = matchingCategory.docs[0].id;
+
+          const phaseTree = getTreePhase(phase.id);
+          const firstCategory = phaseTree && Array.isArray(phaseTree.categories)
+            ? phaseTree.categories[0]
+            : null;
+
+          if (firstCategory) {
+            state.categoryId = firstCategory.id;
+            state.selectedSubcategory = null;
           }
+
+          state.docId = null;
           render();
         });
         phaseStrip.appendChild(btn);
       });
     }
-
     function buildTree(){
       treeRoot.innerHTML = "";
-      HUB.categories.forEach(cat => {
-        const node = document.createElement("div");
-        const isOpen = cat.id === state.categoryId;
-        node.className = "tree-node" + (isOpen ? " open" : "");
-
-        const head = document.createElement("div");
-        head.className = "tree-head";
-        head.innerHTML = `
+
+      (hubIndex().phases || []).forEach(phase => {
+        const phaseNode = document.createElement("div");
+        const phaseOpen = phase.id === state.phaseId;
+        phaseNode.className = "tree-node" + (phaseOpen ? " open" : "");
+
+        const phaseHead = document.createElement("div");
+        phaseHead.className = "tree-head";
+        phaseHead.innerHTML = `
           <div class="tree-head-left">
-            <div class="tree-title">${cat.title}</div>
-            <div class="tree-sub">${cat.sub}</div>
+            <div class="tree-title">${phase.name}</div>
+            <div class="tree-sub">${phase.summary || ""}</div>
           </div>
-          <span class="tree-badge">${cat.badge}</span>
+          <span class="tree-badge">${phase.badge || phase.step || ""}</span>
         `;
-        head.addEventListener("click", () => {
-          state.categoryId = cat.id;
-          const firstDoc = cat.docs[0];
-          if (firstDoc) {
-            state.docId = firstDoc.id;
-            state.phaseId = firstDoc.phase;
+        phaseHead.addEventListener("click", () => {
+          state.phaseId = phase.id;
+
+          const phaseTree = getTreePhase(phase.id);
+          const firstCategory = phaseTree && Array.isArray(phaseTree.categories)
+            ? phaseTree.categories[0]
+            : null;
+
+          if (firstCategory) {
+            state.categoryId = firstCategory.id;
+            state.selectedSubcategory = null;
           }
+
+          state.docId = null;
           render();
         });
 
-        const children = document.createElement("div");
-        children.className = "tree-children";
+        const phaseChildren = document.createElement("div");
+        phaseChildren.className = "tree-children";
 
-        cat.docs.forEach(doc => {
+        const phaseTree = getTreePhase(phase.id);
+        (phaseTree && Array.isArray(phaseTree.categories) ? phaseTree.categories : []).forEach(catTree => {
+          const catMeta = getCategory(catTree.id) || {};
           const btn = document.createElement("button");
           btn.type = "button";
-          btn.className = "tree-doc" + (doc.id === state.docId ? " active" : "");
-          btn.innerHTML = `${doc.label}<small>${doc.layer} • ${doc.type}</small>`;
+          btn.className = "tree-doc" + (catTree.id === state.categoryId ? " active" : "");
+          btn.innerHTML = `${catMeta.title || catTree.id}<small>${catMeta.sub || "category"}</small>`;
           btn.addEventListener("click", (ev) => {
             ev.stopPropagation();
-            state.categoryId = cat.id;
-            state.docId = doc.id;
-            state.phaseId = doc.phase;
+            state.phaseId = phase.id;
+            state.categoryId = catTree.id;
+            state.selectedSubcategory = null;
+            state.docId = null;
             render();
           });
-          children.appendChild(btn);
+          phaseChildren.appendChild(btn);
         });
 
-        node.appendChild(head);
-        node.appendChild(children);
-        treeRoot.appendChild(node);
+        phaseNode.appendChild(phaseHead);
+        phaseNode.appendChild(phaseChildren);
+        treeRoot.appendChild(phaseNode);
       });
     }
 
     function buildPhaseMap(){
+
       const phase = getPhase(state.phaseId);
       if (!phase) return;
 
@@ -1054,7 +1224,32 @@
         const cacheKey = doc.path;
         if (docSourceCache.has(cacheKey)) return docSourceCache.get(cacheKey);
 
-        const promise = 
+        const promise = (async () => {
+          const res = await fetch(doc.path, { cache: "no-store" });
+          if (!res.ok) throw new Error("HTTP " + res.status);
+
+          if (doc.type === "json") {
+            const data = await res.json();
+            const info = summarizeJson(data);
+            return {
+              kind: "json",
+              raw: data,
+              sourceText: JSON.stringify(data, null, 2),
+              summary: info.summary,
+              extra: info
+            };
+          }
+
+          const raw = await res.text();
+          const info = summarizeText(raw);
+          return {
+            kind: "text",
+            raw: raw,
+            sourceText: raw,
+            summary: info.summary,
+            extra: info
+          };
+        })();
 
         docSourceCache.set(cacheKey, promise);
         return promise;
@@ -1209,6 +1404,7 @@
       buildTree();
       buildPhases();
       buildMetrics();
+      buildDocumentationCompleteness();
       buildPhaseMap();
       renderDocViewer();
     }
