Fix 9 seam-review findings

- Pinned target's profitability flag now overrides the extractor's bucket guess
- Extractor/target periods canonicalized so ledger forecast chaining matches
- autoRunOnDrop no longer error-loops on ungradeable inbox content; failed
  batches count as seen
- Ship 2 default graders (pipeline requires >=2 valid reports per deck)
- UI styles 'failed' deck chips as errors; .markdown discoverable
- Unknown adjudicator model disables adjudication loudly instead of silently
- Reserved rids extractor/adjudicator; teardown also clears bm-grader-* containers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Kirkwood
2026-07-06 14:26:41 -05:00
co-authored by Claude Fable 5
parent b1d7aed9f4
commit 1d1074b625
9 changed files with 54 additions and 15 deletions
+16 -9
View File
@@ -70,11 +70,6 @@ REQUEST_PATH = os.path.join(STATE_DIR, "run_request")
TICK_SECONDS = 10
RUNNING_PHASES = ("extracting", "grading", "adjudicating", "scoring", "collecting")
# Canonical-ish reporting periods: 2026-Q2, 2026-H1, FY2026, 2026-05, 2026.
_PERIOD_RE = re.compile(
r"^(?:FY\s?-?\d{4}|\d{4}(?:[-/ ]?(?:Q[1-4]|H[12]|0[1-9]|1[0-2]))?)$", re.IGNORECASE)
def _inbox_signature() -> tuple[int, str]:
"""(count, signature) of supported files anywhere in the inbox tree, for
autoRunOnDrop stability checks (decks live in per-company subfolders)."""
@@ -229,8 +224,13 @@ class JobRunner:
count, sig = _inbox_signature()
if count and sig == self._last_sig and sig != self._last_done_sig:
# stable across two ticks and not the batch we last processed
triggered = True
self.log("[runner] inbox stable — auto-running grading")
if decks.discover(INBOX).get("units"):
triggered = True
self.log("[runner] inbox stable — auto-running grading")
else:
# only ungradeable files (e.g. dropped at the inbox root):
# mark the batch seen so we don't retrigger every tick
self._last_done_sig = sig
self._last_sig = sig
if not triggered:
@@ -288,6 +288,10 @@ class JobRunner:
needed = {r["model"] for r in valid} | {extractor_model}
adjudicate = bool(cfg.get("adjudicatorEnabled"))
adj_model = adj_mod.pick_model(cfg) if adjudicate else ""
if adjudicate and adj_model not in catalog:
self.log(f"[runner] WARNING: adjudicator model '{adj_model}' is not in the "
"model catalog — adjudication disabled for this job")
adjudicate, adj_model = False, ""
needed_all = needed | ({adj_model} if adjudicate and adj_model else set())
# Air-gapped mode can't route to second-Spark models (internal net).
@@ -364,6 +368,9 @@ class JobRunner:
self.message = f"Grading failed: {e}"
self.log(f"[runner] JOB FAILED — {e}")
self.log(traceback.format_exc().splitlines()[-1])
# A failed batch counts as seen — otherwise autoRunOnDrop retries
# the same failing inbox every other tick.
self._last_done_sig = _inbox_signature()[1]
try:
serving.tear_down_all(cfg, self.log)
except Exception:
@@ -545,8 +552,8 @@ class JobRunner:
(flagged as period_inferred in the extraction's red-flag candidates)."""
if unit.get("period"):
return unit["period"], _token(unit["period"])
p = ((ext_obj.get("deck") or {}).get("period") or "").strip()
if p and _PERIOD_RE.match(p):
p = decks.canonicalize_period((ext_obj.get("deck") or {}).get("period"))
if p:
self.log(f"[runner] period '{p}' taken from the deck text")
return p, _token(p)
try: