# PI Orchestrator — Discipline Fixes & Restart Runbook (MC #105648)

# PI Orchestrator — 4 discipline fixa (MC #105648, 2026-07-14)

**Kontekst:** 3 incidenta istog dana tokom Bilko podsjetnik talasa (puni log: `~/system/evidence/105648/incident-log-2026-07-14.md`): (1) porezni research task klasifikovan kao devops + zombie lease bez workera; (2) intake klasifikator blokirao task s tuđim aktivnim lease-om; (3) claim-race na resume → drugi builder u istom worktree-u.

## Šta je fixano (pi-orchestrator.js, backup .bak-105648-20260714)

1. **Route prior u classify():** MC `route` polje je sada prior nad semantičkim klasifikatorom (`ROUTE_TO_DOMAIN_PRIOR` mapa; route=general → null). research više ne može postati devops.
2. **Worktree company konzistencija:** root cause — `task.company` se NIKAD nije popunjavao, `resolveBuildCwd()` je uvijek padao na hardkodirani 'CodeCraft'. Sada se postavlja odmah nakon klasifikacije.
3. **Heartbeat ↔ worker liveness:** `activeWorkerPids` registar + `isWorkerLive()`; `heartbeatClaimExtend` na mrtav/stale worker RELEASE-a lease (error log "zombie claim") umjesto produženja.
4. **Claim/block disciplina:** (a) grab-query isključuje tuđe aktivne lease-ove (ranije je gledao samo legacy `task_scheduling`, ne prave `tasks.lease_holder` kolone); (b) persona-keyword block gate preskače taskove s tuđim lease-om; (c) `checkWorktreeDispatchSafety` — nekomitovane tuđe izmjene u worktree-u = abort na queueForHuman.

## Verifikacija i deploy

- Verifier PASS (15/15 tvrdnji, nezavisni rerun 11/11 smoke): `~/system/evidence/105648/verifier-report.md`
- Deploy: graceful SIGTERM starog daemona → LaunchAgent KeepAlive respawn. **Živo potvrđeno:** PID 90759 start 23:08:05 > file mtime 22:48; prvi ciklus čist.

## Operativne lekcije (restart procedura)

- **Restart = `kill -TERM <pid>` + KeepAlive respawn ILI `launchctl kickstart -k gui/501/com.john.pi-orchestrator`. NIKAD `nohup node ... start`** — orphan procesi drže lock i blokiraju LaunchAgent.
- **Poznati bug (MC #105700):** orphan-detekcija matchuje bilo koji proces čiji command line sadrži pattern string — i tvoj monitoring grep! Prije restarta ugasi procese koji sadrže "pi-orchestrator.js start" u komandi.
- Session-less daemon i dalje ne može čist `mc.js done` (T9-C2 gate) — vidi `project_piorch_daemon_recovery_2026-06-19`.

## MC #105700 — orphan-guard false-positive FIXED (2026-07-15)

Bug iz "Poznati bug" bullet-a iznad je riješen. `startDaemon()` orphan-check (linije ~6598-6616) sada:
1. Koristi strict pattern `pgrep -f "node .*system/kernel/pi-orchestrator.js start"` (umjesto labavog substring `"pi-orchestrator.js start"`).
2. Za svaki kandidat PID verifikuje `ps -o comm= -p <PID>` == `node` (ili završava na `/node`) — shell/grep procesi čiji argv sadrži pattern string se više NE tretiraju kao orphan.
3. Fail-safe: ako ps provjera pukne, PID se NE tretira kao orphan (bolje propustiti duplicate-check nego blokirati respawn zbog stranog procesa).

Monitoring grep petlje više ne blokiraju KeepAlive respawn — nije potrebno gasiti ih prije restarta (bullet iznad ostaje kao historijski kontekst za stare verzije).

- Evidence: `~/system/evidence/105700/fix-evidence-2026-07-15.md` + repro test `orphan-guard.test.js` (decoy bash matched starom logikom, isključen novom; živi daemon PID 90759 i dalje detektovan, netaknut)
- Backup: `pi-orchestrator.js.bak-105700-orphanguard-20260715-092740`
- Aktivacija: na sljedeći prirodni restart daemona (živi proces nije diran).