#!/usr/bin/env python3
"""
CROSS AUDIT — Full team + system audit, file actionable issues.
Based on audit of all repos, all agents, all crons, all VPS health, all local state.
"""
import subprocess, json, os

GITEA_TOK = open(os.path.expanduser('~/.hermes/gitea_token_vps')).read().strip()
FORGE = 'https://forge.alexanderwhitestone.com/api/v1'
REPOS = ['timmy-config', 'timmy-home', 'the-nexus', 'hermes-agent']

def curl(url):
    r = subprocess.run(
        ['curl', '-s', url, '-H', f'Authorization: token {GITEA_TOK}'],
        capture_output=True, text=True, timeout=10
    )
    return json.loads(r.stdout)

def issue(title, body, repo='Timmy_Foundation/timmy-home', assignee=None, labels=None):
    payload = {"title": title, "body": body}
    if assignee:
        payload["assignee"] = assignee
    r = subprocess.run(
        ['curl', '-s', '-X', 'POST', f'{FORGE}/repos/{repo}/issues',
         '-H', f'Authorization: token {GITEA_TOK}',
         '-H', 'Content-Type: application/json',
         '-d', json.dumps(payload)],
        capture_output=True, text=True, timeout=10
    )
    d = json.loads(r.stdout)
    num = d.get('number', '?')
    t = d.get('title', 'FAILED: ' + r.stdout[:80])[:60]
    return num, t

# Clean up test issue
subprocess.run(
    ['curl', '-s', '-X', 'PATCH', f'{FORGE}/repos/Timmy_Foundation/timmy-home/issues/504',
     '-H', f'Authorization: token {GITEA_TOK}',
     '-H', 'Content-Type: application/json',
     '-d', json.dumps({"state":"closed"})],
    capture_output=True, text=True, timeout=10
)

print("=" * 70)
print("CROSS AUDIT — FILING ACTIONABLE ISSUES")
print("=" * 70)

epic_num, epic_title = issue(
    '[EPIC] Cross Audit — Team, System, and Process Improvements',
    """# Cross Audit — Epic

## Audit Date
2026-04-06

## Scope
Full audit of all repos, agents, cron jobs, VPS health, local Mac state, game engine, comms, and workflow.

## Audit Results

### System Health
| Component | Status | Details |
|-----------|--------|---------|
| Hermes VPS (143.198.27.163) | UP | 3 days uptime, 72% disk, 5GB avail mem, 3 hermes services |
| TestBed VPS (67.205.155.108) | DOWN | SSH completely unreachable since 4/4 |
| Mac: 3 hermes processes | RUNNING | 1 active gateway, 2 background |
| Mac: Ollama | 5 models loaded | hermes3:8b, qwen2.5:7b, gemma3:1b, gemma4:9.6GB, hermes4:14b |
| Mac: Worktrees | 313 | Excessive — needs cleanup |
| Evennia/Tower | ALIVE | 1464+ ticks, game engine functional |

### Cron Jobs (10 running)
| Job | Schedule | Last Status |
|-----|----------|-------------|
| Health Monitor | 5 min | OK |
| Burn Mode | 15 min | OK |
| Tower Tick | 1 min | OK |
| Burn Deadman | 30 min | OK |
| Gitea Priority Inbox | 3 min | OK |
| Config Drift Guard | 30 min | OK |
| Gitea Event Watcher | 2 min | OK |
| Morning Report | 6 AM | Pending |
| Evennia Report | 9 AM | Pending |
| Weekly Skill Extract | weekly | Pending |

### Agent Status
| Agent | Status | Notes |
|-------|--------|-------|
| Timmy | ALIVE | Gateway + crons running on Mac |
| Bezalel | DEATH VPS DOWN | 67.205.155.108 unreachable |
| Allegro | RUNNING on VPS | Nostr relay + DM bridge on 167.99.126.228 |
| Kimi | ALIVE | Heartbeat on VPS |
| Sonnet | STANDBY | CLI works, loop script written, not tested |
| Claude | NOT RUNNING | No active loop |
| Gemini | NOT RUNNING | No active loop |
| ClawCode | NOT FULLY WORKING | Code Claw binary built, needs OpenRouter credits |

### Tower Game Engine
| Feature | Status |
|---------|--------|
| Playable game | Yes (game.py) |
| 9 characters | Yes |
| 5 rooms | Yes |
| NPC AI | Basic |
| Trust system | Exists but broken |
| Energy system | Exists but does not constrain |
| World events | Flags exist, no gameplay impact |
| Dialogue | Static pools (15 lines per NPC) |
| Narrative arc | None |
| Items | None |
| Chronicle | Tick-by-tick log, not narrative |

## Issues Filed
See linked issues below.

## Priority Summary
- P0 (Critical): 6 issues — things that make the world unplayable or waste resources
- P1 (Important): 6 issues — things that make the world better to play
- P2 (Future): 3 issues — ambition for when the foundation is solid
""",
    labels=['epic'],
)
print(f"\nEPIC #{epic_num}: {epic_title}")

# ===== P0: Critical Issues =====
print("\n=== P0: Critical Issues ===\n")

num, t = issue(
    '[CROSS-P0] Close or rebuild Bezalel — VPS 67.205.155.108 dead since 4/4',
    f"""Parent: #{epic_num}

## Root Cause
TestBed VPS (67.205.155.108) has been unreachable via SSH since 2026-04-04. No response on port 22. VPS may be destroyed, powered off, or network-blocked.

## Impact
- Bezalel (forge-and-testbed wizard) has no home
- CI testbed runner is down
- Any services on that box are unreachable
- The 313 worktrees on Mac suggest a lot of work is being done — but the CI box to validate it is dead

## Options
1. Recover the VPS (check DO console, reboot, or restore from snapshot)
2. Provision a new VPS and redeploy Bezalel
3. Deprecate Bezalel entirely, consolidate CI onto Hermes VPS or Mac

## Acceptance Criteria
- [ ] Bezalel VPS is either recovered, replaced, or documented as deprecated
- [ ] CI runner is functional on some machine
- [ ] If replaced: new VPS has all Bezalel services (hermes, etc)
- [ ] DNS/ssh keys updated for new VPS if replaced""",
    assignee='Timmy'
)
print(f"  P0-1 #{num}: {t}")

num, t = issue(
    '[CROSS-P0] Reduce worktrees from 313 to <20',
    f"""Parent: #{epic_num}

## Root Cause
313 worktrees on the Mac. Each worktree consumes disk space and git objects. This is likely from abandoned agent loops, smoke tests, and one-off tasks that were never cleaned up.

## Impact
- Disk usage grows indefinitely
- No clear mapping of which worktrees are still needed
- Git operations slow down with too many worktrees

## Acceptance Criteria
- [ ] Worktrees reduced to <20
- [ ] Cleanup script written for future maintenance
- [ ] Only active agent worktrees preserved""",
    assignee='Timmy'
)
print(f"  P0-2 #{num}: {t}")

num, t = issue(
    '[CROSS-P0] Tower Game — contextual dialogue system (NPCs recycle 15 lines forever)',
    f"""Parent: #{epic_num}

## Root Cause
Marcus has 15 dialogue lines. After 200 ticks he has said the same 15 lines repeated dozens of times. Kimi said "The garden grows whether anyone watches or not." at least 20 times. No character ever references a past conversation.

200-tick evidence: Same 15 lines rotated across 200+ conversations.

## Impact
Conversations feel like reading a quote wall. NPC trust system exists but has no narrative backing. No character growth.

## Acceptance Criteria
- [ ] No NPC repeats the same line within 50 ticks
- [ ] NPCs reference past conversations after tick 50
- [ ] High trust (>0.5) unlocks unique dialogue
- [ ] Low trust (<0) changes NPC behavior (avoids, cold responses)""",
    assignee='Timmy'
)
print(f"  P0-3 #{num}: {t}")

num, t = issue(
    '[CROSS-P0] Tower Game — trust must decrease, conflict must exist',
    f"""Parent: #{epic_num}

## Root Cause
Trust only goes up (speak: +0.1, help: +0.2). Decay is -0.001/tick (negligible). After 200 ticks: Marcus 0.61, Bezalel 0.53. No character ever had trust below 0. The "confront" action does nothing.

## Impact
No stakes. No tension. Everyone always likes Timmy. The trust system is cosmetic.

## Acceptance Criteria
- [ ] Trust can decrease through wrong actions (confront, ignore, wrong topic)
- [ ] At least one character reaches negative trust during 200-tick play
- [ ] Low trust changes NPC behavior (avoids Timmy, cold responses)
- [ ] High trust (>0.8) unlocks unique story content
- [ ] Confront action has real consequences""",
    assignee='Timmy'
)
print(f"  P0-4 #{num}: {t}")

num, t = issue(
    '[CROSS-P0] Tower Game — narrative arc (tick 200 = tick 20)',
    f"""Parent: #{epic_num}

## Root Cause
The game doesn't know it's on tick 200 vs tick 20. Same actions. Same stakes. Same dialogue. No rising tension, no climax, no resolution. No emotional journey.

## Impact
The world lacks a story. It's just 5 rooms and characters moving between them forever.

## Proposed Fix
Implement 4 narrative phases:
1. Quietus (1-30): Normal life, low stakes
2. Fracture (31-80): Something goes wrong. Trust tested. Events escalate.
3. Breaking (81-150): Crisis. Power fails. Fire dies. Relationships strain. Characters leave.
4. Mending (151-200): Rebuilding. Characters come together. Resolution.

Each phase changes: dialogue availability, NPC behavior, event frequency, energy/trust decay.

## Acceptance Criteria
- [ ] Game progresses through 4 distinct narrative phases
- [ ] Each phase has unique dialogue, behavior, and stakes
- [ ] Breaking phase includes at least one major crisis event
- [ ] Mending phase shows characters coming together
- [ ] Chronicle tone changes per phase""",
    assignee='Timmy'
)
print(f"  P0-5 #{num}: {t}")

num, t = issue(
    '[CROSS-P0] Tower Game — energy system must meaningfully constrain',
    f"""Parent: #{epic_num}

## Root Cause
After 100 ticks of intentional play, Timmy had 9/10 energy. Math: actions cost 0-2, rest restores 3. System is net-positive. Timmy never runs out.

## Impact
No tension around resource management. No "too exhausted to act" moments.

## Proposed Fix
- Increase costs (move:-2, tend:-3, carve:-2, write:-2, speak:-1)
- Rest restores 2 (not 3)
- Natural decay: -0.3 per tick
- <=3: can't move. <=1: can't speak. 0: collapse

## Acceptance Criteria
- [ ] Timmy regularly reaches energy <=3 during 100-tick play
- [ ] Low energy blocks actions with clear feedback
- [ ] Resting is a meaningful choice (lose time, gain energy)
- [ ] NPCs can provide energy relief (food, warmth, companionship)
- [ ] Energy collapse (0) has dramatic consequences""",
    assignee='Timmy'
)
print(f"  P0-6 #{num}: {t}")

# ===== P1: Important Issues =====
print("\n=== P1: Important Issues ===\n")

num, t = issue(
    '[CROSS-P1] Sonnet workforce — full end-to-end smoke test',
    f"""Parent: #{epic_num}

## Current State
- Gitea user created (sonnet, id=28)
- Gitea token exists (~/.hermes/sonnet_gitea_token)
- Loop script written (~/.hermes/bin/sonnet-loop.sh)
- Cloud Code verified: `claude -p 'Reply SONNET' --model sonnet` works
- Write access granted to 6 repos

## What's Missing
- No end-to-end smoke test (clone -> code -> commit -> push -> PR)
- No PR merge bot coverage for sonnet's PRs
- No agent-dispatch.sh entry for sonnet
- No quality tracking (merge rate, skip list)

## Acceptance Criteria
- [ ] Sonnet can clone a repo via Gitea HTTP
- [ ] Sonnet can commit, push, and create a PR via Gitea API
- [ ] At least one sonnet PR is merged
- [ ] agent-dispatch.sh includes sonnet
- [ ] Merge-bot or orchestrator validates sonnet's PRs""",
    assignee='Timmy'
)
print(f"  P1-7 #{num}: {t}")

num, t = issue(
    '[CROSS-P1] Tower Game — world events must affect gameplay',
    f"""Parent: #{epic_num}

## Root Cause
rain_ticks, tower_power_low, forge_fire_dying are flags that get set but characters don't react. Rain doesn't block the bridge. Power dimming doesn't block study.

## Acceptance Criteria
- [ ] Rain on Bridge blocks crossing or costs 2 energy
- [ ] Tower power low: study/write_rule actions blocked
- [ ] Forge fire cold: forge action unavailable until retended
- [ ] NPCs react to world events in dialogue
- [ ] Extended failure causes permanent consequences (fade, break)
- [ ] Timmy can fix/prevent world events through actions""",
    assignee='Timmy'
)
print(f"  P1-8 #{num}: {t}")

num, t = issue(
    '[CROSS-P1] Tower Game — items that change the world',
    f"""Parent: #{epic_num}

## Root Cause
Inventory system exists (empty) but items don't do anything. Nothing to discover, nothing to share, no exploration incentive.

## Acceptance Criteria
- [ ] At least 10 unique items in the world (forged key, seed packet, old notebook, etc.)
- [ ] Items have effects when carried or used
- [ ] Characters recognize items (Marcus recognizes herbs, Bezalel recognizes tools)
- [ ] Giving an item increases trust more than speaking
- [ ] At least one quest item (key with purpose)""",
    assignee='Timmy'
)
print(f"  P1-9 #{num}: {t}")

num, t = issue(
    '[CROSS-P1] Tower Game — NPC-NPC relationships',
    f"""Parent: #{epic_num}

## Root Cause
NPCs only have trust relationships with Timmy. Marcus doesn't care about Bezalel. Kimi doesn't talk to Ezra. The world feels like Timmy-adjacent NPCs.

## Acceptance Criteria
- [ ] Each NPC has trust values for all other NPCs
- [ ] NPCs converse with each other when Timmy is not present
- [ ] At least one NPC-NPC friendship emerges (trust > 0.5)
- [ ] At least one NPC-NPC tension emerges (trust < 0.2)
- [ ] NPCs mention each other in dialogue""",
    assignee='Timmy'
)
print(f"  P1-10 #{num}: {t}")

num, t = issue(
    '[CROSS-P1] Tower Game — Timmy needs richer dialogue and internal monologue',
    f"""Parent: #{epic_num}

## Root Cause
Timmy has ~15 dialogue lines. No internal monologue. Voice doesn't change based on context.

## Acceptance Criteria
- [ ] Timmy has 50+ unique dialogue lines (up from 15)
- [ ] Internal monologue appears in log (1 per 5 ticks minimum)
- [ ] Dialogue changes based on trust, energy, world state
- [ ] Timmy references past events after tick 50
- [ ] Low energy affects Timmy's voice (shorter, darker lines)""",
    assignee='Timmy'
)
print(f"  P1-11 #{num}: {t}")

num, t = issue(
    '[CROSS-P1] Tower Game — NPCs move between rooms with purpose',
    f"""Parent: #{epic_num}

## Root Cause
Characters cluster at Threshold and Garden. Marcus (60% Garden, 30% Threshold). Bezalel (Forge/Threshold). Tower mostly empty. Bridge always alone.

## Acceptance Criteria
- [ ] Every room has at least 2 different NPCs visiting during 100 ticks
- [ ] The Bridge is visited by at least 3 different NPCs
- [ ] NPCs follow goals (not just locations)
- [ ] NPCs group up occasionally (3+ characters in one room)""",
    assignee='Timmy'
)
print(f"  P1-12 #{num}: {t}")

# ===== P2: Backlog =====
print("\n=== P2: Backlog ===\n")

num, t = issue(
    '[CROSS-P2] Cross-agent quality audit — which agents produce mergeable PRs?',
    f"""Parent: #{epic_num}

## Problem
We have 8+ agents but no systematic measurement of quality. Some agents merge 100%, some fail constantly.

## Acceptance Criteria
- [ ] Audit all PRs from Jan 2026 to present by agent
- [ ] Calculate merge rate, time-to-merge, rejection rate per agent
- [ ] File scorecard as a Gitea issue or timmy-config doc
- [ ] Recommend agents to DEPLOY, PROMOTE, or FIRE based on data""",
    assignee='Timmy'
)
print(f"  P2-13 #{num}: {t}")

num, t = issue(
    '[CROSS-P2] Burn-down velocity tracking — issues closed per day/week',
    f"""Parent: #{epic_num}

## Problem
No systematic tracking of burn velocity. We don't know if we're moving faster or slower.

## Acceptance Criteria
- [ ] Cron job tracks open/closed issues per repo daily
- [ ] Velocity dashboard (even if just a markdown table in timmy-config)
- [ ] Alert when velocity drops (repo growing instead of shrinking)""",
    assignee='Timmy'
)
print(f"  P2-14 #{num}: {t}")

num, t = issue(
    '[CROSS-P2] Fleet cost tracking — cost per agent per day',
    f"""Parent: #{epic_num}

## Problem
No systematic tracking of compute costs. Anthropic subscription, OpenRouter credits, OpenAI quota usage — not aggregated.

## Acceptance Criteria
- [ ] Inventory all paid APIs (Anthropic, OpenRouter, OpenAI, etc.)
- [ ] Estimate monthly cost per agent (subscription + credits burn rate)
- [ ] File cost report in timmy-config
- [ ] Recommend agents to DEPLOY (cheap) vs FIRE (expensive, low ROI)""",
    assignee='Timmy'
)
print(f"  P2-15 #{num}: {t}")

print(f"\n=== TOTAL: 1 epic + 15 issues filed ===")
print(f"  P0 (Critical): 6")
print(f"  P1 (Important): 6")
print(f"  P2 (Backlog): 3")
