Verify-gate uitbreiden: DIVERGENT/PARTIAL vereist agent-acknowledgement (#53)

* feat(schema): add Task.verify_required enum (ALIGNED / ALIGNED_OR_PARTIAL / ANY)

Adds VerifyRequired enum and verify_required field (default ALIGNED_OR_PARTIAL)
to the Task model. Also declares the claude_jobs_status_finished_at_idx index
in the schema to match the live DB. Applied via db execute + migrate resolve.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add verify_required select to TaskDetailDialog

SoloTask interface, solo page mapping, solo store, PATCH route handler
and TaskDetailDialog all updated to expose the three-level verify gate
(ALIGNED / ALIGNED_OR_PARTIAL / ANY) as a native select. Disabled with
DemoTooltip in demo mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-02 17:45:19 +02:00 committed by GitHub
parent d93c91c386
commit ced0a8a4c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 87 additions and 8 deletions

View file

@ -83,6 +83,7 @@ export default async function SoloProductPage({ params }: Props) {
sort_order: t.sort_order,
status: t.status as SoloTask['status'],
verify_only: t.verify_only,
verify_required: t.verify_required as SoloTask['verify_required'],
story_id: t.story.id,
story_code: t.story.code,
story_title: t.story.title,

View file

@ -10,18 +10,22 @@ import { updateTaskStatusWithStoryPromotion } from '@/lib/tasks-status-update'
// drive tasks into a state the shared UI can't display.
const PATCHABLE_TASK_STATUS = TASK_STATUS_API_VALUES.filter((s) => s !== 'review')
const VERIFY_REQUIRED_VALUES = ['ALIGNED', 'ALIGNED_OR_PARTIAL', 'ANY'] as const
const patchSchema = z
.object({
status: z.enum(PATCHABLE_TASK_STATUS as [string, ...string[]]).optional(),
implementation_plan: z.string().optional(),
verify_only: z.boolean().optional(),
verify_required: z.enum(VERIFY_REQUIRED_VALUES).optional(),
})
.refine(
(data) =>
data.status !== undefined ||
data.implementation_plan !== undefined ||
data.verify_only !== undefined,
{ message: 'Geef minimaal status, implementation_plan of verify_only mee' },
data.verify_only !== undefined ||
data.verify_required !== undefined,
{ message: 'Geef minimaal status, implementation_plan, verify_only of verify_required mee' },
)
export async function PATCH(
@ -88,19 +92,21 @@ export async function PATCH(
}
}
// Combine simple field writes (plan, verify_only) into one update call
const simpleData: { implementation_plan?: string; verify_only?: boolean } = {}
// Combine simple field writes (plan, verify_only, verify_required) into one update call
const simpleData: { implementation_plan?: string; verify_only?: boolean; verify_required?: typeof VERIFY_REQUIRED_VALUES[number] } = {}
if (parsed.data.implementation_plan !== undefined)
simpleData.implementation_plan = parsed.data.implementation_plan
if (parsed.data.verify_only !== undefined)
simpleData.verify_only = parsed.data.verify_only
if (parsed.data.verify_required !== undefined)
simpleData.verify_required = parsed.data.verify_required
const updated = await prisma.$transaction(async (tx) => {
const simpleUpdate = Object.keys(simpleData).length > 0
? await tx.task.update({
where: { id },
data: simpleData,
select: { id: true, status: true, implementation_plan: true, verify_only: true },
select: { id: true, status: true, implementation_plan: true, verify_only: true, verify_required: true },
})
: null
@ -111,6 +117,7 @@ export async function PATCH(
status: result.task.status,
implementation_plan: result.task.implementation_plan,
verify_only: simpleUpdate?.verify_only,
verify_required: simpleUpdate?.verify_required,
}
}
@ -125,5 +132,6 @@ export async function PATCH(
status: taskStatusToApi(updated.status),
implementation_plan: updated.implementation_plan,
...(updated.verify_only !== undefined && { verify_only: updated.verify_only }),
...(updated.verify_required !== undefined && { verify_required: updated.verify_required }),
})
}