kin: KIN-DOCS-003-backend_dev

This commit is contained in:
Gros Frumos 2026-03-19 19:06:18 +02:00
parent a0d2f814e4
commit 55f37b9444
6 changed files with 180 additions and 13 deletions

View file

@ -75,6 +75,9 @@ def build_context(
ctx["modules"] = models.get_modules(conn, project_id)
ctx["decisions"] = models.get_decisions(conn, project_id)
elif role == "knowledge_synthesizer":
ctx["decisions"] = models.get_decisions(conn, project_id)
elif role == "debugger":
ctx["decisions"] = models.get_decisions(
conn, project_id, types=["gotcha", "workaround"],

View file

@ -10,7 +10,7 @@ import sqlite3
from core import models
# Canonical order of research roles (architect always last)
# Canonical order of research roles (knowledge_synthesizer and architect always last)
RESEARCH_ROLES = [
"business_analyst",
"market_researcher",
@ -18,6 +18,7 @@ RESEARCH_ROLES = [
"tech_researcher",
"ux_designer",
"marketer",
"knowledge_synthesizer",
"architect",
]
@ -29,17 +30,18 @@ ROLE_LABELS = {
"tech_researcher": "Tech Researcher",
"ux_designer": "UX Designer",
"marketer": "Marketer",
"knowledge_synthesizer": "Knowledge Synthesizer",
"architect": "Architect",
}
def validate_roles(roles: list[str]) -> list[str]:
"""Filter unknown roles, remove duplicates, strip 'architect' (auto-added later)."""
"""Filter unknown roles, remove duplicates, strip auto-managed roles (architect, knowledge_synthesizer)."""
seen: set[str] = set()
result = []
for r in roles:
r = r.strip().lower()
if r == "architect":
if r in ("architect", "knowledge_synthesizer"):
continue
if r in RESEARCH_ROLES and r not in seen:
seen.add(r)
@ -48,9 +50,18 @@ def validate_roles(roles: list[str]) -> list[str]:
def build_phase_order(selected_roles: list[str]) -> list[str]:
"""Return roles in canonical RESEARCH_ROLES order, append architect if any selected."""
ordered = [r for r in RESEARCH_ROLES if r in selected_roles and r != "architect"]
"""Return roles in canonical RESEARCH_ROLES order.
Auto-inserts knowledge_synthesizer before architect when 2 researchers selected.
Architect always appended last when any researcher is selected.
"""
ordered = [
r for r in RESEARCH_ROLES
if r in selected_roles and r not in ("architect", "knowledge_synthesizer")
]
if ordered:
if len(ordered) >= 2:
ordered.append("knowledge_synthesizer")
ordered.append("architect")
return ordered
@ -114,6 +125,24 @@ def activate_phase(conn: sqlite3.Connection, phase_id: int) -> dict:
"phase_order": phase["phase_order"],
"workflow": "research",
}
# knowledge_synthesizer: collect approved researcher outputs into phases_context
if phase["role"] == "knowledge_synthesizer":
all_phases = models.list_phases(conn, phase["project_id"])
phases_context = {}
for p in all_phases:
if p["status"] == "approved" and p.get("task_id"):
row = conn.execute(
"""SELECT output_summary FROM agent_logs
WHERE task_id = ? AND success = 1
ORDER BY created_at DESC LIMIT 1""",
(p["task_id"],),
).fetchone()
if row and row["output_summary"]:
phases_context[p["role"]] = row["output_summary"]
if phases_context:
brief["phases_context"] = phases_context
task = models.create_task(
conn, task_id, phase["project_id"],
title=f"[Research] {ROLE_LABELS.get(phase['role'], phase['role'])}",