Files
orchestra/internal/operations/review_test.go
T
kami 7f12c7fc37 v3 workflow: intent, phases, review, submission, enforcement, burn-in
The v3 stack, previously an uncommitted working tree, plus this session's two
units and the burn-in instrument. This commit is the burn-in build identity:
coordinator and worker must both report this revision before a task is created.

Workflow (earlier sessions, uncommitted until now): human decision events and
reduction, source cursors and reconcile-before-launch, turn-boundary
reconciliation, internal/agentctx as the single renderer, ace-fca phases with
sealed artifacts, the trajectory gate, bounded grilling, independent review,
task pr enforcement, and human review reflection.

Capability restrictions at the agent boundary: an authz.Agent surface at
GatedWrite may ask and may not act. It also fixes two bugs the unit exposed --
gated surfaces could not reach the two endpoints written for them, and
RequestHumanDecision would block an unowned task while rejecting a question
from the session that did own it.

Turn-boundary reconcile-failure escalation: a streak of consecutive failures
asks the session to hand off, fenced on the lease epoch, with reconcile_failure
as a real handoff reason. The worker was dropping the coordinator's verdict on
the floor; it now acts on it.

Burn-in: herdr.WriteLaunchContext dumps the exact agentctx.Build result to
<worktree>/.orchestra/launch.md at every launch, local and federated. BURNIN.md
is the runbook. deploy/build.sh stamps both binaries from one commit.

go build, go vet and go test ./... pass, 20 packages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 18:31:20 +04:00

219 lines
8.5 KiB
Go

package operations
import (
"errors"
"strings"
"testing"
"orchestra/internal/domain"
"orchestra/internal/registry"
"orchestra/internal/review"
"orchestra/internal/store"
)
const shaA = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const shaB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
const shaBase = "0000000000000000000000000000000000000000"
func evidence(result string) review.Evidence {
return review.Evidence{
BaseSHA: shaBase, ResultSHA: result,
Diff: "--- a/internal/attr/attr.go\n+++ b/internal/attr/attr.go\n+index lookup\n",
GateCommand: "go test ./...", GateExit: 0,
}
}
// atImplement walks a task to the implementation phase with both artifacts
// sealed, which is where review becomes possible.
func atImplement(t *testing.T, project registry.Project) (*store.Store, string) {
t.Helper()
s, id := phaseStore(t)
if _, err := AdvanceWorkPhase(s, project, id, nil); err != nil {
t.Fatal(err)
}
if _, err := AdvanceWorkPhase(s, project, id, sealed(t, research)); err != nil {
t.Fatal(err)
}
if _, err := AdvanceWorkPhase(s, project, id, sealed(t, plan)); err != nil {
t.Fatal(err)
}
return s, id
}
func finding(id string, sev review.Severity) review.Finding {
return review.Finding{
ID: id, Severity: sev, File: "internal/attr/attr.go", Line: 81,
Claim: "retry path acknowledges success before the durable append", Evidence: "line 81 returns before Append",
}
}
// Minor findings are reported and the task stays eligible. The review is bound
// to the commit it examined.
func TestMinorOnlyReviewIsAccepted(t *testing.T) {
project := registry.Project{ID: "p", QualityGate: "go test ./..."}
s, id := atImplement(t, project)
if _, err := EnterReview(s, project, id, evidence(shaA)); err != nil {
t.Fatal(err)
}
if got, _ := s.Task(id); got.WorkPhase != domain.WorkPhaseReview {
t.Fatalf("phase = %q", got.WorkPhase)
}
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaA, Findings: []review.Finding{finding("f1", review.Minor)}}); err != nil {
t.Fatal(err)
}
got, _ := s.Task(id)
if got.WorkPhase != domain.WorkPhaseReview {
t.Fatalf("a minor-only review must not send work back: %q", got.WorkPhase)
}
if !got.ReviewSatisfied(shaA) {
t.Fatalf("review not satisfied for its own commit: %+v", got.Review)
}
// The same review says nothing about a different tree.
if got.ReviewSatisfied(shaB) {
t.Fatal("a review of one commit must not satisfy another")
}
}
// A blocking finding returns the task to implementation, and the old review
// cannot satisfy the new commit.
func TestBlockingReviewReturnsWorkAndGoesStale(t *testing.T) {
project := registry.Project{ID: "p", QualityGate: "go test ./..."}
s, id := atImplement(t, project)
if _, err := EnterReview(s, project, id, evidence(shaA)); err != nil {
t.Fatal(err)
}
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaA, Findings: []review.Finding{
finding("f1", review.Important), finding("f2", review.Minor),
}}); err != nil {
t.Fatal(err)
}
got, _ := s.Task(id)
if got.WorkPhase != domain.WorkPhaseImplement {
t.Fatalf("phase = %q, want implement", got.WorkPhase)
}
if got.ReviewSatisfied(shaA) {
t.Fatal("a review with an important finding must not satisfy completion")
}
// The findings are readable for the implementation context.
r, err := TaskReview(s, got)
if err != nil || r == nil || len(r.Findings) != 2 {
t.Fatalf("findings = %+v err=%v", r, err)
}
// Fixed at a new commit: a fresh review passes, and it is bound to B.
if _, err := EnterReview(s, project, id, evidence(shaB)); err != nil {
t.Fatal(err)
}
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaB}); err != nil {
t.Fatal(err)
}
got, _ = s.Task(id)
if !got.ReviewSatisfied(shaB) {
t.Fatalf("fresh review not satisfied: %+v", got.Review)
}
if got.ReviewSatisfied(shaA) {
t.Fatal("the superseded commit must not look reviewed")
}
}
// A review sealed against a commit other than the one under review is
// rejected while the reviewing session still exists to redo it.
func TestReviewForTheWrongCommitIsRejected(t *testing.T) {
project := registry.Project{ID: "p", QualityGate: "go test ./..."}
s, id := atImplement(t, project)
if _, err := EnterReview(s, project, id, evidence(shaA)); err != nil {
t.Fatal(err)
}
if got, _ := s.Task(id); got.ReviewTargetSHA != shaA {
t.Fatalf("review target = %q", got.ReviewTargetSHA)
}
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaB}); !errors.Is(err, domain.ErrInvalid) {
t.Fatalf("want ErrInvalid, got %v", err)
}
if got, _ := s.Task(id); got.Review != nil {
t.Fatalf("a mismatched review was recorded: %+v", got.Review)
}
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaA}); err != nil {
t.Fatal(err)
}
}
func TestReviewEntryConditions(t *testing.T) {
project := registry.Project{ID: "p", QualityGate: "go test ./..."}
// Wrong phase.
s, id := phaseStore(t)
if _, err := EnterReview(s, project, id, evidence(shaA)); !errors.Is(err, ErrReviewNotEligible) {
t.Fatalf("frame phase: want ErrReviewNotEligible, got %v", err)
}
// Failing gate, unanchored commits, empty diff, and a gate that never ran.
s, id = atImplement(t, project)
bad := map[string]review.Evidence{
"failing gate": func() review.Evidence { e := evidence(shaA); e.GateExit = 1; return e }(),
"no result": func() review.Evidence { e := evidence(shaA); e.ResultSHA = "short"; return e }(),
"no base": func() review.Evidence { e := evidence(shaA); e.BaseSHA = ""; return e }(),
"no diff": func() review.Evidence { e := evidence(shaA); e.Diff = ""; return e }(),
"gate skipped": func() review.Evidence { e := evidence(shaA); e.GateCommand = ""; return e }(),
}
for name, ev := range bad {
if _, err := EnterReview(s, project, id, ev); !errors.Is(err, ErrReviewNotEligible) {
t.Fatalf("%s: want ErrReviewNotEligible, got %v", name, err)
}
}
// An unresolved question blocks entry.
lease(t, s, id)
if _, err := RequestHumanDecision(s, project, id, request("which behaviour is intended?")); err != nil {
t.Fatal(err)
}
if _, err := EnterReview(s, project, id, evidence(shaA)); !errors.Is(err, ErrReviewNotEligible) {
t.Fatalf("blocked task: want ErrReviewNotEligible, got %v", err)
}
}
// A review can only be sealed by a reviewing session, and only in a shape that
// is actually reviewable.
func TestReviewResultRejections(t *testing.T) {
project := registry.Project{ID: "p", QualityGate: "go test ./..."}
s, id := atImplement(t, project)
// Not in the review phase yet.
if _, err := RecordReview(s, project, id, review.Result{ResultSHA: shaA}); !errors.Is(err, domain.ErrInvalid) {
t.Fatalf("want ErrInvalid, got %v", err)
}
if _, err := EnterReview(s, project, id, evidence(shaA)); err != nil {
t.Fatal(err)
}
long := strings.Repeat("x", 501)
bad := map[string]review.Result{
"no sha": {Findings: []review.Finding{finding("f1", review.Minor)}},
"short sha": {ResultSHA: "abc"},
"no id": {ResultSHA: shaA, Findings: []review.Finding{{Severity: review.Minor, File: "a.go", Claim: "c", Evidence: "e"}}},
"duplicate id": {ResultSHA: shaA, Findings: []review.Finding{finding("f1", review.Minor), finding("f1", review.Blocker)}},
"bad severity": {ResultSHA: shaA, Findings: []review.Finding{{ID: "f", Severity: "invalid", File: "a.go", Claim: "c", Evidence: "e"}}},
"absolute path": {ResultSHA: shaA, Findings: []review.Finding{{ID: "f", Severity: review.Minor, File: "/etc/passwd", Claim: "c", Evidence: "e"}}},
"no evidence": {ResultSHA: shaA, Findings: []review.Finding{{ID: "f", Severity: review.Minor, File: "a.go", Claim: "c"}}},
"essay": {ResultSHA: shaA, Findings: []review.Finding{{ID: "f", Severity: review.Minor, File: "a.go", Claim: long, Evidence: "e"}}},
"multiline": {ResultSHA: shaA, Findings: []review.Finding{{ID: "f", Severity: review.Minor, File: "a.go", Claim: "one\ntwo", Evidence: "e"}}},
}
for name, result := range bad {
if _, err := RecordReview(s, project, id, result); !errors.Is(err, domain.ErrInvalid) {
t.Fatalf("%s: want ErrInvalid, got %v", name, err)
}
}
// A rejected review left no trace.
if got, _ := s.Task(id); got.Review != nil {
t.Fatalf("a rejected review was recorded: %+v", got.Review)
}
// Too many findings is also a rejection.
flood := review.Result{ResultSHA: shaA}
for i := 0; i < 41; i++ {
flood.Findings = append(flood.Findings, finding(string(rune('a'+i%26))+strings.Repeat("z", i), review.Minor))
}
if _, err := RecordReview(s, project, id, flood); !errors.Is(err, domain.ErrInvalid) {
t.Fatalf("want ErrInvalid, got %v", err)
}
}