Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3f89598
fix closeout waiver test expectation for future expiry
php-workx Apr 21, 2026
ddb737f
Suppress run_id output when ticket final persistence fails
php-workx Apr 21, 2026
ea481fd
chore(tools): keep tools module tidy
php-workx Apr 21, 2026
af5ceea
fix(runtime): harden result normalization
php-workx Apr 21, 2026
7ae32bd
fix(claude): cancel process group on scan errors
php-workx Apr 21, 2026
0db3755
fix(tkmd): harden claim and epic child handling
php-workx Apr 21, 2026
ad76886
fix(verify): constrain default command environment
php-workx Apr 21, 2026
3cdbdb5
fix(engine): repair blocked resume state handling
php-workx Apr 21, 2026
5f42d30
fix(cli): harden run persistence and test IO
php-workx Apr 21, 2026
68f87c8
fix: repair advisory derived check failures
php-workx Apr 22, 2026
c4b237e
docs: mark repair oriented gates implemented
php-workx Apr 22, 2026
5be21c7
fix(runtime): normalize parsed agent results
php-workx Apr 22, 2026
f08cb7b
fix: tighten review feedback edge cases
php-workx Apr 22, 2026
65dc3ef
fix(cli): keep blocked epic runs resumable
php-workx Apr 22, 2026
1786baf
fix(engine): renew live claims and avoid unsafe retries
php-workx Apr 22, 2026
5a896b2
docs: plan ticket state machine outcomes
php-workx Apr 22, 2026
288ccf7
feat(engine): persist ticket run outcomes
php-workx Apr 22, 2026
ff24729
fix: address epic closeout review findings
php-workx Apr 22, 2026
c1835c7
fix: harden claim validation review fixes
php-workx Apr 22, 2026
35bebae
fix: guard claim paths against ancestor symlinks
php-workx Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 38 additions & 43 deletions cmd/verk/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
Expand Down Expand Up @@ -165,57 +166,51 @@ func runCLIFromDir(t *testing.T, dir string, args ...string) (string, string, in
return string(stdoutRes.data), string(stderrRes.data), code
}

// TestRunCLIFromDir_LargeOutput_NoDeadlock verifies that the goroutine-based
// pipe draining in runCLIFromDir does not deadlock when more than 64KB is
// written to stdout or stderr before ExecuteArgs returns.
// TestRunCLIFromDir_LargeOutput_NoDeadlock verifies that pipe draining in
// runCLIFromDir captures full stdout for large outputs that exceed default pipe
// capacity.
func TestRunCLIFromDir_LargeOutput_NoDeadlock(t *testing.T) {
const size = 128 * 1024 // 128KB — well above the old 64KB fixed buffer

// Directly exercise the goroutine+io.ReadAll mechanism used by runCLIFromDir.
stdoutR, stdoutW, err := os.Pipe()
if err != nil {
t.Fatalf("os.Pipe (stdout): %v", err)
}
stderrR, stderrW, err := os.Pipe()
if err != nil {
t.Fatalf("os.Pipe (stderr): %v", err)
}

type result struct{ data []byte }
stdoutCh := make(chan result, 1)
stderrCh := make(chan result, 1)
repoRoot := t.TempDir()
writeCLIRepo(t, repoRoot)

go func() {
data, _ := io.ReadAll(stdoutR)
stdoutCh <- result{data}
}()
go func() {
data, _ := io.ReadAll(stderrR)
stderrCh <- result{data}
}()
const (
largeRunID = "run-large-output"
largeCount = 1200
idSuffixLen = 72
)

// Write >64KB to both streams before closing.
large := make([]byte, size)
if _, err := stdoutW.Write(large); err != nil {
t.Fatalf("stdoutW.Write: %v", err)
}
if _, err := stderrW.Write(large); err != nil {
t.Fatalf("stderrW.Write: %v", err)
ticketIDs := make([]string, 0, largeCount)
for i := 0; i < largeCount; i++ {
ticketIDs = append(ticketIDs, fmt.Sprintf("ticket-%04d-%s", i, strings.Repeat("x", idSuffixLen)))
}

_ = stdoutW.Close()
_ = stderrW.Close()
writeJSONFixture(t, filepath.Join(repoRoot, ".verk", "runs", largeRunID, "run.json"), state.RunArtifact{
ArtifactMeta: state.ArtifactMeta{SchemaVersion: 1, RunID: largeRunID},
Mode: "ticket",
RootTicketID: ticketIDs[0],
Status: state.EpicRunStatusRunning,
CurrentPhase: state.TicketPhaseImplement,
TicketIDs: ticketIDs,
})

stdoutRes := <-stdoutCh
_ = stdoutR.Close()
stderrRes := <-stderrCh
_ = stderrR.Close()
for _, ticketID := range ticketIDs {
writeJSONFixture(t, filepath.Join(repoRoot, ".verk", "runs", largeRunID, "tickets", ticketID, "ticket-run.json"), map[string]any{
"schema_version": 1,
"run_id": largeRunID,
"ticket_id": ticketID,
"current_phase": "implement",
"implementation_attempts": 1,
"verification_attempts": 0,
"review_attempts": 0,
})
}

if got := len(stdoutRes.data); got != size {
t.Errorf("stdout: expected %d bytes, got %d", size, got)
stdout, stderr, code := runCLIFromDir(t, repoRoot, "status", largeRunID)
if code != 0 {
t.Fatalf("status %s failed: code=%d stderr=%s", largeRunID, code, stderr)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if got := len(stderrRes.data); got != size {
t.Errorf("stderr: expected %d bytes, got %d", size, got)
if got, want := len(stdout), 64*1024; got <= want {
t.Fatalf("expected status output > %d bytes, got %d", want, got)
}
}

Expand Down
17 changes: 11 additions & 6 deletions docs/plans/2026-04-19-verk-run-repair-oriented-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- Date: 2026-04-19
- Owner: Ronny Unger
- Epic: `ver-vyag`
- Status: planned
- Status: implemented

## Summary

Expand Down Expand Up @@ -175,15 +175,20 @@ Suggested derivations:
- YAML files: YAML parse or lint when a local tool exists.
- Shell files: shellcheck when available.

Derived checks should be focused and cheap. Missing optional tooling should be
recorded as skipped rather than failing the run by default.
Derived checks should be focused and cheap. Ticket-scoped derived checks are
advisory by default: a failing advisory check may trigger best-effort repair
while implementation attempts remain, but it does not block ticket closure on
its own. Missing optional tooling should be recorded as skipped rather than
failing the run by default.

### 4. Ticket Closeout

Ticket closeout should run declared and derived checks before closing. Failing
checks should trigger repair while budget remains. Closeout should block only
when repair fails, repair is unsafe without user input, or the system cannot map
the problem to a safe action.
required checks should trigger repair while budget remains. Failing advisory
checks should trigger best-effort repair while implementation attempts remain,
then remain visible in validation coverage without blocking closure. Closeout
should block only when required repair fails, repair is unsafe without user
input, or the system cannot map the problem to a safe action.

The closeout artifact should include validation coverage so the operator and
resume logic can understand the state later.
Expand Down
Loading
Loading