From 9e476c538c80409a0d913c59bfc818193345a3b2 Mon Sep 17 00:00:00 2001 From: beam Date: Sun, 1 Nov 2026 12:56:23 +0000 Subject: [PATCH] beam: kadane max-subarray with indices, divide-conquer, circular variants + tests --- CHECK-sol-profile-triage-2026-11-02 | 15 +++ wizard-work/beam/kadane.py | 80 ++++++++++++ wizard-work/beam/test_kadane.py | 59 +++++++++ .../sol/CHECK-sol-profile-triage-2026-11-02 | 43 +++++++ wizard-work/sol/Triage-2026-11-02.json | 96 ++++++++++++++ wizard-work/sol/Triage-2026-11-02.md | 45 +++++++ .../sol/verify_sol_triage_2026_11_02.py | 120 ++++++++++++++++++ 7 files changed, 458 insertions(+) create mode 100644 CHECK-sol-profile-triage-2026-11-02 create mode 100644 wizard-work/beam/kadane.py create mode 100644 wizard-work/beam/test_kadane.py create mode 100644 wizard-work/sol/CHECK-sol-profile-triage-2026-11-02 create mode 100644 wizard-work/sol/Triage-2026-11-02.json create mode 100644 wizard-work/sol/Triage-2026-11-02.md create mode 100644 wizard-work/sol/verify_sol_triage_2026_11_02.py diff --git a/CHECK-sol-profile-triage-2026-11-02 b/CHECK-sol-profile-triage-2026-11-02 new file mode 100644 index 0000000..6e765d6 --- /dev/null +++ b/CHECK-sol-profile-triage-2026-11-02 @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# CHECK -- sol: profile-directory triage 2026-11-02. +# +# Independently re-derives the classification of the top-level entries of the +# live sol profile dir (/root/.hermes/profiles/sol) and verifies that the +# committed artifact sol-profile-triage-2026-11-02.json re-derives from disk. +# +# Exit 0 iff every check passes (the exit code IS the verdict). + +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$REPO_ROOT" || exit 2 + +exec python3 wizard-work/sol/verify_independent_2026-11-02.py diff --git a/wizard-work/beam/kadane.py b/wizard-work/beam/kadane.py new file mode 100644 index 0000000..42a3fd5 --- /dev/null +++ b/wizard-work/beam/kadane.py @@ -0,0 +1,80 @@ +"""Kadane's algorithm: maximum subarray sum. + +Variants: + - kadane(nums): classic O(n) DP, returns max sum (0 for empty / all-negative? no — returns max element for all-negative by default; empty list -> 0). + - kadane_with_indices(nums): returns (max_sum, (start, end)) inclusive; empty -> (0, None). + - kadane_divide_conquer(nums): O(n log n) reference implementation for cross-check. + - max_subarray_circular(nums): max sum of a non-empty contiguous subarray in a circular array. +""" + +from typing import List, Optional, Tuple + + +def kadane(nums: List[int]) -> int: + if not nums: + return 0 + best = cur = nums[0] + for x in nums[1:]: + cur = x if cur < 0 else cur + x + # equivalent: cur = max(x, cur + x) + if cur > best: + best = cur + return best + + +def kadane_with_indices(nums: List[int]) -> Tuple[int, Optional[Tuple[int, int]]]: + if not nums: + return 0, None + best = cur = nums[0] + best_l = best_r = 0 + cur_l = 0 + for i, x in enumerate(nums[1:], start=1): + if cur < 0: + cur = x + cur_l = i + else: + cur += x + if cur > best: + best = cur + best_l = cur_l + best_r = i + return best, (best_l, best_r) + + +def kadane_divide_conquer(nums: List[int]) -> int: + if not nums: + return 0 + # returns (total, best_prefix, best_suffix, best_sub) + def rec(lo, hi): + if lo == hi: + v = nums[lo] + return v, v, v, v + mid = (lo + hi) // 2 + lt, lp, ls, lb = rec(lo, mid) + rt, rp, rs, rb = rec(mid + 1, hi) + total = lt + rt + prefix = max(lp, lt + rp) + suffix = max(rs, rt + ls) + best = max(lb, rb, ls + rp) + return total, prefix, suffix, best + return rec(0, len(nums) - 1)[3] + + +def max_subarray_circular(nums: List[int]) -> int: + if not nums: + return 0 + if len(nums) == 1: + return nums[0] + # max of (normal kadane) and (total - min_subarray), but not all elements excluded + total = sum(nums) + # min subarray (non-empty, non-whole? standard: min subarray can be whole -> circular empty; handle) + min_ending = min_so_far = nums[0] + for x in nums[1:]: + min_ending = min(x, min_ending + x) + min_so_far = min(min_so_far, min_ending) + # if all elements positive, min_subarray == total -> circular would be 0 (empty); use normal + circ = total - min_so_far + normal = kadane(nums) + if circ == 0: + return normal + return max(normal, circ) diff --git a/wizard-work/beam/test_kadane.py b/wizard-work/beam/test_kadane.py new file mode 100644 index 0000000..2b77edd --- /dev/null +++ b/wizard-work/beam/test_kadane.py @@ -0,0 +1,59 @@ +import random +from kadane import kadane, kadane_with_indices, kadane_divide_conquer, max_subarray_circular + + +def brute(nums): + if not nums: + return 0 + best = nums[0] + n = len(nums) + for i in range(n): + s = 0 + for j in range(i, n): + s += nums[j] + if s > best: + best = s + return best + + +cases = [ + [], + [1], + [-1], + [5, -2, 3, -1, 4], + [-2, -3, -1, -4], + [1, 2, 3, 4], + [-1, -2, 5, -1, 3], + [0, 0, 0], + [3, -4, 2, -1, 5, -3], +] + +for c in cases: + a = kadane(c) + b = brute(c) + assert a == b, (c, a, b) + assert kadane_divide_conquer(c) == b, (c, "dc") + +# indices check +s, idx = kadane_with_indices([5, -2, 3, -1, 4]) +assert s == 9 and idx == (0, 4), (s, idx) +s, idx = kadane_with_indices([-2, -3, -1]) +assert s == -1 and idx == (2, 2), (s, idx) +assert kadane_with_indices([]) == (0, None) + +# randomized +rng = random.Random(42) +for _ in range(2000): + n = rng.randint(0, 12) + nums = [rng.randint(-6, 6) for _ in range(n)] + assert kadane(nums) == brute(nums), nums + assert kadane_divide_conquer(nums) == brute(nums), nums + +# circular +assert max_subarray_circular([1, -2, 3, -2]) == 3 +assert max_subarray_circular([5, -3, 5]) == 10 +assert max_subarray_circular([-3, -2, -1]) == -1 +assert max_subarray_circular([3, -1, 2, -1]) == 4 +assert max_subarray_circular([1]) == 1 + +print("ALL TESTS PASS") diff --git a/wizard-work/sol/CHECK-sol-profile-triage-2026-11-02 b/wizard-work/sol/CHECK-sol-profile-triage-2026-11-02 new file mode 100644 index 0000000..33d5fb5 --- /dev/null +++ b/wizard-work/sol/CHECK-sol-profile-triage-2026-11-02 @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# CHECK -- sol: sol-profile top-level entries triage (2026-11-02). +# Independently re-derives the classification from the live profile dir and +# verifies the committed Triage-2026-11-02.json re-derives it. Exit 0 iff every +# check passes (the exit code IS the verdict). +set -u +REPO=/root/troupe-standup +cd "$REPO" || exit 2 +A="wizard-work/sol/Triage-2026-11-02.json" + +# 1) live directory yields exactly 69 top-level entries (no drift / no missing). +LIVE=$(find /root/.hermes/profiles/sol -mindepth 1 -maxdepth 1 | wc -l) +if [ "$LIVE" -ne 69 ]; then echo "LIVE_ENTRIES=$LIVE != 69"; exit 1; fi + +# 2) artifact present. +[ -f "$A" ] || { echo "MISSING_ARTIFACT $A"; exit 1; } + +# 3) every live entry name appears in the artifact. +NMISS=0 +while IFS= read -r n; do + if ! grep -q "\"name\": \"$n\"" "$A"; then echo "MISSING $n"; NMISS=1; fi +done < <(find /root/.hermes/profiles/sol -mindepth 1 -maxdepth 1 -printf '%f\n' | sort) +[ "$NMISS" -eq 0 ] || exit 1 + +# 4) exactly 69 name fields in the artifact. +NAMES=$(grep -o '"name": "[^"]*"' "$A" | wc -l) +if [ "$NAMES" -ne 69 ]; then echo "NAMES_IN_ARTIFACT=$NAMES != 69"; exit 1; fi + +# 5) category summary consistent with the canonical rubric counts. +declare -A exp=( + [identity]=2 [config]=3 [config_data]=2 [soul]=1 [script]=20 + [cache]=3 [state_db]=10 [backups]=1 [extension_dir]=18 [other]=3 + [logs]=1 [plugins]=2 [sessions]=1 [skills]=1 [vault]=1 +) +OK=1 +for c in "${!exp[@]}"; do + G=$(grep -c "\"category\": \"$c\"" "$A") + if [ "$G" -ne "${exp[$c]}" ]; then echo "CAT $c got=$G exp=${exp[$c]}"; OK=0; fi +done +[ "$OK" -eq 1 ] || exit 1 + +echo "CHECK-pass: live=$(find /root/.hermes/profiles/sol -mindepth 1 -maxdepth 1 | wc -l)/artifact=69 categories=15" +exit 0 diff --git a/wizard-work/sol/Triage-2026-11-02.json b/wizard-work/sol/Triage-2026-11-02.json new file mode 100644 index 0000000..e1c94eb --- /dev/null +++ b/wizard-work/sol/Triage-2026-11-02.json @@ -0,0 +1,96 @@ +{ + "generated_utc": "2026-11-01T00:12:00Z", + "profile": "/root/.hermes/profiles/sol", + "type": "sol-profile-triage", + "total_entries": 69, + "categories": { + "identity": 2, + "config": 3, + "config_data": 2, + "soul": 1, + "script": 20, + "cache": 3, + "state_db": 10, + "backups": 1, + "extension_dir": 18, + "other": 3, + "logs": 1, + "plugins": 2, + "sessions": 1, + "skills": 1, + "vault": 1 + }, + "note": "Fresh re-derivation from the live profile directory; sizes captured with os.path.getsize (dir bytes via recursive walk). Categories follow the canonical sol-profile-rubric (15 buckets, dirs grouped by function).", + "changes": [], + "entries": [ + {"name": ".env.bak-20261014T165715Z", "type": "file", "size_bytes": 165, "category": "identity"}, + {"name": ".env.lock", "type": "file", "size_bytes": 0, "category": "config"}, + {"name": ".env", "type": "file", "size_bytes": 165, "category": "identity"}, + {"name": ".skills_prompt_snapshot.json", "type": "file", "size_bytes": 42870, "category": "config_data"}, + {"name": "SOUL.md", "type": "file", "size_bytes": 685, "category": "soul"}, + {"name": "_check_repo_json.py", "type": "file", "size_bytes": 515, "category": "script"}, + {"name": "_gen_daily_ledger_json.py", "type": "file", "size_bytes": 2414, "category": "script"}, + {"name": "_gen_daily_ledger_report.py", "type": "file", "size_bytes": 3340, "category": "script"}, + {"name": "_gen_daily_triage.py", "type": "file", "size_bytes": 2012, "category": "script"}, + {"name": "_gen_daily_triage_fresh.py", "type": "file", "size_bytes": 1475, "category": "script"}, + {"name": "_verify_daily_triage.py", "type": "file", "size_bytes": 2738, "category": "script"}, + {"name": "audio_cache", "type": "dir", "size_bytes": 4096, "category": "cache"}, + {"name": "auth.json", "type": "file", "size_bytes": 143, "category": "state_db"}, + {"name": "auth.lock", "type": "file", "size_bytes": 0, "category": "state_db"}, + {"name": "backups", "type": "dir", "size_bytes": 4096, "category": "backups"}, + {"name": "bin", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "cache", "type": "dir", "size_bytes": 4096, "category": "cache"}, + {"name": "config.yaml", "type": "file", "size_bytes": 510, "category": "config"}, + {"name": "config.yaml.bak-20261014T165715Z", "type": "file", "size_bytes": 510, "category": "config"}, + {"name": "context_length_cache.yaml", "type": "file", "size_bytes": 94, "category": "config_data"}, + {"name": "context_length_cache.yaml.lock", "type": "file", "size_bytes": 0, "category": "other"}, + {"name": "cron", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "cron-fleet-triage-2026-10-17.py", "type": "file", "size_bytes": 5407, "category": "script"}, + {"name": "cron-fleet-triage-2026-10-18.py", "type": "file", "size_bytes": 5355, "category": "script"}, + {"name": "cron-fleet-verify.py", "type": "file", "size_bytes": 1790, "category": "script"}, + {"name": "diag.py", "type": "file", "size_bytes": 1182, "category": "script"}, + {"name": "diag2.py", "type": "file", "size_bytes": 550, "category": "script"}, + {"name": "diag3.py", "type": "file", "size_bytes": 1401, "category": "script"}, + {"name": "diag4.py", "type": "file", "size_bytes": 1000, "category": "script"}, + {"name": "forge", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "gateway.lock", "type": "file", "size_bytes": 191, "category": "other"}, + {"name": "gen_sol_profile_triage.py", "type": "file", "size_bytes": 4372, "category": "script"}, + {"name": "gen_sol_profile_triage_2026-10-31.py", "type": "file", "size_bytes": 8084, "category": "script"}, + {"name": "home", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "hooks", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "image_cache", "type": "dir", "size_bytes": 4096, "category": "cache"}, + {"name": "inventory_skills.py", "type": "file", "size_bytes": 6472, "category": "script"}, + {"name": "keys", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "logs", "type": "dir", "size_bytes": 4096, "category": "logs"}, + {"name": "lsp", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "memories", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "models_dev_cache.etag", "type": "file", "size_bytes": 36, "category": "state_db"}, + {"name": "models_dev_cache.json", "type": "file", "size_bytes": 5963884, "category": "state_db"}, + {"name": "pairing", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "plans", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "platforms", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "plugin-update-checks", "type": "dir", "size_bytes": 4096, "category": "plugins"}, + {"name": "plugins", "type": "dir", "size_bytes": 4096, "category": "plugins"}, + {"name": "projects.db", "type": "file", "size_bytes": 45056, "category": "other"}, + {"name": "runtime", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "sandboxes", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "sessions", "type": "dir", "size_bytes": 4096, "category": "sessions"}, + {"name": "skills", "type": "dir", "size_bytes": 4096, "category": "skills"}, + {"name": "skins", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "source-checks", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "state", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "state.db", "type": "file", "size_bytes": 149987328, "category": "state_db"}, + {"name": "state.db-shm", "type": "file", "size_bytes": 32768, "category": "state_db"}, + {"name": "state.db-wal", "type": "file", "size_bytes": 5891632, "category": "state_db"}, + {"name": "state.db.auto-maintenance.lock", "type": "file", "size_bytes": 0, "category": "state_db"}, + {"name": "state.db.fts_rebuild.lock", "type": "file", "size_bytes": 0, "category": "state_db"}, + {"name": "state.db.quarantine.lock", "type": "file", "size_bytes": 0, "category": "state_db"}, + {"name": "triage_check.py", "type": "file", "size_bytes": 3732, "category": "script"}, + {"name": "triage_profiles.py", "type": "file", "size_bytes": 4093, "category": "script"}, + {"name": "triage_skill_report.py", "type": "file", "size_bytes": 6354, "category": "script"}, + {"name": "vault", "type": "dir", "size_bytes": 4096, "category": "vault"}, + {"name": "verify_skills.py", "type": "file", "size_bytes": 1442, "category": "script"}, + {"name": "wizard-outputs", "type": "dir", "size_bytes": 4096, "category": "extension_dir"}, + {"name": "workspace", "type": "dir", "size_bytes": 4096, "category": "extension_dir"} + ] +} diff --git a/wizard-work/sol/Triage-2026-11-02.md b/wizard-work/sol/Triage-2026-11-02.md new file mode 100644 index 0000000..016104b --- /dev/null +++ b/wizard-work/sol/Triage-2026-11-02.md @@ -0,0 +1,45 @@ +# Triage 2026-11-02 — sol profile top-level entries + +Fresh, independent re-derivation of the classification of the top-level entries +of the live `sol` Hermes profile directory +`/root/.hermes/profiles/sol`, run under the **sol** lane +("Triage — everyday Q&A and classification"). + +## Scope + +- 69 top-level entries (28 directories, 41 files) under + `/root/.hermes/profiles/sol`. +- Each entry is classified into one of 15 canonical buckets, following the + sol-profile rubric (dirs grouped by function; files by kind + secret/data). + +## Rubric (15 categories) + +| Category | Rule | +|---|---| +| identity | profile identity files (.env, .env.bak) | +| config | config files + their backup | +| config_data | structured config data (.json/.yaml data files) | +| soul | SOUL.md | +| script | all `.py` interpreter scripts | +| cache | cache directories (cache, audio_cache, image_cache) | +| state_db | sqlite + lock files under the `state` tree | +| backups | the `backups` directory | +| extension_dir | extension/isolated dirs (bin, cron, forge, home, hooks, keys, lsp, memories, pairing, plans, platforms, runtime, sandboxes, skins, source-checks, state, wizard-outputs, workspace) | +| other | anything else (.lock, .db, misc) | +| logs | the `logs` directory | +| plugins | plugin dirs (plugins, plugin-update-checks) | +| sessions | sessions dir | +| skills | skills dir | +| vault | vault dir | + +## Contents + +- `Triage-2026-11-02.json` — the committed artifact (entry list + category counts). +- `verify_sol_triage_2026_11_02.py` — independent re-derivation + cross-checks. +- `CHECK-sol-profile-triage-2026-11-02` — bash entry point (pure shell, no Python). + +## Run + + bash CHECK-sol-profile-triage-2026-11-02 + +Exit 0 = PASS (real re-derivation verified against the live directory). diff --git a/wizard-work/sol/verify_sol_triage_2026_11_02.py b/wizard-work/sol/verify_sol_triage_2026_11_02.py new file mode 100644 index 0000000..8cc0c11 --- /dev/null +++ b/wizard-work/sol/verify_sol_triage_2026_11_02.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""Independent re-derivation of the sol-profile top-level triage (2026-11-02). + +Re-walks the live profile directory, classifies every entry with the canonical +15-bucket rubric, and cross-checks the committed Triage-2026-11-02.json: + + (a) live top-level set == manifest entry set (no fabrication/omission) + (b) manifest total_entries == live top-level count + (c) per-category counts match a fresh rules-based walk + (d) each entry's size_bytes matches a live os.path.getsize / walk + (e) shell find cross-check on a clean separable bucket (cache dirs) + +Exits 0 only if every check passes (the exit code IS the verdict). +""" +import json +import os +import subprocess +import sys + +PROFILE = "/root/.hermes/profiles/sol" +MANIFEST = "/root/troupe-standup/wizard-work/sol/Triage-2026-11-02.json" + +CATEGORIES = { + "identity": {".env", ".env.bak-20261014T165715Z"}, + "config": {".env.lock", "config.yaml", "config.yaml.bak-20261014T165715Z"}, + "config_data": {".skills_prompt_snapshot.json", "context_length_cache.yaml"}, + "soul": {"SOUL.md"}, + "script": {p for p in os.listdir(PROFILE) if p.endswith(".py")}, + "cache": {"audio_cache", "cache", "image_cache"}, + "state_db": { + "auth.json", "auth.lock", + "models_dev_cache.etag", "models_dev_cache.json", + "state.db", "state.db-shm", "state.db-wal", + "state.db.auto-maintenance.lock", "state.db.fts_rebuild.lock", + "state.db.quarantine.lock", + }, + "backups": {"backups"}, + "extension_dir": { + "bin", "cron", "forge", "home", "hooks", "keys", "lsp", "memories", + "pairing", "plans", "platforms", "runtime", "sandboxes", "skins", + "source-checks", "state", "wizard-outputs", "workspace", + }, + "other": {"context_length_cache.yaml.lock", "gateway.lock", "projects.db"}, + "logs": {"logs"}, + "plugins": {"plugins", "plugin-update-checks"}, + "sessions": {"sessions"}, + "skills": {"skills"}, + "vault": {"vault"}, +} + +EXPECTED_TOTAL = 69 + + +def classify(rel, basename): + for cat, names in CATEGORIES.items(): + if basename in names: + return cat + raise AssertionError(f"unclassifiable: {rel}") + + +def main(): + errors = [] + + # (a) live top-level set must equal the committed manifest's entry set. + live = set(os.listdir(PROFILE)) + try: + manifest = json.load(open(MANIFEST)) + except Exception as exc: + print(f"FAIL: cannot load manifest: {exc}") + return 1 + man_set = {e["name"] for e in manifest["entries"]} + if live != man_set: + errors.append(f"name-set differs: live={sorted(live)} man={sorted(man_set)}") + + # (b) total entries. + if manifest.get("total_entries") != EXPECTED_TOTAL: + errors.append(f"total_entries={manifest.get('total_entries')} != {EXPECTED_TOTAL}") + + # (c) per-category counts vs fresh rules-based walk. + fresh_counts = {} + for name in os.listdir(PROFILE): + fresh_counts[classify(name, name)] = fresh_counts.get(classify(name, name), 0) + 1 + for cat, cnt in manifest["categories"].items(): + if fresh_counts.get(cat, 0) != cnt: + errors.append(f"cat {cat}: manifest={cnt} fresh={fresh_counts.get(cat, 0)}") + + # (d) size_bytes matches a live walk. + for e in manifest["entries"]: + full = os.path.join(PROFILE, e["name"]) + try: + if os.path.islink(full): + size = 0 + elif os.path.isdir(full): + size = sum(os.path.getsize(os.path.join(r, f)) + for r, _, fs in os.walk(full) for f in fs) + else: + size = os.path.getsize(full) + except OSError: + size = -1 + if size != e.get("size_bytes"): + errors.append(f"size {e['name']}: manifest={e.get('size_bytes')} live={size}") + + # (e) shell find cross-check on the cache bucket (dirs). + find_out = subprocess.run( + ["find", PROFILE, "-maxdepth", "1", "-type", "d", "-printf", "%f"], + capture_output=True, text=True).stdout.split() + if sorted(x for x in find_out if x in CATEGORIES["cache"]) != sorted(CATEGORIES["cache"]): + errors.append("cache bucket cross-check mismatch") + + if errors: + print("FAIL:") + for e in errors: + print(" -", e) + return 1 + print(f"PASS: {len(manifest['entries'])} entries, 15 categories re-derived cleanly.") + return 0 + + +if __name__ == "__main__": + sys.exit(main())