diff --git a/client/src/hooks/use-consilium-loops.ts b/client/src/hooks/use-consilium-loops.ts index 870552b..12a9a40 100644 --- a/client/src/hooks/use-consilium-loops.ts +++ b/client/src/hooks/use-consilium-loops.ts @@ -518,9 +518,12 @@ export function useApproveMerge() { */ export function useDevelopLoop() { const qc = useQueryClient(); - return useMutation({ - mutationFn: (id) => apiRequest("POST", `${LIST_KEY}/${id}/develop`), - onSuccess: (_data, id) => { + return useMutation({ + // MR-size control: `scope: "p0"` develops only the P0s (small reviewable MR); + // omitted/"all" keeps the historical full-verdict round. + mutationFn: ({ id, scope }) => + apiRequest("POST", `${LIST_KEY}/${id}/develop`, scope ? { scope } : undefined), + onSuccess: (_data, { id }) => { qc.invalidateQueries({ queryKey: [LIST_KEY, id] }); qc.invalidateQueries({ queryKey: [LIST_KEY] }); }, diff --git a/client/src/pages/ConsiliumLoopDetail.tsx b/client/src/pages/ConsiliumLoopDetail.tsx index b14ba87..826dedd 100644 --- a/client/src/pages/ConsiliumLoopDetail.tsx +++ b/client/src/pages/ConsiliumLoopDetail.tsx @@ -1586,7 +1586,7 @@ function ReviewGateActions({ async function handleDevelop() { try { - await developLoop.mutateAsync(loopId); + await developLoop.mutateAsync({ id: loopId }); toast({ title: "Handed off to SDLC", description: "The developing round has started — follow the progress below.", @@ -2757,6 +2757,8 @@ export default function ConsiliumLoopDetail() { const approveMerge = useApproveMerge(); const developLoop = useDevelopLoop(); const [confirmOpen, setConfirmOpen] = useState(false); + // MR-size control: the develop-scope chooser (Only P0s vs all action points). + const [developScopeOpen, setDevelopScopeOpen] = useState(false); if (isLoading) { return ( @@ -2804,6 +2806,11 @@ export default function ConsiliumLoopDetail() { const latestActionPointCount = Array.isArray(latestRound?.openActionPoints) ? latestRound!.openActionPoints.length : 0; + // MR-size control: P0 slice of the latest verdict — offered as a smaller round. + const latestP0Count = Array.isArray(latestRound?.openActionPoints) + ? (latestRound!.openActionPoints as ActionPoint[]).filter((ap) => ap.priority === "P0") + .length + : 0; const canDevelop = isVerdictTerminalLoopState(loop.state) && latestActionPointCount > 0; @@ -2877,12 +2884,19 @@ export default function ConsiliumLoopDetail() { } } - async function handleDevelop() { + async function handleDevelop(scopeArg?: unknown) { + // Normalize: plain onClick callers pass a click event — only the two literal + // scopes ride to the server; anything else means "all" (historical behaviour). + const scope = scopeArg === "p0" || scopeArg === "all" ? scopeArg : undefined; + setDevelopScopeOpen(false); try { - await developLoop.mutateAsync(id); + await developLoop.mutateAsync({ id, scope }); toast({ title: "Handed off to SDLC", - description: "The developing round has started — follow the progress below.", + description: + scope === "p0" + ? `Developing only the P0 action points — merge that MR and the next round carries the rest.` + : "The developing round has started — follow the progress below.", }); } catch (err) { // 400 (NO_ACTION_POINTS / REPO_NOT_*) | 409 (WRONG_STATE / @@ -2950,7 +2964,13 @@ export default function ConsiliumLoopDetail() { {canDevelop && (