From: Thomas Walker Lynch
Date: Fri, 26 Jun 2026 11:21:03 +0000 (+0000)
Subject: . making layouts indpenedent general structure cleanup
X-Git-Url: https://git.reasoningtechnology.com/%28%5B%5E?a=commitdiff_plain;h=5685ebe84935b6f289cfd2343d514d8c07299d2b;p=RT-Style
. making layouts indpenedent general structure cleanup
---
diff --git a/developer/authored/Manuscript.copy/Core/document_loaded.js b/developer/authored/Manuscript.copy/Core/document_loaded.js
new file mode 100644
index 0000000..e12641d
--- /dev/null
+++ b/developer/authored/Manuscript.copy/Core/document_loaded.js
@@ -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();
+ }
+};
diff --git a/developer/authored/Manuscript.copy/Core/loader.js b/developer/authored/Manuscript.copy/Core/loader.js
index 83a420b..171e6d3 100644
--- a/developer/authored/Manuscript.copy/Core/loader.js
+++ b/developer/authored/Manuscript.copy/Core/loader.js
@@ -1,31 +1,309 @@
-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
index 87a452f..0000000
--- a/developer/authored/Manuscript.copy/Core/utility.js
+++ /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');
- }
-};
diff --git a/developer/authored/Manuscript.copy/Document/manual.html b/developer/authored/Manuscript.copy/Document/manual.html
index 0e34504..9545d07 100644
--- a/developer/authored/Manuscript.copy/Document/manual.html
+++ b/developer/authored/Manuscript.copy/Document/manual.html
@@ -8,14 +8,7 @@
-
+
diff --git a/developer/authored/Manuscript.copy/Layout/article_tech_ref.js b/developer/authored/Manuscript.copy/Layout/article_tech_ref.js
index 2bd381d..ffc9420 100644
--- a/developer/authored/Manuscript.copy/Layout/article_tech_ref.js
+++ b/developer/authored/Manuscript.copy/Layout/article_tech_ref.js
@@ -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.");
}
}
@@ -31,11 +25,10 @@
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"
@@ -78,20 +71,17 @@
,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
index 9550a98..0000000
--- a/developer/authored/Manuscript.copy/Theme/dark_gold.js
+++ /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
index 0000000..acc509f
--- /dev/null
+++ b/developer/authored/Manuscript.copy/Theme/golden_wheat.js
@@ -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
index 0000000..53c356d
--- /dev/null
+++ b/developer/authored/Manuscript.copy/Theme/inverse_wheat.js
@@ -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
index d0e80eb..0000000
--- a/developer/authored/Manuscript.copy/Theme/light.js
+++ /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
index 3136934..0000000
--- a/developer/authored/Manuscript.copy/Theme/light_gold.js
+++ /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
index 0000000..2571cd8
--- /dev/null
+++ b/developer/authored/Manuscript.copy/Theme/wheat.js
@@ -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);
+ }
+ };
+})();
diff --git a/document/introduction_Harmony.html b/document/introduction_Harmony.html
index 2399686..1eec838 100644
--- a/document/introduction_Harmony.html
+++ b/document/introduction_Harmony.html
@@ -9,14 +9,14 @@
-
-
+
-
+
- As of the time of this writing, the defined roles are: administrator, consumer, developer, and tester. A person takes on a role by sourcing the top-level setup script and giving the target role as an argument. For example, in a bash shell with > as the prompt, the command is:
+ As of the time of this writing, the defined roles are: administrator, consumer, developer, and tester. A person takes on a role by sourcing the top-level setup script and giving the target role as an argument. For example, in a bash shell with > as the prompt, the command is:
-
+
> . setup <role>
@@ -70,7 +70,7 @@
Specifically for the developer role:
-
+
> . setup developer
@@ -78,42 +78,42 @@
For the administrator role:
-
+
> . setup administrator
- Instead of starting with a period, the source command can be spelled out explicitly, for example:
+ Instead of starting with a period, the source command can be spelled out explicitly, for example:
-
+
> source setup tester
- Behind the scenes, the setup script performs the following actions:
+ Behind the scenes, the setup script performs the following actions:
- - Sources the project-wide setup (shared/tool/setup) to establish the core environment variables (e.g., REPO_HOME and PROJECT).
- - Conditionally sources shared/authored/setup (if present) to apply administrator-injected, project-specific tool configurations.
- - Dynamically sources all .init files found in the shared/linked-project/ directory.
- - Configures the PATH to include shared tools, library environments, and the specific <role>/tool directory.
+ - Sources the project-wide setup (shared/tool/setup) to establish the core environment variables (e.g., REPO_HOME and PROJECT).
+ - Conditionally sources shared/authored/setup (if present) to apply administrator-injected, project-specific tool configurations.
+ - Dynamically sources all .init files found in the shared/linked-project/ directory.
+ - Configures the PATH to include shared tools, library environments, and the specific <role>/tool directory.
- Changes the working directory into the specified role's workspace.
- - Sources the <role>/tool/setup 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.
+ - Sources the <role>/tool/setup 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.
After git clone
- Because git does not track certain artifact directories (such as consumer/ 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 consumer/ outputs), a freshly cloned repository lacks external dependencies and consumable products. Team members must perform a few steps to populate these areas.
Third-party tools
- 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 shared/linked-project 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 shared/linked-project directory via the `.init` plugin system.
- 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 administrator/document directory. The standard installation method is to clone the external tool into the parent directory alongside the project, create a symlink to it under shared/linked-project/ using the project/ parent link, and supply an .init 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 administrator/document directory. The standard installation method is to clone the external tool into the parent directory alongside the project, create a symlink to it under shared/linked-project/ using the project/ parent link, and supply an .init script to manage the local environment variables.
Consumer build
@@ -121,10 +121,10 @@
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.
- 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 consumer/ 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 consumer/ directory.
- To facilitate this, the developer must explicitly document the project's build and promote procedure, saving this guide as developer/document/build.html. The consumer must then read this document and execute the described steps to locally populate their consumer/ directory.
+ To facilitate this, the developer must explicitly document the project's build and promote procedure, saving this guide as developer/document/build.html. The consumer must then read this document and execute the described steps to locally populate their consumer/ directory.
@@ -132,19 +132,19 @@
- - > bash
- - > cd <project>
- - > . setup developer
- - > build <namespace>
- - > promote write
- - > exit
- - > bash
- - > cd <project>
- - > . setup <role>
+ - > bash
+ - > cd <project>
+ - > . setup developer
+ - > build <namespace>
+ - > promote write
+ - > exit
+ - > bash
+ - > cd <project>
+ - > . setup <role>
- 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 exit command drops the developer role. The last two lines put the person into the <role> 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 exit command drops the developer role. The last two lines put the person into the <role> workspace, typically for testing or deploying.
@@ -153,10 +153,10 @@
This section discusses our thinking in naming the files and directories found in the Harmony skeleton.
- A directory name is considered to be a property 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 property given to each file contained in the directory. A full path then forms a semantic sentence describing each file.
- 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 test.
+ 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 test.
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.
@@ -165,41 +165,41 @@
The following list presents each property type in order of preference when naming directories:
- - Role Association (administrator, developer, tester, consumer): Identifies the persona, whether human or AI, intended to interact with the files.
- - Provenance (authored, made): Indicates whether the file was created by an intellect or mechanically produced by a tool.
- - Capability (tool, document, experiment): Describes the primary function or structural nature of the file.
- - Lifecycle State (scratchpad, stage): Denotes the persistence, volatility, or promotion status of the file.
- - Tracking Status (tracked, untracked): Specifies the version control expectations for the artifacts.
+ - Role Association (administrator, developer, tester, consumer): Identifies the persona, whether human or AI, intended to interact with the files.
+ - Provenance (authored, made): Indicates whether the file was created by an intellect or mechanically produced by a tool.
+ - Capability (tool, document, experiment): Describes the primary function or structural nature of the file.
+ - Lifecycle State (scratchpad, stage): Denotes the persistence, volatility, or promotion status of the file.
+ - Tracking Status (tracked, untracked): Specifies the version control expectations for the artifacts.
Authored, made, scratchpad, inherited
- Files found in a directory named authored 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 authored directories as strictly read-only. Typically these files constitute the intellectual property of a project.
+ Files found in a directory named authored 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 authored directories as strictly read-only. Typically these files constitute the intellectual property of a project.
- All source code that gets built into a promotion or project release must be placed in the developers' authored 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 developer/tool/build file.
+ All source code that gets built into a promotion or project release must be placed in the developers' authored 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 developer/tool/build file.
- When the Harmony version line in the shared/tool/version 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 shared/tool/version 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.
- Files found in a directory named scratchpad are not tracked. Hence, a git clone will always return empty scratchpad 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, scratchpad. Pay attention as one of its commands is clear, and that deletes everything on the current directory's scratchpad.
+ Files found in a directory named scratchpad are not tracked. Hence, a git clone will always return empty scratchpad 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, scratchpad. Pay attention as one of its commands is clear, and that deletes everything on the current directory's scratchpad.
- Third party software is installed under shared/linked-project. Other files are said to be inherited, or to be customizations.
+ Third party software is installed under shared/linked-project. Other files are said to be inherited, or to be customizations.
Top-level repository layout
- A team member will source the project setup file to take on a role. As of this writing, the supported roles are: administrator, developer, tester, and consumer.
+ A team member will source the project setup file to take on a role. As of this writing, the supported roles are: administrator, developer, tester, and consumer.
- - administrator/ : Project-local tools and skeleton maintenance.
- - developer/ : Primary workspace for developers.
- - tester/ : Regression and validation workspace for testers.
- - consumer/ : Consumption workspace acting as the final artifact sink.
- - shared/ : Shared ecosystem tools and global environments.
+ - administrator/ : Project-local tools and skeleton maintenance.
+ - developer/ : Primary workspace for developers.
+ - tester/ : Regression and validation workspace for testers.
+ - consumer/ : Consumption workspace acting as the final artifact sink.
+ - shared/ : Shared ecosystem tools and global environments.
The administrator work area
@@ -209,29 +209,29 @@
The developer work area
- This directory is entered by first going to the top-level directory of the project, then sourcing . setup developer.
+ This directory is entered by first going to the top-level directory of the project, then sourcing . setup developer.
- - authored/ : Human-written source. Tracked by Git.
- - made/ : Tracked artifacts generated by tools (e.g., links to CLI entry points).
- - experiment/ : Try-it-here code. Short-lived spot testing.
- - scratchpad/ : Git-ignored directory. Holds all intermediate build outputs, including the staged namespace directories for promotions.
- - tool/ : Developer-specific tools (like the promote and build scripts).
+ - authored/ : Human-written source. Tracked by Git.
+ - made/ : Tracked artifacts generated by tools (e.g., links to CLI entry points).
+ - experiment/ : Try-it-here code. Short-lived spot testing.
+ - scratchpad/ : Git-ignored directory. Holds all intermediate build outputs, including the staged namespace directories for promotions.
+ - tool/ : Developer-specific tools (like the promote and build scripts).
The tester work area
- This directory is dedicated to formal testing, including regression suites. While a developer can run and keep informal spot tests in their experiment/ 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 experiment/ directory, any experiment promoted to a formal test is moved here. This enforces the boundary between writing code and validating it.
The shared tree
- 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 .init scripts required by the project. To assist in project specific modifications to the Harmony skeleton, Harmony comes with an empty shared/authored directory that is listed earlier in the executable search path than shared/tool.
+ 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 .init scripts required by the project. To assist in project specific modifications to the Harmony skeleton, Harmony comes with an empty shared/authored directory that is listed earlier in the executable search path than shared/tool.
The consumer tree
- The consumer/ 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 consumer/ tree only when the promote script is invoked, which performs a flat-copy from the developer's scratchpad/made directory.
+ The consumer/ 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 consumer/ tree only when the promote script is invoked, which performs a flat-copy from the developer's scratchpad/made directory.
Document directories
@@ -239,23 +239,23 @@
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.
- - document/ : Top-level onboarding, project-wide structure, such as this document.
- - consumer/<namespace>/document/ : Documentation for end-users of made code (e.g., man pages, application manuals, library API references).
- - administrator/document/ : Documentation for maintaining the project skeleton and global tools.
- - developer/document/ : Documentation for developers, including coding standards and internal API guides.
- - tester/document/ : Documentation for testers detailing test plans and tools.
- - shared/document/ : Documentation on installing and configuring shared tools.
+ - document/ : Top-level onboarding, project-wide structure, such as this document.
+ - consumer/<namespace>/document/ : Documentation for end-users of made code (e.g., man pages, application manuals, library API references).
+ - administrator/document/ : Documentation for maintaining the project skeleton and global tools.
+ - developer/document/ : Documentation for developers, including coding standards and internal API guides.
+ - tester/document/ : Documentation for testers detailing test plans and tools.
+ - shared/document/ : Documentation on installing and configuring shared tools.
- Currently, our developers write documents directly in HTML using the RT semantic tags. See the RT-Style project and the documentation there. A common approach is to copy another document and the setup.js 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-Style project and the documentation there. A common approach is to copy another document and the setup.js file, then to type over the top of that other document.
Untracked directories
- - consumer/ (Excluding the base .gitignore)
- - shared/linked-project/ (Excluding .init and .gitignore files)
- - **/scratchpad/
+ - consumer/ (Excluding the base .gitignore)
+ - shared/linked-project/ (Excluding .init and .gitignore files)
+ - **/scratchpad/
Workflow
@@ -263,21 +263,21 @@
Developer promotion and project releases
- As a first step, a developer creates a promotion candidate inside of the consumer/ directory. This is typically done by running build to stage the artifacts into scratchpad/made, followed by running promote write. 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 promotion.
+ As a first step, a developer creates a promotion candidate inside of the consumer/ directory. This is typically done by running build to stage the artifacts into scratchpad/made, followed by running promote write. 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 promotion.
- Then the tester runs tests on the promotion candidate. Tests must only read from the consumer/ 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 consumer/ directory, though local copies can be made and edited as experiments.
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.
- When the product manager determines the work product to be sufficiently reliable and feature rich, the administrator will make a project release. He will do this by creating a branch called release_v<major> 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 project release. He will do this by creating a branch called release_v<major> and tagging it. The major release numbers go up incrementally.
The Harmony directory tree
-
+
2026-06-23 13:41:45 Z [Harmony:administrator] Thomas_developer@StanleyPark
§/home/Thomas/subu_data/developer/project§
> tree Harmony
diff --git a/document/role-and-workflow_product-development.html b/document/role-and-workflow_product-development.html
index 2a4f655..d9a13e6 100644
--- a/document/role-and-workflow_product-development.html
+++ b/document/role-and-workflow_product-development.html
@@ -9,14 +9,14 @@
-
-
+
-
+
Roles as hats
@@ -27,7 +27,7 @@
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:
-
+
> . setup administrator
> . setup developer
> . setup tester
@@ -41,23 +41,23 @@
Responsibilities:
- Set up the project directory and keep it in sync with the Harmony skeleton.
- - Maintain role environments (apart from role-specific tool/setup files).
+ - Maintain role environments (apart from role-specific tool/setup
files).
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.
Developer role
Responsibilities and Boundaries:
- - Write and modify authored/ source.
- - Run builds and place artifacts in scratchpad/made, then execute the promote write script to copy artifacts to consumer/made for testing.
- - Run experiments in experiment/. 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.
- - Strict Boundary: A developer never writes into the tester/ directory. Instead, a developer adds tests to developer/experiment/ and offers to share them.
+ - Write and modify authored/
source.
+ Run builds and place artifacts in scratchpad/made, then execute the promote write script to copy artifacts to consumer/made for testing.
+ Run experiments in experiment/. 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.
+ Strict Boundary: A developer never writes into the tester/ directory. Instead, a developer adds tests to developer/experiment/ and offers to share them.
Tester role
Responsibilities and Boundaries:
- - Evaluate candidates under consumer/made/ and run regression suites to confirm:
+
- Evaluate candidates under consumer/made/ and run regression suites to confirm:
- That the code does not crash.
- That consumers do not have a bad experience.
@@ -65,21 +65,21 @@
- File issues and communicate feedback to the developers.
- - Strict Boundary: A tester never patches code in the developer/ directory. Instead, the tester files issues or proposes code fixes on a separate branch.
+ - Strict Boundary: A tester never patches code in the developer/ directory. Instead, the tester files issues or proposes code fixes on a separate branch.
Consumer role
Responsibilities:
- Act as the end-user simulation environment.
- - Consume and deploy artifacts exclusively from the consumer/made/ target.
+ - Consume and deploy artifacts exclusively from the consumer/made/ target.
- Never author or modify code; strictly run local builds or deployments for architecture-specific testing.
- Report issues. (Anyone can report an issue, and consumers regularly do).
External roles
- These roles drive the project forward but do not have a dedicated setup <role> 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 setup <role> 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.
Product manager
@@ -111,10 +111,10 @@
Promotion mechanics
- Building and promotion are separate activities. The developer compiles and places files in developer/scratchpad/made. The developer then runs promote write to transfer those files to consumer/made.
+ Building and promotion are separate activities. The developer compiles and places files in developer/scratchpad/made. The developer then runs promote write to transfer those files to consumer/made.
- The consumer/made 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 consumer/made 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.
diff --git a/document/role-and-workflow_product-maintenance.html b/document/role-and-workflow_product-maintenance.html
index 1f76dd0..3c5959a 100644
--- a/document/role-and-workflow_product-maintenance.html
+++ b/document/role-and-workflow_product-maintenance.html
@@ -9,14 +9,14 @@
-
-
+
-
+
Maintenance philosophy
@@ -39,7 +39,7 @@
- The tester team develops and maintains the regression suite, the reliability suite, and additional tests.
+ The tester team develops and maintains the regression suite, the reliability suite, and additional tests.
@@ -69,7 +69,7 @@
Core developer queue
- This queue serves the core_developer_branch. A tester 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 core_developer_branch. A tester writes a test for every issue reported in this queue. Doing so isolates the defect, proves the fix, and guards against future regressions.
Released product queue
@@ -79,7 +79,7 @@
Triage and patching
- 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 core_developer_branch, 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 core_developer_branch, 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.
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.
@@ -88,10 +88,10 @@
Members of the tester team also file tickets directly into the core developer queue when they discover defects in the core branch.
- Responsibility for resolving a ticket depends on its target. The core developer team addresses fixes required on the core_developer_branch. The branch maintenance team addresses fixes required on the release_v<major> branches.
+ Responsibility for resolving a ticket depends on its target. The core developer team addresses fixes required on the core_developer_branch. The branch maintenance team addresses fixes required on the release_v<major> branches.
- When a release is patched, the branch name remains static. The administrator advances the minor release number in the shared/tool/version file and tags the commit.
+ When a release is patched, the branch name remains static. The administrator advances the minor release number in the shared/tool/version file and tags the commit.