Gemma 4 26B-A4B head-to-head vs Qwen (4 prompts, via grade_run.py API)

Ran via tools/grade_run.py against LM Studio (no clipboard). Results:
  TTS:        80 Minor Flaws  PASSES (real N-worker concurrency) <- Qwen 49, didn't parse
  Rust:       72 Minor Flaws  COMPILES CLEAN (0 errs w/ deps)     <- Qwen 50, 7 real errors
  Webhook:    55 Critical     uses forbidden aiohttp (won't run)  <- Qwen 75, passed
  Automation: 48 Critical     SyntaxError (global-after-assign)   <- first run for both

DECISIVE head-to-head: Gemma generalizes where Qwen fails (TTS, Rust),
but Qwen beats it on stdlib-discipline prompts (webhook). The two are
COMPLEMENTARY local offloads, not redundant.

Fixed: grade_run.py extractor (markdown/prose wrapping, multi-fence lang
selection), TTFT-null handling in generator. TTFT capture from LM Studio
API still needs the right stats key (left null + noted).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-28 18:42:58 -07:00
co-authored by Claude
parent b82c665ec6
commit b9f45a7c46
7 changed files with 1310 additions and 8 deletions
@@ -0,0 +1,296 @@
import asyncio
import json
import os
import random
import signal
import time
from dataclasses import dataclass, asdict, field
from pathlib import Path
from typing import Set, List, Dict, Any
# --- Domain Exceptions ---
class ProcessingError(Exception):
"""Raised when the flaky external call fails."""
pass
# --- Models ---
@dataclass
class Checkpoint:
completed_ids: Set[str] = field(default_factory=set)
failed_ids: Set[str] = field(default_factory=set)
def to_dict(self) -> Dict[str, Any]:
return {
"completed_ids": list(self.completed_ids),
"failed_ids": list(self.failed_ids)
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Checkpoint":
return cls(
completed_ids=set(data.get("completed_ids", [])),
failed_ids=set(data.get("failed_ids", []))
)
# --- Core Logic ---
class BatchProcessor:
def __init__(
self,
items: List[str],
checkpoint_path: str = "checkpoint.json",
max_concurrency: int = 8,
max_retries: int = 3
):
self.items = items
self.checkpoint_path = Path(checkpoint_path)
self.semaphore = asyncio.Semaphore(max_concurrency)
self.max_retries = max_retries
self.checkpoint = Checkpoint()
self.shutdown_event = asyncio.Event()
self.start_time = 0.0
self._pending_tasks: Set[asyncio.Task] = set()
def _load_checkpoint(self):
if self.checkpoint_path.exists():
try:
with open(self.checkpoint_path, "r") as f:
data = json.load(f)
self.checkpoint = Checkpoint.from_dict(data)
except (json.JSONDecodeError, KeyError):
# If corrupt, we start fresh or could raise error.
# Requirement says "crash must leave valid checkpoint", so we assume it's valid.
pass
def _save_checkpoint(self):
"""Atomic write using a temporary file and os.replace."""
temp_path = self.checkpoint_path.with_suffix(".tmp")
try:
with open(temp_path, "w") as f:
json.dump(self.checkpoint.to_dict(), f)
# os.replace is atomic on both POSIX and Windows (for existing files)
os.replace(temp_path, self.checkpoint_path)
except Exception as e:
print(f"Failed to save checkpoint: {e}")
async def _process_item_with_retry(self, item: str, process_func):
"""Handles the retry logic and backoff for a single item."""
async with self.semaphore:
# Check if we are shutting down before starting a new item
if self.shutdown_event.is_set():
return
for attempt in range(self.max_retries + 1):
try:
await process_func(item)
# Success path
self.checkpoint.completed_ids.add(item)
self._save_checkpoint()
return "succeeded"
except ProcessingError:
if attempt < self.max_retries:
# Exponential backoff: 0.1, 0.2, 0.4...
wait_time = 0.1 * (2 ** attempt)
await asyncio.sleep(wait_time)
else:
# Terminal failure after retries
self.checkpoint.failed_ids.add(item)
self._save_checkpoint()
return "failed"
except asyncio.CancelledError:
# If the task is cancelled (e.g. during shutdown),
# we don't record it as completed or failed.
raise
async def run(self, process_func) -> Dict[str, Any]:
self._load_checkpoint()
self.start_time = time.perf_counter()
# Identify items to skip
to_process = [
i for i in self.items
if i not in self.checkpoint.completed_ids and i not in self.checkpoint.failed_ids
]
skipped_count = len(self.items) - len(to_process) - len(self.checkpoint.failed_ids)
# Note: skipped is items already in checkpoint.completed_ids
skipped_count = len([i for i in self.items if i in self.checkpoint.completed_ids])
# We use a set to track tasks so we can await them during graceful shutdown
tasks = []
for item in to_process:
if self.shutdown_event.is_set():
break
task = asyncio.create_task(self._process_item_with_retry(item, process_func))
tasks.append(task)
self._pending_tasks.add(task)
task.add_done_callback(self._pending_tasks.discard)
# Wait for all spawned tasks to finish
if tasks:
await asyncio.gather(*tasks, return_exceptions=True)
elapsed_ms = int((time.perf_counter() - self.start_time) * 1000)
# Final Summary Calculation
# We must re-calculate based on the final state of checkpoint + what was skipped
succeeded = len(self.checkpoint.completed_ids)
failed = len(self.checkpoint.failed_ids)
# Items that were already done before we started
already_done = len([i for i in self.items if i in self.checkpoint.completed_ids and i not in to_process])
# Actually, the requirement asks for a summary of this run's context.
# Let's provide the absolute state:
return {
"succeeded": succeeded,
"failed": failed,
"skipped": skipped_count,
"total": len(self.items),
"elapsed_ms": elapsed_ms
}
# --- Mock External Service ---
async def flaky_process(item: str) -> str:
"""The provided flaky function."""
# Simulate random latency 10-80ms
await asyncio.sleep(random.uniform(0.01, 0.08))
# 80% success rate
if random.random() < 0.2:
raise ProcessingError(f"Failed to process {item}")
return f"Result for {item}"
# --- Tests ---
async def run_tests():
print("\n--- Starting Tests ---")
checkpoint_file = "test_checkpoint.json"
if os.path.exists(checkpoint_file):
os.remove(checkpoint_file)
# 1. Concurrency Test
print("Test: Bounded Concurrency (Max 8)...", end="", flush=True)
active_count = 0
max_observed = 0
lock = asyncio.Lock()
async def concurrency_mock(item: str):
nonlocal active_count, max_observed
async with lock:
active_count += 1
max_observed = max(max_observed, active_count)
await asyncio.sleep(0.05)
async with lock:
active_count -= 1
proc = BatchProcessor(["item-" + str(i) for i in range(20)], checkpoint_path=checkpoint_file, max_concurrency=8)
await proc.run(concurrency_mock)
assert max_observed <= 8, f"Concurrency exceeded! Observed {max_observed}"
print("PASSED")
# 2. Integrity Test (Watcher)
print("Test: Checkpoint Integrity (JSON Validity)...", end="", flush=True)
stop_watcher = asyncio.Event()
async def integrity_watcher():
while not stop_watcher.is_set():
if os.path.exists(checkpoint_file):
try:
with open(checkpoint_file, "r") as f:
json.load(f)
except Exception as e:
raise AssertionError(f"Corrupt JSON detected: {e}")
await asyncio.sleep(0.005)
watcher_task = asyncio.create_task(integrity_watcher())
proc = BatchProcessor(["item-" + str(i) for i in range(50)], checkpoint_path=checkpoint_file)
await proc.run(flaky_process)
stop_watcher.set()
await watcher_task
print("PASSED")
# 3. Resumability / Idempotency Test
print("Test: Resumability & Idempotency...", end="", flush=True)
items = [f"resumable-{i}" for i in range(100)]
checkpoint_file = "resumable.json"
if os.path.exists(checkpoint_file): os.remove(checkpoint_file)
# Run 1: Start and interrupt mid-way
proc = BatchProcessor(items, checkpoint_path=checkpoint_file)
# We simulate an interruption by cancelling the main task after a short delay
main_task = asyncio.create_task(proc.run(flaky_process))
await asyncio.sleep(0.2)
proc.shutdown_event.set() # Signal shutdown
# We don't cancel the task immediately to allow in-flight items to finish (graceful)
await main_task
# Run 2: Restart
proc_retry = BatchProcessor(items, checkpoint_path=checkpoint_file)
final_summary = await proc_retry.run(flaky_process)
# Assertions
# 1. All items must eventually be in completed or failed sets
all_processed = proc_retry.checkpoint.completed_ids | proc_retry.checkpoint.failed_ids
assert len(all_processed) == len(items), f"Not all items processed. Got {len(all_processed)}/{len(items)}"
# 2. Checkpoint must be valid and contain all items
assert final_summary["total"] == 100
print("PASSED")
# Cleanup
for f in [checkpoint_file, "test_checkpoint.json", "resumable.json"]:
if os.path.exists(f): os.remove(f)
print("--- All Tests Passed Successfully ---\n")
# --- Main Entry Point ---
async def main():
# Setup signal handling for SIGINT (Ctrl+C)
loop = asyncio.get_running_loop()
# We'll use a global processor instance to allow the signal handler access
processor = None
def handle_sigint():
if processor:
print("\n[!] SIGINT received. Shutting down gracefully (finishing in-flight tasks)...")
processor.shutdown_event.set()
# Register signal handler
try:
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, handle_sigint)
except NotImplementedError:
# signal.add_signal_handler is not implemented on Windows in some Python versions
pass
# Input Data
work_items = [f"job-{i:03d}" for i in range(100)]
global processor
processor = BatchProcessor(work_items, max_concurrency=8)
try:
summary = await processor.run(flaky_process)
print(json.dumps(summary))
except KeyboardInterrupt:
# Fallback for environments where signal handler doesn't catch it
pass
except Exception as e:
print(f"Fatal error: {e}")
finally:
# If we are running tests, don't exit yet
import sys
if len(sys.argv) > 1 and sys.argv[1] == "--test":
pass
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "--test":
asyncio.run(run_tests())
else:
try:
asyncio.run(main())
except KeyboardInterrupt:
# Final catch for the top-level loop
sys.exit(0)