Harness: runner, generator, tasks T01 T13 T14 T15, CLAUDE.md
This commit is contained in:
62
harness/task.py
Normal file
62
harness/task.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""Task loading and prefix substitution."""
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
_B36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
|
||||
def _b36(n, width):
|
||||
out = ""
|
||||
while n:
|
||||
n, r = divmod(n, 36)
|
||||
out = _B36[r] + out
|
||||
return out.rjust(width, "0")[-width:]
|
||||
|
||||
|
||||
def prefix_for(run_no, task_id):
|
||||
"""Z + run (4 chars base36) + task (3 chars base36) + '_'.
|
||||
|
||||
Run numbers below 36**3 keep a digit at position 2; the proxy uses this to tell
|
||||
harness objects from other Z objects. Old prefixes (Z201001_) match the same pattern.
|
||||
"""
|
||||
task_no = int("".join(ch for ch in task_id if ch.isdigit()) or 0)
|
||||
return f"Z{_b36(int(run_no), 4)}{_b36(task_no, 3)}_"
|
||||
|
||||
|
||||
class Task:
|
||||
def __init__(self, task_dir, prefix):
|
||||
self.dir = task_dir
|
||||
self.prefix = prefix
|
||||
self.meta = json.loads(self._read("task.json"))
|
||||
self.id = self.meta["id"]
|
||||
|
||||
def _read(self, rel):
|
||||
with open(os.path.join(self.dir, rel)) as f:
|
||||
return f.read()
|
||||
|
||||
def sub(self, text):
|
||||
return text.replace("{{P}}", self.prefix).replace("{{p}}", self.prefix.lower())
|
||||
|
||||
def text(self, rel):
|
||||
return self.sub(self._read(rel))
|
||||
|
||||
def objects(self, key):
|
||||
"""List of dicts with substituted names and loaded source (if 'file')."""
|
||||
out = []
|
||||
for o in self.meta.get(key, []):
|
||||
o = {k: self.sub(v) if isinstance(v, str) else v for k, v in o.items()}
|
||||
if "file" in o:
|
||||
o["source"] = self.text(o["file"])
|
||||
if "testclasses_file" in o:
|
||||
o["testclasses_source"] = self.text(o["testclasses_file"])
|
||||
out.append(o)
|
||||
return out
|
||||
|
||||
@property
|
||||
def spec(self):
|
||||
return self.text("spec.md")
|
||||
|
||||
@property
|
||||
def out_of_scope(self):
|
||||
return [self.sub(n) for n in self.meta.get("out_of_scope", [])]
|
||||
Reference in New Issue
Block a user