From 9581d8758903706ed74fff38cb0c724e16d605f2 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 15 Jun 2026 12:55:48 -0700 Subject: [PATCH] harness: scratch graduation pipeline (push side + spec) + flarum first test case - graduation-push.sh: tar+scp scratch -> BEAST graduation-inbox over Tailscale (decoupled from /save, soft-fail if BEAST off). Tested: 241 files -> BEAST. - docs/graduation-pipeline.md: full spec (push -> Ollama triage on BEAST GPU via API -> reviewed sanitize+git-mv). Secrets never enter git; ride the encrypted link to BEAST only. - tmp-promotion-check.sh: rewritten pure-builtin (0.4s) after the per-file grep/fork loop hung /save for 4 min on Windows at ~240 scratch files. Deep triage moves to the pipeline. - forum-post: GRADUATED the canonical flarum poster from scratch -> skills/forum-post/scripts/flarum-post.py (s9e markdown->XML + DB insert machinery), with the hardcoded IX SSH + Flarum DB passwords swapped to vault lookups. First pipeline test case. - Vaulted the Flarum DB cred (services/flarum-community.sops.yaml) + sanitized the two plaintext copies in forum-post.md. - errorlog: logged the WSL-stub correction + BEAST-Ollama-CPU(vram=0) finding + the promotion-check hang, all via the new log helper. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/commands/forum-post.md | 4 +- .claude/docs/graduation-pipeline.md | 84 +++++++ .claude/scripts/graduation-push.sh | 55 +++++ .claude/scripts/tmp-promotion-check.sh | 39 +-- .../skills/forum-post/scripts/flarum-post.py | 230 ++++++++++++++++++ errorlog.md | 4 + 6 files changed, 383 insertions(+), 33 deletions(-) create mode 100644 .claude/docs/graduation-pipeline.md create mode 100644 .claude/scripts/graduation-push.sh create mode 100644 .claude/skills/forum-post/scripts/flarum-post.py diff --git a/.claude/commands/forum-post.md b/.claude/commands/forum-post.md index 4171bf3..52ca451 100644 --- a/.claude/commands/forum-post.md +++ b/.claude/commands/forum-post.md @@ -25,7 +25,7 @@ determine what to post (the most recent technical problem solved, fix documented | DB host | localhost (on IX) | | DB name | azcompu_flarum | | DB user | azcompu_flarum | -| DB pass | `Fl@rum2026!CGS` | +| DB pass | vault: `services/flarum-community.sops.yaml credentials.db_password` | | IX SSH | root@172.16.3.10 — password from vault: `infrastructure/ix-server.sops.yaml credentials.password` | | Admin user_id | 1 (MikeSwanson) | @@ -219,7 +219,7 @@ The closing nowdoc marker `FLARUM_POST_XML_END;` must be at column 0 with no lea PDO::ERRMODE_EXCEPTION]); +$pdo = new PDO($dsn, 'azcompu_flarum', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); $user_id = 1; $tag_id = %%TAG_ID%%; $title = %%TITLE_PHP%%; diff --git a/.claude/docs/graduation-pipeline.md b/.claude/docs/graduation-pipeline.md new file mode 100644 index 0000000..da0f8fd --- /dev/null +++ b/.claude/docs/graduation-pipeline.md @@ -0,0 +1,84 @@ +# Scratch Graduation Pipeline (spec) + +Status: **draft / in progress** (2026-06-15). Push side built + tested; triage validated on +the flarum test case; scheduled-on-BEAST wiring + execute helper are the remaining work. + +## Problem + +Scratch dirs (`tmp/`, `temp/`, `.claude/tmp/`) are gitignored, so anything in them is invisible +to git and lost on cleanup. The old approach — a **synchronous** `tmp-promotion-check.sh` run +inside `/save` and `/scc` — had two fatal flaws: + +1. **Too slow on Windows.** At ~240 scratch files it forked `basename`/`wc`/`grep -r` per file; + the "referenced in a session log" check recursed `clients/` + `projects/` (Rust `target/`, + `node_modules/`, `.git`) **once per file** and hung `/save` for **4 minutes** (errorlog 2026-06-15). +2. **Too dumb.** Extension/size heuristics can't answer the real question — *which* of + `flarum_do_insert.py` / `do_insert2.py` / `search_insert.py` is canonical, what's a superseded + debug dupe, what holds secrets, where each belongs. That's semantic judgment. + +The interim `tmp-promotion-check.sh` is now a fast (0.4s) pure-builtin "N scripts in scratch" nudge. +The real triage is **offloaded and asynchronous**, per this spec. + +## Architecture + +``` +workstation BEAST (GURU-BEAST-ROG, best GPU) any Claude session +----------- -------------------------------- ------------------ +graduation-push.sh Ollama @ :11434 (GPU) review proposal + tar scratch ──SCP/Tailscale──▶ graduation-inbox//*.tgz sanitize secrets + (soft-fail if BEAST off) graduation-triage (Ollama classify) git mv keepers + ─▶ proposal manifest ──coord msg/todo──▶ delete junk → commit +``` + +1. **Push** (`graduation-push.sh`, built): tars scratch and `scp`s ONE tarball to + `guru@100.101.122.4:graduation-inbox//scratch-.tgz` over Tailscale. Decoupled + from `/save`; soft-fails if BEAST is unreachable. Centralizes every machine's scratch on the + GPU box (archive + lets BEAST batch-process even when the origin machine is off). +2. **Triage** (Ollama on BEAST's GPU): for each file, classify + `{disposition: graduate|delete|keep-data, canonical?, superseded_by, has_secrets, suggested_home, why}`. + Emits a **proposal manifest** (the supersession/secret reasoning the old heuristics couldn't do). + The orchestration can run **on BEAST** (Git-bash, scheduled) or on **any machine** against + BEAST's Ollama API — the GPU is reached over the HTTP API either way. +3. **Review + execute**: a Claude session (or human) reads the manifest, **sanitizes secrets** + (hardcoded creds → vault lookups), `git mv`s keepers to permanent homes, deletes junk, commits. + *Ollama proposes, human/Claude disposes* (same contract as memory-dream + the Tier-0 routing rule). + +## Transport / environment facts (verified 2026-06-15) + +- BEAST = `guru-beast-rog`, Tailscale `100.101.122.4`. SSH key auth works as **`guru`** (no password). +- BEAST default SSH shell = **cmd.exe**; home `C:\Users\guru`. The harness/triage run under + **Git-for-Windows MSYS bash** — NOT WSL. (`bash` on PATH resolves to the WindowsApps WSL stub; + invoke Git-bash explicitly. The WSL stub also can't reach the Windows-host Ollama on localhost — + another reason to avoid it.) +- **Ollama** runs on BEAST's Windows side, bound so it's reachable fleet-wide over Tailscale at + `http://100.101.122.4:11434`. Models incl. `qwen3:32b`, `qwen3.6:latest` (36B), `gemma3:27b`, + `codestral:22b`, `qwen3:14b`, `nomic-embed-text`. +- Inbox: `C:\Users\guru\graduation-inbox\\` (cmd path) — per-machine namespaced. + +## Security (non-negotiable) + +- **Secrets never enter git.** Raw scratch can contain hardcoded creds (the flarum scripts hold the + IX root SSH password). It rides the WireGuard-encrypted Tailscale/SSH link and lands ONLY on BEAST + (trusted). The transport is deliberately NOT the git repo or a multi-tenant store. +- **Sanitize before commit.** Any file graduated into a tracked home gets hardcoded secrets swapped + for vault lookups first (`vault.sh get-field ...`). harness-guard would block a plaintext-secret commit. +- **Manifest-only returns.** Only the proposal manifest comes back toward git — never the raw files. + +## Components + +| Piece | Path | State | +|---|---|---| +| Push | `.claude/scripts/graduation-push.sh` | built + tested (241 files → BEAST) | +| Interim nudge | `.claude/scripts/tmp-promotion-check.sh` | fast builtin-only (0.4s) | +| Triage | `.claude/scripts/graduation-triage.*` | validated ad-hoc on flarum; productize next | +| Execute | manual (Claude session) | flarum = first test case | +| Schedule | BEAST cron/loop calling triage | TODO | +| Return | coord message/todo to origin machine | TODO | + +## Open items + +- Productize `graduation-triage` (general file loop + Ollama classify + manifest) and a `--execute` + helper that sanitizes + `git mv`s per an approved manifest. +- Wire a scheduled triage run on BEAST (or a `/loop`) + coord-message return. +- Decide retention/cleanup of the BEAST inbox + auto-deleting obvious junk to keep scratch bounded. +- Consider dropping `tmp-promotion-check` from `/save` entirely once the pipeline is routine. diff --git a/.claude/scripts/graduation-push.sh b/.claude/scripts/graduation-push.sh new file mode 100644 index 0000000..81b6bd7 --- /dev/null +++ b/.claude/scripts/graduation-push.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# graduation-push.sh — ship this machine's scratch (tmp/, temp/, .claude/tmp/) to BEAST's +# graduation inbox over Tailscale+SSH, for async Ollama triage. Part of the scratch +# graduation pipeline (see .claude/TEMP_GRADUATION.md / graduation-pipeline spec). +# +# DECOUPLED from /save and SOFT-FAIL: if BEAST is off/unreachable it warns and exits 0 — +# it must never block a save or a commit. +# +# Transport: tar the scratch -> scp ONE tarball to guru@:graduation-inbox//. +# Secrets in scratch (e.g. hardcoded creds) ride the WireGuard-encrypted Tailscale/SSH link +# and land ONLY on BEAST (a trusted fleet box) — they never enter git. The graduation step +# sanitizes secrets (-> vault lookups) before anything is committed to a permanent home. +# +# BEAST: guru@100.101.122.4 (key auth as `guru`), default SSH shell = cmd.exe, home C:\Users\guru. +set -u +ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" +SSH="/c/Windows/System32/OpenSSH/ssh.exe"; [ -x "$SSH" ] || SSH="ssh" +SCP="/c/Windows/System32/OpenSSH/scp.exe"; [ -x "$SCP" ] || SCP="scp" +BEAST="guru@100.101.122.4" +CTO=8 + +MACHINE="$(jq -r '.machine_name // .hostname // empty' "$ROOT/.claude/identity.json" 2>/dev/null)" +[ -z "$MACHINE" ] && MACHINE="$(hostname)" +STAMP="$(date -u +%Y%m%dT%H%M%SZ)" + +# Collect existing scratch dirs + count files. +DIRS=(); for d in tmp temp .claude/tmp; do [ -d "$ROOT/$d" ] && DIRS+=("$d"); done +[ "${#DIRS[@]}" -eq 0 ] && { echo "[INFO] graduation-push: no scratch dirs — nothing to send"; exit 0; } +N=$(find "${DIRS[@]/#/$ROOT/}" -type f ! -name '.gitkeep' ! -name '.grad-*.tgz' 2>/dev/null | wc -l | tr -d ' ') +[ "${N:-0}" -eq 0 ] && { echo "[INFO] graduation-push: scratch empty — nothing to send"; exit 0; } + +# Reachability gate (fast, BatchMode so it can't prompt). +if ! "$SSH" -o BatchMode=yes -o ConnectTimeout=$CTO "$BEAST" "exit 0" >/dev/null 2>&1; then + echo "[WARN] graduation-push: BEAST ($BEAST) unreachable — skipped; scratch stays local" >&2 + exit 0 +fi + +# Tar to an OS-temp path OUTSIDE the scratch dirs (avoid taring our own tarball). +TARBALL="$(mktemp -t gradpush-XXXXXX 2>/dev/null).tgz"; [ -z "$TARBALL" ] && TARBALL="/tmp/gradpush-$STAMP.tgz" +if ! tar -czf "$TARBALL" -C "$ROOT" "${DIRS[@]}" 2>/dev/null; then + echo "[WARN] graduation-push: tar failed" >&2; rm -f "$TARBALL" 2>/dev/null; exit 0 +fi + +# Ensure remote per-machine inbox (cmd.exe: mkdir makes intermediate dirs; 2>nul ignores 'exists'). +"$SSH" -o ConnectTimeout=$CTO "$BEAST" "mkdir graduation-inbox\\$MACHINE 2>nul & exit 0" >/dev/null 2>&1 + +REMOTE="graduation-inbox/$MACHINE/scratch-$STAMP.tgz" +if "$SCP" -o ConnectTimeout=$CTO -q "$TARBALL" "$BEAST:$REMOTE" 2>/dev/null; then + echo "[OK] graduation-push: sent $N scratch file(s) -> BEAST:$REMOTE" +else + echo "[WARN] graduation-push: scp to BEAST failed" >&2 + bash "$ROOT/.claude/scripts/log-skill-error.sh" "graduation-push" "scp of scratch tarball to BEAST failed (machine=$MACHINE)" >/dev/null 2>&1 +fi +rm -f "$TARBALL" 2>/dev/null +exit 0 diff --git a/.claude/scripts/tmp-promotion-check.sh b/.claude/scripts/tmp-promotion-check.sh index 9b61b0a..bf2eaa4 100755 --- a/.claude/scripts/tmp-promotion-check.sh +++ b/.claude/scripts/tmp-promotion-check.sh @@ -27,40 +27,17 @@ mapfile -t FILES < <( echo "[INFO] Promotion check: ${#FILES[@]} file(s) in scratch dirs (gitignored — NOT committed)." echo " Graduate anything worth keeping before it's lost. Guide: .claude/TEMP_GRADUATION.md" +# PURE-BUILTIN loop (no per-file subprocesses) — `basename`/`wc` forks ×N hung this for +# 20s+ on Windows Git-bash at ~240 scratch files (fork is expensive). Flag scripts by +# extension only; deep triage (doc size, "is it referenced", what's it for) is deferred to +# the async Ollama graduation pass (see TEMP_GRADUATION.md). Keep this O(N) and fork-free. candidates=0 for f in "${FILES[@]}"; do - base="$(basename "$f")" - reason="" - - # Script-like files: reusable automation worth a permanent home. - case "$base" in - *.py|*.sh|*.ps1|*.psm1|*.js|*.rb|*.pl) reason="script" ;; + case "${f##*/}" in + *.py|*.sh|*.ps1|*.psm1|*.js|*.rb|*.pl|*.php) + echo " [GRADUATE?] $f (script)" + candidates=$((candidates + 1)) ;; esac - - # Substantial docs (audit reports, dossiers) — size threshold ~4 KB. - if [ -z "$reason" ]; then - case "$base" in - *.md|*.csv) - sz=$(wc -c < "$f" 2>/dev/null || echo 0) - [ "${sz:-0}" -ge 4096 ] && reason="doc ($((sz/1024))KB)" - ;; - esac - fi - - # Referenced in a session log / doc → clearly load-bearing. - # Scope to markdown only and skip heavy build/dep/vcs trees — a bare `grep -r` - # over projects/ (Rust target/, node_modules/, .git) hangs for minutes per file. - if grep -rqlF "$f" --include='*.md' \ - --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=target \ - --exclude-dir=dist --exclude-dir=build --exclude-dir=.next --exclude-dir=vendor \ - session-logs/ clients/ projects/ 2>/dev/null; then - reason="${reason:+$reason, }referenced" - fi - - if [ -n "$reason" ]; then - echo " [GRADUATE?] $f ($reason)" - candidates=$((candidates + 1)) - fi done if [ "$candidates" -eq 0 ]; then diff --git a/.claude/skills/forum-post/scripts/flarum-post.py b/.claude/skills/forum-post/scripts/flarum-post.py new file mode 100644 index 0000000..bd07b42 --- /dev/null +++ b/.claude/skills/forum-post/scripts/flarum-post.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python3 +"""flarum-post.py — post a markdown article to community.azcomputerguru.com (Flarum) by +converting it to Flarum's s9e TextFormatter XML and inserting into the Flarum MySQL DB over +SSH to the IX server. The canonical machinery behind the /forum-post skill. + +GRADUATED 2026-06-15 from .claude/tmp scratch (the first test case of the scratch-graduation +pipeline — see .claude/docs/graduation-pipeline.md). Secrets that were HARDCODED in the +scratch original (IX root SSH password, Flarum DB password) now load from the SOPS vault at +runtime, so this file is safe to commit. + +NEXT STEP (Mike's plans): genericize — take TITLE / CONTENT_MD / SLUG / tag_id as inputs +(skill Phase 1) instead of the hardcoded demo article below. The converter + insert flow are +already generic; only the CONTENT_MD/TITLE/SLUG block is example data. +""" +import os, re, subprocess +import paramiko + +# ---- secrets from vault (never hardcode) ---------------------------------------------------- +def _root(): + return os.environ.get("CLAUDETOOLS_ROOT") or os.path.abspath( + os.path.join(os.path.dirname(__file__), "..", "..", "..", "..")) + +def vault_get(path, field): + r = _root() + p = subprocess.run(["bash", os.path.join(r, ".claude", "scripts", "vault.sh"), + "get-field", path, field], + capture_output=True, text=True, timeout=30) + v = (p.stdout or "").strip() + if not v: + raise SystemExit(f"[ERROR] vault_get {path} {field} failed: {(p.stderr or '').strip()[:200]}") + return v + +HOST = "172.16.3.10" +SSH_USER = "root" +SSH_PASS = vault_get("infrastructure/ix-server.sops.yaml", "credentials.password") +DB_PASS = vault_get("services/flarum-community.sops.yaml", "credentials.db_password") + +# ---- DEMO article (replace with skill Phase 1 inputs when genericizing) --------------------- +CONTENT_MD = """\ +We did a server-wide audit today and found 7 production WordPress sites with search indexing silently disabled. The sites looked completely normal to visitors. Google couldn't see any of them. + +Here's the setting, why it gets left on, and how to audit a whole cPanel server at once. + +## The Setting + +In WordPress: **Settings -> Reading -> "Discourage search engines from indexing this site"** + +When checked, WordPress adds `` to every page and sets `blog_public` to `0` in `wp_options`. When unchecked, `blog_public = 1`. One row in one table; no other indicator anywhere on the site. + +## The Fix + +One SQL update per site: + +```sql +UPDATE wp_options SET option_value = '1' WHERE option_name = 'blog_public'; +``` + +After updating, verify by fetching the page source and confirming there's no `` in the ``.""" + +TITLE = 'WordPress "Discourage Search Engines" Setting -- How 7 Production Sites Lost Their Indexing' +SLUG = "wordpress-discourage-search-engines-setting-how-7-production-sites-lost-their-indexing" +TAG_ID = 7 # How-Tos & Tips + + +# ---- markdown -> Flarum s9e TextFormatter XML ----------------------------------------------- +def xml_escape(t): + return t.replace("&", "&").replace("<", "<").replace(">", ">") + + +def inline_to_xml(text): + result = "" + i = 0 + while i < len(text): + if text[i:i + 2] == "**": + end = text.find("**", i + 2) + if end != -1: + result += "**" + inline_to_xml(text[i + 2:end]) + "**" + i = end + 2 + continue + if text[i] == "`": + end = text.find("`", i + 1) + if end != -1: + result += "`" + xml_escape(text[i + 1:end]) + "`" + i = end + 1 + continue + if text[i] == "*" and text[i:i + 2] != "**": + j = i + 1 + end = -1 + while j < len(text): + if text[j] == "*" and text[j:j + 2] != "**": + end = j + break + j += 1 + if end != -1: + result += "*" + xml_escape(text[i + 1:end]) + "*" + i = end + 1 + continue + result += xml_escape(text[i]) + i += 1 + return result + + +def md_to_s9e(md): + lines = md.split("\n") + elements = [] + i = 0 + while i < len(lines): + line = lines[i] + if not line.strip(): + i += 1 + continue + if line.startswith("## "): + elements.append("

## " + inline_to_xml(line[3:]) + "

") + i += 1 + elif line.startswith("### "): + elements.append("

### " + inline_to_xml(line[4:]) + "

") + i += 1 + elif line.startswith("- "): + items = [] + while i < len(lines) and lines[i].startswith("- "): + items.append("
  • - " + inline_to_xml(lines[i][2:]) + "
  • ") + i += 1 + elements.append("" + "\n".join(items) + "") + elif re.match(r"^\d+\. ", line): + items = [] + while i < len(lines) and re.match(r"^\d+\. ", lines[i]): + m = re.match(r"^(\d+)\. (.*)", lines[i]) + items.append("
  • " + m.group(1) + ". " + inline_to_xml(m.group(2)) + "
  • ") + i += 1 + elements.append('' + "\n".join(items) + "") + elif line.startswith("```"): + lang = line[3:].strip() + code_lines = [] + i += 1 + while i < len(lines) and not lines[i].startswith("```"): + code_lines.append(xml_escape(lines[i])) + i += 1 + i += 1 + code_body = "\n".join(code_lines) + if lang: + elements.append(f'```{lang}\n' + code_body + "\n```") + else: + elements.append("```\n" + code_body + "\n```") + else: + para_lines = [] + while i < len(lines) and lines[i].strip(): + l = lines[i] + if (l.startswith("## ") or l.startswith("### ") or l.startswith("- ") + or l.startswith("```") or re.match(r"^\d+\. ", l)): + break + para_lines.append(l) + i += 1 + elements.append("

    " + inline_to_xml("\n".join(para_lines)) + "

    ") + return "" + "\n\n".join(elements) + "" + + +xml_content = md_to_s9e(CONTENT_MD) +print(f"[INFO] XML length={len(xml_content)}") + +php_template = """ PDO::ERRMODE_EXCEPTION]); + +$user_id = 1; +$tag_id = %%TAG_ID%%; +$title = %%TITLE_JSON%%; +$slug = '%%SLUG%%'; +$now = date('Y-m-d H:i:s'); + +$content = <<<'FLARUM_POST_XML_END' +%%XML_CONTENT%% +FLARUM_POST_XML_END; + +$stmt = $pdo->prepare("INSERT INTO discussions (title, comment_count, post_number_index, created_at, user_id, slug, is_private, is_approved) VALUES (?, 1, 1, ?, ?, ?, 0, 1)"); +$stmt->execute([$title, $now, $user_id, $slug]); +$disc_id = $pdo->lastInsertId(); +echo "Discussion ID: $disc_id\\n"; + +$stmt = $pdo->prepare("INSERT INTO posts (discussion_id, number, created_at, user_id, type, content, is_private, is_approved) VALUES (?, 1, ?, ?, 'comment', ?, 0, 1)"); +$stmt->execute([$disc_id, $now, $user_id, $content]); +$post_id = $pdo->lastInsertId(); +echo "Post ID: $post_id\\n"; + +$pdo->prepare("UPDATE discussions SET first_post_id=?, last_post_id=?, last_posted_at=?, last_posted_user_id=?, last_post_number=1 WHERE id=?")->execute([$post_id, $post_id, $now, $user_id, $disc_id]); +$pdo->prepare("INSERT INTO discussion_tag (discussion_id, tag_id) VALUES (?, ?)")->execute([$disc_id, $tag_id]); + +echo "Done! URL: https://community.azcomputerguru.com/d/$disc_id-$slug\\n"; +""" + +import json as _json +php_script = (php_template + .replace("%%XML_CONTENT%%", xml_content) + .replace("%%DB_PASS%%", DB_PASS) + .replace("%%TAG_ID%%", str(TAG_ID)) + .replace("%%SLUG%%", SLUG) + .replace("%%TITLE_JSON%%", _json.dumps(TITLE))) + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect(HOST, username=SSH_USER, password=SSH_PASS, timeout=10) +print("[OK] SSH connected") + +sftp = client.open_sftp() +with sftp.open("/tmp/flarum_post.php", "wb") as f: + f.write(php_script.encode("utf-8")) +sftp.close() + + +def run_chan(cmd): + chan = client.get_transport().open_session() + chan.exec_command(cmd) + chan.shutdown_write() + out = b"" + while not chan.exit_status_ready(): + if chan.recv_ready(): + out += chan.recv(4096) + while chan.recv_ready(): + out += chan.recv(4096) + return out.decode("utf-8", errors="replace"), chan.recv_exit_status() + + +out, rc = run_chan("php -l /tmp/flarum_post.php 2>&1") +print(f"Syntax: {out.strip()}") +out, rc = run_chan("php /tmp/flarum_post.php 2>&1") +print(f"rc={rc}\n{out}") +run_chan("rm -f /tmp/flarum_post.php") +client.close() diff --git a/errorlog.md b/errorlog.md index 2800f6f..9146abb 100644 --- a/errorlog.md +++ b/errorlog.md @@ -17,6 +17,10 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure · +2026-06-15 | GURU-5070 | graduation-pipeline (BEAST Ollama) | [friction] BEAST Ollama ran inference on CPU (api/ps showed qwen3:32b AND qwen3:14b with vram=0); 32b timed out at 240s, 14b at 175s. GPU not engaged - the 'use BEAST GPU' premise needs a BEAST-side Ollama GPU config/driver fix before large-model triage is practical + +2026-06-15 | GURU-5070 | graduation-pipeline (BEAST env) | [friction] assumed BEAST uses WSL because 'bash' there resolved to the WindowsApps WSL stub (uname said WSL2). BEAST runs the harness under Git-for-Windows MSYS bash like other Windows boxes; reach its Ollama via localhost (Git-bash) or the Tailscale IP. REPEAT of the documented WSL-stub-vs-Git-bash gotcha [ctx: ref=feedback_windows_bash_mapping] + 2026-06-15 | GURU-5070 | tmp-promotion-check (/save,/scc) | [friction] hung for minutes: line 51 ran 'grep -rqlF projects/' per scratch file, recursing Rust target/, node_modules/, .git in the guru-rmm/guru-connect submodules. Fixed: --include='*.md' + --exclude-dir for heavy trees. Stalled the /save sync behind it 2026-06-15 | GURU-5070 | memory-dream (--apply-safe) | flagged feedback_broken_backlinks_are_writeme_markers.md as an orphan and appended a DUPLICATE index line though it already had one — orphan detector likely keys on the frontmatter name: slug, not the (file.md) link target. Fix the index-line matching to compare by filename [ctx: mode=apply-safe]