<h1>Prerequisites</h1>
<p>
- A release requires a tested promotion candidate. The developer compiles the code and promotes it to the <RT-code>consumer/made</RT-code> directory. The tester validates the candidate. The product manager gives the order to release.
+ A developer works in the developer branch of the project, and makes use of the <RT-code>build</RT-code> and <RT-code>promote</RT> tools to stage release candidates into the <RT-code>$REPO_HOME/consumer</RT-code> directory. The <RT-code>tester</RT-code> then validates the release candidate. This constitutes a cycle of work, developing, promoting candidates, testing, and then further developing. Once the project manager agrees this cycle is complete, the release flow moves to the next step.
</p>
<h1>Create the release branch</h1>
--- /dev/null
+#+TITLE: Python Installation Guide
+#+AUTHOR: Project Administrator
+
+This project requires a dedicated Python environment. The configuration plugin (`shared/linked-project/Python.init`) was written targeting Python 3.12.3, though the architecture does not rely on any known version-dependent features.
+
+* 1. Download and Extract
+Download the Python source code and extract it as a sibling to the main project directory. Assuming you are at the top level of your project workspace:
+
+#+begin_src bash
+cd ../
+wget https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz
+tar -xzf Python-3.12.3.tgz
+cd Python-3.12.3
+#+end_src
+
+* 2. Build the Environment
+Compile the Python binaries in place. Setting the installation prefix to the current directory isolates the build, and enabling shared libraries ensures compatibility with C extensions.
+
+#+begin_src bash
+./configure --prefix="$(pwd)" --enable-optimizations --enable-shared
+make -j8
+make install
+#+end_src
+
+* 3. Link the Project
+
+Python-3.12.3 is linked to a Harmony derived project by default.
+
+See installation_generic.org for details about linking a project, if you want to check the setup.
+
+If you are installing a different version, then at least the Python-3.12.3 version project linking is there as a good example.
+
+Project linking is not difficult, make a sym link to `project/<linked-project>`, and then add an init file, that is described in installation_generic.org. The 'project' in the link is literal.
+
+
+
+
+
--- /dev/null
+#+TITLE: Generic Third-Party Installation Guide
+#+AUTHOR: Project Administrator
+
+This project utilizes the Harmony skeleton's `.init` architecture for managing external dependencies. Third-party tools and projects are maintained outside the main repository boundary and linked into the workspace.
+
+* 1. The Neighbor Directory
+Download, clone, or extract the external tool into the same parent directory that contains this project workspace. It must sit as a sibling directory to your current project.
+
+* 2. The Symlink
+Navigate to the `$REPO_HOME/shared/linked-project` directory. You will notice a pre-existing symlink named `project` that points to the parent directory of this project. Use that to create a clean symlink to the external tool.
+
+#+begin_src bash
+cd shared/linked-project
+ln -s project/<external_tool_directory> <link_name>
+#+end_src
+
+* 3. The Initialization File
+Create a configuration file named `<link_name>.init` inside the `$REPO_HOME/shared/linked-project/` directory. This file is automatically sourced when a project participate enters their role environment using `. setup <role>` as part of the project setup. Use this file to update the `PATH` or export necessary environment variables needed for using the linked project.
+
+Review existing `.init` files in the directory for structural examples.
+
+++ /dev/null
-#+TITLE: Installing Python in Harmony
-#+AUTHOR: Thomas Walker Lynch
-#+OPTIONS: toc:2 num:nil
-
-* Overview
-
-This document describes how to install a project-local Python environment under:
-
-#+begin_src bash
-shared/linked-project/Python
-#+end_src
-
-* Precondition
-
-Ensure the following:
-
-- You are in a POSIX shell with =python3= installed.
-- The =python3-venv= package is available (on Debian: =sudo apt install python3-venv=).
-- You have sourced the Harmony environment via =env_toolsmith= to initialize =REPO_HOME= and related variables.
-
-* Step-by-Step Installation
-
-1. Source the Harmony environment:
- #+begin_src bash
- source env_toolsmith
- #+end_src
-
-2. Create the virtual environment:
- #+begin_src bash
- python3 -m venv "$REPO_HOME/shared/linked-project/Python"
- #+end_src
-
-3. Activate it temporarily to install required packages:
- #+begin_src bash
- source "$REPO_HOME/shared/linked-project/Python/bin/activate"
- pip install --upgrade pip
- pip install pytest # Add any shared packages here
- deactivate
- #+end_src
-
-4. Rename Python's default activate and deactivate:
- Harmony provides its own role-aware environment management. Using Python’s default activation scripts may interfere with prompt logic, PATH order, and role-specific behavior.
-
- Disable the default scripts by renaming them:
- #+begin_src bash
- mv "$REPO_HOME/shared/linked-project/Python/bin/activate" \
- "$REPO_HOME/shared/linked-project/Python/bin/activate_deprecated"
- #+end_src
-
- This ensures that accidental sourcing of Python’s =activate= script won't override Harmony's environment setup.
-
-5. Verify installation:
- #+begin_src bash
- ls "$REPO_HOME/shared/linked-project/Python/bin/python3"
- #+end_src
-
- The binary should exist and report a working Python interpreter when run.
-
-* Notes
-
-- The virtual environment is deliberately named =Python=, not =venv=, to reflect its role as a shared system component.
-- Harmony environment scripts define and control =VIRTUAL_ENV=, =PYTHON_HOME=, and =PATH=, making Python activation seamless and uniform.
-- There is no need to use Python’s =bin/activate= directly — it is fully replaced by Harmony’s environment logic.
-
-* Related Files
-
-- =shared/authored/env=
-- =shared/authored/env_source=
-- =env_developer=, =env_tester=, =env_toolsmith=
-
-* Last Verified
-
-2025-05-19 :: Activate/deactivate renamed post-install. Requires Harmony environment sourcing prior to execution.
+++ /dev/null
-
-This is the generic install.org doc that comes with the skeleton.
-
-1. $REPO_HOME/shared/linked-project/.gitignore:
-
- *
- !/.gitignore
- !/patch
-
- The only things from the third party directory that will be pushed to the repo origin is the .gitignore file and the patches.
-
-
-2. downloaded tar files etc. go into the directory `upstream`
-
- $REPO_HOME/shared/upstream
-
- Typically the contents of upstream are deleted after the install.
-
-3. for the base install
-
- cd $REPO_HOME/shared/linked-project
- do whatever it takes to install tool, as examples:
- git clone <tool_path>
- tar -xzf ../upstream/tar
- ...
-
- Be sure to add the path to the tool executable(s) in the $REPO_HOME/env_$ROLE files for the $ROLE who uses the tool.
-
- Assuming you are not also developing the tool, for safety
- change each installed git project to a local branch:
-
- b=<site>_<project>_local_$USER
- git switch -c "$b"
-
-
-4. Define some variables to simplify our discussion. Lowercase variable names
- are not exported from the shell.
-
- # already set in the environment
- # REPO_HOME
- # PROJECT
- # USER
-
- # example tool names: 'RT_gcc' 'RT-project share` etc.
- tool=<tool-name>
- tool_dpath="$REPO_HOME/shared/linked-project/$tool"
- patch_dpath="$REPO_HOME/shared/patch/"
-
-
-5. create a patch series (from current vendor state → your local edits)
-
- # this can be repeated and will create an encompassing diff file
-
- # optionally crate a new branch after cloning the third party tool repo and work from there. You won't make any commits, but in case you plan to ever check the changes in, or have a the bad habit of doing ommits burned into your brain-stem, making a brnch will help.
-
- # make changes
-
- cd "$tool_dpath"
-
- # do your edits
-
- # Stage edits. Do not commit them!! Be sure you are in the third party
- # tool directory when doing `git add -A` and `git diff` commands.
- git add -A
-
- # diff the stage from the current repo to create the patch file
- git diff --staged > "$patch_dpath/$tool"
-
- # the diff file can be added to the project and checked in at the project level.
-
-
-6. how to apply an existing patch
-
- Get a fresh clone of the tool into $tool_dpath.
-
- cd "$tool_dpath"
- git apply "$patch_dpath/$tool"
-
- You can see what `git apply` would do by running
-
- git apply --check /path/to/your/patch_dpath/$tool
+++ /dev/null
-#!/usr/bin/env bash
-script_afp=$(realpath "${BASH_SOURCE[0]}")
-
-# Enforce execution for this administrative tool
-if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
- echo "$script_afp:: This script must be executed, not sourced."
- return 1
-fi
-
-# without this bash takes non-matching globs literally
-shopt -s nullglob
-
-# does not presume sharing or world permissions
-umask 0077
-
-# Ensure required environment variables exist
-if [[ -z "$REPO_HOME" || -z "$PROJECT" ]]; then
- echo "Error: REPO_HOME or PROJECT variables are undefined. Please source the setup administrator first."
- exit 1
-fi
-
-echo "Repository Home: $REPO_HOME"
-echo "Project Name: $PROJECT"
-
-# The scratchpad must exist at the top level of the project for scanning clarity
-scratchpad="$REPO_HOME"/scratchpad
-if [[ ! -d "$scratchpad" ]]; then
- echo "Error: scratchpad directory missing at $scratchpad"
- exit 1
-fi
-
-#--------------------------------------------------------------------------------
-# Python name/version
-#
-
-version=3.12.3
-Python_dn=Python-"$version"
-tarf="$Python_dn".tgz
-
-# Python install directory, sibling to this project
-Python_da="$(realpath "$REPO_HOME"/../)"/"$Python_dn"
-
-#--------------------------------------------------------------------------------
-
-# Verify if the requested Python version is already built
-if [[ -x "$Python_da/bin/python3" ]]; then
- echo "Python $version is already built and installed at $Python_da."
-else
- # Download only if the archive is absent
- wget -nc -P "$scratchpad" https://www.python.org/ftp/python/"$version"/"$tarf"
-
- # Extract into the scratchpad to prevent source and installation collisions
- source_dn="$scratchpad"/Python-src-"$version"
- mkdir -p "$source_dn"
- tar xzf "$scratchpad"/"$tarf" -C "$source_dn" --strip-components=1
-
- # Explicit error reporting prevents silent administrative failures
- cd "$source_dn" || {
- echo "Error: Failed to change directory to $source_dn. Extraction likely failed."
- exit 1
- }
-
- # Configure with developer baseline (--enable-shared) required for C extensions
- LDFLAGS="-Wl,-rpath=$Python_da/lib" ./configure --prefix="$Python_da" --enable-optimizations --enable-shared
-
- make -j8
- make install
-fi
-
-# Establish the versioned executable link
-link_dir="$REPO_HOME"/shared/linked-project
-mkdir -p "$link_dir"
-cd "$link_dir" || {
- echo "Error: Failed to navigate to linked-project directory at $link_dir"
- exit 1
-}
-
-if [[ ! -L "$Python_dn" ]]; then
- # The depth accurately escapes linked-project, shared, and REPO_HOME
- ln -s ../../../"$Python_dn"/ "$Python_dn"
- echo "Successfully created symlink for $Python_dn"
-else
- echo "The symlink for $Python_dn already exists."
-fi
-
-# --------------------------------------------------------------------------------
-# Path & Environment Configuration Plugin
-# --------------------------------------------------------------------------------
-path_sh="$REPO_HOME"/shared/tool/PATH.sh
-touch "$path_sh"
-
-# Define the cluster of variables required by the python plugin environment
-line_env="export VIRTUAL_ENV=\"\$REPO_HOME/shared/linked-project/$Python_dn\""
-line_home="export PYTHON_HOME=\"\$VIRTUAL_ENV\""
-line_unset="unset PYTHONHOME"
-line_path="PATH=\"\$VIRTUAL_ENV/bin:\$PATH\""
-
-# Append the variables sequentially if they are missing from the configuration file
-for line in "$line_env" "$line_home" "$line_unset" "$line_path"; do
- if ! grep -Fq "$line" "$path_sh"; then
- echo "$line" >> "$path_sh"
- echo "Appended plugin configuration line to PATH.sh."
- else
- echo "Configuration line already present in PATH.sh."
- fi
-done
-
--- /dev/null
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+import sys ,os ,filecmp
+from pathlib import Path
+
+def get_project_name(repo_path: Path) -> str:
+ return repo_path.resolve().name
+
+def CLI(argv=None) -> int:
+ if argv is None:
+ argv = sys.argv[1:]
+
+ if len(argv) != 2:
+ print("Usage: skeleton_diff <path_to_Harmony> <path_to_project>")
+ return 1
+
+ harmony_dir = Path(argv[0]).resolve()
+ project_dir = Path(argv[1]).resolve()
+
+ if not harmony_dir.is_dir() or not project_dir.is_dir():
+ print("Error: Both arguments must be valid directories." ,file=sys.stderr)
+ return 1
+
+ project_name = get_project_name(project_dir)
+
+ # Semantic boundaries: isolate the skeleton by ignoring user zones
+ IGNORED_DIRS = {".git" ,"scratchpad" ,"consumer" ,"authored" ,"__pycache__"}
+ IGNORED_EXTS = {".pyc" ,".pyo" ,".swp" ,".bak"}
+
+ def is_ignored(path_obj: Path) -> bool:
+ if path_obj.name in IGNORED_DIRS: return True
+ if path_obj.suffix in IGNORED_EXTS: return True
+ if path_obj.name.endswith("~"): return True
+ return False
+
+ harmony_files = set()
+ for TM_root ,TM_dirs ,TM_files in os.walk(harmony_dir):
+ TM_dirs[:] = [TM_d for TM_d in TM_dirs if not is_ignored(Path(TM_d))]
+ for TM_f in TM_files:
+ f_path = Path(TM_root) / TM_f
+ if not is_ignored(f_path):
+ rel_path = f_path.relative_to(harmony_dir)
+ harmony_files.add(str(rel_path))
+
+ project_files = set()
+ for TM_root ,TM_dirs ,TM_files in os.walk(project_dir):
+ TM_dirs[:] = [TM_d for TM_d in TM_dirs if not is_ignored(Path(TM_d))]
+ for TM_f in TM_files:
+ f_path = Path(TM_root) / TM_f
+ if not is_ignored(f_path):
+ rel_path = f_path.relative_to(project_dir)
+ project_files.add(str(rel_path))
+
+ # Map the dynamically generated Opus file
+ harmony_opus = "0pus_Harmony"
+ project_opus = f"0pus_{project_name}"
+
+ if project_opus in project_files:
+ project_files.remove(project_opus)
+ project_files.add(harmony_opus)
+
+ all_files = sorted(list(harmony_files | project_files))
+
+ drift_count = 0
+ for TM_rel in all_files:
+ if TM_rel not in project_files:
+ print(f"Missing in project: {TM_rel}")
+ drift_count += 1
+ elif TM_rel not in harmony_files:
+ print(f"Orphaned in project: {TM_rel}")
+ drift_count += 1
+ else:
+ h_abs = harmony_dir / TM_rel
+ p_abs = project_dir / TM_rel
+
+ if TM_rel == harmony_opus:
+ p_abs = project_dir / project_opus
+
+ if not filecmp.cmp(h_abs ,p_abs ,shallow=False):
+ print(f"Modified: {TM_rel}")
+ drift_count += 1
+
+ if drift_count == 0:
+ print("Skeleton is perfectly synchronized with Harmony.")
+ else:
+ print(f"\nTotal drift: {drift_count} files.")
+
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(CLI())
--- /dev/null
+# -*- mode: sh; sh-shell: bash; -*-
+# init files are bash script
+
+# Python.init
+# --------------------------------------------------------------------------------
+# Ensure the local Python build is prioritized in the PATH.
+# The user must establish the Python-3.12.3 symlink for this to activate.
+
+if [[ -d "$REPO_HOME/shared/linked-project/Python-3.12.3/bin" ]]; then
+ PATH="$REPO_HOME/shared/linked-project/Python-3.12.3/bin:$PATH"
+else
+ # Optional: Issue a quiet warning for the administrator role
+ if [[ "$ROLE" == "administrator" ]]; then
+ echo "Notice: Local Python-3.12.3 bin not found. Using system Python."
+ fi
+fi
--- /dev/null
+# -*- mode: sh; sh-shell: bash; -*-
+# init files are bash script
+
+# RT-Style.init
+# --------------------------------------------------------------------------------
+# Establishes aliases and environment variables for the semantic layout engine.
+# The user must establish the RT-Style -> ../../../RT-Style/consumer symlink.
+
+# If the RT-Style project provides command-line tools (e.g., in a 'tool' directory),
+# they would be prepended here. Otherwise, this serves as documentation.
+export RT_STYLE_HOME="$REPO_HOME/shared/linked-project/RT-Style"
+
+if [[ ! -d "$RT_STYLE_HOME/Manuscript" && "$ROLE" == "administrator" ]]; then
+ echo "Notice: RT-Style layout engine is not linked or built. HTML styling will fail."
+fi
}
clean_path
- # Sourcing is wrapped in a conditional guard to prevent failure on initial bootstrapping
- installed_tool_sh="$REPO_HOME/$(script_dp)/PATH.sh"
- if [[ -f "$installed_tool_sh" ]]; then
- source "$installed_tool_sh"
- fi
+ # Plugin Sourcing: Dynamically load all the linked project configurations
+ for init_file in "$REPO_HOME/shared/linked-project/"*.init; do
+ if [[ -f "$init_file" ]]; then
+ source "$init_file"
+ fi
+ done
export PATH