feat: Wire full request-changes flow for phase review

- Add PhaseChangesRequestedEvent to event bus
- Add requestChangesOnPhase() to ExecutionOrchestrator: reads unresolved
  comments, creates revision task (category='review'), resets phase to
  in_progress, queues task for dispatch
- Expand merge-skip and branch routing to include 'review' category so
  revision tasks work directly on the phase branch
- Add requestPhaseChanges tRPC procedure (reads comments from DB)
- Wire frontend: mutation replaces stub handler, window.prompt for
  optional summary, loading state on button
This commit is contained in:
Lukas May
2026-03-05 11:35:34 +01:00
parent 8ae3916c90
commit 7e0749ef17
7 changed files with 153 additions and 11 deletions

View File

@@ -46,6 +46,7 @@ interface ReviewHeaderProps {
unresolvedCount: number;
onApprove: () => void;
onRequestChanges: () => void;
isRequestingChanges?: boolean;
preview: PreviewState | null;
viewedCount?: number;
totalCount?: number;
@@ -63,6 +64,7 @@ export function ReviewHeader({
unresolvedCount,
onApprove,
onRequestChanges,
isRequestingChanges,
preview,
viewedCount,
totalCount,
@@ -186,9 +188,14 @@ export function ReviewHeader({
variant="outline"
size="sm"
onClick={onRequestChanges}
disabled={isRequestingChanges}
className="h-8 text-xs px-3 border-status-error-border/50 text-status-error-fg hover:bg-status-error-bg/50 hover:border-status-error-border"
>
<X className="h-3 w-3" />
{isRequestingChanges ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : (
<X className="h-3 w-3" />
)}
Request Changes
</Button>
<div className="relative" ref={confirmRef}>

View File

@@ -225,12 +225,21 @@ export function ReviewTab({ initiativeId }: ReviewTabProps) {
approveMutation.mutate({ phaseId: activePhaseId });
}, [activePhaseId, approveMutation]);
const requestChangesMutation = trpc.requestPhaseChanges.useMutation({
onSuccess: () => {
setStatus("changes_requested");
toast.success("Changes requested — revision task dispatched");
phasesQuery.refetch();
},
onError: (err) => toast.error(err.message),
});
const handleRequestChanges = useCallback(() => {
setStatus("changes_requested");
toast("Changes requested", {
description: "The agent will be notified about the requested changes.",
});
}, []);
if (!activePhaseId) return;
const summary = window.prompt("Optional: describe what needs to change (leave blank for comments only)");
if (summary === null) return; // cancelled
requestChangesMutation.mutate({ phaseId: activePhaseId, summary: summary || undefined });
}, [activePhaseId, requestChangesMutation]);
const handleFileClick = useCallback((filePath: string) => {
const el = fileRefs.current.get(filePath);
@@ -282,6 +291,7 @@ export function ReviewTab({ initiativeId }: ReviewTabProps) {
unresolvedCount={unresolvedCount}
onApprove={handleApprove}
onRequestChanges={handleRequestChanges}
isRequestingChanges={requestChangesMutation.isPending}
preview={previewState}
viewedCount={viewedFiles.size}
totalCount={allFiles.length}