Skip to content

Commit f9526a2

Browse files
authored
feat: evaluate runtime completion governance (#80)
* feat: evaluate runtime completion governance * feat: persist context and harness governance artifacts * feat: queue follow-up governance actions * fix: preserve finalize schema-failure handling * fix: address governance review nitpicks
1 parent 19076f3 commit f9526a2

18 files changed

Lines changed: 2177 additions & 54 deletions

apps/dashboard/components/RunDetail.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export default function RunDetail({
8383
const [planningContractsError, setPlanningContractsError] = useState("");
8484
const [unblockTasks, setUnblockTasks] = useState<Array<Record<string, unknown>>>([]);
8585
const [unblockTasksError, setUnblockTasksError] = useState("");
86+
const [contextPackArtifact, setContextPackArtifact] = useState<Record<string, unknown> | null>(null);
87+
const [harnessRequestArtifact, setHarnessRequestArtifact] = useState<Record<string, unknown> | null>(null);
8688
const [chainSpecError, setChainSpecError] = useState("");
8789
const [chainSpecLoading, setChainSpecLoading] = useState(false);
8890
const [liveEnabled, setLiveEnabled] = useState(true);
@@ -108,6 +110,9 @@ export default function RunDetail({
108110
const reviewReport = reportsState.find((r) => r.name === "review_report.json")?.data;
109111
const taskResult = reportsState.find((r) => r.name === "task_result.json")?.data;
110112
const workReport = reportsState.find((r) => r.name === "work_report.json")?.data;
113+
const completionGovernanceReport = toObject(
114+
reportsState.find((r) => r.name === "completion_governance_report.json")?.data
115+
);
111116
const evidenceReport = reportsState.find((r) => r.name === "evidence_report.json")?.data;
112117
const incidentPack = reportsState.find((r) => r.name === "incident_pack.json")?.data;
113118
const proofPack = reportsState.find((r) => r.name === "proof_pack.json")?.data;
@@ -147,6 +152,18 @@ export default function RunDetail({
147152
const path = toStringOr(record.path, "");
148153
return name === "planning_unblock_tasks" || path === "artifacts/planning_unblock_tasks.json";
149154
});
155+
const hasContextPackArtifact = manifestArtifacts.some((item) => {
156+
const record = toObject(item);
157+
const name = toStringOr(record.name, "");
158+
const path = toStringOr(record.path, "");
159+
return name === "context_pack" || path === "artifacts/context_pack.json";
160+
});
161+
const hasHarnessRequestArtifact = manifestArtifacts.some((item) => {
162+
const record = toObject(item);
163+
const name = toStringOr(record.name, "");
164+
const path = toStringOr(record.path, "");
165+
return name === "harness_request" || path === "artifacts/harness_request.json";
166+
});
150167
const observability = toObject(run?.manifest?.observability);
151168
const summaryGroups = ["reports/", "events.jsonl", "contract.json", "other"];
152169
const summary = summaryGroups.map((group) => {
@@ -319,6 +336,40 @@ export default function RunDetail({
319336
};
320337
}, [hasUnblockTasksArtifact, run?.run_id]);
321338

339+
useEffect(() => {
340+
let alive = true;
341+
async function loadGovernanceArtifacts() {
342+
if (!run?.run_id) {
343+
if (alive) {
344+
setContextPackArtifact(null);
345+
setHarnessRequestArtifact(null);
346+
}
347+
return;
348+
}
349+
const [contextPackRes, harnessRequestRes] = await Promise.allSettled([
350+
hasContextPackArtifact ? fetchArtifact(run.run_id, "context_pack.json") : Promise.resolve(null),
351+
hasHarnessRequestArtifact ? fetchArtifact(run.run_id, "harness_request.json") : Promise.resolve(null),
352+
]);
353+
if (!alive) {
354+
return;
355+
}
356+
setContextPackArtifact(
357+
contextPackRes.status === "fulfilled" && contextPackRes.value?.data && typeof contextPackRes.value.data === "object"
358+
? (contextPackRes.value.data as Record<string, unknown>)
359+
: null,
360+
);
361+
setHarnessRequestArtifact(
362+
harnessRequestRes.status === "fulfilled" && harnessRequestRes.value?.data && typeof harnessRequestRes.value.data === "object"
363+
? (harnessRequestRes.value.data as Record<string, unknown>)
364+
: null,
365+
);
366+
}
367+
void loadGovernanceArtifacts();
368+
return () => {
369+
alive = false;
370+
};
371+
}, [hasContextPackArtifact, hasHarnessRequestArtifact, run?.run_id]);
372+
322373
useEffect(() => {
323374
let alive = true;
324375
async function loadChainSpec() {
@@ -532,10 +583,13 @@ export default function RunDetail({
532583
pendingApprovals={pendingApprovals}
533584
evidenceHashes={evidenceHashes}
534585
manifestArtifacts={manifestArtifacts}
586+
completionGovernanceReport={completionGovernanceReport}
535587
planningContracts={planningContracts}
536588
planningContractsError={planningContractsError}
537589
unblockTasks={unblockTasks}
538590
unblockTasksError={unblockTasksError}
591+
contextPackArtifact={contextPackArtifact}
592+
harnessRequestArtifact={harnessRequestArtifact}
539593
onOpenLogs={() => handleFailedTerminalAction("logs")}
540594
onOpenReports={() => handleFailedTerminalAction("reports")}
541595
failedTerminalActionFeedback={failedTerminalActionFeedback}

apps/dashboard/components/run-detail/RunDetailStatusContractCard.tsx

Lines changed: 121 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,13 @@ type RunDetailStatusContractCardProps = {
3838
pendingApprovals: EventRecord[];
3939
evidenceHashes: Record<string, unknown>;
4040
manifestArtifacts: unknown[];
41+
completionGovernanceReport: Record<string, unknown>;
4142
planningContracts: Array<Record<string, unknown>>;
4243
planningContractsError: string;
4344
unblockTasks: Array<Record<string, unknown>>;
4445
unblockTasksError: string;
46+
contextPackArtifact: Record<string, unknown> | null;
47+
harnessRequestArtifact: Record<string, unknown> | null;
4548
onOpenLogs: () => void;
4649
onOpenReports: () => void;
4750
failedTerminalActionFeedback: string;
@@ -68,15 +71,19 @@ export default function RunDetailStatusContractCard({
6871
pendingApprovals,
6972
evidenceHashes,
7073
manifestArtifacts,
74+
completionGovernanceReport,
7175
planningContracts,
7276
planningContractsError,
7377
unblockTasks,
7478
unblockTasksError,
79+
contextPackArtifact,
80+
harnessRequestArtifact,
7581
onOpenLogs,
7682
onOpenReports,
7783
failedTerminalActionFeedback,
7884
}: RunDetailStatusContractCardProps) {
7985
const bindingReadModelCopy = getUiCopy(DEFAULT_UI_LOCALE).desktop.runDetail.bindingReadModel;
86+
const completionGovernanceCopy = getUiCopy(DEFAULT_UI_LOCALE).desktop.runDetail.completionGovernance;
8087
const terminal = terminalStatus.toUpperCase();
8188
const isTerminal = terminal === "FAILED" || terminal === "ERROR" || terminal === "SUCCESS" || terminal === "DONE" || terminal === "REJECTED";
8289
const isFailedTerminal = terminal === "FAILED" || terminal === "ERROR" || terminal === "REJECTED";
@@ -129,6 +136,29 @@ export default function RunDetailStatusContractCard({
129136
),
130137
);
131138
const roleBindingReadModel = run.role_binding_read_model;
139+
const runtimeCompletionGovernance = toObject(completionGovernanceReport);
140+
const hasRuntimeCompletionGovernance = Object.keys(runtimeCompletionGovernance).length > 0;
141+
const runtimeDodChecker = toObject(runtimeCompletionGovernance.dod_checker);
142+
const runtimeReplyAuditor = toObject(runtimeCompletionGovernance.reply_auditor);
143+
const runtimeContinuationDecision = toObject(runtimeCompletionGovernance.continuation_decision);
144+
const runtimeContextPack = toObject(runtimeCompletionGovernance.context_pack);
145+
const runtimeHarnessRequest = toObject(runtimeCompletionGovernance.harness_request);
146+
const contextPackRecord = toObject(contextPackArtifact);
147+
const harnessRequestRecord = toObject(harnessRequestArtifact);
148+
const runtimeDodRequiredChecks = Array.from(
149+
new Set(
150+
toArray(runtimeDodChecker.required_checks as unknown[] | null | undefined)
151+
.map((value) => toDisplayText(value))
152+
.filter((value) => value !== "-"),
153+
),
154+
);
155+
const runtimeDodUnmetChecks = Array.from(
156+
new Set(
157+
toArray(runtimeDodChecker.unmet_checks as unknown[] | null | undefined)
158+
.map((value) => toDisplayText(value))
159+
.filter((value) => value !== "-"),
160+
),
161+
);
132162
const unblockTaskOwners = Array.from(
133163
new Set(unblockTasks.map((task) => toDisplayText(task.owner)).filter((value) => value !== "-")),
134164
);
@@ -281,36 +311,100 @@ export default function RunDetailStatusContractCard({
281311
</div>
282312
</div>
283313
) : null}
284-
{planningContracts.length > 0 || planningContractsError || unblockTasks.length > 0 || unblockTasksError ? (
314+
{hasRuntimeCompletionGovernance || planningContracts.length > 0 || planningContractsError || unblockTasks.length > 0 || unblockTasksError ? (
285315
<div className="run-detail-section" data-testid="run-completion-governance-summary">
286-
<div className="mono run-detail-section-label">Completion governance</div>
287-
<div className="mono">Worker prompt contracts: {planningContracts.length}</div>
288-
{unblockTasks.length > 0 ? <div className="mono">Unblock tasks: {unblockTasks.length}</div> : null}
289-
{continuationOnIncomplete.length > 0 ? (
290-
<div className="mono">On incomplete: {continuationOnIncomplete.join(" / ")}</div>
291-
) : null}
292-
{continuationOnBlocked.length > 0 ? (
293-
<div className="mono">On blocked: {continuationOnBlocked.join(" / ")}</div>
294-
) : null}
295-
{doneChecks.length > 0 ? (
296-
<div className="mono">DoD checks: {doneChecks.join(" / ")}</div>
297-
) : null}
298-
{unblockTaskOwners.length > 0 ? (
299-
<div className="mono">Unblock owner: {unblockTaskOwners.join(" / ")}</div>
300-
) : null}
301-
{unblockTaskModes.length > 0 ? (
302-
<div className="mono">Unblock mode: {unblockTaskModes.join(" / ")}</div>
316+
<div className="mono run-detail-section-label">{completionGovernanceCopy.title}</div>
317+
{hasRuntimeCompletionGovernance ? (
318+
<div data-testid="run-completion-governance-report">
319+
<div className="mono run-detail-section-label">{completionGovernanceCopy.runtimeTitle}</div>
320+
<div className="mono">{completionGovernanceCopy.overallVerdict}: {toDisplayText(runtimeCompletionGovernance.overall_verdict)}</div>
321+
<div className="mono">{completionGovernanceCopy.reportAuthority}: {toDisplayText(runtimeCompletionGovernance.authority)}</div>
322+
<div className="mono">{completionGovernanceCopy.reportSource}: {toDisplayText(runtimeCompletionGovernance.source)}</div>
323+
<div className="mono">{completionGovernanceCopy.reportExecutionAuthority}: {toDisplayText(runtimeCompletionGovernance.execution_authority)}</div>
324+
<div className="mono">{completionGovernanceCopy.dodChecker}: {toDisplayText(runtimeDodChecker.status)}</div>
325+
{toDisplayText(runtimeDodChecker.summary) !== "-" ? (
326+
<div className="mono">{completionGovernanceCopy.dodSummary}: {toDisplayText(runtimeDodChecker.summary)}</div>
327+
) : null}
328+
{runtimeDodRequiredChecks.length > 0 ? (
329+
<div className="mono">{completionGovernanceCopy.dodRequiredChecks}: {runtimeDodRequiredChecks.join(" / ")}</div>
330+
) : null}
331+
{runtimeDodUnmetChecks.length > 0 ? (
332+
<div className="mono">{completionGovernanceCopy.dodUnmetChecks}: {runtimeDodUnmetChecks.join(" / ")}</div>
333+
) : null}
334+
<div className="mono">{completionGovernanceCopy.replyAuditor}: {toDisplayText(runtimeReplyAuditor.status)}</div>
335+
{toDisplayText(runtimeReplyAuditor.summary) !== "-" ? (
336+
<div className="mono">{completionGovernanceCopy.replySummary}: {toDisplayText(runtimeReplyAuditor.summary)}</div>
337+
) : null}
338+
<div className="mono">{completionGovernanceCopy.continuationDecision}: {toDisplayText(runtimeContinuationDecision.selected_action)}</div>
339+
{toDisplayText(runtimeContinuationDecision.summary) !== "-" ? (
340+
<div className="mono">{completionGovernanceCopy.continuationSummary}: {toDisplayText(runtimeContinuationDecision.summary)}</div>
341+
) : null}
342+
{toDisplayText(runtimeContinuationDecision.action_source) !== "-" ? (
343+
<div className="mono">{completionGovernanceCopy.actionSource}: {toDisplayText(runtimeContinuationDecision.action_source)}</div>
344+
) : null}
345+
{toDisplayText(runtimeContinuationDecision.unblock_task_id) !== "-" ? (
346+
<div className="mono">{completionGovernanceCopy.selectedUnblockTask}: {toDisplayText(runtimeContinuationDecision.unblock_task_id)}</div>
347+
) : null}
348+
<div className="mono">{completionGovernanceCopy.contextPack}: {toDisplayText(runtimeContextPack.status)}</div>
349+
{toDisplayText(runtimeContextPack.summary) !== "-" ? (
350+
<div className="mono">{completionGovernanceCopy.contextPackSummary}: {toDisplayText(runtimeContextPack.summary)}</div>
351+
) : null}
352+
{toDisplayText(contextPackRecord.pack_id) !== "-" ? (
353+
<div className="mono">{completionGovernanceCopy.contextPackId}: {toDisplayText(contextPackRecord.pack_id)}</div>
354+
) : null}
355+
{toDisplayText(contextPackRecord.trigger_reason) !== "-" ? (
356+
<div className="mono">{completionGovernanceCopy.contextPackTrigger}: {toDisplayText(contextPackRecord.trigger_reason)}</div>
357+
) : null}
358+
<div className="mono">{completionGovernanceCopy.harnessRequest}: {toDisplayText(runtimeHarnessRequest.status)}</div>
359+
{toDisplayText(runtimeHarnessRequest.summary) !== "-" ? (
360+
<div className="mono">{completionGovernanceCopy.harnessRequestSummary}: {toDisplayText(runtimeHarnessRequest.summary)}</div>
361+
) : null}
362+
{toDisplayText(harnessRequestRecord.request_id) !== "-" ? (
363+
<div className="mono">{completionGovernanceCopy.harnessRequestId}: {toDisplayText(harnessRequestRecord.request_id)}</div>
364+
) : null}
365+
{toDisplayText(harnessRequestRecord.scope) !== "-" ? (
366+
<div className="mono">{completionGovernanceCopy.harnessRequestScope}: {toDisplayText(harnessRequestRecord.scope)}</div>
367+
) : null}
368+
{harnessRequestRecord.approval_required !== undefined ? (
369+
<div className="mono">{completionGovernanceCopy.harnessRequestApproval}: {toDisplayText(harnessRequestRecord.approval_required)}</div>
370+
) : null}
371+
<div className="mono muted">{completionGovernanceCopy.runtimeNote}</div>
372+
</div>
303373
) : null}
304-
{unblockTaskTriggers.length > 0 ? (
305-
<div className="mono">Unblock trigger: {unblockTaskTriggers.join(" / ")}</div>
374+
{planningContracts.length > 0 || planningContractsError || unblockTasks.length > 0 || unblockTasksError ? (
375+
<>
376+
{hasRuntimeCompletionGovernance ? (
377+
<div className="mono run-detail-section-label">{completionGovernanceCopy.planningFallbackTitle}</div>
378+
) : null}
379+
<div className="mono">{completionGovernanceCopy.workerPromptContracts}: {planningContracts.length}</div>
380+
{unblockTasks.length > 0 ? (
381+
<div className="mono">{completionGovernanceCopy.unblockTasks}: {unblockTasks.length}</div>
382+
) : null}
383+
{continuationOnIncomplete.length > 0 ? (
384+
<div className="mono">{completionGovernanceCopy.onIncomplete}: {continuationOnIncomplete.join(" / ")}</div>
385+
) : null}
386+
{continuationOnBlocked.length > 0 ? (
387+
<div className="mono">{completionGovernanceCopy.onBlocked}: {continuationOnBlocked.join(" / ")}</div>
388+
) : null}
389+
{doneChecks.length > 0 ? (
390+
<div className="mono">{completionGovernanceCopy.doneChecks}: {doneChecks.join(" / ")}</div>
391+
) : null}
392+
{unblockTaskOwners.length > 0 ? (
393+
<div className="mono">{completionGovernanceCopy.unblockOwner}: {unblockTaskOwners.join(" / ")}</div>
394+
) : null}
395+
{unblockTaskModes.length > 0 ? (
396+
<div className="mono">{completionGovernanceCopy.unblockMode}: {unblockTaskModes.join(" / ")}</div>
397+
) : null}
398+
{unblockTaskTriggers.length > 0 ? (
399+
<div className="mono">{completionGovernanceCopy.unblockTrigger}: {unblockTaskTriggers.join(" / ")}</div>
400+
) : null}
401+
{planningContractsError || unblockTasksError ? (
402+
<div className="mono muted">{planningContractsError || unblockTasksError}</div>
403+
) : (
404+
<div className="mono muted">{completionGovernanceCopy.advisoryNote}</div>
405+
)}
406+
</>
306407
) : null}
307-
{planningContractsError || unblockTasksError ? (
308-
<div className="mono muted">{planningContractsError || unblockTasksError}</div>
309-
) : (
310-
<div className="mono muted">
311-
Derived from persisted worker prompt contracts and unblock tasks. These summaries stay advisory; task_contract still owns execution authority.
312-
</div>
313-
)}
314408
</div>
315409
) : null}
316410
<div className="mono">Manifest artifacts:</div>

0 commit comments

Comments
 (0)