missions: phase-completion summary card (Claude Opus 4.8 synthesized)
ci / gates (push) Successful in 6s
ci / rust (push) Failing after 9s
ci / frontend (push) Successful in 26s
ci / e2e (push) Skipped
ci / publish (push) Skipped

New phase_summarizer background worker fires on any mission_phase
transition to a terminal state (completed/failed). Aggregates every
topology_runs.checkpoint.outputs[] + mission_tasks + mission_artifacts
bound to that phase and asks Claude Opus 4.8 to produce a structured
JSON card:

  { narrative, metrics, sources, tooling, next_actions }

Rendered inline on the mission page under each completed phase via
new PhaseSummaryCard component. Metrics grid is kind-specific:
research surfaces insights/sources/int_cards/artifacts, coding
surfaces cards_picked_up/commits/tests/issues, benchmark surfaces
regressions/improvements, security surfaces findings-by-severity.

New table: mission_phase_summaries (migration 0060), unique per
phase_id — regenerates on retry.
New endpoint: GET /api/missions/{id}/phases/{phase_id}/summary.

Model overridable via CLAWMATES_SUMMARIZER_MODEL. Reuses the
ANTHROPIC_API_KEY prod already carries for mission_refiner.
This commit is contained in:
Omar Sobh
2026-07-23 16:54:38 -07:00
parent 1be3430bf2
commit 5c63ef0ed3
8 changed files with 1022 additions and 0 deletions
@@ -37,6 +37,7 @@ import { MissionLivePane } from "./MissionLivePane";
import { MissionTeamTab } from "./MissionTeamTab";
import { MissionWizard } from "./MissionWizard";
import { PhaseRunsList } from "./PhaseRunsList";
import { PhaseSummaryCard } from "./PhaseSummaryCard";
import { RefineDiffModal } from "./RefineDiffModal";
const mono =
@@ -681,6 +682,9 @@ export function MissionCanvas({
</span>
)}
<PhaseRunsList runs={runsByPhase.get(p.id) ?? []} />
{(p.status === "completed" || p.status === "failed") && (
<PhaseSummaryCard missionId={mission.id} phaseId={p.id} />
)}
{mission.status === "running" || mission.status === "completed" ? (
<div style={{ display: "flex", gap: 6, marginTop: 6 }}>
{p.status === "failed" && mission.status === "running" && (