@onlooker-community/ecosystem 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +13 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.release-please-manifest.json +3 -2
- package/CHANGELOG.md +7 -0
- package/package.json +3 -3
- package/plugins/governor/.claude-plugin/plugin.json +14 -0
- package/plugins/governor/CHANGELOG.md +15 -0
- package/plugins/governor/config.json +19 -0
- package/plugins/governor/hooks/hooks.json +48 -0
- package/plugins/governor/scripts/hooks/governor-post-tool-use.sh +147 -0
- package/plugins/governor/scripts/hooks/governor-pre-tool-use.sh +199 -0
- package/plugins/governor/scripts/hooks/governor-session-start.sh +109 -0
- package/plugins/governor/scripts/hooks/governor-stop.sh +108 -0
- package/plugins/governor/scripts/lib/governor-config.sh +79 -0
- package/plugins/governor/scripts/lib/governor-estimate.sh +116 -0
- package/plugins/governor/scripts/lib/governor-events.sh +81 -0
- package/plugins/governor/scripts/lib/governor-ledger.sh +172 -0
- package/release-please-config.json +16 -0
- package/test/bats/governor-config.bats +106 -0
- package/test/bats/governor-estimate.bats +86 -0
- package/test/bats/governor-events.bats +238 -0
- package/test/bats/governor-ledger.bats +220 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
setup() {
|
|
4
|
+
source "${BATS_TEST_DIRNAME}/../helpers/setup.bash"
|
|
5
|
+
setup_test_env
|
|
6
|
+
|
|
7
|
+
PLUGIN_ROOT="${REPO_ROOT}/plugins/governor"
|
|
8
|
+
export CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT"
|
|
9
|
+
|
|
10
|
+
# shellcheck disable=SC1091
|
|
11
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-config.sh"
|
|
12
|
+
# shellcheck disable=SC1091
|
|
13
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-estimate.sh"
|
|
14
|
+
|
|
15
|
+
governor_config_load ""
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@test "governor_estimate_method returns tier_table" {
|
|
19
|
+
local m
|
|
20
|
+
m=$(governor_estimate_method)
|
|
21
|
+
[ "$m" = "tier_table" ]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@test "empty input returns a nonzero estimate" {
|
|
25
|
+
local t
|
|
26
|
+
t=$(governor_estimate_tokens "")
|
|
27
|
+
[ "$t" -gt 0 ]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@test "prose input produces a positive estimate" {
|
|
31
|
+
local input="This is a plain English sentence with no special characters at all."
|
|
32
|
+
local t
|
|
33
|
+
t=$(governor_estimate_tokens "$input" 1.0)
|
|
34
|
+
[ "$t" -gt 0 ]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@test "JSON input produces higher token density estimate than prose" {
|
|
38
|
+
local prose="This is a longer plain English paragraph used as baseline comparison text."
|
|
39
|
+
local json='{"key":"value","nested":{"array":[1,2,3,4,5],"flag":true},"extra":"padding"}'
|
|
40
|
+
|
|
41
|
+
local chars_prose=${#prose}
|
|
42
|
+
local chars_json=${#json}
|
|
43
|
+
local toks_prose
|
|
44
|
+
local toks_json
|
|
45
|
+
toks_prose=$(governor_estimate_tokens "$prose" 1.0)
|
|
46
|
+
toks_json=$(governor_estimate_tokens "$json" 1.0)
|
|
47
|
+
|
|
48
|
+
# JSON uses 3 chars/tok vs 4 for prose, so per char JSON should yield more tokens.
|
|
49
|
+
local ratio_prose=$(( toks_prose * 100 / chars_prose ))
|
|
50
|
+
local ratio_json=$(( toks_json * 100 / chars_json ))
|
|
51
|
+
[ "$ratio_json" -ge "$ratio_prose" ]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@test "safety margin multiplies the base estimate" {
|
|
55
|
+
local input="hello world this is a test sentence"
|
|
56
|
+
local base
|
|
57
|
+
local with_margin
|
|
58
|
+
base=$(governor_estimate_tokens "$input" 1.0)
|
|
59
|
+
with_margin=$(governor_estimate_tokens "$input" 1.3)
|
|
60
|
+
|
|
61
|
+
# with_margin should be >= base (margin >= 1.0)
|
|
62
|
+
[ "$with_margin" -ge "$base" ]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@test "estimate scales with input length" {
|
|
66
|
+
local short="short"
|
|
67
|
+
local long
|
|
68
|
+
long=$(printf 'x%.0s' {1..500})
|
|
69
|
+
local t_short t_long
|
|
70
|
+
t_short=$(governor_estimate_tokens "$short" 1.0)
|
|
71
|
+
t_long=$(governor_estimate_tokens "$long" 1.0)
|
|
72
|
+
[ "$t_long" -gt "$t_short" ]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@test "governor_estimate_cost returns a positive float for nonzero tokens" {
|
|
76
|
+
local cost
|
|
77
|
+
cost=$(governor_estimate_cost 10000)
|
|
78
|
+
# Should be > 0
|
|
79
|
+
awk "BEGIN { exit ($cost > 0) ? 0 : 1 }"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@test "governor_estimate_cost returns 0-ish for 0 tokens" {
|
|
83
|
+
local cost
|
|
84
|
+
cost=$(governor_estimate_cost 0)
|
|
85
|
+
[ "$cost" = "0.000000" ] || [ "$cost" = "0" ] || [ "$cost" = "0.0" ]
|
|
86
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
# Validates that governor.* events pass @onlooker-community/schema validation.
|
|
4
|
+
|
|
5
|
+
setup() {
|
|
6
|
+
source "${BATS_TEST_DIRNAME}/../helpers/setup.bash"
|
|
7
|
+
setup_test_env
|
|
8
|
+
|
|
9
|
+
PLUGIN_ROOT="${REPO_ROOT}/plugins/governor"
|
|
10
|
+
export CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT"
|
|
11
|
+
export ONLOOKER_EVENTS_LOG="${ONLOOKER_DIR}/logs/onlooker-events.jsonl"
|
|
12
|
+
mkdir -p "$(dirname "$ONLOOKER_EVENTS_LOG")"
|
|
13
|
+
|
|
14
|
+
export _ONLOOKER_EVENT_JS="${REPO_ROOT}/scripts/lib/onlooker-event.mjs"
|
|
15
|
+
|
|
16
|
+
# shellcheck disable=SC1091
|
|
17
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-config.sh"
|
|
18
|
+
# shellcheck disable=SC1091
|
|
19
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-events.sh"
|
|
20
|
+
|
|
21
|
+
export CLAUDE_SESSION_ID="bats-gov-session-$$"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_validate_latest_event() {
|
|
25
|
+
local last
|
|
26
|
+
last=$(tail -n 1 "$ONLOOKER_EVENTS_LOG")
|
|
27
|
+
[ -n "$last" ] || return 1
|
|
28
|
+
printf '%s' "$last" | ONLOOKER_DIR="$ONLOOKER_DIR" \
|
|
29
|
+
node "${REPO_ROOT}/scripts/lib/onlooker-event.mjs" validate >/dev/null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
SID="bats-session-000"
|
|
33
|
+
AID="bats-agent-000"
|
|
34
|
+
|
|
35
|
+
@test "governor.gate.checked allow validates" {
|
|
36
|
+
local p
|
|
37
|
+
p=$(jq -n \
|
|
38
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
39
|
+
'{
|
|
40
|
+
session_id: $sid,
|
|
41
|
+
agent_id: $aid,
|
|
42
|
+
agent_type: "Task",
|
|
43
|
+
decision: "allow",
|
|
44
|
+
estimated_tokens: 5000,
|
|
45
|
+
tokens_available: 95000,
|
|
46
|
+
estimation_method: "tier_table",
|
|
47
|
+
safety_margin: 1.3
|
|
48
|
+
}')
|
|
49
|
+
governor_emit_event "governor.gate.checked" "$p"
|
|
50
|
+
run _validate_latest_event
|
|
51
|
+
[ "$status" -eq 0 ]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@test "governor.gate.checked block with reason validates" {
|
|
55
|
+
local p
|
|
56
|
+
p=$(jq -n \
|
|
57
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
58
|
+
'{
|
|
59
|
+
session_id: $sid,
|
|
60
|
+
agent_id: $aid,
|
|
61
|
+
agent_type: "Task",
|
|
62
|
+
decision: "block",
|
|
63
|
+
reason: "budget_exceeded",
|
|
64
|
+
estimated_tokens: 110000,
|
|
65
|
+
tokens_available: 5000,
|
|
66
|
+
estimation_method: "tier_table",
|
|
67
|
+
safety_margin: 1.3
|
|
68
|
+
}')
|
|
69
|
+
governor_emit_event "governor.gate.checked" "$p"
|
|
70
|
+
run _validate_latest_event
|
|
71
|
+
[ "$status" -eq 0 ]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@test "governor.call.recorded validates" {
|
|
75
|
+
local p
|
|
76
|
+
p=$(jq -n \
|
|
77
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
78
|
+
'{
|
|
79
|
+
session_id: $sid,
|
|
80
|
+
agent_id: $aid,
|
|
81
|
+
agent_type: "Task",
|
|
82
|
+
estimated_tokens: 4200,
|
|
83
|
+
cost_usd_estimated: 0.038,
|
|
84
|
+
duration_ms: 3500
|
|
85
|
+
}')
|
|
86
|
+
governor_emit_event "governor.call.recorded" "$p"
|
|
87
|
+
run _validate_latest_event
|
|
88
|
+
[ "$status" -eq 0 ]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@test "governor.call.recorded with actuals validates" {
|
|
92
|
+
local p
|
|
93
|
+
p=$(jq -n \
|
|
94
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
95
|
+
'{
|
|
96
|
+
session_id: $sid,
|
|
97
|
+
agent_id: $aid,
|
|
98
|
+
agent_type: "Task",
|
|
99
|
+
estimated_tokens: 4200,
|
|
100
|
+
actual_tokens: 3900,
|
|
101
|
+
estimation_error_pct: 7.69,
|
|
102
|
+
cost_usd_estimated: 0.038,
|
|
103
|
+
cost_usd_actual: 0.035,
|
|
104
|
+
duration_ms: 3500,
|
|
105
|
+
tokens_returned_to_pool: 0
|
|
106
|
+
}')
|
|
107
|
+
governor_emit_event "governor.call.recorded" "$p"
|
|
108
|
+
run _validate_latest_event
|
|
109
|
+
[ "$status" -eq 0 ]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@test "governor.ledger.write_failed validates" {
|
|
113
|
+
local p
|
|
114
|
+
p=$(jq -n \
|
|
115
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
116
|
+
'{
|
|
117
|
+
session_id: $sid,
|
|
118
|
+
agent_id: $aid,
|
|
119
|
+
error: "write failed after 3 attempts",
|
|
120
|
+
retry_count: 3,
|
|
121
|
+
ledger_poisoned: true,
|
|
122
|
+
unrecorded_tokens: 4200
|
|
123
|
+
}')
|
|
124
|
+
governor_emit_event "governor.ledger.write_failed" "$p"
|
|
125
|
+
run _validate_latest_event
|
|
126
|
+
[ "$status" -eq 0 ]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@test "governor.budget.warning validates" {
|
|
130
|
+
local p
|
|
131
|
+
p=$(jq -n \
|
|
132
|
+
--arg sid "$SID" \
|
|
133
|
+
'{
|
|
134
|
+
budget_usd: 1.0,
|
|
135
|
+
spent_usd: 0.72,
|
|
136
|
+
threshold_pct: 70,
|
|
137
|
+
remaining_usd: 0.28,
|
|
138
|
+
session_id: $sid,
|
|
139
|
+
dimension: "cost_usd"
|
|
140
|
+
}')
|
|
141
|
+
governor_emit_event "governor.budget.warning" "$p"
|
|
142
|
+
run _validate_latest_event
|
|
143
|
+
[ "$status" -eq 0 ]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@test "governor.budget.exceeded validates" {
|
|
147
|
+
local p
|
|
148
|
+
p=$(jq -n \
|
|
149
|
+
--arg sid "$SID" --arg aid "$AID" \
|
|
150
|
+
'{
|
|
151
|
+
budget_usd: 1.0,
|
|
152
|
+
spent_usd: 1.05,
|
|
153
|
+
blocked_operation: "Task spawn",
|
|
154
|
+
session_id: $sid,
|
|
155
|
+
agent_id: $aid,
|
|
156
|
+
dimension: "tokens",
|
|
157
|
+
estimated_call_cost: 0.08,
|
|
158
|
+
ceiling_type: "session"
|
|
159
|
+
}')
|
|
160
|
+
governor_emit_event "governor.budget.exceeded" "$p"
|
|
161
|
+
run _validate_latest_event
|
|
162
|
+
[ "$status" -eq 0 ]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@test "governor.session.complete validates" {
|
|
166
|
+
local p
|
|
167
|
+
p=$(jq -n \
|
|
168
|
+
--arg sid "$SID" \
|
|
169
|
+
'{
|
|
170
|
+
total_cost_usd: 0.42,
|
|
171
|
+
budget_usd: 1.0,
|
|
172
|
+
under_budget: true,
|
|
173
|
+
session_id: $sid,
|
|
174
|
+
total_tokens: 46200,
|
|
175
|
+
total_api_calls: 11,
|
|
176
|
+
duration_ms: 0,
|
|
177
|
+
calls_blocked: 0,
|
|
178
|
+
calls_warned: 2,
|
|
179
|
+
ledger_poisoned: false
|
|
180
|
+
}')
|
|
181
|
+
governor_emit_event "governor.session.complete" "$p"
|
|
182
|
+
run _validate_latest_event
|
|
183
|
+
[ "$status" -eq 0 ]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@test "governor.lock.stale_cleared validates" {
|
|
187
|
+
local p
|
|
188
|
+
p=$(jq -n \
|
|
189
|
+
'{
|
|
190
|
+
lock_path: "/tmp/test.lock.d",
|
|
191
|
+
lock_age_seconds: 120.5,
|
|
192
|
+
pid_verified_dead: false
|
|
193
|
+
}')
|
|
194
|
+
governor_emit_event "governor.lock.stale_cleared" "$p"
|
|
195
|
+
run _validate_latest_event
|
|
196
|
+
[ "$status" -eq 0 ]
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@test "governor.child.allocated validates" {
|
|
200
|
+
local p
|
|
201
|
+
p=$(jq -n \
|
|
202
|
+
--arg sid "$SID" \
|
|
203
|
+
'{
|
|
204
|
+
session_id: $sid,
|
|
205
|
+
parent_agent_id: "parent-001",
|
|
206
|
+
child_agent_id: "child-001",
|
|
207
|
+
child_agent_type: "tribunal-actor",
|
|
208
|
+
tokens_allocated: 20000,
|
|
209
|
+
cost_usd_allocated: 0.18,
|
|
210
|
+
tokens_remaining_after_allocation: 80000,
|
|
211
|
+
conservation_check_passed: true
|
|
212
|
+
}')
|
|
213
|
+
governor_emit_event "governor.child.allocated" "$p"
|
|
214
|
+
run _validate_latest_event
|
|
215
|
+
[ "$status" -eq 0 ]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@test "governor.child.returned validates" {
|
|
219
|
+
local p
|
|
220
|
+
p=$(jq -n \
|
|
221
|
+
--arg sid "$SID" \
|
|
222
|
+
'{
|
|
223
|
+
session_id: $sid,
|
|
224
|
+
parent_agent_id: "parent-001",
|
|
225
|
+
child_agent_id: "child-001",
|
|
226
|
+
tokens_allocated: 20000,
|
|
227
|
+
tokens_consumed: 14200,
|
|
228
|
+
tokens_returned: 5800
|
|
229
|
+
}')
|
|
230
|
+
governor_emit_event "governor.child.returned" "$p"
|
|
231
|
+
run _validate_latest_event
|
|
232
|
+
[ "$status" -eq 0 ]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@test "governor_emit_event returns nonzero for unknown event type" {
|
|
236
|
+
run governor_emit_event "governor.no_such_event" '{"session_id":"x"}'
|
|
237
|
+
[ "$status" -ne 0 ]
|
|
238
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
setup() {
|
|
4
|
+
source "${BATS_TEST_DIRNAME}/../helpers/setup.bash"
|
|
5
|
+
setup_test_env
|
|
6
|
+
|
|
7
|
+
PLUGIN_ROOT="${REPO_ROOT}/plugins/governor"
|
|
8
|
+
export CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT"
|
|
9
|
+
export ONLOOKER_EVENTS_LOG="${ONLOOKER_DIR}/logs/onlooker-events.jsonl"
|
|
10
|
+
mkdir -p "$(dirname "$ONLOOKER_EVENTS_LOG")"
|
|
11
|
+
|
|
12
|
+
export _ONLOOKER_EVENT_JS="${REPO_ROOT}/scripts/lib/onlooker-event.mjs"
|
|
13
|
+
export CLAUDE_SESSION_ID="bats-ledger-$$"
|
|
14
|
+
|
|
15
|
+
# shellcheck disable=SC1091
|
|
16
|
+
source "${REPO_ROOT}/scripts/lib/portable-lock.sh"
|
|
17
|
+
# shellcheck disable=SC1091
|
|
18
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-config.sh"
|
|
19
|
+
# shellcheck disable=SC1091
|
|
20
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-events.sh"
|
|
21
|
+
# shellcheck disable=SC1091
|
|
22
|
+
source "${PLUGIN_ROOT}/scripts/lib/governor-ledger.sh"
|
|
23
|
+
|
|
24
|
+
export ONLOOKER_DIR="${TEST_HOME}/.onlooker"
|
|
25
|
+
SID="ledger-test-session-$$"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_make_record() {
|
|
29
|
+
local tokens="${1:-1000}"
|
|
30
|
+
local cost="${2:-0.009}"
|
|
31
|
+
jq -n \
|
|
32
|
+
--arg ts "2026-01-01T00:00:00Z" \
|
|
33
|
+
--arg sid "$SID" \
|
|
34
|
+
--arg aid "test-agent" \
|
|
35
|
+
--argjson est "$tokens" \
|
|
36
|
+
--argjson cost "$cost" \
|
|
37
|
+
'{
|
|
38
|
+
ts: $ts,
|
|
39
|
+
session_id: $sid,
|
|
40
|
+
agent_id: $aid,
|
|
41
|
+
agent_type: "Task",
|
|
42
|
+
estimated_tokens: $est,
|
|
43
|
+
cost_usd_estimated: $cost,
|
|
44
|
+
duration_ms: 1000
|
|
45
|
+
}'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_make_reservation() {
|
|
49
|
+
local tokens="${1:-1000}"
|
|
50
|
+
local cost="${2:-0.009}"
|
|
51
|
+
jq -n \
|
|
52
|
+
--arg ts "2026-01-01T00:00:00Z" \
|
|
53
|
+
--arg sid "$SID" \
|
|
54
|
+
--arg aid "test-agent" \
|
|
55
|
+
--argjson est "$tokens" \
|
|
56
|
+
--argjson cost "$cost" \
|
|
57
|
+
'{
|
|
58
|
+
ts: $ts,
|
|
59
|
+
session_id: $sid,
|
|
60
|
+
agent_id: $aid,
|
|
61
|
+
agent_type: "Task",
|
|
62
|
+
estimated_tokens: $est,
|
|
63
|
+
cost_usd_estimated: $cost,
|
|
64
|
+
record_type: "reservation"
|
|
65
|
+
}'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_make_completion() {
|
|
69
|
+
local neg_tokens="${1:--1000}"
|
|
70
|
+
local actual_tokens="${2:-900}"
|
|
71
|
+
local cost="${3:-0.009}"
|
|
72
|
+
jq -n \
|
|
73
|
+
--arg ts "2026-01-01T00:00:00Z" \
|
|
74
|
+
--arg sid "$SID" \
|
|
75
|
+
--arg aid "test-agent" \
|
|
76
|
+
--argjson est "$neg_tokens" \
|
|
77
|
+
--argjson actual "$actual_tokens" \
|
|
78
|
+
--argjson cost "$cost" \
|
|
79
|
+
'{
|
|
80
|
+
ts: $ts,
|
|
81
|
+
session_id: $sid,
|
|
82
|
+
agent_id: $aid,
|
|
83
|
+
agent_type: "Task",
|
|
84
|
+
estimated_tokens: $est,
|
|
85
|
+
actual_tokens: $actual,
|
|
86
|
+
cost_usd_estimated: $cost,
|
|
87
|
+
duration_ms: 1500
|
|
88
|
+
}'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@test "governor_ledger_path returns a .jsonl path under ONLOOKER_DIR" {
|
|
92
|
+
local p
|
|
93
|
+
p=$(governor_ledger_path "test-session")
|
|
94
|
+
[[ "$p" == *".jsonl" ]]
|
|
95
|
+
[[ "$p" == *"test-session"* ]]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@test "governor_ledger_total_tokens returns 0 for missing ledger" {
|
|
99
|
+
local total
|
|
100
|
+
total=$(governor_ledger_total_tokens "no-such-session")
|
|
101
|
+
[ "$total" = "0" ]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@test "governor_ledger_total_cost returns 0 for missing ledger" {
|
|
105
|
+
local total
|
|
106
|
+
total=$(governor_ledger_total_cost "no-such-session")
|
|
107
|
+
[ "$total" = "0" ]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@test "governor_ledger_call_count returns 0 for missing ledger" {
|
|
111
|
+
local count
|
|
112
|
+
count=$(governor_ledger_call_count "no-such-session")
|
|
113
|
+
[ "$count" = "0" ]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@test "governor_ledger_append writes a record and it is readable" {
|
|
117
|
+
local record
|
|
118
|
+
record=$(_make_record 5000 0.045)
|
|
119
|
+
governor_ledger_append "$SID" "$record"
|
|
120
|
+
|
|
121
|
+
local ledger_path
|
|
122
|
+
ledger_path=$(governor_ledger_path "$SID")
|
|
123
|
+
[ -f "$ledger_path" ]
|
|
124
|
+
|
|
125
|
+
local lines
|
|
126
|
+
lines=$(awk 'END{print NR}' "$ledger_path")
|
|
127
|
+
[ "$lines" = "1" ]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@test "governor_ledger_total_tokens sums across multiple records" {
|
|
131
|
+
governor_ledger_append "$SID" "$(_make_record 3000 0.027)"
|
|
132
|
+
governor_ledger_append "$SID" "$(_make_record 4000 0.036)"
|
|
133
|
+
governor_ledger_append "$SID" "$(_make_record 2500 0.023)"
|
|
134
|
+
|
|
135
|
+
local total
|
|
136
|
+
total=$(governor_ledger_total_tokens "$SID")
|
|
137
|
+
[ "$total" = "9500" ]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@test "governor_ledger_total_cost sums across multiple records" {
|
|
141
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.01)"
|
|
142
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.02)"
|
|
143
|
+
|
|
144
|
+
local total
|
|
145
|
+
total=$(governor_ledger_total_cost "$SID")
|
|
146
|
+
# Allow slight floating-point representation variance
|
|
147
|
+
[[ "$total" =~ ^0\.03 ]]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@test "governor_ledger_call_count counts records" {
|
|
151
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.009)"
|
|
152
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.009)"
|
|
153
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.009)"
|
|
154
|
+
|
|
155
|
+
local count
|
|
156
|
+
count=$(governor_ledger_call_count "$SID")
|
|
157
|
+
[ "$count" = "3" ]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@test "governor_ledger_is_poisoned returns false for healthy ledger" {
|
|
161
|
+
governor_ledger_append "$SID" "$(_make_record 1000 0.009)"
|
|
162
|
+
run governor_ledger_is_poisoned "$SID"
|
|
163
|
+
[ "$status" -ne 0 ]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@test "governor_ledger_is_poisoned returns true after poison sentinel" {
|
|
167
|
+
local ledger_path
|
|
168
|
+
ledger_path=$(governor_ledger_path "$SID")
|
|
169
|
+
mkdir -p "$(dirname "$ledger_path")"
|
|
170
|
+
touch "$(governor_ledger_poison_path "$ledger_path")"
|
|
171
|
+
|
|
172
|
+
run governor_ledger_is_poisoned "$SID"
|
|
173
|
+
[ "$status" -eq 0 ]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@test "governor_ledger_write_direct writes a record without acquiring the write lock" {
|
|
177
|
+
local ledger_path
|
|
178
|
+
ledger_path=$(governor_ledger_path "$SID")
|
|
179
|
+
mkdir -p "$(dirname "$ledger_path")"
|
|
180
|
+
|
|
181
|
+
local record
|
|
182
|
+
record=$(_make_reservation 2000 0.018)
|
|
183
|
+
governor_ledger_write_direct "$ledger_path" "$record"
|
|
184
|
+
|
|
185
|
+
local lines
|
|
186
|
+
lines=$(awk 'END{print NR}' "$ledger_path")
|
|
187
|
+
[ "$lines" = "1" ]
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@test "two-phase: reservation plus completion converges to actual tokens" {
|
|
191
|
+
# Phase 1: PreToolUse writes reservation with N_est = 5000
|
|
192
|
+
local reservation
|
|
193
|
+
reservation=$(_make_reservation 5000 0.045)
|
|
194
|
+
governor_ledger_append "$SID" "$reservation"
|
|
195
|
+
|
|
196
|
+
local mid_total
|
|
197
|
+
mid_total=$(governor_ledger_total_tokens "$SID")
|
|
198
|
+
[ "$mid_total" = "5000" ]
|
|
199
|
+
|
|
200
|
+
# Phase 2: PostToolUse writes completion with estimated=-5000, actual=4200
|
|
201
|
+
local completion
|
|
202
|
+
completion=$(_make_completion -5000 4200 0.045)
|
|
203
|
+
governor_ledger_append "$SID" "$completion"
|
|
204
|
+
|
|
205
|
+
# Net: 5000 + (-5000) + 4200 = 4200
|
|
206
|
+
local final_total
|
|
207
|
+
final_total=$(governor_ledger_total_tokens "$SID")
|
|
208
|
+
[ "$final_total" = "4200" ]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@test "governor_ledger_call_count excludes reservation records" {
|
|
212
|
+
governor_ledger_append "$SID" "$(_make_reservation 1000 0.009)"
|
|
213
|
+
governor_ledger_append "$SID" "$(_make_completion -1000 900 0.009)"
|
|
214
|
+
governor_ledger_append "$SID" "$(_make_completion -1000 800 0.009)"
|
|
215
|
+
|
|
216
|
+
local count
|
|
217
|
+
count=$(governor_ledger_call_count "$SID")
|
|
218
|
+
# 2 completions, 1 reservation — only completions count
|
|
219
|
+
[ "$count" = "2" ]
|
|
220
|
+
}
|