feat(PBI-67/ST-1299/T-788): wait_for_job retourneert config

Roept resolveJobConfig aan na het claimen van een job en voegt het
resultaat toe als `config: JobConfig` aan de response payload. Werkt
voor alle 3 return-paden (IDEA_*, SPRINT_IMPLEMENTATION, default
TASK_IMPLEMENTATION).

Schema-velden lokaal toegevoegd ter ondersteuning van het Prisma-include
(preferred_*, requires_opus, requested_*, actual_thinking_tokens). De
sync-schema.sh-flow refresht ze later vanuit het scrum4me-submodule
zodra PBI-67/ST-1297 in main is.

Pure additief — oude clients negeren `config` en blijven werken op
Claude Code defaults uit ~/.claude/settings.json.

301 tests slagen onveranderd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Madhura68 2026-05-08 11:11:29 +02:00
parent 070c039740
commit e2963d58fb
2 changed files with 40 additions and 1 deletions

View file

@ -200,6 +200,9 @@ model Product {
definition_of_done String definition_of_done String
auto_pr Boolean @default(false) auto_pr Boolean @default(false)
pr_strategy PrStrategy @default(SPRINT) pr_strategy PrStrategy @default(SPRINT)
preferred_model String?
thinking_budget_default Int?
preferred_permission_mode String?
archived Boolean @default(false) archived Boolean @default(false)
created_at DateTime @default(now()) created_at DateTime @default(now())
updated_at DateTime @updatedAt updated_at DateTime @updatedAt
@ -353,6 +356,7 @@ model Task {
status TaskStatus @default(TO_DO) status TaskStatus @default(TO_DO)
verify_only Boolean @default(false) verify_only Boolean @default(false)
verify_required VerifyRequired @default(ALIGNED_OR_PARTIAL) verify_required VerifyRequired @default(ALIGNED_OR_PARTIAL)
requires_opus Boolean @default(false)
// Override product.repo_url for branch/worktree/push purposes. Set when // Override product.repo_url for branch/worktree/push purposes. Set when
// a task targets a different repo than its parent product (e.g. an // a task targets a different repo than its parent product (e.g. an
// MCP-server task tracked under the main product's PBI). Falls back to // MCP-server task tracked under the main product's PBI). Falls back to
@ -398,6 +402,10 @@ model ClaudeJob {
output_tokens Int? output_tokens Int?
cache_read_tokens Int? cache_read_tokens Int?
cache_write_tokens Int? cache_write_tokens Int?
requested_model String?
requested_thinking_budget Int?
requested_permission_mode String?
actual_thinking_tokens Int?
plan_snapshot String? plan_snapshot String?
base_sha String? base_sha String?
head_sha String? head_sha String?

View file

@ -18,6 +18,7 @@ import { createWorktreeForJob } from '../git/worktree.js'
import { getWorktreeRoot } from '../git/worktree-paths.js' import { getWorktreeRoot } from '../git/worktree-paths.js'
import { setupProductWorktrees, releaseLocksOnTerminal } from '../git/job-locks.js' import { setupProductWorktrees, releaseLocksOnTerminal } from '../git/job-locks.js'
import { pushBranchForJob } from '../git/push.js' import { pushBranchForJob } from '../git/push.js'
import { resolveJobConfig } from '../lib/job-config.js'
/** Parse `https://github.com/<owner>/<name>(.git)?` → `<name>`. */ /** Parse `https://github.com/<owner>/<name>(.git)?` → `<name>`. */
export function repoNameFromUrl(repoUrl: string | null | undefined): string | null { export function repoNameFromUrl(repoUrl: string | null | undefined): string | null {
@ -467,11 +468,38 @@ async function getFullJobContext(jobId: string) {
}, },
}, },
}, },
product: { select: { id: true, name: true, repo_url: true, definition_of_done: true } }, product: {
select: {
id: true,
name: true,
repo_url: true,
definition_of_done: true,
preferred_model: true,
thinking_budget_default: true,
preferred_permission_mode: true,
},
},
}, },
}) })
if (!job) return null if (!job) return null
// PBI-67: model + mode-selectie. Resolved op claim-moment; override-cascade
// task.requires_opus → job.requested_* → product.preferred_* → kind-default.
const config = resolveJobConfig(
{
kind: job.kind,
requested_model: job.requested_model,
requested_thinking_budget: job.requested_thinking_budget,
requested_permission_mode: job.requested_permission_mode,
},
{
preferred_model: job.product.preferred_model,
thinking_budget_default: job.product.thinking_budget_default,
preferred_permission_mode: job.product.preferred_permission_mode,
},
job.task ? { requires_opus: job.task.requires_opus } : undefined,
)
// M12: branch on kind. Idea-jobs hebben geen task/story/pbi/sprint; ze // M12: branch on kind. Idea-jobs hebben geen task/story/pbi/sprint; ze
// hebben in plaats daarvan idea + embedded prompt_text. // hebben in plaats daarvan idea + embedded prompt_text.
if (job.kind === 'IDEA_GRILL' || job.kind === 'IDEA_MAKE_PLAN') { if (job.kind === 'IDEA_GRILL' || job.kind === 'IDEA_MAKE_PLAN') {
@ -515,6 +543,7 @@ async function getFullJobContext(jobId: string) {
job_id: job.id, job_id: job.id,
kind: job.kind, kind: job.kind,
status: 'claimed', status: 'claimed',
config,
idea: { idea: {
id: idea.id, id: idea.id,
code: idea.code, code: idea.code,
@ -659,6 +688,7 @@ async function getFullJobContext(jobId: string) {
job_id: job.id, job_id: job.id,
kind: job.kind, kind: job.kind,
status: 'claimed', status: 'claimed',
config,
sprint: { sprint: {
id: sprintRun.sprint.id, id: sprintRun.sprint.id,
sprint_goal: sprintRun.sprint.sprint_goal, sprint_goal: sprintRun.sprint.sprint_goal,
@ -724,6 +754,7 @@ async function getFullJobContext(jobId: string) {
job_id: job.id, job_id: job.id,
kind: job.kind, kind: job.kind,
status: 'claimed', status: 'claimed',
config,
task: { task: {
id: task.id, id: task.id,
title: task.title, title: task.title,