Commit graph

17 commits

Author SHA1 Message Date
f01fab8c38
feat: branch-per-story + worktree-defer + verify EMPTY edge-cases (#12)
Implementeert vier open stories uit PBI 'Veilige Claude-agent-workflow':

**Branch per story (cmon11tbe001zbortx35n155c)**
- `resolveBranchForJob`: zoek sibling-job in dezelfde story; reuse z'n
  branch (1 PR per story i.p.v. per task).
- Branch-naam: `feat/story-<8-char>` voor nieuwe stories.
- `createWorktreeForJob` kent nu `reuseBranch=true`: detecteert stale
  sibling-worktree die de branch nog vasthoudt en verwijdert die eerst.
- `attachWorktreeToJob` neemt `storyId` mee.

**PR-hergebruik (zelfde story)**
- `maybeCreateAutoPr`: als sibling-job in story al een pr_url heeft,
  hergebruik die zonder nieuwe `gh pr create`-call. PR-titel komt nu
  van de story (was task) zodat het als 'story-PR' leest.

**Worktree-cleanup uitgesteld bij actieve siblings**
- `cleanupWorktreeForTerminalStatus`: count active sibling-jobs in
  dezelfde story; defer als > 0 (volgende sub-task gebruikt branch).

**Worktree-cleanup logging (cmon0jc14001ubortjxf2a2ck)**
- Warning bij ontbrekende repoRoot, met productId + jobId in message.
- Warning bij removeWorktreeForJob-failure met keepBranch in message.

**resolveRepoRoot fallback (cmon0jc14001ubortjxf2a2ck)**
- Convention-based fallback: `~/Projects/<repo-name>` afgeleid uit
  `product.repo_url` als noch env-var noch config-bestand iets oplevert.
- `repoNameFromUrl` helper geëxporteerd voor herbruikbaarheid.

**Verify EMPTY-detection edge-case (cmon0kdq6001xbort2kgbcqmr)**
- `classifyDiffAgainstPlan`: na file-paths-check ook content-lines
  checken; als alle +/- regels alleen headers of whitespace zijn,
  return EMPTY met duidelijke reasoning.

Tests: 120/120 groen (3 nieuwe), tsc clean, build clean.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:04:54 +02:00
f87b20744b
feat: worker presence layer + batch-loop docs (#7)
* feat: add next_action field to update_job_status response

* docs: add Batch-loop section to README

* feat: presence layer — registerWorker, startHeartbeat, registerShutdownHandlers

* feat: bootstrap worker presence at server startup, remove inline presence from wait-for-job

* docs: document worker presence layer in CLAUDE.md

* docs: refine Batch-loop intro — add 'Hier is de flow:' per implementation plan
2026-05-01 16:39:26 +02:00
5cd792a8fe feat: DONE gate in update_job_status — reject if verify_result null or EMPTY without verify_only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 13:58:28 +02:00
1015264558 feat(M13): auto-PR via gh CLI after successful push (auto_pr=true)
New src/git/pr.ts helper wraps 'gh pr create'; returns { url } or { error }.
maybeCreateAutoPr() in update-job-status checks product.auto_pr, builds title
from story.code + task.title, writes pr_url to DB. Non-fatal: gh failure logs
a warning and leaves DONE status intact. Also syncs schema: auto_pr on Product,
pr_url on ClaudeJob.
2026-05-01 13:30:38 +02:00
dadcbc48d6 feat(M13): cleanup_my_worktrees tool — scan + remove stale worktrees for terminal-status jobs 2026-05-01 13:22:47 +02:00
095ebc40f8 feat(M13): retry-tracking — stale CLAIMED jobs → QUEUED (retry_count++) or FAILED (≥2 retries)
resetStaleClaimedJobs now uses $queryRaw with RETURNING so it can send pg_notify
claude_job_status events per transitioned job. Jobs under the retry limit are
re-queued with retry_count incremented; jobs at ≥2 retries are marked FAILED.
2026-05-01 13:18:59 +02:00
e63ea7026b feat: verify_task_against_plan calls classifyDiffAgainstPlan + saves verify_result to DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 12:59:17 +02:00
1e264ed521 feat: classifyDiffAgainstPlan — pure diff vs plan classifier (VerifyResult)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 12:55:47 +02:00
8ebf4ff895 feat: integrate push into update_job_status DONE transition
On status=done, calls pushBranchForJob before DB write:
- pushed=true → DONE + pushed_at + branch set + worktree cleanup (keepBranch=true)
- no-changes → DONE without pushed_at + worktree cleanup
- push failure → FAILED with error message + worktree preserved for manual inspection

Also adds pushed_at to vendored prisma schema + regenerates client.
6 unit tests for prepareDoneUpdate covering all push outcomes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 12:00:30 +02:00
fbfaf905c8 feat: add pushBranchForJob helper (src/git/push.ts)
Runs git push -u origin <branch> in the worktree. Detects no-changes
(HEAD = origin/main) before pushing. Classifies push failures into
no-credentials, conflict, or unknown via stderr pattern matching.
5 unit tests covering all paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:57:14 +02:00
ce4afa1928 feat: cleanup worktree in update_job_status on terminal transitions
On DONE/FAILED, resolves repoRoot and calls removeWorktreeForJob (best-effort).
keepBranch=true when status=done and agent reported a branch (push assumed);
false otherwise. Cleanup failures are logged as warnings — DB status is preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:52:16 +02:00
6ee55e79b6 feat: integrate createWorktreeForJob into wait_for_job tool
After claiming a job, resolves repoRoot (env SCRUM4ME_REPO_ROOT_<productId>
or ~/.scrum4me-agent-config.json), creates a git worktree, and returns
worktree_path + branch_name in the response. Rolls back claim to QUEUED
on failure. Tool description updated to instruct agent to work in worktree.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:50:51 +02:00
b20e297851 feat: add removeWorktreeForJob helper
Removes worktree dir via `git worktree remove --force` and deletes
the local branch by default; keepBranch=true preserves the branch.
Returns { removed: false } when the worktree path doesn't exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:46:31 +02:00
e7bb3c82ba feat: createWorktreeForJob helper — isolate agent per job in git worktree
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:34:19 +02:00
d9f3a7ea40 test+docs: verify-plan tests and README for verify_task_against_plan
23 unit tests covering parseAcceptanceCriteria, extractKeywords,
checkACStatus, computeDriftScore, lineDiff, and 4 end-to-end scenarios
(plan unchanged, edited, AC missed, no baseline). README documents the
tool with example output and heuristic limitations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:36:43 +02:00
54ace839f8 test: snapshot capture + stale reset in wait_for_job
Verifies: claim writes plan_snapshot from task.implementation_plan;
NULL plan becomes '' snapshot; no job returns null; stale reset SQL
includes plan_snapshot = NULL; product_id scoping passes correct param.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 19:27:56 +02:00
3564070bbe test: add unit tests for tasks-status-update helper and get-claude-context filter
tasks-status-update.test.ts: 7 tests covering promote, idempotent
promote, partial-siblings no-promote, demote, no-demote-when-not-done,
task-always-updated, and custom tx client pass-through.

get-claude-context-filter.test.ts: 3 tests verifying the OR tasks
filter is passed, sprint_id/status filter is present, and no story
query fires when there is no active sprint.
2026-04-30 18:22:55 +02:00