Repository navigation
Expand file tree
/
Copy pathdeadline_contract_test.go
More file actions
150 lines (141 loc) · 6.14 KB
/
Copy pathdeadline_contract_test.go
File metadata and controls
150 lines (141 loc) · 6.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package exec
import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/Agent-Field/agentfield/sdk/go/ai"
)
// TestALeafsRoomGrowsToFitTheWallItRunsUnder proves A1 and A4: the wall's
// unused room reaches the leaf, and the watchdog derived from that room lands
// on the wall rather than below it.
func TestALeafsRoomGrowsToFitTheWallItRunsUnder(t *testing.T) {
leaf := SubharnessFor(LinearSubharness)
wall := 45 * time.Minute
room := leaf.DeadlineWithin(150_000, wall)
if want := wall - watchdogPad; room != want {
t.Fatalf("a 45m wall granted %s, want %s", room, want)
}
if got := WatchdogAbove(room); got != wall {
t.Fatalf("the watchdog lands at %s, want the wall %s", got, wall)
}
}
// TestALeafsRoomIsNeverSmallerThanItsTokenGrantBought proves A2: the wall can
// widen the token-sized floor, but never take any of that floor away.
func TestALeafsRoomIsNeverSmallerThanItsTokenGrantBought(t *testing.T) {
leaf := SubharnessFor(LinearSubharness)
if got, want := leaf.DeadlineWithin(150_000, 5*time.Minute), leaf.Deadline(150_000); got != want {
t.Fatalf("a short wall narrowed the leaf to %s, want its %s token floor", got, want)
}
}
// TestNoWallLeavesALeafsRoomExactlyAsItWas proves A3 to the nanosecond over
// the floor, the first scaled grant and a larger scaled grant.
func TestNoWallLeavesALeafsRoomExactlyAsItWas(t *testing.T) {
leaf := SubharnessFor(LinearSubharness)
for _, tokens := range []int{0, 150_000, 1_000_000} {
if got, want := leaf.DeadlineWithin(tokens, 0), leaf.Deadline(tokens); got != want {
t.Errorf("%d tokens with no wall granted %s, want %s", tokens, got, want)
}
}
}
// TestTheDeadlineReserveIsNotSpendableByTheWork proves A5 at the late-order
// seam: the first call consumes the leaf's whole lease, and four landing turns
// still run on the reserve ordered after that lease has expired.
func TestTheDeadlineReserveIsNotSpendableByTheWork(t *testing.T) {
space := workspace(t)
turns := make([][]ai.ToolCall, landingTurns+1)
for index := 1; index <= landingTurns; index++ {
turns[index] = []ai.ToolCall{call(
fmt.Sprintf("landing-%d", index), "write",
fmt.Sprintf(`{"path":"landing-%d.txt","text":"landed"}`, index),
)}
}
client := &scriptedCompleter{
turns: turns,
delays: []time.Duration{2 * time.Second},
}
linear := NewLinear(client, space, nil, 10, 1_000_000, time.Second)
outcome, err := linear.Run(context.Background(), Task{NodeID: 21, Brief: "land the work"})
if err != nil {
t.Fatal(err)
}
if outcome.Stop != StopDeadline || outcome.Exhausted != StopDeadline {
t.Fatalf("landing ended with stop %q and exhaustion %q, want deadline", outcome.Stop, outcome.Exhausted)
}
if len(client.seen) != landingTurns+1 {
t.Fatalf("model calls = %d, want the spent work call and %d landing calls", len(client.seen), landingTurns)
}
for index := 1; index <= landingTurns; index++ {
if _, err := os.Stat(filepath.Join(space.Root(), fmt.Sprintf("landing-%d.txt", index))); err != nil {
t.Fatalf("landing turn %d did not execute: %v", index, err)
}
}
}
// TestALeafEndedByItsClockCarriesItsNumbers proves A6 on the arm where the
// lease expires inside one call and the landing's own clock expires inside the
// next. That arm used to name no meter at all.
func TestALeafEndedByItsClockCarriesItsNumbers(t *testing.T) {
client := &scriptedCompleter{delays: []time.Duration{2 * time.Second, 2 * time.Second}}
linear := NewLinear(client, workspace(t), nil, 10, 1_000_000, time.Second)
outcome, err := linear.Run(context.Background(), Task{NodeID: 22, Brief: "work until the clock"})
if err == nil {
t.Fatal("a landing cut by its own clock returned no error")
}
if outcome.Stop != StopDeadline || outcome.Exhausted != StopDeadline {
t.Fatalf("clock ending = stop %q, exhausted %q", outcome.Stop, outcome.Exhausted)
}
if outcome.Meter.Name != MeterDeadline || outcome.Meter.Unit != "seconds" {
t.Fatalf("clock meter = %+v", outcome.Meter)
}
if outcome.Meter.Allowed != 1 || outcome.Meter.Reached < 1 {
t.Fatalf("clock figures = allowed %d, reached %d", outcome.Meter.Allowed, outcome.Meter.Reached)
}
}
// TestALeafNeverOutlivesTheWatchdogAboveItsLease proves the amended A7. A
// landing may cross the leaf's lease now, but it remains under both the node
// watchdog above that lease and the errand wall carried by the granted context.
func TestALeafNeverOutlivesTheWatchdogAboveItsLease(t *testing.T) {
const lease = time.Second
const wall = 1500 * time.Millisecond
granted, cancel := context.WithTimeout(context.Background(), wall)
defer cancel()
client := &scriptedCompleter{delays: []time.Duration{10 * time.Second, 10 * time.Second}}
linear := NewLinear(client, workspace(t), nil, 10, 1_000_000, lease)
started := time.Now()
outcome, err := linear.Run(granted, Task{NodeID: 23, Brief: "respect every wall"})
elapsed := time.Since(started)
if err == nil || outcome.Stop != StopDeadline {
t.Fatalf("wall ending = outcome %+v, err %v", outcome, err)
}
if elapsed > wall+2*time.Second {
t.Fatalf("the leaf returned after %s, past its %s errand wall", elapsed, wall)
}
if elapsed > WatchdogAbove(lease) {
t.Fatalf("the leaf returned after %s, past the %s watchdog above its lease", elapsed, WatchdogAbove(lease))
}
}
// A later parent wall must not widen the protected landing reserve. A landing
// gets the smaller of its own allowance and the caller's remaining time.
func TestTheLandingClockNeverWidensItsReserveToTheParentWall(t *testing.T) {
parent, cancel := context.WithTimeout(context.Background(), time.Hour)
defer cancel()
const reserve = time.Second
started := time.Now()
landing, stop := landingClock(parent, reserve)
defer stop()
deadline, ok := landing.Deadline()
if !ok || deadline.After(started.Add(reserve+100*time.Millisecond)) {
t.Fatalf("landing deadline %s exceeds its %s reserve", deadline, reserve)
}
short, cancelShort := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancelShort()
shortDeadline, _ := short.Deadline()
landingShort, stopShort := landingClock(short, reserve)
defer stopShort()
got, _ := landingShort.Deadline()
if !got.Equal(shortDeadline) {
t.Fatalf("landing deadline %s differs from earlier caller deadline %s", got, shortDeadline)
}
}