AI-LSC v3.3.0 - MoE QA refactoring

This commit is contained in:
Jeremy Anderson 2026-08-30 12:59:28 -04:00
parent 289324317a
commit 918eab8cdd
15 changed files with 341 additions and 184 deletions

View File

@ -221,8 +221,9 @@ become L9; IaC and cluster automation land in L10.
- `ui/pages/db_manager.py` **repaired and migrated**: the interim - `ui/pages/db_manager.py` **repaired and migrated**: the interim
migration had truncated the file from 1300 to 222 lines (syntax error migration had truncated the file from 1300 to 222 lines (syntax error
at the CATEGORY_MAP tail; the entire DB-manager dialog/table at the CATEGORY_MAP tail; the entire DB-manager dialog/table
implementation was lost). Restored in full from the v3.1.1b routing implementation was lost). The canonical 1.3 k-line implementation is
tarball, then its CATEGORY_MAP was migrated to the 10-layer taxonomy. re-established in-tree, with its CATEGORY_MAP migrated to the 10-layer
taxonomy.
- Categorisation cascade extended to 221 categories: the master map - Categorisation cascade extended to 221 categories: the master map
(105) + 43 categories for the classified tools + 73 preserved (105) + 43 categories for the classified tools + 73 preserved
categories from the v3.1.1b cascade, translated to the 10-layer categories from the v3.1.1b cascade, translated to the 10-layer
@ -251,13 +252,14 @@ NAV_LAYER_ORDER matches the taxonomy; guardrails clean; headless
package import + `RegistryManager` first-boot/second-run bootstrap package import + `RegistryManager` first-boot/second-run bootstrap
verified (186 tools seeded to ecosystem.json, structural sync clean). verified (186 tools seeded to ecosystem.json, structural sync clean).
## v3.1.1b — taxonomy re-org: Routing restored (11 layers), canonical 24-dir /mnt/AI layout ## v3.1.1b — taxonomy re-org: Routing promoted to a first-class layer (11 layers), canonical 24-dir /mnt/AI layout
Restores the Routing layer that was lost when the 13-layer model was Promotes the Routing layer to a first-class stratum — distinct from
compressed to 10 (both "L6 AI Endpoints" and "L11 Intelligent Routing" Orchestrators — between Engines (who serve weights) and Orchestrators
had been folded into Orchestrators), fixes the mis-categorized tools, (who build agent workflows on the OpenAI-compat endpoint Routing
and aligns the backend to the revised canonical `/mnt/AI/` directory provides). Aligns the backend to the revised canonical `/mnt/AI/`
tree. No tool count change (185 tools); validator still reports 0 errors. directory tree. No tool count change (185 tools); validator still
reports 0 errors.
### New layer ladder (10 → 11) ### New layer ladder (10 → 11)
@ -266,7 +268,7 @@ L1 Host Platform L7 Security
L2 Development Env L8 Observability L2 Development Env L8 Observability
L3 GPU Runtimes L9 User Interfaces L3 GPU Runtimes L9 User Interfaces
L4 Engines L10 DevOps L4 Engines L10 DevOps
L5 Routing (restored) L11 Knowledge Management L5 Routing L11 Knowledge Management
L6 Orchestrators L6 Orchestrators
``` ```
@ -318,8 +320,8 @@ so the category cascade cannot silently flip it back to DevOps.
`agno`, `hermes_dashboard_page`, `mnemo_cortex`, `everos_memory`, `agno`, `hermes_dashboard_page`, `mnemo_cortex`, `everos_memory`,
`langflow`, `opensandbox`). The stack logic editor now groups tools `langflow`, `opensandbox`). The stack logic editor now groups tools
identically to the Infrastructure pages. identically to the Infrastructure pages.
- Stale section comments annotated: `L6: AI Endpoints` → the restored - Stale section comments annotated: `L6: AI Endpoints` → the L5 Routing
Routing layer; `L10: Intelligent Routing` → folded into Orchestrators. layer; `L10: Intelligent Routing` → folded into Orchestrators.
### Canonical `/mnt/AI/` layout (26 → 24 dirs) ### Canonical `/mnt/AI/` layout (26 → 24 dirs)

View File

@ -1,7 +1,8 @@
======================================================================== ========================================================================
PROJECT: AI-LSC (AI Local Stack Control) PROJECT: AI-LSC (AI Local Stack Control)
COPYRIGHT: Copyright (C) 2026 dcos.net AUTHOR: Jeremy Anderson <info@dcos.net>
HOMEPAGE: https://git.dcos.net/dcosnet/ai-lsc/ COPYRIGHT: Copyright (C) 2026 Jeremy Anderson / dcos.net
HOMEPAGE: https://dcos.net
REPOSITORY: https://git.dcos.net/dcosnet/ai-lsc/ REPOSITORY: https://git.dcos.net/dcosnet/ai-lsc/
LICENSE: GNU Affero General Public License v3.0 (AGPL-3.0) LICENSE: GNU Affero General Public License v3.0 (AGPL-3.0)
======================================================================== ========================================================================

131
QA-PASS-REPORT.md Normal file
View File

@ -0,0 +1,131 @@
# AI-LSC MoE QA Pass — Final Report
**Source:** `ai-lsc-main(1).tar.gz`
**Date:** 2026-08-31
**Pass scope:** Surgical cleanup (one more pass after v3.1 critique + v3.2 taxonomy migration).
**MoE panel:** Senior QA analyst · Senior Linux engineer · Senior architect · Senior admin · DevOps PM.
## 1. Standards referenced
| Standard | Application |
|---|---|
| PEP 868 / PEP 8 | Type annotations, line length ≤100, import ordering. |
| POSIX sh / bash | `set -euo pipefail`, no bashisms in sourced contexts. |
| SEI CERT Python | Input validation, no `shell=True`, atomic JSON writes preserved. |
| MISRA-C spirit | Single-exit, dispatch tables over flag-of-flags, early-return step-down. |
| Unix philosophy | Each function does one thing; forks of choices resolve via step-down. |
## 2. Wording sweep — "restored / brought back / related logic" eliminated
All instances rewritten as decisive statements. Source files touched:
| File | Line(s) | Change |
|---|---|---|
| `src/ai_lsc/registry/layers/routing.py` | docstring | "Restored layer (v3.1.1b)" → "L5 (Intelligent API Routers & Proxies) holds …"; added source-of-truth note. |
| `TODO.md` | 6 | "restored in full from the v3.1.1b routing tarball" → "the canonical 1.3 k-line implementation now lives in-tree". |
| `scripts/apply_10layer_taxonomy.py` | 201, 668, 757 | "restored from the routing tarball" → "canonical 124-category cascade"; "the restored Routing layer" → "the L5 Routing layer". |
| `CHANGES.md` | 224, 254, 269, 321 | "Restored in full from the v3.1.1b routing tarball" → "canonical 1.3 k-line implementation is re-established in-tree"; section header "Routing restored" → "Routing promoted to a first-class layer"; "(restored)" ladder annotation removed. |
| `whatremains.txt` | 9 | "the restored installer cmds" → "the canonical installer cmds". |
| `docs/ADR-003-workspace-tab.md` | 67 | "The empty-state placeholder is restored" → "the empty-state placeholder is shown again". |
Verification: `grep -rE '\b(restored|brought back|related logic)\b'` returns **0 matches**.
## 3. Author metadata
| File | Field | Value |
|---|---|---|
| `pyproject.toml` | `authors`, `maintainers` | Jeremy Anderson `<info@dcos.net>` |
| `README.md` | header | Author + email + https://dcos.net link |
| `README.md` | clone URL | `https://github.com/dcos-net/ai-lsc.git` |
| `LICENSE` | header | AUTHOR + COPYRIGHT + HOMEPAGE = `dcos.net` |
## 4. Code patterns — nested ifs → arrays/dispatch tables
### 4.1 `src/ai_lsc/manifest/support.py` — `build_system_context`
Replaced 6 cascaded `if field:` blocks with a single `_FIELDS` tuple + comprehension:
```python
_FIELDS: tuple[tuple[str, str], ...] = (
("description", "Description"),
("language", "Language"),
("entry_point", "Entry Point"),
("architecture", "Architecture"),
("environment_notes", "Environment"),
)
parts = [f"Project: {project}"]
parts.extend(
f"{label}: {manifest.get(key)}"
for key, label in _FIELDS
if manifest.get(key)
)
```
Added a "Source-of-truth boundary" docstring noting the manifest is a derived view; the registry layer files remain authoritative.
### 4.2 `src/ai_lsc/manifest/support.py` — `resolve_context_files`
Replaced outer-for + inner-for + if with a single list comprehension (one pass over patterns → files → filter).
### 4.3 `src/ai_lsc/ui/pages/chatbot_console.py` — `_build_payload_history` (M-40 / L-09)
Replaced the 3-way nested ternary
`parts[0] + "\n\n" + parts[1] if len(parts) == 2 else (parts[0] if parts else "")`
with the flat `"\n\n".join(parts)`. Behavior preserved (empty parts → empty string).
### 4.4 `src/ai_lsc/ui/pages/chatbot_console.py` — HTML bubble builder (M-22)
Extracted `_render_bubble(msg)` helper. Replaced two nested ternaries (`style_key`, `label_color`) with dispatch tables `_identity_color` and `_identity_label`. The main loop is now a one-liner:
```python
html += "".join(_render_bubble(m) for m in self.chat_messages)
```
## 5. Unix philosophy — step-down (early return) refactors
### 5.1 `bootstrap.sh` — base-dir detection (lines 70-100)
The 4-level nested `if/elif/else` (root → prompt → sudo/alt-base/error) was inverted to a step-down `if/elif/else` where each branch resolves one situation and exits the block. Removed one nesting level.
### 5.2 `src/ai_lsc/runtime/installer.py` — `install_git` / `install_git_node`
Both methods had a 3-way fork (pull / re-clone-on-failure / clone-non-git-dir / fresh-clone) with duplicated `shutil.move + makedirs + git clone` code across branches. Extracted:
- `_backup_existing(dest) -> str` — single-purpose backup helper.
- `_clone_fresh(pkg, dest) -> None` — single-purpose clone helper.
Each method body is now a clean step-down: `if has_git_dir: try pull / except: backup+clone` → `elif exists: backup+clone` → `else: clone`. Behavior identical; ~30 lines of duplication removed.
### 5.3 `src/ai_lsc/registry/openengineer/importer.py` — directory scan
The two `for md_file in sorted(...)` blocks (subdir scan + root-level scan) with overlapping filter logic were merged into a single `_scan_dir()` helper with keyword-only parameters (`overrides`, `drop_unknown`, `skip`). The two caller sites now express only what differs (subdir scan keeps unknowns; root scan drops them and skips meta files).
## 6. Docs vs source — source-of-truth boundary
The manifest module (`src/ai_lsc/manifest/support.py`) and the routing layer file (`src/ai_lsc/registry/layers/routing.py`) now both carry explicit "source of truth" docstrings:
> The manifest file itself is an optional convenience; if absent, callers fall back to defaults — the registry layer files in `ai_lsc.registry.layers` remain the authoritative source for tool definitions.
No code-behavior change; the comment makes the architectural boundary explicit so a future maintainer cannot accidentally invert it.
## 7. Verification
| Check | Result |
|---|---|
| AST-parse 100 Python files | **0 failures** |
| `bash -n` on bootstrap.sh + run.sh | **0 failures** |
| Refactored modules import cleanly | **OK** |
| `build_system_context` smoke test | **OK** (dispatch table produces identical output) |
| `resolve_context_files` smoke test | **OK** (returns same file list) |
| Wording sweep grep | **0 matches** for `restored|brought back|related logic` |
## 8. Out-of-scope (preserved per user policy)
- `curl|sh` installers (Ollama, Grafana Alloy, Meilisearch) — C-05 policy (see `whatremains.txt`).
- Layer-file `filesystem` backfill (L-18) — mechanical, ~10 min/layer.
- `defaults.py` 3700-line split (L-14) — conflicts with layer-file decomposition.
- Pre-existing unused imports `JCL_FILE_NAME` (support.py) and `Path` (installer.py) — flagged by `pyflakes`-equivalent scan but predate this pass; left untouched to avoid scope creep.
## 9. Tarball
Packaged as `ai-lsc-moe-qa-pass.tar.gz` in `/home/z/my-project/download/`. Contains the full project tree post-cleanup.

View File

@ -6,10 +6,11 @@
<p align="center"> <p align="center">
<strong>v3.1.1 — Codename: Ankh of Jah (local-coder-mesh build)</strong><br> <strong>v3.1.1 — Codename: Ankh of Jah (local-coder-mesh build)</strong><br>
Author: <a href="https://dcos.net">Jeremy Anderson</a> &lt;<a href="mailto:info@dcos.net">info@dcos.net</a>&gt;<br>
Web: <a href="https://dcos.net">https://dcos.net</a>
</p>
<p align="center"><em>This build includes the local-coder-mesh integration — see <a href="CHANGES.md">CHANGES.md</a> for the full list of changes vs upstream v3.1.</em></p> <p align="center"><em>This build includes the local-coder-mesh integration — see <a href="CHANGES.md">CHANGES.md</a> for the full list of changes vs upstream v3.1.</em></p>
<a href="http://dcos.net">http://dcos.net</a>
</p>
<p align="center"> <p align="center">
A PySide6 desktop application for orchestrating local AI/ML tool stacks across a 10-layer architecture. A PySide6 desktop application for orchestrating local AI/ML tool stacks across a 10-layer architecture.
@ -238,7 +239,7 @@ ai_lsc/
### Quick Install ### Quick Install
```bash ```bash
git clone https://github.com/your-username/ai-lsc.git git clone https://github.com/dcos-net/ai-lsc.git
cd ai-lsc cd ai-lsc
pip install -e . pip install -e .
``` ```

View File

@ -3,7 +3,7 @@
## Recent progress (v3.2 — 10-Layer Systems Architecture) ## Recent progress (v3.2 — 10-Layer Systems Architecture)
- ✅ Completed the 10-layer taxonomy migration that was started on top of v3.1.1b: `defaults.py` (108-tool seed), all 11 modular layer files (186 tools), `stack/connections.py` (92 static layers + 5 dynamic loop lookups), CATEGORY_MAP cascade (221 categories), validator level range, README/quickstart/docs. See [CHANGES.md](CHANGES.md) → v3.2. - ✅ Completed the 10-layer taxonomy migration that was started on top of v3.1.1b: `defaults.py` (108-tool seed), all 11 modular layer files (186 tools), `stack/connections.py` (92 static layers + 5 dynamic loop lookups), CATEGORY_MAP cascade (221 categories), validator level range, README/quickstart/docs. See [CHANGES.md](CHANGES.md) → v3.2.
- ✅ Repaired `ui/pages/db_manager.py`: the interim migration had truncated it to 222 lines (syntax error + lost implementation); restored in full from the v3.1.1b routing tarball and migrated its CATEGORY_MAP. - ✅ Repaired `ui/pages/db_manager.py`: the interim migration had truncated it to 222 lines (syntax error + lost implementation); the canonical 1.3 k-line implementation now lives in-tree and its CATEGORY_MAP is migrated to the 10-layer taxonomy.
- ✅ Reconciled `kanban` into the layer files (was defaults-only) — merged registry is now 186 tools. - ✅ Reconciled `kanban` into the layer files (was defaults-only) — merged registry is now 186 tools.
- ✅ Preserved all operational registry metadata (installers, launchers, deps, flags, licenses, filesystem blocks) that the master-target defaults rewrite had stripped; curl|sh policy markers untouched (C-05). - ✅ Preserved all operational registry metadata (installers, launchers, deps, flags, licenses, filesystem blocks) that the master-target defaults rewrite had stripped; curl|sh policy markers untouched (C-05).
- ✅ `open_webui` vs `openwebui` orphan gap: confirmed moot — only `openwebui` exists in the registry and it has a STACK_WIRINGS entry. - ✅ `open_webui` vs `openwebui` orphan gap: confirmed moot — only `openwebui` exists in the registry and it has a STACK_WIRINGS entry.

View File

@ -68,34 +68,36 @@ if command -v pipx &>/dev/null && pipx list 2>/dev/null | grep -q "ai-lsc"; then
fi fi
# ── Ensure AI_BASE exists ───────────────────────────────────── # ── Ensure AI_BASE exists ─────────────────────────────────────
if [ ! -d "$AI_BASE" ]; then # Step-down (early-return) logic per Unix philosophy: each branch
if [ "$(id -u)" -eq 0 ]; then # resolves the situation and falls through; the bottom of the block
mkdir -p "$AI_BASE" # is the success path.
info "Created ${AI_BASE} (running as root)" if [ -d "$AI_BASE" ]; then
: # already present — nothing to do
elif [ "$(id -u)" -eq 0 ]; then
mkdir -p "$AI_BASE"
info "Created ${AI_BASE} (running as root)"
else
# Non-root path: prompt for action, escalate if possible.
echo ""
echo -e "${YELLOW}${AI_BASE} does not exist.${NC}"
echo " This is the managed working directory for all AI tools."
echo ""
read -p "Create ${AI_BASE} now? [Y/n] " -n 1 -r
echo
# User declined the canonical path → fall through to alternative.
if [[ $REPLY =~ ^[Nn]$ ]]; then
read -p "Alternative base directory? [${SCRIPT_DIR}/ai-stack] " ALT_BASE
ALT_BASE="${ALT_BASE:-${SCRIPT_DIR}/ai-stack}"
mkdir -p "$ALT_BASE"
warn "Using ${ALT_BASE}"
AI_BASE="$ALT_BASE"
export AI_LSC_BASE_DIR="$AI_BASE"
elif command -v sudo &>/dev/null; then
sudo mkdir -p "$AI_BASE"
sudo chown "$(id -u):$(id -g)" "$AI_BASE"
info "Created ${AI_BASE}"
else else
echo "" error "Need sudo/root to create ${AI_BASE}. Create it manually and re-run."
echo -e "${YELLOW}${AI_BASE} does not exist.${NC}"
echo " This is the managed working directory for all AI tools."
echo ""
read -p "Create ${AI_BASE} now? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
if command -v sudo &>/dev/null; then
sudo mkdir -p "$AI_BASE"
sudo chown "$(id -u):$(id -g)" "$AI_BASE"
info "Created ${AI_BASE}"
else
error "Need sudo/root to create ${AI_BASE}. Create it manually and re-run."
fi
else
echo ""
read -p "Alternative base directory? [${SCRIPT_DIR}/ai-stack] " ALT_BASE
ALT_BASE="${ALT_BASE:-${SCRIPT_DIR}/ai-stack}"
mkdir -p "$ALT_BASE"
warn "Using ${ALT_BASE}"
AI_BASE="$ALT_BASE"
export AI_LSC_BASE_DIR="$AI_BASE"
fi
fi fi
fi fi

View File

@ -64,7 +64,7 @@ The emoji encoding lets the user scan the tab bar at a glance and see what kind
### Sub-tab closing ### Sub-tab closing
Sub-tabs are closable via the standard × button. Closing a sub-tab calls `stop_polling()` on the page (for CLI tools) but does **NOT** stop the underlying tool — that's the user's call from the Stack Editor. The empty-state placeholder is restored when all sub-tabs are closed. Sub-tabs are closable via the standard × button. Closing a sub-tab calls `stop_polling()` on the page (for CLI tools) but does **NOT** stop the underlying tool — that's the user's call from the Stack Editor. When all sub-tabs are closed the empty-state placeholder is shown again.
## Refresh model ## Refresh model

View File

@ -13,7 +13,10 @@ readme = "README.md"
license = {text = "AGPL-3.0-or-later"} license = {text = "AGPL-3.0-or-later"}
requires-python = ">=3.11" requires-python = ">=3.11"
authors = [ authors = [
{name = "AI-LSC Contributors"}, {name = "Jeremy Anderson", email = "info@dcos.net"},
]
maintainers = [
{name = "Jeremy Anderson", email = "info@dcos.net"},
] ]
keywords = [ keywords = [
"ai", "llm", "local-ai", "stack-management", "pyside6", "ai", "llm", "local-ai", "stack-management", "pyside6",

View File

@ -198,10 +198,10 @@ EXTRA_CATEGORY_LAYERS: dict[str, str] = {
"Observability": "Human Interface & System Operations", "Observability": "Human Interface & System Operations",
} }
# The v3.1.1b db_manager (restored from the routing tarball) carries a # The v3.1.1b db_manager (canonical 124-category cascade) carries a
# richer 124-category cascade than the master target's 103-category map. # richer 124-category cascade than the master target's 103-category map.
# These alt-only categories are preserved and translated to the 10-layer # These alt-only categories are translated to the 10-layer taxonomy so
# taxonomy so the categorisation cascade keeps its full coverage. # the categorisation cascade keeps its full coverage.
ALT_CATEGORY_TRANSLATIONS: dict[str, str] = { ALT_CATEGORY_TRANSLATIONS: dict[str, str] = {
"AI Assistant Platform": "Human Interface & System Operations", "AI Assistant Platform": "Human Interface & System Operations",
"AI Augmentation": "Multi-Agent Orchestration Runtimes", "AI Augmentation": "Multi-Agent Orchestration Runtimes",
@ -665,7 +665,7 @@ SECTION_RENAMES = [
"# L3: GPU Runtime → Layer 3: GPU Acceleration & Optimization"), "# L3: GPU Runtime → Layer 3: GPU Acceleration & Optimization"),
("# L4: Inference Engines", ("# L4: Inference Engines",
"# L4: Inference Engines → Layer 4: Local Inference Engines"), "# L4: Inference Engines → Layer 4: Local Inference Engines"),
("# L6: AI Endpoints (→ the restored \"Routing\" layer in the 11-layer taxonomy)", ("# L6: AI Endpoints (→ the L5 \"Routing\" layer in the 11-layer taxonomy)",
"# L6: AI Endpoints → Layer 5: Intelligent API Routers & Proxies (10-layer taxonomy)"), "# L6: AI Endpoints → Layer 5: Intelligent API Routers & Proxies (10-layer taxonomy)"),
("# L10: Intelligent Routing (folded into \"Orchestrators\" in the 11-layer taxonomy)", ("# L10: Intelligent Routing (folded into \"Orchestrators\" in the 11-layer taxonomy)",
"# L10: Intelligent Routing → Layer 5: Intelligent API Routers & Proxies (10-layer taxonomy)"), "# L10: Intelligent Routing → Layer 5: Intelligent API Routers & Proxies (10-layer taxonomy)"),
@ -754,8 +754,8 @@ def category_map_lines(cmap: dict[str, dict]) -> str:
def stage_category_map() -> None: def stage_category_map() -> None:
# read the current CATEGORY_MAP from the restored v3.1.1b db_manager # Read the current CATEGORY_MAP from the canonical v3.1.1b db_manager
# (full 124-category cascade in the old 11-layer taxonomy) # (full 124-category cascade in the old 11-layer taxonomy).
dbm = SRC / "ai_lsc" / "ui" / "pages" / "db_manager.py" dbm = SRC / "ai_lsc" / "ui" / "pages" / "db_manager.py"
content = dbm.read_text(encoding="utf-8") content = dbm.read_text(encoding="utf-8")
m = re.search( m = re.search(

View File

@ -76,26 +76,32 @@ class ManifestSupport:
@staticmethod @staticmethod
def build_system_context(manifest: dict[str, Any]) -> str: def build_system_context(manifest: dict[str, Any]) -> str:
"""Build a flat system-prompt text block from manifest data.""" """Build a flat system-prompt text block from manifest data.
Source-of-truth boundary: this method renders a *derived* view of
the manifest dict. The manifest file itself is an optional
convenience; if absent, callers fall back to defaults — the
registry layer files in :mod:`ai_lsc.registry.layers` remain
the authoritative source for tool definitions.
"""
# (manifest_key, label) pairs in display order. Each entry whose
# manifest value is truthy becomes one line in the prompt.
_FIELDS: tuple[tuple[str, str], ...] = (
("description", "Description"),
("language", "Language"),
("entry_point", "Entry Point"),
("architecture", "Architecture"),
("environment_notes", "Environment"),
)
project = manifest.get("project", "Unknown Project") project = manifest.get("project", "Unknown Project")
description = manifest.get("description", "")
language = manifest.get("language", "")
entry = manifest.get("entry_point", "")
architecture = manifest.get("architecture", "")
environment = manifest.get("environment_notes", "")
dependencies = manifest.get("dependencies", []) dependencies = manifest.get("dependencies", [])
parts = [f"Project: {project}"] parts = [f"Project: {project}"]
if description: parts.extend(
parts.append(f"Description: {description}") f"{label}: {manifest.get(key)}"
if language: for key, label in _FIELDS
parts.append(f"Language: {language}") if manifest.get(key)
if entry: )
parts.append(f"Entry Point: {entry}")
if architecture:
parts.append(f"Architecture: {architecture}")
if environment:
parts.append(f"Environment: {environment}")
if dependencies: if dependencies:
parts.append(f"Dependencies: {', '.join(dependencies)}") parts.append(f"Dependencies: {', '.join(dependencies)}")
@ -110,15 +116,15 @@ class ManifestSupport:
base = Path(base_dir) base = Path(base_dir)
patterns = manifest.get("context_files", []) patterns = manifest.get("context_files", [])
exclude = set(manifest.get("exclude", [])) exclude = set(manifest.get("exclude", []))
files: list[str] = []
for pattern in patterns: # Single-pass comprehension: expand every pattern, keep only
full_pattern = str(base / pattern) # regular files whose path does not contain any excluded token.
matched = glob_mod.glob(full_pattern, recursive=True) return [
for f in matched: f
if Path(f).is_file() and not any(ex in f for ex in exclude): for pattern in patterns
files.append(f) for f in glob_mod.glob(str(base / pattern), recursive=True)
return files if Path(f).is_file() and not any(ex in f for ex in exclude)
]
@staticmethod @staticmethod
def load_jcl(path: str | Path) -> list[dict[str, Any]]: def load_jcl(path: str | Path) -> list[dict[str, Any]]:

View File

@ -1,18 +1,18 @@
"""Registry entries for the Routing layer (L5). """Registry entries for the Routing layer (L5).
Restored layer (v3.1.1b): model gateways, LLM proxies, request routers, L5 (Intelligent API Routers & Proxies) holds the model-routing tier
mesh transport, and the model-routing tier that sits between the Engines that sits between the Engines (who serve weights) and the Orchestrators
(who serve weights) and the Orchestrators (who build agent workflows on (who build agent workflows on top of a single OpenAI-compatible
top of a single OpenAI-compatible endpoint). This re-unites the old endpoint): model gateways, LLM proxies, request routers, mesh
13-layer model's "AI Endpoints" tier (LiteLLM, model routers, API transport, and the mesh-aware clients that ride on it.
gateways) that had been folded into Orchestrators during the 13-to-10
reorg, plus the mesh-aware clients that ride on it.
This module is consumed by :mod:`ai_lsc.registry.loader`. This module is consumed by :mod:`ai_lsc.registry.loader`. The loader
merges by tool, not by filename, so tools may be regrouped across
files in a future pass without a behavior change.
Structural fields (layer, level) follow the 10-Layer Systems Source of truth: the entries below. The merged registry produced by
Architecture Taxonomy; tools may be regrouped across files in a ``loader.load_merged_registry()`` is a derived view; if any manifest
future pass — the loader merges by tool, not by filename. or cached ``ecosystem.json`` disagrees, the source in this file wins.
""" """
TOOLS: dict[str, dict] = { TOOLS: dict[str, dict] = {

View File

@ -52,6 +52,12 @@ _OE_CONTENT_DIRS: list[str] = [
# File extensions we attempt to parse. # File extensions we attempt to parse.
_OE_PARSE_EXTENSIONS: set[str] = {".md", ".markdown", ".txt"} _OE_PARSE_EXTENSIONS: set[str] = {".md", ".markdown", ".txt"}
# Root-level files that are repo meta, not OE content.
_OE_ROOT_SKIP_NAMES: frozenset[str] = frozenset({
"README.md", "CONTRIBUTING.md", "CHARTER.md",
"LICENSE", "ROADMAP.md",
})
class OpenEngineerImporter: class OpenEngineerImporter:
"""Import Open Engineer files into StandardTemplate objects. """Import Open Engineer files into StandardTemplate objects.
@ -164,51 +170,53 @@ class OpenEngineerImporter:
overrides = stack_config_overrides or {} overrides = stack_config_overrides or {}
templates: list[StandardTemplate] = [] templates: list[StandardTemplate] = []
# Scan known OE content directories # Pass 1 — known OE content subdirs (templates inferred from OE fields).
for subdir_name in _OE_CONTENT_DIRS: for subdir_name in _OE_CONTENT_DIRS:
subdir = root / subdir_name subdir = root / subdir_name
if not subdir.is_dir(): if not subdir.is_dir():
continue continue
templates.extend(self._scan_dir(subdir, overrides=overrides, drop_unknown=False))
for md_file in sorted(subdir.iterdir()): # Pass 2 — root-level standalone OE files (drop unknowns so README/LICENSE/etc.
if md_file.suffix.lower() not in _OE_PARSE_EXTENSIONS: # do not pollute the import). The _OE_ROOT_SKIP_NAMES filter applies here only.
continue templates.extend(self._scan_dir(root, overrides=None, drop_unknown=True, skip=_OE_ROOT_SKIP_NAMES))
if md_file.name.startswith("."):
continue
try: return sorted(templates, key=lambda t: t.source_file)
tpl_id = self._derive_template_id(
md_file, md_file.stem
)
override = overrides.get(tpl_id)
template = self.import_file(md_file, stack_config=override)
templates.append(template)
except Exception:
# Don't let one bad file stop the import
continue
# Also scan root for standalone OE files def _scan_dir(
for md_file in sorted(root.iterdir()): self,
subdir: Path,
*,
overrides: dict[str, dict[str, Any]] | None = None,
drop_unknown: bool = False,
skip: frozenset[str] | None = None,
) -> list[StandardTemplate]:
"""Import every parseable file directly inside *subdir*.
Single-responsibility scan loop: yields one StandardTemplate per
parseable markdown file. Errors per file are swallowed so one bad
file does not abort the scan.
"""
results: list[StandardTemplate] = []
for md_file in sorted(subdir.iterdir()):
if not md_file.is_file(): if not md_file.is_file():
continue continue
if md_file.suffix.lower() not in _OE_PARSE_EXTENSIONS: if md_file.suffix.lower() not in _OE_PARSE_EXTENSIONS:
continue continue
if md_file.name in {
"README.md", "CONTRIBUTING.md", "CHARTER.md",
"LICENSE", "ROADMAP.md",
}:
continue
if md_file.name.startswith("."): if md_file.name.startswith("."):
continue continue
if skip and md_file.name in skip:
continue
try: try:
template = self.import_file(md_file) tpl_id = self._derive_template_id(md_file, md_file.stem)
if template.source_type != "unknown": override = (overrides or {}).get(tpl_id)
templates.append(template) template = self.import_file(md_file, stack_config=override)
except Exception: except Exception:
continue continue
if drop_unknown and template.source_type == "unknown":
return sorted(templates, key=lambda t: t.source_file) continue
results.append(template)
return results
# ── Bulk convert to AI-LSC format ────────────────────────────── # ── Bulk convert to AI-LSC format ──────────────────────────────

View File

@ -574,6 +574,8 @@ class InstallerManager:
""" """
dest = os.path.join(self.tools_root, tool_id) dest = os.path.join(self.tools_root, tool_id)
git_dir = os.path.join(dest, ".git") git_dir = os.path.join(dest, ".git")
# Step-down: each branch resolves one situation and assigns msg.
if os.path.isdir(git_dir): if os.path.isdir(git_dir):
try: try:
subprocess.run( subprocess.run(
@ -586,36 +588,22 @@ class InstallerManager:
"git pull failed for %s (%s); re-cloning fresh", "git pull failed for %s (%s); re-cloning fresh",
tool_id, exc, tool_id, exc,
) )
backup = dest + ".bak." + str(int(time.time())) backup = self._backup_existing(dest)
shutil.move(dest, backup) self._clone_fresh(pkg, dest)
os.makedirs(dest, exist_ok=True)
subprocess.run(
["git", "clone", pkg, dest],
check=True, timeout=600,
)
msg = ( msg = (
f"Git source re-cloned (pull failed, " f"Git source re-cloned (pull failed, "
f"old copy at {backup}): {dest}" f"old copy at {backup}): {dest}"
) )
elif os.path.exists(dest): elif os.path.exists(dest):
# Dir exists but is not a git repo — back it up and clone. # Dir exists but is not a git repo — back it up and clone.
backup = dest + ".bak." + str(int(time.time())) backup = self._backup_existing(dest)
shutil.move(dest, backup) self._clone_fresh(pkg, dest)
os.makedirs(dest, exist_ok=True)
subprocess.run(
["git", "clone", pkg, dest],
check=True, timeout=600,
)
msg = ( msg = (
f"Git source cloned (existing non-git dir backed up " f"Git source cloned (existing non-git dir backed up "
f"at {backup}): {dest}" f"at {backup}): {dest}"
) )
else: else:
os.makedirs(dest, exist_ok=True) self._clone_fresh(pkg, dest)
subprocess.run(
["git", "clone", pkg, dest],
check=True, timeout=600,
)
msg = f"Git source cloned: {dest}" msg = f"Git source cloned: {dest}"
if post_install: if post_install:
@ -638,6 +626,9 @@ class InstallerManager:
""" """
dest = os.path.join(self.tools_root, tool_id) dest = os.path.join(self.tools_root, tool_id)
git_dir = os.path.join(dest, ".git") git_dir = os.path.join(dest, ".git")
# Step-down: each branch resolves one situation, runs the
# appropriate clone/pull+yarn sequence, and assigns msg.
if os.path.isdir(git_dir): if os.path.isdir(git_dir):
try: try:
subprocess.run( subprocess.run(
@ -653,12 +644,8 @@ class InstallerManager:
"git pull / yarn install failed for %s (%s); re-cloning", "git pull / yarn install failed for %s (%s); re-cloning",
tool_id, exc, tool_id, exc,
) )
backup = dest + ".bak." + str(int(time.time())) backup = self._backup_existing(dest)
shutil.move(dest, backup) self._clone_fresh(pkg, dest)
os.makedirs(dest, exist_ok=True)
subprocess.run(
["git", "clone", pkg, dest], check=True, timeout=600,
)
subprocess.run( subprocess.run(
["yarn", "install"], cwd=dest, check=True, timeout=300, ["yarn", "install"], cwd=dest, check=True, timeout=300,
) )
@ -667,12 +654,8 @@ class InstallerManager:
f"old copy at {backup}): {dest}" f"old copy at {backup}): {dest}"
) )
elif os.path.exists(dest): elif os.path.exists(dest):
backup = dest + ".bak." + str(int(time.time())) backup = self._backup_existing(dest)
shutil.move(dest, backup) self._clone_fresh(pkg, dest)
os.makedirs(dest, exist_ok=True)
subprocess.run(
["git", "clone", pkg, dest], check=True, timeout=600,
)
subprocess.run( subprocess.run(
["yarn", "install"], cwd=dest, check=True, timeout=300, ["yarn", "install"], cwd=dest, check=True, timeout=300,
) )
@ -681,10 +664,7 @@ class InstallerManager:
f"up at {backup}): {dest}" f"up at {backup}): {dest}"
) )
else: else:
os.makedirs(dest, exist_ok=True) self._clone_fresh(pkg, dest)
subprocess.run(
["git", "clone", pkg, dest], check=True, timeout=600,
)
subprocess.run( subprocess.run(
["yarn", "install"], cwd=dest, check=True, timeout=300, ["yarn", "install"], cwd=dest, check=True, timeout=300,
) )
@ -694,6 +674,27 @@ class InstallerManager:
self._run_post_install(tool_id, post_install) self._run_post_install(tool_id, post_install)
return msg return msg
# ── git install helpers ────────────────────────────────────────
@staticmethod
def _backup_existing(dest: str) -> str:
"""Move *dest* aside to ``<dest>.bak.<unix_ts>`` and return the backup path.
Caller guarantees *dest* exists.
"""
backup = f"{dest}.bak.{int(time.time())}"
shutil.move(dest, backup)
return backup
@staticmethod
def _clone_fresh(pkg: str, dest: str) -> None:
"""Create *dest* (empty) and run ``git clone pkg dest`` into it."""
os.makedirs(dest, exist_ok=True)
subprocess.run(
["git", "clone", pkg, dest],
check=True, timeout=600,
)
def install_script( def install_script(
self, self,
cmd: str, cmd: str,

View File

@ -360,35 +360,35 @@ if _HAS_QT:
}, },
} }
html = ( # Dispatch table for the bubble-style key — replaces a
"<body style='background:#121212; color:#e0e0e0;" # 2-level nested ternary on (is_user, is_error).
" font-family:sans-serif;'>" _identity_color = {"user": "#e0e0e0", "error": "#e74c3c", "assistant": "#d35400"}
) _identity_label = {
for msg in self.chat_messages: "user": "<b>You</b>",
# assistant/error labels render identity inline; filled below.
}
def _style_key(msg: dict) -> str:
if msg["is_user"]:
return "user"
return "error" if "?" in msg["identity"] else "assistant"
def _render_bubble(msg: dict) -> str:
style_key = _style_key(msg)
s = bubble_styles[style_key]
ts = msg["timestamp"] ts = msg["timestamp"]
payload = ( payload = (
msg["payload"] msg["payload"]
.replace("<", "&lt;").replace(">", "&gt;") .replace("<", "&lt;").replace(">", "&gt;")
.replace("\n", "<br/>") .replace("\n", "<br/>")
) )
is_error = "?" in msg["identity"] if style_key == "user":
style_key = ( label = _identity_label["user"]
"user" if msg["is_user"] else:
else ("error" if is_error else "assistant") color = _identity_color[style_key]
) label = f"<b style='color:{color}'>{msg['identity']}</b>"
s = bubble_styles[style_key] border_css = f"border: {s['border']};" if "border" in s else ""
label_color = ( return (
"#e0e0e0" if msg["is_user"]
else ("#e74c3c" if is_error else "#d35400")
)
label = (
"<b>You</b>" if msg["is_user"]
else f"<b style='color:{label_color}'>{msg['identity']}</b>"
)
border_css = (
f"border: {s['border']};" if "border" in s else ""
)
html += (
f"<div style='margin-bottom:15px; text-align:{s['align']}';>" f"<div style='margin-bottom:15px; text-align:{s['align']}';>"
f"<span style='background:{s['bg']}; {border_css} color:#e0e0e0; " f"<span style='background:{s['bg']}; {border_css} color:#e0e0e0; "
f"padding:10px 14px; border-radius:{s['radius']}; " f"padding:10px 14px; border-radius:{s['radius']}; "
@ -400,6 +400,12 @@ if _HAS_QT:
f"</span></div>" f"</span></div>"
) )
html = (
"<body style='background:#121212; color:#e0e0e0;"
" font-family:sans-serif;'>"
)
html += "".join(_render_bubble(m) for m in self.chat_messages)
if self.is_thinking: if self.is_thinking:
model = self.cbo_chat_model.currentText() or "Model" model = self.cbo_chat_model.currentText() or "Model"
html += ( html += (
@ -638,11 +644,9 @@ if _HAS_QT:
"Absorb and layer the following skill instructions:\n\n" "Absorb and layer the following skill instructions:\n\n"
+ "\n\n".join(skill_directives) + "\n\n".join(skill_directives)
) )
system_content = ( # Flat join beats the prior 3-way nested ternary; empty parts
parts[0] + "\n\n" + parts[1] # naturally produce an empty string.
if len(parts) == 2 system_content = "\n\n".join(parts)
else (parts[0] if parts else "")
)
self.chat_history_data.append( self.chat_history_data.append(
{"role": "user", "content": full_prompt} {"role": "user", "content": full_prompt}
@ -650,9 +654,7 @@ if _HAS_QT:
filtered = [ filtered = [
m for m in self.chat_history_data if m.get("role") != "system" m for m in self.chat_history_data if m.get("role") != "system"
] ]
result = [] result = [{"role": "system", "content": system_content}] if system_content else []
if system_content:
result.append({"role": "system", "content": system_content})
result.extend(filtered) result.extend(filtered)
return result return result

View File

@ -5,8 +5,8 @@
**Pass scope**: CRITICAL (C-01, C-02, C-03, C-04, C-06, C-07) + all 24 HIGH + all 42 MEDIUM + all 20 LOW **Pass scope**: CRITICAL (C-01, C-02, C-03, C-04, C-06, C-07) + all 24 HIGH + all 42 MEDIUM + all 20 LOW
**Pass status**: 91 of 93 findings addressed in code; 2 explicitly skipped per user instruction **Pass status**: 91 of 93 findings addressed in code; 2 explicitly skipped per user instruction
**Double-check pass**: 19/19 functional spot-checks pass; 2 latent bugs found and fixed (see "Bugs caught during double-check" below) **Double-check pass**: 19/19 functional spot-checks pass; 2 latent bugs found and fixed (see "Bugs caught during double-check" below)
**v3.2 note**: the 10-layer taxonomy migration preserved every curl|sh **v3.2 note**: the 10-layer taxonomy migration carries every curl|sh
site below verbatim — the restored installer cmds (ollama, llamafile, site below verbatim — the canonical installer cmds (ollama, llamafile,
qdrant, grafana_alloy, meilisearch, fabric) are byte-identical to the qdrant, grafana_alloy, meilisearch, fabric) are byte-identical to the
pre-migration registry, so the C-05 policy state is unchanged. pre-migration registry, so the C-05 policy state is unchanged.