kin: auto-commit after pipeline

This commit is contained in:
Gros Frumos 2026-03-17 17:26:31 +02:00
parent 17d7806838
commit eab9e951ab
12 changed files with 1696 additions and 5 deletions

View file

@ -1058,6 +1058,17 @@ def _execute_department_head_step(
# Blocked status from dept head
if parsed.get("status") == "blocked":
reason = parsed.get("blocked_reason", "Department head reported blocked")
# KIN-084: log dept head blocked
if parent_pipeline_id:
try:
models.write_log(
conn, parent_pipeline_id,
f"Dept {step['role']} blocked: {reason}",
level="WARN",
extra={"role": step["role"], "blocked_reason": reason},
)
except Exception:
pass
return {
"success": False,
"output": json.dumps(parsed, ensure_ascii=False),
@ -1095,6 +1106,18 @@ def _execute_department_head_step(
},
}, ensure_ascii=False)
# KIN-084: log sub-pipeline start
if parent_pipeline_id:
try:
sub_roles = [s.get("role", "") for s in sub_pipeline]
models.write_log(
conn, parent_pipeline_id,
f"Sub-pipeline start: dept={dept_name}, steps={len(sub_pipeline)}",
extra={"dept_name": dept_name, "sub_steps": len(sub_pipeline), "sub_roles": sub_roles},
)
except Exception:
pass
# Run the sub-pipeline (noninteractive=True — Opus already reviewed the plan)
# pass parent_pipeline_id and department so run_pipeline creates the child
# pipeline with correct attributes (route_type='dept_sub') — no double create
@ -1108,6 +1131,19 @@ def _execute_department_head_step(
department=dept_name,
)
# KIN-084: log sub-pipeline done
if parent_pipeline_id:
try:
sub_success = sub_result.get("success", False)
models.write_log(
conn, parent_pipeline_id,
f"Sub-pipeline done: dept={dept_name}, success={sub_success}, steps={sub_result.get('steps_completed', 0)}",
level="INFO" if sub_success else "ERROR",
extra={"dept_name": dept_name, "success": sub_success, "steps_completed": sub_result.get("steps_completed", 0)},
)
except Exception:
pass
# Extract decisions from sub-pipeline results for handoff
decisions_made = []
sub_results = sub_result.get("results", [])
@ -1268,6 +1304,15 @@ def run_pipeline(
# Save PID so watchdog can detect dead subprocesses (KIN-099)
pipeline = models.update_pipeline(conn, pipeline["id"], pid=os.getpid())
models.update_task(conn, task_id, status="in_progress")
# KIN-084: log pipeline start
try:
models.write_log(
conn, pipeline["id"],
f"Pipeline start: task={task_id}, steps={len(steps)}, route_type={effective_route_type}, mode={mode}",
extra={"route_type": effective_route_type, "steps_count": len(steps), "mode": mode},
)
except Exception:
pass
results = []
total_cost = 0.0
@ -1281,6 +1326,19 @@ def run_pipeline(
model = step.get("model", "sonnet")
brief = step.get("brief")
# KIN-084: log step start
try:
if pipeline:
brief_preview = (step.get("brief") or "")[:100]
models.write_log(
conn, pipeline["id"],
f"Step {i+1}/{len(steps)} start: role={role}, model={model}",
level="INFO",
extra={"role": role, "model": model, "brief_preview": brief_preview},
)
except Exception:
pass
# Check parent process is still alive (KIN-099 watchdog)
if not dry_run and pipeline:
if _check_parent_alive(conn, pipeline, task_id, project_id):
@ -1335,6 +1393,16 @@ def run_pipeline(
total_tokens=total_tokens,
total_duration_seconds=total_duration,
)
# KIN-084: log step exception
try:
models.write_log(
conn, pipeline["id"],
f"Step {i+1}/{len(steps)} exception: {exc}",
level="ERROR",
extra={"role": role, "exc_type": type(exc).__name__},
)
except Exception:
pass
models.log_agent_run(
conn,
project_id=project_id,
@ -1382,6 +1450,23 @@ def run_pipeline(
total_tokens += result.get("tokens_used") or 0
total_duration += result.get("duration_seconds") or 0
# KIN-084: log step done
try:
if pipeline:
models.write_log(
conn, pipeline["id"],
f"Step {i+1}/{len(steps)} done: role={role}, success={result.get('success')}",
level="INFO",
extra={
"role": role,
"tokens_used": result.get("tokens_used") or 0,
"cost_usd": result.get("cost_usd") or 0,
"duration_seconds": result.get("duration_seconds") or 0,
},
)
except Exception:
pass
if not result["success"]:
# Auto mode: retry once with allow_write on permission error
if mode == "auto_complete" and not allow_write and _is_permission_error(result):
@ -1433,6 +1518,17 @@ def run_pipeline(
total_duration_seconds=total_duration,
)
agent_error = result.get("error") or ""
# KIN-084: log step failed
try:
if pipeline:
models.write_log(
conn, pipeline["id"],
f"Step {i+1}/{len(steps)} failed: {agent_error}",
level="ERROR",
extra={"role": role, "error": agent_error},
)
except Exception:
pass
error_msg = f"Step {i+1}/{len(steps)} ({role}) failed"
if agent_error:
error_msg += f": {agent_error}"
@ -1499,6 +1595,16 @@ def run_pipeline(
total_tokens=total_tokens,
total_duration_seconds=total_duration,
)
# KIN-084: log step blocked
try:
models.write_log(
conn, pipeline["id"],
f"Step {i+1}/{len(steps)} blocked: {blocked_info['reason']}",
level="WARN",
extra={"role": role, "reason": blocked_info["reason"]},
)
except Exception:
pass
models.update_task(
conn, task_id,
status="blocked",
@ -1746,6 +1852,20 @@ def run_pipeline(
total_tokens=total_tokens,
total_duration_seconds=total_duration,
)
# KIN-084: log pipeline completed
try:
models.write_log(
conn, pipeline["id"],
f"Pipeline completed: {len(steps)} steps, cost=${total_cost:.4f}, tokens={total_tokens}, duration={total_duration}s",
extra={
"total_cost_usd": total_cost,
"total_tokens": total_tokens,
"total_duration_seconds": total_duration,
"steps_count": len(steps),
},
)
except Exception:
pass
task_modules = models.get_modules(conn, project_id)
@ -1771,6 +1891,15 @@ def run_pipeline(
elif mode == "auto_complete" and auto_eligible:
# Auto-complete mode: last step is tester/reviewer — skip review, approve immediately
models.update_task(conn, task_id, status="done")
# KIN-084: log task status
try:
models.write_log(
conn, pipeline["id"],
"Task status: done",
extra={"task_status": "done", "mode": mode},
)
except Exception:
pass
try:
run_hooks(conn, project_id, task_id,
event="task_auto_approved", task_modules=task_modules)
@ -1800,6 +1929,15 @@ def run_pipeline(
else:
# Review mode: wait for manual approval
models.update_task(conn, task_id, status="review", execution_mode="review")
# KIN-084: log task status
try:
models.write_log(
conn, pipeline["id"],
"Task status: review",
extra={"task_status": "review", "mode": mode},
)
except Exception:
pass
# Run post-pipeline hooks (failures don't affect pipeline status)
try: