Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 44 additions & 8 deletions tests/test_budget_enforcement.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,23 @@
re-report of a metered call from a real charge by identity — matching token
counts swallowed charges that were real, which is the direction that costs
money.

**On the wall-clock assertions in here.** Each timing test bounds how long an
interrupted node took, and every such bound is placed *between* the deadline
and the uninterrupted body rather than close to either. That placement is the
whole fix for a flake that only ever appeared on a loaded machine: three suites
running at once turned `< 2.0` on a 0.2s deadline red, while the same tests
passed 16/16 on the same box while it was idle. The deadline machinery was
never the thing failing — the assertion on how promptly the interrupt landed
was, because a hand-picked constant sitting 1.8s above the deadline has no room
left when scheduling delays run 2-3x.

So the question each bound must answer is "was this interrupted, or did it run
to completion", and it answers it with seconds of slack on both sides. Where
the gap was too narrow to widen the bound into, the *body* was lengthened
instead — an uninterrupted body only ever runs that long when the test is
failing, so a longer one costs nothing on the green path and makes the red path
unambiguous.
"""

import asyncio
Expand DownExpand Up@@ -383,7 +400,8 @@ def slow(state):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
compiled.invoke({})
assert time.perf_counter() - started < 2.0
# Between the 0.2s deadline and the 5.0s body, near neither.
assert time.perf_counter() - started < 3.0


def test_the_error_names_the_node_that_ran_long():
Expand DownExpand Up@@ -434,7 +452,12 @@ def plan(state):
return None

def work(payload: Shard):
deadline = time.perf_counter() + 5.0
# 15s, not 5s: with a 1.5s ceiling there was no room to put a bound
# between the two — `< 3.0` sat 1.5s above the deadline and 2s below the
# body, and three workers spinning on a contended box closed that gap
# from both ends. Lengthening the body is free on the green path,
# because a worker only ever spins this long when the interrupt failed.
deadline = time.perf_counter() + 15.0
while time.perf_counter() < deadline:
pass
return {"done": [payload.index]}
Expand All@@ -445,7 +468,7 @@ def work(payload: Shard):
# the deadline had already passed, so its entry check raised a plain
# `BudgetExceeded` and that propagated first — `NodeDeadlineExceeded` is a
# subclass, so the assertion below correctly rejected it. The ceiling only
# has to outlast task scheduling; the workers spin for 5s either way.
# has to outlast task scheduling; the workers spin for 15s either way.
g = GraphARC(FanState, name="fan", budget=Budget(max_seconds=1.5))
g.add_node("plan", plan, writes=set())
g.add_node("work", work, writes={"done"}, input_schema=Shard)
Expand All@@ -456,7 +479,8 @@ def work(payload: Shard):
started = time.perf_counter()
with pytest.raises(NodeDeadlineExceeded):
g.compile().invoke({"done": []})
assert time.perf_counter() - started < 3.0
# Between the 1.5s ceiling and the 15s body, near neither.
assert time.perf_counter() - started < 6.0


def _swallow_interrupts_for(
Expand DownExpand Up@@ -643,20 +667,32 @@ def test_an_unreachable_max_seconds_does_not_disable_the_next_run(unreachable):
and the process-wide slot is taken, and both were left that way — so every
later guard found the slot held and silently fell back to the async-exception
mechanism, which cannot unwind a blocking syscall. The 0.2s deadline below
then took the full 2s sleep to be noticed.
then took the full sleep to be noticed.
"""

# Two bodies, because the two runs below want opposite things from one. The
# first must run to completion, so its body is the cost of this test on the
# green path and wants to be short. The second must be cut off, so its body
# is what the elapsed bound is measured against and wants to be long — one
# 2.0s body served both badly, leaving `< 1.0` with 0.8s of room above the
# deadline and 1.0s below the body, which is the gap contention closed.
def quick(state):
time.sleep(0.05)
return {"ok": True}

def slow(state):
time.sleep(2.0)
time.sleep(10.0)
return {"ok": True}

# An unreachable ceiling must not fire, and must not leave a trap behind.
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})
_single_node_graph(quick, writes={"ok"}, budget=Budget(max_seconds=unreachable)).invoke({})

started = time.monotonic()
with pytest.raises(NodeDeadlineExceeded, match="max_seconds"):
_single_node_graph(slow, writes={"ok"}, budget=Budget(max_seconds=0.2)).invoke({})
assert time.monotonic() - started < 1.0, "SIGALRM was still poisoned"
# Poisoned, the fallback cannot unwind a blocking syscall and this takes the
# full 10s. Between the 0.2s deadline and that, near neither.
assert time.monotonic() - started < 4.0, "SIGALRM was still poisoned"

if hasattr(signal, "SIGALRM"):
assert signal.getsignal(signal.SIGALRM) in (signal.SIG_DFL, signal.SIG_IGN)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_cli.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -745,7 +745,10 @@ def invoke(self, messages):
elapsed = time.monotonic() - started
assert code == 1
assert "max_seconds" in payload["error"]
assert elapsed < 10, "the sleeping call was waited out rather than interrupted"
# Between the 0.5s ceiling and the 30s call, near neither: this asks whether
# the call was interrupted or waited out, and a bound close to either end
# answers a question about machine load instead.
assert elapsed < 15, "the sleeping call was waited out rather than interrupted"


def test_agent_reports_an_unusable_model_spec(tmp_path, capsys, stub_tools):
Expand Down
6 changes: 5 additions & 1 deletion tests/test_cookbook_basics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -412,7 +412,11 @@ def nap(state: BoundedState) -> dict:
assert caught.value.reason.split(" (")[0] == (
"max_seconds reached while node 'n' was running"
)
assert elapsed < 1.0, f"the sleep ran to completion ({elapsed:.1f}s)"
# Between the page's 0.25s ceiling and its 5.0s sleep, near neither. The
# snippet's own numbers are the page's and stay as printed; this bound is
# the test's, and `< 1.0` left it 0.75s above a deadline that a loaded
# machine can overshoot by more than that.
assert elapsed < 3.0, f"the sleep ran to completion ({elapsed:.1f}s)"


# -- "How do I forbid cycles until I actually need one?" -------------------
Expand Down
Loading