. making layouts indpenedent general structure cleanup
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 26 Jun 2026 11:21:03 +0000 (11:21 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 26 Jun 2026 11:21:03 +0000 (11:21 +0000)
14 files changed:
developer/authored/Manuscript.copy/Core/document_loaded.js [new file with mode: 0644]
developer/authored/Manuscript.copy/Core/loader.js
developer/authored/Manuscript.copy/Core/utility.js [deleted file]
developer/authored/Manuscript.copy/Document/manual.html
developer/authored/Manuscript.copy/Layout/article_tech_ref.js
developer/authored/Manuscript.copy/Theme/dark_gold.js [deleted file]
developer/authored/Manuscript.copy/Theme/golden_wheat.js [new file with mode: 0644]
developer/authored/Manuscript.copy/Theme/inverse_wheat.js [new file with mode: 0644]
developer/authored/Manuscript.copy/Theme/light.js [deleted file]
developer/authored/Manuscript.copy/Theme/light_gold.js [deleted file]
developer/authored/Manuscript.copy/Theme/wheat.js [new file with mode: 0644]
document/introduction_Harmony.html
document/role-and-workflow_product-development.html
document/role-and-workflow_product-maintenance.html

diff --git a/developer/authored/Manuscript.copy/Core/document_loaded.js b/developer/authored/Manuscript.copy/Core/document_loaded.js
new file mode 100644 (file)
index 0000000..e12641d
--- /dev/null
@@ -0,0 +1,24 @@
+window.RT = window.RT || {};
+
+window.RT.document_loaded = function(layout_callback) {
+  const debug = window.RT.debug || { log: function(){} };
+  debug.log('lifecycle', 'Processing registered elements.');
+
+  if (window.RT.theme) {
+    window.RT.theme();
+  }
+  
+  if (window.RT.Element && Array.isArray(window.RT.Element)) {
+    window.RT.Element.forEach(function(element_fn) {
+      if (typeof element_fn === 'function') {
+        element_fn();
+      }
+    });
+  }
+
+  if (window.MathJax && MathJax.Hub && MathJax.Hub.Queue) {
+    MathJax.Hub.Queue(["Typeset", MathJax.Hub], layout_callback);
+  } else {
+    layout_callback();
+  }
+};
index 83a420b..171e6d3 100644 (file)
-window.RT = window.RT || {};
+// Core/loader.js
 
-// 1. Establish the module registry
-window.RT._loaded_modules = window.RT._loaded_modules || new Set();
+window.RT = window.RT || {};
+window.RT.Element = [];
+window.RT.Module = window.RT.Module || new Set();
 
-window.RT.load = function(module_path){
-  let target_module = module_path;
+// 1. Establish the Generic Theme Dictionary
+//  e.g. RT.theme( 'read', 'content_main')
+window.RT.theme = (function() {
+  const dictionary = {
+    meta: { 
+      is_dark: false, 
+      name: "" 
+    },
+    surface: { 
+      0: "", 1: "", 2: "", 3: "", 
+      input: "", code: "", select: "" 
+    },
+    content: { 
+      main: "", muted: "", subtle: "", inverse: "" 
+    },
+    brand: { 
+      primary: "", secondary: "", tertiary: "", link: "" 
+    },
+    border: { 
+      faint: "", regular: "", strong: "" 
+    },
+    state: { 
+      success: "", warning: "", error: "", info: "" 
+    },
+    syntax: { 
+      keyword: "", string: "", func: "", comment: "" 
+    },
+    page: { 
+      width: "", min_height: "", padding: "", margin: "", 
+      bg_color: "", border_color: "", text_color: "", shadow: "" 
+    }
+  };
 
-  // Strict enforcement of the PascalCase namespace
-  if (target_module === 'Theme') {
-    let saved_theme = localStorage.getItem('RT·theme_preference');
-    if (!saved_theme) {
-      saved_theme = 'dark_gold';
-      localStorage.setItem('RT·theme_preference', saved_theme);
+  function resolve_path(path_array) {
+    let current = dictionary;
+    for (let i = 0; i < path_array.length - 1; i++) {
+      const step = path_array[i];
+      if (current[step] === undefined) return null;
+      current = current[step];
     }
-    target_module = 'Theme/' + saved_theme;
+    return { container: current, key: path_array[path_array.length - 1] };
   }
 
-  // 2. The Idempotency Check: Abort if already loaded
-  if (window.RT._loaded_modules.has(target_module)) {
-    return; 
+  function check_completion(obj, path_string) {
+    for (const key in obj) {
+      if (typeof obj[key] === 'object' && obj[key] !== null) {
+        if (!check_completion(obj[key], path_string + key + '.')) {
+          return false;
+        }
+      } else {
+        if (obj[key] === "") {
+          window.RT.debug.error('theme', 'is_defined check failed at missing key: ' + path_string + key);
+          return false;
+        }
+      }
+    }
+    return true;
   }
+
+  return function(command, ...args) {
+
+    // e.g. RT.theme('read','page','width')
+    if (command === 'read') {
+      const target = resolve_path(args);
+      if (target && target.container.hasOwnProperty(target.key)) {
+        return target.container[target.key];
+      }
+      window.RT.debug.error('theme', 'Read attempt on unknown path: ' + args.join('.'));
+      return null;
+    } 
+    
+    if (command === 'write') {
+      if (args.length < 2) {
+        window.RT.debug.error('theme', 'Write command expects a path and a value.');
+        return;
+      }
+      const value = args.pop();
+      const target = resolve_path(args);
+      
+      if (target && target.container.hasOwnProperty(target.key)) {
+        target.container[target.key] = value;
+      } else {
+        window.RT.debug.error('theme', 'Write attempt on unknown path rejected: ' + args.join('.'));
+      }
+      return;
+    }
+
+    if (command === 'is_defined') {
+      if (args.length === 0) {
+        return check_completion(dictionary, '');
+      }
+      
+      for (let i = 0; i < args.length; i++) {
+        const path_array = args[i];
+        if (!Array.isArray(path_array)) {
+           window.RT.debug.error('theme', 'is_defined arguments must be path arrays. Received: ' + path_array);
+           return false;
+        }
+        const target = resolve_path(path_array);
+        if (!target || !target.container.hasOwnProperty(target.key) || target.container[target.key] === "") {
+           window.RT.debug.error('theme', 'is_defined check failed at: ' + path_array.join('.'));
+           return false;
+        }
+      }
+      return true;
+    }
+    
+    window.RT.debug.error('theme', 'Invalid command passed to theme dictionary: ' + command);
+  };
+})();
+
+
+// 2. Establish the Debug System
+window.RT.debug = {
+  active_tokens: new Set([
+    'scroll'
+  ]),
+
+  log: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.log(`[RT:${token}]`, message);
+    }
+  },
+
+  warn: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.warn(`[RT:${token}]`, message);
+    }
+  },
   
-  // 3. Register the module
-  window.RT._loaded_modules.add(target_module);
+  error: function(token, message) {
+    console.error(`[RT:${token}] CRITICAL:`, message);
+  },
+  
+  enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); },
+  disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); }
+};
+
+// 3. Establish the Utilities
+window.RT.utility = {
 
-  let resolved_path = window.RT.dirpr_library + '/' + target_module;
+  string: {
+    to_roman: function(num) {
+      if (num < 1) return num.toString();
+      const lookup = {M:1000, CM:900, D:500, CD:400, C:100, XC:90, L:50, XL:40, X:10, IX:9, V:5, IV:4, I:1};
+      let roman = '';
+      for (let i in lookup) {
+        while (num >= lookup[i]) {
+          roman += i;
+          num -= lookup[i];
+        }
+      }
+      return roman;
+    },
+
+    strip_common_indent: function(text, tag_indent = '') {
+      const raw_lines = text.split('\n');
+      const content_lines = raw_lines.filter(line => line.trim().length > 0);
+      let common_indent = '';
+
+      if (content_lines.length > 0) {
+        const first_match = content_lines[0].match(/^\s*/);
+        common_indent = first_match ? first_match[0] : '';
+
+        for (let i = 1; i < content_lines.length; i++) {
+          const line = content_lines[i];
+          let j = 0;
+          while (j < common_indent.length && j < line.length && common_indent[j] === line[j]) {
+            j++;
+          }
+          common_indent = common_indent.substring(0, j);
+          if (common_indent.length === 0) break;
+        }
+      }
+
+      let final_string = '';
+      if (common_indent.length > 0 && common_indent.startsWith(tag_indent)) {
+         const cleaned_lines = raw_lines.map(line => {
+            return line.startsWith(common_indent) ? line.replace(common_indent, '') : line;
+         });
+         
+         if (cleaned_lines.length > 0 && cleaned_lines[0].length === 0) {
+           cleaned_lines.shift();
+         }
+         if (cleaned_lines.length > 0 && cleaned_lines[cleaned_lines.length - 1].trim().length === 0) {
+            cleaned_lines.pop();
+         }
+         final_string = cleaned_lines.join('\n');
+      } else {
+         final_string = text.trim();
+      }
+
+      return final_string;
+    }
+  },
+
+  dom: {
+    measure_outer_height: function(el) {
+      const wasInDOM = el.parentNode !== null;
+      if (!wasInDOM) document.body.appendChild(el);
+      const rect = el.getBoundingClientRect();
+      const style = window.getComputedStyle(el);
+      const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+      if (!wasInDOM) el.remove();
+      return (rect.height || 0) + (margin || 0);
+    },
+
+    is_block_content: function(element) {
+      return element.textContent.trim().includes('\n');
+    }
+  },
+
+  font: {
+    measure_ink_ratio: function(target_font, ref_font = null) {
+      const debug = window.RT.debug;
+      debug.log('layout', `Measuring ink ratio for ${target_font}`);
+
+      const canvas = document.createElement('canvas');
+      const ctx = canvas.getContext('2d');
+
+      if (!ref_font) {
+        const bodyStyle = window.getComputedStyle(document.body);
+        ref_font = bodyStyle.fontFamily;
+      }
+
+      const get_metrics = (font) => {
+        ctx.font = '100px ' + font; 
+        const metrics = ctx.measureText('M');
+        return {
+          ascent: metrics.actualBoundingBoxAscent, 
+          descent: metrics.actualBoundingBoxDescent 
+        };
+      };
+
+      const ref_m = get_metrics(ref_font);
+      const target_m = get_metrics(target_font);
+      
+      const ratio = ref_m.ascent / target_m.ascent;
+
+      return { 
+        ratio: ratio,
+        baseline_diff: ref_m.descent - target_m.descent 
+      };
+    }
+  },
+
+  color: {
+    extract_l: function(color_string) {
+      const str = String(color_string).trim();
+      
+      if (!str.startsWith('oklch')) {
+        console.error(`[RT:color] Invalid format: Expected oklch color string, received '${str}'`);
+        return 0; 
+      }
+
+      const match = str.match(/oklch\(\s*([\d.]+%?)/);
+      if (!match) {
+        console.error(`[RT:color] Parsing error: Could not extract lightness from '${str}'`);
+        return 0;
+      }
+
+      const l_value = match[1];
+      return l_value.includes('%') ? parseFloat(l_value) / 100 : parseFloat(l_value);
+    },
+
+    is_high_contrast: function(bg_color, text_color) {
+      const bg_l = this.extract_l(bg_color);
+      const text_l = this.extract_l(text_color);
+      return Math.abs(text_l - bg_l) >= 0.7;
+    },
+
+    is_readable: function(bg_color, text_color) {
+      const bg_l = this.extract_l(bg_color);
+      const text_l = this.extract_l(text_color);
+      return Math.abs(text_l - bg_l) >= 0.5;
+    },
+    
+    is_light: function(color_string) {
+      return this.extract_l(color_string) > 0.75;
+    },
+
+    is_gray: function(color_string) {
+      const l = this.extract_l(color_string);
+      return l >= 0.25 && l <= 0.75;
+    },
+
+    is_dark: function(color_string) {
+      return this.extract_l(color_string) < 0.25;
+    }
+  }
+
+};
+
+window.RT.load = function(module_path) {
+  if (window.RT.Module.has(module_path)) {
+    return;
+  }
+  window.RT.Module.add(module_path);
 
+  let resolved_path = window.RT.dirpr_library + '/' + module_path;
   if (!resolved_path.endsWith('.js')) {
     resolved_path = resolved_path + '.js';
   }
diff --git a/developer/authored/Manuscript.copy/Core/utility.js b/developer/authored/Manuscript.copy/Core/utility.js
deleted file mode 100644 (file)
index 87a452f..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-  General utilities for the RT Style library.
-*/
-
-window.RT = window.RT || {};
-
-// --- DEBUG SYSTEM ---
-window.RT.debug = {
-
-  // all debug messages enabled
-/*
-  active_tokens: new Set([
-    'style', 'layout', 'pagination'
-    ,'selector', 'config', 'error'
-    ,'term'
-    ,'scroll'
-  ]),
-
-  active_tokens: new Set([
-    'term'
-  ]),
-*/  
-
-  active_tokens: new Set([
-    'scroll'
-  ]),
-
-  log: function(token, message) {
-    if (this.active_tokens.has(token)) {
-      console.log(`[RT:${token}]`, message);
-    }
-  },
-
-  warn: function(token, message) {
-    if (this.active_tokens.has(token)) {
-      console.warn(`[RT:${token}]`, message);
-    }
-  },
-  
-  error: function(token, message) {
-    console.error(`[RT:${token}] CRITICAL:`, message);
-  },
-  
-  enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); },
-  disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); }
-};
-
-// --- UTILITIES ---
-window.RT.utility = {
-  // --- FONT PHYSICS ---
-  measure_ink_ratio: function(target_font, ref_font = null) {
-    const debug = window.RT.debug;
-    debug.log('layout', `Measuring ink ratio for ${target_font}`);
-
-    const canvas = document.createElement('canvas');
-    const ctx = canvas.getContext('2d');
-
-    if (!ref_font) {
-      const bodyStyle = window.getComputedStyle(document.body);
-      ref_font = bodyStyle.fontFamily;
-    }
-
-    const get_metrics = (font) => {
-      ctx.font = '100px ' + font; 
-      const metrics = ctx.measureText('M');
-      return {
-        ascent: metrics.actualBoundingBoxAscent, 
-        descent: metrics.actualBoundingBoxDescent 
-      };
-    };
-
-    const ref_m = get_metrics(ref_font);
-    const target_m = get_metrics(target_font);
-    
-    const ratio = ref_m.ascent / target_m.ascent;
-
-    return { 
-      ratio: ratio,
-      baseline_diff: ref_m.descent - target_m.descent 
-    };
-  },
-
-  // --- COLOR PHYSICS ---
-  is_color_light: function(color_string) {
-    // 1. HSL Check
-    if (color_string.startsWith('hsl')) {
-      const numbers = color_string.match(/\d+/g);
-      if (numbers && numbers.length >= 3) {
-        const lightness = parseInt(numbers[2]);
-        return lightness > 50;
-      }
-    }
-
-    // 2. RGB Check
-    const rgb = color_string.match(/\d+/g);
-    if (!rgb) {
-      return true; 
-    }
-
-    const r = parseInt(rgb[0]);
-    const g = parseInt(rgb[1]);
-    const b = parseInt(rgb[2]);
-    const luma = (r * 299 + g * 587 + b * 114) / 1000;
-    return luma > 128;
-  },
-
-  is_block_content: function(element) {
-    return element.textContent.trim().includes('\n');
-  }
-};
index 0e34504..9545d07 100644 (file)
@@ -8,14 +8,7 @@
     <script>
       window.RT.load('Layout/article_tech_ref');
     </script>
-    <style>
-      /* Minor inline styling to improve manual readability */
-      table { width: 100%; margin-bottom: 2rem; border-collapse: collapse; }
-      th, td { padding: 0.75rem; border-bottom: 1px solid var(--RT·surface-3); vertical-align: top; }
-      th { text-align: left; color: var(--RT·brand-secondary); }
-      .attr-list { margin-top: 0.5rem; font-size: 0.9em; color: var(--RT·content-muted); }
-      .attr-list code { color: var(--RT·content-main); }
-    </style>
+
   </head>
   <body>
     <RT·theme-selector></RT·theme-selector>
index 2bd381d..ffc9420 100644 (file)
@@ -2,20 +2,14 @@
   const RT = window.RT = window.RT || {};
   const debug = RT.debug || { log: function(){} };
 
-  // --- Shared State ---
   let target_y = 0;
   let is_reload = false;
   let is_layout_locked = true;
   let scroll_timer;
 
-  // ==========================================
-  // FUNCTION DEFINITIONS
-  // ==========================================
-
   function configure_history(){
     if ('scrollRestoration' in history) {
       history.scrollRestoration = 'manual';
-      debug.log('scroll' ,"2. history.scrollRestoration set to manual.");
     }
   }
 
         is_reload = (performance.navigation.type === 1);
       }
     }
-    debug.log('scroll' ,`3. Target Y: ${target_y} | Is Reload: ${is_reload}`);
   }
 
   function load_elements(){
-    debug.log('scroll' ,"4. Loading module dependencies.");
+    // The specific elements requested by the layout
     RT.load('Element/counter');
     RT.load('Element/chapter');
     RT.load('Element/endnote');
@@ -67,8 +60,8 @@
   }
 
   function apply_style(){
-    debug.log('scroll' ,"5. Applying typography styles.");
-    
+    // Note: This will be updated to read from window.RT.theme('read', ...) 
+    // in the next iteration.
     RT.config = RT.config || {};
     RT.config.article = {
       font_family: "'Noto Sans JP', Arial, sans-serif"
       ,max_width: "46.875rem" 
       ,margin: "0 auto"
     };
-
+    
     if( RT.config.theme && RT.config.theme.meta_is_dark === false ){
       RT.config.article.font_weight = "600";
     }
 
-    window.RT = window.RT || {};
-    window.RT.config = window.RT.config || {};
     window.RT.config.page = window.RT.config.page || {};
     window.RT.config.page.height_limit = 900; 
 
     const conf = RT.config.article;
 
-apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important" });
-
+    apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important" });
     apply_style_rule('RT·article', {
       display: "block",
       fontFamily: conf.font_family,
@@ -104,10 +94,9 @@ apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important"
       color: RT.config.theme.content_main,
       boxSizing: "border-box !important"
     });
-
+    
     apply_style_rule('RT·article:not(:has(RT·page))' ,{ padding: "3rem !important" });
     apply_style_rule('RT·article:has(RT·page)' ,{ padding: "0 !important" });
-
     apply_style_rule('RT·article RT·page' ,{
       position: "relative",
       display: "block",
@@ -127,45 +116,13 @@ apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important"
     apply_style_rule('RT·article img' ,{ maxWidth: "100%", height: "auto", display: "block", margin: "1.5rem auto" });
   }
 
-  function process_custom_elements(){
-    debug.log('scroll' ,`7. Processing custom elements.`);
-    
-    if(RT.theme) RT.theme();     
-    if(RT.endnote) RT.endnote();
-    
-    if(RT.Counter.parse_and_count){
-      RT.Counter.parse_and_count(document.body);
-      if(RT.Counter.read) RT.Counter.read(document.body);
-    }
-    
-    if(RT.title) RT.title(); 
-    if(RT.term) RT.term();
-    if(RT.math) RT.math();
-    if(RT.code) RT.code();
-    if(RT.symbol) RT.symbol();
-    if(RT.constraint) RT.constraint();
-    if(RT.crossref) RT.crossref();
-
-    if( window.MathJax && MathJax.Hub && MathJax.Hub.Queue ){
-      MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,execute_pagination_and_scroll );
-    }else{
-      execute_pagination_and_scroll();
-    }
-  }
-
   function execute_pagination_and_scroll(){
     debug.log('scroll' ,`8. Pagination layout starting.`);
-
-    if(RT.chapter) RT.chapter();
-    if(RT.TOC) RT.TOC();
     if(RT.paginate_by_element) RT.paginate_by_element();
     if(RT.page) RT.page();
     
-    debug.log('scroll' ,`9. Pagination complete.`);
-
     let final_target = target_y;
     let use_hash = false;
-
     if (window.location.hash && !is_reload) {
         const hash_target = document.getElementById(window.location.hash.substring(1));
         if (hash_target) {
@@ -173,13 +130,11 @@ apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important"
         }
     }
 
-    debug.log('scroll' ,`10. Commencing viewport enforce loop. Mode: ${use_hash ? 'HASH' : 'Y-COORDINATE'}`);
     enforce_scroll(final_target ,use_hash ,0);
   }
 
   function enforce_scroll(target ,use_hash ,attempts){
     if (attempts > 15) {
-      debug.log('scroll' ,"11. Scroll enforcement timed out. Unlocking.");
       unlock_layout();
       return;
     }
@@ -194,12 +149,9 @@ apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important"
     }
 
     let is_successful = use_hash ? true : (Math.abs(window.scrollY - target) < 5 || target === 0);
-
     if (is_successful && document.body.scrollHeight > 1000) { 
-       debug.log('scroll' ,`12. Viewport anchored successfully.`);
        setTimeout(() => {
          if (!use_hash && Math.abs(window.scrollY - target) >= 5) {
-             debug.log('scroll' ,`12a. Browser late-stage rebellion detected. Re-enforcing.`);
              enforce_scroll(target ,use_hash ,attempts + 1);
          } else {
              unlock_layout();
@@ -213,43 +165,37 @@ apply_style_rule('body, html, RT·article' ,{ overflowAnchor: "none !important"
   function unlock_layout(){
     if (!is_layout_locked) return;
     is_layout_locked = false;
-    debug.log('scroll' ,"13. Layout fully unlocked. Emitting completion signal.");
     document.dispatchEvent(new Event("RT_layout_complete"));
   }
 
   function bind_window_events(){
-    debug.log('scroll' ,"6. Binding passive lifecycle events.");
-
     window.addEventListener('scroll' ,() => {
       if (is_layout_locked) return;
       clearTimeout(scroll_timer);
       scroll_timer = setTimeout(() => {
         sessionStorage.setItem('RT_saved_y' ,window.scrollY);
-        debug.log('scroll' ,`X. User stopped scrolling. Saved Y: ${window.scrollY}`);
       }, 200);
     }, { passive: true });
-
+    
     window.addEventListener('beforeunload' ,() => {
       is_layout_locked = true;
-      debug.log('scroll' ,"Y. Page unloading. Scroll listener locked.");
     });
   }
 
-  // ==========================================
-  // THE EXECUTION OUTLINE
-  // ==========================================
-  debug.log('scroll' ,"1. Initializing script.");
-  
-  // Synchronous tasks (execute immediately while head parses)
+  // Execution Outline
   configure_history();
   capture_scroll_target();
   load_elements();
   bind_window_events();
-
-  // Asynchronous tasks (wait for body elements to exist)
+  
   document.addEventListener('DOMContentLoaded', () => {
-    process_custom_elements(); // 1. Build the final DOM structure
-    apply_style();             // 2. Paint the assembled structure
+    apply_style();             
+    
+    if (window.RT.document_loaded) {
+      window.RT.document_loaded(execute_pagination_and_scroll);
+    } else {
+      execute_pagination_and_scroll();
+    }
   });
 
 })();
diff --git a/developer/authored/Manuscript.copy/Theme/dark_gold.js b/developer/authored/Manuscript.copy/Theme/dark_gold.js
deleted file mode 100644 (file)
index 9550a98..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-  Theme: Inverse Wheat (Dark)
-  Standard: Theme 1.0
-  Description: High contrast Amber on Deep Charcoal.
-*/
-( function(){
-  const RT = window.RT = window.RT || {};
-  
-  RT.theme = function(){
-    RT.config = RT.config || {};
-    
-    // THEME 1.0 DATA CONTRACT
-    RT.config.theme = {
-       meta_is_dark: true
-      ,meta_name:    "Inverse Wheat"
-
-      // --- SURFACES (Depth & Container Hierarchy) ---
-      ,surface_0:       "hsl(0, 0%, 5%)"      // App Background (Deepest)
-      ,surface_1:       "hsl(0, 0%, 10%)"     // Sidebar / Nav / Panels
-      ,surface_2:       "hsl(0, 0%, 14%)"     // Cards / Floating Elements
-      ,surface_3:       "hsl(0, 0%, 18%)"     // Modals / Dropdowns / Popovers
-      ,surface_input:   "hsl(0, 0%, 12%)"     // Form Inputs
-      ,surface_code:    "hsl(0, 0%, 11%)"     // Code Block Background
-      ,surface_select:  "hsl(45, 100%, 15%)"  // Text Selection Highlight
-
-      // --- CONTENT (Text & Icons) ---
-      ,content_main:    "hsl(50, 60%, 85%)"   // Primary Reading Text
-      ,content_muted:   "hsl(36, 15%, 60%)"   // Metadata, subtitles
-      ,content_subtle:  "hsl(36, 10%, 40%)"   // Placeholders, disabled states
-      ,content_inverse: "hsl(0, 0%, 5%)"      // Text on high-contrast buttons
-
-      // --- BRAND & ACTION (The "Wheat" Identity) ---
-      ,brand_primary:   "hsl(45, 100%, 50%)"  // Main Action / H1 / Focus Ring
-      ,brand_secondary: "hsl(38, 90%, 65%)"   // Secondary Buttons / H2
-      ,brand_tertiary:  "hsl(30, 60%, 70%)"   // Accents / H3
-      ,brand_link:      "hsl(48, 100%, 50%)"  // Hyperlinks (High Visibility)
-
-      // --- BORDERS & DIVIDERS ---
-      ,border_faint:    "hsl(36, 20%, 15%)"   // Subtle separation
-      ,border_default:  "hsl(36, 20%, 25%)"   // Standard Card Borders
-      ,border_strong:   "hsl(36, 20%, 40%)"   // Active states / Inputs
-
-      // --- STATE & FEEDBACK (Earth Tones) ---
-      ,state_success:   "hsl(100, 50%, 45%)"  // Olive Green
-      ,state_warning:   "hsl(35, 90%, 55%)"   // Burnt Orange
-      ,state_error:     "hsl(0, 60%, 55%)"    // Brick Red
-      ,state_info:      "hsl(200, 40%, 55%)"  // Slate Blue
-
-      // --- SYNTAX HIGHLIGHTING (For Code) ---
-      ,syntax_keyword:  "hsl(35, 100%, 65%)"  // Orange
-      ,syntax_string:   "hsl(75, 50%, 60%)"   // Sage Green
-      ,syntax_func:     "hsl(45, 90%, 70%)"   // Light Gold
-      ,syntax_comment:  "hsl(36, 15%, 45%)"   // Brown/Gray
-    };
-
-    // --- APPLY THEME ---
-    const palette = RT.config.theme;
-    const body = document.body;
-    const html = document.documentElement;
-
-    // 1. Paint Base
-    html.style.backgroundColor = palette.surface_0;
-    body.style.backgroundColor = palette.surface_0;
-    body.style.color = palette.content_main;
-
-    // 2. Export Variables (Standardization)
-    const s = body.style;
-    for (const [key, value] of Object.entries(palette)) {
-      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
-    }
-    
-
-    // 3. Global Overrides
-    const style_id = 'rt-global-overrides';
-    if (!document.getElementById(style_id)) {
-      const style = document.createElement('style');
-      style.id = style_id;
-      style.textContent = `
-        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
-        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
-        
-        ::-webkit-scrollbar { width: 12px; }
-        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
-        ::-webkit-scrollbar-thumb { 
-           background: var(--rt-border-default); 
-           border: 2px solid var(--rt-surface-0);
-           border-radius: 8px; 
-        }
-        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
-
-        /* --- Citation & Endnote Styling --- */
-        rt-cite a, .rt-inline-cite a, rt-endnotes a {
-          color: var(--rt-brand-link);
-          text-decoration: none;
-        }
-        rt-cite a:hover, .rt-inline-cite a:hover, rt-endnotes a:hover {
-          text-decoration: underline;
-        }
-        rt-cite, .rt-inline-cite {
-          font-size: 1em;
-          vertical-align: baseline;
-          padding: 0 0.15em;
-        }
-
-        /* --- Image Inversion for Diagrams --- */
-        img.rt-diagram {
-          filter: invert(1) hue-rotate(180deg);
-        }
-      `;
-
-      document.head.appendChild(style);
-    }
-  };
-  
-} )();
diff --git a/developer/authored/Manuscript.copy/Theme/golden_wheat.js b/developer/authored/Manuscript.copy/Theme/golden_wheat.js
new file mode 100644 (file)
index 0000000..acc509f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  Theme: Golden Wheat (Light) - "Spanish Gold Edition"
+  Standard: Theme 1.0
+  Description: Light Parchment background with Oxblood Red ink.
+*/
+(function(){
+  const RT = window.RT = window.RT || {};
+  
+  RT.theme = function(){
+    const dictionary = {
+       meta_is_dark: false
+      ,meta_name:    "Golden Wheat (Yellow)"
+
+      // --- SURFACES ---
+      ,surface_0:       "oklch(0.95 0.02 90)"
+      ,surface_1:       "oklch(0.92 0.02 90)"
+      ,surface_2:       "oklch(0.97 0.01 90)"
+      ,surface_3:       "oklch(0.99 0 0)"
+      ,surface_input:   "oklch(0.94 0.01 90)"
+      ,surface_code:    "oklch(0.90 0.02 90)"
+      ,surface_select:  "oklch(0.85 0.05 25)"
+
+      // --- CONTENT ---
+      ,content_main:    "oklch(0.20 0.02 25)"
+      ,content_muted:   "oklch(0.35 0.03 25)"
+      ,content_subtle:  "oklch(0.55 0.02 25)"
+      ,content_inverse: "oklch(0.92 0.02 90)"
+
+      // --- BRAND & ACTION ---
+      ,brand_primary:   "oklch(0.40 0.15 25)"
+      ,brand_secondary: "oklch(0.45 0.14 25)"
+      ,brand_tertiary:  "oklch(0.50 0.12 25)"
+      ,brand_link:      "oklch(0.40 0.16 25)"
+
+      // --- BORDERS ---
+      ,border_faint:    "oklch(0.85 0.02 90)"
+      ,border_default:  "oklch(0.75 0.03 90)"
+      ,border_strong:   "oklch(0.50 0.08 25)"
+
+      // --- STATE & FEEDBACK ---
+      ,state_success:   "oklch(0.45 0.10 130)"
+      ,state_warning:   "oklch(0.55 0.15 45)"
+      ,state_error:     "oklch(0.45 0.15 25)"
+      ,state_info:      "oklch(0.50 0.12 240)"
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "oklch(0.45 0.15 25)"
+      ,syntax_string:   "oklch(0.40 0.10 130)"
+      ,syntax_func:     "oklch(0.45 0.12 35)"
+      ,syntax_comment:  "oklch(0.60 0.02 90)"
+    };
+
+    // 1. Populate the Dictionary
+    for (const [key, value] of Object.entries(dictionary)) {
+      window.RT.theme('write', key, value);
+    }
+
+    // 2. Structural Safety Net
+    if (!window.RT.theme('is_defined')) {
+      window.RT.debug.error('theme', `Theme '${dictionary.meta_name}' failed structural completeness check. Missing keys detected.`);
+    }
+
+    // 3. Global Pseudo Elements
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      
+      const [select_bg, select_fg, scroll_bg, scroll_thumb, scroll_hover, content_main] = 
+        window.RT.theme('read', 'surface_select', 'brand_primary', 'surface_0', 'border_default', 'brand_secondary', 'content_main');
+
+      style.textContent = `
+        ::selection { background: ${select_bg}; color: ${select_fg}; }
+        ::-moz-selection { background: ${select_bg}; color: ${select_fg}; }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: ${scroll_bg}; }
+        ::-webkit-scrollbar-thumb { 
+           background: ${scroll_thumb};
+           border: 2px solid ${scroll_bg};
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: ${scroll_hover}; }
+
+        rt-article p, rt-article li {
+           text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2);
+        }
+
+        .MathJax, .MathJax_Display, .mjx-chtml {
+            color: ${content_main} !important;
+            fill: ${content_main} !important;
+            stroke: ${content_main} !important;
+        }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+})();
diff --git a/developer/authored/Manuscript.copy/Theme/inverse_wheat.js b/developer/authored/Manuscript.copy/Theme/inverse_wheat.js
new file mode 100644 (file)
index 0000000..53c356d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  Theme: Inverse Wheat (Dark)
+  Standard: Theme 1.0
+  Description: High contrast Amber on Deep Charcoal.
+*/
+(function(){
+  const RT = window.RT = window.RT || {};
+  
+  RT.theme = function(){
+    const dictionary = {
+       meta_is_dark: true
+      ,meta_name:    "Inverse Wheat"
+
+      // --- SURFACES ---
+      ,surface_0:       "oklch(0.15 0 0)"
+      ,surface_1:       "oklch(0.18 0 0)"
+      ,surface_2:       "oklch(0.21 0 0)"
+      ,surface_3:       "oklch(0.24 0 0)"
+      ,surface_input:   "oklch(0.19 0 0)"
+      ,surface_code:    "oklch(0.17 0 0)"
+      ,surface_select:  "oklch(0.30 0.05 80)"
+
+      // --- CONTENT ---
+      ,content_main:    "oklch(0.85 0.05 90)"
+      ,content_muted:   "oklch(0.70 0.03 90)"
+      ,content_subtle:  "oklch(0.50 0.02 90)"
+      ,content_inverse: "oklch(0.15 0 0)"
+
+      // --- BRAND & ACTION ---
+      ,brand_primary:   "oklch(0.75 0.15 80)"
+      ,brand_secondary: "oklch(0.65 0.12 70)"
+      ,brand_tertiary:  "oklch(0.60 0.10 60)"
+      ,brand_link:      "oklch(0.75 0.15 85)"
+
+      // --- BORDERS ---
+      ,border_faint:    "oklch(0.25 0.01 90)"
+      ,border_default:  "oklch(0.35 0.02 90)"
+      ,border_strong:   "oklch(0.45 0.03 90)"
+
+      // --- STATE & FEEDBACK ---
+      ,state_success:   "oklch(0.60 0.12 130)"
+      ,state_warning:   "oklch(0.65 0.15 50)"
+      ,state_error:     "oklch(0.55 0.15 25)"
+      ,state_info:      "oklch(0.60 0.10 240)"
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "oklch(0.70 0.15 50)"
+      ,syntax_string:   "oklch(0.75 0.10 130)"
+      ,syntax_func:     "oklch(0.80 0.12 85)"
+      ,syntax_comment:  "oklch(0.55 0.02 90)"
+    };
+
+    // 1. Populate the Dictionary
+    for (const [key, value] of Object.entries(dictionary)) {
+      window.RT.theme('write', key, value);
+    }
+
+    // 2. Structural Safety Net
+    if (!window.RT.theme('is_defined')) {
+      window.RT.debug.error('theme', `Theme '${dictionary.meta_name}' failed structural completeness check. Missing keys detected.`);
+    }
+
+    // 3. Global Pseudo Elements
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      
+      const [select_bg, select_fg, scroll_bg, scroll_thumb, scroll_hover] = 
+        window.RT.theme('read', 'surface_select', 'brand_primary', 'surface_0', 'border_default', 'brand_secondary');
+
+      style.textContent = `
+        ::selection { background: ${select_bg}; color: ${select_fg}; }
+        ::-moz-selection { background: ${select_bg}; color: ${select_fg}; }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: ${scroll_bg}; }
+        ::-webkit-scrollbar-thumb { 
+           background: ${scroll_thumb};
+           border: 2px solid ${scroll_bg};
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: ${scroll_hover}; }
+
+        img.rt-diagram { filter: invert(1) hue-rotate(180deg); }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+})();
diff --git a/developer/authored/Manuscript.copy/Theme/light.js b/developer/authored/Manuscript.copy/Theme/light.js
deleted file mode 100644 (file)
index d0e80eb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-  Theme: Classic Wheat (Light)
-  Standard: Theme 1.0
-  Description: Warm paper tones with Burnt Orange accents.
-*/
-( function(){
-  const RT = window.RT = window.RT || {};
-  
-  RT.theme_light = function(){
-    RT.config = RT.config || {};
-    
-    // THEME 1.0 DATA CONTRACT
-    RT.config.theme = {
-       meta_is_dark: false
-      ,meta_name:    "Classic Wheat"
-
-      // --- SURFACES ---
-      ,surface_0:       "hsl(40, 30%, 94%)"   // App Background (Cream/Linen)
-      ,surface_1:       "hsl(40, 25%, 90%)"   // Sidebar (Slightly darker beige)
-      ,surface_2:       "hsl(40, 20%, 98%)"   // Cards (Lighter, almost white)
-      ,surface_3:       "hsl(0, 0%, 100%)"    // Modals (Pure White)
-      ,surface_input:   "hsl(40, 20%, 98%)"   // Form Inputs
-      ,surface_code:    "hsl(40, 15%, 90%)"   // Code Block Background
-      ,surface_select:  "hsl(45, 100%, 85%)"  // Text Selection Highlight
-
-      // --- CONTENT ---
-      ,content_main:    "hsl(30, 20%, 20%)"   // Deep Umber (Not Black)
-      ,content_muted:   "hsl(30, 15%, 45%)"   // Medium Brown
-      ,content_subtle:  "hsl(30, 10%, 65%)"   // Light Brown/Gray
-      ,content_inverse: "hsl(40, 30%, 94%)"   // Text on dark buttons
-
-      // --- BRAND & ACTION ---
-      ,brand_primary:   "hsl(30, 90%, 35%)"   // Burnt Orange (Action)
-      ,brand_secondary: "hsl(35, 70%, 45%)"   // Rust / Gold
-      ,brand_tertiary:  "hsl(25, 60%, 55%)"   // Copper
-      ,brand_link:      "hsl(30, 100%, 35%)"  // Link Color
-
-      // --- BORDERS ---
-      ,border_faint:    "hsl(35, 20%, 85%)"
-      ,border_default:  "hsl(35, 20%, 75%)"
-      ,border_strong:   "hsl(35, 20%, 55%)"
-
-      // --- STATE & FEEDBACK ---
-      ,state_success:   "hsl(100, 40%, 40%)"  // Forest Green
-      ,state_warning:   "hsl(30, 90%, 50%)"   // Persimmon
-      ,state_error:     "hsl(0, 60%, 45%)"    // Crimson
-      ,state_info:      "hsl(200, 50%, 45%)"  // Navy Blue
-
-      // --- SYNTAX ---
-      ,syntax_keyword:  "hsl(20, 90%, 45%)"   // Rust
-      ,syntax_string:   "hsl(100, 35%, 35%)"  // Ivy Green
-      ,syntax_func:     "hsl(300, 30%, 40%)"  // Muted Purple
-      ,syntax_comment:  "hsl(35, 10%, 60%)"   // Light Brown
-    };
-
-    // --- APPLY THEME ---
-    const palette = RT.config.theme;
-    const body = document.body;
-    const html = document.documentElement;
-
-    html.style.backgroundColor = palette.surface_0;
-    body.style.backgroundColor = palette.surface_0;
-    body.style.color = palette.content_main;
-
-    const s = body.style;
-    for (const [key, value] of Object.entries(palette)) {
-      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
-    }
-  };
-} )();
diff --git a/developer/authored/Manuscript.copy/Theme/light_gold.js b/developer/authored/Manuscript.copy/Theme/light_gold.js
deleted file mode 100644 (file)
index 3136934..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-  Theme: Golden Wheat (Light) - "Spanish Gold Edition"
-  File: style/theme-light-gold.js
-  Standard: Theme 1.0
-  Description: Light Parchment background with Oxblood Red ink.
-*/
-( function(){
-  const RT = window.RT = window.RT || {};
-  
-  RT.theme = function(){
-    RT.config = RT.config || {};
-    
-    RT.config.theme = {
-       meta_is_dark: false
-      ,meta_name:    "Golden Wheat (Yellow)"
-
-      // --- SURFACES (Light Parchment) ---
-      // Shifted lightness up to 94% for a "whiter" feel that still holds the yellow tint.
-      ,surface_0:       "hsl(48, 50%, 94%)"   // Main Page: Fine Parchment
-      ,surface_1:       "hsl(48, 40%, 90%)"   // Panels: Slightly darker
-      ,surface_2:       "hsl(48, 30%, 97%)"   // Cards: Very light
-      ,surface_3:       "hsl(0, 0%, 100%)"    // Popups
-      ,surface_input:   "hsl(48, 20%, 96%)"   
-      ,surface_code:    "hsl(48, 25%, 88%)"   // Distinct Code BG
-      ,surface_select:  "hsl(10, 70%, 85%)"   // Red Highlight
-
-      // --- CONTENT (Deep Ink) ---
-      ,content_main:    "hsl(10, 25%, 7%)"    // Deep Warm Black (Ink)
-      ,content_muted:   "hsl(10, 15%, 35%)"   // Dark Grey-Red
-      ,content_subtle:  "hsl(10, 10%, 55%)"   
-      ,content_inverse: "hsl(48, 50%, 90%)"   
-
-      // --- BRAND & ACTION (The Red Spectrum) ---
-      ,brand_primary:   "hsl(12, 85%, 30%)"   // H1 (Deep Oxblood)
-      ,brand_secondary: "hsl(10, 80%, 35%)"   // H2 (Garnet)
-      ,brand_tertiary:  "hsl(8, 70%, 40%)"    // H3 (Brick)
-      ,brand_link:      "hsl(12, 90%, 35%)"   // Link
-
-      // --- BORDERS ---
-      ,border_faint:    "hsl(45, 30%, 80%)"
-      ,border_default:  "hsl(45, 30%, 70%)"   // Pencil Grey
-      ,border_strong:   "hsl(12, 50%, 40%)"   
-
-      // --- STATE ---
-      ,state_success:   "hsl(120, 40%, 30%)"  
-      ,state_warning:   "hsl(25, 90%, 45%)"   
-      ,state_error:     "hsl(0, 75%, 35%)"    
-      ,state_info:      "hsl(210, 60%, 40%)"  
-
-      // --- SYNTAX ---
-      ,syntax_keyword:  "hsl(0, 75%, 35%)"    
-      ,syntax_string:   "hsl(100, 35%, 25%)"  
-      ,syntax_func:     "hsl(15, 85%, 35%)"   
-      ,syntax_comment:  "hsl(45, 20%, 50%)"   
-    };
-
-    // --- APPLY THEME ---
-    const palette = RT.config.theme;
-    const body = document.body;
-    const html = document.documentElement;
-
-    html.style.backgroundColor = palette.surface_0;
-    body.style.backgroundColor = palette.surface_0;
-    body.style.color = palette.content_main;
-
-    const s = body.style;
-    for (const [key, value] of Object.entries(palette)) {
-      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
-    }
-    
-    // Global overrides
-    const style_id = 'rt-global-overrides';
-    if (!document.getElementById(style_id)) {
-      const style = document.createElement('style');
-      style.id = style_id;
-      style.textContent = `
-        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
-        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
-        
-        ::-webkit-scrollbar { width: 12px; }
-        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
-        ::-webkit-scrollbar-thumb { 
-           background: var(--rt-border-default); 
-           border: 2px solid var(--rt-surface-0);
-           border-radius: 8px; 
-        }
-        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
-
-        rt-article p, rt-article li {
-           text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2); 
-        }
-
-        .MathJax, .MathJax_Display, .mjx-chtml {
-            color: var(--rt-content-main) !important;
-            fill: var(--rt-content-main) !important;
-            stroke: var(--rt-content-main) !important;
-        }
-      `;
-      document.head.appendChild(style);
-    }
-  };
-  
-} )();
diff --git a/developer/authored/Manuscript.copy/Theme/wheat.js b/developer/authored/Manuscript.copy/Theme/wheat.js
new file mode 100644 (file)
index 0000000..2571cd8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Theme: Classic Wheat (Light)
+  Standard: Theme 1.0
+  Description: Warm paper tones with Burnt Orange accents.
+*/
+(function(){
+  const RT = window.RT = window.RT || {};
+  
+  RT.theme_light = function(){
+    const dictionary = {
+       meta_is_dark: false
+      ,meta_name:    "Classic Wheat"
+
+      // --- SURFACES ---
+      ,surface_0:       "oklch(0.95 0.02 80)"
+      ,surface_1:       "oklch(0.92 0.02 80)"
+      ,surface_2:       "oklch(0.97 0.01 80)"
+      ,surface_3:       "oklch(0.99 0 0)"
+      ,surface_input:   "oklch(0.96 0.01 80)"
+      ,surface_code:    "oklch(0.92 0.01 80)"
+      ,surface_select:  "oklch(0.88 0.06 80)"
+
+      // --- CONTENT ---
+      ,content_main:    "oklch(0.25 0.02 60)"
+      ,content_muted:   "oklch(0.45 0.03 60)"
+      ,content_subtle:  "oklch(0.65 0.02 60)"
+      ,content_inverse: "oklch(0.94 0.02 80)"
+
+      // --- BRAND & ACTION ---
+      ,brand_primary:   "oklch(0.50 0.15 50)"
+      ,brand_secondary: "oklch(0.55 0.12 60)"
+      ,brand_tertiary:  "oklch(0.60 0.10 45)"
+      ,brand_link:      "oklch(0.50 0.16 50)"
+
+      // --- BORDERS ---
+      ,border_faint:    "oklch(0.85 0.02 80)"
+      ,border_default:  "oklch(0.75 0.02 80)"
+      ,border_strong:   "oklch(0.55 0.04 80)"
+
+      // --- STATE & FEEDBACK ---
+      ,state_success:   "oklch(0.50 0.10 130)"
+      ,state_warning:   "oklch(0.60 0.15 50)"
+      ,state_error:     "oklch(0.50 0.15 25)"
+      ,state_info:      "oklch(0.55 0.10 240)"
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "oklch(0.50 0.14 50)"
+      ,syntax_string:   "oklch(0.45 0.10 130)"
+      ,syntax_func:     "oklch(0.50 0.10 320)"
+      ,syntax_comment:  "oklch(0.65 0.02 80)"
+    };
+
+    // 1. Populate the Dictionary
+    for (const [key, value] of Object.entries(dictionary)) {
+      window.RT.theme('write', key, value);
+    }
+
+    // 2. Structural Safety Net
+    if (!window.RT.theme('is_defined')) {
+      window.RT.debug.error('theme', `Theme '${dictionary.meta_name}' failed structural completeness check. Missing keys detected.`);
+    }
+
+    // 3. Global Pseudo Elements
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      
+      const [select_bg, select_fg, scroll_bg, scroll_thumb, scroll_hover] = 
+        window.RT.theme('read', 'surface_select', 'brand_primary', 'surface_0', 'border_default', 'brand_secondary');
+
+      style.textContent = `
+        ::selection { background: ${select_bg}; color: ${select_fg}; }
+        ::-moz-selection { background: ${select_bg}; color: ${select_fg}; }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: ${scroll_bg}; }
+        ::-webkit-scrollbar-thumb { 
+           background: ${scroll_thumb};
+           border: 2px solid ${scroll_bg};
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: ${scroll_hover}; }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+})();
index 2399686..1eec838 100644 (file)
@@ -9,14 +9,14 @@
     </script>
   </head>
   <body>
-    <RT-article>
-      <RT-title 
+    <RT·article>
+      <RT·title 
         author="Thomas Walker Lynch" 
         date="2026-06-23" 
         title="Introduction to Harmony">
       </RT-title>
 
-      <RT-TOC level="1"></RT-TOC>
+      <RT·TOC level="1"></RT-TOC>
 
       <h1>Purpose</h1>
       <p>
       </p>
       <ol>
         <li>Clone the Harmony project to a local directory.</li>
-        <li>Remove the <RT-code>.git</RT-code> tree.</li>
+        <li>Remove the <RT·code>.git</RT-code> tree.</li>
         <li>Rename the Harmony directory to the name of the new project.</li>
-        <li>Rename the <RT-code>0pus_Harmony</RT-code> file to reflect the name of the new project.</li>
-        <li>Add a line to the <RT-code>shared/tool/version</RT-code> file for the new project.</li>
-        <li><RT-code>git init -b core_developer_branch</RT-code></li>
+        <li>Rename the <RT·code>0pus_Harmony</RT-code> file to reflect the name of the new project.</li>
+        <li>Add a line to the <RT·code>shared/tool/version</RT-code> file for the new project.</li>
+        <li><RT·code>git init -b core_developer_branch</RT-code></li>
       </ol>
 
       <p>
@@ -51,7 +51,7 @@
         Leave the Harmony skeleton version in the version file, so that project administrators can understand what has changed in the skeleton over time.
       </p>
       <p>
-        The <RT-code>core_developer_branch</RT-code> is the branch that the core development team works on. Project releases are moved to release branches.
+        The <RT·code>core_developer_branch</RT-code> is the branch that the core development team works on. Project releases are moved to release branches.
       </p>
 
       <h1>Environment setup</h1>
         Python programmers who use virtual environments will be familiar with an analogous process. The term 'virtual environment' does not invoke any hardware virtualization features; rather, it is a local environment setup. To avoid confusion, a Harmony user refers instead to the 'project setup'. The command to establish the environment is called 'setup' instead of 'activate'. Also note that in Harmony, unlike in Python, there are multiple setups available, each tailored to the specific role a person takes on.
       </p>
       <p>
-        As of the time of this writing, the defined roles are: <strong>administrator</strong>, <strong>consumer</strong>, <strong>developer</strong>, and <strong>tester</strong>. A person takes on a role by sourcing the top-level <RT-code>setup</RT-code> script and giving the target role as an argument. For example, in a bash shell with <RT-code>></RT-code> as the prompt, the command is:
+        As of the time of this writing, the defined roles are: <strong>administrator</strong>, <strong>consumer</strong>, <strong>developer</strong>, and <strong>tester</strong>. A person takes on a role by sourcing the top-level <RT·code>setup</RT-code> script and giving the target role as an argument. For example, in a bash shell with <RT·code>></RT-code> as the prompt, the command is:
       </p>
 
-      <RT-code>
+      <RT·code>
         > . setup &lt;role&gt;
       </RT-code>
 
@@ -70,7 +70,7 @@
         Specifically for the developer role:
       </p>
         
-      <RT-code>
+      <RT·code>
         > . setup developer
       </RT-code>
 
         For the administrator role:
       </p>
         
-      <RT-code>
+      <RT·code>
         > . setup administrator
       </RT-code>
 
       <p>
-        Instead of starting with a period, the <RT-code>source</RT-code> command can be spelled out explicitly, for example:
+        Instead of starting with a period, the <RT·code>source</RT-code> command can be spelled out explicitly, for example:
       </p>
       
-      <RT-code>
+      <RT·code>
         > source setup tester
       </RT-code>
 
       <p>
-        Behind the scenes, the <RT-code>setup</RT-code> script performs the following actions:
+        Behind the scenes, the <RT·code>setup</RT-code> script performs the following actions:
       </p>
 
       <ul>
-        <li>Sources the project-wide setup (<RT-code>shared/tool/setup</RT-code>) to establish the core environment variables (e.g., <RT-code>REPO_HOME</RT-code> and <RT-code>PROJECT</RT-code>).</li>
-        <li>Conditionally sources <RT-code>shared/authored/setup</RT-code> (if present) to apply administrator-injected, project-specific tool configurations.</li>
-        <li>Dynamically sources all <RT-code>.init</RT-code> files found in the <RT-code>shared/linked-project/</RT-code> directory.</li>
-        <li>Configures the <RT-code>PATH</RT-code> to include shared tools, library environments, and the specific <RT-code>&lt;role&gt;/tool</RT-code> directory.</li>
+        <li>Sources the project-wide setup (<RT·code>shared/tool/setup</RT-code>) to establish the core environment variables (e.g., <RT·code>REPO_HOME</RT-code> and <RT·code>PROJECT</RT-code>).</li>
+        <li>Conditionally sources <RT·code>shared/authored/setup</RT-code> (if present) to apply administrator-injected, project-specific tool configurations.</li>
+        <li>Dynamically sources all <RT·code>.init</RT-code> files found in the <RT·code>shared/linked-project/</RT-code> directory.</li>
+        <li>Configures the <RT·code>PATH</RT-code> to include shared tools, library environments, and the specific <RT·code>&lt;role&gt;/tool</RT-code> directory.</li>
         <li>Changes the working directory into the specified role's workspace.</li>
-        <li>Sources the <RT-code>&lt;role&gt;/tool/setup</RT-code> script. While the earlier steps apply the standard Harmony skeleton setup, this final step applies the role setup that is customized for this specific project.</li>
+        <li>Sources the <RT·code>&lt;role&gt;/tool/setup</RT-code> script. While the earlier steps apply the standard Harmony skeleton setup, this final step applies the role setup that is customized for this specific project.</li>
       </ul>
 
       <h1>After git clone</h1>
       <p>
-        Because git does not track certain artifact directories (such as <RT-code>consumer/</RT-code> outputs), a freshly cloned repository lacks external dependencies and consumable products. Team members must perform a few steps to populate these areas.
+        Because git does not track certain artifact directories (such as <RT·code>consumer/</RT-code> outputs), a freshly cloned repository lacks external dependencies and consumable products. Team members must perform a few steps to populate these areas.
       </p>
 
       <h2>Third-party tools</h2>
       <p>
-        Harmony is language agnostic. When a project makes use of project-specific C, Python, NodeJS, Java, or other tools, the project administrator configures the project to expect these tools in the <RT-code>shared/linked-project</RT-code> directory via the `.init` plugin system.
+        Harmony is language agnostic. When a project makes use of project-specific C, Python, NodeJS, Java, or other tools, the project administrator configures the project to expect these tools in the <RT·code>shared/linked-project</RT-code> directory via the `.init` plugin system.
       </p>
       <p>
-        Because multiple team members will have to repeat the third-party install process after cloning a project, the administrator should carefully document the installation steps and place the resulting documents in the <RT-code>administrator/document</RT-code> directory. The standard installation method is to clone the external tool into the parent directory alongside the project, create a symlink to it under <RT-code>shared/linked-project/</RT-code> using the <RT-code>project/</RT-code> parent link, and supply an <RT-code>.init</RT-code> script to manage the local environment variables.
+        Because multiple team members will have to repeat the third-party install process after cloning a project, the administrator should carefully document the installation steps and place the resulting documents in the <RT·code>administrator/document</RT-code> directory. The standard installation method is to clone the external tool into the parent directory alongside the project, create a symlink to it under <RT·code>shared/linked-project/</RT-code> using the <RT·code>project/</RT-code> parent link, and supply an <RT·code>.init</RT-code> script to manage the local environment variables.
       </p>
 
       <h2>Consumer build</h2>
         In this section we use the term 'consumer' to mean any team member that wants to make use of the project work product. The tester will want to test it, and the consumer role will want to deploy it, etc.
       </p>
       <p>
-        Because compiled binaries and final layouts are not tracked in the repository, the current version of Harmony requires a work product consumer to run a local build after cloning the project. The results of the build will appear directly in the <RT-code>consumer/</RT-code> directory.
+        Because compiled binaries and final layouts are not tracked in the repository, the current version of Harmony requires a work product consumer to run a local build after cloning the project. The results of the build will appear directly in the <RT·code>consumer/</RT-code> directory.
       </p>
       <p>
-        To facilitate this, the developer must explicitly document the project's build and promote procedure, saving this guide as <RT-code>developer/document/build.html</RT-code>. The consumer must then read this document and execute the described steps to locally populate their <RT-code>consumer/</RT-code> directory.
+        To facilitate this, the developer must explicitly document the project's build and promote procedure, saving this guide as <RT·code>developer/document/build.html</RT-code>. The consumer must then read this document and execute the described steps to locally populate their <RT·code>consumer/</RT-code> directory.
       </p>
 
       <p>
       </p>
 
       <ol>
-        <li><RT-code>> bash</RT-code></li>
-        <li><RT-code>> cd &lt;project&gt;</RT-code></li>
-        <li><RT-code>> . setup developer</RT-code></li>
-        <li><RT-code>> build &lt;namespace&gt;</RT-code></li>
-        <li><RT-code>> promote write</RT-code></li>
-        <li><RT-code>> exit</RT-code></li>
-        <li><RT-code>> bash</RT-code></li>
-        <li><RT-code>> cd &lt;project&gt;</RT-code></li>
-        <li><RT-code>> . setup &lt;role&gt;</RT-code></li>
+        <li><RT·code>> bash</RT-code></li>
+        <li><RT·code>> cd &lt;project&gt;</RT-code></li>
+        <li><RT·code>> . setup developer</RT-code></li>
+        <li><RT·code>> build &lt;namespace&gt;</RT-code></li>
+        <li><RT·code>> promote write</RT-code></li>
+        <li><RT·code>> exit</RT-code></li>
+        <li><RT·code>> bash</RT-code></li>
+        <li><RT·code>> cd &lt;project&gt;</RT-code></li>
+        <li><RT·code>> . setup &lt;role&gt;</RT-code></li>
       </ol>
 
       <p>
-        This sequence opens a bash shell, assumes the developer role to orchestrate the build, makes the work product, then promotes it to the consumer's workspace. The <RT-code>exit</RT-code> command drops the developer role. The last two lines put the person into the &lt;role&gt; workspace, typically for testing or deploying.
+        This sequence opens a bash shell, assumes the developer role to orchestrate the build, makes the work product, then promotes it to the consumer's workspace. The <RT·code>exit</RT-code> command drops the developer role. The last two lines put the person into the &lt;role&gt; workspace, typically for testing or deploying.
       </p>
 
 
         This section discusses our thinking in naming the files and directories found in the Harmony skeleton.
       </p>
       <p>
-        A directory name is considered to be a <RT-term>property</RT-term> given to each file contained in the directory. A full path then forms a semantic sentence describing each file.
+        A directory name is considered to be a <RT·term>property</RT-term> given to each file contained in the directory. A full path then forms a semantic sentence describing each file.
       </p>
       <p>
-        Because a directory name represents a property, it is rarely plural. For example, when each and every file in a directory is a test, the directory is named <RT-code>test</RT-code>.
+        Because a directory name represents a property, it is rarely plural. For example, when each and every file in a directory is a test, the directory is named <RT·code>test</RT-code>.
       </p>
       <p>
         We run into limitations when using a conventional file system as though it were a property based file system. One limitation is that we are forced to choose a single directory name for each file. When a set of files in a directory all share the same multiple properties, we can use a compound directory name with the properties separated by an underscore, but it is impractical to specify overlapping directory groupings, i.e. we can't arbitrarily define any number of properties for a file in this manner.
         The following list presents each property type in order of preference when naming directories:
       </p>
       <ul>
-        <li><strong>Role Association</strong> (<RT-code>administrator</RT-code>, <RT-code>developer</RT-code>, <RT-code>tester</RT-code>, <RT-code>consumer</RT-code>): Identifies the persona, whether human or AI, intended to interact with the files.</li>
-        <li><strong>Provenance</strong> (<RT-code>authored</RT-code>, <RT-code>made</RT-code>): Indicates whether the file was created by an intellect or mechanically produced by a tool.</li>
-        <li><strong>Capability</strong> (<RT-code>tool</RT-code>, <RT-code>document</RT-code>, <RT-code>experiment</RT-code>): Describes the primary function or structural nature of the file.</li>
-        <li><strong>Lifecycle State</strong> (<RT-code>scratchpad</RT-code>, <RT-code>stage</RT-code>): Denotes the persistence, volatility, or promotion status of the file.</li>
-        <li><strong>Tracking Status</strong> (<RT-code>tracked</RT-code>, <RT-code>untracked</RT-code>): Specifies the version control expectations for the artifacts.</li>
+        <li><strong>Role Association</strong> (<RT·code>administrator</RT-code>, <RT·code>developer</RT-code>, <RT·code>tester</RT-code>, <RT·code>consumer</RT-code>): Identifies the persona, whether human or AI, intended to interact with the files.</li>
+        <li><strong>Provenance</strong> (<RT·code>authored</RT-code>, <RT·code>made</RT-code>): Indicates whether the file was created by an intellect or mechanically produced by a tool.</li>
+        <li><strong>Capability</strong> (<RT·code>tool</RT-code>, <RT·code>document</RT-code>, <RT·code>experiment</RT-code>): Describes the primary function or structural nature of the file.</li>
+        <li><strong>Lifecycle State</strong> (<RT·code>scratchpad</RT-code>, <RT·code>stage</RT-code>): Denotes the persistence, volatility, or promotion status of the file.</li>
+        <li><strong>Tracking Status</strong> (<RT·code>tracked</RT-code>, <RT·code>untracked</RT-code>): Specifies the version control expectations for the artifacts.</li>
       </ul>
 
       <h2>Authored, made, scratchpad, inherited</h2>
       <p>
-        Files found in a directory named <RT-code>authored</RT-code> were written by project team members. They did not come with the Harmony skeleton, nor with the installation of other software. Project build tools treat <RT-code>authored</RT-code> directories as strictly read-only. Typically these files constitute the intellectual property of a project.
+        Files found in a directory named <RT·code>authored</RT-code> were written by project team members. They did not come with the Harmony skeleton, nor with the installation of other software. Project build tools treat <RT·code>authored</RT-code> directories as strictly read-only. Typically these files constitute the intellectual property of a project.
       </p>
       <p>
-        All source code that gets built into a promotion or project release must be placed in the developers' <RT-code>authored</RT-code> directory. The story is not as clean for build tools and other files. New documents go into document directories, and new tools go into the tool directories, etc. As a specific example, the developer will almost certainly edit the <RT-code>developer/tool/build</RT-code> file.
+        All source code that gets built into a promotion or project release must be placed in the developers' <RT·code>authored</RT-code> directory. The story is not as clean for build tools and other files. New documents go into document directories, and new tools go into the tool directories, etc. As a specific example, the developer will almost certainly edit the <RT·code>developer/tool/build</RT-code> file.
       </p>
       <p>
-        When the Harmony version line in the <RT-code>shared/tool/version</RT-code> file is left in place, it is straightforward for a project administrator to determine which Harmony skeleton files have been edited in a project, and which new files have been added.
+        When the Harmony version line in the <RT·code>shared/tool/version</RT-code> file is left in place, it is straightforward for a project administrator to determine which Harmony skeleton files have been edited in a project, and which new files have been added.
       </p>
       <p>
-        Files found in a directory named <RT-code>scratchpad</RT-code> are not tracked. Hence, a <RT-code>git clone</RT-code> will always return empty <RT-code>scratchpad</RT-code> directories. It is common for tools to place intermediate files on a scratchpad. It is also common for files to be staged on a scratchpad. Tools play nice and use subdirectories on the pad, so a person who is aware of those subdirectory names can use a scratchpad as a temporary directory. There is a scratchpad maintenance tool that comes with the Harmony, called unimaginatively, <RT-code>scratchpad</RT-code>. Pay attention as one of its commands is <RT-code>clear</RT-code>, and that deletes everything on the current directory's scratchpad.
+        Files found in a directory named <RT·code>scratchpad</RT-code> are not tracked. Hence, a <RT·code>git clone</RT-code> will always return empty <RT·code>scratchpad</RT-code> directories. It is common for tools to place intermediate files on a scratchpad. It is also common for files to be staged on a scratchpad. Tools play nice and use subdirectories on the pad, so a person who is aware of those subdirectory names can use a scratchpad as a temporary directory. There is a scratchpad maintenance tool that comes with the Harmony, called unimaginatively, <RT·code>scratchpad</RT-code>. Pay attention as one of its commands is <RT·code>clear</RT-code>, and that deletes everything on the current directory's scratchpad.
       </p>
       <p>
-        Third party software is installed under <RT-code>shared/linked-project</RT-code>. Other files are said to be <RT-term>inherited</RT-term>, or to be <RT-term>customizations</RT-term>.
+        Third party software is installed under <RT·code>shared/linked-project</RT-code>. Other files are said to be <RT·term>inherited</RT-term>, or to be <RT·term>customizations</RT-term>.
       </p>
 
       <h1>Top-level repository layout</h1>
       <p>
-        A team member will source the project setup file to take on a role. As of this writing, the supported roles are: <RT-code>administrator</RT-code>, <RT-code>developer</RT-code>, <RT-code>tester</RT-code>, and <RT-code>consumer</RT-code>.
+        A team member will source the project setup file to take on a role. As of this writing, the supported roles are: <RT·code>administrator</RT-code>, <RT·code>developer</RT-code>, <RT·code>tester</RT-code>, and <RT·code>consumer</RT-code>.
       </p>
 
       <ul>
-        <li><RT-code>administrator/</RT-code> : Project-local tools and skeleton maintenance.</li>
-        <li><RT-code>developer/</RT-code> : Primary workspace for developers.</li>
-        <li><RT-code>tester/</RT-code> : Regression and validation workspace for testers.</li>
-        <li><RT-code>consumer/</RT-code> : Consumption workspace acting as the final artifact sink.</li>
-        <li><RT-code>shared/</RT-code> : Shared ecosystem tools and global environments.</li>
+        <li><RT·code>administrator/</RT-code> : Project-local tools and skeleton maintenance.</li>
+        <li><RT·code>developer/</RT-code> : Primary workspace for developers.</li>
+        <li><RT·code>tester/</RT-code> : Regression and validation workspace for testers.</li>
+        <li><RT·code>consumer/</RT-code> : Consumption workspace acting as the final artifact sink.</li>
+        <li><RT·code>shared/</RT-code> : Shared ecosystem tools and global environments.</li>
       </ul>
 
       <h2>The administrator work area</h2>
 
       <h2>The developer work area</h2>
       <p>
-        This directory is entered by first going to the top-level directory of the project, then sourcing <RT-code>. setup developer</RT-code>.
+        This directory is entered by first going to the top-level directory of the project, then sourcing <RT·code>. setup developer</RT-code>.
       </p>
       <ul>
-        <li><RT-code>authored/</RT-code> : Human-written source. Tracked by Git.</li>
-        <li><RT-code>made/</RT-code> : Tracked artifacts generated by tools (e.g., links to CLI entry points).</li>
-        <li><RT-code>experiment/</RT-code> : Try-it-here code. Short-lived spot testing.</li>
-        <li><RT-code>scratchpad/</RT-code> : Git-ignored directory. Holds all intermediate build outputs, including the staged namespace directories for promotions.</li>
-        <li><RT-code>tool/</RT-code> : Developer-specific tools (like the promote and build scripts).</li>
+        <li><RT·code>authored/</RT-code> : Human-written source. Tracked by Git.</li>
+        <li><RT·code>made/</RT-code> : Tracked artifacts generated by tools (e.g., links to CLI entry points).</li>
+        <li><RT·code>experiment/</RT-code> : Try-it-here code. Short-lived spot testing.</li>
+        <li><RT·code>scratchpad/</RT-code> : Git-ignored directory. Holds all intermediate build outputs, including the staged namespace directories for promotions.</li>
+        <li><RT·code>tool/</RT-code> : Developer-specific tools (like the promote and build scripts).</li>
       </ul>
 
       <h2>The tester work area</h2>
       <p>
-        This directory is dedicated to formal testing, including regression suites. While a developer can run and keep informal spot tests in their <RT-code>experiment/</RT-code> directory, any experiment promoted to a formal test is moved here. This enforces the boundary between writing code and validating it.
+        This directory is dedicated to formal testing, including regression suites. While a developer can run and keep informal spot tests in their <RT·code>experiment/</RT-code> directory, any experiment promoted to a formal test is moved here. This enforces the boundary between writing code and validating it.
       </p>
 
       <h2>The shared tree</h2>
       <p>
-        This directory contains ecosystem tools and global environments available to all roles. This includes the shared tool directory, as well as third-party symlinks and <RT-code>.init</RT-code> scripts required by the project. To assist in project specific modifications to the Harmony skeleton, Harmony comes with an empty <RT-code>shared/authored</RT-code> directory that is listed earlier in the executable search path than <RT-code>shared/tool</RT-code>.
+        This directory contains ecosystem tools and global environments available to all roles. This includes the shared tool directory, as well as third-party symlinks and <RT·code>.init</RT-code> scripts required by the project. To assist in project specific modifications to the Harmony skeleton, Harmony comes with an empty <RT·code>shared/authored</RT-code> directory that is listed earlier in the executable search path than <RT·code>shared/tool</RT-code>.
       </p>
 
       <h2>The consumer tree</h2>
       <p>
-        The <RT-code>consumer/</RT-code> tree is where developers put work product that is ready to be consumed. The entire directory is git-ignored and treated as a transient deployment target. Artifacts arrive in the <RT-code>consumer/</RT-code> tree <em>only</em> when the promote script is invoked, which performs a flat-copy from the developer's <RT-code>scratchpad/made</RT-code> directory.
+        The <RT·code>consumer/</RT-code> tree is where developers put work product that is ready to be consumed. The entire directory is git-ignored and treated as a transient deployment target. Artifacts arrive in the <RT·code>consumer/</RT-code> tree <em>only</em> when the promote script is invoked, which performs a flat-copy from the developer's <RT·code>scratchpad/made</RT-code> directory.
       </p>
 
       <h2>Document directories</h2>
         There is a directory for documents that talks about the project as a whole, one for each role, one for tools that are shared among the roles, and the released work product probably comes with a document directory of its own.
       </p>
       <ul>
-        <li><RT-code>document/</RT-code> : Top-level onboarding, project-wide structure, such as this document.</li>
-        <li><RT-code>consumer/&lt;namespace&gt;/document/</RT-code> : Documentation for end-users of made code (e.g., man pages, application manuals, library API references).</li>
-        <li><RT-code>administrator/document/</RT-code> : Documentation for maintaining the project skeleton and global tools.</li>
-        <li><RT-code>developer/document/</RT-code> : Documentation for developers, including coding standards and internal API guides.</li>
-        <li><RT-code>tester/document/</RT-code> : Documentation for testers detailing test plans and tools.</li>
-        <li><RT-code>shared/document/</RT-code> : Documentation on installing and configuring shared tools.</li>
+        <li><RT·code>document/</RT-code> : Top-level onboarding, project-wide structure, such as this document.</li>
+        <li><RT·code>consumer/&lt;namespace&gt;/document/</RT-code> : Documentation for end-users of made code (e.g., man pages, application manuals, library API references).</li>
+        <li><RT·code>administrator/document/</RT-code> : Documentation for maintaining the project skeleton and global tools.</li>
+        <li><RT·code>developer/document/</RT-code> : Documentation for developers, including coding standards and internal API guides.</li>
+        <li><RT·code>tester/document/</RT-code> : Documentation for testers detailing test plans and tools.</li>
+        <li><RT·code>shared/document/</RT-code> : Documentation on installing and configuring shared tools.</li>
       </ul>
 
       <p>
-        Currently, our developers write documents directly in HTML using the RT semantic tags. See the <RT-code>RT-Style</RT-code> project and the documentation there. A common approach is to copy another document and the <RT-code>setup.js</RT-code> file, then to type over the top of that other document.
+        Currently, our developers write documents directly in HTML using the RT semantic tags. See the <RT·code>RT-Style</RT-code> project and the documentation there. A common approach is to copy another document and the <RT·code>setup.js</RT-code> file, then to type over the top of that other document.
       </p>
 
       <h2>Untracked directories</h2>
       <ol>
-        <li><RT-code>consumer/</RT-code> (Excluding the base <RT-code>.gitignore</RT-code>)</li>
-        <li><RT-code>shared/linked-project/</RT-code> (Excluding <RT-code>.init</RT-code> and <RT-code>.gitignore</RT-code> files)</li>
-        <li><RT-code>**/scratchpad/</RT-code></li>
+        <li><RT·code>consumer/</RT-code> (Excluding the base <RT·code>.gitignore</RT-code>)</li>
+        <li><RT·code>shared/linked-project/</RT-code> (Excluding <RT·code>.init</RT-code> and <RT·code>.gitignore</RT-code> files)</li>
+        <li><RT·code>**/scratchpad/</RT-code></li>
       </ol>
 
       <h1>Workflow</h1>
 
       <h1>Developer promotion and project releases</h1>
       <p>
-        As a first step, a developer creates a <RT-term>promotion candidate</RT-term> inside of the <RT-code>consumer/</RT-code> directory. This is typically done by running <RT-code>build</RT-code> to stage the artifacts into <RT-code>scratchpad/made</RT-code>, followed by running <RT-code>promote write</RT-code>. The developer will often modify the versions of one or both of those tools that come with the Harmony skeleton. The promotion candidate remains stable until the next <RT-term>promotion</RT-term>.
+        As a first step, a developer creates a <RT·term>promotion candidate</RT-term> inside of the <RT·code>consumer/</RT-code> directory. This is typically done by running <RT·code>build</RT-code> to stage the artifacts into <RT·code>scratchpad/made</RT-code>, followed by running <RT·code>promote write</RT-code>. The developer will often modify the versions of one or both of those tools that come with the Harmony skeleton. The promotion candidate remains stable until the next <RT·term>promotion</RT-term>.
       </p>
       <p>
-        Then the tester runs tests on the promotion candidate. Tests must only read from the <RT-code>consumer/</RT-code> directory, though local copies can be made and edited as experiments.
+        Then the tester runs tests on the promotion candidate. Tests must only read from the <RT·code>consumer/</RT-code> directory, though local copies can be made and edited as experiments.
       </p>
       <p>
         It is common for a developer to open a second window on his desktop, and then enter the project as a tester in that second window. The developer can then make a promotion candidate, run the tests, edit source code, and perhaps tests, and then quickly spin through the test-debug-fix-promote cycle repeatedly.
       </p>
       <p>
-        When the product manager determines the work product to be sufficiently reliable and feature rich, the administrator will make a <RT-term>project release</RT-term>. He will do this by creating a branch called <RT-code>release_v&lt;major&gt;</RT-code> and tagging it. The major release numbers go up incrementally.
+        When the product manager determines the work product to be sufficiently reliable and feature rich, the administrator will make a <RT·term>project release</RT-term>. He will do this by creating a branch called <RT·code>release_v&lt;major&gt;</RT-code> and tagging it. The major release numbers go up incrementally.
       </p>
 
       <h1>The Harmony directory tree</h1>
 
-      <RT-code>
+      <RT·code>
       2026-06-23 13:41:45 Z [Harmony:administrator] Thomas_developer@StanleyPark
       §/home/Thomas/subu_data/developer/project§
       > tree Harmony
index 2a4f655..d9a13e6 100644 (file)
@@ -9,14 +9,14 @@
     </script>
   </head>
   <body>
-    <RT-article>
-      <RT-title 
+    <RT·article>
+      <RT·title 
         author="Thomas Walker Lynch" 
         date="2026-03-09" 
         title="Product development roles and workflow">
       </RT-title>
 
-      <RT-TOC level="1"></RT-TOC>
+      <RT·TOC level="1"></RT-TOC>
 
       <h1>Roles as hats</h1>
       <p>
@@ -27,7 +27,7 @@
       <p>
         These roles interact directly with the repository. To enter a workspace, change directory to the top-level of the project and source the setup file for the desired role:
       </p>
-      <RT-code>
+      <RT·code>
         > . setup administrator
         > . setup developer
         > . setup tester
       <p>Responsibilities:</p>
       <ol>
         <li>Set up the project directory and keep it in sync with the Harmony skeleton.</li>
-        <li>Maintain role environments (apart from role-specific <RT-code>tool/setup</RT-code> files).</li>
+        <li>Maintain role environments (apart from role-specific <RT·code>tool/setup</RT-code> files).</li>
         <li>Install and maintain shared and third_party tools, addressing issues with the project workflow. Note that the term "third_party" encompasses any software not authored within this specific project.</li>
       </ol>
 
       <h3>Developer role</h3>
       <p>Responsibilities and Boundaries:</p>
       <ol>
-        <li>Write and modify <RT-code>authored/</RT-code> source.</li>
-        <li>Run builds and place artifacts in <RT-code>scratchpad/made</RT-code>, then execute the <RT-code>promote write</RT-code> script to copy artifacts to <RT-code>consumer/made</RT-code> for testing.</li>
-        <li>Run experiments in <RT-code>experiment/</RT-code>. These experiments can sometimes be promoted to formal tests, but there is no requirement to do so. The developer role should not blur into the tester role; experiments are informal, whereas tests are formal and retained.</li>
-        <li><strong>Strict Boundary:</strong> A developer never writes into the <RT-code>tester/</RT-code> directory. Instead, a developer adds tests to <RT-code>developer/experiment/</RT-code> and offers to share them.</li>
+        <li>Write and modify <RT·code>authored/</RT-code> source.</li>
+        <li>Run builds and place artifacts in <RT·code>scratchpad/made</RT-code>, then execute the <RT·code>promote write</RT-code> script to copy artifacts to <RT·code>consumer/made</RT-code> for testing.</li>
+        <li>Run experiments in <RT·code>experiment/</RT-code>. These experiments can sometimes be promoted to formal tests, but there is no requirement to do so. The developer role should not blur into the tester role; experiments are informal, whereas tests are formal and retained.</li>
+        <li><strong>Strict Boundary:</strong> A developer never writes into the <RT·code>tester/</RT-code> directory. Instead, a developer adds tests to <RT·code>developer/experiment/</RT-code> and offers to share them.</li>
       </ol>
 
       <h3>Tester role</h3>
       <p>Responsibilities and Boundaries:</p>
       <ol>
-        <li>Evaluate candidates under <RT-code>consumer/made/</RT-code> and run regression suites to confirm:
+        <li>Evaluate candidates under <RT·code>consumer/made/</RT-code> and run regression suites to confirm:
           <ul>
             <li>That the code does not crash.</li>
             <li>That consumers do not have a bad experience.</li>
           </ul>
         </li>
         <li>File issues and communicate feedback to the developers.</li>
-        <li><strong>Strict Boundary:</strong> A tester never patches code in the <RT-code>developer/</RT-code> directory. Instead, the tester files issues or proposes code fixes on a separate branch.</li>
+        <li><strong>Strict Boundary:</strong> A tester never patches code in the <RT·code>developer/</RT-code> directory. Instead, the tester files issues or proposes code fixes on a separate branch.</li>
       </ol>
 
       <h3>Consumer role</h3>
       <p>Responsibilities:</p>
       <ol>
         <li>Act as the end-user simulation environment.</li>
-        <li>Consume and deploy artifacts exclusively from the <RT-code>consumer/made/</RT-code> target.</li>
+        <li>Consume and deploy artifacts exclusively from the <RT·code>consumer/made/</RT-code> target.</li>
         <li>Never author or modify code; strictly run local builds or deployments for architecture-specific testing.</li>
         <li>Report issues. (Anyone can report an issue, and consumers regularly do).</li>
       </ol>
 
       <h2>External roles</h2>
       <p>
-        These roles drive the project forward but do not have a dedicated <RT-code>setup &lt;role&gt;</RT-code> workspace, as they do not directly build or test the code in that capacity. If these individuals need to interface with the code, they simply put on a workspace role hat, such as administer, developer, tester, or consumer.
+        These roles drive the project forward but do not have a dedicated <RT·code>setup &lt;role&gt;</RT-code> workspace, as they do not directly build or test the code in that capacity. If these individuals need to interface with the code, they simply put on a workspace role hat, such as administer, developer, tester, or consumer.
       </p>
 
       <h3>Product manager</h3>
 
       <h1>Promotion mechanics</h1>
       <p>
-        Building and promotion are separate activities. The developer compiles and places files in <RT-code>developer/scratchpad/made</RT-code>. The developer then runs <RT-code>promote write</RT-code> to transfer those files to <RT-code>consumer/made</RT-code>. 
+        Building and promotion are separate activities. The developer compiles and places files in <RT·code>developer/scratchpad/made</RT-code>. The developer then runs <RT·code>promote write</RT-code> to transfer those files to <RT·code>consumer/made</RT-code>. 
       </p>
       <p>
-        The <RT-code>consumer/made</RT-code> directory is strictly an untracked deployment target. No tools are permitted to rebuild during promotion, and no builds are run directly inside the consumer made directory.
+        The <RT·code>consumer/made</RT-code> directory is strictly an untracked deployment target. No tools are permitted to rebuild during promotion, and no builds are run directly inside the consumer made directory.
       </p>
 
     </RT-article>
index 1f76dd0..3c5959a 100644 (file)
@@ -9,14 +9,14 @@
     </script>
   </head>
   <body>
-    <RT-article>
-      <RT-title 
+    <RT·article>
+      <RT·title 
         author="Thomas Walker Lynch" 
         date="2026-03-10" 
         title="Product maintenance roles and workflow">
       </RT-title>
 
-      <RT-TOC level="1"></RT-TOC>
+      <RT·TOC level="1"></RT-TOC>
 
       <h1>Maintenance philosophy</h1>
       <p>
@@ -39,7 +39,7 @@
       </p>
 
       <p>
-        The tester team develops and maintains the <RT-term>regression suite</RT-term>, the <RT-term>reliability suite</RT-term>, and <RT-term>additional tests</RT-term>.
+        The tester team develops and maintains the <RT·term>regression suite</RT-term>, the <RT·term>reliability suite</RT-term>, and <RT·term>additional tests</RT-term>.
       </p>
 
       <p>
@@ -69,7 +69,7 @@
 
       <h2>Core developer queue</h2>
       <p>
-        This queue serves the <RT-code>core_developer_branch</RT-code>. A <RT-term>tester</RT-term> writes a test for every issue reported in this queue. Doing so isolates the defect, proves the fix, and guards against future regressions.
+        This queue serves the <RT·code>core_developer_branch</RT-code>. A <RT·term>tester</RT-term> writes a test for every issue reported in this queue. Doing so isolates the defect, proves the fix, and guards against future regressions.
       </p>
 
       <h2>Released product queue</h2>
@@ -79,7 +79,7 @@
 
       <h1>Triage and patching</h1>
       <p>
-        Guided by the project philosophy, the triage team reviews each release queue issue to determine its impact. The team assesses whether the defect affects the <RT-code>core_developer_branch</RT-code>, assuming by default that it probably does. The team also determines if the defect is critical enough to warrant a patch on one or more active release branches.
+        Guided by the project philosophy, the triage team reviews each release queue issue to determine its impact. The team assesses whether the defect affects the <RT·code>core_developer_branch</RT-code>, assuming by default that it probably does. The team also determines if the defect is critical enough to warrant a patch on one or more active release branches.
       </p>
       <p>
         Based on this assessment, the triage team files actionable tickets in the core developer queue. A ticket explicitly specifies its target branches. A ticket will be filed against either the core developer branch, specific release branches, or a combination of both.
         Members of the tester team also file tickets directly into the core developer queue when they discover defects in the core branch.
       </p>
       <p>
-        Responsibility for resolving a ticket depends on its target. The core developer team addresses fixes required on the <RT-code>core_developer_branch</RT-code>. The branch maintenance team addresses fixes required on the <RT-code>release_v&lt;major&gt;</RT-code> branches.
+        Responsibility for resolving a ticket depends on its target. The core developer team addresses fixes required on the <RT·code>core_developer_branch</RT-code>. The branch maintenance team addresses fixes required on the <RT·code>release_v&lt;major&gt;</RT-code> branches.
       </p>
       <p>
-        When a release is patched, the branch name remains static. The administrator advances the minor release number in the <RT-code>shared/tool/version</RT-code> file and tags the commit.
+        When a release is patched, the branch name remains static. The administrator advances the minor release number in the <RT·code>shared/tool/version</RT-code> file and tags the commit.
       </p>
 
     </RT-article>