From 4edada89447ce25ddaa48a1c7fe84905e78cc5cb Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Tue, 29 Sep 2026 09:49:15 +0900 Subject: [PATCH 01/39] docs: ADR-029 plan, what the Score order measurements look at Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/DECISIONS.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index dff4ea3..37506df 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -581,6 +581,30 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode --- +## ADR-029 — Score is read in one order; measure the position effect, and offer averaging off by default + +**Open.** Proposed in [#1](https://github.com/Abhinavexists/lev/issues/1); the default is the maintainer's call. + +**Problem.** Choice and binary Noul are read in two orders and averaged, which cancels the preference for the first letter (ADR-020). Score is not: its levels keep the low-to-high order training uses, because reversing them measured -2.4 points on helpsteer2, inside sampling noise, on a prompt training never produces (FINDINGS §12). What that leaves was not measured. On `interfaze-ai/lev` with Score questions over the 290 states of sokudan's `bench_en`, an identical-option control (every level the same text, so levels differ only by position and code) put slot 0 at -0.332 below the mean in calibrated log-probability and -0.931 in raw scores, and the first slot won 0.270 of the decisions over all six orders of three levels, where an order-free readout is at 1/3 (#1). The check is the one NandhaKishorM/laya#259 added to Laya, whose gate is -0.20 on raw scores. + +**Options.** + +- (a) Average Score over orders by default: `reversed` (2 rows, as Choice) or `cyclic` (every rotation, K rows). Both show the model level orders training never produces; in the `chat` style each line still names its level (`(level i of K)`). +- (b) Keep Score in one order by default, ship averaging as `EngineConfig.score_order_average` (off), and put the control in CI: `lev presentation-checks` against a committed report, failing on drift. + +**What is measured, fixed before the runs.** One checkpoint (`interfaze-ai/lev`, bf16, one RTX 5090), sokudan's `bench_en` (290) and `bench_ja` (300), `score_order_average` in {off, reversed, cyclic}: + +1. The identical-option control and the first-slot rate, for Score and Choice, with the shipped calibration and raw (an empty `CalibrationProfile`). +2. Score RPS and accuracy on the benches' 3-level urgency question, with Choice and Noul on the same requests expected unchanged (Score rows are the only rows added). +3. Milliseconds per three-question request, as the cost of each mode. +4. With averaging off, every answer identical to the current code on the same items. + +Every result is reported whichever way it goes, including accuracy that does not improve. + +**Evidence.** Pending the runs above. + +--- + ## ADR-030 — The server batches across requests and refuses work it cannot do in time **Accepted.** From eea147636ea87ca163a576e06d1f168f439827df Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Tue, 29 Sep 2026 17:47:55 +0900 Subject: [PATCH 02/39] Measure Score's position effect with lev presentation-checks, and offer Score order averaging (off by default) Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/ARCHITECTURE.md | 2 + packages/lev/src/lev/cli.py | 137 +++++++++++ packages/lev/src/lev/model.py | 28 ++- packages/lev/src/lev/presentation.py | 281 +++++++++++++++++++++++ packages/lev/src/lev/server.py | 3 + packages/lev/tests/test_presentation.py | 289 ++++++++++++++++++++++++ 6 files changed, 732 insertions(+), 8 deletions(-) create mode 100644 packages/lev/src/lev/presentation.py create mode 100644 packages/lev/tests/test_presentation.py diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 580044c..b14ecc3 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -201,6 +201,8 @@ LoRA r32 on `q,k,v,o,gate,up,down` ≈ 25–40 M trainable parameters. **The Fam - they get **separate fitted temperatures** — one global scalar would be wrong for at least one of them; - on option sets where **both** are valid we measure agreement. Material disagreement means the router is a correctness hazard, not merely a capacity switch. This is an explicit eval, not an assumption. +**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `lev presentation-checks` measures what that changes (ADR-029). + ### 5.4 Output types | Type | Mode A | Mode B | diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index a439f3e..2710bc8 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -216,12 +216,102 @@ def cmd_serve(args: argparse.Namespace) -> None: prompt_style=args.prompt_style, max_pending=args.max_pending, max_batch_tokens=args.max_batch_tokens, + score_order_average=args.score_order_average, ), host=args.host, port=args.port, ) +def _cuda(): + """`torch.cuda` when a GPU is in use, else None; torch is imported only here.""" + try: + import torch + except ImportError: + return None + return torch.cuda if torch.cuda.is_available() else None + + +def cmd_presentation_checks(args: argparse.Namespace) -> None: + """Label-free presentation checks (ADR-029). Exits non-zero when a metric drifts + from `--compare` beyond `--tolerance`, or, with `--enforce-gate`, below a gate.""" + import time + + from . import presentation + from .calibrate import CalibrationProfile + from .model import load + + states = presentation.read_states(args.states)[: args.limit] + engine = load( + args.checkpoint, + model_id=args.model, + cache_dir=args.model_cache, + calibration=args.calibration, + score_order_average=args.score_order_average, + ) + if args.raw: + engine.calibration = CalibrationProfile() + kinds = [k.strip() for k in args.kinds.split(",") if k.strip()] + grouping = { + "split_checks": args.split_checks, + "max_score_rows": args.max_score_rows, + "score_order_average": args.score_order_average, + } + cuda = _cuda() + if cuda: + cuda.empty_cache() + cuda.reset_peak_memory_stats() + started = time.perf_counter() + report = presentation.run( + engine.system_one, states, args.lang, kinds, args.slot0_min, **grouping + ) + seconds = time.perf_counter() - started + packed = presentation.packed_consistency( + engine.system_one, states[: args.packed], args.lang, kinds, **grouping + ) + peak = ( + { + "allocated_gib": round(cuda.max_memory_allocated() / 2**30, 2), + "reserved_gib": round(cuda.max_memory_reserved() / 2**30, 2), + } + if cuda + else None + ) + if cuda: + cuda.empty_cache() + print(presentation.to_markdown(report)) + print(f"packed vs alone: max |dp| {packed:.2e} over {min(args.packed, len(states))} states") + payload = { + "checkpoint": args.checkpoint, + "states": args.states, + "n_states": len(states), + "lang": args.lang, + "raw": args.raw, + "kinds": kinds, + **grouping, + "seconds": round(seconds, 1), + "peak_vram": peak, + "packed_max_abs_diff": packed, + "checks": report, + } + if args.out: + text = json.dumps(payload, indent=1, ensure_ascii=False) + "\n" + Path(args.out).write_text(text, "utf-8") + failures = [] + if args.compare: + committed = json.loads(Path(args.compare).read_text("utf-8"))["checks"] + failures += presentation.drift(report, committed, args.tolerance) + if args.enforce_gate: + failures += [ + f"{kind}.{check}: {r[check]['metric']:+.3f} below {r[check]['gate']:+.2f}" + for kind, r in report.items() + for check in ("identical", "first_slot") + if not r[check]["passed"] + ] + if failures: + sys.exit("presentation checks failed:\n " + "\n ".join(failures)) + + def main(argv: list[str] | None = None) -> None: parser = argparse.ArgumentParser(prog="lev", description=__doc__) sub = parser.add_subparsers(dest="command", required=True) @@ -296,10 +386,57 @@ def main(argv: list[str] | None = None) -> None: default=16384, help="padded tokens per batched forward across requests (default 16384)", ) + serve_parser.add_argument( + "--score-order-average", + choices=["off", "reversed", "cyclic"], + default="off", + help="average Score levels over reversed or all cyclic orders (2x / Kx rows; ADR-029)", + ) serve_parser.add_argument("--host", default="127.0.0.1") serve_parser.add_argument("--port", type=int, default=8000) serve_parser.set_defaults(func=cmd_serve) + presentation_parser = sub.add_parser( + "presentation-checks", + help="label-free position checks for Score and Choice (ADR-029)", + ) + presentation_parser.add_argument("states", help="JSONL with a `state` per line") + presentation_parser.add_argument("--checkpoint", default=None) + presentation_parser.add_argument("--model", default="Qwen/Qwen3.5-4B-Base") + presentation_parser.add_argument("--model-cache", default=None) + presentation_parser.add_argument("--calibration", default=None) + presentation_parser.add_argument("--lang", choices=["en", "ja"], default="en") + presentation_parser.add_argument("--kinds", default="score,choice") + presentation_parser.add_argument("--limit", type=int, default=None) + presentation_parser.add_argument( + "--raw", action="store_true", help="score without calibration (T = 1 everywhere)" + ) + presentation_parser.add_argument( + "--score-order-average", choices=["off", "reversed", "cyclic"], default="off" + ) + presentation_parser.add_argument( + "--packed", type=int, default=3, help="states for the packed-vs-alone check" + ) + presentation_parser.add_argument( + "--split-checks", + action="store_true", + help="ask the identical and permuted questions in separate calls", + ) + presentation_parser.add_argument( + "--max-score-rows", + type=int, + default=24, + help="Score rows per call before the probe is split (cyclic reads a level K times)", + ) + presentation_parser.add_argument("--slot0-min", type=float, default=-0.20) + presentation_parser.add_argument("--out", default=None, help="write the report JSON here") + presentation_parser.add_argument("--compare", default=None, help="a committed report JSON") + presentation_parser.add_argument("--tolerance", type=float, default=0.05) + presentation_parser.add_argument( + "--enforce-gate", action="store_true", help="also fail when a check is below its gate" + ) + presentation_parser.set_defaults(func=cmd_presentation_checks) + data_parser = sub.add_parser("data", help="build the training mixture and the eval set") data_sub = data_parser.add_subparsers(dest="data_command", required=True) diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index f1714ca..9b6cb04 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -46,6 +46,10 @@ class EngineConfig: noul_readout: Literal["rating", "binary"] = "rating" # A second option order reduces letter-position bias; costs one extra batch row. order_average: bool = True + # Score levels keep their low-to-high order unless this opts in (ADR-029): "reversed" + # adds the reversed order (2 rows per Score, as Choice), "cyclic" every rotation (K rows). + # Both show the model level orders training never produces (ADR-020, FINDINGS §12). + score_order_average: Literal["off", "reversed", "cyclic"] = "off" # Serving can skip split codes; training keeps large sets for Mode B (ADR-028). skip_multi_token_codes: bool = True # Forking avoids repeated prefix work but adds a forward and cache copies (ADR-023). @@ -279,16 +283,22 @@ def _respond(self, request: Prepared, logits, hidden) -> SystemOneResponse: def _orders(self, question: Question, route: Route) -> list[list[int] | None]: """Candidate orders to render; None means the original order. Only lettered Choice and binary Noul in state-first layout are reversed (ordered scales - keep training's low-to-high order; schema-first shares options).""" - if ( - not self.config.order_average - or route.mode is not Mode.LABEL_TOKEN - or self.config.layout is not Layout.STATE_FIRST - or isinstance(question, Score) - or (isinstance(question, Noul) and route.reason != BINARY_NOUL) - ): + keep training's low-to-high order; schema-first shares options), unless + `score_order_average` opts a Score in: "reversed" adds one row, "cyclic" + K-1, both in orders training never shows (ADR-029).""" + if route.mode is not Mode.LABEL_TOKEN or self.config.layout is not Layout.STATE_FIRST: return [None] n = len(route.codes or []) + if isinstance(question, Score): + if self.config.score_order_average == "off" or n < 2: + return [None] + if self.config.score_order_average == "reversed": + return [None, list(reversed(range(n)))] + return [None] + [[(j + r) % n for j in range(n)] for r in range(1, n)] + if not self.config.order_average or ( + isinstance(question, Noul) and route.reason != BINARY_NOUL + ): + return [None] return [None, list(reversed(range(n)))] if n >= 2 else [None] def _render( @@ -520,6 +530,7 @@ def load( compile: bool = False, max_label_options: int | None = None, skip_multi_token_codes: bool = True, + score_order_average: Literal["off", "reversed", "cyclic"] = "off", ) -> DecisionEngine: """Load a checkpoint -- a release directory, a training output or a Hub id -- into a ready `DecisionEngine`. With no checkpoint, serves `model_id` frozen. @@ -595,6 +606,7 @@ def load( prompt_style=prompt_style or "plain", max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, + score_order_average=score_order_average, ) engine = DecisionEngine(model, tokenizer, config, profile, mode_b_head=head) engine.checkpoint = resolved diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py new file mode 100644 index 0000000..5a06774 --- /dev/null +++ b/packages/lev/src/lev/presentation.py @@ -0,0 +1,281 @@ +"""Presentation checks: does an answer move with where an option is shown? + +The design of NandhaKishorM/laya#259, over `system_one` (ADR-029). Per question type +(Score and Choice), on any list of states, with no labels: + +- **identical**: every option carries the same text, so options differ only by + position and code. Metric: slot 0's log-probability minus the mean over the slots, + averaged over states and configurations. 0 is no position effect; below 0, slot 0 + is disfavoured. Choice keys must be unique, so they are numbered (`1`, `2`, ...) + and share one description, as Score levels share one text. +- **first_slot**: three real options in all 3! = 6 orders per state. Every option + sits in every slot exactly twice, so an order-free readout picks slot 0 in exactly + 1/3 of the decisions. +- **packed**: the probe asks its questions in as few `system_one` calls as fit + `MAX_SCORE_ROWS` (one, by default); this asks each question alone on a few states and + reports the largest probability difference, so what is measured is the presentation + and not the packing. + +Probabilities are whatever `system_one` returns: calibrated, unless the engine carries +an empty `CalibrationProfile`. Within one question, calibrated log-probabilities are the +raw scores divided by the bucket's temperature, so the identical metric shrinks by 1/T +and the first-slot rate does not change. The proposed gate, -0.20, is Laya's, set on +raw scores. +""" + +from __future__ import annotations + +import itertools +import json +import math +from collections.abc import Callable, Mapping, Sequence +from typing import Any + +KINDS = ("score", "choice") +IDENTICAL_KS = (3, 4, 5) +SLOT0_MIN = -0.20 +FIRST_SLOT_MIN = 0.15 +# Score rows per `system_one` call. The default probe is 12 rows off and 24 reversed, one call +# either way; cyclic reads a K-level question K times (42 rows), which filled a 32 GB GPU. +MAX_SCORE_ROWS = 24 + +# en follows Laya's presentation_checks.py; ja the same wording in Japanese. +TEXT: dict[str, dict[str, Any]] = { + "en": { + "score": { + "instructions": "How urgent is this request?", + "identical": ("moderate", "a request"), + "options": ("Not urgent", "Soon", "Work is blocked"), + }, + "choice": { + "instructions": "Which team should handle this message?", + "identical": ("a team", "a request"), + "options": { + "Billing": "payments, refunds, invoices", + "Technical": "bugs, outages, errors", + "Sales": "plans, contracts, quotes", + }, + }, + }, + "ja": { + "score": { + "instructions": "この依頼の緊急度は", + "identical": ("中程度", "依頼"), + "options": ("急がない", "早めに", "業務が止まっている"), + }, + "choice": { + "instructions": "この問い合わせはどの部署が担当すべきか", + "identical": ("部署", "依頼"), + "options": { + "請求": "支払い・返金・請求書", + "技術": "不具合・障害・エラー", + "営業": "料金プラン・契約・見積もり", + }, + }, + }, +} + +SystemOne = Callable[[Any, Mapping[str, dict]], Any] + + +def identical_question(kind: str, text: str, k: int, instructions: str) -> dict: + if kind == "score": + return {"type": "score", "instructions": instructions, "criteria": [text] * k} + return { + "type": "choice", + "instructions": instructions, + "criteria": {str(i + 1): text for i in range(k)}, + } + + +def probe_questions(lang: str = "en", kinds: Sequence[str] = KINDS) -> dict[str, dict]: + """Every probe question for one state, keyed `kind|identical|text|k` or + `kind|perm|012`. One `system_one` call answers them all.""" + questions: dict[str, dict] = {} + for kind in kinds: + spec = TEXT[lang][kind] + for text in spec["identical"]: + for k in IDENTICAL_KS: + questions[f"{kind}|identical|{text}|{k}"] = identical_question( + kind, text, k, spec["instructions"] + ) + options = list(spec["options"]) + for order in itertools.permutations(range(len(options))): + shown = [options[i] for i in order] + criteria = shown if kind == "score" else {key: spec["options"][key] for key in shown} + questions[f"{kind}|perm|{''.join(map(str, order))}"] = { + "type": kind, + "instructions": spec["instructions"], + "criteria": criteria, + } + return questions + + +def slot_probs(answer: Any, question: dict) -> list[float]: + """An answer's probabilities in the order the options were shown.""" + probs = answer.probabilities + if question["type"] == "score": + return [float(probs[i]) for i in range(len(question["criteria"]))] + return [float(probs[key]) for key in question["criteria"]] + + +def leave_one_out(per_state: Sequence[float]) -> list[float]: + n, total = len(per_state), sum(per_state) + loo = [(total - x) / (n - 1) for x in per_state] if n > 1 else list(per_state) + return [min(loo), max(loo)] + + +def score_rows(question: dict, score_order_average: str) -> int: + """Batch rows a Score question adds: one per order it is read in (`_orders`).""" + k = len(question["criteria"]) + return {"off": 1, "reversed": 2, "cyclic": k}[score_order_average] if k >= 2 else 1 + + +def call_groups( + questions: dict[str, dict], + split_checks: bool = False, + max_score_rows: int = MAX_SCORE_ROWS, + score_order_average: str = "off", +) -> list[dict[str, dict]]: + """The probe split into `system_one` calls. By default one call, cut only where the + Score rows would pass `max_score_rows`, which bounds memory under `cyclic`; with + `split_checks` the identical and permuted questions never share a call.""" + groups: list[dict[str, dict]] = [] + for check in ("identical", "perm") if split_checks else (None,): + current: dict[str, dict] = {} + rows = 0 + for qid, question in questions.items(): + if check is not None and qid.split("|")[1] != check: + continue + added = score_rows(question, score_order_average) if question["type"] == "score" else 0 + if current and rows + added > max_score_rows: + groups.append(current) + current, rows = {}, 0 + current[qid] = question + rows += added + if current: + groups.append(current) + return groups + + +def run( + system_one: SystemOne, + states: Sequence[Any], + lang: str = "en", + kinds: Sequence[str] = KINDS, + slot0_min: float = SLOT0_MIN, + split_checks: bool = False, + max_score_rows: int = MAX_SCORE_ROWS, + score_order_average: str = "off", +) -> dict[str, dict]: + """Both checks for each kind, from the `call_groups` calls per state (one by default).""" + questions = probe_questions(lang, kinds) + groups = call_groups(questions, split_checks, max_score_rows, score_order_average) + slot0: dict[str, list[float]] = {kind: [] for kind in kinds} + first: dict[str, list[float]] = {kind: [] for kind in kinds} + by_config: dict[str, dict[str, list[float]]] = {kind: {} for kind in kinds} + by_slot = {kind: [0] * len(TEXT[lang][kind]["options"]) for kind in kinds} + for state in states: + answers = {} + for group in groups: + answers.update(system_one(state, group).answers) + centred: dict[str, list[float]] = {kind: [] for kind in kinds} + firsts: dict[str, list[int]] = {kind: [] for kind in kinds} + for qid, question in questions.items(): + kind, check, *rest = qid.split("|") + p = slot_probs(answers[qid], question) + if check == "identical": + logp = [math.log(max(x, 1e-12)) for x in p] + value = logp[0] - sum(logp) / len(logp) + centred[kind].append(value) + by_config[kind].setdefault("|".join(rest), []).append(value) + else: + slot = max(range(len(p)), key=p.__getitem__) + firsts[kind].append(int(slot == 0)) + by_slot[kind][slot] += 1 + for kind in kinds: + slot0[kind].append(sum(centred[kind]) / len(centred[kind])) + first[kind].append(sum(firsts[kind]) / len(firsts[kind])) + report: dict[str, dict] = {} + for kind in kinds: + identical = sum(slot0[kind]) / len(slot0[kind]) + rate = sum(first[kind]) / len(first[kind]) + report[kind] = { + "identical": { + "metric": identical, + "leave_one_out": leave_one_out(slot0[kind]), + "gate": slot0_min, + "passed": identical >= slot0_min, + "by_config": {c: sum(v) / len(v) for c, v in by_config[kind].items()}, + }, + "first_slot": { + "metric": rate, + "leave_one_out": leave_one_out(first[kind]), + "gate": FIRST_SLOT_MIN, + "passed": rate >= FIRST_SLOT_MIN, + "decisions": len(states) * math.factorial(len(TEXT[lang][kind]["options"])), + "argmax_by_slot": by_slot[kind], + }, + } + return report + + +def packed_consistency( + system_one: SystemOne, + states: Sequence[Any], + lang: str = "en", + kinds: Sequence[str] = KINDS, + split_checks: bool = False, + max_score_rows: int = MAX_SCORE_ROWS, + score_order_average: str = "off", +) -> float: + """Largest |p| difference between the probe as `run` asks it and each question alone.""" + questions = probe_questions(lang, kinds) + groups = call_groups(questions, split_checks, max_score_rows, score_order_average) + worst = 0.0 + for state in states: + packed = {} + for group in groups: + packed.update(system_one(state, group).answers) + for qid, question in questions.items(): + alone = system_one(state, {qid: question}).answers[qid] + for a, b in zip( + slot_probs(packed[qid], question), slot_probs(alone, question), strict=True + ): + worst = max(worst, abs(a - b)) + return worst + + +def drift(report: dict, snapshot: dict, tolerance: float) -> list[str]: + """Every metric that moved more than `tolerance` from the committed report.""" + moved = [] + for kind, checks in snapshot.items(): + for check, committed in checks.items(): + now = report.get(kind, {}).get(check, {}).get("metric") + if now is None: + moved.append(f"{kind}.{check}: missing from this run") + elif abs(now - committed["metric"]) > tolerance: + moved.append(f"{kind}.{check}: {committed['metric']:+.3f} -> {now:+.3f}") + return moved + + +def to_markdown(report: dict) -> str: + lines = [ + "| kind | identical (slot 0 - mean) | leave-one-out | first-slot rate | leave-one-out |", + "|---|---|---|---|---|", + ] + for kind, r in report.items(): + ident, first = r["identical"], r["first_slot"] + lines.append( + f"| {kind} | {ident['metric']:+.3f} {'PASS' if ident['passed'] else 'FAIL'} " + f"| {ident['leave_one_out'][0]:+.3f} .. {ident['leave_one_out'][1]:+.3f} " + f"| {first['metric']:.3f} {'PASS' if first['passed'] else 'FAIL'} " + f"| {first['leave_one_out'][0]:.3f} .. {first['leave_one_out'][1]:.3f} |" + ) + return "\n".join(lines) + + +def read_states(path: str) -> list[Any]: + """`state` from each line of a JSONL file (bench_en.jsonl, bench_ja.jsonl or your own).""" + with open(path, encoding="utf-8") as fh: + return [json.loads(line)["state"] for line in fh if line.strip()] diff --git a/packages/lev/src/lev/server.py b/packages/lev/src/lev/server.py index e62ccb4..0ce5dad 100644 --- a/packages/lev/src/lev/server.py +++ b/packages/lev/src/lev/server.py @@ -30,6 +30,7 @@ def create_app( max_pending: int = 64, max_batch_tokens: int = 16384, timeout: float = 30.0, + score_order_average: Literal["off", "reversed", "cyclic"] = "off", ) -> Any: from fastapi import FastAPI, HTTPException, Response from starlette.concurrency import run_in_threadpool @@ -51,6 +52,7 @@ def _load() -> None: compile=compile, max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, + score_order_average=score_order_average, ) state["batcher"] = Batcher( engine, max_pending=max_pending, max_batch_tokens=max_batch_tokens, timeout=timeout @@ -73,6 +75,7 @@ async def health() -> dict: "noul_readout": config.noul_readout, "max_label_options": config.max_label_options, "order_average": config.order_average, + "score_order_average": config.score_order_average, "prefix_mode": config.prefix_mode, "compiled": config.compile, "prompt_style": config.prompt_style, diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py new file mode 100644 index 0000000..9b5638f --- /dev/null +++ b/packages/lev/tests/test_presentation.py @@ -0,0 +1,289 @@ +"""Presentation checks (ADR-029) and opt-in Score order averaging. + +The checks run against a fake `system_one` that validates every request with +lev's own `SystemOneRequest` and answers with lev's answer types, so a probe lev +would reject, or an answer shape the checks misread, fails here without weights. +""" + +from __future__ import annotations + +import json +import math + +import pytest +from lev import ( + ChoiceAnswer, + Score, + ScoreAnswer, + SystemOneRequest, + SystemOneResponse, + Usage, +) +from lev.model import DecisionEngine, EngineConfig, average_orders +from lev.presentation import ( + IDENTICAL_KS, + KINDS, + SLOT0_MIN, + TEXT, + drift, + packed_consistency, + probe_questions, + read_states, + run, + to_markdown, +) +from lev.router import route +from lev.types import Choice + + +def softmax(z: list[float]) -> list[float]: + m = max(z) + e = [math.exp(v - m) for v in z] + return [v / sum(e) for v in e] + + +class FakeEngine: + """logit = content[option text] + slot_bias[slot]. `packing` adds a term that + depends on how many questions share the call, which a packed readout must not.""" + + def __init__(self, slot0: float = 0.0, content: dict | None = None, packing: float = 0.0): + self.slot0, self.content, self.packing, self.calls = slot0, content or {}, packing, 0 + + def system_one(self, state, questions): + request = SystemOneRequest(state=state, questions=questions) + self.calls += 1 + answers = {} + for name, q in request.questions.items(): + texts = list(q.criteria) + z = [ + self.content.get(t, 0.0) + + (self.slot0 if i == 0 else 0.0) + + self.packing * len(request.questions) * i + for i, t in enumerate(texts) + ] + p = softmax(z) + if q.type == "score": + answers[name] = ScoreAnswer( + score=0.0, + probabilities=dict(enumerate(p)), + legend=dict(enumerate(q.criteria)), + confidence=max(p), + ) + else: + keys = list(q.criteria) + answers[name] = ChoiceAnswer( + choice=keys[p.index(max(p))], + probabilities=dict(zip(keys, p, strict=True)), + confidence=max(p), + ) + return SystemOneResponse(model="fake", answers=answers, usage=Usage(input_tokens=1)) + + +class TestProbeQuestions: + @pytest.mark.parametrize("lang", sorted(TEXT)) + def test_every_probe_is_a_valid_request(self, lang): + questions = probe_questions(lang) + assert SystemOneRequest(state="s", questions=questions) + per_kind = 2 * len(IDENTICAL_KS) + 6 + assert len(questions) == per_kind * len(KINDS) + + @pytest.mark.parametrize("lang", sorted(TEXT)) + def test_identical_options_differ_only_by_position(self, lang): + for qid, q in probe_questions(lang).items(): + if "|identical|" not in qid: + continue + texts = q["criteria"] if q["type"] == "score" else list(q["criteria"].values()) + assert len(set(texts)) == 1 + if q["type"] == "choice": + assert list(q["criteria"]) == [str(i + 1) for i in range(len(q["criteria"]))] + + @pytest.mark.parametrize("lang", sorted(TEXT)) + def test_every_option_sits_in_every_slot_twice(self, lang): + for kind in KINDS: + perms = [ + list(q["criteria"]) + for qid, q in probe_questions(lang, [kind]).items() + if "|perm|" in qid + ] + options = list(TEXT[lang][kind]["options"]) + for slot in range(3): + assert sorted(p[slot] for p in perms) == sorted(options * 2) + + +class TestChecks: + def test_a_flat_readout_sits_at_zero_and_one_third(self): + content = {"Soon": 3.0, "Technical": 3.0} + report = run(FakeEngine(content=content).system_one, ["a", "b"]) + for kind in KINDS: + assert report[kind]["identical"]["metric"] == pytest.approx(0.0) + assert report[kind]["identical"]["passed"] + assert report[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) + + def test_a_planted_slot_zero_penalty_is_measured_exactly(self): + report = run(FakeEngine(slot0=-2.0).system_one, ["a", "b", "c"]) + # centred slot 0 = -2 - (-2/K), averaged over K = 3, 4, 5 and both texts + expected = sum(-2.0 * (1 - 1 / k) for k in IDENTICAL_KS) / len(IDENTICAL_KS) + for kind in KINDS: + assert report[kind]["identical"]["metric"] == pytest.approx(expected) + assert not report[kind]["identical"]["passed"] + assert report[kind]["first_slot"]["argmax_by_slot"][0] == 0 + assert report[kind]["first_slot"]["decisions"] == 18 + + def test_one_call_per_state(self): + engine = FakeEngine() + run(engine.system_one, ["a", "b", "c"]) + assert engine.calls == 3 + + def test_the_gate_is_the_proposal_and_can_be_moved(self): + engine = FakeEngine(slot0=-0.3) + assert not run(engine.system_one, ["a"])["score"]["identical"]["passed"] + assert run(engine.system_one, ["a"], slot0_min=-1.0)["score"]["identical"]["passed"] + assert SLOT0_MIN == -0.20 + + +class TestPackedConsistency: + def test_an_isolated_readout_agrees_with_itself_alone(self): + assert packed_consistency(FakeEngine(slot0=-1.0).system_one, ["a"]) == pytest.approx(0.0) + + def test_a_readout_that_depends_on_packing_is_caught(self): + assert packed_consistency(FakeEngine(packing=0.01).system_one, ["a"]) > 0.01 + + +class TestReport: + def test_drift_flags_only_what_moved_past_the_tolerance(self): + now = run(FakeEngine(slot0=-2.0).system_one, ["a"]) + committed = json.loads(json.dumps(now)) + assert drift(now, committed, 0.05) == [] + committed["score"]["identical"]["metric"] += 0.2 + assert drift(now, committed, 0.05) == [ + f"score.identical: {committed['score']['identical']['metric']:+.3f}" + f" -> {now['score']['identical']['metric']:+.3f}" + ] + del now["choice"] + assert "choice.identical: missing from this run" in drift(now, committed, 0.05) + + def test_markdown_has_a_row_per_kind(self): + text = to_markdown(run(FakeEngine().system_one, ["a"])) + assert text.count("\n") == 1 + len(KINDS) + + def test_states_are_read_from_jsonl(self, tmp_path): + path = tmp_path / "s.jsonl" + path.write_text('{"state": "one"}\n\n{"state": "two", "x": 1}\n', "utf-8") + assert read_states(str(path)) == ["one", "two"] + + def test_the_cli_is_registered(self): + from lev.cli import main + + with pytest.raises(SystemExit) as exc: + main(["presentation-checks", "--help"]) + assert exc.value.code == 0 + + +class TestScoreOrderAverage: + """Off by default: a Score keeps its level order unless the config opts in.""" + + def orders(self, question, tokenizer, **config): + engine = DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) + return engine._orders(question, route(question, tokenizer)) + + def test_off_by_default(self, rich_tokenizer): + assert EngineConfig().score_order_average == "off" + assert self.orders(Score(criteria=["low", "mid", "high"]), rich_tokenizer) == [None] + + def test_reversed_is_two_rows(self, rich_tokenizer): + q = Score(criteria=["low", "mid", "high"]) + assert self.orders(q, rich_tokenizer, score_order_average="reversed") == [None, [2, 1, 0]] + + def test_cyclic_is_every_rotation(self, rich_tokenizer): + q = Score(criteria=["low", "mid", "high"]) + assert self.orders(q, rich_tokenizer, score_order_average="cyclic") == [ + None, + [1, 2, 0], + [2, 0, 1], + ] + + def test_independent_of_the_choice_switch(self, rich_tokenizer): + q = Score(criteria=["low", "high"]) + assert self.orders( + q, rich_tokenizer, score_order_average="reversed", order_average=False + ) == [None, [1, 0]] + c = Choice(criteria={"a": None, "b": None, "c": None}) + for mode in ("off", "reversed", "cyclic"): + assert self.orders(c, rich_tokenizer, score_order_average=mode) == [None, [2, 1, 0]] + + def test_schema_first_never_doubles_the_prefix(self, rich_tokenizer): + from lev.prompt import Layout + + q = Score(criteria=["low", "high"]) + assert self.orders( + q, rich_tokenizer, score_order_average="cyclic", layout=Layout.SCHEMA_FIRST + ) == [None] + + def test_cyclic_averaging_cancels_a_slot_bias_on_equal_content(self): + """Each level sits in each slot once, so a pure position bias averages out.""" + k = 4 + orders = [None] + [[(j + r) % k for j in range(k)] for r in range(1, k)] + biased = softmax([2.0, 0.0, 0.0, 0.0]) # slot 0 favoured, content equal + assert average_orders([biased] * k, orders) == pytest.approx([1 / k] * k) + + +class TestCallGroups: + """How the probe is split into calls: one by default, bounded Score rows under cyclic.""" + + def rows(self, group, mode): + from lev.presentation import score_rows + + return sum(score_rows(q, mode) for q in group.values() if q["type"] == "score") + + def test_off_and_reversed_stay_one_call(self): + from lev.presentation import call_groups + + questions = probe_questions("en", ["score"]) + assert len(call_groups(questions)) == 1 + assert self.rows(questions, "reversed") == 24 + assert len(call_groups(questions, score_order_average="reversed")) == 1 + + def test_cyclic_is_cut_at_the_row_limit_and_asks_everything_once(self): + from lev.presentation import call_groups + + questions = probe_questions("en") + assert self.rows(questions, "cyclic") == 42 + groups = call_groups(questions, score_order_average="cyclic") + assert len(groups) > 1 + assert all(self.rows(g, "cyclic") <= 24 for g in groups) + asked = [qid for g in groups for qid in g] + assert sorted(asked) == sorted(questions) + + def test_split_checks_never_mixes_the_two_checks(self): + from lev.presentation import call_groups + + for group in call_groups(probe_questions("ja"), split_checks=True): + assert len({qid.split("|")[1] for qid in group}) == 1 + + def test_the_split_does_not_change_an_isolated_readout(self): + engine = FakeEngine(slot0=-1.0, content={"Soon": 1.0}) + one = run(engine.system_one, ["a", "b"]) + split = run( + engine.system_one, + ["a", "b"], + split_checks=True, + max_score_rows=5, + score_order_average="cyclic", + ) + assert split == one + assert packed_consistency(engine.system_one, ["a"], split_checks=True) == pytest.approx(0.0) + + +class TestCommittedReport: + """`data/presentation-checks.json` is what `--compare` reads in CI.""" + + def test_it_parses_and_carries_every_metric(self): + from pathlib import Path + + path = Path(__file__).resolve().parents[3] / "data" / "presentation-checks.json" + committed = json.loads(path.read_text("utf-8")) + assert committed["score_order_average"] == "off" and committed["n_states"] == 290 + for kind in KINDS: + for check in ("identical", "first_slot"): + assert isinstance(committed["checks"][kind][check]["metric"], float) + assert drift(committed["checks"], committed["checks"], 0.0) == [] From 582c93c5b6d726df598dd6592d3966fbbd82a208 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Tue, 29 Sep 2026 17:47:56 +0900 Subject: [PATCH 03/39] ADR-029 evidence: before/after on bench_en, bench_ja as reference; committed presentation report Co-Authored-By: Claude Opus 5.5 (1M context) --- data/adr-029-summary.json | 134 ++++++++++++++++++++++++++++++++++ data/presentation-checks.json | 86 ++++++++++++++++++++++ docs/DECISIONS.md | 34 ++++++++- 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 data/adr-029-summary.json create mode 100644 data/presentation-checks.json diff --git a/data/adr-029-summary.json b/data/adr-029-summary.json new file mode 100644 index 0000000..58c6e72 --- /dev/null +++ b/data/adr-029-summary.json @@ -0,0 +1,134 @@ +{ + "about": "Summary of the ADR-029 runs: the numbers behind its tables. interfaze-ai/lev (HF f8ef711), bf16, one RTX 5090, 2026-09-29. Raw per-run reports are not committed and are available on request.", + "benches": { + "bench_en": "sokudan data/bench_en.jsonl, 290 states (English)", + "bench_ja": "sokudan data/bench_ja.jsonl, 300 states (Japanese, outside Lev's target language; reference only)" + }, + "score_presentation": { + "bench_en": { + "off": { + "identical_calibrated": -0.3321, + "identical_raw": -0.931, + "first_slot": 0.2695, + "first_slot_raw": 0.2695 + }, + "reversed": { + "identical_calibrated": -0.0101, + "identical_raw": 0.0878, + "first_slot": 0.3207, + "first_slot_raw": 0.3207 + }, + "cyclic": { + "identical_calibrated": -0.0161, + "identical_raw": -0.0365, + "first_slot": 0.3126, + "first_slot_raw": 0.3121 + } + }, + "bench_ja": { + "off": { + "identical_calibrated": -0.5184, + "identical_raw": -1.4532, + "first_slot": 0.24, + "first_slot_raw": 0.24 + }, + "reversed": { + "identical_calibrated": -0.0586, + "identical_raw": 0.038, + "first_slot": 0.315, + "first_slot_raw": 0.3139 + }, + "cyclic": { + "identical_calibrated": -0.0558, + "identical_raw": -0.1313, + "first_slot": 0.3017, + "first_slot_raw": 0.3006 + } + } + }, + "choice_presentation_off": { + "bench_en": { + "identical_calibrated": -0.1001, + "identical_raw": -0.1597, + "first_slot": 0.3333 + }, + "bench_ja": { + "identical_calibrated": -0.0547, + "identical_raw": -0.0362, + "first_slot": 0.3306 + } + }, + "bench_accuracy": { + "bench_en": { + "off": { + "score_acc": 0.5828, + "score_rps": 0.1504, + "choice_acc": 0.9172, + "noul_acc": 0.9379, + "noul_auroc": 0.9778, + "ms_per_request": 164.6 + }, + "reversed": { + "score_acc": 0.6517, + "score_rps": 0.1275, + "choice_acc": 0.9172, + "noul_acc": 0.9379, + "noul_auroc": 0.978, + "ms_per_request": 184.0 + }, + "cyclic": { + "score_acc": 0.6414, + "score_rps": 0.1249, + "choice_acc": 0.9172, + "noul_acc": 0.9379, + "noul_auroc": 0.9784, + "ms_per_request": 215.4 + } + }, + "bench_ja": { + "off": { + "score_acc": 0.6433, + "score_rps": 0.1384, + "choice_acc": 0.8867, + "noul_acc": 0.8167, + "noul_auroc": 0.889, + "ms_per_request": 150.9 + }, + "reversed": { + "score_acc": 0.73, + "score_rps": 0.1079, + "choice_acc": 0.8867, + "noul_acc": 0.8133, + "noul_auroc": 0.8877, + "ms_per_request": 171.4 + }, + "cyclic": { + "score_acc": 0.7167, + "score_rps": 0.108, + "choice_acc": 0.8867, + "noul_acc": 0.8133, + "noul_auroc": 0.8876, + "ms_per_request": 199.9 + } + } + }, + "noul_alone_bench_ja": { + "requests": 300, + "identical_across_modes": true + }, + "off_vs_main_cf104b6": { + "bench_en": { + "responses": 40, + "identical": true + }, + "bench_ja": { + "responses": 40, + "identical": true + } + }, + "issue_1_reproduced": { + "identical_calibrated": -0.3321, + "identical_raw": -0.931, + "first_slot": 0.2695 + } +} diff --git a/data/presentation-checks.json b/data/presentation-checks.json new file mode 100644 index 0000000..ebfecbc --- /dev/null +++ b/data/presentation-checks.json @@ -0,0 +1,86 @@ +{ + "about": "Committed report for `lev presentation-checks --compare` (ADR-029). One run: interfaze-ai/lev (HF f8ef711), bf16, one RTX 5090, the shipped calibration, score_order_average off, kinds score and choice, lang en, 2026-09-29.", + "checkpoint": "interfaze-ai/lev", + "states": "sokudan bench_en.jsonl (github.com/hiroki-abe-58/sokudan, data/bench_en.jsonl, CC BY 4.0), 290 states", + "n_states": 290, + "lang": "en", + "raw": false, + "kinds": [ + "score", + "choice" + ], + "score_order_average": "off", + "split_checks": false, + "max_score_rows": 24, + "packed_max_abs_diff": 0.0207, + "checks": { + "score": { + "identical": { + "metric": -0.3323, + "leave_one_out": [ + -0.3362, + -0.3298 + ], + "gate": -0.2, + "passed": false, + "by_config": { + "moderate|3": -0.1182, + "moderate|4": -0.2365, + "moderate|5": -0.3193, + "a request|3": -0.3249, + "a request|4": -0.4617, + "a request|5": -0.5332 + } + }, + "first_slot": { + "metric": 0.2713, + "leave_one_out": [ + 0.2699, + 0.2722 + ], + "gate": 0.15, + "passed": true, + "decisions": 1740, + "argmax_by_slot": [ + 472, + 598, + 670 + ] + } + }, + "choice": { + "identical": { + "metric": -0.1006, + "leave_one_out": [ + -0.1024, + -0.0991 + ], + "gate": -0.2, + "passed": true, + "by_config": { + "a team|3": -0.0569, + "a team|4": -0.1228, + "a team|5": -0.2804, + "a request|3": 0.0892, + "a request|4": -0.0295, + "a request|5": -0.2033 + } + }, + "first_slot": { + "metric": 0.3333, + "leave_one_out": [ + 0.3328, + 0.3339 + ], + "gate": 0.15, + "passed": true, + "decisions": 1740, + "argmax_by_slot": [ + 580, + 581, + 579 + ] + } + } + } +} diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 37506df..b6e498c 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -601,7 +601,39 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode Every result is reported whichever way it goes, including accuracy that does not improve. -**Evidence.** Pending the runs above. +**Evidence.** Run 2026-09-29 on `interfaze-ai/lev` (HF f8ef711), bf16, one RTX 5090. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json), and the raw per-run reports are available on request. The committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. + +Issue #1 reproduced with averaging off (Score probe alone, 12 questions per call): identical control -0.332 calibrated / -0.931 raw, first-slot rate 0.270. With averaging off, every answer on 20 items of each bench, the probe included, is identical to the current code. + +Score, identical control (slot 0 minus the mean; gate -0.20 raw) and first-slot rate (1/3 is order-free): + +```text + bench_en (290) bench_ja (300, reference) + calibrated raw first slot calibrated raw first slot + off -0.332 -0.931 0.270 -0.518 -1.453 0.240 + reversed -0.010 +0.088 0.321 -0.059 +0.038 0.315 + cyclic -0.016 -0.037 0.312 -0.056 -0.131 0.301 +``` + +Choice, which is already read in two orders, with Score averaging off: identical control -0.100 / -0.160 (en) and -0.055 / -0.036 (ja), first-slot rate 0.333 and 0.331. + +The benches' three questions per request (4-way Choice, 3-level Score, Noul), shipped calibration: + +```text + Score acc Score RPS Choice acc Noul acc Noul AUROC ms / request + en off 0.583 0.150 0.917 0.938 0.9778 164.6 + reversed 0.652 0.128 0.917 0.938 0.9780 184.0 (1.12x) + cyclic 0.641 0.125 0.917 0.938 0.9784 215.4 (1.31x) + ja off (ref.) 0.643 0.138 0.887 0.817 0.8890 150.9 + reversed 0.730 0.108 0.887 0.813 0.8877 171.4 (1.14x) + cyclic 0.717 0.108 0.887 0.813 0.8876 199.9 (1.32x) +``` + +Choice does not move. Noul moves by one item on bench_ja, and asked alone it is identical under all three modes on all 300 items: the change comes from the batch the extra Score rows make (bf16), not from the Noul readout. + +Two caveats. Asking the probe's questions together or one at a time differs by up to |Δp| 0.18 (raw, bench_ja, off) on the three states checked per run, so a metric is tied to how many questions share a call; `lev presentation-checks` fixes that at one call of at most 24 Score rows. And `cyclic` needs that cap: 42 Score rows per call exhausted a 32 GB card. Even capped, PyTorch's reserved memory went past the card (44-49 GiB for `cyclic`, 62 GiB for the default probe of both kinds), which Windows backs with shared system memory. + +**Reading, for the decision.** `reversed` removes most of the slot-0 deficit and lifts Score accuracy by 6.9 points on bench_en (8.7 on the Japanese reference bench) at 1.12-1.14x the time. `cyclic` is no better than `reversed` on either bench and costs 1.31-1.32x. Neither was tested on helpsteer2, the case that kept Score out of averaging in ADR-020, and both benches are one family of synthetic support messages. The proposal keeps the default off and leaves the choice between (a) and (b) to the maintainer. --- From b4572f454b460b1076eba3664213eb84f5b92db5 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Tue, 29 Sep 2026 18:05:12 +0900 Subject: [PATCH 04/39] presentation-checks --compare refuses a report measured under other settings (exit 2) Co-Authored-By: Claude Opus 5.5 (1M context) --- data/presentation-checks.json | 2 + packages/lev/src/lev/cli.py | 49 ++++++++++++++++++++----- packages/lev/src/lev/presentation.py | 23 ++++++++++++ packages/lev/tests/test_presentation.py | 46 +++++++++++++++++++++++ 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/data/presentation-checks.json b/data/presentation-checks.json index ebfecbc..aa3f4b3 100644 --- a/data/presentation-checks.json +++ b/data/presentation-checks.json @@ -12,6 +12,8 @@ "score_order_average": "off", "split_checks": false, "max_score_rows": 24, + "checkpoint_revision": "f8ef71157ec06a7d3b6435bc0756f9d735c33748", + "dtype": "torch.bfloat16", "packed_max_abs_diff": 0.0207, "checks": { "score": { diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 2710bc8..0cbc824 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -232,9 +232,24 @@ def _cuda(): return torch.cuda if torch.cuda.is_available() else None +def _snapshot_revision(checkpoint) -> str | None: + """The Hub commit a checkpoint was loaded from: the `snapshots/` directory name.""" + parts = Path(checkpoint).parts if checkpoint else () + return parts[parts.index("snapshots") + 1] if "snapshots" in parts[:-1] else None + + +def _weights_dtype(engine) -> str | None: + model = getattr(engine, "_eager_model", None) or getattr(engine, "model", None) + try: + return str(next(model.parameters()).dtype) + except (AttributeError, StopIteration, TypeError): + return None + + def cmd_presentation_checks(args: argparse.Namespace) -> None: - """Label-free presentation checks (ADR-029). Exits non-zero when a metric drifts - from `--compare` beyond `--tolerance`, or, with `--enforce-gate`, below a gate.""" + """Label-free presentation checks (ADR-029). With `--compare`, exits 2 when the run's + settings differ from the report's, and 1 when a metric drifts beyond `--tolerance`; + `--enforce-gate` also fails a check below its gate.""" import time from . import presentation @@ -257,6 +272,25 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: "max_score_rows": args.max_score_rows, "score_order_average": args.score_order_average, } + settings = { + "n_states": len(states), + "lang": args.lang, + "raw": args.raw, + "kinds": kinds, + **grouping, + "checkpoint_revision": _snapshot_revision(engine.checkpoint), + "dtype": _weights_dtype(engine), + } + saved = json.loads(Path(args.compare).read_text("utf-8")) if args.compare else None + if saved is not None: + # Metrics move with the order mode, the batching and the weights; compare like with like. + differ = presentation.settings_mismatch(saved, settings) + if differ: + print( + "presentation settings differ from the committed report: " + "; ".join(differ), + file=sys.stderr, + ) + sys.exit(2) cuda = _cuda() if cuda: cuda.empty_cache() @@ -284,11 +318,7 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: payload = { "checkpoint": args.checkpoint, "states": args.states, - "n_states": len(states), - "lang": args.lang, - "raw": args.raw, - "kinds": kinds, - **grouping, + **settings, "seconds": round(seconds, 1), "peak_vram": peak, "packed_max_abs_diff": packed, @@ -298,9 +328,8 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: text = json.dumps(payload, indent=1, ensure_ascii=False) + "\n" Path(args.out).write_text(text, "utf-8") failures = [] - if args.compare: - committed = json.loads(Path(args.compare).read_text("utf-8"))["checks"] - failures += presentation.drift(report, committed, args.tolerance) + if saved is not None: + failures += presentation.drift(report, saved["checks"], args.tolerance) if args.enforce_gate: failures += [ f"{kind}.{check}: {r[check]['metric']:+.3f} below {r[check]['gate']:+.2f}" diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py index 5a06774..d8c94e6 100644 --- a/packages/lev/src/lev/presentation.py +++ b/packages/lev/src/lev/presentation.py @@ -246,6 +246,29 @@ def packed_consistency( return worst +SETTINGS = ( + "n_states", + "lang", + "raw", + "kinds", + "score_order_average", + "split_checks", + "max_score_rows", + "checkpoint_revision", + "dtype", +) + + +def settings_mismatch(saved: dict, run: dict) -> list[str]: + """Every recorded setting of `saved` that this run does not share, as + ` (report: X, run: Y)`. A setting the report never recorded is not checked.""" + return [ + f"{key} (report: {saved[key]!r}, run: {run.get(key)!r})" + for key in SETTINGS + if key in saved and saved[key] != run.get(key) + ] + + def drift(report: dict, snapshot: dict, tolerance: float) -> list[str]: """Every metric that moved more than `tolerance` from the committed report.""" moved = [] diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 9b5638f..4afa056 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -48,6 +48,7 @@ class FakeEngine: def __init__(self, slot0: float = 0.0, content: dict | None = None, packing: float = 0.0): self.slot0, self.content, self.packing, self.calls = slot0, content or {}, packing, 0 + self.checkpoint = None # a DecisionEngine's resolved checkpoint; None for a frozen base def system_one(self, state, questions): request = SystemOneRequest(state=state, questions=questions) @@ -287,3 +288,48 @@ def test_it_parses_and_carries_every_metric(self): for check in ("identical", "first_slot"): assert isinstance(committed["checks"][kind][check]["metric"], float) assert drift(committed["checks"], committed["checks"], 0.0) == [] + + +class TestCompareGuardsItsSettings: + """`--compare` compares like with like: settings first (exit 2), then metrics (exit 1).""" + + def cli(self, monkeypatch, tmp_path, engine, *extra): + from lev.cli import main + + monkeypatch.setattr("lev.model.load", lambda *a, **k: engine) + monkeypatch.setattr("lev.cli._cuda", lambda: None) + states = tmp_path / "states.jsonl" + states.write_text('{"state": "a"}\n{"state": "b"}\n', "utf-8") + main(["presentation-checks", str(states), "--packed", "0", *extra]) + + def committed(self, monkeypatch, tmp_path, engine) -> dict: + out = tmp_path / "report.json" + self.cli(monkeypatch, tmp_path, engine, "--out", str(out)) + return json.loads(out.read_text("utf-8")) + + def test_matching_settings_are_compared_metric_by_metric(self, monkeypatch, tmp_path): + engine = FakeEngine(slot0=-1.0) + saved = self.committed(monkeypatch, tmp_path, engine) + assert saved["score_order_average"] == "off" and saved["max_score_rows"] == 24 + saved["checks"]["score"]["identical"]["metric"] += 0.5 + path = tmp_path / "committed.json" + path.write_text(json.dumps(saved), "utf-8") + with pytest.raises(SystemExit) as exc: + self.cli(monkeypatch, tmp_path, engine, "--compare", str(path)) + assert "score.identical" in str(exc.value.code) + + def test_different_settings_are_refused_before_any_run(self, monkeypatch, tmp_path, capsys): + engine = FakeEngine(slot0=-1.0) + saved = self.committed(monkeypatch, tmp_path, engine) + saved["score_order_average"] = "reversed" + path = tmp_path / "committed.json" + path.write_text(json.dumps(saved), "utf-8") + calls = engine.calls + with pytest.raises(SystemExit) as exc: + self.cli(monkeypatch, tmp_path, engine, "--compare", str(path)) + assert exc.value.code == 2 + assert engine.calls == calls + assert ( + "presentation settings differ from the committed report: " + "score_order_average (report: 'reversed', run: 'off')" + ) in capsys.readouterr().err From 4c27d72e7aa37ea703df59a3c0f0a491b1f94cbe Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Sun, 4 Oct 2026 23:35:13 +0900 Subject: [PATCH 05/39] Address review: one-read identical control, engine-counted rows and a request row limit Presentation checks (ADR-029): - The identical-option control reads every question once (order_average=False): averaged orders cancel it by construction (cyclic) or hide the middle slots (reversed), so it measures the bias averaging has to remove. - Choice control keys are unordered shapes, and every assignment of keys to slots is read, so a key's own pull cancels. - First-slot rate: a tie gives each of its m slots 1/m. The report adds `consistent`, the states whose six orders all give one answer. - Calls are cut by the engine's own row count (DecisionEngine.question_rows), for Choice too; --max-rows replaces --max-score-rows and --split-checks. - packed_consistency reuses the answers the run computed. - --compare checks the model-free settings before the load, and only revision and dtype after it. Engine: - order_average=False reads every question once, Score included. - question_rows: the rows each question adds, from the same _orders prepare renders. - max_request_rows (default 32, about the batcher's 16384-token budget at bench-length rows): prepare refuses a larger request with a ValueError (HTTP 422) before any GPU work; `lev serve --max-request-rows`, /health reports it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- packages/lev/src/lev/cli.py | 85 ++--- packages/lev/src/lev/model.py | 36 ++- packages/lev/src/lev/presentation.py | 296 +++++++++-------- packages/lev/src/lev/server.py | 5 +- packages/lev/tests/test_presentation.py | 401 +++++++++++++++++------- 5 files changed, 535 insertions(+), 288 deletions(-) diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 0cbc824..9a3ff09 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -217,6 +217,11 @@ def cmd_serve(args: argparse.Namespace) -> None: max_pending=args.max_pending, max_batch_tokens=args.max_batch_tokens, score_order_average=args.score_order_average, + **( + {"max_request_rows": args.max_request_rows} + if args.max_request_rows is not None + else {} + ), ), host=args.host, port=args.port, @@ -254,54 +259,44 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: from . import presentation from .calibrate import CalibrationProfile - from .model import load + from .model import MAX_REQUEST_ROWS, load states = presentation.read_states(args.states)[: args.limit] + kinds = [k.strip() for k in args.kinds.split(",") if k.strip()] + max_rows = args.max_rows or MAX_REQUEST_ROWS + settings = { + "n_states": len(states), + "lang": args.lang, + "raw": args.raw, + "kinds": kinds, + "score_order_average": args.score_order_average, + "max_rows": max_rows, + } + saved = json.loads(Path(args.compare).read_text("utf-8")) if args.compare else None + _refuse_other_settings(saved, settings, presentation.PRE_LOAD) engine = load( args.checkpoint, model_id=args.model, cache_dir=args.model_cache, calibration=args.calibration, score_order_average=args.score_order_average, + max_request_rows=max(max_rows, MAX_REQUEST_ROWS), ) if args.raw: engine.calibration = CalibrationProfile() - kinds = [k.strip() for k in args.kinds.split(",") if k.strip()] - grouping = { - "split_checks": args.split_checks, - "max_score_rows": args.max_score_rows, - "score_order_average": args.score_order_average, - } - settings = { - "n_states": len(states), - "lang": args.lang, - "raw": args.raw, - "kinds": kinds, - **grouping, - "checkpoint_revision": _snapshot_revision(engine.checkpoint), - "dtype": _weights_dtype(engine), - } - saved = json.loads(Path(args.compare).read_text("utf-8")) if args.compare else None - if saved is not None: - # Metrics move with the order mode, the batching and the weights; compare like with like. - differ = presentation.settings_mismatch(saved, settings) - if differ: - print( - "presentation settings differ from the committed report: " + "; ".join(differ), - file=sys.stderr, - ) - sys.exit(2) + settings["checkpoint_revision"] = _snapshot_revision(engine.checkpoint) + settings["dtype"] = _weights_dtype(engine) + _refuse_other_settings(saved, settings, presentation.POST_LOAD) cuda = _cuda() if cuda: cuda.empty_cache() cuda.reset_peak_memory_stats() started = time.perf_counter() - report = presentation.run( - engine.system_one, states, args.lang, kinds, args.slot0_min, **grouping - ) + answers = presentation.ask(engine, states, args.lang, kinds, max_rows) seconds = time.perf_counter() - started + report = presentation.report(answers, args.lang, kinds, args.slot0_min) packed = presentation.packed_consistency( - engine.system_one, states[: args.packed], args.lang, kinds, **grouping + engine, states[: args.packed], answers, args.lang, kinds ) peak = ( { @@ -341,6 +336,19 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: sys.exit("presentation checks failed:\n " + "\n ".join(failures)) +def _refuse_other_settings(saved: dict | None, settings: dict, keys) -> None: + """Metrics move with the order mode, the batching and the weights; compare like with like.""" + from .presentation import settings_mismatch + + differ = settings_mismatch(saved, settings, keys) if saved is not None else [] + if differ: + print( + "presentation settings differ from the committed report: " + "; ".join(differ), + file=sys.stderr, + ) + sys.exit(2) + + def main(argv: list[str] | None = None) -> None: parser = argparse.ArgumentParser(prog="lev", description=__doc__) sub = parser.add_subparsers(dest="command", required=True) @@ -415,6 +423,12 @@ def main(argv: list[str] | None = None) -> None: default=16384, help="padded tokens per batched forward across requests (default 16384)", ) + serve_parser.add_argument( + "--max-request-rows", + type=int, + default=None, + help="batch rows one request may need before it gets 422 (default: the engine's)", + ) serve_parser.add_argument( "--score-order-average", choices=["off", "reversed", "cyclic"], @@ -447,15 +461,10 @@ def main(argv: list[str] | None = None) -> None: "--packed", type=int, default=3, help="states for the packed-vs-alone check" ) presentation_parser.add_argument( - "--split-checks", - action="store_true", - help="ask the identical and permuted questions in separate calls", - ) - presentation_parser.add_argument( - "--max-score-rows", + "--max-rows", type=int, - default=24, - help="Score rows per call before the probe is split (cyclic reads a level K times)", + default=None, + help="batch rows per call, as the engine counts them (default: max_request_rows)", ) presentation_parser.add_argument("--slot0-min", type=float, default=-0.20) presentation_parser.add_argument("--out", default=None, help="write the report JSON here") diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index 9b6cb04..b936a9f 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -33,6 +33,9 @@ _QUESTIONS = TypeAdapter(dict[str, Question]) +# Bench-length rows (~500 tokens) x 32 is about the batcher's 16384-token budget (ADR-029). +MAX_REQUEST_ROWS = 32 + @dataclass class EngineConfig: @@ -50,6 +53,9 @@ class EngineConfig: # adds the reversed order (2 rows per Score, as Choice), "cyclic" every rotation (K rows). # Both show the model level orders training never produces (ADR-020, FINDINGS §12). score_order_average: Literal["off", "reversed", "cyclic"] = "off" + # Rows one request may put into a forward (every question's every order); `prepare` + # refuses more with a ValueError (HTTP 422). None: no limit. + max_request_rows: int | None = MAX_REQUEST_ROWS # Serving can skip split codes; training keeps large sets for Mode B (ADR-028). skip_multi_token_codes: bool = True # Forking avoids repeated prefix work but adds a forward and cache copies (ADR-023). @@ -213,8 +219,23 @@ def prepare(self, state, questions: Mapping[str, Question | dict]) -> Prepared: with self._tokenizer_lock: return self._route_and_tokenise(state, questions) + def question_rows(self, questions: Mapping[str, Question | dict]) -> dict[str, int]: + """Batch rows each question adds to a request under this engine's config: + the orders `prepare` renders it in. Depends on routing, not on the state.""" + questions = _QUESTIONS.validate_python(questions) + with self._tokenizer_lock: + routes = serving_routes(questions, self.tokenizer, self.config) + return {name: len(self._orders(q, routes[name])) for name, q in questions.items()} + def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared: routes = serving_routes(questions, self.tokenizer, self.config) + limit = self.config.max_request_rows + rows = sum(len(self._orders(q, routes[name])) for name, q in questions.items()) + if limit is not None and rows > limit: + raise ValueError( + f"this request needs {rows} batch rows, above max_request_rows={limit}; " + "send fewer questions per request, or average fewer orders" + ) unsupported = [ name @@ -285,8 +306,13 @@ def _orders(self, question: Question, route: Route) -> list[list[int] | None]: Choice and binary Noul in state-first layout are reversed (ordered scales keep training's low-to-high order; schema-first shares options), unless `score_order_average` opts a Score in: "reversed" adds one row, "cyclic" - K-1, both in orders training never shows (ADR-029).""" - if route.mode is not Mode.LABEL_TOKEN or self.config.layout is not Layout.STATE_FIRST: + K-1, both in orders training never shows (ADR-029). `order_average=False` + reads every question once.""" + if ( + not self.config.order_average + or route.mode is not Mode.LABEL_TOKEN + or self.config.layout is not Layout.STATE_FIRST + ): return [None] n = len(route.codes or []) if isinstance(question, Score): @@ -295,9 +321,7 @@ def _orders(self, question: Question, route: Route) -> list[list[int] | None]: if self.config.score_order_average == "reversed": return [None, list(reversed(range(n)))] return [None] + [[(j + r) % n for j in range(n)] for r in range(1, n)] - if not self.config.order_average or ( - isinstance(question, Noul) and route.reason != BINARY_NOUL - ): + if isinstance(question, Noul) and route.reason != BINARY_NOUL: return [None] return [None, list(reversed(range(n)))] if n >= 2 else [None] @@ -531,6 +555,7 @@ def load( max_label_options: int | None = None, skip_multi_token_codes: bool = True, score_order_average: Literal["off", "reversed", "cyclic"] = "off", + max_request_rows: int | None = MAX_REQUEST_ROWS, ) -> DecisionEngine: """Load a checkpoint -- a release directory, a training output or a Hub id -- into a ready `DecisionEngine`. With no checkpoint, serves `model_id` frozen. @@ -607,6 +632,7 @@ def load( max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, score_order_average=score_order_average, + max_request_rows=max_request_rows, ) engine = DecisionEngine(model, tokenizer, config, profile, mode_b_head=head) engine.checkpoint = resolved diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py index d8c94e6..6e3d68b 100644 --- a/packages/lev/src/lev/presentation.py +++ b/packages/lev/src/lev/presentation.py @@ -3,18 +3,21 @@ The design of NandhaKishorM/laya#259, over `system_one` (ADR-029). Per question type (Score and Choice), on any list of states, with no labels: -- **identical**: every option carries the same text, so options differ only by - position and code. Metric: slot 0's log-probability minus the mean over the slots, - averaged over states and configurations. 0 is no position effect; below 0, slot 0 - is disfavoured. Choice keys must be unique, so they are numbered (`1`, `2`, ...) - and share one description, as Score levels share one text. -- **first_slot**: three real options in all 3! = 6 orders per state. Every option - sits in every slot exactly twice, so an order-free readout picks slot 0 in exactly - 1/3 of the decisions. -- **packed**: the probe asks its questions in as few `system_one` calls as fit - `MAX_SCORE_ROWS` (one, by default); this asks each question alone on a few states and - reports the largest probability difference, so what is measured is the presentation - and not the packing. +- **identical**: the position bias of one read, before any order averaging. Every + option carries the same text, so options differ only by position and code. Metric: + slot 0's log-probability minus the mean over the slots, averaged over states and + configurations; 0 is no position effect. It is read with `order_average=False`, + because averaged orders cancel it by construction (cyclic) or hide the middle slots + (reversed): it measures the bias averaging has to remove, not what is left after it. + Choice keys must be unique, so they are shapes with no order (`KEYS`), and every + assignment of keys to slots is read, so a key's own pull cancels. +- **first_slot**: three real options in all 3! = 6 orders per state, read as the engine + is configured. An order-free readout picks slot 0 in exactly 1/3 of the decisions; a + tie gives each of its m slots 1/m. `consistent` is the share of states whose six orders + all give one answer. In the chat style a Score line names its level by its place in + the request (`(level i of K)`), so a permuted listing renumbers the levels too. +- **packed**: the largest probability difference between the probe's answers and each + question asked alone, so what is measured is the presentation and not the packing. Probabilities are whatever `system_one` returns: calibrated, unless the engine carries an empty `CalibrationProfile`. Within one question, calibrated log-probabilities are the @@ -28,16 +31,16 @@ import itertools import json import math -from collections.abc import Callable, Mapping, Sequence +from collections.abc import Iterator, Mapping, Sequence +from contextlib import contextmanager +from dataclasses import replace from typing import Any KINDS = ("score", "choice") IDENTICAL_KS = (3, 4, 5) +KEYS = ("■", "●", "◆", "▲", "◎") SLOT0_MIN = -0.20 FIRST_SLOT_MIN = 0.15 -# Score rows per `system_one` call. The default probe is 12 rows off and 24 reversed, one call -# either way; cyclic reads a K-level question K times (42 rows), which filled a 32 GB GPU. -MAX_SCORE_ROWS = 24 # en follows Laya's presentation_checks.py; ja the same wording in Japanese. TEXT: dict[str, dict[str, Any]] = { @@ -75,30 +78,36 @@ }, } -SystemOne = Callable[[Any, Mapping[str, dict]], Any] +# Settings a report records. The first group is known before the model loads. +PRE_LOAD = ("n_states", "lang", "raw", "kinds", "score_order_average", "max_rows") +POST_LOAD = ("checkpoint_revision", "dtype") +SETTINGS = PRE_LOAD + POST_LOAD -def identical_question(kind: str, text: str, k: int, instructions: str) -> dict: +def identical_questions(kind: str, text: str, k: int, instructions: str) -> dict[str, dict]: + """The identical-option questions of one configuration, keyed by key assignment.""" if kind == "score": - return {"type": "score", "instructions": instructions, "criteria": [text] * k} + return {"": {"type": "score", "instructions": instructions, "criteria": [text] * k}} return { - "type": "choice", - "instructions": instructions, - "criteria": {str(i + 1): text for i in range(k)}, + "".join(map(str, keys)): { + "type": "choice", + "instructions": instructions, + "criteria": {KEYS[i]: text for i in keys}, + } + for keys in itertools.permutations(range(k)) } def probe_questions(lang: str = "en", kinds: Sequence[str] = KINDS) -> dict[str, dict]: - """Every probe question for one state, keyed `kind|identical|text|k` or - `kind|perm|012`. One `system_one` call answers them all.""" + """Every probe question for one state, keyed `kind|identical|text|k|keys` or + `kind|perm|012`.""" questions: dict[str, dict] = {} for kind in kinds: spec = TEXT[lang][kind] for text in spec["identical"]: for k in IDENTICAL_KS: - questions[f"{kind}|identical|{text}|{k}"] = identical_question( - kind, text, k, spec["instructions"] - ) + for keys, q in identical_questions(kind, text, k, spec["instructions"]).items(): + questions[f"{kind}|identical|{text}|{k}|{keys}"] = q options = list(spec["options"]) for order in itertools.permutations(range(len(options))): shown = [options[i] for i in order] @@ -111,6 +120,68 @@ def probe_questions(lang: str = "en", kinds: Sequence[str] = KINDS) -> dict[str, return questions +def is_identical(qid: str) -> bool: + return qid.split("|")[1] == "identical" + + +@contextmanager +def single_order(engine) -> Iterator[None]: + """Read every question once, in the order given.""" + config = engine.config + engine.config = replace(config, order_average=False) + try: + yield + finally: + engine.config = config + + +def call_groups(engine, questions: dict[str, dict], max_rows: int) -> list[dict[str, dict]]: + """`questions` split into `system_one` calls of at most `max_rows` batch rows, as the + engine counts them under its current config.""" + rows = engine.question_rows(questions) + groups: list[dict[str, dict]] = [] + current: dict[str, dict] = {} + total = 0 + for qid, question in questions.items(): + if current and total + rows[qid] > max_rows: + groups.append(current) + current, total = {}, 0 + current[qid] = question + total += rows[qid] + if current: + groups.append(current) + return groups + + +def ask( + engine, + states: Sequence[Any], + lang: str = "en", + kinds: Sequence[str] = KINDS, + max_rows: int | None = None, +) -> list[dict[str, Any]]: + """Every probe answer for every state: the identical questions in one order, the + permuted ones as the engine is configured. Calls hold at most `max_rows` batch rows, + the engine's `max_request_rows` by default.""" + max_rows = max_rows or engine.config.max_request_rows + questions = probe_questions(lang, kinds) + identical = {q: v for q, v in questions.items() if is_identical(q)} + permuted = {q: v for q, v in questions.items() if not is_identical(q)} + with single_order(engine): + identical_groups = call_groups(engine, identical, max_rows) + permuted_groups = call_groups(engine, permuted, max_rows) + answers = [] + for state in states: + got: dict[str, Any] = {} + with single_order(engine): + for group in identical_groups: + got.update(engine.system_one(state, group).answers) + for group in permuted_groups: + got.update(engine.system_one(state, group).answers) + answers.append(got) + return answers + + def slot_probs(answer: Any, question: dict) -> list[float]: """An answer's probabilities in the order the options were shown.""" probs = answer.probabilities @@ -119,126 +190,100 @@ def slot_probs(answer: Any, question: dict) -> list[float]: return [float(probs[key]) for key in question["criteria"]] +def top_slots(p: Sequence[float]) -> list[int]: + best = max(p) + return [i for i, x in enumerate(p) if x == best] + + def leave_one_out(per_state: Sequence[float]) -> list[float]: n, total = len(per_state), sum(per_state) loo = [(total - x) / (n - 1) for x in per_state] if n > 1 else list(per_state) return [min(loo), max(loo)] -def score_rows(question: dict, score_order_average: str) -> int: - """Batch rows a Score question adds: one per order it is read in (`_orders`).""" - k = len(question["criteria"]) - return {"off": 1, "reversed": 2, "cyclic": k}[score_order_average] if k >= 2 else 1 - - -def call_groups( - questions: dict[str, dict], - split_checks: bool = False, - max_score_rows: int = MAX_SCORE_ROWS, - score_order_average: str = "off", -) -> list[dict[str, dict]]: - """The probe split into `system_one` calls. By default one call, cut only where the - Score rows would pass `max_score_rows`, which bounds memory under `cyclic`; with - `split_checks` the identical and permuted questions never share a call.""" - groups: list[dict[str, dict]] = [] - for check in ("identical", "perm") if split_checks else (None,): - current: dict[str, dict] = {} - rows = 0 - for qid, question in questions.items(): - if check is not None and qid.split("|")[1] != check: - continue - added = score_rows(question, score_order_average) if question["type"] == "score" else 0 - if current and rows + added > max_score_rows: - groups.append(current) - current, rows = {}, 0 - current[qid] = question - rows += added - if current: - groups.append(current) - return groups +def mean(values: Sequence[float]) -> float: + return sum(values) / len(values) -def run( - system_one: SystemOne, - states: Sequence[Any], +def report( + answers: Sequence[Mapping[str, Any]], lang: str = "en", kinds: Sequence[str] = KINDS, slot0_min: float = SLOT0_MIN, - split_checks: bool = False, - max_score_rows: int = MAX_SCORE_ROWS, - score_order_average: str = "off", ) -> dict[str, dict]: - """Both checks for each kind, from the `call_groups` calls per state (one by default).""" + """Both checks for each kind from `ask`'s answers.""" questions = probe_questions(lang, kinds) - groups = call_groups(questions, split_checks, max_score_rows, score_order_average) - slot0: dict[str, list[float]] = {kind: [] for kind in kinds} - first: dict[str, list[float]] = {kind: [] for kind in kinds} - by_config: dict[str, dict[str, list[float]]] = {kind: {} for kind in kinds} - by_slot = {kind: [0] * len(TEXT[lang][kind]["options"]) for kind in kinds} - for state in states: - answers = {} - for group in groups: - answers.update(system_one(state, group).answers) - centred: dict[str, list[float]] = {kind: [] for kind in kinds} - firsts: dict[str, list[int]] = {kind: [] for kind in kinds} - for qid, question in questions.items(): - kind, check, *rest = qid.split("|") - p = slot_probs(answers[qid], question) - if check == "identical": - logp = [math.log(max(x, 1e-12)) for x in p] - value = logp[0] - sum(logp) / len(logp) - centred[kind].append(value) - by_config[kind].setdefault("|".join(rest), []).append(value) - else: - slot = max(range(len(p)), key=p.__getitem__) - firsts[kind].append(int(slot == 0)) - by_slot[kind][slot] += 1 - for kind in kinds: - slot0[kind].append(sum(centred[kind]) / len(centred[kind])) - first[kind].append(sum(firsts[kind]) / len(firsts[kind])) - report: dict[str, dict] = {} + out: dict[str, dict] = {} for kind in kinds: - identical = sum(slot0[kind]) / len(slot0[kind]) - rate = sum(first[kind]) / len(first[kind]) - report[kind] = { + options = TEXT[lang][kind]["options"] + slot0, first, consistent = [], [], 0 + by_config: dict[str, list[float]] = {} + by_slot = [0.0] * len(options) + for got in answers: + centred: dict[str, list[float]] = {} + firsts, picks = [], set() + for qid, question in questions.items(): + if not qid.startswith(kind + "|"): + continue + p = slot_probs(got[qid], question) + if is_identical(qid): + logp = [math.log(max(x, 1e-12)) for x in p] + config = "|".join(qid.split("|")[2:4]) + centred.setdefault(config, []).append(logp[0] - mean(logp)) + continue + order = [int(c) for c in qid.split("|")[2]] + top = top_slots(p) + for slot in top: + by_slot[slot] += 1 / len(top) + firsts.append(1 / len(top) if 0 in top else 0.0) + picks.add(frozenset(order[slot] for slot in top)) + per_config = {c: mean(v) for c, v in centred.items()} + for c, v in per_config.items(): + by_config.setdefault(c, []).append(v) + slot0.append(mean(list(per_config.values()))) + first.append(mean(firsts)) + consistent += int(len(picks) == 1) + identical, rate = mean(slot0), mean(first) + out[kind] = { "identical": { "metric": identical, - "leave_one_out": leave_one_out(slot0[kind]), + "leave_one_out": leave_one_out(slot0), "gate": slot0_min, "passed": identical >= slot0_min, - "by_config": {c: sum(v) / len(v) for c, v in by_config[kind].items()}, + "read": "single order", + "by_config": {c: mean(v) for c, v in by_config.items()}, }, "first_slot": { "metric": rate, - "leave_one_out": leave_one_out(first[kind]), + "leave_one_out": leave_one_out(first), "gate": FIRST_SLOT_MIN, "passed": rate >= FIRST_SLOT_MIN, - "decisions": len(states) * math.factorial(len(TEXT[lang][kind]["options"])), - "argmax_by_slot": by_slot[kind], + "decisions": len(answers) * math.factorial(len(options)), + "argmax_by_slot": by_slot, + "consistent": consistent / len(answers), }, } - return report + return out def packed_consistency( - system_one: SystemOne, + engine, states: Sequence[Any], + answers: Sequence[Mapping[str, Any]], lang: str = "en", kinds: Sequence[str] = KINDS, - split_checks: bool = False, - max_score_rows: int = MAX_SCORE_ROWS, - score_order_average: str = "off", ) -> float: - """Largest |p| difference between the probe as `run` asks it and each question alone.""" + """Largest |p| difference between `ask`'s answers for `states` and each question asked + alone, under the same order setting.""" questions = probe_questions(lang, kinds) - groups = call_groups(questions, split_checks, max_score_rows, score_order_average) worst = 0.0 - for state in states: - packed = {} - for group in groups: - packed.update(system_one(state, group).answers) + for state, packed in zip(states, answers, strict=False): for qid, question in questions.items(): - alone = system_one(state, {qid: question}).answers[qid] + if is_identical(qid): + with single_order(engine): + alone = engine.system_one(state, {qid: question}).answers[qid] + else: + alone = engine.system_one(state, {qid: question}).answers[qid] for a, b in zip( slot_probs(packed[qid], question), slot_probs(alone, question), strict=True ): @@ -246,25 +291,12 @@ def packed_consistency( return worst -SETTINGS = ( - "n_states", - "lang", - "raw", - "kinds", - "score_order_average", - "split_checks", - "max_score_rows", - "checkpoint_revision", - "dtype", -) - - -def settings_mismatch(saved: dict, run: dict) -> list[str]: - """Every recorded setting of `saved` that this run does not share, as +def settings_mismatch(saved: dict, run: dict, keys: Sequence[str] = SETTINGS) -> list[str]: + """Every setting among `keys` that `saved` recorded and this run does not share, as ` (report: X, run: Y)`. A setting the report never recorded is not checked.""" return [ f"{key} (report: {saved[key]!r}, run: {run.get(key)!r})" - for key in SETTINGS + for key in keys if key in saved and saved[key] != run.get(key) ] @@ -284,8 +316,9 @@ def drift(report: dict, snapshot: dict, tolerance: float) -> list[str]: def to_markdown(report: dict) -> str: lines = [ - "| kind | identical (slot 0 - mean) | leave-one-out | first-slot rate | leave-one-out |", - "|---|---|---|---|---|", + "| kind | identical, one read (slot 0 - mean) | leave-one-out " + "| first-slot rate | leave-one-out | consistent |", + "|---|---|---|---|---|---|", ] for kind, r in report.items(): ident, first = r["identical"], r["first_slot"] @@ -293,7 +326,8 @@ def to_markdown(report: dict) -> str: f"| {kind} | {ident['metric']:+.3f} {'PASS' if ident['passed'] else 'FAIL'} " f"| {ident['leave_one_out'][0]:+.3f} .. {ident['leave_one_out'][1]:+.3f} " f"| {first['metric']:.3f} {'PASS' if first['passed'] else 'FAIL'} " - f"| {first['leave_one_out'][0]:.3f} .. {first['leave_one_out'][1]:.3f} |" + f"| {first['leave_one_out'][0]:.3f} .. {first['leave_one_out'][1]:.3f} " + f"| {first['consistent']:.3f} |" ) return "\n".join(lines) diff --git a/packages/lev/src/lev/server.py b/packages/lev/src/lev/server.py index 0ce5dad..90c045b 100644 --- a/packages/lev/src/lev/server.py +++ b/packages/lev/src/lev/server.py @@ -13,7 +13,7 @@ from fastapi import Request from .batcher import Batcher, ClientGone, Overloaded, WorkerStopped -from .model import load +from .model import MAX_REQUEST_ROWS, load from .types import SystemOneRequest, SystemOneResponse @@ -31,6 +31,7 @@ def create_app( max_batch_tokens: int = 16384, timeout: float = 30.0, score_order_average: Literal["off", "reversed", "cyclic"] = "off", + max_request_rows: int | None = MAX_REQUEST_ROWS, ) -> Any: from fastapi import FastAPI, HTTPException, Response from starlette.concurrency import run_in_threadpool @@ -53,6 +54,7 @@ def _load() -> None: max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, score_order_average=score_order_average, + max_request_rows=max_request_rows, ) state["batcher"] = Batcher( engine, max_pending=max_pending, max_batch_tokens=max_batch_tokens, timeout=timeout @@ -76,6 +78,7 @@ async def health() -> dict: "max_label_options": config.max_label_options, "order_average": config.order_average, "score_order_average": config.score_order_average, + "max_request_rows": config.max_request_rows, "prefix_mode": config.prefix_mode, "compiled": config.compile, "prompt_style": config.prompt_style, diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 4afa056..410a65e 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -1,39 +1,41 @@ -"""Presentation checks (ADR-029) and opt-in Score order averaging. +"""Presentation checks (ADR-029), opt-in Score order averaging and the request row limit. -The checks run against a fake `system_one` that validates every request with -lev's own `SystemOneRequest` and answers with lev's answer types, so a probe lev -would reject, or an answer shape the checks misread, fails here without weights. +The checks run against `FakeEngine`: a real `DecisionEngine` without weights routes, +renders and counts every request, as serving does, and only the logits are scripted. +So a probe lev would reject, a row count that disagrees with the engine, or an answer +shape the checks misread fails here without weights. """ from __future__ import annotations import json import math +from pathlib import Path +from string import ascii_uppercase import pytest -from lev import ( - ChoiceAnswer, - Score, - ScoreAnswer, - SystemOneRequest, - SystemOneResponse, - Usage, -) -from lev.model import DecisionEngine, EngineConfig, average_orders +from lev import ChoiceAnswer, Score, ScoreAnswer, SystemOneRequest, SystemOneResponse, Usage +from lev.model import MAX_REQUEST_ROWS, DecisionEngine, EngineConfig, average_orders from lev.presentation import ( IDENTICAL_KS, + KEYS, KINDS, + POST_LOAD, + PRE_LOAD, SLOT0_MIN, TEXT, + ask, + call_groups, drift, packed_consistency, probe_questions, read_states, - run, + report, + single_order, to_markdown, ) from lev.router import route -from lev.types import Choice +from lev.types import Choice, Noul def softmax(z: list[float]) -> list[float]: @@ -42,27 +44,59 @@ def softmax(z: list[float]) -> list[float]: return [v / sum(e) for v in e] +class Tokenizer: + """Space-prefixed A-Z and 0-8 are single tokens, as `rich_tokenizer`.""" + + single = {f" {c}" for c in ascii_uppercase} | {f" {i}" for i in range(9)} + + def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: + return [1] if text in self.single else [1] * (len(text) + 1) + + class FakeEngine: - """logit = content[option text] + slot_bias[slot]. `packing` adds a term that - depends on how many questions share the call, which a packed readout must not.""" + """logit = content[text] + key_pull[key] + slot0 (in slot 0) + a packing term that + grows with the questions per call, read in every order the engine renders and + averaged as lev does. Routing, orders, row counts and the row limit are the real + engine's.""" + + def __init__(self, slot0=0.0, content=None, packing=0.0, key_pull=None, **config): + self.real = DecisionEngine(model=None, tokenizer=Tokenizer(), config=EngineConfig(**config)) + self.slot0, self.content, self.packing = slot0, content or {}, packing + self.key_pull = key_pull or {} + self.calls = 0 + self.checkpoint = None + + @property + def config(self) -> EngineConfig: + return self.real.config + + @config.setter + def config(self, value: EngineConfig) -> None: + self.real.config = value - def __init__(self, slot0: float = 0.0, content: dict | None = None, packing: float = 0.0): - self.slot0, self.content, self.packing, self.calls = slot0, content or {}, packing, 0 - self.checkpoint = None # a DecisionEngine's resolved checkpoint; None for a frozen base + def question_rows(self, questions): + return self.real.question_rows(questions) def system_one(self, state, questions): - request = SystemOneRequest(state=state, questions=questions) + prepared = self.real.prepare(state, questions) + SystemOneRequest(state=state, questions=questions) self.calls += 1 - answers = {} - for name, q in request.questions.items(): - texts = list(q.criteria) + rows: dict[str, list] = {} + for variant in prepared.variants: + q = prepared.questions[variant.name] + items = list(q.criteria.items()) if q.type == "choice" else list(enumerate(q.criteria)) + shown = items if variant.order is None else [items[i] for i in variant.order] z = [ - self.content.get(t, 0.0) - + (self.slot0 if i == 0 else 0.0) - + self.packing * len(request.questions) * i - for i, t in enumerate(texts) + self.content.get(text, 0.0) + + self.key_pull.get(key, 0.0) + + (self.slot0 if j == 0 else 0.0) + + self.packing * len(questions) * j + for j, (key, text) in enumerate(shown) ] - p = softmax(z) + rows.setdefault(variant.name, []).append((softmax(z), variant.order)) + answers = {} + for name, q in prepared.questions.items(): + p = average_orders([r[0] for r in rows[name]], [r[1] for r in rows[name]]) if q.type == "score": answers[name] = ScoreAnswer( score=0.0, @@ -80,13 +114,18 @@ def system_one(self, state, questions): return SystemOneResponse(model="fake", answers=answers, usage=Usage(input_tokens=1)) +def run(engine, states, lang="en", kinds=KINDS, max_rows=MAX_REQUEST_ROWS, slot0_min=SLOT0_MIN): + return report(ask(engine, states, lang, kinds, max_rows), lang, kinds, slot0_min) + + class TestProbeQuestions: @pytest.mark.parametrize("lang", sorted(TEXT)) def test_every_probe_is_a_valid_request(self, lang): questions = probe_questions(lang) assert SystemOneRequest(state="s", questions=questions) - per_kind = 2 * len(IDENTICAL_KS) + 6 - assert len(questions) == per_kind * len(KINDS) + score = 2 * len(IDENTICAL_KS) + 6 + choice = 2 * sum(math.factorial(k) for k in IDENTICAL_KS) + 6 + assert len(questions) == score + choice @pytest.mark.parametrize("lang", sorted(TEXT)) def test_identical_options_differ_only_by_position(self, lang): @@ -96,7 +135,20 @@ def test_identical_options_differ_only_by_position(self, lang): texts = q["criteria"] if q["type"] == "score" else list(q["criteria"].values()) assert len(set(texts)) == 1 if q["type"] == "choice": - assert list(q["criteria"]) == [str(i + 1) for i in range(len(q["criteria"]))] + assert set(q["criteria"]) <= set(KEYS) + assert not any(c.isdigit() for key in q["criteria"] for c in key) + + def test_every_choice_key_sits_in_every_slot_equally_often(self): + for k in IDENTICAL_KS: + listings = [ + list(q["criteria"]) + for qid, q in probe_questions("en", ["choice"]).items() + if qid.startswith(f"choice|identical|a team|{k}|") + ] + assert len(listings) == math.factorial(k) + for slot in range(k): + counts = {key: sum(lst[slot] == key for lst in listings) for key in KEYS[:k]} + assert set(counts.values()) == {math.factorial(k - 1)} @pytest.mark.parametrize("lang", sorted(TEXT)) def test_every_option_sits_in_every_slot_twice(self, lang): @@ -113,46 +165,114 @@ def test_every_option_sits_in_every_slot_twice(self, lang): class TestChecks: def test_a_flat_readout_sits_at_zero_and_one_third(self): - content = {"Soon": 3.0, "Technical": 3.0} - report = run(FakeEngine(content=content).system_one, ["a", "b"]) + content = {"Soon": 3.0, "payments, refunds, invoices": 3.0} + r = run(FakeEngine(content=content), ["a", "b"]) for kind in KINDS: - assert report[kind]["identical"]["metric"] == pytest.approx(0.0) - assert report[kind]["identical"]["passed"] - assert report[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) + assert r[kind]["identical"]["metric"] == pytest.approx(0.0) + assert r[kind]["identical"]["passed"] + assert r[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) + assert r[kind]["first_slot"]["consistent"] == 1.0 def test_a_planted_slot_zero_penalty_is_measured_exactly(self): - report = run(FakeEngine(slot0=-2.0).system_one, ["a", "b", "c"]) + r = run(FakeEngine(slot0=-2.0, order_average=False), ["a", "b", "c"]) # centred slot 0 = -2 - (-2/K), averaged over K = 3, 4, 5 and both texts expected = sum(-2.0 * (1 - 1 / k) for k in IDENTICAL_KS) / len(IDENTICAL_KS) for kind in KINDS: - assert report[kind]["identical"]["metric"] == pytest.approx(expected) - assert not report[kind]["identical"]["passed"] - assert report[kind]["first_slot"]["argmax_by_slot"][0] == 0 - assert report[kind]["first_slot"]["decisions"] == 18 + assert r[kind]["identical"]["metric"] == pytest.approx(expected) + assert not r[kind]["identical"]["passed"] + assert r[kind]["first_slot"]["argmax_by_slot"][0] == 0 + assert r[kind]["first_slot"]["decisions"] == 18 + + def test_ties_are_split_between_the_tied_slots(self): + """A flat readout ties all three slots; argmax would credit slot 0 every time.""" + r = run(FakeEngine(), ["a", "b"]) + for kind in KINDS: + assert r[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) + assert r[kind]["first_slot"]["argmax_by_slot"] == pytest.approx([4.0, 4.0, 4.0]) + + def test_a_choice_key_pull_cancels_and_a_position_effect_does_not(self): + pulled = run(FakeEngine(key_pull={KEYS[0]: 2.0}), ["a"], kinds=["choice"]) + assert pulled["choice"]["identical"]["metric"] == pytest.approx(0.0, abs=1e-12) + both = run(FakeEngine(key_pull={KEYS[0]: 2.0}, slot0=-1.0, order_average=False), ["a"]) + alone = run(FakeEngine(slot0=-1.0, order_average=False), ["a"]) + assert both["choice"]["identical"]["metric"] == pytest.approx( + alone["choice"]["identical"]["metric"] + ) - def test_one_call_per_state(self): - engine = FakeEngine() - run(engine.system_one, ["a", "b", "c"]) - assert engine.calls == 3 + @pytest.mark.parametrize("mode", ["reversed", "cyclic"]) + def test_the_identical_check_reads_one_order_whatever_the_engine_averages(self, mode): + """Averaged, a pure slot bias cancels (cyclic) or hides the middle slots (reversed).""" + single = run(FakeEngine(slot0=-2.0, order_average=False), ["a"]) + averaged = run(FakeEngine(slot0=-2.0, score_order_average=mode), ["a"]) + for kind in KINDS: + assert averaged[kind]["identical"]["metric"] == pytest.approx( + single[kind]["identical"]["metric"] + ) + engine = FakeEngine(score_order_average=mode) + with single_order(engine): + assert engine.config.order_average is False + assert engine.config.order_average and engine.config.score_order_average == mode def test_the_gate_is_the_proposal_and_can_be_moved(self): - engine = FakeEngine(slot0=-0.3) - assert not run(engine.system_one, ["a"])["score"]["identical"]["passed"] - assert run(engine.system_one, ["a"], slot0_min=-1.0)["score"]["identical"]["passed"] + engine = FakeEngine(slot0=-0.3, order_average=False) + assert not run(engine, ["a"])["score"]["identical"]["passed"] + assert run(engine, ["a"], slot0_min=-1.0)["score"]["identical"]["passed"] assert SLOT0_MIN == -0.20 +class TestCallGroups: + """Calls hold at most `max_rows` rows, counted by the engine for every question.""" + + @pytest.mark.parametrize("mode", ["off", "reversed", "cyclic"]) + def test_every_call_fits_the_limit_and_asks_everything_once(self, mode): + engine = FakeEngine(score_order_average=mode) + questions = probe_questions("en") + groups = call_groups(engine, questions, 24) + rows = engine.question_rows(questions) + assert all(sum(rows[q] for q in g) <= 24 for g in groups) + assert sorted(q for g in groups for q in g) == sorted(questions) + + def test_choice_rows_count(self): + engine = FakeEngine() + rows = engine.question_rows(probe_questions("en", ["choice"])) + assert set(rows.values()) == {2} + assert len(call_groups(engine, probe_questions("en", ["choice"]), 24)) > 1 + + def test_the_grouping_does_not_change_an_isolated_readout(self): + engine = FakeEngine(slot0=-1.0, content={"Soon": 1.0}, score_order_average="cyclic") + assert run(engine, ["a", "b"], max_rows=5) == run(engine, ["a", "b"]) + + def test_identical_and_permuted_questions_never_share_a_call(self): + engine = FakeEngine() + seen = [] + real = engine.system_one + engine.system_one = lambda state, qs: seen.append(set(qs)) or real(state, qs) + ask(engine, ["a"]) + for qids in seen: + assert len({q.split("|")[1] for q in qids}) == 1 + + class TestPackedConsistency: def test_an_isolated_readout_agrees_with_itself_alone(self): - assert packed_consistency(FakeEngine(slot0=-1.0).system_one, ["a"]) == pytest.approx(0.0) + engine = FakeEngine(slot0=-1.0) + answers = ask(engine, ["a"]) + assert packed_consistency(engine, ["a"], answers) == pytest.approx(0.0) def test_a_readout_that_depends_on_packing_is_caught(self): - assert packed_consistency(FakeEngine(packing=0.01).system_one, ["a"]) > 0.01 + engine = FakeEngine(packing=0.01) + assert packed_consistency(engine, ["a"], ask(engine, ["a"])) > 0.01 + + def test_the_packed_answers_are_reused_not_asked_again(self): + engine = FakeEngine() + answers = ask(engine, ["a", "b"]) + before = engine.calls + packed_consistency(engine, ["a"], answers) + assert engine.calls - before == len(probe_questions("en")) class TestReport: def test_drift_flags_only_what_moved_past_the_tolerance(self): - now = run(FakeEngine(slot0=-2.0).system_one, ["a"]) + now = run(FakeEngine(slot0=-2.0), ["a"]) committed = json.loads(json.dumps(now)) assert drift(now, committed, 0.05) == [] committed["score"]["identical"]["metric"] += 0.2 @@ -164,7 +284,7 @@ def test_drift_flags_only_what_moved_past_the_tolerance(self): assert "choice.identical: missing from this run" in drift(now, committed, 0.05) def test_markdown_has_a_row_per_kind(self): - text = to_markdown(run(FakeEngine().system_one, ["a"])) + text = to_markdown(run(FakeEngine(), ["a"])) assert text.count("\n") == 1 + len(KINDS) def test_states_are_read_from_jsonl(self, tmp_path): @@ -203,11 +323,17 @@ def test_cyclic_is_every_rotation(self, rich_tokenizer): [2, 0, 1], ] - def test_independent_of_the_choice_switch(self, rich_tokenizer): - q = Score(criteria=["low", "high"]) - assert self.orders( - q, rich_tokenizer, score_order_average="reversed", order_average=False - ) == [None, [1, 0]] + @pytest.mark.parametrize("mode", ["off", "reversed", "cyclic"]) + def test_order_average_off_reads_every_question_once(self, rich_tokenizer, mode): + for q in ( + Score(criteria=["low", "mid", "high"]), + Choice(criteria={"a": None, "b": None, "c": None}), + ): + assert self.orders( + q, rich_tokenizer, score_order_average=mode, order_average=False + ) == [None] + + def test_choice_does_not_follow_the_score_switch(self, rich_tokenizer): c = Choice(criteria={"a": None, "b": None, "c": None}) for mode in ("off", "reversed", "cyclic"): assert self.orders(c, rich_tokenizer, score_order_average=mode) == [None, [2, 1, 0]] @@ -224,67 +350,95 @@ def test_cyclic_averaging_cancels_a_slot_bias_on_equal_content(self): """Each level sits in each slot once, so a pure position bias averages out.""" k = 4 orders = [None] + [[(j + r) % k for j in range(k)] for r in range(1, k)] - biased = softmax([2.0, 0.0, 0.0, 0.0]) # slot 0 favoured, content equal + biased = softmax([2.0, 0.0, 0.0, 0.0]) assert average_orders([biased] * k, orders) == pytest.approx([1 / k] * k) -class TestCallGroups: - """How the probe is split into calls: one by default, bounded Score rows under cyclic.""" +QUESTIONS = { + "team": Choice(criteria={"a": None, "b": None, "c": None}), + "urgency": Score(criteria=["low", "mid", "high", "blocked"]), + "churn": Noul(instructions="leaving?"), + "many": Choice(criteria={f"o{i}": None for i in range(40)}), +} + + +class TestQuestionRows: + """`question_rows` is what `prepare` renders, so callers never recount rows.""" + + @pytest.mark.parametrize("mode", ["off", "reversed", "cyclic"]) + @pytest.mark.parametrize("order_average", [True, False]) + @pytest.mark.parametrize("noul_readout", ["rating", "binary"]) + def test_it_matches_prepare(self, poor_tokenizer, mode, order_average, noul_readout): + engine = DecisionEngine( + model=None, + tokenizer=poor_tokenizer, + config=EngineConfig( + score_order_average=mode, + order_average=order_average, + noul_readout=noul_readout, + max_request_rows=None, + ), + mode_b_head=object(), + ) + rows = engine.question_rows(QUESTIONS) + assert sum(rows.values()) == engine.prepare("s", QUESTIONS).rows + assert rows["many"] == 1 # Mode B: one row whatever the averaging - def rows(self, group, mode): - from lev.presentation import score_rows + def test_schema_first_is_one_row_per_question(self, rich_tokenizer): + from lev.prompt import Layout - return sum(score_rows(q, mode) for q in group.values() if q["type"] == "score") + engine = DecisionEngine( + model=None, + tokenizer=rich_tokenizer, + config=EngineConfig(layout=Layout.SCHEMA_FIRST, score_order_average="cyclic"), + mode_b_head=object(), + ) + assert set(engine.question_rows(QUESTIONS).values()) == {1} + assert engine.prepare("s", QUESTIONS).rows == len(QUESTIONS) - def test_off_and_reversed_stay_one_call(self): - from lev.presentation import call_groups - questions = probe_questions("en", ["score"]) - assert len(call_groups(questions)) == 1 - assert self.rows(questions, "reversed") == 24 - assert len(call_groups(questions, score_order_average="reversed")) == 1 +class TestRequestRowLimit: + def engine(self, tokenizer, **config) -> DecisionEngine: + return DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) - def test_cyclic_is_cut_at_the_row_limit_and_asks_everything_once(self): - from lev.presentation import call_groups + def test_a_request_past_the_limit_is_refused_before_any_forward(self, rich_tokenizer): + questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(4)} + engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=11) + with pytest.raises(ValueError, match="needs 12 batch rows, above max_request_rows=11"): + engine.prepare("s", questions) + assert self.engine(rich_tokenizer, max_request_rows=11).prepare("s", questions).rows == 4 - questions = probe_questions("en") - assert self.rows(questions, "cyclic") == 42 - groups = call_groups(questions, score_order_average="cyclic") - assert len(groups) > 1 - assert all(self.rows(g, "cyclic") <= 24 for g in groups) - asked = [qid for g in groups for qid in g] - assert sorted(asked) == sorted(questions) - - def test_split_checks_never_mixes_the_two_checks(self): - from lev.presentation import call_groups - - for group in call_groups(probe_questions("ja"), split_checks=True): - assert len({qid.split("|")[1] for qid in group}) == 1 - - def test_the_split_does_not_change_an_isolated_readout(self): - engine = FakeEngine(slot0=-1.0, content={"Soon": 1.0}) - one = run(engine.system_one, ["a", "b"]) - split = run( - engine.system_one, - ["a", "b"], - split_checks=True, - max_score_rows=5, - score_order_average="cyclic", - ) - assert split == one - assert packed_consistency(engine.system_one, ["a"], split_checks=True) == pytest.approx(0.0) + def test_none_is_no_limit(self, rich_tokenizer): + questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(30)} + engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=None) + assert engine.prepare("s", questions).rows == 90 + assert EngineConfig().max_request_rows == MAX_REQUEST_ROWS + + def test_the_server_answers_422(self, monkeypatch, rich_tokenizer): + pytest.importorskip("fastapi") + from fastapi.testclient import TestClient + from lev import server + + engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=5) + monkeypatch.setattr(server, "load", lambda *a, **k: engine) + questions = {f"q{i}": {"type": "score", "criteria": ["a", "b", "c"]} for i in range(2)} + with TestClient(server.create_app()) as client: + response = client.post("/v1/systemone", json={"state": "s", "questions": questions}) + assert response.status_code == 422 + assert "max_request_rows=5" in response.json()["detail"] class TestCommittedReport: """`data/presentation-checks.json` is what `--compare` reads in CI.""" def test_it_parses_and_carries_every_metric(self): - from pathlib import Path path = Path(__file__).resolve().parents[3] / "data" / "presentation-checks.json" committed = json.loads(path.read_text("utf-8")) assert committed["score_order_average"] == "off" and committed["n_states"] == 290 + assert committed["max_rows"] == MAX_REQUEST_ROWS for kind in KINDS: + assert committed["checks"][kind]["identical"]["read"] == "single order" for check in ("identical", "first_slot"): assert isinstance(committed["checks"][kind][check]["metric"], float) assert drift(committed["checks"], committed["checks"], 0.0) == [] @@ -302,34 +456,55 @@ def cli(self, monkeypatch, tmp_path, engine, *extra): states.write_text('{"state": "a"}\n{"state": "b"}\n', "utf-8") main(["presentation-checks", str(states), "--packed", "0", *extra]) - def committed(self, monkeypatch, tmp_path, engine) -> dict: + def committed(self, monkeypatch, tmp_path, engine, **edit) -> str: out = tmp_path / "report.json" self.cli(monkeypatch, tmp_path, engine, "--out", str(out)) - return json.loads(out.read_text("utf-8")) + saved = json.loads(out.read_text("utf-8")) | edit + path = tmp_path / "committed.json" + path.write_text(json.dumps(saved), "utf-8") + return str(path) + + def test_the_settings_split_at_the_load(self): + assert set(PRE_LOAD).isdisjoint(POST_LOAD) + assert set(POST_LOAD) == {"checkpoint_revision", "dtype"} def test_matching_settings_are_compared_metric_by_metric(self, monkeypatch, tmp_path): engine = FakeEngine(slot0=-1.0) - saved = self.committed(monkeypatch, tmp_path, engine) - assert saved["score_order_average"] == "off" and saved["max_score_rows"] == 24 + path = Path(self.committed(monkeypatch, tmp_path, engine)) + saved = json.loads(path.read_text("utf-8")) + assert saved["score_order_average"] == "off" and saved["max_rows"] == MAX_REQUEST_ROWS saved["checks"]["score"]["identical"]["metric"] += 0.5 - path = tmp_path / "committed.json" path.write_text(json.dumps(saved), "utf-8") with pytest.raises(SystemExit) as exc: self.cli(monkeypatch, tmp_path, engine, "--compare", str(path)) assert "score.identical" in str(exc.value.code) - def test_different_settings_are_refused_before_any_run(self, monkeypatch, tmp_path, capsys): - engine = FakeEngine(slot0=-1.0) - saved = self.committed(monkeypatch, tmp_path, engine) - saved["score_order_average"] = "reversed" - path = tmp_path / "committed.json" - path.write_text(json.dumps(saved), "utf-8") - calls = engine.calls + def test_a_model_free_setting_is_refused_before_the_load(self, monkeypatch, tmp_path, capsys): + path = self.committed(monkeypatch, tmp_path, FakeEngine(), score_order_average="reversed") + + def no_load(*a, **k): + raise AssertionError("loaded a model for a run it had to refuse") + + monkeypatch.setattr("lev.model.load", no_load) + from lev.cli import main + + states = tmp_path / "states.jsonl" with pytest.raises(SystemExit) as exc: - self.cli(monkeypatch, tmp_path, engine, "--compare", str(path)) + main(["presentation-checks", str(states), "--packed", "0", "--compare", path]) assert exc.value.code == 2 - assert engine.calls == calls assert ( "presentation settings differ from the committed report: " "score_order_average (report: 'reversed', run: 'off')" ) in capsys.readouterr().err + + def test_another_revision_is_refused_after_the_load_and_before_any_run( + self, monkeypatch, tmp_path, capsys + ): + engine = FakeEngine() + path = self.committed(monkeypatch, tmp_path, engine, checkpoint_revision="abc123") + calls = engine.calls + with pytest.raises(SystemExit) as exc: + self.cli(monkeypatch, tmp_path, engine, "--compare", str(path)) + assert exc.value.code == 2 + assert engine.calls == calls + assert "checkpoint_revision (report: 'abc123', run: None)" in capsys.readouterr().err From 0e5fc6e32017024baef3213df7278d4247a6acf2 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Mon, 5 Oct 2026 05:36:30 +0900 Subject: [PATCH 06/39] ADR-029 evidence after review: one-read bias, labelled and calibration effects, row limit Re-run 2026-10-04/05 on interfaze-ai/lev (HF 7bdc748, the weights of f8ef711), bf16, one RTX 5090, on this branch rebased after #4. The identical-option control is reported as the bias of one read, which no mode changes; what averaging changes is shown by Score accuracy, RPS and ECE, the first-slot rate with ties split, and order consistency. A held-out refit of the Score temperature per mode, the row-limit memory table, and a regenerated committed report (max_rows 32) are included. Accuracy, RPS, Choice and Noul match the earlier runs exactly. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- data/adr-029-summary.json | 712 +++++++++++++++++++++++++++++++--- data/presentation-checks.json | 73 ++-- docs/ARCHITECTURE.md | 2 +- docs/DECISIONS.md | 70 +++- 4 files changed, 754 insertions(+), 103 deletions(-) diff --git a/data/adr-029-summary.json b/data/adr-029-summary.json index 58c6e72..4638f94 100644 --- a/data/adr-029-summary.json +++ b/data/adr-029-summary.json @@ -1,61 +1,321 @@ { - "about": "Summary of the ADR-029 runs: the numbers behind its tables. interfaze-ai/lev (HF f8ef711), bf16, one RTX 5090, 2026-09-29. Raw per-run reports are not committed and are available on request.", + "about": "Summary of the ADR-029 runs after review (2026-10-04/05): the numbers behind its tables. interfaze-ai/lev (HF 7bdc748; weights and calibration identical to f8ef711, only README.md changed), bf16, one RTX 5090, lev branch rebased on main 8ca94b7 (#4).", "benches": { "bench_en": "sokudan data/bench_en.jsonl, 290 states (English)", "bench_ja": "sokudan data/bench_ja.jsonl, 300 states (Japanese, outside Lev's target language; reference only)" }, - "score_presentation": { + "shipped_temperatures": { + "choice:B:large": 0.6333, + "choice:B": 0.6333, + "noul:A": 2.3333, + "score:A": 2.8033, + "choice:A": 1.7667, + "choice:A:small": 1.7898, + "choice:A:mid": 1.6086, + "choice:A:large": 1.6641 + }, + "identical_one_read": { + "bench_en": { + "score": { + "calibrated": -0.3323, + "leave_one_out": [ + -0.3364, + -0.3298 + ], + "raw": -0.9317, + "by_config_calibrated": { + "moderate|3": -0.1191, + "moderate|4": -0.2373, + "moderate|5": -0.3198, + "a request|3": -0.3249, + "a request|4": -0.4614, + "a request|5": -0.5315 + }, + "by_config_raw": { + "moderate|3": -0.3338, + "moderate|4": -0.6652, + "moderate|5": -0.8966, + "a request|3": -0.9108, + "a request|4": -1.2935, + "a request|5": -1.49 + }, + "max_abs_diff_across_modes": 0.0 + }, + "choice": { + "calibrated": -0.454, + "leave_one_out": [ + -0.4556, + -0.4515 + ], + "raw": -0.8125, + "by_config_calibrated": { + "a team|3": -0.5365, + "a team|4": -0.534, + "a team|5": -0.5335, + "a request|3": -0.323, + "a request|4": -0.3803, + "a request|5": -0.4165 + }, + "by_config_raw": { + "a team|3": -0.9601, + "a team|4": -0.9558, + "a team|5": -0.9548, + "a request|3": -0.5781, + "a request|4": -0.6807, + "a request|5": -0.7455 + }, + "max_abs_diff_across_modes": 0.0 + } + }, + "bench_ja": { + "score": { + "calibrated": -0.5181, + "leave_one_out": [ + -0.5222, + -0.5151 + ], + "raw": -1.4524, + "by_config_calibrated": { + "中程度|3": -0.1889, + "中程度|4": -0.2989, + "中程度|5": -0.3897, + "依頼|3": -0.5875, + "依頼|4": -0.7656, + "依頼|5": -0.8779 + }, + "by_config_raw": { + "中程度|3": -0.5294, + "中程度|4": -0.838, + "中程度|5": -1.0926, + "依頼|3": -1.647, + "依頼|4": -2.1462, + "依頼|5": -2.4609 + }, + "max_abs_diff_across_modes": 0.0 + }, + "choice": { + "calibrated": -0.6602, + "leave_one_out": [ + -0.6624, + -0.6577 + ], + "raw": -1.1817, + "by_config_calibrated": { + "部署|3": -0.611, + "部署|4": -0.7262, + "部署|5": -0.7265, + "依頼|3": -0.5278, + "依頼|4": -0.6493, + "依頼|5": -0.7206 + }, + "by_config_raw": { + "部署|3": -1.0936, + "部署|4": -1.2998, + "部署|5": -1.3002, + "依頼|3": -0.9447, + "依頼|4": -1.162, + "依頼|5": -1.2897 + }, + "max_abs_diff_across_modes": 0.0 + } + } + }, + "first_slot": { "bench_en": { "off": { - "identical_calibrated": -0.3321, - "identical_raw": -0.931, - "first_slot": 0.2695, - "first_slot_raw": 0.2695 + "score": { + "metric": 0.2646, + "leave_one_out": [ + 0.2641, + 0.2655 + ], + "argmax_by_slot": [ + 460.3333, + 595.8333, + 683.8333 + ], + "consistent": 0.7138, + "decisions": 1740 + }, + "choice": { + "metric": 0.331, + "leave_one_out": [ + 0.331, + 0.3319 + ], + "argmax_by_slot": [ + 576.0, + 588.0, + 576.0 + ], + "consistent": 0.9862, + "decisions": 1740 + } }, "reversed": { - "identical_calibrated": -0.0101, - "identical_raw": 0.0878, - "first_slot": 0.3207, - "first_slot_raw": 0.3207 + "score": { + "metric": 0.3191, + "leave_one_out": [ + 0.3184, + 0.3202 + ], + "argmax_by_slot": [ + 555.1667, + 575.6667, + 609.1667 + ], + "consistent": 0.8724, + "decisions": 1740 + }, + "choice": { + "metric": 0.3317, + "leave_one_out": [ + 0.3317, + 0.3323 + ], + "argmax_by_slot": [ + 577.1667, + 585.6667, + 577.1667 + ], + "consistent": 0.9793, + "decisions": 1740 + } }, "cyclic": { - "identical_calibrated": -0.0161, - "identical_raw": -0.0365, - "first_slot": 0.3126, - "first_slot_raw": 0.3121 + "score": { + "metric": 0.3101, + "leave_one_out": [ + 0.3091, + 0.3111 + ], + "argmax_by_slot": [ + 539.5, + 590.5, + 610.0 + ], + "consistent": 0.8931, + "decisions": 1740 + }, + "choice": { + "metric": 0.332, + "leave_one_out": [ + 0.3314, + 0.3328 + ], + "argmax_by_slot": [ + 577.6667, + 584.6667, + 577.6667 + ], + "consistent": 0.9828, + "decisions": 1740 + } } }, "bench_ja": { "off": { - "identical_calibrated": -0.5184, - "identical_raw": -1.4532, - "first_slot": 0.24, - "first_slot_raw": 0.24 + "score": { + "metric": 0.2422, + "leave_one_out": [ + 0.2414, + 0.243 + ], + "argmax_by_slot": [ + 436.0, + 631.5, + 732.5 + ], + "consistent": 0.6267, + "decisions": 1800 + }, + "choice": { + "metric": 0.3311, + "leave_one_out": [ + 0.3305, + 0.3322 + ], + "argmax_by_slot": [ + 596.0, + 608.0, + 596.0 + ], + "consistent": 0.9733, + "decisions": 1800 + } }, "reversed": { - "identical_calibrated": -0.0586, - "identical_raw": 0.038, - "first_slot": 0.315, - "first_slot_raw": 0.3139 + "score": { + "metric": 0.3142, + "leave_one_out": [ + 0.3135, + 0.3152 + ], + "argmax_by_slot": [ + 565.5, + 606.0, + 628.5 + ], + "consistent": 0.87, + "decisions": 1800 + }, + "choice": { + "metric": 0.3306, + "leave_one_out": [ + 0.3305, + 0.3317 + ], + "argmax_by_slot": [ + 595.0, + 610.0, + 595.0 + ], + "consistent": 0.9767, + "decisions": 1800 + } }, "cyclic": { - "identical_calibrated": -0.0558, - "identical_raw": -0.1313, - "first_slot": 0.3017, - "first_slot_raw": 0.3006 + "score": { + "metric": 0.2994, + "leave_one_out": [ + 0.2993, + 0.3004 + ], + "argmax_by_slot": [ + 539.0, + 619.0, + 642.0 + ], + "consistent": 0.8533, + "decisions": 1800 + }, + "choice": { + "metric": 0.33, + "leave_one_out": [ + 0.3294, + 0.3311 + ], + "argmax_by_slot": [ + 594.0, + 612.0, + 594.0 + ], + "consistent": 0.9733, + "decisions": 1800 + } } } }, - "choice_presentation_off": { + "packed_max_abs_diff": { "bench_en": { - "identical_calibrated": -0.1001, - "identical_raw": -0.1597, - "first_slot": 0.3333 + "off": 0.0375, + "reversed": 0.0375, + "cyclic": 0.0375 }, "bench_ja": { - "identical_calibrated": -0.0547, - "identical_raw": -0.0362, - "first_slot": 0.3306 + "off": 0.0408, + "reversed": 0.0408, + "cyclic": 0.0408 } }, "bench_accuracy": { @@ -63,60 +323,202 @@ "off": { "score_acc": 0.5828, "score_rps": 0.1504, + "score_ece15": 0.1238, + "score_ece15_equal_mass": 0.1545, + "score_mean_confidence": 0.6814, "choice_acc": 0.9172, "noul_acc": 0.9379, "noul_auroc": 0.9778, - "ms_per_request": 164.6 + "ms_per_request": 156.5 }, "reversed": { "score_acc": 0.6517, "score_rps": 0.1275, + "score_ece15": 0.1013, + "score_ece15_equal_mass": 0.1066, + "score_mean_confidence": 0.6594, "choice_acc": 0.9172, "noul_acc": 0.9379, "noul_auroc": 0.978, - "ms_per_request": 184.0 + "ms_per_request": 179.3 }, "cyclic": { "score_acc": 0.6414, "score_rps": 0.1249, + "score_ece15": 0.0601, + "score_ece15_equal_mass": 0.0912, + "score_mean_confidence": 0.6453, "choice_acc": 0.9172, "noul_acc": 0.9379, "noul_auroc": 0.9784, - "ms_per_request": 215.4 + "ms_per_request": 210.2 } }, "bench_ja": { "off": { "score_acc": 0.6433, "score_rps": 0.1384, + "score_ece15": 0.0934, + "score_ece15_equal_mass": 0.113, + "score_mean_confidence": 0.7184, "choice_acc": 0.8867, "noul_acc": 0.8167, "noul_auroc": 0.889, - "ms_per_request": 150.9 + "ms_per_request": 149.2 }, "reversed": { "score_acc": 0.73, "score_rps": 0.1079, + "score_ece15": 0.0588, + "score_ece15_equal_mass": 0.1072, + "score_mean_confidence": 0.6829, "choice_acc": 0.8867, "noul_acc": 0.8133, "noul_auroc": 0.8877, - "ms_per_request": 171.4 + "ms_per_request": 169.9 }, "cyclic": { "score_acc": 0.7167, "score_rps": 0.108, + "score_ece15": 0.0765, + "score_ece15_equal_mass": 0.0879, + "score_mean_confidence": 0.6813, "choice_acc": 0.8867, "noul_acc": 0.8133, "noul_auroc": 0.8876, - "ms_per_request": 199.9 + "ms_per_request": 197.3 } } }, - "noul_alone_bench_ja": { - "requests": 300, - "identical_across_modes": true + "score_temperature_refit": { + "bench_en": { + "split": "seed 0, stratified by gold level, alternate halves", + "off": { + "n_fit": 146, + "n_eval": 144, + "T_shipped": 2.8033, + "T_refit": 3.9628, + "held_out_shipped": { + "acc": 0.5903, + "rps": 0.152, + "ece15": 0.1296, + "ece15_equal_mass": 0.1683, + "nll": 0.9348 + }, + "held_out_refit": { + "acc": 0.5903, + "rps": 0.1466, + "ece15": 0.108, + "ece15_equal_mass": 0.134, + "nll": 0.9087 + } + }, + "reversed": { + "n_fit": 146, + "n_eval": 144, + "T_shipped": 2.8033, + "T_refit": 3.1595, + "held_out_shipped": { + "acc": 0.6736, + "rps": 0.1264, + "ece15": 0.1108, + "ece15_equal_mass": 0.1453, + "nll": 0.8388 + }, + "held_out_refit": { + "acc": 0.6736, + "rps": 0.1263, + "ece15": 0.1193, + "ece15_equal_mass": 0.1668, + "nll": 0.8381 + } + }, + "cyclic": { + "n_fit": 146, + "n_eval": 144, + "T_shipped": 2.8033, + "T_refit": 2.9175, + "held_out_shipped": { + "acc": 0.6597, + "rps": 0.1238, + "ece15": 0.0775, + "ece15_equal_mass": 0.1387, + "nll": 0.8279 + }, + "held_out_refit": { + "acc": 0.6597, + "rps": 0.1238, + "ece15": 0.0765, + "ece15_equal_mass": 0.1382, + "nll": 0.8284 + } + } + }, + "bench_ja": { + "split": "seed 0, stratified by gold level, alternate halves", + "off": { + "n_fit": 151, + "n_eval": 149, + "T_shipped": 2.8033, + "T_refit": 3.5967, + "held_out_shipped": { + "acc": 0.6577, + "rps": 0.1321, + "ece15": 0.0896, + "ece15_equal_mass": 0.1275, + "nll": 0.7807 + }, + "held_out_refit": { + "acc": 0.6577, + "rps": 0.13, + "ece15": 0.0772, + "ece15_equal_mass": 0.0914, + "nll": 0.7792 + } + }, + "reversed": { + "n_fit": 151, + "n_eval": 149, + "T_shipped": 2.8033, + "T_refit": 2.3927, + "held_out_shipped": { + "acc": 0.7584, + "rps": 0.1015, + "ece15": 0.0888, + "ece15_equal_mass": 0.1219, + "nll": 0.641 + }, + "held_out_refit": { + "acc": 0.7584, + "rps": 0.1008, + "ece15": 0.0611, + "ece15_equal_mass": 0.1142, + "nll": 0.6267 + } + }, + "cyclic": { + "n_fit": 151, + "n_eval": 149, + "T_shipped": 2.8033, + "T_refit": 2.3974, + "held_out_shipped": { + "acc": 0.7517, + "rps": 0.1013, + "ece15": 0.0681, + "ece15_equal_mass": 0.0959, + "nll": 0.6436 + }, + "held_out_refit": { + "acc": 0.7517, + "rps": 0.1006, + "ece15": 0.0865, + "ece15_equal_mass": 0.0909, + "nll": 0.6286 + } + } + } }, - "off_vs_main_cf104b6": { + "off_vs_main_8ca94b7": { "bench_en": { "responses": 40, "identical": true @@ -126,9 +528,225 @@ "identical": true } }, - "issue_1_reproduced": { - "identical_calibrated": -0.3321, - "identical_raw": -0.931, - "first_slot": 0.2695 + "request_rows_rtx5090": { + "what": "one system_one request of R single-order Score rows; peak CUDA memory in GiB (bf16 weights alone are ~8.1). Past ~31 GiB reserved, Windows spills into shared system memory instead of raising out-of-memory, and the request slows 5-10x.", + "bench_row_tokens": { + "bench_en": { + "n": 290, + "median": 259, + "p95": 449, + "max": 509 + }, + "bench_ja": { + "n": 300, + "median": 249, + "p95": 419, + "max": 526 + } + }, + "results": [ + { + "state_tokens": 350, + "rows": 8, + "width": 474, + "padded_tokens": 3792, + "seconds": 0.376, + "peak_allocated_gib": 9.05, + "above_weights_gib": 0.94, + "peak_reserved_gib": 9.66 + }, + { + "state_tokens": 350, + "rows": 16, + "width": 474, + "padded_tokens": 7584, + "seconds": 0.782, + "peak_allocated_gib": 9.99, + "above_weights_gib": 1.88, + "peak_reserved_gib": 11.21 + }, + { + "state_tokens": 350, + "rows": 24, + "width": 474, + "padded_tokens": 11376, + "seconds": 1.194, + "peak_allocated_gib": 10.93, + "above_weights_gib": 2.81, + "peak_reserved_gib": 12.71 + }, + { + "state_tokens": 350, + "rows": 32, + "width": 474, + "padded_tokens": 15168, + "seconds": 1.598, + "peak_allocated_gib": 11.86, + "above_weights_gib": 3.75, + "peak_reserved_gib": 14.24 + }, + { + "state_tokens": 350, + "rows": 48, + "width": 474, + "padded_tokens": 22752, + "seconds": 2.425, + "peak_allocated_gib": 13.74, + "above_weights_gib": 5.63, + "peak_reserved_gib": 17.29 + }, + { + "state_tokens": 350, + "rows": 64, + "width": 474, + "padded_tokens": 30336, + "seconds": 3.277, + "peak_allocated_gib": 15.61, + "above_weights_gib": 7.5, + "peak_reserved_gib": 20.34 + }, + { + "state_tokens": 350, + "rows": 96, + "width": 474, + "padded_tokens": 45504, + "seconds": 5.254, + "peak_allocated_gib": 19.36, + "above_weights_gib": 11.25, + "peak_reserved_gib": 26.44 + }, + { + "state_tokens": 700, + "rows": 8, + "width": 824, + "padded_tokens": 6592, + "seconds": 0.696, + "peak_allocated_gib": 9.65, + "above_weights_gib": 1.54, + "peak_reserved_gib": 11.18 + }, + { + "state_tokens": 700, + "rows": 16, + "width": 824, + "padded_tokens": 13184, + "seconds": 1.389, + "peak_allocated_gib": 11.19, + "above_weights_gib": 3.07, + "peak_reserved_gib": 14.49 + }, + { + "state_tokens": 700, + "rows": 24, + "width": 824, + "padded_tokens": 19776, + "seconds": 2.098, + "peak_allocated_gib": 12.73, + "above_weights_gib": 4.61, + "peak_reserved_gib": 17.68 + }, + { + "state_tokens": 700, + "rows": 32, + "width": 824, + "padded_tokens": 26368, + "seconds": 2.813, + "peak_allocated_gib": 14.26, + "above_weights_gib": 6.15, + "peak_reserved_gib": 21.05 + }, + { + "state_tokens": 700, + "rows": 48, + "width": 824, + "padded_tokens": 39552, + "seconds": 4.317, + "peak_allocated_gib": 17.33, + "above_weights_gib": 9.22, + "peak_reserved_gib": 27.51 + }, + { + "state_tokens": 1000, + "rows": 8, + "width": 1124, + "padded_tokens": 8992, + "seconds": 0.947, + "peak_allocated_gib": 10.39, + "above_weights_gib": 2.28, + "peak_reserved_gib": 12.9 + }, + { + "state_tokens": 1000, + "rows": 16, + "width": 1124, + "padded_tokens": 17984, + "seconds": 1.946, + "peak_allocated_gib": 12.67, + "above_weights_gib": 4.56, + "peak_reserved_gib": 17.62 + }, + { + "state_tokens": 1000, + "rows": 24, + "width": 1124, + "padded_tokens": 26976, + "seconds": 2.925, + "peak_allocated_gib": 14.95, + "above_weights_gib": 6.84, + "peak_reserved_gib": 22.38 + }, + { + "state_tokens": 1000, + "rows": 32, + "width": 1124, + "padded_tokens": 35968, + "seconds": 3.916, + "peak_allocated_gib": 17.22, + "above_weights_gib": 9.11, + "peak_reserved_gib": 27.12 + }, + { + "state_tokens": 2000, + "rows": 8, + "width": 2124, + "padded_tokens": 16992, + "seconds": 1.956, + "peak_allocated_gib": 14.71, + "above_weights_gib": 6.6, + "peak_reserved_gib": 19.12 + }, + { + "state_tokens": 2000, + "rows": 16, + "width": 2124, + "padded_tokens": 33984, + "seconds": 12.348, + "peak_allocated_gib": 21.29, + "above_weights_gib": 13.18, + "peak_reserved_gib": 30.12 + }, + { + "state_tokens": 4000, + "rows": 8, + "width": 4124, + "padded_tokens": 32992, + "seconds": 42.186, + "peak_allocated_gib": 29.8, + "above_weights_gib": 21.69, + "peak_reserved_gib": 39.3 + } + ], + "first_run_past_the_card": [ + { + "state_tokens": 350, + "rows": 128, + "width": 474, + "padded_tokens": 60672, + "seconds": 59.979, + "peak_allocated_gib": 23.11, + "above_weights_gib": 15.0, + "peak_reserved_gib": 32.53 + } + ] } } diff --git a/data/presentation-checks.json b/data/presentation-checks.json index aa3f4b3..748a9f5 100644 --- a/data/presentation-checks.json +++ b/data/presentation-checks.json @@ -1,5 +1,5 @@ { - "about": "Committed report for `lev presentation-checks --compare` (ADR-029). One run: interfaze-ai/lev (HF f8ef711), bf16, one RTX 5090, the shipped calibration, score_order_average off, kinds score and choice, lang en, 2026-09-29.", + "about": "Committed report for `lev presentation-checks --compare` (ADR-029). One run: interfaze-ai/lev (HF 7bdc748), bf16, one RTX 5090, the shipped calibration, score_order_average off, kinds score and choice, lang en, 2026-10-05. The identical check reads one order.", "checkpoint": "interfaze-ai/lev", "states": "sokudan bench_en.jsonl (github.com/hiroki-abe-58/sokudan, data/bench_en.jsonl, CC BY 4.0), 290 states", "n_states": 290, @@ -10,78 +10,81 @@ "choice" ], "score_order_average": "off", - "split_checks": false, - "max_score_rows": 24, - "checkpoint_revision": "f8ef71157ec06a7d3b6435bc0756f9d735c33748", + "max_rows": 32, + "checkpoint_revision": "7bdc748dffebd85b57ee0dbea8f994c6354fed31", "dtype": "torch.bfloat16", - "packed_max_abs_diff": 0.0207, + "packed_max_abs_diff": 0.0375, "checks": { "score": { "identical": { "metric": -0.3323, "leave_one_out": [ - -0.3362, + -0.3364, -0.3298 ], "gate": -0.2, "passed": false, + "read": "single order", "by_config": { - "moderate|3": -0.1182, - "moderate|4": -0.2365, - "moderate|5": -0.3193, + "moderate|3": -0.1191, + "moderate|4": -0.2373, + "moderate|5": -0.3198, "a request|3": -0.3249, - "a request|4": -0.4617, - "a request|5": -0.5332 + "a request|4": -0.4614, + "a request|5": -0.5315 } }, "first_slot": { - "metric": 0.2713, + "metric": 0.2646, "leave_one_out": [ - 0.2699, - 0.2722 + 0.2641, + 0.2655 ], "gate": 0.15, "passed": true, "decisions": 1740, "argmax_by_slot": [ - 472, - 598, - 670 - ] + 460.3333, + 595.8333, + 683.8333 + ], + "consistent": 0.7138 } }, "choice": { "identical": { - "metric": -0.1006, + "metric": -0.454, "leave_one_out": [ - -0.1024, - -0.0991 + -0.4556, + -0.4515 ], "gate": -0.2, - "passed": true, + "passed": false, + "read": "single order", "by_config": { - "a team|3": -0.0569, - "a team|4": -0.1228, - "a team|5": -0.2804, - "a request|3": 0.0892, - "a request|4": -0.0295, - "a request|5": -0.2033 + "a team|3": -0.5365, + "a team|4": -0.534, + "a team|5": -0.5335, + "a request|3": -0.323, + "a request|4": -0.3803, + "a request|5": -0.4165 } }, "first_slot": { - "metric": 0.3333, + "metric": 0.331, "leave_one_out": [ - 0.3328, - 0.3339 + 0.331, + 0.3319 ], "gate": 0.15, "passed": true, "decisions": 1740, "argmax_by_slot": [ - 580, - 581, - 579 - ] + 576.0, + 588.0, + 576.0 + ], + "consistent": 0.9862 } } } diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index b14ecc3..1d2d356 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -201,7 +201,7 @@ LoRA r32 on `q,k,v,o,gate,up,down` ≈ 25–40 M trainable parameters. **The Fam - they get **separate fitted temperatures** — one global scalar would be wrong for at least one of them; - on option sets where **both** are valid we measure agreement. Material disagreement means the router is a correctness hazard, not merely a capacity switch. This is an explicit eval, not an assumption. -**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `lev presentation-checks` measures what that changes (ADR-029). +**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `order_average=False` reads every question once. A request may need at most `max_request_rows` batch rows (32 by default); `prepare` refuses a larger one before any GPU work. `lev presentation-checks` measures the position bias of one read, the bias averaging has to remove (ADR-029). ### 5.4 Output types diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index b6e498c..f557d4e 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -601,39 +601,69 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode Every result is reported whichever way it goes, including accuracy that does not improve. -**Evidence.** Run 2026-09-29 on `interfaze-ai/lev` (HF f8ef711), bf16, one RTX 5090. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json), and the raw per-run reports are available on request. The committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. +**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error, and by the first-slot rate on real options. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows one request may need. -Issue #1 reproduced with averaging off (Score probe alone, 12 questions per call): identical control -0.332 calibrated / -0.931 raw, first-slot rate 0.270. With averaging off, every answer on 20 items of each bench, the probe included, is identical to the current code. +**Evidence.** Run 2026-10-04/05 on `interfaze-ai/lev` (HF 7bdc748: the weights and calibration of f8ef711, only README.md changed), bf16, one RTX 5090, this branch rebased on main after #4. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json); the committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. -Score, identical control (slot 0 minus the mean; gate -0.20 raw) and first-slot rate (1/3 is order-free): +The bias of one read: identical-option control, slot 0 minus the mean (gate -0.20 raw). Raw is calibrated x T, exact within one temperature bucket. The three runs per bench, one per mode, agree exactly, as they must. ```text - bench_en (290) bench_ja (300, reference) - calibrated raw first slot calibrated raw first slot - off -0.332 -0.931 0.270 -0.518 -1.453 0.240 - reversed -0.010 +0.088 0.321 -0.059 +0.038 0.315 - cyclic -0.016 -0.037 0.312 -0.056 -0.131 0.301 + bench_en (290) bench_ja (300, reference) + calibrated raw calibrated raw + Score -0.332 -0.932 -0.518 -1.452 + Choice -0.454 -0.813 -0.660 -1.182 ``` -Choice, which is already read in two orders, with Score averaging off: identical control -0.100 / -0.160 (en) and -0.055 / -0.036 (ja), first-slot rate 0.333 and 0.331. +Choice, read once, avoids slot 0 more than Score does; it is already read in two orders when served, and the first-slot rate below is what that leaves. -The benches' three questions per request (4-way Choice, 3-level Score, Noul), shipped calibration: +What averaging changes. The benches' three questions per request (4-way Choice, 3-level Score, Noul), shipped calibration; Score ECE over 15 equal-width bins. First-slot rate over all six orders of three real options, ties split (1/3 is order-free), and `consistent`, the share of states whose six orders give one answer: ```text - Score acc Score RPS Choice acc Noul acc Noul AUROC ms / request - en off 0.583 0.150 0.917 0.938 0.9778 164.6 - reversed 0.652 0.128 0.917 0.938 0.9780 184.0 (1.12x) - cyclic 0.641 0.125 0.917 0.938 0.9784 215.4 (1.31x) - ja off (ref.) 0.643 0.138 0.887 0.817 0.8890 150.9 - reversed 0.730 0.108 0.887 0.813 0.8877 171.4 (1.14x) - cyclic 0.717 0.108 0.887 0.813 0.8876 199.9 (1.32x) + Score Choice Noul + acc RPS ECE first slot consistent acc first slot consistent acc AUROC ms / request + en off 0.583 0.150 0.124 0.265 0.714 0.917 0.331 0.986 0.938 0.9778 156.5 + reversed 0.652 0.127 0.101 0.319 0.872 0.917 0.332 0.979 0.938 0.9780 179.3 (1.15x) + cyclic 0.641 0.125 0.060 0.310 0.893 0.917 0.332 0.983 0.938 0.9784 210.2 (1.34x) + ja off 0.643 0.138 0.093 0.242 0.627 0.887 0.331 0.973 0.817 0.8890 149.2 + reversed 0.730 0.108 0.059 0.314 0.870 0.887 0.331 0.977 0.813 0.8877 169.9 (1.14x) + cyclic 0.717 0.108 0.077 0.299 0.853 0.887 0.330 0.973 0.813 0.8876 197.3 (1.32x) ``` -Choice does not move. Noul moves by one item on bench_ja, and asked alone it is identical under all three modes on all 300 items: the change comes from the batch the extra Score rows make (bf16), not from the Noul readout. +Accuracy, RPS, Choice and Noul are identical, to the last digit, to the runs before the rebase and the review fixes. In the chat style the release uses, a Score line names its level by its place in the request (`(level i of K)`), so the probe's permuted listings renumber the levels as well as move them, and Score's first-slot rate measures both; the engine's own averaging moves each level with its number. -Two caveats. Asking the probe's questions together or one at a time differs by up to |Δp| 0.18 (raw, bench_ja, off) on the three states checked per run, so a metric is tied to how many questions share a call; `lev presentation-checks` fixes that at one call of at most 24 Score rows. And `cyclic` needs that cap: 42 Score rows per call exhausted a 32 GB card. Even capped, PyTorch's reserved memory went past the card (44-49 GiB for `cyclic`, 62 GiB for the default probe of both kinds), which Windows backs with shared system memory. +Calibration of the averaged modes. The shipped Score temperature (2.80) was fitted on single-order rows. Refit per mode on half of each bench (stratified by the gold level, seed 0), judged on the other half: -**Reading, for the decision.** `reversed` removes most of the slot-0 deficit and lifts Score accuracy by 6.9 points on bench_en (8.7 on the Japanese reference bench) at 1.12-1.14x the time. `cyclic` is no better than `reversed` on either bench and costs 1.31-1.32x. Neither was tested on helpsteer2, the case that kept Score out of averaging in ADR-020, and both benches are one family of synthetic support messages. The proposal keeps the default off and leaves the choice between (a) and (b) to the maintainer. +```text + T refit held-out NLL held-out ECE held-out RPS + shipped refit shipped refit shipped refit + en (144) off 3.96 0.935 0.909 0.130 0.108 0.152 0.147 + reversed 3.16 0.839 0.838 0.111 0.119 0.126 0.126 + cyclic 2.92 0.828 0.828 0.077 0.077 0.124 0.124 + ja (149) off 3.60 0.781 0.779 0.090 0.077 0.132 0.130 + reversed 2.39 0.641 0.627 0.089 0.061 0.102 0.101 + cyclic 2.40 0.644 0.629 0.068 0.086 0.101 0.101 +``` + +On bench_en a refit gains nothing for either averaged mode (held-out NLL within 0.001), and the shipped temperature is if anything a little sharp for `off`. On the Japanese reference the refit goes the other way for the averaged modes. A per-mode temperature is not proposed. + +The rows one request may need (`max_request_rows`, default 32). One `system_one` request of R single-order Score rows; peak CUDA memory on the RTX 5090, GiB (the bf16 weights alone are ~8.1). The benches' rows are at most 509 tokens (en) and 526 (ja): + +```text + row tokens rows reserved seconds + 474 32 14.2 1.6 + 474 64 20.3 3.3 + 474 96 26.4 5.3 + 474 128 32.5 60.0 past the card: Windows spills into system memory + 824 48 27.5 4.3 + 1124 32 27.1 3.9 + 2124 16 30.1 12.3 spilling +``` + +Memory grows with rows times row length, and faster for long rows, so the limit is set for bench-length requests: 32 rows of ~510 tokens is about the batcher's 16384-token budget (ADR-030). A full presentation run with 64-row calls filled the card on bench_en (32 GB in use, 100% busy, no result after 22 minutes) and was stopped; with 32-row calls the six runs peaked at 22.5 GiB reserved, about 50 minutes each. + +With averaging off, every answer on 20 items of each bench (40 responses each, the probe included) is identical to main at 8ca94b7. Asking the probe's questions together or alone differs by up to |Δp| 0.038 (bench_en) and 0.041 (bench_ja), so the committed report records `max_rows`. + +**Reading, for the decision.** `reversed` lifts Score accuracy by 6.9 points on bench_en and lowers its RPS and ECE at 1.15x the time, with the shipped temperature. `cyclic` calibrates best on bench_en (ECE 0.060) but is no more accurate than `reversed` and costs 1.34x. Neither was tested on helpsteer2, the case that kept Score out of averaging in ADR-020, and both benches are one family of synthetic support messages. The proposal keeps the default off and leaves the choice between (a) and (b) to the maintainer. --- From ff8fbd7057c87a2fa5766ea6a296b6286b80210f Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Mon, 5 Oct 2026 12:43:58 +0900 Subject: [PATCH 07/39] Row limit: refuse only the rows Score averaging adds, never a request main accepts #4's batcher does not split a request: one larger than max_batch_tokens runs alone, in one forward (20 Choice + 40 Score questions with averaging off: one forward of 80 rows, up to 35,680 padded tokens, on main). So max_request_rows now refuses a request only when Score averaging added rows to it and the total is past the limit. With averaging off nothing is refused, and that 80-row request answers exactly as on main (3 bench_en states, real model; a tiny-model test pins it against an unlimited engine). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- data/adr-029-summary.json | 59 +++++++++++++++++++++++ docs/ARCHITECTURE.md | 2 +- docs/DECISIONS.md | 6 +-- packages/lev/src/lev/cli.py | 2 +- packages/lev/src/lev/model.py | 18 ++++--- packages/lev/tests/test_engine_forward.py | 29 +++++++++++ packages/lev/tests/test_presentation.py | 21 +++++++- 7 files changed, 125 insertions(+), 12 deletions(-) diff --git a/data/adr-029-summary.json b/data/adr-029-summary.json index 4638f94..bcc3e7f 100644 --- a/data/adr-029-summary.json +++ b/data/adr-029-summary.json @@ -528,6 +528,65 @@ "identical": true } }, + "large_request_without_averaging": { + "what": "20 Choice + 40 Score questions per request, default settings, through lev.batcher (max_batch_tokens 16384), first 3 bench_en states: every forward's rows and width", + "requests": [ + { + "item_id": "bench_en-0000", + "rows": 80, + "padded_tokens": 26800, + "forwards_main": [ + { + "rows": 80, + "width": 335 + } + ], + "forwards_branch": [ + { + "rows": 80, + "width": 335 + } + ], + "answers_identical_to_main": true + }, + { + "item_id": "bench_en-0001", + "rows": 80, + "padded_tokens": 15760, + "forwards_main": [ + { + "rows": 80, + "width": 197 + } + ], + "forwards_branch": [ + { + "rows": 80, + "width": 197 + } + ], + "answers_identical_to_main": true + }, + { + "item_id": "bench_en-0002", + "rows": 80, + "padded_tokens": 35680, + "forwards_main": [ + { + "rows": 80, + "width": 446 + } + ], + "forwards_branch": [ + { + "rows": 80, + "width": 446 + } + ], + "answers_identical_to_main": true + } + ] + }, "request_rows_rtx5090": { "what": "one system_one request of R single-order Score rows; peak CUDA memory in GiB (bf16 weights alone are ~8.1). Past ~31 GiB reserved, Windows spills into shared system memory instead of raising out-of-memory, and the request slows 5-10x.", "bench_row_tokens": { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 1d2d356..a355809 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -201,7 +201,7 @@ LoRA r32 on `q,k,v,o,gate,up,down` ≈ 25–40 M trainable parameters. **The Fam - they get **separate fitted temperatures** — one global scalar would be wrong for at least one of them; - on option sets where **both** are valid we measure agreement. Material disagreement means the router is a correctness hazard, not merely a capacity switch. This is an explicit eval, not an assumption. -**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `order_average=False` reads every question once. A request may need at most `max_request_rows` batch rows (32 by default); `prepare` refuses a larger one before any GPU work. `lev presentation-checks` measures the position bias of one read, the bias averaging has to remove (ADR-029). +**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `order_average=False` reads every question once. A request that Score averaging grows past `max_request_rows` batch rows (32 by default) is refused in `prepare`, before any GPU work; one without averaged Score rows never is, since the batcher runs an oversized request alone (ADR-030). `lev presentation-checks` measures the position bias of one read, the bias averaging has to remove (ADR-029). ### 5.4 Output types diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index f557d4e..7994eda 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -601,7 +601,7 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode Every result is reported whichever way it goes, including accuracy that does not improve. -**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error, and by the first-slot rate on real options. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows one request may need. +**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error, and by the first-slot rate on real options. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows Score averaging may add to a request. **Evidence.** Run 2026-10-04/05 on `interfaze-ai/lev` (HF 7bdc748: the weights and calibration of f8ef711, only README.md changed), bf16, one RTX 5090, this branch rebased on main after #4. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json); the committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. @@ -646,7 +646,7 @@ Calibration of the averaged modes. The shipped Score temperature (2.80) was fitt On bench_en a refit gains nothing for either averaged mode (held-out NLL within 0.001), and the shipped temperature is if anything a little sharp for `off`. On the Japanese reference the refit goes the other way for the averaged modes. A per-mode temperature is not proposed. -The rows one request may need (`max_request_rows`, default 32). One `system_one` request of R single-order Score rows; peak CUDA memory on the RTX 5090, GiB (the bf16 weights alone are ~8.1). The benches' rows are at most 509 tokens (en) and 526 (ja): +The rows Score averaging may add (`max_request_rows`, default 32). One `system_one` request of R single-order Score rows; peak CUDA memory on the RTX 5090, GiB (the bf16 weights alone are ~8.1). The benches' rows are at most 509 tokens (en) and 526 (ja): ```text row tokens rows reserved seconds @@ -659,7 +659,7 @@ The rows one request may need (`max_request_rows`, default 32). One `system_one` 2124 16 30.1 12.3 spilling ``` -Memory grows with rows times row length, and faster for long rows, so the limit is set for bench-length requests: 32 rows of ~510 tokens is about the batcher's 16384-token budget (ADR-030). A full presentation run with 64-row calls filled the card on bench_en (32 GB in use, 100% busy, no result after 22 minutes) and was stopped; with 32-row calls the six runs peaked at 22.5 GiB reserved, about 50 minutes each. +Memory grows with rows times row length, and faster for long rows, so the limit is set for bench-length requests: 32 rows of ~510 tokens is about the batcher's 16384-token budget (ADR-030). The batcher does not split a request: on main, 20 Choice and 40 Score questions with averaging off ran as one forward of 80 rows, up to 35,680 padded tokens. So the limit refuses only a request that Score averaging grows past it, and never one without averaged Score rows; that 80-row request gets answers identical to main's. A full presentation run with 64-row calls filled the card on bench_en (32 GB in use, 100% busy, no result after 22 minutes) and was stopped; with 32-row calls the six runs peaked at 22.5 GiB reserved, about 50 minutes each. With averaging off, every answer on 20 items of each bench (40 responses each, the probe included) is identical to main at 8ca94b7. Asking the probe's questions together or alone differs by up to |Δp| 0.038 (bench_en) and 0.041 (bench_ja), so the committed report records `max_rows`. diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 9a3ff09..5e5cb2b 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -427,7 +427,7 @@ def main(argv: list[str] | None = None) -> None: "--max-request-rows", type=int, default=None, - help="batch rows one request may need before it gets 422 (default: the engine's)", + help="refuse (422) a request Score averaging grows past this many batch rows (default 32)", ) serve_parser.add_argument( "--score-order-average", diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index b936a9f..3072f74 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -53,8 +53,8 @@ class EngineConfig: # adds the reversed order (2 rows per Score, as Choice), "cyclic" every rotation (K rows). # Both show the model level orders training never produces (ADR-020, FINDINGS §12). score_order_average: Literal["off", "reversed", "cyclic"] = "off" - # Rows one request may put into a forward (every question's every order); `prepare` - # refuses more with a ValueError (HTTP 422). None: no limit. + # Rows a request may need once Score averaging adds rows to it; `prepare` refuses + # more with a ValueError (HTTP 422). Requests without added rows are never refused. max_request_rows: int | None = MAX_REQUEST_ROWS # Serving can skip split codes; training keeps large sets for Mode B (ADR-028). skip_multi_token_codes: bool = True @@ -229,12 +229,18 @@ def question_rows(self, questions: Mapping[str, Question | dict]) -> dict[str, i def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared: routes = serving_routes(questions, self.tokenizer, self.config) + orders = {name: self._orders(q, routes[name]) for name, q in questions.items()} + rows = sum(len(o) for o in orders.values()) + added = sum(len(o) - 1 for name, o in orders.items() if isinstance(questions[name], Score)) limit = self.config.max_request_rows - rows = sum(len(self._orders(q, routes[name])) for name, q in questions.items()) - if limit is not None and rows > limit: + # The batcher runs an oversized request alone and unsplit; refuse only the rows + # Score averaging adds, so a request main accepts is never refused for its size. + if limit is not None and added and rows > limit: raise ValueError( - f"this request needs {rows} batch rows, above max_request_rows={limit}; " - "send fewer questions per request, or average fewer orders" + f"this request needs {rows} batch rows, {added} of them from " + f"score_order_average={self.config.score_order_average!r}, above " + f"max_request_rows={limit}; send fewer Score questions per request, " + "or average fewer orders" ) unsupported = [ diff --git a/packages/lev/tests/test_engine_forward.py b/packages/lev/tests/test_engine_forward.py index 17eb149..bc679da 100644 --- a/packages/lev/tests/test_engine_forward.py +++ b/packages/lev/tests/test_engine_forward.py @@ -47,3 +47,32 @@ def test_single_forward_matches_the_full_logits_at_each_last_token(tiny_model, w torch.testing.assert_close(hidden[i], full.hidden_states[-1][0, -1]) assert logits.shape == (len(rows), 512), "one vocabulary row per variant, not per position" assert (hidden is not None) == want_hidden + + +class TinyTokenizer: + """Ids inside the tiny vocabulary; space-prefixed A-Z are single tokens, as label codes need.""" + + pad_token_id = 0 + single = {f" {c}": 400 + i for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ")} + + def encode(self, text, add_special_tokens=True): + return ( + [self.single[text]] if text in self.single else [ord(c) % 300 + 2 for c in text] or [1] + ) + + +def test_without_score_averaging_a_large_request_answers_as_with_no_limit(tiny_model): + """The row limit never touches a request Score averaging did not grow (ADR-029).""" + from lev.types import Choice, Score + + questions = { + **{ + f"c{i}": Choice(criteria={"a": None, "b": None, "c": None, "d": None}) + for i in range(20) + }, + **{f"s{i}": Score(criteria=["low", "mid", "high"]) for i in range(40)}, + } + limited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig()) + unlimited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig(max_request_rows=None)) + assert limited.prepare("state", questions).rows == 80 > limited.config.max_request_rows + assert limited.system_one("state", questions) == unlimited.system_one("state", questions) diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 410a65e..91ff55c 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -397,6 +397,12 @@ def test_schema_first_is_one_row_per_question(self, rich_tokenizer): assert engine.prepare("s", QUESTIONS).rows == len(QUESTIONS) +BIG = { + **{f"c{i}": Choice(criteria={"a": None, "b": None, "c": None, "d": None}) for i in range(20)}, + **{f"s{i}": Score(criteria=["low", "mid", "high"]) for i in range(40)}, +} + + class TestRequestRowLimit: def engine(self, tokenizer, **config) -> DecisionEngine: return DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) @@ -404,10 +410,23 @@ def engine(self, tokenizer, **config) -> DecisionEngine: def test_a_request_past_the_limit_is_refused_before_any_forward(self, rich_tokenizer): questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(4)} engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=11) - with pytest.raises(ValueError, match="needs 12 batch rows, above max_request_rows=11"): + with pytest.raises(ValueError, match="needs 12 batch rows, 8 of them from"): engine.prepare("s", questions) assert self.engine(rich_tokenizer, max_request_rows=11).prepare("s", questions).rows == 4 + def test_without_score_averaging_a_large_request_is_never_refused(self, rich_tokenizer): + """#4's batcher runs an oversized request alone and unsplit, so main accepts it.""" + prepared = self.engine(rich_tokenizer).prepare("s", BIG) + assert prepared.rows == 80 > MAX_REQUEST_ROWS + assert [v.order for v in prepared.variants] == [None, [3, 2, 1, 0]] * 20 + [None] * 40 + + def test_only_rows_score_averaging_adds_can_refuse(self, rich_tokenizer): + engine = self.engine(rich_tokenizer, score_order_average="cyclic") + with pytest.raises(ValueError, match="needs 160 batch rows, 80 of them"): + engine.prepare("s", BIG) + choices = {k: q for k, q in BIG.items() if k.startswith("c")} + assert engine.prepare("s", choices).rows == 40 + def test_none_is_no_limit(self, rich_tokenizer): questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(30)} engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=None) From 3136a79ce5473b743df4a93ce7c7592de6390be0 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Mon, 5 Oct 2026 12:44:25 +0900 Subject: [PATCH 08/39] ADR-029: Score's first-slot rate is a reference, not evidence for averaging In the chat style a Score line names its level by its place in the request, so the probe's permuted listings renumber the levels as well as move them. The evidence for averaging is labelled accuracy, RPS and ECE. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- docs/DECISIONS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 7994eda..0b50de8 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -601,7 +601,7 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode Every result is reported whichever way it goes, including accuracy that does not improve. -**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error, and by the first-slot rate on real options. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows Score averaging may add to a request. +**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error. Score's first-slot rate on real options is kept as a reference only: in the chat style the release uses, the probe's permuted listings renumber the levels as well as move them. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows Score averaging may add to a request. **Evidence.** Run 2026-10-04/05 on `interfaze-ai/lev` (HF 7bdc748: the weights and calibration of f8ef711, only README.md changed), bf16, one RTX 5090, this branch rebased on main after #4. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json); the committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. @@ -616,7 +616,7 @@ The bias of one read: identical-option control, slot 0 minus the mean (gate -0.2 Choice, read once, avoids slot 0 more than Score does; it is already read in two orders when served, and the first-slot rate below is what that leaves. -What averaging changes. The benches' three questions per request (4-way Choice, 3-level Score, Noul), shipped calibration; Score ECE over 15 equal-width bins. First-slot rate over all six orders of three real options, ties split (1/3 is order-free), and `consistent`, the share of states whose six orders give one answer: +What averaging changes. The benches' three questions per request (4-way Choice, 3-level Score, Noul), shipped calibration; Score ECE over 15 equal-width bins. For reference, the first-slot rate over all six orders of three real options, ties split (1/3 is order-free), and `consistent`, the share of states whose six orders give one answer: ```text Score Choice Noul From 79d9451f77dd8516be767a97b6b6b26d9e1d9fd3 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Mon, 5 Oct 2026 14:13:29 +0900 Subject: [PATCH 09/39] Remove the _eager_model reference that #4's description pointed out _weights_dtype read engine._eager_model, which #4 removed; it now reads the dtype from engine.model only, the fallback that already gave the right value. A test pins bf16. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- packages/lev/src/lev/cli.py | 2 +- packages/lev/tests/test_presentation.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 5e5cb2b..4a9fe8c 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -244,7 +244,7 @@ def _snapshot_revision(checkpoint) -> str | None: def _weights_dtype(engine) -> str | None: - model = getattr(engine, "_eager_model", None) or getattr(engine, "model", None) + model = getattr(engine, "model", None) try: return str(next(model.parameters()).dtype) except (AttributeError, StopIteration, TypeError): diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 91ff55c..7ae072b 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -483,6 +483,16 @@ def committed(self, monkeypatch, tmp_path, engine, **edit) -> str: path.write_text(json.dumps(saved), "utf-8") return str(path) + def test_the_weights_dtype_comes_from_the_engine_model(self): + torch = pytest.importorskip("torch") + from types import SimpleNamespace + + from lev.cli import _weights_dtype + + model = torch.nn.Linear(2, 2).to(torch.bfloat16) + assert _weights_dtype(SimpleNamespace(model=model)) == "torch.bfloat16" + assert _weights_dtype(SimpleNamespace(model=None)) is None + def test_the_settings_split_at_the_load(self): assert set(PRE_LOAD).isdisjoint(POST_LOAD) assert set(POST_LOAD) == {"checkpoint_revision", "dtype"} From b61852980cd9f1d86966453f9fed616f304de5a1 Mon Sep 17 00:00:00 2001 From: hiroki-abe-58 Date: Mon, 5 Oct 2026 14:50:50 +0900 Subject: [PATCH 10/39] Bound Score-averaged requests by the batcher's token budget, not by rows CodeRabbit (review 5410274149) pointed out that a row count does not bound a request's memory: long states need fewer rows to fill the card (16 single-order rows of 2,124 tokens already spilled). `prepare` now refuses a request only when Score averaging added rows to it and its padded tokens (rows x widest row) pass `max_batch_tokens`, the same 16384-token budget #4's batcher uses; the server passes its own value to the engine, so the two always agree, and /health reports it. Requests without averaged Score rows are never refused (an 80-row request still answers exactly as on main). Removed: `max_request_rows`, `MAX_REQUEST_ROWS`, `lev serve --max-request-rows`, and its /health field. Added: `EngineConfig.max_batch_tokens`, `MAX_BATCH_TOKENS`, `lev.load(max_batch_tokens=)`. The probe sizes its own calls (`--max-rows`, 32) and lifts the serving limit for them. On an RTX 5090 the largest admitted averaged request peaked at 13.1-19.8 GiB reserved at 474-4,124-token rows and 25.8 GiB at 5,423; at 8,124-token rows it reached the card's edge, as one unaveraged Choice question does on the same state (ADR-029). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VyLpqwg29AwAk4YfyeTqxP --- data/adr-029-summary.json | 121 +++++++++++++++++++++- docs/ARCHITECTURE.md | 2 +- docs/DECISIONS.md | 25 +++-- packages/lev/src/lev/batcher.py | 4 +- packages/lev/src/lev/cli.py | 21 +--- packages/lev/src/lev/model.py | 46 ++++---- packages/lev/src/lev/presentation.py | 28 +++-- packages/lev/src/lev/server.py | 9 +- packages/lev/tests/test_engine_forward.py | 10 +- packages/lev/tests/test_presentation.py | 96 +++++++++++------ 10 files changed, 262 insertions(+), 100 deletions(-) diff --git a/data/adr-029-summary.json b/data/adr-029-summary.json index bcc3e7f..3348833 100644 --- a/data/adr-029-summary.json +++ b/data/adr-029-summary.json @@ -587,7 +587,126 @@ } ] }, - "request_rows_rtx5090": { + "averaged_token_budget_rtx5090": { + "what": "the largest Score-averaged request max_batch_tokens (16384) admits, by row length: averaged Score questions topped up with one-row Noul; one question more is refused in every case. The value is the batcher's budget; this only checks it.", + "results": [ + { + "state_tokens": 350, + "mode": "reversed", + "score_questions": 17, + "noul_questions": 0, + "rows": 34, + "width": 474, + "padded_tokens": 16116, + "one_more_refused": true, + "seconds": 1.686, + "peak_allocated_gib": 12.1, + "peak_reserved_gib": 14.62 + }, + { + "state_tokens": 350, + "mode": "cyclic", + "score_questions": 11, + "noul_questions": 1, + "rows": 34, + "width": 474, + "padded_tokens": 16116, + "one_more_refused": true, + "seconds": 1.653, + "peak_allocated_gib": 12.18, + "peak_reserved_gib": 14.63 + }, + { + "state_tokens": 2000, + "mode": "reversed", + "score_questions": 3, + "noul_questions": 1, + "rows": 7, + "width": 2124, + "padded_tokens": 14868, + "one_more_refused": true, + "seconds": 1.539, + "peak_allocated_gib": 11.7, + "peak_reserved_gib": 14.03 + }, + { + "state_tokens": 2000, + "mode": "cyclic", + "score_questions": 2, + "noul_questions": 1, + "rows": 7, + "width": 2124, + "padded_tokens": 14868, + "one_more_refused": true, + "seconds": 1.527, + "peak_allocated_gib": 11.7, + "peak_reserved_gib": 14.03 + }, + { + "state_tokens": 4000, + "mode": "reversed", + "score_questions": 1, + "noul_questions": 1, + "rows": 3, + "width": 4124, + "padded_tokens": 12372, + "one_more_refused": true, + "seconds": 1.387, + "peak_allocated_gib": 11.09, + "peak_reserved_gib": 13.06 + }, + { + "state_tokens": 4000, + "mode": "cyclic", + "score_questions": 1, + "noul_questions": 0, + "rows": 3, + "width": 4124, + "padded_tokens": 12372, + "one_more_refused": true, + "seconds": 1.998, + "peak_allocated_gib": 16.29, + "peak_reserved_gib": 19.84 + }, + { + "state_tokens": 5300, + "mode": "cyclic", + "score_questions": 1, + "noul_questions": 0, + "rows": 3, + "width": 5423, + "padded_tokens": 16269, + "one_more_refused": true, + "seconds": 2.776, + "peak_allocated_gib": 21.72, + "peak_reserved_gib": 25.83 + }, + { + "state_tokens": 8000, + "mode": "reversed", + "score_questions": 1, + "noul_questions": 0, + "rows": 2, + "width": 8124, + "padded_tokens": 16248, + "one_more_refused": true, + "seconds": 18.927, + "peak_allocated_gib": 27.72, + "peak_reserved_gib": 31.68 + } + ], + "averaging_off_one_choice_8000_tokens": { + "what": "averaging off (default), one Choice question read in two orders", + "state_tokens": 8000, + "rows": 2, + "width": 8109, + "padded_tokens": 16218, + "seconds": 30.932, + "peak_allocated_gib": 27.66, + "peak_reserved_gib": 31.63 + } + }, + "rows_without_a_limit_rtx5090": { "what": "one system_one request of R single-order Score rows; peak CUDA memory in GiB (bf16 weights alone are ~8.1). Past ~31 GiB reserved, Windows spills into shared system memory instead of raising out-of-memory, and the request slows 5-10x.", "bench_row_tokens": { "bench_en": { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a355809..770e9bf 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -201,7 +201,7 @@ LoRA r32 on `q,k,v,o,gate,up,down` ≈ 25–40 M trainable parameters. **The Fam - they get **separate fitted temperatures** — one global scalar would be wrong for at least one of them; - on option sets where **both** are valid we measure agreement. Material disagreement means the router is a correctness hazard, not merely a capacity switch. This is an explicit eval, not an assumption. -**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `order_average=False` reads every question once. A request that Score averaging grows past `max_request_rows` batch rows (32 by default) is refused in `prepare`, before any GPU work; one without averaged Score rows never is, since the batcher runs an oversized request alone (ADR-030). `lev presentation-checks` measures the position bias of one read, the bias averaging has to remove (ADR-029). +**Order averaging** (added in the build, not in the original design). Under Mode A with the state-first layout, Choice and binary Noul are read in their shown order and reversed, and the two distributions are averaged in canonical order (ADR-020). Score keeps its level order by default; `EngineConfig.score_order_average` opts it into the reversed order or every rotation, at 2x or Kx rows, and `order_average=False` reads every question once. A request that Score averaging grew is refused in `prepare`, before any GPU work, when its padded tokens pass `max_batch_tokens` (16384, the batcher's budget; the server passes its own value to the engine); one without averaged Score rows never is, since the batcher runs an oversized request alone (ADR-030). `lev presentation-checks` measures the position bias of one read, the bias averaging has to remove (ADR-029). ### 5.4 Output types diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 0b50de8..9b6e762 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -601,7 +601,7 @@ Serving now skips by default; training does not, so Mode B keeps its data. Mode Every result is reported whichever way it goes, including accuracy that does not improve. -**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error. Score's first-slot rate on real options is kept as a reference only: in the chat style the release uses, the probe's permuted listings renumber the levels as well as move them. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine bounds the rows Score averaging may add to a request. +**Revised after review (2026-10-02).** The first runs read the identical-option control after averaging, where `cyclic` makes it zero by construction and `reversed` cannot see the middle slots, so it was no evidence for averaging. The control now measures the bias of one read, before any averaging (`order_average=False`); what averaging changes is judged by labelled accuracy, RPS and calibration error. Score's first-slot rate on real options is kept as a reference only: in the chat style the release uses, the probe's permuted listings renumber the levels as well as move them. Also changed: Choice keys are shapes with no order (■ ● ◆ ▲ ◎), read under every key-to-slot assignment so a key's own pull cancels; argmax ties split between the tied slots; calls are cut by the engine's own row count; and the engine refuses a request Score averaging grew past the batcher's token budget. **Evidence.** Run 2026-10-04/05 on `interfaze-ai/lev` (HF 7bdc748: the weights and calibration of f8ef711, only README.md changed), bf16, one RTX 5090, this branch rebased on main after #4. The numbers behind every table are in [`data/adr-029-summary.json`](../data/adr-029-summary.json); the committed report CI compares against is [`data/presentation-checks.json`](../data/presentation-checks.json). `bench_ja` is Japanese, outside Lev's target language, so its rows are a reference only; `bench_en` is the one that bears on the decision. @@ -646,20 +646,23 @@ Calibration of the averaged modes. The shipped Score temperature (2.80) was fitt On bench_en a refit gains nothing for either averaged mode (held-out NLL within 0.001), and the shipped temperature is if anything a little sharp for `off`. On the Japanese reference the refit goes the other way for the averaged modes. A per-mode temperature is not proposed. -The rows Score averaging may add (`max_request_rows`, default 32). One `system_one` request of R single-order Score rows; peak CUDA memory on the RTX 5090, GiB (the bf16 weights alone are ~8.1). The benches' rows are at most 509 tokens (en) and 526 (ja): +The batch budget for averaged requests (`max_batch_tokens`, 16384). The batcher does not split a request: on main, 20 Choice and 40 Score questions with averaging off ran as one forward of 80 rows, up to 35,680 padded tokens. So `prepare` refuses only a request that Score averaging grew, when its padded tokens (rows x widest row) pass the batcher's own budget; the server passes its `max_batch_tokens` to the engine, so the two always agree, and a request without averaged Score rows is never refused (the 80-row request above answers exactly as on main). The value is the batcher's; this run only checks it on the RTX 5090, with the largest averaged request the budget admits at each row length, averaged Score questions topped up with one-row Noul (one question more is refused in every case): ```text - row tokens rows reserved seconds - 474 32 14.2 1.6 - 474 64 20.3 3.3 - 474 96 26.4 5.3 - 474 128 32.5 60.0 past the card: Windows spills into system memory - 824 48 27.5 4.3 - 1124 32 27.1 3.9 - 2124 16 30.1 12.3 spilling + row tokens mode rows padded tokens reserved GiB seconds + 474 reversed 34 16,116 14.6 1.7 + 474 cyclic 34 16,116 14.6 1.7 + 2,124 reversed 7 14,868 14.0 1.5 + 2,124 cyclic 7 14,868 14.0 1.5 + 4,124 reversed 3 12,372 13.1 1.4 + 4,124 cyclic 3 12,372 19.8 2.0 + 5,423 cyclic 3 16,269 25.8 2.8 + 8,124 reversed 2 16,248 31.7 18.9 at the card's edge, slow ``` -Memory grows with rows times row length, and faster for long rows, so the limit is set for bench-length requests: 32 rows of ~510 tokens is about the batcher's 16384-token budget (ADR-030). The batcher does not split a request: on main, 20 Choice and 40 Score questions with averaging off ran as one forward of 80 rows, up to 35,680 padded tokens. So the limit refuses only a request that Score averaging grows past it, and never one without averaged Score rows; that 80-row request gets answers identical to main's. A full presentation run with 64-row calls filled the card on bench_en (32 GB in use, 100% busy, no result after 22 minutes) and was stopped; with 32-row calls the six runs peaked at 22.5 GiB reserved, about 50 minutes each. +Rows of ~5,400 tokens fit with room to spare. At ~8,100-token rows attention outgrows the token count: the admitted request reached the edge of the 32 GB card and took 18.9 s. Averaging is not the cause there: one Choice question on the same state with averaging off, read in two orders as always, needs the same (31.6 GiB reserved, 30.9 s). A row count could not have bounded this either: in a first measurement without any limit, 16 single-order rows of 2,124 tokens already spilled (30.1 GiB reserved, 12.3 s). + +The probe's own calls hold at most 32 rows (`--max-rows`, a measurement setting): a full presentation run with 64-row calls filled the card on bench_en (32 GB in use, 100% busy, no result after 22 minutes) and was stopped; with 32-row calls the six runs peaked at 22.5 GiB reserved, about 50 minutes each. With averaging off, every answer on 20 items of each bench (40 responses each, the probe included) is identical to main at 8ca94b7. Asking the probe's questions together or alone differs by up to |Δp| 0.038 (bench_en) and 0.041 (bench_ja), so the committed report records `max_rows`. diff --git a/packages/lev/src/lev/batcher.py b/packages/lev/src/lev/batcher.py index 648d370..0c92080 100644 --- a/packages/lev/src/lev/batcher.py +++ b/packages/lev/src/lev/batcher.py @@ -14,7 +14,7 @@ from concurrent.futures import Future from dataclasses import dataclass -from .model import DecisionEngine, Prepared +from .model import MAX_BATCH_TOKENS, DecisionEngine, Prepared from .types import SystemOneResponse @@ -42,7 +42,7 @@ def __init__( self, engine: DecisionEngine, max_pending: int = 64, - max_batch_tokens: int = 16384, + max_batch_tokens: int = MAX_BATCH_TOKENS, timeout: float = 30.0, ): self.engine = engine diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 4a9fe8c..9e78631 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -217,11 +217,6 @@ def cmd_serve(args: argparse.Namespace) -> None: max_pending=args.max_pending, max_batch_tokens=args.max_batch_tokens, score_order_average=args.score_order_average, - **( - {"max_request_rows": args.max_request_rows} - if args.max_request_rows is not None - else {} - ), ), host=args.host, port=args.port, @@ -259,11 +254,11 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: from . import presentation from .calibrate import CalibrationProfile - from .model import MAX_REQUEST_ROWS, load + from .model import load states = presentation.read_states(args.states)[: args.limit] kinds = [k.strip() for k in args.kinds.split(",") if k.strip()] - max_rows = args.max_rows or MAX_REQUEST_ROWS + max_rows = args.max_rows or presentation.MAX_ROWS settings = { "n_states": len(states), "lang": args.lang, @@ -280,7 +275,6 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: cache_dir=args.model_cache, calibration=args.calibration, score_order_average=args.score_order_average, - max_request_rows=max(max_rows, MAX_REQUEST_ROWS), ) if args.raw: engine.calibration = CalibrationProfile() @@ -421,13 +415,8 @@ def main(argv: list[str] | None = None) -> None: "--max-batch-tokens", type=int, default=16384, - help="padded tokens per batched forward across requests (default 16384)", - ) - serve_parser.add_argument( - "--max-request-rows", - type=int, - default=None, - help="refuse (422) a request Score averaging grows past this many batch rows (default 32)", + help="padded tokens per batched forward, and the most a request Score averaging grew " + "may need (default 16384)", ) serve_parser.add_argument( "--score-order-average", @@ -464,7 +453,7 @@ def main(argv: list[str] | None = None) -> None: "--max-rows", type=int, default=None, - help="batch rows per call, as the engine counts them (default: max_request_rows)", + help="batch rows per probe call, as the engine counts them (default 32)", ) presentation_parser.add_argument("--slot0-min", type=float, default=-0.20) presentation_parser.add_argument("--out", default=None, help="write the report JSON here") diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index 3072f74..1255222 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -33,8 +33,9 @@ _QUESTIONS = TypeAdapter(dict[str, Question]) -# Bench-length rows (~500 tokens) x 32 is about the batcher's 16384-token budget (ADR-029). -MAX_REQUEST_ROWS = 32 +# Padded tokens (rows x widest row) per forward: `lev.batcher`'s budget, and the most a +# request Score averaging grew may need (ADR-029, ADR-030). +MAX_BATCH_TOKENS = 16384 @dataclass @@ -53,9 +54,9 @@ class EngineConfig: # adds the reversed order (2 rows per Score, as Choice), "cyclic" every rotation (K rows). # Both show the model level orders training never produces (ADR-020, FINDINGS §12). score_order_average: Literal["off", "reversed", "cyclic"] = "off" - # Rows a request may need once Score averaging adds rows to it; `prepare` refuses - # more with a ValueError (HTTP 422). Requests without added rows are never refused. - max_request_rows: int | None = MAX_REQUEST_ROWS + # A request whose Score averaging added rows must fit this many padded tokens; `prepare` + # refuses it otherwise (HTTP 422). Requests without added Score rows are never refused. + max_batch_tokens: int | None = MAX_BATCH_TOKENS # Serving can skip split codes; training keeps large sets for Mode B (ADR-028). skip_multi_token_codes: bool = True # Forking avoids repeated prefix work but adds a forward and cache copies (ADR-023). @@ -229,20 +230,6 @@ def question_rows(self, questions: Mapping[str, Question | dict]) -> dict[str, i def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared: routes = serving_routes(questions, self.tokenizer, self.config) - orders = {name: self._orders(q, routes[name]) for name, q in questions.items()} - rows = sum(len(o) for o in orders.values()) - added = sum(len(o) - 1 for name, o in orders.items() if isinstance(questions[name], Score)) - limit = self.config.max_request_rows - # The batcher runs an oversized request alone and unsplit; refuse only the rows - # Score averaging adds, so a request main accepts is never refused for its size. - if limit is not None and added and rows > limit: - raise ValueError( - f"this request needs {rows} batch rows, {added} of them from " - f"score_order_average={self.config.score_order_average!r}, above " - f"max_request_rows={limit}; send fewer Score questions per request, " - "or average fewer orders" - ) - unsupported = [ name for name, r in routes.items() @@ -257,7 +244,22 @@ def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared prefix, variants = self._render(state, questions, routes) prefix_ids = self.tokenizer.encode(prefix, add_special_tokens=True) - return Prepared(questions, routes, prefix_ids, variants) + prepared = Prepared(questions, routes, prefix_ids, variants) + added = sum( + 1 for v in variants if v.order is not None and isinstance(questions[v.name], Score) + ) + limit = self.config.max_batch_tokens + # The batcher runs an oversized request alone and unsplit; refuse only one that + # Score averaging grew, so a request main accepts is never refused for its size. + if limit is not None and added and prepared.rows * prepared.width > limit: + raise ValueError( + f"this request needs {prepared.rows} rows x {prepared.width} tokens = " + f"{prepared.rows * prepared.width} padded tokens, {added} of the rows from " + f"score_order_average={self.config.score_order_average!r}, above " + f"max_batch_tokens={limit}; send fewer Score questions or a shorter state, " + "or average fewer orders" + ) + return prepared def answer(self, requests: list[Prepared]) -> list[SystemOneResponse]: """Answer prepared requests, in single prefix mode all in one forward. @@ -561,7 +563,7 @@ def load( max_label_options: int | None = None, skip_multi_token_codes: bool = True, score_order_average: Literal["off", "reversed", "cyclic"] = "off", - max_request_rows: int | None = MAX_REQUEST_ROWS, + max_batch_tokens: int | None = MAX_BATCH_TOKENS, ) -> DecisionEngine: """Load a checkpoint -- a release directory, a training output or a Hub id -- into a ready `DecisionEngine`. With no checkpoint, serves `model_id` frozen. @@ -638,7 +640,7 @@ def load( max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, score_order_average=score_order_average, - max_request_rows=max_request_rows, + max_batch_tokens=max_batch_tokens, ) engine = DecisionEngine(model, tokenizer, config, profile, mode_b_head=head) engine.checkpoint = resolved diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py index 6e3d68b..835002b 100644 --- a/packages/lev/src/lev/presentation.py +++ b/packages/lev/src/lev/presentation.py @@ -41,6 +41,8 @@ KEYS = ("■", "●", "◆", "▲", "◎") SLOT0_MIN = -0.20 FIRST_SLOT_MIN = 0.15 +# Batch rows per probe call: a full bench_en run peaked at 22.5 GiB reserved on a 32 GB card. +MAX_ROWS = 32 # en follows Laya's presentation_checks.py; ja the same wording in Japanese. TEXT: dict[str, dict[str, Any]] = { @@ -125,16 +127,21 @@ def is_identical(qid: str) -> bool: @contextmanager -def single_order(engine) -> Iterator[None]: - """Read every question once, in the order given.""" +def configured(engine, **changes) -> Iterator[None]: + """Run the block with `engine.config` changed as given, then restore it.""" config = engine.config - engine.config = replace(config, order_average=False) + engine.config = replace(config, **changes) try: yield finally: engine.config = config +def single_order(engine): + """Read every question once, in the order given.""" + return configured(engine, order_average=False) + + def call_groups(engine, questions: dict[str, dict], max_rows: int) -> list[dict[str, dict]]: """`questions` split into `system_one` calls of at most `max_rows` batch rows, as the engine counts them under its current config.""" @@ -161,9 +168,8 @@ def ask( max_rows: int | None = None, ) -> list[dict[str, Any]]: """Every probe answer for every state: the identical questions in one order, the - permuted ones as the engine is configured. Calls hold at most `max_rows` batch rows, - the engine's `max_request_rows` by default.""" - max_rows = max_rows or engine.config.max_request_rows + permuted ones as the engine is configured. Calls hold at most `max_rows` batch rows.""" + max_rows = max_rows or MAX_ROWS questions = probe_questions(lang, kinds) identical = {q: v for q, v in questions.items() if is_identical(q)} permuted = {q: v for q, v in questions.items() if not is_identical(q)} @@ -176,8 +182,11 @@ def ask( with single_order(engine): for group in identical_groups: got.update(engine.system_one(state, group).answers) - for group in permuted_groups: - got.update(engine.system_one(state, group).answers) + # The probe sizes its own calls; the serving limit would refuse its averaged + # calls on long states. + with configured(engine, max_batch_tokens=None): + for group in permuted_groups: + got.update(engine.system_one(state, group).answers) answers.append(got) return answers @@ -283,7 +292,8 @@ def packed_consistency( with single_order(engine): alone = engine.system_one(state, {qid: question}).answers[qid] else: - alone = engine.system_one(state, {qid: question}).answers[qid] + with configured(engine, max_batch_tokens=None): + alone = engine.system_one(state, {qid: question}).answers[qid] for a, b in zip( slot_probs(packed[qid], question), slot_probs(alone, question), strict=True ): diff --git a/packages/lev/src/lev/server.py b/packages/lev/src/lev/server.py index 90c045b..ec9c24a 100644 --- a/packages/lev/src/lev/server.py +++ b/packages/lev/src/lev/server.py @@ -13,7 +13,7 @@ from fastapi import Request from .batcher import Batcher, ClientGone, Overloaded, WorkerStopped -from .model import MAX_REQUEST_ROWS, load +from .model import MAX_BATCH_TOKENS, load from .types import SystemOneRequest, SystemOneResponse @@ -28,10 +28,9 @@ def create_app( prompt_style: Literal["plain", "chat"] | None = None, skip_multi_token_codes: bool = True, max_pending: int = 64, - max_batch_tokens: int = 16384, + max_batch_tokens: int = MAX_BATCH_TOKENS, timeout: float = 30.0, score_order_average: Literal["off", "reversed", "cyclic"] = "off", - max_request_rows: int | None = MAX_REQUEST_ROWS, ) -> Any: from fastapi import FastAPI, HTTPException, Response from starlette.concurrency import run_in_threadpool @@ -54,7 +53,7 @@ def _load() -> None: max_label_options=max_label_options, skip_multi_token_codes=skip_multi_token_codes, score_order_average=score_order_average, - max_request_rows=max_request_rows, + max_batch_tokens=max_batch_tokens, ) state["batcher"] = Batcher( engine, max_pending=max_pending, max_batch_tokens=max_batch_tokens, timeout=timeout @@ -78,7 +77,7 @@ async def health() -> dict: "max_label_options": config.max_label_options, "order_average": config.order_average, "score_order_average": config.score_order_average, - "max_request_rows": config.max_request_rows, + "max_batch_tokens": config.max_batch_tokens, "prefix_mode": config.prefix_mode, "compiled": config.compile, "prompt_style": config.prompt_style, diff --git a/packages/lev/tests/test_engine_forward.py b/packages/lev/tests/test_engine_forward.py index bc679da..b2d9dcf 100644 --- a/packages/lev/tests/test_engine_forward.py +++ b/packages/lev/tests/test_engine_forward.py @@ -62,7 +62,7 @@ def encode(self, text, add_special_tokens=True): def test_without_score_averaging_a_large_request_answers_as_with_no_limit(tiny_model): - """The row limit never touches a request Score averaging did not grow (ADR-029).""" + """The token limit never touches a request Score averaging did not grow (ADR-029).""" from lev.types import Choice, Score questions = { @@ -73,6 +73,8 @@ def test_without_score_averaging_a_large_request_answers_as_with_no_limit(tiny_m **{f"s{i}": Score(criteria=["low", "mid", "high"]) for i in range(40)}, } limited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig()) - unlimited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig(max_request_rows=None)) - assert limited.prepare("state", questions).rows == 80 > limited.config.max_request_rows - assert limited.system_one("state", questions) == unlimited.system_one("state", questions) + unlimited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig(max_batch_tokens=None)) + state = "a long support message " * 16 + prepared = limited.prepare(state, questions) + assert prepared.rows == 80 and prepared.rows * prepared.width > limited.config.max_batch_tokens + assert limited.system_one(state, questions) == unlimited.system_one(state, questions) diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 7ae072b..9f58e30 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -8,6 +8,7 @@ from __future__ import annotations +import inspect import json import math from pathlib import Path @@ -15,11 +16,12 @@ import pytest from lev import ChoiceAnswer, Score, ScoreAnswer, SystemOneRequest, SystemOneResponse, Usage -from lev.model import MAX_REQUEST_ROWS, DecisionEngine, EngineConfig, average_orders +from lev.model import MAX_BATCH_TOKENS, DecisionEngine, EngineConfig, average_orders from lev.presentation import ( IDENTICAL_KS, KEYS, KINDS, + MAX_ROWS, POST_LOAD, PRE_LOAD, SLOT0_MIN, @@ -114,7 +116,7 @@ def system_one(self, state, questions): return SystemOneResponse(model="fake", answers=answers, usage=Usage(input_tokens=1)) -def run(engine, states, lang="en", kinds=KINDS, max_rows=MAX_REQUEST_ROWS, slot0_min=SLOT0_MIN): +def run(engine, states, lang="en", kinds=KINDS, max_rows=MAX_ROWS, slot0_min=SLOT0_MIN): return report(ask(engine, states, lang, kinds, max_rows), lang, kinds, slot0_min) @@ -376,7 +378,6 @@ def test_it_matches_prepare(self, poor_tokenizer, mode, order_average, noul_read score_order_average=mode, order_average=order_average, noul_readout=noul_readout, - max_request_rows=None, ), mode_b_head=object(), ) @@ -403,48 +404,85 @@ def test_schema_first_is_one_row_per_question(self, rich_tokenizer): } -class TestRequestRowLimit: +LONG = "x" * 6000 + + +class TestAveragedTokenLimit: + """Only a request Score averaging grew can be refused, and only past the batch budget.""" + def engine(self, tokenizer, **config) -> DecisionEngine: return DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) - def test_a_request_past_the_limit_is_refused_before_any_forward(self, rich_tokenizer): - questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(4)} - engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=11) - with pytest.raises(ValueError, match="needs 12 batch rows, 8 of them from"): - engine.prepare("s", questions) - assert self.engine(rich_tokenizer, max_request_rows=11).prepare("s", questions).rows == 4 + def test_a_long_state_with_few_averaged_rows_is_refused(self, rich_tokenizer): + question = {"urgency": Score(criteria=["low", "mid", "high"])} + engine = self.engine(rich_tokenizer, score_order_average="cyclic") + with pytest.raises( + ValueError, match="2 of the rows from score_order_average='cyclic', above" + ): + engine.prepare(LONG, question) + assert engine.prepare("short", question).rows == 3 + assert self.engine(rich_tokenizer).prepare(LONG, question).rows == 1 def test_without_score_averaging_a_large_request_is_never_refused(self, rich_tokenizer): """#4's batcher runs an oversized request alone and unsplit, so main accepts it.""" - prepared = self.engine(rich_tokenizer).prepare("s", BIG) - assert prepared.rows == 80 > MAX_REQUEST_ROWS + prepared = self.engine(rich_tokenizer).prepare("x" * 400, BIG) + assert prepared.rows == 80 and prepared.rows * prepared.width > MAX_BATCH_TOKENS assert [v.order for v in prepared.variants] == [None, [3, 2, 1, 0]] * 20 + [None] * 40 - def test_only_rows_score_averaging_adds_can_refuse(self, rich_tokenizer): + def test_only_a_request_score_averaging_grew_can_be_refused(self, rich_tokenizer): engine = self.engine(rich_tokenizer, score_order_average="cyclic") - with pytest.raises(ValueError, match="needs 160 batch rows, 80 of them"): - engine.prepare("s", BIG) + with pytest.raises(ValueError, match="80 of the rows from"): + engine.prepare("x" * 400, BIG) choices = {k: q for k, q in BIG.items() if k.startswith("c")} - assert engine.prepare("s", choices).rows == 40 + assert engine.prepare("x" * 400, choices).rows == 40 - def test_none_is_no_limit(self, rich_tokenizer): - questions = {f"q{i}": Score(criteria=["a", "b", "c"]) for i in range(30)} - engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=None) - assert engine.prepare("s", questions).rows == 90 - assert EngineConfig().max_request_rows == MAX_REQUEST_ROWS + def test_none_is_no_limit_and_the_default_is_the_batchers(self, rich_tokenizer): + from lev.batcher import Batcher - def test_the_server_answers_422(self, monkeypatch, rich_tokenizer): + question = {"urgency": Score(criteria=["low", "mid", "high"])} + engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_batch_tokens=None) + assert engine.prepare(LONG, question).rows == 3 + default = inspect.signature(Batcher).parameters["max_batch_tokens"].default + assert EngineConfig().max_batch_tokens == MAX_BATCH_TOKENS == default == 16384 + + def serve(self, monkeypatch, tokenizer, **create): pytest.importorskip("fastapi") from fastapi.testclient import TestClient from lev import server - engine = self.engine(rich_tokenizer, score_order_average="cyclic", max_request_rows=5) - monkeypatch.setattr(server, "load", lambda *a, **k: engine) + seen = {} + + def load(*a, **kwargs): + seen["engine"] = self.engine( + tokenizer, score_order_average="cyclic", max_batch_tokens=kwargs["max_batch_tokens"] + ) + return seen["engine"] + + def batcher(engine, **kwargs): + seen["batcher"] = kwargs["max_batch_tokens"] + return real_batcher(engine, **kwargs) + + real_batcher = server.Batcher + monkeypatch.setattr(server, "load", load) + monkeypatch.setattr(server, "Batcher", batcher) + return TestClient(server.create_app(**create)), seen + + def test_the_server_gives_its_budget_to_the_engine(self, monkeypatch, rich_tokenizer): + client, seen = self.serve(monkeypatch, rich_tokenizer, max_batch_tokens=1234) + with client: + health = client.get("/health").json() + assert seen["batcher"] == seen["engine"].config.max_batch_tokens == 1234 + assert health["max_batch_tokens"] == 1234 + + def test_the_server_answers_422(self, monkeypatch, rich_tokenizer): + client, _ = self.serve(monkeypatch, rich_tokenizer, max_batch_tokens=500) questions = {f"q{i}": {"type": "score", "criteria": ["a", "b", "c"]} for i in range(2)} - with TestClient(server.create_app()) as client: - response = client.post("/v1/systemone", json={"state": "s", "questions": questions}) + with client: + response = client.post( + "/v1/systemone", json={"state": "x" * 200, "questions": questions} + ) assert response.status_code == 422 - assert "max_request_rows=5" in response.json()["detail"] + assert "max_batch_tokens=500" in response.json()["detail"] class TestCommittedReport: @@ -455,7 +493,7 @@ def test_it_parses_and_carries_every_metric(self): path = Path(__file__).resolve().parents[3] / "data" / "presentation-checks.json" committed = json.loads(path.read_text("utf-8")) assert committed["score_order_average"] == "off" and committed["n_states"] == 290 - assert committed["max_rows"] == MAX_REQUEST_ROWS + assert committed["max_rows"] == MAX_ROWS for kind in KINDS: assert committed["checks"][kind]["identical"]["read"] == "single order" for check in ("identical", "first_slot"): @@ -501,7 +539,7 @@ def test_matching_settings_are_compared_metric_by_metric(self, monkeypatch, tmp_ engine = FakeEngine(slot0=-1.0) path = Path(self.committed(monkeypatch, tmp_path, engine)) saved = json.loads(path.read_text("utf-8")) - assert saved["score_order_average"] == "off" and saved["max_rows"] == MAX_REQUEST_ROWS + assert saved["score_order_average"] == "off" and saved["max_rows"] == MAX_ROWS saved["checks"]["score"]["identical"]["metric"] += 0.5 path.write_text(json.dumps(saved), "utf-8") with pytest.raises(SystemExit) as exc: From 771db93b6f57b6b916c97573e824a241ff9babdc Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Tue, 6 Oct 2026 15:59:56 +0530 Subject: [PATCH 11/39] perf(model): merge the lora adapter when loading --- packages/lev/src/lev/model.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index 1255222..b0a2c09 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -564,6 +564,7 @@ def load( skip_multi_token_codes: bool = True, score_order_average: Literal["off", "reversed", "cyclic"] = "off", max_batch_tokens: int | None = MAX_BATCH_TOKENS, + merge_adapter: bool = True, ) -> DecisionEngine: """Load a checkpoint -- a release directory, a training output or a Hub id -- into a ready `DecisionEngine`. With no checkpoint, serves `model_id` frozen. @@ -614,7 +615,13 @@ def load( if resolved: from peft import PeftModel + # Merged by default: the forward is launch-bound (ADR-023), so the per-layer + # lora_A/lora_B matmuls cost launches rather than arithmetic, and graph + # capture needs the weights fixed. `merge_adapter=False` keeps the adapter + # separate, which is what lets its scale be swept without retraining. model = PeftModel.from_pretrained(model, str(resolved)) + if merge_adapter: + model = model.merge_and_unload() head = _load_head(resolved / MODE_B_HEAD, model) model = model.eval() From f1752fb2d2311249ee0d7b7de283afc7703f73cc Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Tue, 6 Oct 2026 15:59:56 +0530 Subject: [PATCH 12/39] feat(modal): sweep the adapter scale on the rating subsets --- modal/app.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/modal/app.py b/modal/app.py index bf375cc..380634d 100644 --- a/modal/app.py +++ b/modal/app.py @@ -462,6 +462,62 @@ def check_release(name: str = "4b") -> dict: return {"health": health, "response": served} +@app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=2 * 60 * 60) +def diagnose_ordinal( + name: str = "lev", + scales: str = "0,0.25,0.5,0.75,1.0", + subsets: str = "summeval-consistency,summeval-relevance,helpsteer2", +) -> dict: + """Score the rating subsets at several adapter scales, keeping the adapter unmerged. + + summeval-consistency is 0.271 against the frozen backbone's 0.826, so the + regression may be recoverable by scaling the adapter rather than retraining + (WiSE-FT, arXiv 2109.01903, which for a LoRA is just the adapter scale). + Scale 0 must reproduce the frozen backbone; that is the run's own control. + Also reports the argmax histogram, which levbench aggregates away. + """ + import collections + import json + + from lev import load + from lev.data.s1bench import load_eval_subset + from peft.tuners.lora import LoraLayer + + engine = load(f"{RELEASES_DIR}/{name}", cache_dir=MODELS_DIR, merge_adapter=False) + layers = [m for m in engine.model.modules() if isinstance(m, LoraLayer)] + if not layers: + raise RuntimeError("no LoraLayer found; the adapter was merged or never applied") + adapters = sorted({a for m in layers for a in m.scaling}) + print(f"{len(layers)} lora layers, adapters {adapters}") + + data = {s: load_eval_subset(s) for s in subsets.split(",")} + report: dict = {"layers": len(layers), "subsets": {}} + for scale in [float(x) for x in scales.split(",")]: + for m in layers: + for a in m.scaling: + m.set_scale(a, scale) + for subset, (question, items) in data.items(): + hits = 0 + picks: collections.Counter = collections.Counter() + for item in items: + answer = engine.system_one(item.state, {"decision": question}).answers["decision"] + probs = {int(k): float(v) for k, v in answer.probabilities.items()} + pick = max(probs, key=probs.get) + picks[pick] += 1 + hits += pick == item.truth + row = report["subsets"].setdefault(subset, {}) + row[f"{scale:g}"] = { + "accuracy": round(hits / len(items), 4), + "n": len(items), + "argmax": dict(sorted(picks.items())), + } + acc = hits / len(items) + print(f" scale {scale:<5g} {subset:22} {acc:.4f} {dict(sorted(picks.items()))}") + + print(json.dumps(report, indent=2)) + return report + + @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def diagnose_candidates(model_id: str = "Qwen/Qwen3.5-4B-Base") -> dict: """Compare candidate representations alone, batched, reversed and left-padded. From a7e045e6983db07b614bd4a82526a67fcaef0ddf Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Tue, 6 Oct 2026 15:59:56 +0530 Subject: [PATCH 13/39] docs(decisions): correct the torch.compile rejection in ADR-023 --- docs/DECISIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 9b6e762..37d2487 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -482,7 +482,7 @@ Both are flat in the number of questions, which says the forward is bound by ker With `causal_conv1d` present (the image now builds it against `torch 2.14.0+cu130`): fork 140-156 ms, single 65-75 ms -- about 10% each. That the kernel bought so little is the diagnosis confirmed from a second angle: the time is in launching ~200 kernels twice, not in any one of them. What removes launches is CUDA-graph replay, so the engine gains `EngineConfig.compile` (`torch.compile(mode="reduce-overhead", dynamic=True)`) with inputs padded to shape buckets -- width to 32 tokens, rows to a power of two -- so the set of recorded graphs stays small, and a `warmup()` the server runs at startup so no request pays a capture. Padding changes no real row's logits: right padding is masked and rows are independent. The GPU forward is taken under a lock, because graph replay is not thread-safe and the server now accepts concurrent requests; parsing, tokenising and the network overlap around it. -**Compile: measured, rejected.** On the same container, eager single-forward ran 86–94 ms and the compiled path 103–137 ms, after a 104 s warmup; dynamo hit its recompile limit (8) on the hybrid's linear-attention layers, so much of the forward stayed eager with extra guard overhead, and the Mode B shape then failed with a CUDA-graphs output-buffer overwrite when hidden states from one replay were read after the next. The flag stays (`LEV_SERVE_COMPILE=1`) so the measurement can be repeated on a future transformers/FLA release, and defaults off. Getting decider's 8 ms would mean a static-shape engine built for this model, not `torch.compile` over the stock one. +**Compile: measured, rejected.** On the same container, eager single-forward ran 86–94 ms and the compiled path 103–137 ms, after a 104 s warmup; `torch.compile` cannot reach this model's dominant cost at all: FLA decorates `chunk_gated_delta_rule` and `fused_gdn_gate` with `@torch.compiler.disable` (`fla/ops/gated_delta_rule/chunk.py`, `gate.py`), so each of the 24 GDN layers is a permanent graph break and stays eager at full launch cost whatever the mode. What is left to capture is the 8 attention layers, the MLPs and the norms, while every partition boundary copies inputs to static buffers -- overhead without the win. Dynamo's `recompile_limit` (8, per code object, so all 24 GDN layers share one budget) compounded it, and the Mode B shape then failed with a CUDA-graphs output-buffer overwrite when hidden states from one replay were read after the next. `dynamic=True` was not the cause: it does not veto graph capture. The flag stays (`LEV_SERVE_COMPILE=1`) so the measurement can be repeated once FLA lifts the decorator ([fla-org RFC #1155](https://github.com/fla-org/flash-linear-attention/issues/1155) tracks graph capture for the GDN paths), and defaults off. Getting decider's 8 ms means manual `torch.cuda.CUDAGraph` capture over the eager forward, one graph per padded length bucket, warmed eagerly first so the Triton autotune choice is fixed before capture -- not `torch.compile` over the stock model. Also decided here, from the same session's measurements (FINDINGS.md §13): the image builds `causal_conv1d` from a CUDA devel base, since no wheel exists for `torch 2.14.0+cu130` and every log said the reference path was in use; and the serving path was verified correct end to end -- in-distribution accuracy over HTTP matches the collator-path `evaluate` on every source -- so no inference-side error is hiding behind the S1Bench gap. From 724f6e785b3b5fd9c68c5ac550e3bf02da291f22 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Wed, 7 Oct 2026 00:04:35 +0530 Subject: [PATCH 14/39] refactor: tighten comments, docstrings and naming across the repo --- .env.example | 9 +- CONTRIBUTING.md | 2 +- Makefile | 81 ++++---- data/adr-029-summary.json | 24 +-- docs/ARCHITECTURE.md | 4 +- docs/DECISIONS.md | 4 +- docs/charts/build.py | 21 +- docs/charts/levbench_log.py | 4 +- modal/app.py | 117 ++--------- packages/lev/src/lev/__init__.py | 5 - packages/lev/src/lev/batcher.py | 95 +++++---- packages/lev/src/lev/calibrate.py | 174 ++++++++++++----- packages/lev/src/lev/cli.py | 17 +- packages/lev/src/lev/data/build.py | 16 +- packages/lev/src/lev/data/contamination.py | 25 +-- packages/lev/src/lev/data/export_eval.py | 13 +- packages/lev/src/lev/data/mixture.py | 44 ++--- packages/lev/src/lev/data/s1bench.py | 30 +-- packages/lev/src/lev/data/sources.py | 130 +++++-------- packages/lev/src/lev/data/splits.py | 18 +- packages/lev/src/lev/labels.py | 27 +-- packages/lev/src/lev/model.py | 125 ++++-------- packages/lev/src/lev/presentation.py | 59 ++---- packages/lev/src/lev/prompt.py | 44 ++--- packages/lev/src/lev/readout/mode_a.py | 13 +- packages/lev/src/lev/readout/mode_b.py | 16 +- packages/lev/src/lev/release.py | 26 +-- packages/lev/src/lev/router.py | 8 +- packages/lev/src/lev/server.py | 18 +- packages/lev/src/lev/train/calibration_run.py | 16 +- packages/lev/src/lev/train/checkpoints.py | 34 +--- packages/lev/src/lev/train/collate.py | 54 +++--- packages/lev/src/lev/train/config.py | 13 +- packages/lev/src/lev/train/evaluate.py | 12 +- packages/lev/src/lev/train/loop.py | 59 ++---- packages/lev/src/lev/train/progress.py | 10 +- packages/lev/src/lev/types.py | 10 +- packages/lev/tests/conftest.py | 12 +- packages/lev/tests/test_batcher.py | 12 +- packages/lev/tests/test_cache_fork.py | 5 +- packages/lev/tests/test_calibration.py | 20 +- packages/lev/tests/test_collate.py | 15 +- packages/lev/tests/test_contamination.py | 5 +- packages/lev/tests/test_core.py | 41 ++-- packages/lev/tests/test_data_pipeline.py | 95 ++++----- packages/lev/tests/test_engine_forward.py | 1 + packages/lev/tests/test_eval_export.py | 17 +- packages/lev/tests/test_evaluate.py | 4 +- packages/lev/tests/test_loss.py | 11 +- packages/lev/tests/test_packaging.py | 11 +- packages/lev/tests/test_presentation.py | 40 ++-- packages/lev/tests/test_progress.py | 19 +- packages/lev/tests/test_release.py | 6 +- packages/lev/tests/test_s1bench.py | 12 +- packages/lev/tests/test_training_loop.py | 36 ++-- packages/levbench/src/levbench/__init__.py | 6 +- packages/levbench/src/levbench/batching.py | 20 +- packages/levbench/src/levbench/cli.py | 9 +- .../levbench/src/levbench/confidence_id.py | 38 ++-- packages/levbench/src/levbench/metrics.py | 20 +- packages/levbench/src/levbench/pricing.py | 11 +- packages/levbench/src/levbench/runner.py | 40 ++-- .../levbench/src/levbench/snake/__init__.py | 7 +- packages/levbench/src/levbench/snake/game.py | 10 +- .../levbench/src/levbench/snake/policy.py | 18 +- packages/levbench/src/levbench/snake/run.py | 38 ++-- packages/levbench/src/levbench/snake/ui.py | 8 +- packages/levbench/src/levbench/tasks.py | 13 +- packages/levbench/tests/fake_transport.py | 29 ++- packages/levbench/tests/test_offline.py | 181 ++++++++---------- packages/levbench/tests/test_snake.py | 95 +++++---- pyproject.toml | 2 +- scripts/publish_hf.sh | 24 ++- 73 files changed, 904 insertions(+), 1404 deletions(-) diff --git a/.env.example b/.env.example index 4a8a40f..abf1c78 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,6 @@ -# Benchmarking against the hosted Jev API. TYPESAFE_API_KEY= - -# The LLM baseline `levbench compare` measures against. ANTHROPIC_API_KEY= -# Only if you front a local /v1/systemone server with auth. Your real -# TYPESAFE_API_KEY is deliberately never sent to a --base-url host. -# Left commented on purpose: `VAR=` sets the variable to the empty string, -# which is not the same as leaving it unset. +# Optional local-server auth; TYPESAFE_API_KEY is never sent to --base-url hosts. +# Leave commented to keep unset; VAR= assigns an empty string. # LEVBENCH_LOCAL_API_KEY= diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d598c1c..996f384 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ make check # ruff + the full test suite ``` -Both must be clean. Tests run without a GPU, network or API keys. A basic `uv sync` skips tests that need optional model dependencies; use `uv sync --extra train` to include the CPU tensor, cache and training-loop tests. +Both must be clean. Tests run without a GPU, network or API keys. use `uv sync --extra train` to include the CPU tensor, cache and training-loop tests. ## Finding the code diff --git a/Makefile b/Makefile index e3d49b6..808d89a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,15 @@ -# `make help` lists every target. Variables are overridable: `make train PRESET=9b`. +# setup: Install workspace | setup-train: + training deps +# setup-serve: + serving deps | setup-modal: + Modal client + +# test: Run tests | lint: Check code | fmt: Format code +# check: Lint + test | clean: Remove caches + +# smoke-local: CPU smoke test | smoke: Modal H100 smoke test +# train: Full training run | calibrate: Fit temperatures + +# serve: Dev server | deploy: Stable endpoint +# release: Package checkpoint | weights: Pull weights | publish: Push to HF + .DEFAULT_GOAL := help PRESET ?= 4b-instruct @@ -15,111 +26,101 @@ URL ?= http://localhost:8000 FRESH ?= RESUME ?= -help: ## Show this help - @awk 'BEGIN{FS=":.*?## "} \ - /^##@/ {printf "\n\033[1m%s\033[0m\n", substr($$0, 5)} \ - /^[a-zA-Z0-9_-]+:.*?## / {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) - -##@ Setup +help: + @awk '/^#/ {sub(/^# ?/, ""); print; next} /^$$/ {print; next} {exit}' $(MAKEFILE_LIST) .PHONY: setup setup-train setup-serve setup-modal -setup: ## Install the workspace +setup: uv sync -setup-train: ## Install with the training extras (torch, transformers, peft) +setup-train: uv sync --extra train -setup-serve: ## Install with the serving extras (adds fastapi, uvicorn) +setup-serve: uv sync --extra serve -setup-modal: ## Install with the Modal client +setup-modal: uv sync --extra modal -##@ Develop - .PHONY: test lint fmt check clean -test: ## Run every test +test: uv run pytest -lint: ## Check formatting and lint rules +lint: uv run ruff check . uv run ruff format --check . -fmt: ## Apply formatting and autofixes +fmt: uv run ruff check --fix . uv run ruff format . -check: lint test ## Lint then test — run before pushing +check: lint test -clean: ## Remove caches and build artefacts +clean: find . -type d -name __pycache__ -prune -exec rm -rf {} + rm -rf .pytest_cache .ruff_cache dist build -##@ Data .PHONY: plan check-data data eval-set s1bench -plan: ## Print the H100 training budget without spending it +plan: uv run lev plan --preset $(PRESET) -check-data: ## Contamination guard over a source list (SOURCES=path) +check-data: uv run lev check-data $(SOURCES) -data: ## Build the training mixture locally (LIMIT=rows per source) +data: uv run lev data build --out $(OUT) --limit-per-source $(LIMIT) -eval-set: ## Export the held-out split as levbench task files +eval-set: uv run lev data eval --data $(OUT) --out $(EVAL) -s1bench: ## Export the S1Bench eval subsets as levbench task files +s1bench: uv run lev s1bench export --out $(S1) -##@ Train .PHONY: smoke-local smoke train calibrate -smoke-local: ## Train 0.8B on CPU for a few steps — proves the path without Modal +smoke-local: uv run lev data build --out /tmp/lev-mix --limit-per-source 2000 --n-examples 4000 uv run lev train --preset smoke --data /tmp/lev-mix \ --output-dir /tmp/lev-smoke --max-steps $(STEPS) -smoke: ## Modal: exercise the whole training path on 0.8B (~5 min of H100) +smoke: modal run modal/app.py::smoke -train: ## Modal: the real run; resumes the newest checkpoint (FRESH=1 to start over, RESUME=path) +train: modal run modal/app.py::train --preset $(PRESET) $(if $(FRESH),--fresh,) $(if $(RESUME),--resume $(RESUME),) -calibrate: ## Modal: fit per-bucket temperatures after training +calibrate: modal run modal/app.py::calibrate --preset $(PRESET) -##@ Serve and release .PHONY: serve deploy release weights publish -serve: ## Modal: dev server on an H100 (ephemeral; any `modal run` on this app steals its URL) +serve: LEV_SERVE_PRESET=$(PRESET) modal serve modal/app.py -deploy: ## Modal: deploy /v1/systemone with a stable URL (PRESET selects the checkpoint) +deploy: LEV_SERVE_PRESET=$(PRESET) modal deploy modal/app.py -release: ## Modal: package the newest PRESET checkpoint into a release dir on the volume +release: modal run modal/app.py::export_checkpoint --preset $(PRESET) $(if $(NAME),--name $(NAME),) -weights: ## Pull a packaged release to weights/RELEASE (RELEASE=name, default PRESET) +weights: mkdir -p weights modal volume get --force lev-checkpoints releases/$(RELEASE) weights/ -publish: ## Upload weights/RELEASE to the Hub (REPO=org/name; needs HF_TOKEN) +publish: uv run lev release publish weights/$(RELEASE) --repo $(REPO) -##@ Benchmark .PHONY: bench bench-local sweep snake -bench: s1bench ## Benchmark Jev on the S1Bench subsets (needs TYPESAFE_API_KEY) +bench: s1bench uv run levbench eval --backend jev --tasks $(S1) -bench-local: s1bench ## Benchmark a /v1/systemone server on the S1Bench subsets (URL=server) +bench-local: s1bench uv run levbench eval --backend lev --base-url $(URL) --tasks $(S1) -sweep: ## Measure shared-state batching economics +sweep: uv run levbench sweep --backend jev -snake: ## The decision model plays Snake over /v1/systemone (URL=server; --record in artifacts/) +snake: uv run levbench snake --backend lev --base-url $(URL) --record artifacts/snake/run.jsonl diff --git a/data/adr-029-summary.json b/data/adr-029-summary.json index 3348833..da41b22 100644 --- a/data/adr-029-summary.json +++ b/data/adr-029-summary.json @@ -403,14 +403,14 @@ "rps": 0.152, "ece15": 0.1296, "ece15_equal_mass": 0.1683, - "nll": 0.9348 + "negative_log_likelihood": 0.9348 }, "held_out_refit": { "acc": 0.5903, "rps": 0.1466, "ece15": 0.108, "ece15_equal_mass": 0.134, - "nll": 0.9087 + "negative_log_likelihood": 0.9087 } }, "reversed": { @@ -423,14 +423,14 @@ "rps": 0.1264, "ece15": 0.1108, "ece15_equal_mass": 0.1453, - "nll": 0.8388 + "negative_log_likelihood": 0.8388 }, "held_out_refit": { "acc": 0.6736, "rps": 0.1263, "ece15": 0.1193, "ece15_equal_mass": 0.1668, - "nll": 0.8381 + "negative_log_likelihood": 0.8381 } }, "cyclic": { @@ -443,14 +443,14 @@ "rps": 0.1238, "ece15": 0.0775, "ece15_equal_mass": 0.1387, - "nll": 0.8279 + "negative_log_likelihood": 0.8279 }, "held_out_refit": { "acc": 0.6597, "rps": 0.1238, "ece15": 0.0765, "ece15_equal_mass": 0.1382, - "nll": 0.8284 + "negative_log_likelihood": 0.8284 } } }, @@ -466,14 +466,14 @@ "rps": 0.1321, "ece15": 0.0896, "ece15_equal_mass": 0.1275, - "nll": 0.7807 + "negative_log_likelihood": 0.7807 }, "held_out_refit": { "acc": 0.6577, "rps": 0.13, "ece15": 0.0772, "ece15_equal_mass": 0.0914, - "nll": 0.7792 + "negative_log_likelihood": 0.7792 } }, "reversed": { @@ -486,14 +486,14 @@ "rps": 0.1015, "ece15": 0.0888, "ece15_equal_mass": 0.1219, - "nll": 0.641 + "negative_log_likelihood": 0.641 }, "held_out_refit": { "acc": 0.7584, "rps": 0.1008, "ece15": 0.0611, "ece15_equal_mass": 0.1142, - "nll": 0.6267 + "negative_log_likelihood": 0.6267 } }, "cyclic": { @@ -506,14 +506,14 @@ "rps": 0.1013, "ece15": 0.0681, "ece15_equal_mass": 0.0959, - "nll": 0.6436 + "negative_log_likelihood": 0.6436 }, "held_out_refit": { "acc": 0.7517, "rps": 0.1006, "ece15": 0.0865, "ece15_equal_mass": 0.0909, - "nll": 0.6286 + "negative_log_likelihood": 0.6286 } } } diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 770e9bf..9772bdc 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -107,7 +107,7 @@ This is our plan's §14 ("encode the question, don't build per-question heads") ### 3.6 Training objectives — from `NanoJev` and `decider` - NanoJev: CE / Brier / paired-proper-reward variants, with exact gradient checks. -- decider: cross-entropy fine-tune with **random layout per example** and **abstain augmentation**; evaluation reports accuracy / NLL / Brier / ECE / AURC / selective accuracy per task; v10 adds **RL with a proper-score belief reward** — the open analogue of RLCD. +- decider: cross-entropy fine-tune with **random layout per example** and **abstain augmentation**; evaluation reports accuracy / negative_log_likelihood / Brier / ECE / AURC / selective accuracy per task; v10 adds **RL with a proper-score belief reward** — the open analogue of RLCD. Supervised proper-scoring first, RL only after. That vindicates the plan's §17 ordering. @@ -237,7 +237,7 @@ Three splits, not two. Temperature is fitted on a split disjoint from **both** t 1. Train with a proper scoring rule (cross-entropy + Brier). 2. **Abstain augmentation** (decider): examples where the answer is not determinable from the state, teaching the model to spread mass rather than guess confidently. 3. Post-hoc temperature fit on the calibration split. -4. Report accuracy, NLL, Brier and **ECE** per source, with and without the temperature. +4. Report accuracy, negative_log_likelihood, Brier and **ECE** per source, with and without the temperature. Evidence this is worth the effort: the untuned Qwen3-8B (`qwen3-8b-full`) sits at **ECE 0.4252**; reflex, Qwen3.5-4B plus one fitted scalar, reaches **0.0849**. Jev is **0.0764**. **A single scalar is most of the gap.** diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 37d2487..bc4610e 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -634,7 +634,7 @@ Accuracy, RPS, Choice and Noul are identical, to the last digit, to the runs bef Calibration of the averaged modes. The shipped Score temperature (2.80) was fitted on single-order rows. Refit per mode on half of each bench (stratified by the gold level, seed 0), judged on the other half: ```text - T refit held-out NLL held-out ECE held-out RPS + T refit held-out negative_log_likelihood held-out ECE held-out RPS shipped refit shipped refit shipped refit en (144) off 3.96 0.935 0.909 0.130 0.108 0.152 0.147 reversed 3.16 0.839 0.838 0.111 0.119 0.126 0.126 @@ -644,7 +644,7 @@ Calibration of the averaged modes. The shipped Score temperature (2.80) was fitt cyclic 2.40 0.644 0.629 0.068 0.086 0.101 0.101 ``` -On bench_en a refit gains nothing for either averaged mode (held-out NLL within 0.001), and the shipped temperature is if anything a little sharp for `off`. On the Japanese reference the refit goes the other way for the averaged modes. A per-mode temperature is not proposed. +On bench_en a refit gains nothing for either averaged mode (held-out negative_log_likelihood within 0.001), and the shipped temperature is if anything a little sharp for `off`. On the Japanese reference the refit goes the other way for the averaged modes. A per-mode temperature is not proposed. The batch budget for averaged requests (`max_batch_tokens`, 16384). The batcher does not split a request: on main, 20 Choice and 40 Score questions with averaging off ran as one forward of 80 rows, up to 35,680 padded tokens. So `prepare` refuses only a request that Score averaging grew, when its padded tokens (rows x widest row) pass the batcher's own budget; the server passes its `max_batch_tokens` to the engine, so the two always agree, and a request without averaged Score rows is never refused (the 80-row request above answers exactly as on main). The value is the batcher's; this run only checks it on the RTX 5090, with the largest averaged request the budget admits at each row length, averaged Score questions topped up with one-row Noul (one question more is refused in every case): diff --git a/docs/charts/build.py b/docs/charts/build.py index 53cdc1a..bee494b 100644 --- a/docs/charts/build.py +++ b/docs/charts/build.py @@ -1,16 +1,5 @@ # ruff: noqa: E501 -- SVG and HTML markup, one element per line -"""Render docs/charts/lev-vs-jev.html from measured logs and recorded history. - - uv run python docs/charts/build.py - -Inputs, all checked in: - logs/jev-s1bench-*.txt, logs/lev-s1bench-*.txt both on the 13 S1Bench task files, same laptop - logs/pre-nimble/ earlier six-subset definitions, the scale of history.json - history.json lev iterations and speed measurements, with FINDINGS sections - ../../data/s1bench-snapshot.json the public S1Bench board: every other model - -lev blue and Jev orange (CVD-checked in both modes); every other model is context gray. -""" +"""Render docs/charts/lev-vs-jev.html from checked-in logs, history, and the S1Bench snapshot.""" from __future__ import annotations @@ -25,7 +14,6 @@ HERE = Path(__file__).parent SNAPSHOT = HERE.parent.parent / "data" / "s1bench-snapshot.json" -# The six subsets every model on the board completed; the leaderboard is over these. SUBSETS = ["aegis2", "boolq", "helpsteer2", "massive-en-US", "paws", "vitaminc-dev"] ALL_SUBSETS = list(EVAL_SUBSETS) W = 760 @@ -142,7 +130,6 @@ def grouped_bars(cats, series, vmax, fmt, ticks, label_w=118) -> str: def scatter( points, xr, yr, xfmt, yfmt, xticks, yticks, xlabel, ylabel, xlog=False, hline=None ) -> str: - """Points: dicts with x, y, name, var, and label (direct-label it).""" h, left, right, top, bottom = 380, 58, 24, 14, 44 pw, ph = W - left - right, h - top - bottom tx = math.log10 if xlog else (lambda v: v) @@ -169,7 +156,7 @@ def scatter( f'' f'{esc(hline["name"])}' ) - for p in sorted(points, key=lambda p: p["var"] != CTX): # context underneath + for p in sorted(points, key=lambda p: p["var"] != CTX): cx, cy = px(p["x"]), py(p["y"]) r = 6 if p["var"] != CTX else 4.5 tip = f"{p['name']}|{xfmt(p['x'])} · {yfmt(p['y'])}" @@ -294,8 +281,6 @@ def majority_rate(subset: str) -> float: def completed_targets(board: dict) -> list[dict]: - """Board models that completed all six subsets; a model stopped after one - subset reports a one-subset macro and is not comparable.""" return [ t for t in board["targets"] @@ -316,7 +301,6 @@ def leaderboard_row(name: str, value: float, var: str, size: str, ece: float, bo def leaderboard_rows(done: list[dict], data: Inputs) -> list[dict]: - """Board models plus lev and Jev as measured here, best first.""" rows = [] for t in done: is_jev = t["target"] == "jev" @@ -526,7 +510,6 @@ def size_section(points: list[dict], jev_board: dict) -> str: def per_subset_series(data: Inputs, value) -> list[dict]: - """lev and Jev as grouped-bar series, `value(scores)` per subset.""" return [ {"name": "lev", "var": LEV, "values": [value(data.lev[s]) for s in ALL_SUBSETS]}, {"name": "Jev", "var": JEV, "values": [value(data.jev[s]) for s in ALL_SUBSETS]}, diff --git a/docs/charts/levbench_log.py b/docs/charts/levbench_log.py index 9fa5780..36a53aa 100644 --- a/docs/charts/levbench_log.py +++ b/docs/charts/levbench_log.py @@ -20,8 +20,6 @@ def parse(text: str) -> dict: - """`{"subsets": {subset: {n, accuracy, log_loss, brier, ece, p50_s, ...}}}`, plus - `served_by` when the log names the serving model.""" out: dict = {"subsets": {}} marks = list(_HEADER.finditer(text)) for i, mark in enumerate(marks): @@ -29,7 +27,7 @@ def parse(text: str) -> dict: scores = _SCORES.search(body) if not scores: continue - row = {"n": int(mark.group(2))} + row: dict[str, float | int] = {"n": int(mark.group(2))} row.update( zip(("accuracy", "log_loss", "brier", "ece"), map(float, scores.groups()), strict=True) ) diff --git a/modal/app.py b/modal/app.py index 380634d..3586ba5 100644 --- a/modal/app.py +++ b/modal/app.py @@ -1,8 +1,6 @@ -"""Build data, train, calibrate, evaluate and serve lev on Modal. See docs/SETUP.md. +"""Build, train, calibrate, evaluate, and serve lev on Modal (SETUP.md). -Use `modal deploy` for a stable URL: other ephemeral runs can take over `modal serve`'s -`-dev` label. -""" +Use modal deploy for a stable URL; modal serve uses a shared development label.""" from __future__ import annotations @@ -25,14 +23,10 @@ APP_NAME = "lev" -# From this file, not the cwd: `modal run` may start anywhere, and a relative path mounts nothing. REPO_ROOT = Path(__file__).resolve().parent.parent -# Pinned for reproducibility. `transformers` must be 5.x: the prefix-cache fork -# calls `reorder_cache` on a hybrid cache, which 4.x cannot do. +# Pin dependencies; hybrid-cache reordering requires Transformers 5.x. image = ( - # Devel base for the `nvcc` that `causal-conv1d` builds with (served compute 81 -> 69 ms, - # ADR-023). The CUDA major must match torch's build (2.14.0+cu130). modal.Image.from_registry("nvidia/cuda:13.0.3-devel-ubuntu24.04", add_python="3.12") .pip_install( "torch==2.14.0", @@ -45,14 +39,10 @@ "fastapi==0.141.1", "huggingface-hub==1.32.0", ) - # Speed, not correctness: if the conv build breaks on a pin change, delete it. .pip_install("flash-linear-attention", "ninja", "packaging") - # The devel image has nvcc but no host C++ compiler, which torch's extension - # builder requires ("clang++ 0.0.0"). Arch 9.0 only: this image runs on H100s. .apt_install("build-essential") .env({"CC": "gcc", "CXX": "g++", "TORCH_CUDA_ARCH_LIST": "9.0", "MAX_JOBS": "8"}) - # Length-bucketed batches vary widely in shape; without this the caching - # allocator fragments (the OOM at step 6,075 had 29 GiB reserved-but-free). + # Expandable segments reduce fragmentation from varying batch shapes. .env({"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True"}) .pip_install("causal-conv1d", extra_options="--no-build-isolation") .add_local_dir( @@ -78,17 +68,11 @@ DATA_DIR: datasets_vol, } -# The preset `serve` exposes when `LEV_SERVE_PRESET` is unset. Not a function -# argument: Modal requires `@modal.asgi_app` functions to take none. +# Use an environment preset because Modal ASGI functions accept no arguments. SERVE_PRESET = "4b" def _hf_secrets() -> list: - """The Secret named by `LEV_HF_SECRET`, else the local `HF_TOKEN`, else none. - - Never an unconditional `Secret.from_name`: it fails at function creation when the - Secret is missing, and the backbones are public. - """ named = os.environ.get("LEV_HF_SECRET") if named: return [modal.Secret.from_name(named, required_keys=[])] @@ -96,13 +80,6 @@ def _hf_secrets() -> list: return [modal.Secret.from_dict({"HF_TOKEN": token})] if token else [] -# Deploy knobs (docs/SETUP.md), read where `modal deploy` runs: decorator arguments are -# fixed at import, so these cannot travel as Secrets. -# LEV_SERVE_CONCURRENCY per-container inputs, also the server's max_pending (32; ADR-030) -# LEV_SERVE_WARM containers kept running (0); one removes the 20-55 s cold start -# LEV_SERVE_REGION Modal region near the client (unset); the measured 280 ms RTT is distance -# LEV_SERVE_SCALEDOWN idle seconds before a container stops (300) -# LEV_SERVE_MAX container ceiling (unset: Modal's limit); pin it for benchmark sweeps SERVE_CONCURRENCY = int(os.environ.get("LEV_SERVE_CONCURRENCY", "32")) SERVE_WARM = int(os.environ.get("LEV_SERVE_WARM", "0")) SERVE_REGION = os.environ.get("LEV_SERVE_REGION") @@ -119,7 +96,6 @@ def _prompt_style(value: str | None) -> Literal["plain", "chat"] | None: def _serve_overrides() -> list: - """The set `LEV_SERVE_*` overrides as a Secret: local env does not reach the container.""" overrides: dict[str, str | None] = { key: value for key in ( @@ -141,10 +117,6 @@ def _serve_overrides() -> list: @app.function(volumes={MODELS_DIR: models}, secrets=SECRETS, timeout=60 * 60) def download(model_id: str = "Qwen/Qwen3.5-4B-Base") -> str: - """Pre-fetch a checkpoint into the models Volume. Idempotent. - - `cache_dir`, not `local_dir`: `from_pretrained(..., cache_dir=)` expects the HF cache layout. - """ from huggingface_hub import snapshot_download path = snapshot_download( @@ -161,7 +133,7 @@ def download(model_id: str = "Qwen/Qwen3.5-4B-Base") -> str: gpu="H100", volumes=VOLUMES, secrets=SECRETS, - timeout=24 * 60 * 60, # the released run took 7.8 h; a truncated run costs everything + timeout=24 * 60 * 60, # Allow the full training run to finish. ) def train( preset: str = "4b", @@ -170,11 +142,6 @@ def train( max_steps: int | None = None, fresh: bool = False, ) -> dict: - """Fine-tune on one H100. See `lev.train.config.PRESETS`. - - Resumes from the newest checkpoint in the preset's directory unless - `--fresh`; `--resume ` names one explicitly. - """ from lev.train.config import PRESETS from lev.train.loop import run_training @@ -204,10 +171,6 @@ def train( @app.function(volumes={DATA_DIR: datasets_vol}, secrets=SECRETS, timeout=4 * 60 * 60) def build_data(limit_per_source: int = 20_000, n_examples: int = 200_000) -> dict: - """Download every source and write the three splits to the data volume. CPU only. - - Run it once, before `train`. - """ from lev.data.build import build_dataset # The HF download cache lives on the volume, so rebuilds reuse the corpora. @@ -223,10 +186,6 @@ def build_data(limit_per_source: int = 20_000, n_examples: int = 200_000) -> dic @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=2 * 60 * 60) def smoke(steps: int = 40) -> dict: - """Exercise every part of `train` but its duration, on the 0.8B preset. Run this first. - - Builds a small mixture if the data volume is empty. - """ if not (Path(DATA_DIR) / "train.jsonl").is_file(): # Builds on the GPU, acceptable only for this small mixture (a couple of minutes). print("data volume is empty; building a small mixture first") @@ -247,21 +206,16 @@ def smoke(steps: int = 40) -> dict: @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=60 * 60) def calibrate(preset: str = "4b", split: str = "calibration", method: str = "transfer") -> dict: - """Fit per-bucket temperatures on a split that is neither train nor test. - - Separate from `train` so re-fitting needs no fine-tune. - """ from lev.train.calibration_run import fit_profile from lev.train.config import PRESETS config = replace(PRESETS[preset], output_dir=f"{CKPT_DIR}/{preset}") return fit_profile( - # `fit_profile` resolves the newest checkpoint inside this directory. checkpoint_dir=config.output_dir, data_dir=DATA_DIR, split=split, on_complete=lambda: checkpoints.commit(), - # Otherwise the head is built at the 4B hidden size whatever the preset. + # Use the preset's hidden size when building the head. config=config, method=method, ) @@ -273,9 +227,6 @@ def evaluate( split: str = "test", limit_per_source: int | None = None, ) -> dict: - """Score the newest checkpoint on a held-out split, with and without the - fitted temperature. - """ from lev.calibrate import CalibrationProfile from lev.train.checkpoints import CALIBRATION from lev.train.config import PRESETS @@ -316,14 +267,6 @@ def evaluate( @modal.concurrent(max_inputs=SERVE_CONCURRENCY) @modal.asgi_app() def serve(): - """Serve `/v1/systemone`, wire-compatible with the TypeSafe API. - - levbench eval --backend lev --base-url \ - --tasks data/eval - - With no trained checkpoint for the preset it serves the base backbone - uncalibrated, with a warning, rather than refusing to start. - """ from lev.server import create_app from lev.train.checkpoints import ADAPTER_WEIGHTS, latest_checkpoint from lev.train.config import PRESETS @@ -335,13 +278,12 @@ def serve(): # Off unless asked: measured slower than eager on this model (ADR-023). compile = os.environ.get("LEV_SERVE_COMPILE", "0") in ("1", "true", "yes") - # Default None: Mode A up to the tokenizer limit (ADR-025). Set to force a - # lower cap, e.g. 26 to reproduce the ADR-020 policy. + # Default to the tokenizer limit; allow an explicit lower label cap. cap_env = os.environ.get("LEV_SERVE_MAX_LABEL_OPTIONS") max_label_options = int(cap_env) if cap_env else None prompt_style = _prompt_style(os.environ.get("LEV_SERVE_PROMPT")) or config.prompt_style skip_codes = os.environ.get("LEV_SERVE_SKIP_CODES", "1") not in ("0", "false", "no") - # A frozen model is a different backbone from the adapter's, so no checkpoint. + # A frozen-model override must bypass the adapter checkpoint. frozen = os.environ.get("LEV_SERVE_MODEL") if frozen: print(f"serving {frozen} frozen: no adapter, binary Noul, raw softmax") @@ -379,11 +321,6 @@ def main(preset: str = "4b", dry_run: bool = True): @app.function(volumes={CKPT_DIR: checkpoints}, secrets=SECRETS, timeout=30 * 60) def export_checkpoint(preset: str = "4b", name: str | None = None) -> dict: - """Package the newest checkpoint of a preset into `/checkpoints/releases/`. - - No GPU: it copies files (adapter, head, tokenizer, calibration, manifest) - for `make weights` to pull and `lev release publish` to upload. - """ from lev.release import build_release from lev.train.config import PRESETS @@ -406,11 +343,6 @@ def export_checkpoint(preset: str = "4b", name: str | None = None) -> dict: @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def check_release(name: str = "4b") -> dict: - """Load a packaged release the way a user will -- `lev.load` on the flat - directory, then the HTTP server over it -- and answer one request of every - question type through each. Raises if the release loads without its - calibration or head, or if the two paths disagree. - """ import json from fastapi.testclient import TestClient @@ -468,14 +400,7 @@ def diagnose_ordinal( scales: str = "0,0.25,0.5,0.75,1.0", subsets: str = "summeval-consistency,summeval-relevance,helpsteer2", ) -> dict: - """Score the rating subsets at several adapter scales, keeping the adapter unmerged. - - summeval-consistency is 0.271 against the frozen backbone's 0.826, so the - regression may be recoverable by scaling the adapter rather than retraining - (WiSE-FT, arXiv 2109.01903, which for a LoRA is just the adapter scale). - Scale 0 must reproduce the frozen backbone; that is the run's own control. - Also reports the argmax histogram, which levbench aggregates away. - """ + """Sweep adapter scales on rating tasks; use scale zero as the frozen-backbone control.""" import collections import json @@ -520,14 +445,11 @@ def diagnose_ordinal( @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def diagnose_candidates(model_id: str = "Qwen/Qwen3.5-4B-Base") -> dict: - """Compare candidate representations alone, batched, reversed and left-padded. - - Tests whether Mode B's padded batch leaks across rows. Result: bit-identical (FINDINGS §12). - """ + """Compare candidate embeddings alone, batched, reversed, and left-padded.""" import torch from transformers import AutoModelForCausalLM, AutoTokenizer - tok = AutoTokenizer.from_pretrained(model_id, cache_dir=MODELS_DIR) + tok: Any = AutoTokenizer.from_pretrained(model_id, cache_dir=MODELS_DIR) # `from_pretrained` is typed as returning the class, not an instance. loaded: Any = AutoModelForCausalLM.from_pretrained( model_id, dtype=torch.bfloat16, cache_dir=MODELS_DIR @@ -618,10 +540,6 @@ def gap(a, b): def _probabilities(answer: Answer) -> dict[Any, float]: - """An answer's probability map; a Noul without one stands in its single probability. - - Choice keys are strings and Score keys ints, so compare a map only with the same answer's. - """ from lev.types import NoulAnswer # noqa: PLC0415 if isinstance(answer, NoulAnswer): @@ -631,10 +549,7 @@ def _probabilities(answer: Answer) -> dict[Any, float]: @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def profile_engine(preset: str = "4b", rounds: int = 20) -> dict: - """Time each engine stage of a `/v1/systemone` call in the container, CUDA-synchronised. - - Both prefix modes and the compiled path; medians over `rounds` after warmup. Excludes network. - """ + """Time CUDA-synchronized engine stages after warmup, excluding network time.""" import statistics import time @@ -724,8 +639,7 @@ def wrapper(*a, **k): worst = max(worst, *(abs(pa[k] - pb[k]) for k in pa)) report["fork_vs_single_max_prob_diff"] = round(worst, 5) print(f"fork vs single: max |dp| over all answers = {worst:.5f}", flush=True) - # Fork wins when the forward is FLOP-bound, single when launch-bound; then the - # compiled single path, with its warmup reported separately. + # Compare forked, single, and compiled forwards; report warmup separately. variants: list[tuple[Literal["fork", "single"], bool]] = [ ("fork", False), ("single", False), @@ -795,13 +709,10 @@ def wrapper(*a, **k): @app.function(secrets=SECRETS, timeout=10 * 60) def env_info() -> dict: - """What the image actually runs: torch, its CUDA build, and which kernels import.""" import platform import torch - # Plain strings: `torch.__version__` is a TorchVersion, which the local - # `modal run` process cannot unpickle without torch installed. info = { "python": platform.python_version(), "torch": str(torch.__version__), diff --git a/packages/lev/src/lev/__init__.py b/packages/lev/src/lev/__init__.py index 89836fd..4973c8b 100644 --- a/packages/lev/src/lev/__init__.py +++ b/packages/lev/src/lev/__init__.py @@ -1,8 +1,3 @@ -"""Typed, calibrated decisions without token generation. - -The core imports without Torch; loading a model requires the train extra. -""" - from .calibrate import CalibrationProfile from .model import DecisionEngine, load from .prompt import Layout diff --git a/packages/lev/src/lev/batcher.py b/packages/lev/src/lev/batcher.py index 0c92080..5c2c207 100644 --- a/packages/lev/src/lev/batcher.py +++ b/packages/lev/src/lev/batcher.py @@ -13,21 +13,26 @@ from collections.abc import Awaitable, Callable from concurrent.futures import Future from dataclasses import dataclass +from typing import Protocol -from .model import MAX_BATCH_TOKENS, DecisionEngine, Prepared +from .model import MAX_BATCH_TOKENS, Prepared from .types import SystemOneResponse +class AnswerEngine(Protocol): + def answer(self, requests: list[Prepared]) -> list[SystemOneResponse]: ... + + class Overloaded(Exception): - """`max_pending` requests are already in flight.""" + pass class ClientGone(Exception): - """The client disconnected before its answer was ready.""" + pass class WorkerStopped(RuntimeError): - """The GPU worker thread has exited; the server needs a restart.""" + pass @dataclass @@ -40,25 +45,27 @@ class _Job: class Batcher: def __init__( self, - engine: DecisionEngine, + engine: AnswerEngine, max_pending: int = 64, max_batch_tokens: int = MAX_BATCH_TOKENS, timeout: float = 30.0, ): self.engine = engine self.max_pending = max_pending - # Padded tokens per forward (rows x widest row); bounds activation memory. - # A request larger than the budget still runs, alone. - self.max_batch_tokens = max_batch_tokens + self.max_batch_tokens = max_batch_tokens # Bounds activation memory per forward pass. self.timeout = timeout - # A request counts until the worker finishes or skips it, not until its - # client leaves: abandoned work still occupies the GPU. - self._pending = 0 + + self._pending = 0 # Counts work until the worker finishes, even if the client leaves. self._pending_lock = threading.Lock() self._queue: queue.SimpleQueue[_Job] = queue.SimpleQueue() self._held: _Job | None = None self._batch: list[_Job] = [] - self._worker = threading.Thread(target=self._run, name="lev-gpu", daemon=True) + + self._worker = threading.Thread( + target=self._run, + name="lev-gpu", + daemon=True, + ) self._worker.start() @property @@ -71,38 +78,47 @@ def alive(self) -> bool: return self._worker.is_alive() async def submit( - self, prepared: Prepared, disconnected: Callable[[], Awaitable] | None = None + self, + prepared: Prepared, + disconnected: Callable[[], Awaitable] | None = None, ) -> SystemOneResponse: - """Queue one request and wait for its answer. `disconnected` makes an - awaitable that completes if the client leaves; it is called only once - the request is admitted. If it raises instead, disconnects go undetected - and the answer is awaited alone.""" + if not self.alive: raise WorkerStopped("the GPU worker has stopped; restart the server") + with self._pending_lock: if self._pending >= self.max_pending: raise Overloaded(f"{self._pending} requests in flight; retry shortly") self._pending += 1 + job = _Job(prepared, Future(), time.monotonic() + self.timeout) job.future.add_done_callback(self._release) self._queue.put(job) - # Cancelling this wrapper cancels `job.future` unless the worker has - # already started it. - result = asyncio.wrap_future(job.future) + + result = asyncio.wrap_future(job.future) # Cancelling may cancel the queued job. + if disconnected is None: return await result + watcher = asyncio.ensure_future(disconnected()) + try: - await asyncio.wait({result, watcher}, return_when=asyncio.FIRST_COMPLETED) + await asyncio.wait( + {result, watcher}, + return_when=asyncio.FIRST_COMPLETED, + ) + if not result.done() and watcher.exception() is not None: return await result finally: if watcher.done() and not watcher.cancelled(): - watcher.exception() # retrieved, so asyncio does not log it as lost + watcher.exception() # Mark the exception as retrieved. watcher.cancel() + if not result.done(): result.cancel() raise ClientGone + return result.result() def _release(self, _future: Future) -> None: @@ -113,10 +129,11 @@ def _run(self) -> None: try: while True: self._batch = [] + try: self._fill(self._batch) self._compute(self._batch) - except Exception as error: # noqa: BLE001 -- the worker must outlive any one batch + except Exception as error: # noqa: BLE001 -- worker must outlive one batch traceback.print_exc() _fail([job.future for job in self._batch], error) finally: @@ -125,34 +142,40 @@ def _run(self) -> None: def _compute(self, batch: list[_Job]) -> None: try: responses = self.engine.answer([job.prepared for job in batch]) - except Exception as error: # noqa: BLE001 -- a failed forward fails requests, not the worker + except Exception as error: # noqa: BLE001 -- failed forward should not kill worker if len(batch) == 1: batch[0].future.set_exception(error) return - # A batch can fail where its requests alone would not (out of - # memory), and one bad request must not fail the others. + + # A batch may fail where its requests alone would not. for job in batch: self._compute([job]) return + for job, response in zip(batch, responses, strict=True): job.future.set_result(response) def _fill(self, batch: list[_Job]) -> None: - # Marked running only on joining, so a request held for the next batch - # can still be cancelled or time out. + # Held jobs remain cancellable until they actually join a batch. rows = width = 0 + while (job := self._take(block=not batch)) is not None: - grown_rows, grown_width = rows + job.prepared.rows, max(width, job.prepared.width) + grown_rows = rows + job.prepared.rows + grown_width = max(width, job.prepared.width) + if batch and grown_rows * grown_width > self.max_batch_tokens: self._held = job return + if not job.future.set_running_or_notify_cancel(): - continue # the client left between `_take` and here + continue # Client disconnected while queued. + batch.append(job) rows, width = grown_rows, grown_width def _take(self, block: bool) -> _Job | None: - """The next request still worth computing, not yet marked running.""" + """Return the next request worth computing.""" + while True: if self._held is not None: job, self._held = self._held, None @@ -161,23 +184,27 @@ def _take(self, block: bool) -> _Job | None: job = self._queue.get(block=block) except queue.Empty: return None + if job.future.cancelled(): - continue # the client left while it waited + continue + if time.monotonic() > job.deadline: if job.future.set_running_or_notify_cancel(): job.future.set_exception( TimeoutError(f"queued longer than the {self.timeout:.0f}s deadline") ) continue + return job def _fail_queued(self) -> None: - """On worker exit, fail the running batch and everything still waiting, - rather than leave them hanging.""" + stopped = WorkerStopped("the GPU worker has stopped; restart the server") _fail([job.future for job in self._batch], stopped) + while (job := self._held or self._next_queued()) is not None: self._held = None + if job.future.set_running_or_notify_cancel(): job.future.set_exception(stopped) diff --git a/packages/lev/src/lev/calibrate.py b/packages/lev/src/lev/calibrate.py index 9bf42aa..3d8074a 100644 --- a/packages/lev/src/lev/calibrate.py +++ b/packages/lev/src/lev/calibrate.py @@ -1,11 +1,11 @@ -"""Temperature scaling per question type, readout mode and Choice option band (ADR-028).""" +"""Temperature scaling by question type, readout mode, and Choice option band (ADR-028).""" from __future__ import annotations import json import math from collections import Counter -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from dataclasses import dataclass, field from pathlib import Path @@ -15,28 +15,34 @@ def softmax(logits: Logits, temperature: float = 1.0) -> list[float]: if temperature <= 0: raise ValueError(f"temperature must be positive, got {temperature}") + scaled = [x / temperature for x in logits] top = max(scaled) exps = [math.exp(x - top) for x in scaled] total = sum(exps) + return [e / total for e in exps] -def nll( +def negative_log_likelihood( samples: Sequence[tuple[Logits, int]], temperature: float, weights: Sequence[float] | None = None, ) -> float: - """Mean (optionally weighted) negative log-likelihood of the true class.""" + if not samples: return 0.0 + total = 0.0 weight_sum = 0.0 + for i, (logits, truth) in enumerate(samples): - w = 1.0 if weights is None else weights[i] - p = softmax(logits, temperature)[truth] - total -= w * math.log(max(p, 1e-15)) - weight_sum += w + weight = 1.0 if weights is None else weights[i] + probability = softmax(logits, temperature)[truth] + + total -= weight * math.log(max(probability, 1e-15)) + weight_sum += weight + return total / weight_sum @@ -47,22 +53,29 @@ def fit_temperature( tol: float = 1e-4, weights: Sequence[float] | None = None, ) -> float: - """Minimise NLL over temperature by ternary search (NLL is unimodal in it). - Returns 1.0 when no temperature beats the identity, e.g. for all-equal logits. - """ if not samples: return 1.0 + while hi - lo > tol: m1 = lo + (hi - lo) / 3 m2 = hi - (hi - lo) / 3 - if nll(samples, m1, weights) < nll(samples, m2, weights): + + if negative_log_likelihood(samples, m1, weights) < negative_log_likelihood( + samples, m2, weights + ): hi = m2 else: lo = m1 + fitted = (lo + hi) / 2 - if nll(samples, fitted, weights) >= nll(samples, 1.0, weights) - 1e-12: + + if ( + negative_log_likelihood(samples, fitted, weights) + >= negative_log_likelihood(samples, 1.0, weights) - 1e-12 + ): return 1.0 + return fitted @@ -70,131 +83,182 @@ def fit_temperature( def family_weights(families: Sequence[str]) -> list[float]: - """Each family's rows share a total weight of 1.""" + """Give each family equal total weight.""" + counts = Counter(families) - return [1.0 / counts[f] for f in families] + return [1.0 / counts[family] for family in families] def _fit(samples, families, method: str) -> float: return fit_temperature( - samples, weights=family_weights(families) if method == "family" else None + samples, + weights=family_weights(families) if method == "family" else None, ) def leave_one_family_out_ece( - samples: Sequence[tuple[Logits, int]], families: Sequence[str], method: str + samples: Sequence[tuple[Logits, int]], + families: Sequence[str], + method: str, ) -> float: - """Mean over families of the ECE on that family, at the temperature `method` - fits on every other family. Families weigh equally, as a new task would.""" + """Measure transfer ECE by holding out each family once.""" + eces = [] + for held_out in sorted(set(families)): - train = [(s, f) for s, f in zip(samples, families, strict=True) if f != held_out] - test = [s for s, f in zip(samples, families, strict=True) if f == held_out] - t = _fit([s for s, _ in train], [f for _, f in train], method) - probs = [softmax(logits, t) for logits, _ in test] - eces.append(expected_calibration_error(probs, [y for _, y in test])) + train = [ + (sample, family) + for sample, family in zip(samples, families, strict=True) + if family != held_out + ] + test = [ + sample for sample, family in zip(samples, families, strict=True) if family == held_out + ] + + temperature = _fit( + [sample for sample, _ in train], + [family for _, family in train], + method, + ) + probs = [softmax(logits, temperature) for logits, _ in test] + eces.append(expected_calibration_error(probs, [truth for _, truth in test])) + return sum(eces) / len(eces) def fit_for_transfer( - buckets: dict[str, Sequence[tuple[Logits, int, str]]], + buckets: Mapping[str, Sequence[tuple[Logits, int, str]]], split_name: str, min_samples: int = 50, ) -> tuple[CalibrationProfile, dict[str, dict]]: - """Per bucket, keep whichever of the row and family fits transfers better. + """Choose the row- or family-weighted fit that transfers better per bucket.""" - Buckets from fewer than `MIN_FAMILIES_FOR_TRANSFER` families keep the row fit. - Returns the profile and a per-bucket report of both fits and the choice. - """ _refuse_held_out(split_name) + profile = CalibrationProfile(fitted_on=f"{split_name} (transfer-selected)") report: dict[str, dict] = {} + for bucket, rows in buckets.items(): if len(rows) < min_samples: continue - samples = [(logits, y) for logits, y, _ in rows] - families = [f for _, _, f in rows] - entry: dict = {"n": len(rows), "families": len(set(families))} + + samples = [(logits, truth) for logits, truth, _ in rows] + families = [family for _, _, family in rows] + + entry: dict = { + "n": len(rows), + "families": len(set(families)), + } entry["t_rows"] = _fit(samples, families, "rows") + if entry["families"] >= MIN_FAMILIES_FOR_TRANSFER: entry["t_family"] = _fit(samples, families, "family") entry["lofo_ece_rows"] = leave_one_family_out_ece(samples, families, "rows") - entry["lofo_ece_family"] = leave_one_family_out_ece(samples, families, "family") + entry["lofo_ece_family"] = leave_one_family_out_ece( + samples, + families, + "family", + ) entry["chosen"] = ( "family" if entry["lofo_ece_family"] < entry["lofo_ece_rows"] else "rows" ) else: entry["chosen"] = "rows" + profile.temperatures[bucket] = entry[f"t_{entry['chosen']}"] profile.n_samples[bucket] = len(rows) report[bucket] = entry + return profile, report def expected_calibration_error( - probs: Sequence[Sequence[float]], truths: Sequence[int], n_bins: int = 10 + probs: Sequence[Sequence[float]], + truths: Sequence[int], + n_bins: int = 10, ) -> float: - """Sample-weighted mean absolute gap between top probability and accuracy.""" + if not probs: return 0.0 bins: list[list[tuple[float, bool]]] = [[] for _ in range(n_bins)] + for distribution, truth in zip(probs, truths, strict=True): confidence = max(distribution) predicted = max(range(len(distribution)), key=distribution.__getitem__) - # The top bin is closed: a confidence of exactly 1.0 would otherwise - # index one past the end. - bin_index = min(int(confidence * n_bins), n_bins - 1) + + bin_index = min(int(confidence * n_bins), n_bins - 1) # Keep 1.0 in the top bin. bins[bin_index].append((confidence, predicted == truth)) total_weighted_gap = 0.0 + for members in bins: if not members: continue - mean_confidence = sum(c for c, _ in members) / len(members) + + mean_confidence = sum(confidence for confidence, _ in members) / len(members) accuracy = sum(hit for _, hit in members) / len(members) + total_weighted_gap += len(members) * abs(mean_confidence - accuracy) + return total_weighted_gap / len(probs) -# Softmax spreads mass differently as option count grows, so Choice fits use bands. +# Choice calibration is banded because option count changes softmax behaviour. CHOICE_BANDS = ((8, "small"), (26, "mid")) def option_band(n_options: int | None) -> str | None: if n_options is None: return None + for upper, name in CHOICE_BANDS: if n_options <= upper: return name + return "large" @dataclass class CalibrationProfile: - """Fitted temperatures keyed by `"{question_type}:{mode}"`, and for Choice - by `"choice:{mode}:{band}"` as well.""" - temperatures: dict[str, float] = field(default_factory=dict) fitted_on: str = "" n_samples: dict[str, int] = field(default_factory=dict) @staticmethod - def key(question_type: str, mode: str, n_options: int | None = None) -> str: + def key( + question_type: str, + mode: str, + n_options: int | None = None, + ) -> str: band = option_band(n_options) if question_type == "choice" else None return f"{question_type}:{mode}" + (f":{band}" if band else "") - def temperature(self, question_type: str, mode: str, n_options: int | None = None) -> float: - # Banded, then unbanded (profiles fitted before bands), then 1.0: an - # unfitted bucket gets raw softmax rather than a borrowed scalar. + def temperature( + self, + question_type: str, + mode: str, + n_options: int | None = None, + ) -> float: banded = self.key(question_type, mode, n_options) plain = self.key(question_type, mode) - return self.temperatures.get(banded, self.temperatures.get(plain, 1.0)) + + return self.temperatures.get( + banded, + self.temperatures.get(plain, 1.0), + ) def apply( - self, logits: Logits, question_type: str, mode: str, n_options: int | None = None + self, + logits: Logits, + question_type: str, + mode: str, + n_options: int | None = None, ) -> list[float]: - return softmax(logits, self.temperature(question_type, mode, n_options)) + return softmax( + logits, + self.temperature(question_type, mode, n_options), + ) def save(self, path: str | Path) -> None: Path(path).write_text( @@ -211,6 +275,7 @@ def save(self, path: str | Path) -> None: @classmethod def load(cls, path: str | Path) -> CalibrationProfile: payload = json.loads(Path(path).read_text()) + return cls( temperatures=payload["temperatures"], fitted_on=payload.get("fitted_on", ""), @@ -219,19 +284,22 @@ def load(cls, path: str | Path) -> CalibrationProfile: def fit( - buckets: dict[str, Sequence[tuple[Logits, int]]], + buckets: Mapping[str, Sequence[tuple[Logits, int]]], split_name: str, min_samples: int = 50, ) -> CalibrationProfile: - """Fit one temperature per bucket; reject test, eval and holdout splits.""" + """Fit one temperature per sufficiently large bucket.""" + _refuse_held_out(split_name) profile = CalibrationProfile(fitted_on=split_name) + for bucket, samples in buckets.items(): if len(samples) < min_samples: - # Leave it unfitted (identity) rather than fit a scalar on noise. continue + profile.temperatures[bucket] = fit_temperature(samples) profile.n_samples[bucket] = len(samples) + return profile diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 9e78631..0cd616f 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -10,7 +10,6 @@ def _measure_tokens(config, data_dir: str, sample: int = 1500) -> dict: - """Length distribution of real rendered prompts; the budget rests on it (ADR-016).""" import statistics from transformers import AutoTokenizer @@ -21,8 +20,9 @@ def _measure_tokens(config, data_dir: str, sample: int = 1500) -> dict: from .train.collate import RouteCache, render tokenizer = AutoTokenizer.from_pretrained(config.model_id) + if tokenizer is None: + raise RuntimeError(f"could not load tokenizer for {config.model_id!r}") rows = load_split(data_dir, Split.TRAIN)[:sample] - # The preset's own prompt style: `chat` adds a system turn to every prompt. style = Style(config.prompt_style) routes = RouteCache(tokenizer, config.max_label_options, style) lengths = sorted( @@ -92,8 +92,6 @@ def cmd_check_data(args: argparse.Namespace) -> None: def _preset_names() -> list[str]: - """Lazy, like every CLI import, so `lev plan` and `lev check-data` run - without the train extra.""" from .train.config import PRESETS return sorted(PRESETS) @@ -224,7 +222,6 @@ def cmd_serve(args: argparse.Namespace) -> None: def _cuda(): - """`torch.cuda` when a GPU is in use, else None; torch is imported only here.""" try: import torch except ImportError: @@ -233,13 +230,14 @@ def _cuda(): def _snapshot_revision(checkpoint) -> str | None: - """The Hub commit a checkpoint was loaded from: the `snapshots/` directory name.""" parts = Path(checkpoint).parts if checkpoint else () return parts[parts.index("snapshots") + 1] if "snapshots" in parts[:-1] else None def _weights_dtype(engine) -> str | None: model = getattr(engine, "model", None) + if model is None: + return None try: return str(next(model.parameters()).dtype) except (AttributeError, StopIteration, TypeError): @@ -247,9 +245,7 @@ def _weights_dtype(engine) -> str | None: def cmd_presentation_checks(args: argparse.Namespace) -> None: - """Label-free presentation checks (ADR-029). With `--compare`, exits 2 when the run's - settings differ from the report's, and 1 when a metric drifts beyond `--tolerance`; - `--enforce-gate` also fails a check below its gate.""" + """Run presentation checks; exit 2 for settings mismatches and 1 for failed checks.""" import time from . import presentation @@ -331,7 +327,6 @@ def cmd_presentation_checks(args: argparse.Namespace) -> None: def _refuse_other_settings(saved: dict | None, settings: dict, keys) -> None: - """Metrics move with the order mode, the batching and the weights; compare like with like.""" from .presentation import settings_mismatch differ = settings_mismatch(saved, settings, keys) if saved is not None else [] @@ -359,7 +354,7 @@ def main(argv: list[str] | None = None) -> None: route_parser = sub.add_parser("route", help="show the readout mode per question") route_parser.add_argument("request", help="path to a /v1/systemone request JSON") route_parser.add_argument("--model", default="Qwen/Qwen3.5-4B-Base") - # Defaults mirror `EngineConfig`, so the preview matches what a server does. + # Keep route-preview defaults aligned with EngineConfig. route_parser.add_argument( "--max-label-options", type=int, diff --git a/packages/lev/src/lev/data/build.py b/packages/lev/src/lev/data/build.py index 0503770..2612786 100644 --- a/packages/lev/src/lev/data/build.py +++ b/packages/lev/src/lev/data/build.py @@ -1,7 +1,4 @@ -"""Write train, calibration and test JSONL files and a manifest for offline training. - -Source rows are split before sampling or augmentation, so no row leaks across splits (ADR-014). -""" +"""Write offline training splits and a manifest; split before augmentation (ADR-014).""" from __future__ import annotations @@ -77,10 +74,7 @@ def read_jsonl(path: Path) -> list[Example]: def verify_round_trip(path: Path, sample: int = 1000) -> int: - """Check sampled rows of a written split read back exactly; return the number checked. - - Order-sensitive, since `target` indexes option order (ADR-024). Raises `ValueError` on drift. - """ + """Check sampled rows round-trip exactly, including option order; return the count.""" rows = read_jsonl(path) step = max(1, len(rows) // sample) with path.open(encoding="utf-8") as handle: @@ -89,7 +83,7 @@ def verify_round_trip(path: Path, sample: int = 1000) -> int: continue written = json.loads(line) reread = to_json(rows[i]) - # As text: dict equality ignores key order, which a merged question loses. + # Compare serialized text because dict equality ignores option order. if json.dumps(reread, ensure_ascii=False) != json.dumps(written, ensure_ascii=False): raise ValueError( f"{path} row {i} did not survive the round trip: written " @@ -156,8 +150,7 @@ def build_dataset( # A different stream per split, so layouts do not repeat in lockstep. seed=seed + split_index, adjacent=adjacent, - # Test keeps canonical questions (one per eval file); calibration varies - # option sets, not wording, so each option-count band has rows (ADR-026). + # Keep test questions canonical; vary calibration option sets to cover count bands. augment=augment if split is not Split.TEST else {}, **held_out_overrides, ) @@ -171,7 +164,6 @@ def build_dataset( unique_train = sum(len(rows) for rows in by_source[Split.TRAIN].values()) manifest = { "sources": {name: REGISTRY[name].hf_id for name in weights}, - # Sampling with replacement can expose each unique row more than once per epoch. "unique_train_rows": unique_train, "oversample_ratio": round(n_examples / max(1, unique_train), 2), "weights": weights, diff --git a/packages/lev/src/lev/data/contamination.py b/packages/lev/src/lev/data/contamination.py index 83a2466..f49236a 100644 --- a/packages/lev/src/lev/data/contamination.py +++ b/packages/lev/src/lev/data/contamination.py @@ -1,7 +1,4 @@ -"""Reject training sources that resolve to any of the 13 S1Bench subsets. - -`assert_eval_only` is the inverse gate, for the S1Bench evaluation loader. -""" +"""Block S1Bench training sources and restrict evaluation to S1Bench subsets.""" from __future__ import annotations @@ -27,8 +24,7 @@ } ) -# Aliases and parent datasets that resolve to a blocked subset. A mixture that lists -# `google-research-datasets/paws` is contaminated even though the string differs. +# Block aliases and parent datasets, not just exact subset names. _ALIASES: dict[str, str] = { "vitaminc": "vitaminc-dev", "tals/vitaminc": "vitaminc-dev", @@ -38,8 +34,7 @@ "mteb/amazon_massive_scenario": "massive-en-US", "setfit/amazon_massive_intent_en-us": "massive-en-US", "setfit/amazon_massive_scenario_en-us": "massive-en-US", - # Different rows, same 64-intent schema MASSIVE inherited via SLURP: it would - # make massive-en-US a seen taxonomy (ADR-020). + # SLURP shares MASSIVE's intent taxonomy (ADR-020). "hwu64": "massive-en-US", "deeppavlov/hwu64": "massive-en-US", "super_glue/boolq": "boolq", @@ -71,7 +66,7 @@ class ContaminationError(RuntimeError): - """Raised when a training mixture touches an evaluation subset.""" + pass def normalise(name: str) -> str: @@ -83,8 +78,7 @@ def normalise(name: str) -> str: _BLOCKED_BY_NORMALISED: dict[str, str] = {normalise(s): s for s in BLOCKED_SUBSETS} _ALIASES_BY_NORMALISED: dict[str, str] = {normalise(a): t for a, t in _ALIASES.items()} -# Bare aliases match as segment sets, so an unlisted re-host (`someorg/squad_v2_dedup`) -# is caught (ADR-020); org-qualified aliases stay exact-match only. +# Match bare aliases by segments to catch re-hosts; qualified aliases stay exact. _ALIAS_SEGMENTS: tuple[tuple[frozenset[str], str], ...] = tuple( (frozenset(alias.split("-")), target) for alias, target in _ALIASES_BY_NORMALISED.items() @@ -107,8 +101,7 @@ def resolve(name: str) -> str | None: for normalised_subset, subset in _BLOCKED_BY_NORMALISED.items(): if normalised_subset in segments: return subset - # Likewise for a bare alias: every segment of `squad-v2` present, in any order. - # Conservative on purpose: a false block costs one dataset, a miss the result. + # Conservative segment matching prevents renamed evaluation data from entering training. for alias_segments, subset in _ALIAS_SEGMENTS: if alias_segments <= segments: return subset @@ -116,7 +109,7 @@ def resolve(name: str) -> str | None: def check_mixture(dataset_names: Iterable[str]) -> dict[str, str]: - """Return `{offending name: blocked subset}` for everything that collides.""" + """Return the blocked subset for each offending source.""" hits: dict[str, str] = {} for name in dataset_names: if (subset := resolve(name)) is not None: @@ -125,7 +118,7 @@ def check_mixture(dataset_names: Iterable[str]) -> dict[str, str]: def assert_eval_only(dataset_name: str) -> str: - """Return the blocked subset `dataset_name` resolves to; raise `ContaminationError` if none.""" + """Resolve an evaluation subset or raise ContaminationError.""" subset = resolve(dataset_name) if subset is None: raise ContaminationError( @@ -138,7 +131,7 @@ def assert_eval_only(dataset_name: str) -> str: def assert_clean(dataset_names: Iterable[str]) -> None: - """Raise `ContaminationError` if any dataset resolves to a blocked evaluation subset.""" + """Reject sources that resolve to blocked evaluation subsets.""" if hits := check_mixture(dataset_names): listed = "\n".join(f" {src!r} -> blocked subset {dst!r}" for src, dst in hits.items()) raise ContaminationError( diff --git a/packages/lev/src/lev/data/export_eval.py b/packages/lev/src/lev/data/export_eval.py index e824107..a8fc3af 100644 --- a/packages/lev/src/lev/data/export_eval.py +++ b/packages/lev/src/lev/data/export_eval.py @@ -1,7 +1,4 @@ -"""Write the held-out test split as levbench task files, one per source. - -levbench does not import `lev` (ADR-010). A combined file would ask every question of every item. -""" +"""Export held-out rows as levbench task files, one question per source.""" from __future__ import annotations @@ -13,13 +10,12 @@ from .build import _group_by_source, load_split from .splits import Split -# Below this an accuracy is not a measurement: at n=24 the 95% interval is -# about +/-16 points. +# Require enough rows for a useful accuracy estimate. MIN_USEFUL_ITEMS = 100 def truth_for(question: Question, target: int) -> bool | int | str: - """The label levbench compares: a Choice option string, a Score level index, a Noul bool.""" + """Convert a target to a Choice key, Score index, or Noul bool.""" if isinstance(question, Noul): # The target is a rating index; collapse it as the readout does. return noul_probability({target: 1.0}) >= 0.5 @@ -48,8 +44,7 @@ def export( if limit_per_source: rows = rows[:limit_per_source] question = rows[0].question - # A task file has one question for all items, so QA sources with per-row - # options (race, sciq, ...) are skipped; `evaluate_split` still scores them. + # Skip per-row option sets: each task file has one shared question. payloads = {json.dumps(question_payload(r.question), sort_keys=True) for r in rows} if len(payloads) != 1: variable.append(source) diff --git a/packages/lev/src/lev/data/mixture.py b/packages/lev/src/lev/data/mixture.py index cebc1ba..a985fda 100644 --- a/packages/lev/src/lev/data/mixture.py +++ b/packages/lev/src/lev/data/mixture.py @@ -1,12 +1,9 @@ -"""Sample typed training examples with layout, abstention and question variation. - -Loaders are injected so the mixture can be built and tested offline. -""" +"""Sample typed examples with layout, abstention, and question variation.""" from __future__ import annotations import random -from collections.abc import Callable, Iterable, Iterator +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence from dataclasses import dataclass, field from ..labels import NOUL_RATING_TOKENS @@ -25,23 +22,18 @@ class Example: layout: Layout source: str abstain: bool = False - # Abstain examples only: no gold index, so the loss reads this uniform target - # instead of `target`. + # Abstain rows use a uniform soft target instead of a gold index. soft_target: list[float] | None = None @dataclass(frozen=True) class Augment: - """Per-source variation: train varies wording and options, calibration options only (ADR-026). - - `negations` flip the Noul target so "yes" is not always "good"; `min_options` floors subsets. - """ + """Per-source wording and option variation; negations flip Noul targets.""" paraphrases: tuple[str, ...] = () negations: tuple[str, ...] = () min_options: int = 2 - # Fraction of Choice rows exempt from subsampling; they may still be shuffled. - # For a large taxonomy this is the candidate-path head's training data. + # Keep full option sets on this share of rows to train the candidate head. keep_full_fraction: float = 0.0 @@ -52,8 +44,7 @@ class MixtureSpec: schema_first_fraction: float = 0.5 abstain_fraction: float = 0.1 seed: int = 17 - # source -> sources whose states must not be used as abstain donors, - # because they would in fact answer the question. See `sources.ADJACENT`. + # Exclude sources that could still answer the question from abstain donors. adjacent: dict[str, frozenset[str]] = field(default_factory=dict) # Variation per source; empty means canonical questions (ADR-020). augment: dict[str, Augment] = field(default_factory=dict) @@ -64,7 +55,6 @@ class MixtureSpec: description_dropout: float = 0.3 def validate(self) -> None: - # Before any example loads: a contaminated run silently looks better. assert_clean(self.sources.keys()) if not self.sources: raise ValueError("mixture has no sources") @@ -76,12 +66,8 @@ def validate(self) -> None: Loader = Callable[[], Iterable[Example]] -def build_mixture(spec: MixtureSpec, loaders: dict[str, Loader]) -> Iterator[Example]: - """Yield `spec.n_examples`, respecting weights, layout split and abstain rate. - - Raises `ContaminationError` for a blocked source, `KeyError` for one with no loader, and - `ValueError` for no sources, weights not summing to 1, or a source that yields nothing. - """ +def build_mixture(spec: MixtureSpec, loaders: Mapping[str, Loader]) -> Iterator[Example]: + """Sample examples from validated sources using the configured weights and augmentations.""" spec.validate() missing = set(spec.sources) - set(loaders) if missing: @@ -107,16 +93,14 @@ def build_mixture(spec: MixtureSpec, loaders: dict[str, Loader]) -> Iterator[Exa state = example.state question, target = example.question, example.target if (augment := spec.augment.get(source)) is not None: - # Negation flips the target, so it must not touch an abstain row, - # whose supervision is uniform regardless of polarity. + # Abstain supervision is uniform, so do not flip its target. question, target = _vary( question, target, augment, spec, rng, allow_negation=not abstain ) soft_target = None if abstain: - # Swap in an unrelated state and supervise a uniform distribution: - # with no evidence that is the calibrated answer (ADR-012). + # Pair unrelated evidence with uniform supervision (ADR-012). state = _donor_state(pools, source, spec.adjacent, rng) n_candidates = candidate_count(question) soft_target = [1.0 / n_candidates] * n_candidates @@ -142,8 +126,7 @@ def _vary( rng: random.Random, allow_negation: bool, ) -> tuple[Question, int]: - # Preserves the gold answer: negation mirrors a Noul rating, subsampling keeps and - # re-indexes the gold option, and Score levels are never reordered. + # Preserve gold targets through negation and option subsets; never reorder Score levels. instructions = question.instructions can_negate = isinstance(question, Noul) and augment.negations and allow_negation if can_negate and rng.random() < spec.negate_fraction: @@ -177,7 +160,7 @@ def _vary( return Choice(instructions=instructions, criteria=dict(options)), _index_of(options, gold[0]) -def _index_of(options: list[tuple[str, object]], key: str) -> int: +def _index_of(options: Sequence[tuple[str, object]], key: str) -> int: for i, (k, _) in enumerate(options): if k == key: return i @@ -190,8 +173,7 @@ def _donor_state( adjacent: dict[str, frozenset[str]], rng: random.Random, ) -> str | dict | list: - # Another source is not enough: a rotten_tomatoes state answers imdb's question, so - # `adjacent` sources are excluded too; the fallbacks let a narrow mixture still yield. + # Exclude adjacent sources when possible; fall back for narrow mixtures. excluded = {source} | set(adjacent.get(source, ())) eligible = ( [name for name in pools if name not in excluded] diff --git a/packages/lev/src/lev/data/s1bench.py b/packages/lev/src/lev/data/s1bench.py index d97e00b..e81ee79 100644 --- a/packages/lev/src/lev/data/s1bench.py +++ b/packages/lev/src/lev/data/s1bench.py @@ -1,9 +1,4 @@ -"""Export the 13 S1Bench subsets as levbench task files, for evaluation only. - -Must not import training data builders or produce an `Example` (checked by `test_s1bench.py`). -Ids, questions and labels come from Nimble's pinned manifests in `s1bench_subsets/`; -conversion details and the multinli metadata exception are in docs/FINDINGS.md §17. -""" +"""Export S1Bench evaluation data from pinned manifests; keep it outside training (FINDINGS §17).""" from __future__ import annotations @@ -17,19 +12,19 @@ from pathlib import Path from typing import TYPE_CHECKING, cast -if TYPE_CHECKING: # `datasets` is heavy and only imported where it is used. +if TYPE_CHECKING: from datasets import Dataset from ..types import Choice, Noul, Question, Score, question_payload from .contamination import assert_eval_only SUBSET_DIR = Path(__file__).with_name("s1bench_subsets") -QUESTION_NAME = "decision" # S1Bench asks every record one question under this name +QUESTION_NAME = "decision" @dataclass(frozen=True) class EvalItem: - """One S1Bench record; `truth` is a Choice option string, Score level index or Noul bool.""" + """An evaluation record with a Choice key, Score index, or Noul bool as truth.""" id: str state: dict | str @@ -38,11 +33,7 @@ class EvalItem: @dataclass(frozen=True) class EvalSubset: - """One S1Bench subset and Jev's score on it. - - `jev_published` is Jev 1.13's figure; `jev_measured` is the board's `s1-fast` run in - `data/s1bench-snapshot.json`, which covered only six subsets. - """ + """A subset with published Jev 1.13 and measured s1-fast scores.""" name: str hf_id: str @@ -100,14 +91,13 @@ def _download(repo: str, filename: str, revision: str | None = None) -> str: def _parquet(repo: str, filename: str, revision: str | None = None) -> Dataset: - from datasets import load_dataset # heavy, and only needed to export + from datasets import load_dataset - # `split=` narrows load_dataset's return union to the one Dataset the annotation names. return load_dataset("parquet", data_files=_download(repo, filename, revision), split="train") def _rows(dataset: Dataset) -> Iterator[dict]: - # Upstream leaves `Dataset.__iter__` unannotated, so checkers reject column lookups. + # Upstream row iteration lacks type annotations. return cast("Iterator[dict]", iter(dataset)) @@ -264,11 +254,7 @@ def _read_pubmedqa() -> Iterator[EvalItem]: def load_eval_subset(name: str) -> tuple[Question, list[EvalItem]]: - """One S1Bench subset as its question plus exactly its records, sorted by id. - - Raises `ContaminationError` for anything that is not S1Bench evaluation data, - and `ValueError` if the upstream data no longer yields the pinned ids and labels. - """ + """Load a S1Bench subset, validating its records against pinned ids and labels.""" subset = get_subset(name) spec = definition(subset.name) by_id = {item.id: item for item in _READERS[subset.name]()} diff --git a/packages/lev/src/lev/data/sources.py b/packages/lev/src/lev/data/sources.py index 4a56415..25b0606 100644 --- a/packages/lev/src/lev/data/sources.py +++ b/packages/lev/src/lev/data/sources.py @@ -1,7 +1,4 @@ -"""Training dataset registry and readers for Choice, Score and Noul examples. - -Tests use fake loaders, so they do not verify that upstream datasets remain available. -""" +"""Training dataset registry and readers for Choice, Score, and Noul examples.""" from __future__ import annotations @@ -17,8 +14,7 @@ from .contamination import assert_clean from .mixture import Augment, Example -# Large taxonomies whose label names are read at load time, so the registry -# cannot count them. +# Taxonomies with label counts determined at load time. _LARGE_OPTION_SETS = frozenset({"banking77", "clinc_oos"}) Primitive = Literal["choice", "score", "noul"] @@ -27,11 +23,13 @@ MODE_B_SHARE = 0.25 -# What a per-row reader returns: the state to show, the option texts if the row -# carries its own (None means the source's fixed label set), and the gold index. +# Reader output: state, per-row options (None uses fixed labels), and gold index. Row = tuple[str | dict, list[str] | None, int] +ChoiceRow = tuple[str | dict, list[str], int] +PairRow = tuple[dict, None, int] +Rows = list[Row] | list[ChoiceRow] | list[PairRow] # Readers may yield several examples from one row, or None to skip it. -Reader = Callable[[dict, random.Random], Row | list[Row] | None] +Reader = Callable[[dict, random.Random], Row | Rows | None] @dataclass(frozen=True) @@ -61,7 +59,7 @@ def is_mode_b(self) -> bool: return bool(self.label_names) and len(self.label_names) > LABEL_OPTION_CAP -def _read_race(row: dict, rng: random.Random) -> Row | None: +def _read_race(row: dict, rng: random.Random) -> ChoiceRow | None: options = [str(o) for o in row["options"]] index = ord(str(row["answer"]).strip().upper()[:1] or "?") - ord("A") if len(options) < 2 or not 0 <= index < len(options): @@ -69,13 +67,12 @@ def _read_race(row: dict, rng: random.Random) -> Row | None: return {"passage": row["article"], "question": row["question"]}, options, index -def _read_keyed_choices(question_field: str, context_field: str | None = None) -> Reader: - """Read the `choices={"label", "text"}` + `answerKey` shape of commonsense_qa, openbookqa, ARC. - - ARC keys some rows 1-4 rather than A-D, so the key is matched against the labels, not A-Z. - """ +def _read_keyed_choices( + question_field: str, context_field: str | None = None +) -> Callable[[dict, random.Random], ChoiceRow | None]: + """Match answerKey to choice labels, including numeric ARC labels.""" - def reader(row: dict, rng: random.Random) -> Row | None: + def reader(row: dict, rng: random.Random) -> ChoiceRow | None: labels = [str(x) for x in row["choices"]["label"]] texts = [str(x) for x in row["choices"]["text"]] key = str(row["answerKey"]).strip() @@ -92,7 +89,7 @@ def reader(row: dict, rng: random.Random) -> Row | None: return reader -def _read_sciq(row: dict, rng: random.Random) -> Row | None: +def _read_sciq(row: dict, rng: random.Random) -> ChoiceRow | None: gold = row["correct_answer"] options = [gold, row["distractor1"], row["distractor2"], row["distractor3"]] options = [o for o in options if o and str(o).strip()] @@ -122,10 +119,7 @@ def _read_nli(row: dict, rng: random.Random) -> Row | None: def swap_two_words(text: str, rng: random.Random) -> str | None: - """Exchange two distinct content words: full lexical overlap, changed meaning. - - None when there are fewer than two candidates or 8 draws find no distinct pair. - """ + """Swap distinct content words, or return None if no pair is found in eight draws.""" words = text.split() slots = [i for i, w in enumerate(words) if len(w) > 3 and w.isalpha()] if len(slots) < 2: @@ -139,17 +133,15 @@ def swap_two_words(text: str, rng: random.Random) -> str | None: return None -def _read_pair(first: str, second: str, adversarial: float = 0.0) -> Reader: - """Read labelled sentence pairs, optionally adding word-swapped negatives. +def _read_pair( + first: str, second: str, adversarial: float = 0.0 +) -> Callable[[dict, random.Random], list[PairRow]]: + """Read sentence pairs, optionally adding word-swapped negatives to positive rows.""" - `adversarial` is the fraction of positive pairs that also yield a negative, - reducing the usefulness of lexical overlap as a shortcut. - """ - - def reader(row: dict, rng: random.Random) -> list[Row] | None: + def reader(row: dict, rng: random.Random) -> list[PairRow]: a, b = row[first], row[second] label = int(row["label"]) - out: list[Row] = [({"sentence1": a, "sentence2": b}, None, label)] + out: list[PairRow] = [({"sentence1": a, "sentence2": b}, None, label)] adversary = label == 1 and adversarial and rng.random() < adversarial if adversary and (swapped := swap_two_words(b, rng)) is not None: out.append(({"sentence1": a, "sentence2": swapped}, None, 0)) @@ -167,15 +159,14 @@ def reader(row: dict, rng: random.Random) -> list[Row] | None: def _read_nli_fever(row: dict, rng: random.Random) -> Row | None: - # `premise` is the claim and `hypothesis` the evidence; the integer label's - # order differs from FEVER's own, so the string label is used. + # Use FEVER's string label; its integer order differs. label = row.get("fever_gold_label") if label not in FEVER_LABELS: return None return {"claim": row["premise"], "evidence": row["hypothesis"]}, None, FEVER_LABELS.index(label) -def _read_parade(row: dict, rng: random.Random) -> Row | None: +def _read_parade(row: dict, rng: random.Random) -> PairRow: return ( {"sentence1": row["Definition1"], "sentence2": row["Definition2"]}, None, @@ -183,19 +174,20 @@ def _read_parade(row: dict, rng: random.Random) -> Row | None: ) -def _read_strategyqa(row: dict, rng: random.Random) -> Row | None: +def _read_strategyqa(row: dict, rng: random.Random) -> PairRow: return {"question": row["question"], "facts": row["facts"]}, None, int(bool(row["answer"])) -def yes_no_from_choices(reader: Reader) -> Reader: +def yes_no_from_choices(reader: Reader) -> Callable[[dict, random.Random], list[PairRow] | None]: """Turn each multiple-choice row into two Noul rows: gold and wrong proposals.""" - def wrapped(row: dict, rng: random.Random) -> list[Row] | None: + def wrapped(row: dict, rng: random.Random) -> list[PairRow] | None: produced = reader(row, rng) if produced is None: return None - out: list[Row] = [] - for state, options, target in produced if isinstance(produced, list) else [produced]: + out: list[PairRow] = [] + rows = produced if isinstance(produced, list) else [produced] + for state, options, target in rows: if not options or len(options) < 2: continue base = state if isinstance(state, dict) else {"question": state} @@ -207,7 +199,7 @@ def wrapped(row: dict, rng: random.Random) -> list[Row] | None: return wrapped -def _read_toxic_chat(row: dict, rng: random.Random) -> Row | None: +def _read_toxic_chat(row: dict, rng: random.Random) -> Row: return row["user_input"], None, int(row["toxicity"]) @@ -219,9 +211,7 @@ def _read_toxigen(row: dict, rng: random.Random) -> Row | None: return row["text"], None, int(float(score) >= 3.0) -def _read_beavertails(row: dict, rng: random.Random) -> Row | None: - # `is_safe` True -> yes; the registry's negation keeps polarity from being - # constant. +def _read_beavertails(row: dict, rng: random.Random) -> PairRow: return {"prompt": row["prompt"], "response": row["response"]}, None, int(bool(row["is_safe"])) @@ -234,8 +224,8 @@ def _read_beavertails(row: dict, rng: random.Random) -> Row | None: ) -def _read_ultrafeedback(row: dict, rng: random.Random) -> list[Row] | None: - out: list[Row] = [] +def _read_ultrafeedback(row: dict, rng: random.Random) -> list[PairRow] | None: + out: list[PairRow] = [] for completion in row.get("completions") or []: rating = ((completion.get("annotations") or {}).get("helpfulness") or {}).get("Rating") if rating is None: @@ -273,7 +263,6 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: REGISTRY: dict[str, SourceSpec] = { - # Choice: small, well-separated option sets. "ag_news": SourceSpec( name="ag_news", hf_id="fancyzhx/ag_news", @@ -307,8 +296,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: "What type of entity is being described?", ), ), - # Choice with the question varying per row: the state alone cannot identify - # the answer set, so the model has to read the question. + # Per-row questions require reading the options as well as the state. "race": SourceSpec( name="race", hf_id="ehovy/race", @@ -355,8 +343,6 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: paraphrases=("Choose the correct answer.", "What is the right answer to this question?"), reader=_read_keyed_choices("question"), ), - # Natural language inference: the same three options every time, but the - # answer depends on a relation between two fields, not on either alone. "snli": SourceSpec( name="snli", hf_id="stanfordnlp/snli", @@ -406,7 +392,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: label_names=SNIPS_INTENTS, reader=_read_snips, ), - # Large taxonomies: their full sets train the Mode B head. + # Full taxonomies train the Mode B head. "banking77": SourceSpec( name="banking77", hf_id="legacy-datasets/banking77", @@ -467,8 +453,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: label_names=HELPFULNESS_LEVELS, reader=_read_ultrafeedback, ), - # Noul: a single yes/no proposition. Every source carries a negation, so the - # mixture asks both polarities and "yes" is not always the good outcome. + # Each Noul source includes a negation to vary answer polarity. "imdb": SourceSpec( name="imdb", hf_id="stanfordnlp/imdb", @@ -485,7 +470,6 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: paraphrases=("Did the critic like it?", "Is the sentiment favourable?"), negations=("Is this review negative?", "Did the critic pan it?"), ), - # Paraphrase, with word-swapped negatives so overlap is not the answer. "mrpc": SourceSpec( name="mrpc", hf_id="SetFit/mrpc", @@ -516,7 +500,6 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: label_names=YES_NO, reader=_read_parade, ), - # Yes/no on a factual axis: a proposed answer to a grounded question. "strategyqa": SourceSpec( name="strategyqa", hf_id="ChilleD/StrategyQA", @@ -594,7 +577,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: ), } -# Checked once, at import. A contaminated id must never reach a loader. +# Reject contaminated source ids before loading. assert_clean(REGISTRY.keys()) assert_clean([spec.hf_id for spec in REGISTRY.values()]) @@ -602,8 +585,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: name for name, spec in REGISTRY.items() if spec.is_mode_b ) -# Sources whose states can answer each other's questions, so none donates an abstain -# state to another (ADR-012); e.g. clinc_oos contains banking intents. +# Adjacent sources may answer each other's questions; exclude them as abstain donors. ADJACENT: tuple[frozenset[str], ...] = ( frozenset({"imdb", "rotten_tomatoes", "sst5", "yelp_review_full", "emotion"}), frozenset({"banking77", "clinc_oos", "snips"}), @@ -628,11 +610,7 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: def family_of(source: str) -> str: - """The task family a source belongs to: its `ADJACENT` group, else itself. - - Holding out mrpc while qqp stays in is not a new task, so calibration - transfer is measured over families, not sources (ADR-028). - """ + """Return the adjacent-source family used for calibration transfer (ADR-028).""" for group in ADJACENT: if source in group: return "+".join(sorted(group)) @@ -640,7 +618,7 @@ def family_of(source: str) -> str: def adjacency_map() -> dict[str, frozenset[str]]: - """source -> the sources whose states must not be used to make it unanswerable.""" + """Map sources to those excluded as abstain donors.""" return { name: frozenset().union(*(group for group in ADJACENT if name in group)) - {name} for name in REGISTRY @@ -679,7 +657,6 @@ def build_question(spec: SourceSpec, names: list[str]) -> Question: return Noul(instructions=spec.instructions) options = [humanise(n) for n in names] if spec.primitive == "score": - # `list` is invariant, so the element type has to be the one Score declares. levels: list[JSONContent] = [*options] return Score(instructions=spec.instructions, criteria=levels) return Choice( @@ -696,13 +673,9 @@ def load_source( seed: int = 17, load_dataset: Callable | None = None, ) -> Iterator[Example]: - """Yield examples, shuffling before applying a row limit. - - A head slice can contain only one class in a label-sorted corpus. - `load_dataset` is injectable so tests run offline. - """ + """Yield examples through an injectable loader, shuffling before applying the limit.""" if load_dataset is None: - from datasets import load_dataset # noqa: PLC0415 + from datasets import load_dataset extra = {"revision": spec.revision} if spec.revision else {} dataset = load_dataset( @@ -711,8 +684,7 @@ def load_source( if limit is not None and limit < len(dataset): dataset = dataset.shuffle(seed=seed).select(range(limit)) - # A fixed label set comes from the ClassLabel or the spec; a reader that - # supplies options per row has none. + # Fixed labels come from ClassLabel or the spec; per-row readers supply their own. names = _label_names(spec, dataset) if spec.reader is None or spec.label_names else None fixed_question = build_question(spec, names) if names is not None else None is_noul = spec.primitive == "noul" @@ -755,8 +727,7 @@ def emit(state, question: Question, target: int, n_labels: int, i: int) -> Examp raise ValueError(f"{spec.name}: reader gave no options and spec has no labels") yield emit(state, fixed_question, target, len(names), i) else: - # Duplicate options would collapse in the criteria map and shift - # the gold index. + # Duplicate options collapse map keys and corrupt the gold index. if len(set(options)) != len(options): continue question = Choice( @@ -776,12 +747,7 @@ def _blank(state) -> bool: def augmentation_map() -> dict[str, Augment]: - """Per-source augmentation for the train and calibration mixtures, read off the registry. - - Large taxonomies keep their full option set half the time (the Mode B head's - data) and otherwise may be cut to `LARGE_SET_MIN_OPTIONS` or more, so Mode A - also learns large lettered sets. Everything else may be cut to two (ADR-026). - """ + """Configure option variation; large taxonomies retain full sets half the time (ADR-026).""" return { name: Augment( paraphrases=spec.paraphrases, @@ -794,11 +760,7 @@ def augmentation_map() -> dict[str, Augment]: def default_weights() -> dict[str, float]: - """Sampling weight per source: `MODE_B_SHARE` to Mode B, the rest by primitive. - - The remainder splits evenly across the three primitives, then within each, - so no readout is starved by having few sources. - """ + """Reserve MODE_B_SHARE for large taxonomies; balance the remainder across primitives.""" mode_b_sources = sorted(MODE_B_SOURCES) sources_by_primitive: dict[str, list[str]] = {} for name, spec in REGISTRY.items(): diff --git a/packages/lev/src/lev/data/splits.py b/packages/lev/src/lev/data/splits.py index ce5fdf6..2d09c2a 100644 --- a/packages/lev/src/lev/data/splits.py +++ b/packages/lev/src/lev/data/splits.py @@ -1,7 +1,4 @@ -"""Deterministic, disjoint train, calibration and test splits (ADR-014). - -The key includes row position: the same input order reproduces a split, reordering changes it. -""" +"""Deterministic splits keyed by source and row position; input order matters (ADR-014).""" from __future__ import annotations @@ -24,8 +21,6 @@ class Split(StrEnum): # Changing this re-splits every row, making models before and after incomparable. SPLIT_SALT = "lev-split-v1" -# A temperature needs far fewer rows than a model, and test only has to separate -# two runs. DEFAULT_FRACTIONS: dict[Split, float] = { Split.TRAIN: 0.80, Split.CALIBRATION: 0.10, @@ -38,7 +33,7 @@ def row_key(source: str, index: int, text: str) -> str: def hash_position(key: str, salt: str = SPLIT_SALT) -> float: - """Map a key to a uniform float in [0, 1), stable across processes, unlike salted `hash()`.""" + """Map a key to a process-stable float in [0, 1).""" digest = hashlib.blake2b(f"{salt}|{key}".encode(), digest_size=8).digest() return int.from_bytes(digest, "big") / float(1 << 64) @@ -89,19 +84,14 @@ def split_examples( def check_coverage(splits: dict[Split, list[Example]], strict: bool = True) -> SplitReport: - """Run two label-coverage checks (ADR-014); with `strict`, raise `ValueError` on either. - - Every observed label must appear in train, and every label the question offers must be - observed at all, which catches a truncated or label-sorted corpus the first check passes. - """ + """Check observed labels appear in train and offered labels appear in the data.""" seen: dict[str, set[int]] = defaultdict(set) in_train: dict[str, set[int]] = defaultdict(set) offered: dict[str, int] = {} for split, items in splits.items(): for example in items: seen[example.source].add(example.target) - # A Noul offers nine rating levels but its data supplies only the two - # ends, so "every offered label must be observed" does not apply. + # Binary Noul data only covers the rating scale's endpoints. if example.question.type != "noul": offered.setdefault(example.source, candidate_count(example.question)) if split is Split.TRAIN: diff --git a/packages/lev/src/lev/labels.py b/packages/lev/src/lev/labels.py index e1b4ee0..8439649 100644 --- a/packages/lev/src/lev/labels.py +++ b/packages/lev/src/lev/labels.py @@ -4,17 +4,18 @@ from itertools import islice, product from string import ascii_uppercase +from typing import Protocol -# Above this the source registry trains a label set's full taxonomy on the Mode B -# head; routing follows the tokenizer, not this cap (ADR-025/026). + +class TokenEncoder(Protocol): + def encode(self, text: str, *, add_special_tokens: bool = True) -> list[int]: ... + + +# Training taxonomy cap; serving routes by tokenizer support (ADR-025/026). LABEL_OPTION_CAP = len(ascii_uppercase) def label_codes(n: int) -> list[str]: - """First `n` codes: A..Z, then AA..ZZ, then AAA..ZZZ. - - Raises for n > 18,278 (past ZZZ). - """ if n < 1: raise ValueError("need at least one code") codes = list(islice(_all_codes(), n)) @@ -26,19 +27,13 @@ def label_codes(n: int) -> list[str]: def single_token_codes( tokenizer, n: int, prefix: str = " ", skip_multi_token: bool = False ) -> list[str] | None: - """Return `n` single-token codes, or None to request Mode B. - - The prefix must match the answer boundary: a space in plain prompts, - no space in chat prompts. By default, all first `n` codes must pass. - Serving may skip split codes; training retains contiguous codes (ADR-028). - """ + """Find n single-token codes using the prompt boundary prefix; optionally skip split codes.""" if not skip_multi_token: try: codes = label_codes(n) except ValueError: return None - verified = [c for c in codes if _is_single_token(tokenizer, prefix + c)] - return verified[:n] if len(verified) >= n else None + return codes if all(_is_single_token(tokenizer, prefix + c) for c in codes) else None picked: list[str] = [] for code in _all_codes(): @@ -50,7 +45,6 @@ def single_token_codes( def _all_codes(): - """A..Z, AA..ZZ, AAA..ZZZ, lazily -- the same order as `label_codes`.""" yield from ascii_uppercase for width in (2, 3): for t in product(ascii_uppercase, repeat=width): @@ -61,8 +55,7 @@ def _is_single_token(tokenizer, text: str) -> bool: return len(tokenizer.encode(text, add_special_tokens=False)) == 1 -# A rating scale, not yes/no, so a Noul answer carries a calibratable -# distribution (docs/ARCHITECTURE.md §3.4). +# Rating probabilities allow Noul calibration (ARCHITECTURE §3.4). NOUL_RATING_TOKENS = [str(i) for i in range(9)] diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index b0a2c09..00a7eaa 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -33,8 +33,7 @@ _QUESTIONS = TypeAdapter(dict[str, Question]) -# Padded tokens (rows x widest row) per forward: `lev.batcher`'s budget, and the most a -# request Score averaging grew may need (ADR-029, ADR-030). +# Padded-token budget shared by batching and Score-order averaging. MAX_BATCH_TOKENS = 16384 @@ -50,19 +49,15 @@ class EngineConfig: noul_readout: Literal["rating", "binary"] = "rating" # A second option order reduces letter-position bias; costs one extra batch row. order_average: bool = True - # Score levels keep their low-to-high order unless this opts in (ADR-029): "reversed" - # adds the reversed order (2 rows per Score, as Choice), "cyclic" every rotation (K rows). - # Both show the model level orders training never produces (ADR-020, FINDINGS §12). + # Score averaging adds reversed (2 rows) or cyclic (K rows) orders absent from training. score_order_average: Literal["off", "reversed", "cyclic"] = "off" - # A request whose Score averaging added rows must fit this many padded tokens; `prepare` - # refuses it otherwise (HTTP 422). Requests without added Score rows are never refused. + # Reject over-budget requests only when Score averaging added rows. max_batch_tokens: int | None = MAX_BATCH_TOKENS # Serving can skip split codes; training keeps large sets for Mode B (ADR-028). skip_multi_token_codes: bool = True # Forking avoids repeated prefix work but adds a forward and cache copies (ADR-023). prefix_mode: Literal["fork", "single"] = "single" - # Off because it measured slower on this backbone (ADR-023). When enabled, - # inputs are padded to shape buckets and warmup captures graphs at startup. + # Opt-in compilation uses shape buckets; measured slower than eager (ADR-023). compile: bool = False pad_to: int = 32 @@ -108,11 +103,7 @@ def want_hidden(self) -> bool: def average_orders(prob_rows: list[list[float]], orders: list[list[int] | None]) -> list[float]: - """Map each rendered-order distribution back to canonical order and average. - - `probs[j]` belongs to canonical slot `order[j]`; averaging probabilities, not - logits, keeps the result a distribution. - """ + """Restore canonical candidate order and average probabilities, not logits.""" if len(prob_rows) != len(orders): raise ValueError("one order per probability row") k = len(prob_rows[0]) @@ -138,8 +129,7 @@ def serving_routes( class DecisionEngine: - """Answers typed questions about a state in one forward pass; `answer` puts - several prepared requests in the same forward.""" + """Answer typed questions, batching prepared requests into shared forwards.""" def __init__( self, @@ -157,17 +147,15 @@ def __init__( self.checkpoint: Path | None = None self._candidate_cache: dict[tuple[str, ...], Any] = {} self._device = getattr(model, "device", None) - # One forward at a time: CUDA-graph replay is not thread-safe. The server - # batches concurrent requests into one forward instead (`lev.batcher`). + # Serialize forwards because CUDA-graph replay is not thread-safe. self._lock = threading.Lock() - # A fast tokenizer's padding and truncation are shared state: concurrent - # calls raise "Already borrowed" or encode with another call's truncation. + # Serialize tokenizer access to protect shared padding and truncation settings. self._tokenizer_lock = threading.RLock() - # The decoder runs alone and `lm_head` projects only the scored - # positions: full (rows, width, vocab) logits are GBs at a 248k vocabulary. base = model.get_base_model() if hasattr(model, "get_base_model") else model - self._decoder = base.get_decoder() if model is not None else None - self._lm_head = base.get_output_embeddings() if model is not None else None + # Held apart so the head runs on scored positions only (`_project`), instead of + # allocating logits for the whole sequence. `Any`: the wrappers are dynamically typed. + self._decoder: Any = base.get_decoder() if model is not None else None + self._lm_head: Any = base.get_output_embeddings() if model is not None else None self._eager_decoder = self._decoder if self.config.compile: import torch @@ -185,10 +173,7 @@ def warmup( (2, 512), ), ) -> float: - """Run one forward per shape bucket so compile and graph capture happen - before the first request. Returns seconds spent. Falls back to eager, - with a warning, if the compiled path fails. - """ + """Warm compiled shape buckets; return elapsed seconds and fall back to eager on failure.""" import torch started = time.perf_counter() @@ -208,21 +193,17 @@ def warmup( return time.perf_counter() - started def system_one(self, state, questions: Mapping[str, Question | dict]) -> SystemOneResponse: - """Answer every question about `state` in one forward pass. Questions may - be `Noul`/`Choice`/`Score` objects or the same shapes as plain dicts.""" + """Answer typed or JSON-shaped questions about a state.""" return self.answer([self.prepare(state, questions)])[0] def prepare(self, state, questions: Mapping[str, Question | dict]) -> Prepared: - """Validate, route and tokenise one request. Raises `ValueError` or - `TypeError` for a malformed one, and `RuntimeError` for one that needs - Mode B with no head loaded, before any GPU work.""" + """Validate and tokenize a request, rejecting malformed input or a missing Mode B head.""" questions = _QUESTIONS.validate_python(questions) with self._tokenizer_lock: return self._route_and_tokenise(state, questions) def question_rows(self, questions: Mapping[str, Question | dict]) -> dict[str, int]: - """Batch rows each question adds to a request under this engine's config: - the orders `prepare` renders it in. Depends on routing, not on the state.""" + """Count rendered orders per question under the current routing configuration.""" questions = _QUESTIONS.validate_python(questions) with self._tokenizer_lock: routes = serving_routes(questions, self.tokenizer, self.config) @@ -249,8 +230,7 @@ def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared 1 for v in variants if v.order is not None and isinstance(questions[v.name], Score) ) limit = self.config.max_batch_tokens - # The batcher runs an oversized request alone and unsplit; refuse only one that - # Score averaging grew, so a request main accepts is never refused for its size. + # Oversized requests run alone; reject only growth from Score averaging. if limit is not None and added and prepared.rows * prepared.width > limit: raise ValueError( f"this request needs {prepared.rows} rows x {prepared.width} tokens = " @@ -262,8 +242,7 @@ def _route_and_tokenise(self, state, questions: dict[str, Question]) -> Prepared return prepared def answer(self, requests: list[Prepared]) -> list[SystemOneResponse]: - """Answer prepared requests, in single prefix mode all in one forward. - Rows are independent, so batching requests changes no row's inputs.""" + """Answer prepared requests; single-prefix mode batches them into one forward.""" logits, hidden = self._forward(requests) responses, start = [], 0 for request in requests: @@ -310,12 +289,7 @@ def _respond(self, request: Prepared, logits, hidden) -> SystemOneResponse: ) def _orders(self, question: Question, route: Route) -> list[list[int] | None]: - """Candidate orders to render; None means the original order. Only lettered - Choice and binary Noul in state-first layout are reversed (ordered scales - keep training's low-to-high order; schema-first shares options), unless - `score_order_average` opts a Score in: "reversed" adds one row, "cyclic" - K-1, both in orders training never shows (ADR-029). `order_average=False` - reads every question once.""" + """Choose candidate orders; keep scales canonical unless Score averaging is enabled.""" if ( not self.config.order_average or route.mode is not Mode.LABEL_TOKEN @@ -361,8 +335,7 @@ def _render( for name, question in questions.items() for order in self._orders(question, routes[name]) ] - # Every variant shares one prefix by construction; a mismatch would make - # the cache wrong, not just slow. + # Variants must share a prefix for cache reuse to be valid. prefixes = {r.prefix for _, _, r in rendered} if len(prefixes) != 1: raise AssertionError(f"layout produced {len(prefixes)} prefixes, expected 1") @@ -372,8 +345,7 @@ def _render( ] def _forward(self, requests: list[Prepared]): - """Logits `(N, V)` and, for Mode B, hidden states `(N, H)` at every - variant's last token, rows in request order.""" + """Return last-token logits (N, V) and optional hidden states (N, H) in request order.""" import torch want_hidden = any(r.want_hidden for r in requests) @@ -386,13 +358,13 @@ def _forward(self, requests: list[Prepared]): for r in requests ] logits = torch.cat([logits for logits, _ in outs]) - hidden = torch.cat([hidden for _, hidden in outs]) if want_hidden else None + hidden = ( + torch.cat([hidden for _, hidden in outs if hidden is not None]) if want_hidden else None + ) return logits, hidden def _forward_single(self, rows: list[list[int]], want_hidden: bool): - """One right-padded batch of prefix+suffix rows. Under `compile`, rows pad to - a power of two and width to `pad_to`, so few graphs are recorded; padding - changes no real row, since right padding is masked and rows are independent.""" + """Run right-padded prefix/suffix rows, using shape buckets when compiled.""" import torch device = self._device @@ -465,6 +437,7 @@ def _label_token_scores(self, logits, route: Route) -> list[float]: self.tokenizer, prefix=label_prefix(Style(self.config.prompt_style)) ) with self._tokenizer_lock: + assert route.codes is not None, "Mode A requires label codes" candidate_ids = readout.candidate_ids(route.codes) return logits[candidate_ids].float().tolist() @@ -486,9 +459,7 @@ def _candidate_path_scores(self, hidden, question: Question) -> list[float]: return scores[0].float().tolist() def _candidate_reprs(self, texts: list[str]): - """One hidden vector per candidate string, cached per candidate set. The cache - is unbounded: fine for fixed schemas (151 candidates ~1.5 MB), not for - arbitrary caller-supplied option sets.""" + """Cache candidate embeddings without a size bound; intended for fixed schemas.""" import torch key = tuple(texts) @@ -522,7 +493,7 @@ def _to_answer(self, question: Question, route: Route, probs: list[float]): if isinstance(question, Choice): distribution = dict(zip(question.criteria, probs, strict=True)) return ChoiceAnswer( - choice=max(distribution, key=distribution.get), + choice=max(distribution, key=distribution.__getitem__), probabilities=distribution, confidence=confidence, ) @@ -538,8 +509,7 @@ def _to_answer(self, question: Question, route: Route, probs: list[float]): if isinstance(question, Noul): if route.reason == BINARY_NOUL: - # Two lettered options, yes first; no rating distribution exists, - # so `probabilities` stays absent. + # Binary Noul has no rating distribution. return NoulAnswer(noul=probs[0], probabilities=None, confidence=confidence) by_rating = dict(enumerate(probs)) return NoulAnswer( @@ -566,24 +536,16 @@ def load( max_batch_tokens: int | None = MAX_BATCH_TOKENS, merge_adapter: bool = True, ) -> DecisionEngine: - """Load a checkpoint -- a release directory, a training output or a Hub id -- - into a ready `DecisionEngine`. With no checkpoint, serves `model_id` frozen. + """Load an engine from a release, training output, or Hub id; otherwise use the frozen base. - engine = lev.load("interfaze-ai/lev") - engine.system_one(state, {"urgent": {"type": "noul", "instructions": "..."}}) - - A release's `lev_release.json` names the base model and prompt style its - weights were trained under and overrides `model_id` and `prompt_style`. The - Mode B head and `calibration.json` beside the adapter are picked up; a - missing calibration is warned about, not hidden. - """ + Release metadata overrides the base model and prompt style. Load the checkpoint's + tokenizer, head, and calibration when present; warn if calibration is missing.""" import torch from transformers import AutoModelForCausalLM, AutoTokenizer from .train.checkpoints import CALIBRATION, resolve_checkpoint - # A checkpoint holds a LoRA adapter, not a full model: load the base from - # `model_id`, then apply the adapter. + # Load the base model before applying the checkpoint's adapter. resolved = resolve_checkpoint(checkpoint, cache_dir) if checkpoint else None manifest_file = resolved / "lev_release.json" if resolved else None if manifest_file and manifest_file.is_file(): @@ -596,8 +558,7 @@ def load( ) model_id = manifest["base_model"] - # The checkpoint's own tokenizer when saved: Mode A reads specific token ids, - # so a mismatched tokenizer gives plausible wrong answers, not an error. + # Use the saved tokenizer to preserve Mode A label ids. tok_source = resolved if resolved and (resolved / "tokenizer.json").is_file() else model_id tokenizer = AutoTokenizer.from_pretrained(str(tok_source), cache_dir=cache_dir) @@ -615,18 +576,14 @@ def load( if resolved: from peft import PeftModel - # Merged by default: the forward is launch-bound (ADR-023), so the per-layer - # lora_A/lora_B matmuls cost launches rather than arithmetic, and graph - # capture needs the weights fixed. `merge_adapter=False` keeps the adapter - # separate, which is what lets its scale be swept without retraining. + # Merge to reduce launches and fix graph weights; keep separate for adapter-scale sweeps. model = PeftModel.from_pretrained(model, str(resolved)) if merge_adapter: model = model.merge_and_unload() head = _load_head(resolved / MODE_B_HEAD, model) model = model.eval() - # Default to the profile sitting beside the weights it was fitted for: - # inside a flat release directory, or one level up in a training tree. + # Use calibration beside release weights or above training checkpoints. if calibration is None and resolved: candidates = [resolved / CALIBRATION, resolved.parent / CALIBRATION] calibration = next((c for c in candidates if c.is_file()), candidates[-1]) @@ -639,8 +596,7 @@ def load( config = EngineConfig( model_id=model_id, - # A stock checkpoint pins the 0-8 rating scale at one end regardless of - # content (ADR-007), so untrained serving reads Noul as two options. + # Use binary Noul for untrained backbones with unreliable rating scales (ADR-007). noul_readout=noul_readout or ("rating" if resolved else "binary"), compile=compile, prompt_style=prompt_style or "plain", @@ -679,12 +635,6 @@ def _bucket_type(question: Question, route: Route) -> str: def _fork(cache, n: int, device=None): - """Copy a batch-1 prefix cache and expand it to `n` rows. - - `reorder_cache` supports both full- and linear-attention layers; - `batch_repeat_interleave` does not. Copy first because reordering mutates - the cache and the original must stay reusable. - """ import torch forked = copy.deepcopy(cache) @@ -694,7 +644,6 @@ def _fork(cache, n: int, device=None): def _gini(probs: list[float]) -> float: - """Normalised Gini concentration: uniform -> 0, point mass -> 1.""" k = len(probs) if k <= 1: return 1.0 diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py index 835002b..34b9020 100644 --- a/packages/lev/src/lev/presentation.py +++ b/packages/lev/src/lev/presentation.py @@ -1,37 +1,15 @@ -"""Presentation checks: does an answer move with where an option is shown? - -The design of NandhaKishorM/laya#259, over `system_one` (ADR-029). Per question type -(Score and Choice), on any list of states, with no labels: - -- **identical**: the position bias of one read, before any order averaging. Every - option carries the same text, so options differ only by position and code. Metric: - slot 0's log-probability minus the mean over the slots, averaged over states and - configurations; 0 is no position effect. It is read with `order_average=False`, - because averaged orders cancel it by construction (cyclic) or hide the middle slots - (reversed): it measures the bias averaging has to remove, not what is left after it. - Choice keys must be unique, so they are shapes with no order (`KEYS`), and every - assignment of keys to slots is read, so a key's own pull cancels. -- **first_slot**: three real options in all 3! = 6 orders per state, read as the engine - is configured. An order-free readout picks slot 0 in exactly 1/3 of the decisions; a - tie gives each of its m slots 1/m. `consistent` is the share of states whose six orders - all give one answer. In the chat style a Score line names its level by its place in - the request (`(level i of K)`), so a permuted listing renumbers the levels too. -- **packed**: the largest probability difference between the probe's answers and each - question asked alone, so what is measured is the presentation and not the packing. - -Probabilities are whatever `system_one` returns: calibrated, unless the engine carries -an empty `CalibrationProfile`. Within one question, calibrated log-probabilities are the -raw scores divided by the bucket's temperature, so the identical metric shrinks by 1/T -and the first-slot rate does not change. The proposed gate, -0.20, is Laya's, set on -raw scores. -""" +"""Label-free checks for option-position bias and packing consistency (ADR-029). + +Identical-option probes use one order; real-option probes use configured averaging. +Scores use returned probabilities: calibration scales the identical metric by 1/T. +The -0.20 gate comes from Laya's raw-score checks (NandhaKishorM/laya#259).""" from __future__ import annotations import itertools import json import math -from collections.abc import Iterator, Mapping, Sequence +from collections.abc import Generator, Mapping, Sequence from contextlib import contextmanager from dataclasses import replace from typing import Any @@ -41,7 +19,7 @@ KEYS = ("■", "●", "◆", "▲", "◎") SLOT0_MIN = -0.20 FIRST_SLOT_MIN = 0.15 -# Batch rows per probe call: a full bench_en run peaked at 22.5 GiB reserved on a 32 GB card. +# Limit probe rows to bound GPU memory use. MAX_ROWS = 32 # en follows Laya's presentation_checks.py; ja the same wording in Japanese. @@ -80,7 +58,7 @@ }, } -# Settings a report records. The first group is known before the model loads. +# Check pre-load settings before spending time loading weights. PRE_LOAD = ("n_states", "lang", "raw", "kinds", "score_order_average", "max_rows") POST_LOAD = ("checkpoint_revision", "dtype") SETTINGS = PRE_LOAD + POST_LOAD @@ -101,8 +79,7 @@ def identical_questions(kind: str, text: str, k: int, instructions: str) -> dict def probe_questions(lang: str = "en", kinds: Sequence[str] = KINDS) -> dict[str, dict]: - """Every probe question for one state, keyed `kind|identical|text|k|keys` or - `kind|perm|012`.""" + """Build identical-option and permutation probes with structured question ids.""" questions: dict[str, dict] = {} for kind in kinds: spec = TEXT[lang][kind] @@ -127,7 +104,7 @@ def is_identical(qid: str) -> bool: @contextmanager -def configured(engine, **changes) -> Iterator[None]: +def configured(engine, **changes) -> Generator[None, None, None]: """Run the block with `engine.config` changed as given, then restore it.""" config = engine.config engine.config = replace(config, **changes) @@ -138,13 +115,11 @@ def configured(engine, **changes) -> Iterator[None]: def single_order(engine): - """Read every question once, in the order given.""" return configured(engine, order_average=False) def call_groups(engine, questions: dict[str, dict], max_rows: int) -> list[dict[str, dict]]: - """`questions` split into `system_one` calls of at most `max_rows` batch rows, as the - engine counts them under its current config.""" + """Group questions into calls within the engine's rendered-row budget.""" rows = engine.question_rows(questions) groups: list[dict[str, dict]] = [] current: dict[str, dict] = {} @@ -167,8 +142,7 @@ def ask( kinds: Sequence[str] = KINDS, max_rows: int | None = None, ) -> list[dict[str, Any]]: - """Every probe answer for every state: the identical questions in one order, the - permuted ones as the engine is configured. Calls hold at most `max_rows` batch rows.""" + """Run single-order identical probes and configured permutation probes within max_rows.""" max_rows = max_rows or MAX_ROWS questions = probe_questions(lang, kinds) identical = {q: v for q, v in questions.items() if is_identical(q)} @@ -182,8 +156,7 @@ def ask( with single_order(engine): for group in identical_groups: got.update(engine.system_one(state, group).answers) - # The probe sizes its own calls; the serving limit would refuse its averaged - # calls on long states. + # Probes enforce their own row budget instead of the serving token limit. with configured(engine, max_batch_tokens=None): for group in permuted_groups: got.update(engine.system_one(state, group).answers) @@ -282,8 +255,7 @@ def packed_consistency( lang: str = "en", kinds: Sequence[str] = KINDS, ) -> float: - """Largest |p| difference between `ask`'s answers for `states` and each question asked - alone, under the same order setting.""" + """Return the largest probability difference between packed and individual probes.""" questions = probe_questions(lang, kinds) worst = 0.0 for state, packed in zip(states, answers, strict=False): @@ -302,8 +274,6 @@ def packed_consistency( def settings_mismatch(saved: dict, run: dict, keys: Sequence[str] = SETTINGS) -> list[str]: - """Every setting among `keys` that `saved` recorded and this run does not share, as - ` (report: X, run: Y)`. A setting the report never recorded is not checked.""" return [ f"{key} (report: {saved[key]!r}, run: {run.get(key)!r})" for key in keys @@ -343,6 +313,5 @@ def to_markdown(report: dict) -> str: def read_states(path: str) -> list[Any]: - """`state` from each line of a JSONL file (bench_en.jsonl, bench_ja.jsonl or your own).""" with open(path, encoding="utf-8") as fh: return [json.loads(line)["state"] for line in fh if line.strip()] diff --git a/packages/lev/src/lev/prompt.py b/packages/lev/src/lev/prompt.py index 4b65878..6e03c0e 100644 --- a/packages/lev/src/lev/prompt.py +++ b/packages/lev/src/lev/prompt.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +from collections.abc import Mapping from dataclasses import dataclass from enum import StrEnum @@ -18,20 +19,14 @@ class Layout(StrEnum): class Style(StrEnum): - """Prompt format recorded with the weights and shared by training and serving. - - Plain uses Context/Question/Options/Answer sections. Chat uses ChatML with - a system prompt and an empty think block (ADR-027). - """ + """Plain or ChatML prompts; the format must match training (ADR-027).""" PLAIN = "plain" CHAT = "chat" def label_prefix(style: Style) -> str: - """The character before a label token as the model emits it: a space after - `Answer:`, nothing at the start of an assistant turn. Verifying the wrong - variant passes while the scored token differs.""" + """Use a space after plain Answer: and no prefix at the start of a chat answer.""" return " " if style is Style.PLAIN else "" @@ -50,11 +45,7 @@ def label_prefix(style: Style) -> str: @dataclass(frozen=True) class Rendered: - """A prompt split at the point the cache is taken. - - `prefix` is computed once and reused; `suffix` is the varying part. The scored - position is always the final token of `suffix`. - """ + """Reusable prefix and varying suffix; score the suffix's final token.""" prefix: str suffix: str @@ -85,19 +76,13 @@ def render_question( order: list[int] | None = None, style: Style = Style.PLAIN, ) -> str: - """Render one question. `codes` are Mode A label codes; None means Mode B. - - `order` indexes the question's own candidates; codes are positional, so two - orders averaged cancel first-letter bias. A Noul with two codes is the binary - readout for an untrained checkpoint, which cannot rate 0-8 (ADR-007). - """ + """Render positional label codes or Mode B text; two Noul codes select binary readout.""" if style is Style.CHAT: return _render_question_chat(name, question, codes, order) lines = [f"Question: {question.instructions or name}"] if isinstance(question, Choice): - # Mode B does not list options: the head embeds each candidate's text, - # and listing 151 intents would cost ~700 tokens per prompt. + # Mode B embeds candidates separately, avoiding long option lists in prompts. if codes: lines.append("Options:") items = _ordered(list(question.criteria.items()), order) @@ -134,8 +119,7 @@ def render_question( def _render_question_chat( name: str, question: Question, codes: list[str] | None, order: list[int] | None ) -> str: - """reflex's headed layout: `# Criterion`, `# Options` with `A. text` lines, - and an explicit ask. Codes are positional, as in the plain style.""" + """Render ChatML criterion and option sections with positional codes.""" lines = [f"# Criterion\n{question.instructions or name}\n"] if isinstance(question, Choice): @@ -181,8 +165,7 @@ def _render_question_chat( def render_content(value: JSONContent) -> str: - """A `JSONContent` field as prompt text. Objects are dumped with sorted keys - so an identical value always renders identically, as `render_state` does.""" + """Render JSON content deterministically, sorting object keys.""" return value if isinstance(value, str) else json.dumps(value, sort_keys=True) @@ -214,16 +197,13 @@ def build( if layout is Layout.STATE_FIRST: return Rendered(prefix=state_block, suffix=f"{question_block}\n{ANSWER_CUE}") - # Schema-first: the catalogue is the reusable prefix and must not depend on the - # state; `cached_schema` passes the whole catalogue, not just this question. + # The reusable schema prefix must contain the full catalogue and exclude state. prefix = (cached_schema if cached_schema is not None else question_block) + "\n\n" return Rendered(prefix=prefix, suffix=f"{state_block}{ANSWER_CUE}") def _build_chat(state, name, question, codes, layout, cached_schema, order) -> Rendered: - """ChatML: system turn, then a user turn holding evidence and criterion in - either order, then the opened assistant turn the label token is read from. - The scored position is the final `\\n\\n` after the empty think block.""" + """Render ChatML evidence and criterion; score the boundary after the empty think block.""" head = f"<|im_start|>system\n{CHAT_SYSTEM_PROMPT}<|im_end|>\n<|im_start|>user\n" evidence = f"# Evidence\n{render_state(state)}\n\n" criterion = render_question(name, question, codes, order, Style.CHAT) @@ -234,8 +214,8 @@ def _build_chat(state, name, question, codes, layout, cached_schema, order) -> R def schema_block( - questions: dict[str, Question], - codes: dict[str, list[str] | None], + questions: Mapping[str, Question], + codes: Mapping[str, list[str] | None], style: Style = Style.PLAIN, ) -> str: """The full question catalogue, for schema-first caching across states.""" diff --git a/packages/lev/src/lev/readout/mode_a.py b/packages/lev/src/lev/readout/mode_a.py index a8affb6..69e2d35 100644 --- a/packages/lev/src/lev/readout/mode_a.py +++ b/packages/lev/src/lev/readout/mode_a.py @@ -4,21 +4,18 @@ from dataclasses import dataclass +from ..labels import TokenEncoder + @dataclass class LabelTokenReadout: - """Maps label codes to the single token ids Mode A reads. - - `tokenizer` must be the one the router verified against; another tokenizer - silently changes which ids are read. - """ + """Read label ids using the same tokenizer that verified the codes.""" - tokenizer: object + tokenizer: TokenEncoder prefix: str = " " def candidate_ids(self, codes: list[str]) -> list[int]: - """Token id for each label code as the model emits it at the answer boundary: - after `Answer:` in the plain style, opening the assistant turn in chat.""" + """Encode each label code at the configured answer boundary.""" ids = [] for code in codes: encoded = self.tokenizer.encode(self.prefix + code, add_special_tokens=False) diff --git a/packages/lev/src/lev/readout/mode_b.py b/packages/lev/src/lev/readout/mode_b.py index 87de06f..54410ef 100644 --- a/packages/lev/src/lev/readout/mode_b.py +++ b/packages/lev/src/lev/readout/mode_b.py @@ -13,8 +13,7 @@ def __init__(self, hidden_size: int = 2560, proj_dim: int = 512, n_heads: int = super().__init__() self.question_proj = nn.Linear(hidden_size, proj_dim, bias=False) self.candidate_proj = nn.Linear(hidden_size, proj_dim, bias=False) - # Candidates attend to each other: "is this the best of these", not "is - # this good in isolation". + # Compare candidates jointly through set attention. self.set_attention = nn.MultiheadAttention(proj_dim, n_heads, batch_first=True, dropout=0.0) self.norm = nn.LayerNorm(proj_dim) self.score = nn.Linear(proj_dim, 1, bias=False) @@ -25,16 +24,9 @@ def forward( candidate_reprs: torch.Tensor, candidate_mask: torch.Tensor | None = None, ) -> torch.Tensor: - """ - Args: - question_repr: `(batch, hidden)`. - candidate_reprs: `(batch, n_candidates, hidden)`. - candidate_mask: `(batch, n_candidates)`, True where padded. - - Returns: - `(batch, n_candidates)` raw scores. Masked slots are -inf so they - vanish under softmax regardless of the temperature applied later. - """ + """Score candidates (B, K); input shapes are (B, H) and (B, K, H). + + candidate_mask is (B, K), True for padding; masked scores are -inf.""" q = self.question_proj(question_repr).unsqueeze(1) c = self.candidate_proj(candidate_reprs) diff --git a/packages/lev/src/lev/release.py b/packages/lev/src/lev/release.py index 3e7adcd..e57d53e 100644 --- a/packages/lev/src/lev/release.py +++ b/packages/lev/src/lev/release.py @@ -1,7 +1,4 @@ -"""Package adapters, head, tokenizer and calibration into a flat Hub release. - -The manifest pins the base model and prompt format required to load it. -""" +"""Package adapter, head, tokenizer, and calibration with a base-model and prompt manifest.""" from __future__ import annotations @@ -26,20 +23,14 @@ def build_release( metrics: dict | None = None, prompt_style: str = "plain", ) -> dict: - """Copy a `step-N` checkpoint into a self-describing release directory. - - `calibration` defaults to the `calibration.json` beside the checkpoint's - parent, where `calibrate` writes it. An uncalibrated release is recorded as - such and serves raw softmax. - """ + """Package a checkpoint; default to parent calibration, otherwise serve raw softmax.""" step_dir = resolve_checkpoint(checkpoint) target = Path(out) target.mkdir(parents=True, exist_ok=True) copied: list[str] = [] for file in sorted(step_dir.iterdir()): - # Training state is for resuming, not serving; PEFT's README is replaced - # by the model card. + # Exclude resume state and replace PEFT's README with the release card. if file.is_file() and file.name not in (TRAINING_STATE, MODEL_CARD): shutil.copy2(file, target / file.name) copied.append(file.name) @@ -59,8 +50,7 @@ def build_release( "lora_rank": adapter_config.get("r"), "mode_b_head": MODE_B_HEAD in copied, "calibrated": calibrated, - # `lev.load` reads `prompt_style` (and `base_model`); `noul_readout` - # records the readout the temperatures were fitted on. + # Record the model, prompt format, and readout required by these weights and temperatures. "noul_readout": "rating", "prompt_style": prompt_style, "files": copied, @@ -73,7 +63,7 @@ def build_release( def model_card(manifest: dict) -> str: - """A Hub model card: front matter the Hub indexes, then what a user needs.""" + """Build Hub metadata and usage instructions for a release.""" metrics = manifest.get("metrics") or {} metric_lines = "\n".join(f"| {k} | {v} |" for k, v in metrics.items()) or "| — | not recorded |" calibration = ( @@ -137,11 +127,7 @@ def model_card(manifest: dict) -> str: def publish(release_dir: str | Path, repo_id: str, *, private: bool = False) -> str: - """Upload a release directory to the Hub. Returns the repo URL. - - Needs `HF_TOKEN` or `hf auth login`. Creates the repo if it does not exist; - re-running uploads only the changed files. - """ + """Upload a release using HF authentication; create the repo if needed and return its URL.""" from huggingface_hub import HfApi folder = Path(release_dir) diff --git a/packages/lev/src/lev/router.py b/packages/lev/src/lev/router.py index f23dcaf..35222d7 100644 --- a/packages/lev/src/lev/router.py +++ b/packages/lev/src/lev/router.py @@ -44,13 +44,7 @@ def route( label_prefix: str = " ", skip_multi_token: bool = False, ) -> Route: - """Pick a mode for one question. - - `max_label_options` caps Mode A below the tokenizer limit (decider measured it - losing 5-24 points on 50-219 options); None uses Mode A whenever it fits. - `noul_binary` reads a Noul as two lettered options: a stock checkpoint pins the - 0-8 scale at one end regardless of content (ADR-007). - """ + """Choose a readout using tokenizer support, an optional label cap, and binary Noul mode.""" n = candidate_count(question) if max_label_options is not None and n > max_label_options: diff --git a/packages/lev/src/lev/server.py b/packages/lev/src/lev/server.py index ec9c24a..08236f3 100644 --- a/packages/lev/src/lev/server.py +++ b/packages/lev/src/lev/server.py @@ -1,12 +1,9 @@ -"""FastAPI endpoints for typed decisions and model health. - -Status codes: 422 malformed, 529 still loading, 503 past `max_pending` in flight -or worker stopped, 504 queued past `timeout`. -""" +"""Serve typed decisions and health; return 422, 529, 503, or 504 for request failures.""" from __future__ import annotations import asyncio +from contextlib import asynccontextmanager from typing import Any, Literal # Module level: FastAPI resolves the endpoint's string annotations here. @@ -37,11 +34,10 @@ def create_app( from . import __version__ - app = FastAPI(title="lev", version=__version__) state: dict[str, Any] = {"engine": None, "batcher": None} - @app.on_event("startup") - def _load() -> None: + @asynccontextmanager + async def lifespan(app): engine = load( checkpoint_dir, model_id=model_id, @@ -59,6 +55,9 @@ def _load() -> None: engine, max_pending=max_pending, max_batch_tokens=max_batch_tokens, timeout=timeout ) state["engine"] = engine + yield + + app = FastAPI(title="lev", version=__version__, lifespan=lifespan) # Async, so a saturated thread pool cannot starve it. @app.get("/health") @@ -112,8 +111,7 @@ async def system_one(body: SystemOneRequest, request: Request) -> Any: async def _disconnected(request: Request) -> None: - """Return when the client hangs up. With the body read, the next ASGI message is - the disconnect; any other means none is reported, so wait forever, not spin.""" + """Wait for an ASGI disconnect; if none is reported, wait without polling.""" if (await request.receive())["type"] == "http.disconnect": return await asyncio.Event().wait() diff --git a/packages/lev/src/lev/train/calibration_run.py b/packages/lev/src/lev/train/calibration_run.py index 40bd39a..1eb3fc1 100644 --- a/packages/lev/src/lev/train/calibration_run.py +++ b/packages/lev/src/lev/train/calibration_run.py @@ -19,14 +19,9 @@ def fit_profile( config=None, method: str = "transfer", ) -> dict: - """Collect raw logits on `split`, fit one temperature per bucket. + """Fit bucket temperatures on calibration data; optionally select by family transfer. - `method="transfer"` fits each bucket both by rows and by task family and - keeps whichever has the lower leave-one-family-out ECE (ADR-028), writing - the comparison to `calibration.report.json`; a bucket with too few families - keeps the row fit. `method="rows"` fits pooled rows only, ignoring family. - An existing profile is kept as `calibration.previous.json`. - """ + Save transfer comparisons and preserve the previous profile before replacing it.""" rows = collect_logits(checkpoint_dir, data_dir, split, config=config) out = Path(checkpoint_dir) / CALIBRATION if out.is_file(): @@ -73,12 +68,7 @@ def collect_logits( batch_size: int = 16, limit: int | None = None, ) -> dict[str, list[tuple[list[float], int, str]]]: - """Raw candidate logits per `CalibrationProfile.key` bucket, from the trained - model under `no_grad`, before any temperature. - - Abstain rows are skipped: a temperature is fitted against a gold index. Each - sample carries its task family (`sources.family_of`) for the transfer fit. - """ + """Collect raw logits and task families by calibration bucket, skipping abstain rows.""" import torch from ..data.build import load_split diff --git a/packages/lev/src/lev/train/checkpoints.py b/packages/lev/src/lev/train/checkpoints.py index 3735149..6325b77 100644 --- a/packages/lev/src/lev/train/checkpoints.py +++ b/packages/lev/src/lev/train/checkpoints.py @@ -11,10 +11,7 @@ def latest_checkpoint(output: str | Path) -> Path | None: - """The newest `step-N` under `output` that holds adapter weights, or None. - - By step number, not mtime: a resumed run rewrites older directories. - """ + """Return the highest numbered step with adapter weights, regardless of mtime.""" source = Path(output) steps = sorted( (d for d in source.glob("step-*") if (d / ADAPTER_WEIGHTS).is_file()), @@ -24,11 +21,7 @@ def latest_checkpoint(output: str | Path) -> Path | None: def fetch_checkpoint(spec: str | Path, cache_dir: str | None = None) -> Path: - """A local path as-is, else a Hub id (`hf://org/name` or `org/name`) downloaded. - - A missing path shaped `a/b` (not starting `/` or `.`) is tried on the Hub, so a typo like - `checkpoints/lev-instuct` raises `FileNotFoundError` naming both readings. - """ + """Use an existing local path or download a Hub id; report ambiguous missing paths clearly.""" local = Path(spec) if local.exists(): return local @@ -47,8 +40,7 @@ def fetch_checkpoint(spec: str | Path, cache_dir: str | None = None) -> Path: def resolve_checkpoint(path: str | Path, cache_dir: str | None = None) -> Path: - """Accept a `step-N` directory, a parent holding several (newest step wins), a flat - release directory, or a Hub id for one.""" + """Resolve a step directory, training output, flat release, or Hub id.""" source = fetch_checkpoint(path, cache_dir) if (source / ADAPTER_WEIGHTS).is_file(): return source @@ -62,27 +54,18 @@ def resolve_checkpoint(path: str | Path, cache_dir: str | None = None) -> Path: def load_training_state(path: str | Path) -> dict | None: - """The optimiser, schedule and position saved beside the weights, if any. - - None for a weights-only checkpoint (including those from before ADR-021); - the caller then starts the optimiser and schedule fresh. - """ + """Load resume state, or return None for a weights-only checkpoint.""" import torch file = resolve_checkpoint(path) / TRAINING_STATE if not file.is_file(): return None - # Tensors, dicts, tuples and ints only, so `weights_only` loads it without arbitrary - # unpickling: safe for a state downloaded from a Hub id. + # Use weights_only to avoid arbitrary unpickling of downloaded resume state. return torch.load(file, map_location="cpu", weights_only=True) def load_checkpoint(model, head, path: str | Path) -> None: - """Restore adapter and head weights into existing parameter tensors. - - Keeping the tensors preserves optimiser references. A missing or unexpected - head is an error, since dropping it would discard Mode B training. - """ + """Restore weights in place to preserve optimizer references; reject head mismatches.""" import torch from peft import set_peft_model_state_dict from safetensors.torch import load_file @@ -117,10 +100,7 @@ def save_checkpoint( on_checkpoint=None, state: dict | None = None, ) -> Path: - """Write adapter, head and tokenizer, then optional training state. - - Not atomic: an interrupted save may be incomplete (ADR-021). - """ + """Write weights, tokenizer, and optional resume state; interrupted saves may be incomplete.""" import torch path = output / f"step-{step}" diff --git a/packages/lev/src/lev/train/collate.py b/packages/lev/src/lev/train/collate.py index a442cbc..cf103bd 100644 --- a/packages/lev/src/lev/train/collate.py +++ b/packages/lev/src/lev/train/collate.py @@ -1,13 +1,14 @@ -"""Batch and collate examples by readout mode. - -Rows are right-padded: `last_positions` points to each final real token. -""" +"""Collate by readout mode with right padding and final-real-token positions.""" from __future__ import annotations import random from collections.abc import Iterable, Iterator from dataclasses import dataclass +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from torch import Tensor from ..data.mixture import Example from ..prompt import Style, candidate_texts, label_prefix @@ -27,8 +28,7 @@ def __init__(self, tokenizer, max_label_options: int | None = None, style: Style self._routes: dict[tuple[str, str, int], Route] = {} def route_for(self, example: Example) -> Route: - # Keyed on the option count: a source has many questions (subsampled option sets, - # per-row QA choices), and the route depends only on the count. + # Cache by option count; routing is independent of option wording. key = (example.source, example.name, candidate_count(example.question)) if key not in self._routes: self._routes[key] = route( @@ -42,24 +42,23 @@ def route_for(self, example: Example) -> Route: @dataclass class Batch: - """One homogeneous training batch. Tensors are torch, typed loosely to keep - this module importable without torch.""" + """A training batch with one readout mode.""" mode: Mode - input_ids: object # (B, T) - attention_mask: object # (B, T) - last_positions: object # (B,) - candidate_mask: object # (B, Kmax) True where padded - targets: object # (B,) gold index, IGNORE_INDEX on abstain rows - soft_targets: object | None # (B, Kmax) or None if no abstain rows - ordinal: object # (B,) True for the ordered types: Score and Noul + input_ids: Tensor # (B, T) + attention_mask: Tensor # (B, T) + last_positions: Tensor # (B,) + candidate_mask: Tensor # (B, Kmax) True where padded + targets: Tensor # (B,) gold index, IGNORE_INDEX on abstain rows + soft_targets: Tensor | None # (B, Kmax) or None if no abstain rows + ordinal: Tensor # (B,) True for the ordered types: Score and Noul # Mode A only: the label token id per candidate slot. - candidate_token_ids: object | None = None # (B, Kmax) + candidate_token_ids: Tensor | None = None # (B, Kmax) # Mode B only: a shared pool of encoded candidate strings, indexed per row. - candidate_input_ids: object | None = None # (C, Tc) - candidate_attention_mask: object | None = None # (C, Tc) - candidate_last_positions: object | None = None # (C,) - candidate_index: object | None = None # (B, Kmax) -> row in C, 0 where padded + candidate_input_ids: Tensor | None = None # (C, Tc) + candidate_attention_mask: Tensor | None = None # (C, Tc) + candidate_last_positions: Tensor | None = None # (C,) + candidate_index: Tensor | None = None # (B, Kmax) -> row in C, 0 where padded @property def size(self) -> int: @@ -79,11 +78,7 @@ def render(example: Example, codes: list[str] | None, style: Style = Style.PLAIN class ModeBatcher: - """Group by readout mode, sort within length windows, then shuffle batches. - - Windowed sorting limits padding without globally ordering rows by length - or source. No examples are dropped. - """ + """Group by mode, sort within length windows, and shuffle batches without dropping examples.""" def __init__( self, @@ -131,13 +126,12 @@ def __call__(self, examples: Iterable[Example], epoch: int = 0) -> Iterator[list for i in range(0, len(chunk), self.batch_size) ) - # Seeded on the epoch: differs between epochs, reproduces on a re-run. random.Random(self.seed + epoch).shuffle(batches) yield from (b for b in batches if b) class DecisionCollator: - """Examples -> Batch. All rows must share a mode; `ModeBatcher` guarantees it.""" + """Collate rows sharing one readout mode.""" def __init__( self, @@ -187,8 +181,7 @@ def __call__(self, examples: list[Example]) -> Batch: ) soft_targets[i, : n_candidates[i]] = torch.tensor(e.soft_target) - # Noul is ordinal too ("0 = certainly no, 8 = certainly yes"): without - # this, rating 4 against a truth of 8 costs as much as rating 0. + # Treat Noul ratings as ordered so distant errors cost more. ordinal = torch.tensor( [e.question.type in ("score", "noul") for e in examples], dtype=torch.bool ) @@ -219,8 +212,7 @@ def _encode(self, prompts: list[str]) -> dict: max_length=self.max_seq_len, add_special_tokens=False, ) - # The last real token, from the mask rather than len(text): truncation - # may have shortened the row. + # Derive final token positions from the mask to account for truncation. out["last_positions"] = out["attention_mask"].sum(dim=1).long() - 1 if (out["last_positions"] < 0).any(): raise ValueError("a prompt encoded to zero tokens") diff --git a/packages/lev/src/lev/train/config.py b/packages/lev/src/lev/train/config.py index 64690b4..2b41c8a 100644 --- a/packages/lev/src/lev/train/config.py +++ b/packages/lev/src/lev/train/config.py @@ -1,21 +1,16 @@ -"""Training presets and approximate H100 compute and memory budgets. - -Estimate assumptions are documented in docs/ARCHITECTURE.md §5. -""" +"""Training presets and approximate H100 budgets (ARCHITECTURE §5).""" from __future__ import annotations from dataclasses import dataclass from typing import Literal -# Measured on the released 4b-instruct run (2.46e18 FLOPs in 7.8 h, padding and overhead -# included); reads high for the plain-prompt 4B runs (4h50, 5h53). docs/TRAINING.md. +# Effective throughput measured on the 4b-instruct run, including overhead (TRAINING.md). H100_EFFECTIVE_FLOPS = 8.75e13 H100_VRAM_GB = 80.0 -# ~6*N FLOPs/token forward+backward, plus ~a third for checkpointing's recompute. Holds -# under LoRA: backward still traverses the frozen weights to reach the adapters. +# Include checkpoint recomputation; LoRA backward still traverses frozen weights. FLOPS_PER_PARAM_PER_TOKEN = 8.0 @@ -85,7 +80,7 @@ def total_tokens(self) -> int: @property def tokens_per_step(self) -> int: - # The work per step is the padded batch, not `max_seq_len` (~16x larger). + # Estimate compute from padded batch length, not the truncation cap. return self.avg_tokens_per_example * self.per_device_batch * self.grad_accum @property diff --git a/packages/lev/src/lev/train/evaluate.py b/packages/lev/src/lev/train/evaluate.py index 1bdb5df..5b18507 100644 --- a/packages/lev/src/lev/train/evaluate.py +++ b/packages/lev/src/lev/train/evaluate.py @@ -1,5 +1,4 @@ -"""Evaluate checkpoints through the training forward path, per source, before and after -fitted temperatures.""" +"""Evaluate checkpoints per source before and after temperature scaling.""" from __future__ import annotations @@ -100,11 +99,7 @@ def evaluate_split( limit_per_source: int | None = None, batch_size: int = 16, ) -> tuple[EvalReport, EvalReport]: - """Return (uncalibrated, calibrated) reports over `split`. - - Both come from one forward pass, with the temperature applied to stored raw - logits, so any difference is the temperature alone. - """ + """Return raw and calibrated reports from the same stored logits.""" import torch from ..data.build import load_split @@ -157,8 +152,7 @@ def evaluate_split( resolved = str(resolve_checkpoint(checkpoint_dir)) plain = EvalReport(split=split, checkpoint=resolved, calibrated=False) tuned = EvalReport(split=split, checkpoint=resolved, calibrated=bool(profile.temperatures)) - # A source's rows may differ in option count, which sets the temperature, so - # each group is scored at its own temperature and then reported per source. + # Apply option-count temperatures per group before aggregating by source. per_source: dict[tuple[str, str, str], list[tuple[list[float], int, float]]] = {} for (source, qtype, mode, width), samples in collected.items(): t = profile.temperature(qtype, mode, width) diff --git a/packages/lev/src/lev/train/loop.py b/packages/lev/src/lev/train/loop.py index 7e01e5e..eeed601 100644 --- a/packages/lev/src/lev/train/loop.py +++ b/packages/lev/src/lev/train/loop.py @@ -32,13 +32,14 @@ def build_model(config: TrainConfig, model_cache: str | None = None): from transformers import AutoModelForCausalLM, AutoTokenizer tokenizer = AutoTokenizer.from_pretrained(config.model_id, cache_dir=model_cache) + if tokenizer is None: + raise RuntimeError(f"could not load tokenizer for {config.model_id!r}") if tokenizer.pad_token_id is None: - # Rows are right-padded and `last_positions` comes from the attention mask, - # so the pad token only has to exist. + # Right padding uses mask-derived positions, so an existing token can serve as padding. tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "right" - # bfloat16 on CPU is glacial, and `make smoke-local` runs on a laptop. + # Use fp32 for CPU smoke runs. dtype = getattr(torch, config.dtype) if dtype is torch.bfloat16 and not torch.cuda.is_available(): print("no CUDA; training in float32 instead of bfloat16") @@ -48,8 +49,7 @@ def build_model(config: TrainConfig, model_cache: str | None = None): model: Any = AutoModelForCausalLM.from_pretrained( config.model_id, dtype=dtype, - # Multi-GPU only: on an Apple machine accelerate dispatches to MPS and - # the process dies with SIGSEGV part-way through loading. + # Restrict automatic device mapping to CUDA; MPS loading can crash. device_map="auto" if torch.cuda.device_count() > 1 else None, cache_dir=model_cache, ) @@ -58,8 +58,7 @@ def build_model(config: TrainConfig, model_cache: str | None = None): if config.gradient_checkpointing: model.gradient_checkpointing_enable() - # Without it, checkpointed activations have no grad_fn and the LoRA - # adapters get no gradient: a silent no-op run. + # Enable input gradients so checkpointing propagates gradients to LoRA adapters. model.enable_input_require_grads() if config.use_lora: @@ -102,8 +101,7 @@ def decision_loss(logits, targets, config: TrainConfig, ordinal=False, soft_targ if soft_targets is not None and (~hard).any(): target_dist[~hard] = soft_targets[~hard].to(probs.dtype) - # `torch.where`, not a product: a padded slot has logit -inf and target 0, and - # `0 * -inf` is NaN, which poisons the batch mean. + # Use where to avoid NaN from padded slots with 0 * -inf. weighted = torch.where(target_dist > 0, target_dist * log_probs, torch.zeros_like(log_probs)) ce = -weighted.sum(dim=-1).mean() brier = ((probs - target_dist) ** 2).sum(dim=-1).mean() @@ -120,18 +118,13 @@ def decision_loss(logits, targets, config: TrainConfig, ordinal=False, soft_targ def candidate_logits(model, batch, head=None): - """One forward pass -> `(B, K)` logits over the batch's candidate set. - - Mode A gathers label-token logits at the answer boundary. Mode B scores pooled - candidate strings through the head: one extra short forward, not one per option. - """ + """Compute (B, K) scores using label logits or pooled candidate embeddings.""" import torch from ..router import Mode if batch.mode is Mode.LABEL_TOKEN: - # Project only answer positions to avoid a full (B, seq, vocab) allocation. - # Rows with different answer positions must pick their own output column. + # Project answer positions only; each row selects its own output column. keep, column = torch.unique(batch.last_positions, return_inverse=True) out = model( input_ids=batch.input_ids, @@ -163,13 +156,11 @@ def candidate_logits(model, batch, head=None): flat = batch.candidate_index.reshape(-1) reprs = candidate_repr[flat].view(*batch.candidate_index.shape, -1) # (B, K, H) - # Cast hidden states up to the fp32 head. Casting to the bf16 activations' - # dtype instead raises on GPU, and is invisible on CPU, where both are fp32. + # Match hidden states to the fp32 head, not the bf16 backbone. target_dtype = next(head.parameters()).dtype logits = head(question_repr.to(target_dtype), reprs.to(target_dtype), batch.candidate_mask) - # Mode B already masks padded slots; Mode A's gather returns a real (wrong) - # vocabulary logit there. + # Mask Mode A padding after gathering vocabulary logits. return logits.float().masked_fill(batch.candidate_mask.to(logits.device), float("-inf")) @@ -218,8 +209,7 @@ def prepare_data(config: TrainConfig, data_dir: str): if not train: raise ValueError(f"{root / 'train.jsonl'} is empty") - # Repeats the contamination guard on the manifest's Hub ids: the only check - # that sees a manifest edited after the build. Skipped without a manifest. + # Recheck manifest Hub ids in case the manifest changed after data assembly. manifest_path = root / MANIFEST if manifest_path.is_file(): from ..data.contamination import assert_clean @@ -240,19 +230,15 @@ def run_training( max_steps: int | None = None, fresh: bool = False, ) -> dict: - """Train, checkpointing periodically so a long run survives a preemption. + """Train with periodic checkpoints; auto-resume the newest step unless fresh=True. - With no `resume_from`, the newest `step-N` under `config.output_dir` is resumed; - `fresh=True` starts over. Resume restores optimiser, schedule and data order, so a - finished run trains nothing; pre-ADR-021 checkpoints restore weights only. - """ + Resume optimizer, schedule, and data order when saved; otherwise restore weights only.""" import torch from torch.optim import AdamW from transformers import get_cosine_schedule_with_warmup config.validate() - # Everything cheap and fallible happens before the model is touched. data = prepare_data(config, data_dir) output = Path(config.output_dir) output.mkdir(parents=True, exist_ok=True) @@ -260,8 +246,7 @@ def run_training( if resume_from is None and not fresh and (found := latest_checkpoint(output)) is not None: resume_from = str(found) print(f"resuming from {found} (pass --fresh to start over)", flush=True) - # Move, not delete, the previous run, so auto-resume (highest step) and the - # calibration lookup cannot pick it up. + # Preserve the previous run outside active resume and calibration lookups. if fresh and (moved := set_aside_previous_run(output)) is not None: print(f"previous run moved to {moved}", flush=True) @@ -291,8 +276,7 @@ def run_training( train = data["train"] steps_per_epoch = max(1, len(train) // config.examples_per_step) total_steps = max_steps or steps_per_epoch * config.epochs - # Sized in optimiser steps: sized in micro-steps, the cosine would finish - # `grad_accum` times early and the tail would train at a learning rate of 0. + # Size the schedule in optimizer steps so accumulation does not finish it early. optimiser_steps = max(1, total_steps // config.grad_accum) scheduler = get_cosine_schedule_with_warmup( optimiser, int(optimiser_steps * config.warmup_ratio), optimiser_steps @@ -331,8 +315,7 @@ def run_training( model.train() def training_state() -> dict: - # Read at save time: the loop below rebinds `epoch`, `step_in_epoch` and - # `rng_before_epoch`, and every save happens after at least one step. + # Read loop position and RNG state at save time, after they are updated. return { "step": step, "epoch": epoch, @@ -348,7 +331,6 @@ def training_state() -> dict: # Before the shuffle, so a resumed run reproduces this epoch's order. rng_before_epoch = rng.getstate() order = list(train) - # Shuffled before bucketing so windows differ per epoch. rng.shuffle(order) groups = batcher(order, epoch=epoch) step_in_epoch = 0 @@ -405,7 +387,7 @@ def training_state() -> dict: state=training_state(), ) last_saved = step - # So a run that dies late still leaves its loss curve. + # Persist history periodically to survive late preemption. _write_history(output, history, step) if step >= total_steps: break @@ -424,10 +406,7 @@ def training_state() -> dict: def set_aside_previous_run(output: Path) -> Path | None: - """Move prior checkpoints, history and calibration under `superseded-`. - - Return the directory, or None if there was nothing to move. - """ + """Move previous run artifacts into a timestamped directory, or return None if empty.""" stale = list(output.glob("step-*")) + [ output / name for name in (HISTORY, CALIBRATION) if (output / name).exists() ] diff --git a/packages/lev/src/lev/train/progress.py b/packages/lev/src/lev/train/progress.py index 5c06ed6..8277e2c 100644 --- a/packages/lev/src/lev/train/progress.py +++ b/packages/lev/src/lev/train/progress.py @@ -6,12 +6,7 @@ class ProgressLog: - """Periodic one-line progress, flushed: on Modal stdout is the only view, and it is - block-buffered when not a tty. - - Losses are per mode (Mode B starts near `ln(K)`). Throughput counts real tokens from the - attention mask, so it can contradict a wrong plan (ADR-016). - """ + """Flush periodic per-mode losses and throughput measured from real tokens.""" def __init__(self, total_steps: int, log_every: int): self.total = total_steps @@ -31,8 +26,7 @@ def record(self, step: int, loss: float, mode: str, lr: float, tokens: int = 0) now = time.monotonic() elapsed = max(now - self.start, 1e-9) - # Over the window, not since start: startup skews a cumulative rate ~8x (ADR-017). - # A coarse clock can report zero on a fast window; never divide by it. + # Use windowed rates to exclude startup delay; guard against zero elapsed time. span = max(now - self.mark, 1e-9) rate = (done - self.mark_step) / span remaining = (self.total - done) / rate if rate else 0.0 diff --git a/packages/lev/src/lev/types.py b/packages/lev/src/lev/types.py index 2e12b5e..f8c205e 100644 --- a/packages/lev/src/lev/types.py +++ b/packages/lev/src/lev/types.py @@ -1,8 +1,4 @@ -"""TypeSafe-compatible request and response models for `/v1/systemone`. - -lev also exposes Noul rating probabilities and confidence. Clients that only -read the shared `noul` probability can ignore these extra fields. -""" +"""TypeSafe-compatible models; lev adds optional Noul rating probabilities and confidence.""" from __future__ import annotations @@ -60,9 +56,7 @@ def _level_count(cls, v: list) -> list: def question_payload(question: Question) -> dict: - """The question as a levbench task file carries it. `criteria` is required on - a Choice and a Score and optional on a Noul, so an absent Noul criteria map - stays absent rather than round-tripping as an empty one.""" + """Serialize a task question, preserving absent Noul criteria.""" payload: dict = {"type": question.type, "instructions": question.instructions} if isinstance(question, Choice | Score) or question.criteria: payload["criteria"] = question.criteria diff --git a/packages/lev/tests/conftest.py b/packages/lev/tests/conftest.py index 95f0f2b..834b950 100644 --- a/packages/lev/tests/conftest.py +++ b/packages/lev/tests/conftest.py @@ -1,5 +1,4 @@ -"""torch is imported only inside `BatchingTokenizer.__call__`, so the torch-free half of -the suite still collects on a bare `uv sync`.""" +"""Shared fixtures; import Torch only when tensor batching is needed.""" from __future__ import annotations @@ -11,8 +10,7 @@ class FakeTokenizer: - """Strings in `single_tokens` encode to one id -- exactly what `labels.single_token_codes` - checks, so a fake tests the routing decision faithfully.""" + """Control which strings encode as a single token.""" def __init__(self, single_tokens: set[str]): self.single_tokens = single_tokens @@ -20,8 +18,7 @@ def __init__(self, single_tokens: set[str]): def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: if text in self.single_tokens: return [1] - # Even a single character must encode to >1 token, or it looks single-token by - # accident and the router test proves nothing. + # Encode unlisted characters as multiple tokens to avoid accidental routing matches. return [1] * (len(text) + 1) @@ -50,8 +47,7 @@ def poor_tokenizer() -> FakeTokenizer: class BatchingTokenizer(FakeTokenizer): - """One id per character so prompts get different lengths; equal lengths would hide the - bug `last_positions` exists to prevent.""" + """Encode one id per character to expose padding and last-token errors.""" pad_token_id = 0 padding_side = "right" diff --git a/packages/lev/tests/test_batcher.py b/packages/lev/tests/test_batcher.py index 0a9031c..de8a811 100644 --- a/packages/lev/tests/test_batcher.py +++ b/packages/lev/tests/test_batcher.py @@ -15,8 +15,7 @@ def request(name: str, rows: int = 1, width: int = 10): class GatedEngine: - """Records each forward's requests; the first forward waits for `release`, - so requests submitted meanwhile queue up behind it.""" + """Hold the first forward so later requests queue behind it.""" def __init__(self): self.forwards: list[list[str]] = [] @@ -185,8 +184,6 @@ async def until(condition, timeout=2.0): def test_a_held_request_can_still_be_cancelled_before_it_runs(): - """With a budget of one row, `c` is held back while `b` runs; its client - leaving then must keep it off the GPU.""" async def run(): engine = SteppedEngine() @@ -232,7 +229,7 @@ async def run(): def test_an_abandoned_running_request_still_counts_as_pending(): - """A client leaving does not free the GPU, so it must not free a slot.""" + """Disconnecting does not release GPU capacity already in use.""" async def run(): engine = SteppedEngine() @@ -252,8 +249,6 @@ async def run(): def test_a_failing_disconnect_watch_still_returns_the_answer(): - """A server whose `receive()` raises cannot report disconnects; the request - must be answered, not dropped as if its client had left.""" async def broken_watch(): raise RuntimeError("receive() is not available") @@ -270,8 +265,7 @@ async def run(): def test_an_error_outside_the_forward_fails_its_batch_and_the_worker_keeps_serving(): - """One answer short trips the `zip(strict=True)` after the forward, outside - the forward's own error handling.""" + """A short response list triggers zip(strict=True) outside forward error handling.""" async def run(): engine = SteppedEngine(short_by=1) diff --git a/packages/lev/tests/test_cache_fork.py b/packages/lev/tests/test_cache_fork.py index 13e96cd..999c64a 100644 --- a/packages/lev/tests/test_cache_fork.py +++ b/packages/lev/tests/test_cache_fork.py @@ -1,4 +1,4 @@ -"""Qwen3.5's `LinearAttentionLayer` has no `batch_repeat_interleave`; a fork built on it raised.""" +"""Test prefix-cache copying with mixed full- and linear-attention layers.""" from __future__ import annotations @@ -51,7 +51,6 @@ def test_every_forked_row_is_a_copy_of_row_zero(): def test_fork_does_not_mutate_the_source(): - """The prefix cache must stay reusable for the next request.""" original = hybrid_cache() before_keys = original.layers[0].keys.clone() before_conv = original.layers[1].conv_states[0].clone() @@ -64,7 +63,7 @@ def test_fork_does_not_mutate_the_source(): def test_the_old_approach_still_fails(): - """Pins why `_fork` avoids `batch_repeat_interleave`, so nobody 'simplifies' it back.""" + """Hybrid caches do not support batch_repeat_interleave.""" linear = cache_utils.LinearAttentionLayer() assert not hasattr(linear, "batch_repeat_interleave"), ( "LinearAttentionLayer now implements batch_repeat_interleave; " diff --git a/packages/lev/tests/test_calibration.py b/packages/lev/tests/test_calibration.py index 6dc538f..197a085 100644 --- a/packages/lev/tests/test_calibration.py +++ b/packages/lev/tests/test_calibration.py @@ -1,4 +1,4 @@ -"""Calibration must actually reduce ECE, and must refuse to cheat.""" +"""Test calibration improvement and held-out split rejection.""" from __future__ import annotations @@ -11,14 +11,13 @@ expected_calibration_error, fit, fit_temperature, - nll, + negative_log_likelihood, softmax, ) def overconfident_samples(n: int = 600, seed: int = 7, sharpness: float = 4.0): - """The untuned-backbone failure (ECE 0.4252): the correct class wins ~70% of the time, - but the margin implies ~96%.""" + """Generate roughly 70% accuracy at 96% confidence.""" rng = random.Random(seed) samples = [] for _ in range(n): @@ -56,19 +55,17 @@ def test_fitting_reduces_ece_on_overconfident_logits(self): [softmax(x, t) for x, _ in samples], [y for _, y in samples] ) assert after < before, f"ECE got worse: {before:.4f} -> {after:.4f}" - # The measured effect on real backbones is 0.43 -> 0.08. Demand a real - # improvement, not a rounding-level one. + # Require a meaningful calibration improvement. assert after < before / 2, f"expected a large reduction, {before:.4f} -> {after:.4f}" - def test_fitting_minimises_nll(self): + def test_fitting_minimises_negative_log_likelihood(self): samples = overconfident_samples() t = fit_temperature(samples) - best = nll(samples, t) + best = negative_log_likelihood(samples, t) for other in (t * 0.5, t * 1.5, 1.0): - assert best <= nll(samples, other) + 1e-6 + assert best <= negative_log_likelihood(samples, other) + 1e-6 def test_a_flat_objective_returns_the_identity(self): - # All-equal logits: every temperature gives the same NLL, so none is fitted. samples = [([0.0, 0.0], i % 2) for i in range(400)] assert fit_temperature(samples) == 1.0 @@ -141,8 +138,7 @@ def test_banded_temperature_falls_back_to_the_unbanded_bucket(self): class TestTransferSelectedCalibration: def family_rows(self): - """Equally confident rows where large easy families dominate a small hard one, so the - row fit is overconfident on the hard family.""" + """Large easy families outnumber a small hard family at equal confidence.""" rows = [] for fam, n, acc in ( ("easy1", 400, 0.97), diff --git a/packages/lev/tests/test_collate.py b/packages/lev/tests/test_collate.py index b2bdc31..cc3912f 100644 --- a/packages/lev/tests/test_collate.py +++ b/packages/lev/tests/test_collate.py @@ -1,4 +1,4 @@ -"""torch is in the `train` extra, so these skip on a bare `uv sync`.""" +"""Tensor collation tests; skip when Torch is unavailable.""" from __future__ import annotations @@ -20,7 +20,7 @@ def collator(self, batching_tokenizer): return DecisionCollator(batching_tokenizer, max_seq_len=512) def test_last_position_is_the_final_real_token_not_seq_minus_one(self, collator): - """Rows are right-padded, so `seq - 1` reads a pad token's logits: noise, and no error.""" + """Right padding makes seq - 1 point to a pad token.""" batch = collator( [an_example(a_choice(), state="short"), an_example(a_choice(), state="x" * 200)] ) @@ -77,7 +77,6 @@ def test_a_large_option_set_routes_to_mode_b_with_a_candidate_pool(self, collato assert batch.candidate_input_ids.shape[0] == 40 def test_the_candidate_pool_is_shared_across_rows(self, collator): - """A 77-option question in a batch of 8 must not cost 8x77 encodes.""" rows = [an_example(a_choice(40), target=i) for i in range(4)] batch = collator(rows) assert batch.candidate_input_ids.shape[0] == 40, "pool grew with batch size" @@ -102,8 +101,6 @@ def test_batches_are_homogeneous_and_correctly_sized(self, batching_tokenizer): assert sum(len(g) for g in groups) == 12 def test_routes_are_resolved_once_per_question_not_per_row(self, batching_tokenizer): - """Re-tokenising an option set for each of 200k rows is the slowest - thing in the pipeline, and it produces the same answer every time.""" batcher = ModeBatcher(batching_tokenizer, batch_size=2) rows = [an_example(a_choice(4), source="same") for _ in range(50)] resolved = {id(batcher.route_for(row)) for row in rows} @@ -120,8 +117,7 @@ def test_batcher_and_collator_can_share_one_route_cache(self, batching_tokenizer class TestLengthBucketing: - """A batch pads to its longest row; on the real mixture random batching wasted 4.43x - on padding and bucketing 1.43x (ADR-017).""" + """Test padding savings without global length ordering.""" def rows(self, n=512): rng = random.Random(0) @@ -143,8 +139,7 @@ def test_bucketing_cuts_padding_waste(self, batching_tokenizer): before = self.waste(list(unbucketed(rows))) after = self.waste(list(bucketed(rows))) assert before > 2.0, f"fixture is not bimodal enough to show the effect ({before:.2f})" - # Relative, not absolute: the absolute floor depends on where the window - # boundary falls, and the multiple of compute saved is what matters. + # Compare relative padding because window boundaries affect the absolute count. assert after < before / 2, f"bucketing only got {before:.2f}x -> {after:.2f}x" assert after < 1.5, f"bucketing left {after:.2f}x waste" @@ -155,14 +150,12 @@ def test_no_example_is_lost_or_duplicated(self, batching_tokenizer): assert {id(e) for e in batched} == {id(e) for e in rows} def test_batches_stay_mode_homogeneous(self, batching_tokenizer): - """Bucketing must not undo the mode grouping the collator relies on.""" rows = self.rows(100) + [an_example(a_choice(40), target=0) for _ in range(60)] batcher = ModeBatcher(batching_tokenizer, 16, bucket_window=4) for group in batcher(rows): assert len({batcher.route_for(e).mode for e in group}) == 1 def test_batch_order_differs_between_epochs(self, batching_tokenizer): - """Length must not track step number, or the schedule correlates with it.""" rows = self.rows(256) batcher = ModeBatcher(batching_tokenizer, 32, bucket_window=4) first = [len(str(b[0].state)) for b in batcher(rows, epoch=0)] diff --git a/packages/lev/tests/test_contamination.py b/packages/lev/tests/test_contamination.py index a391c00..6c3185b 100644 --- a/packages/lev/tests/test_contamination.py +++ b/packages/lev/tests/test_contamination.py @@ -1,4 +1,4 @@ -"""The guard must catch aliases, not just exact names, and must raise not warn.""" +"""Test blocked dataset names, aliases, and re-hosts.""" from __future__ import annotations @@ -73,8 +73,7 @@ def test_innocent_datasets_pass(self, innocent): assert resolve(innocent) is None def test_subsets_that_did_not_run_are_blocked_too(self): - """The 7 subsets `s1-fast` skipped are still evaluation data: easy to - forget, since the completed-run leaderboard never mentions them.""" + """All evaluation subsets are blocked, including those absent from completed runs.""" unrun = [ "massive-de-DE", "squad2", diff --git a/packages/lev/tests/test_core.py b/packages/lev/tests/test_core.py index 0d9f056..08c9afa 100644 --- a/packages/lev/tests/test_core.py +++ b/packages/lev/tests/test_core.py @@ -66,8 +66,7 @@ def test_rejects_zero_and_oversized_option_counts(self): label_codes(100_000) def test_single_token_check_uses_the_space_prefix(self, rich_tokenizer): - # The scored token follows "Answer:", so it is space-prefixed. Verifying - # the bare code would pass while the real token differs. + # Verify space-prefixed codes at the actual answer boundary. assert single_token_codes(rich_tokenizer, 5) == ["A", "B", "C", "D", "E"] assert single_token_codes(rich_tokenizer, 5, prefix="") is None @@ -95,7 +94,6 @@ def test_small_choice_uses_mode_a(self, rich_tokenizer): assert r.codes == ["A", "B", "C"] def test_falls_through_to_mode_b_instead_of_rejecting(self, poor_tokenizer): - """The differentiator: where other implementations reject, lev routes.""" q = Choice(criteria={k: None for k in "abcdefgh"}) r = route(q, poor_tokenizer) assert r.mode is Mode.CANDIDATE_PATH @@ -110,11 +108,13 @@ def test_policy_cap_forces_mode_b_below_the_tokenizer_limit(self, rich_tokenizer def test_noul_routes_on_the_rating_scale(self, rich_tokenizer): r = route(Noul(instructions="urgent?"), rich_tokenizer) assert r.mode is Mode.LABEL_TOKEN + assert r.codes is not None assert len(r.codes) == len(NOUL_RATING_TOKENS) def test_score_routes_on_level_count(self, rich_tokenizer): r = route(Score(criteria=["low", "mid", "high"]), rich_tokenizer) - assert r.mode is Mode.LABEL_TOKEN and len(r.codes) == 3 + assert r.mode is Mode.LABEL_TOKEN + assert r.codes is not None and len(r.codes) == 3 def test_route_all_is_per_question(self, poor_tokenizer): routes = route_all( @@ -179,8 +179,6 @@ def test_score_level_bounds(self): class TestOptionCap: def test_generous_tokenizer_still_routes_above_the_cap_to_mode_b(self): - """An explicit `max_label_options` forces Mode B even when the tokenizer - can express every code (Qwen3.5 encodes codes up to `BP` as one token).""" generous = two_letter_tokenizer() sixty = Choice(criteria={f"o{i}": None for i in range(60)}) assert single_token_codes(generous, 60) is not None, "fixture must be generous" @@ -200,6 +198,7 @@ def test_binary_route_uses_two_lettered_codes(self, rich_tokenizer): def test_default_route_is_still_the_rating_scale(self, rich_tokenizer): r = route(Noul(instructions="safe?"), rich_tokenizer) + assert r.codes is not None assert len(r.codes) == len(NOUL_RATING_TOKENS) def test_binary_render_lists_yes_then_no(self): @@ -232,8 +231,6 @@ def test_average_maps_reversed_row_back_to_canonical_slots(self): assert merged == pytest.approx([0.7, 0.2, 0.1]) def test_average_cancels_a_first_position_bias(self): - """A first-position bonus lands on different candidates in the two orders, so averaging - spreads it back out.""" biased_forward = [0.6, 0.2, 0.2] # candidate 0 first, gets the bonus biased_backward = [0.6, 0.2, 0.2] # candidate 2 first, gets the bonus merged = average_orders([biased_forward, biased_backward], [None, [2, 1, 0]]) @@ -271,8 +268,7 @@ def test_binary_noul_is_read_both_ways(self, rich_tokenizer): ] def test_score_keeps_its_level_order(self, rich_tokenizer): - """Levels run low to high and training never reorders them; a reversed - scale is a prompt the model has not seen (helpsteer2: -2.4 points).""" + """Training presents ordered levels from low to high.""" assert self.orders(Score(criteria=["low", "mid", "high"]), rich_tokenizer) == [None] def test_rating_noul_keeps_its_scale(self, rich_tokenizer): @@ -349,8 +345,7 @@ def test_label_prefix_is_bare_for_chat_and_space_for_plain( assert label_prefix(Style.PLAIN) == " " and label_prefix(Style.CHAT) == "" q = Choice(criteria={"a": None, "b": None, "c": None}) assert route(q, chat_tokenizer, label_prefix="").codes == ["A", "B", "C"] - # A tokenizer with only space-prefixed letters cannot express bare codes: - # the chat style falls through to Mode B there rather than misreading. + # Plain-only label tokens must fall back to Mode B for chat prompts. assert route(q, rich_tokenizer, label_prefix="").mode is Mode.CANDIDATE_PATH def test_plain_style_is_unchanged(self): @@ -369,6 +364,7 @@ def test_default_scheme_stops_at_the_first_split_code(self): def test_skipping_passes_over_split_codes_and_keeps_the_order(self): tok = two_letter_tokenizer(missing="BQ") codes = single_token_codes(tok, 77, skip_multi_token=True) + assert codes is not None assert len(codes) == 77 and "BQ" not in codes and len(set(codes)) == 77 assert codes[:68] == single_token_codes(tok, 68), "codes below the split are unchanged" assert codes[68] == "BR" @@ -385,11 +381,16 @@ def test_route_uses_mode_a_past_the_split_only_when_asked(self): class TestRoutePreviewMatchesServing: def preview(self, tokenizer, request, tmp_path, monkeypatch, capsys) -> str: - """Run `lev route` on `request`, with `tokenizer` standing in for the Hub's.""" + """Run the route CLI with an injected tokenizer.""" from lev.cli import main stub = types.ModuleType("transformers") - stub.AutoTokenizer = types.SimpleNamespace(from_pretrained=lambda *_a, **_k: tokenizer) + monkeypatch.setattr( + stub, + "AutoTokenizer", + types.SimpleNamespace(from_pretrained=lambda *_a, **_k: tokenizer), + raising=False, + ) monkeypatch.setitem(sys.modules, "transformers", stub) path = tmp_path / "request.json" path.write_text(json.dumps(request)) @@ -398,8 +399,6 @@ def preview(self, tokenizer, request, tmp_path, monkeypatch, capsys) -> str: return capsys.readouterr().out def test_lev_route_previews_the_mode_the_server_uses(self, tmp_path, monkeypatch, capsys): - """A 60-option Choice is Mode A when served, since the tokenizer can - express 60 codes, so the preview must say Mode A too.""" request = { "state": "turn the lights off", "questions": { @@ -420,31 +419,27 @@ def test_lev_route_prints_a_mode_b_route_without_codes(self, tmp_path, monkeypat class TestSystemOneAcceptsPlainDicts: - """`lev.load` hands users an engine; they pass questions as JSON-shaped dicts.""" - def engine(self, tokenizer, **config): from lev.model import DecisionEngine, EngineConfig return DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) def test_a_dict_question_is_parsed_and_routed(self, rich_tokenizer): - # Capped at two label options with no head loaded, a three-option Choice - # needs Mode B, so routing refuses before any forward pass is attempted. + # Require a Mode B head when the label cap excludes this question. engine = self.engine(rich_tokenizer, max_label_options=2) questions = {"pick": {"type": "choice", "criteria": {"a": None, "b": None, "c": None}}} with pytest.raises(RuntimeError, match="need Mode B"): engine.system_one("state", questions) def test_a_malformed_dict_is_a_value_error(self, rich_tokenizer): - """ValueError is what the server turns into a 422.""" + """The server maps ValueError to HTTP 422.""" engine = self.engine(rich_tokenizer) with pytest.raises(ValueError, match="at least 2 options"): engine.system_one("state", {"pick": {"type": "choice", "criteria": {"a": None}}}) class TestTokenizerIsUsedOneCallAtATime: - """A fast tokenizer keeps padding and truncation as state on one shared Rust object, so - overlapping calls raise "Already borrowed" or encode with another call's truncation.""" + """Concurrent access to a fast tokenizer can corrupt settings or raise Already borrowed.""" class OverlapDetector: def __init__(self, inner): diff --git a/packages/lev/tests/test_data_pipeline.py b/packages/lev/tests/test_data_pipeline.py index 83bcc3b..88576e1 100644 --- a/packages/lev/tests/test_data_pipeline.py +++ b/packages/lev/tests/test_data_pipeline.py @@ -1,5 +1,4 @@ -"""Offline: `load_source` takes an injected `load_dataset`, so nothing here checks that the -real dataset ids resolve; a dead id surfaces on the next `lev data build`.""" +"""Test data assembly with fake loaders; upstream dataset availability is not checked.""" from __future__ import annotations @@ -90,8 +89,7 @@ def test_mode_b_sources_exist_and_exceed_the_code_ceiling(self): def test_mode_b_gets_a_material_share_of_the_mixture(self): weights = default_weights() share = sum(weights[n] for n in MODE_B_SOURCES) - # Size-proportional weighting would starve Mode B; this pins the - # deliberate over-weighting. + # Reserve enough weight to train Mode B. assert share >= 0.2, f"Mode B is only {share:.1%} of the mixture" def test_weights_are_a_distribution_over_known_sources(self): @@ -111,18 +109,19 @@ def test_noul_needs_exactly_two_labels(self): def test_score_keeps_level_order(self): spec = REGISTRY["sst5"] + assert spec.label_names is not None question = build_question(spec, list(spec.label_names)) assert question.criteria == list(spec.label_names) def test_choice_options_are_humanised(self): question = build_question(REGISTRY["banking77"], ["card_arrival", "age_limit"]) + assert isinstance(question, Choice) assert set(question.criteria) == {"card arrival", "age limit"} class TestSampling: def test_limit_samples_rather_than_truncates(self): - """A head slice of a label-sorted corpus yields one class (`imdb[:400]` is - 400 negative reviews).""" + """A head slice of a label-sorted corpus may contain only one class.""" spec = REGISTRY["dbpedia_14"] loader = label_sorted_loader(14, 100, text_field="content") rows = list(load_source(spec, limit=140, load_dataset=loader)) @@ -135,8 +134,7 @@ def test_sampling_is_reproducible(self): assert a == b def test_noul_labels_land_on_the_ends_of_the_rating_scale(self): - """The raw class would supervise "yes" as rating 1, which - `noul_probability` reads back as P(yes) = 0.125.""" + """A binary label of 1 must become rating 8, not P(yes) = 0.125.""" loader = label_sorted_loader(2, 20) rows = list(load_source(REGISTRY["imdb"], load_dataset=loader)) assert {e.target for e in rows} == {0, len(NOUL_RATING_TOKENS) - 1} @@ -183,7 +181,7 @@ def test_splits_are_disjoint(self, examples): assert not states[Split.CALIBRATION] & states[Split.TEST] def test_assignment_is_stable_across_processes(self): - """`hash()` is salted per process, so a split built on it reshuffles on every rebuild.""" + """Python hash() is salted per process.""" import os import subprocess import sys @@ -215,7 +213,7 @@ def test_label_only_outside_train_raises(self): check_coverage(splits) def test_option_never_observed_at_all_raises(self): - """A sample holding 2 of 4 options passes the in-train check but not this.""" + """Train coverage alone misses offered labels absent from every split.""" splits = { Split.TRAIN: [traceable_example("s", 0, 1), traceable_example("s", 1, 2)], Split.CALIBRATION: [], @@ -225,7 +223,7 @@ def test_option_never_observed_at_all_raises(self): check_coverage(splits) def test_noul_is_exempt_from_the_offered_option_check(self): - """Nine rating levels, two classes in the data. Not an error.""" + """Binary data observes only the endpoints of the nine-level scale.""" rows = [ Example("t", "n", Noul(instructions="q"), t, Layout.STATE_FIRST, "imdb") for t in (0, 8, 0, 8) @@ -247,8 +245,6 @@ def mixture(self): return list(build_mixture(spec, loaders)) def test_abstain_examples_carry_a_foreign_state(self, mixture): - """An abstain row must be unanswerable, so its state is replaced, not just - its label.""" abstained = [e for e in mixture if e.abstain] assert abstained assert all(not str(e.state).startswith(e.source) for e in abstained) @@ -274,8 +270,7 @@ def test_the_threshold_is_the_single_letter_alphabet(self): class TestAbstainDonors: - """Adjacent sources cannot supply an abstain state: an imdb question is still - answerable from a rotten_tomatoes review.""" + """Adjacent sources may still answer the question and are unsuitable abstain donors.""" def test_adjacency_is_symmetric_and_excludes_self(self): mapping = adjacency_map() @@ -316,7 +311,6 @@ def test_no_abstain_state_comes_from_an_adjacent_source(self): ) def test_a_source_adjacent_to_everything_still_yields_an_example(self): - """Degrading to "any other source" beats emitting nothing.""" sources = ["a", "b"] loaders = { s: (lambda s=s: [traceable_example(s, 0, i) for i in range(10)]) for s in sources @@ -333,7 +327,6 @@ def test_a_source_adjacent_to_everything_still_yields_an_example(self): class TestModeBPrompt: def test_mode_b_does_not_emit_an_empty_option_header(self): - """`Options:` with nothing under it costs a header and informs nothing.""" choice = build_prompt( "s", "q", Choice(instructions="pick", criteria={"a": None, "b": None}), None ).full @@ -354,13 +347,13 @@ def test_mode_a_still_lists_every_option_with_its_code(self): class TestReaders: - """Per-row readers are pure functions; drive them with the real column shapes.""" - def test_race_maps_the_answer_letter_to_an_index(self): from lev.data.sources import _read_race row = {"article": "A.", "question": "Q?", "options": ["w", "x", "y", "z"], "answer": "C"} - state, options, target = _read_race(row, random.Random(0)) + result = _read_race(row, random.Random(0)) + assert result is not None + state, options, target = result assert options[target] == "y" assert state == {"passage": "A.", "question": "Q?"} @@ -372,7 +365,9 @@ def test_keyed_choices_match_arc_numeric_keys(self): "choices": {"label": ["1", "2", "3"], "text": ["a", "b", "c"]}, "answerKey": "3", } - _, options, target = _read_keyed_choices("question")(row, random.Random(0)) + result = _read_keyed_choices("question")(row, random.Random(0)) + assert result is not None + _, options, target = result assert options[target] == "c" def test_keyed_choices_attach_context_when_present(self): @@ -384,7 +379,9 @@ def test_keyed_choices_attach_context_when_present(self): "choices": {"label": ["A", "B"], "text": ["a", "b"]}, "answerKey": "B", } - state, _, _ = _read_keyed_choices("question_stem", "fact1")(row, random.Random(0)) + result = _read_keyed_choices("question_stem", "fact1")(row, random.Random(0)) + assert result is not None + state, _, _ = result assert state == {"question": "Q?", "context": "F."} def test_sciq_shuffles_but_keeps_the_gold_index_right(self): @@ -400,7 +397,9 @@ def test_sciq_shuffles_but_keeps_the_gold_index_right(self): } seen_first = set() for seed in range(20): - _, options, target = _read_sciq(row, random.Random(seed)) + result = _read_sciq(row, random.Random(seed)) + assert result is not None + _, options, target = result assert options[target] == "gold" seen_first.add(options[0]) assert len(seen_first) > 1, "the gold answer must not always sit first" @@ -422,16 +421,18 @@ def test_nli_skips_rows_without_gold(self): from lev.data.sources import _read_nli assert _read_nli({"premise": "p", "hypothesis": "h", "label": -1}, random.Random(0)) is None - _, options, target = _read_nli( - {"premise": "p", "hypothesis": "h", "label": 2}, random.Random(0) - ) + result = _read_nli({"premise": "p", "hypothesis": "h", "label": 2}, random.Random(0)) + assert result is not None + _, options, target = result assert options is None and target == 2 def test_toxigen_uses_the_dataset_threshold(self): from lev.data.sources import _read_toxigen - assert _read_toxigen({"text": "t", "toxicity_human": 2.9}, random.Random(0))[2] == 0 - assert _read_toxigen({"text": "t", "toxicity_human": 3.0}, random.Random(0))[2] == 1 + for toxicity, expected in [(2.9, 0), (3.0, 1)]: + result = _read_toxigen({"text": "t", "toxicity_human": toxicity}, random.Random(0)) + assert result is not None + assert result[2] == expected assert _read_toxigen({"text": "t", "toxicity_human": None}, random.Random(0)) is None def test_beavertails_yes_means_safe(self): @@ -453,15 +454,16 @@ def test_ultrafeedback_flattens_completions_and_drops_bad_ratings(self): ], } rows = _read_ultrafeedback(row, random.Random(0)) + assert rows is not None assert [(r[0]["response"], r[2]) for r in rows] == [("a", 4), ("c", 0)] def test_snips_unknown_category_is_skipped(self): from lev.data.sources import SNIPS_INTENTS, _read_snips assert _read_snips({"text": "t", "category": "Nope"}, random.Random(0)) is None - assert _read_snips({"text": "t", "category": "GetWeather"}, random.Random(0))[2] == ( - SNIPS_INTENTS.index("GetWeather") - ) + result = _read_snips({"text": "t", "category": "GetWeather"}, random.Random(0)) + assert result is not None + assert result[2] == SNIPS_INTENTS.index("GetWeather") def test_humanise_splits_camel_case(self): assert humanise("SearchScreeningEvent") == "Search Screening Event" @@ -481,10 +483,12 @@ def test_per_row_options_become_per_row_questions(self): ] examples = list(load_source(REGISTRY["race"], load_dataset=fixed_loader(rows))) assert len(examples) == 8 - assert all( - isinstance(e.question, Choice) and len(e.question.criteria) == 4 for e in examples - ) - assert [list(e.question.criteria)[e.target] for e in examples] == ["w", "x", "y", "z"] * 2 + answers = [] + for e in examples: + assert isinstance(e.question, Choice) + assert len(e.question.criteria) == 4 + answers.append(list(e.question.criteria)[e.target]) + assert answers == ["w", "x", "y", "z"] * 2 def test_noul_reader_targets_land_on_the_rating_ends(self): rows = [{"text1": "a", "text2": "b", "label": 1}, {"text1": "c", "text2": "d", "label": 0}] @@ -493,8 +497,7 @@ def test_noul_reader_targets_land_on_the_rating_ends(self): assert examples[0].state == {"sentence1": "a", "sentence2": "b"} def test_every_noul_source_carries_a_negation(self): - """The aegis2 failure: Noul learned yes = good because no training - question ever made yes the bad outcome.""" + """Both polarities prevent yes from always meaning a good outcome.""" for name, spec in REGISTRY.items(): if spec.primitive == "noul": assert spec.negations, f"{name} has no negated question" @@ -617,7 +620,9 @@ def test_nli_fever_uses_the_string_label_not_the_integer(self): "fever_gold_label": "REFUTES", "label": 2, } - state, options, target = _read_nli_fever(row, random.Random(0)) + result = _read_nli_fever(row, random.Random(0)) + assert result is not None + state, options, target = result assert state == {"claim": "claim", "evidence": "evidence"} assert options is None and FEVER_LABELS[target] == "REFUTES" assert _read_nli_fever({**row, "fever_gold_label": "weird"}, random.Random(0)) is None @@ -665,6 +670,7 @@ def test_yes_no_wrapper_emits_one_true_and_one_false_per_row(self): row = {"article": "A.", "question": "Q?", "options": ["w", "x", "y", "z"], "answer": "C"} rows = yes_no_from_choices(_read_race)(row, random.Random(0)) + assert rows is not None assert [r[2] for r in rows] == [1, 0] assert rows[0][0]["proposed_answer"] == "y" and rows[1][0]["proposed_answer"] != "y" assert rows[0][0]["passage"] == "A." and rows[0][1] is None @@ -680,7 +686,10 @@ def test_large_taxonomy_rows_split_between_full_and_cut_sets(self): subsample_fraction=1.0, augment={"big": Augment(min_options=15, keep_full_fraction=0.5)}, ) - sizes = [len(e.question.criteria) for e in build_mixture(spec, {"big": lambda: pool})] + sizes = [] + for e in build_mixture(spec, {"big": lambda: pool}): + assert isinstance(e.question, Choice) + sizes.append(len(e.question.criteria)) full = sum(s == 40 for s in sizes) assert 120 < full < 280, f"about half should keep the full set, got {full}/400" assert min(sizes) >= 15, "a cut set fell below min_options" @@ -713,8 +722,7 @@ def build(self, out): ) def test_every_split_draws_from_every_source(self, tmp_path): - """The loaders are built in a loop; a late-bound closure would make every - split draw from the last source while coverage and round-trip checks pass.""" + """Late-bound loader closures can cross source contents while preserving source labels.""" from lev.data.build import SPLIT_FILES, read_jsonl manifest = self.build(tmp_path) @@ -722,10 +730,9 @@ def test_every_split_draws_from_every_source(self, tmp_path): for split, filename in SPLIT_FILES.items(): rows = read_jsonl(tmp_path / filename) assert {e.source for e in rows} == {"ag_news", "imdb"}, split.value - # A row is labelled with the pool it was drawn from, so a crossed - # loader leaves the labels right and the content wrong. Check both. for e in rows: if not e.abstain: + assert isinstance(e.state, str) assert e.state.startswith(prefix[e.source]), ( f"{split.value}: {e.source} row holds {e.state!r}" ) @@ -733,8 +740,6 @@ def test_every_split_draws_from_every_source(self, tmp_path): assert set(manifest["sources"]) == {"ag_news", "imdb"} def test_held_out_splits_keep_the_canonical_question(self, tmp_path): - """The test split keeps each source's canonical wording, since an exported - eval needs one question per source.""" from lev.data.build import SPLIT_FILES, read_jsonl self.build(tmp_path) diff --git a/packages/lev/tests/test_engine_forward.py b/packages/lev/tests/test_engine_forward.py index b2d9dcf..e362ec7 100644 --- a/packages/lev/tests/test_engine_forward.py +++ b/packages/lev/tests/test_engine_forward.py @@ -76,5 +76,6 @@ def test_without_score_averaging_a_large_request_answers_as_with_no_limit(tiny_m unlimited = DecisionEngine(tiny_model, TinyTokenizer(), EngineConfig(max_batch_tokens=None)) state = "a long support message " * 16 prepared = limited.prepare(state, questions) + assert limited.config.max_batch_tokens is not None assert prepared.rows == 80 and prepared.rows * prepared.width > limited.config.max_batch_tokens assert limited.system_one(state, questions) == unlimited.system_one(state, questions) diff --git a/packages/lev/tests/test_eval_export.py b/packages/lev/tests/test_eval_export.py index 06cab7e..867be83 100644 --- a/packages/lev/tests/test_eval_export.py +++ b/packages/lev/tests/test_eval_export.py @@ -1,4 +1,4 @@ -"""The lev -> levbench handoff: a file, because levbench must not import lev.""" +"""Test the task-file contract between lev and levbench.""" from __future__ import annotations @@ -36,8 +36,7 @@ def write_test_split(directory, rows): class TestRoundTrip: def test_same_options_in_a_different_order_are_different_questions(self, tmp_path): - """A question cache keyed on sorted payloads moved shuffled rows' targets onto wrong - options (ADR-024).""" + """Sorting cache keys changes what positional targets refer to (ADR-024).""" forward = Choice(instructions="q", criteria={"a": None, "b": None, "c": None}) backward = Choice(instructions="q", criteria={"c": None, "b": None, "a": None}) rows = [an_example(forward, target=0, state="x"), an_example(backward, target=0, state="y")] @@ -45,13 +44,14 @@ def test_same_options_in_a_different_order_are_different_questions(self, tmp_pat write_jsonl(path, rows) back = read_jsonl(path) + assert isinstance(back[0].question, Choice) + assert isinstance(back[1].question, Choice) assert list(back[0].question.criteria)[back[0].target] == "a" assert list(back[1].question.criteria)[back[1].target] == "c" assert back[0].question is not back[1].question def test_round_trip_guard_catches_an_order_blind_reader(self, tmp_path, monkeypatch): - """Re-introduce the ADR-024 bug -- a question cache keyed on sorted - payloads -- and the build-time guard must refuse the file and name the row.""" + """Inject an order-blind cache and require the guard to reject it.""" import lev.data.build as build from lev.data.build import verify_round_trip @@ -108,7 +108,6 @@ def test_score_truth_is_the_level_index(self): assert truth_for(SCORE, 2) == 2 def test_noul_truth_collapses_the_rating_the_way_the_readout_will(self): - """Stored as a rating 0-8, compared as a bool. Both ends must map.""" assert truth_for(NOUL, 8) is True assert truth_for(NOUL, 0) is False @@ -126,7 +125,6 @@ def test_one_file_per_source_plus_an_index(self, tmp_path): assert json.loads((out / "index.json").read_text())["total_items"] == 160 def test_levbench_can_read_what_was_written(self, tmp_path): - """The actual contract. levbench never imports lev; this file is the seam.""" pytest.importorskip("levbench") from levbench.tasks import load_task_file @@ -141,7 +139,6 @@ def test_levbench_can_read_what_was_written(self, tmp_path): assert items[0].labels["a"] in questions["a"].criteria def test_abstain_rows_are_excluded(self, tmp_path): - """Scoring them measures abstention, not accuracy.""" rows = [example(CHOICE, i % 2, i, source="a") for i in range(MIN_USEFUL_ITEMS + 10)] rows += [example(CHOICE, 0, 999, source="a", abstain=True) for _ in range(20)] out = tmp_path / "eval" @@ -149,7 +146,6 @@ def test_abstain_rows_are_excluded(self, tmp_path): assert index["total_items"] == MIN_USEFUL_ITEMS + 10 def test_an_eval_too_small_to_measure_anything_raises(self, tmp_path): - """At n=24 the interval is +/-16 points. That is not a measurement.""" rows = [example(CHOICE, i % 2, i, source="a") for i in range(24)] with pytest.raises(ValueError, match="cannot tell you"): export(write_test_split(tmp_path / "mix", rows), tmp_path / "eval") @@ -157,8 +153,7 @@ def test_an_eval_too_small_to_measure_anything_raises(self, tmp_path): class TestVariableQuestions: def test_sources_whose_question_varies_per_row_are_skipped_and_listed(self, tmp_path): - """A task file has one question for all its items, so per-row options must not be - silently written under the first row's option set.""" + """One task file cannot represent different option sets per row.""" rows = [example(CHOICE, i % 2, i, source="a") for i in range(MIN_USEFUL_ITEMS + 10)] rows += [ example( diff --git a/packages/lev/tests/test_evaluate.py b/packages/lev/tests/test_evaluate.py index 4e5a877..0d65d51 100644 --- a/packages/lev/tests/test_evaluate.py +++ b/packages/lev/tests/test_evaluate.py @@ -29,8 +29,6 @@ def test_perfect_predictions_score_accuracy_one(self): class TestAccuracyInterval: - """The report must state its own resolution: the eval is not reproducible.""" - def test_interval_shrinks_with_n(self): assert accuracy_interval(0.86, 200) > accuracy_interval(0.86, 1800) @@ -38,7 +36,7 @@ def test_matches_the_normal_approximation(self): assert accuracy_interval(0.86, 200) == pytest.approx(0.048, abs=0.001) def test_a_certain_estimate_still_reports_a_finite_interval(self): - """p=1.0 gives zero variance; the formula must not claim infinite precision.""" + """Perfect observed accuracy does not imply zero uncertainty.""" assert 0.0 <= accuracy_interval(1.0, 200) < 0.01 def test_no_items_means_no_information(self): diff --git a/packages/lev/tests/test_loss.py b/packages/lev/tests/test_loss.py index d73cd82..d0669c8 100644 --- a/packages/lev/tests/test_loss.py +++ b/packages/lev/tests/test_loss.py @@ -1,4 +1,4 @@ -"""torch is in the `train` extra, so these skip on a bare `uv sync`.""" +"""Decision-loss tests; skip when Torch is unavailable.""" from __future__ import annotations @@ -14,8 +14,7 @@ class TestDecisionLoss: def test_padded_slots_do_not_produce_nan(self, train_config): - """The first smoke run's bug: a padded slot has logit -inf and target 0, - so a plain product is `0 * -inf` = NaN, poisoning the batch mean.""" + """Padded slots must avoid 0 * -inf, which produces NaN.""" logits = torch.tensor( [[1.0, 2.0, 0.5, 0.1], [0.3, 1.2, float("-inf"), float("-inf")]], requires_grad=True, @@ -26,7 +25,6 @@ def test_padded_slots_do_not_produce_nan(self, train_config): assert torch.isfinite(logits.grad).all() def test_matches_cross_entropy_when_only_ce_is_enabled(self, train_config): - """Supporting soft targets must not change the hard-target answer.""" import torch.nn.functional as F train_config.brier_weight = 0.0 @@ -40,7 +38,6 @@ def test_matches_cross_entropy_when_only_ce_is_enabled(self, train_config): @pytest.mark.parametrize("weight", [0.5, 1.0]) def test_brier_adds_the_weighted_multiclass_brier_score(self, train_config, weight): - """A padded slot (probability 0, target 0) must add nothing to the Brier term.""" logits = torch.tensor( [[8.0, 0.0, 0.0], [2.0, 0.0, 0.0], [0.0, 3.0, float("-inf")]], ) @@ -88,7 +85,6 @@ def test_ordinal_term_prefers_a_near_miss(self, train_config): assert near < far, "an ordered scale must not treat every wrong level alike" def test_ordinal_applies_only_to_the_rows_flagged(self, train_config): - """`ordinal` is per-row: a Score and a Choice can share a batch.""" train_config.ordinal_weight = 5.0 logits = torch.randn(4, 5) targets = torch.tensor([0, 1, 2, 3]) @@ -103,14 +99,11 @@ def test_ordinal_applies_only_to_the_rows_flagged(self, train_config): class TestOrdinalCoverage: def test_noul_rows_are_flagged_ordinal(self, batching_tokenizer): - """The scale runs "0 = certainly no" to "8 = certainly yes": without the - ordinal term, rating 4 is as wrong as rating 0 when the truth is 8.""" collator = DecisionCollator(batching_tokenizer, max_seq_len=512) batch = collator([an_example(Noul(instructions="urgent?"), target=8)]) assert batch.ordinal.tolist() == [True] def test_choice_rows_are_not_flagged_ordinal(self, batching_tokenizer): - """Choice options are unordered symbols; a distance term is meaningless.""" collator = DecisionCollator(batching_tokenizer, max_seq_len=512) assert collator([an_example(a_choice(4))]).ordinal.tolist() == [False] diff --git a/packages/lev/tests/test_packaging.py b/packages/lev/tests/test_packaging.py index c412472..13f14e9 100644 --- a/packages/lev/tests/test_packaging.py +++ b/packages/lev/tests/test_packaging.py @@ -1,4 +1,4 @@ -"""Docs run commands from the repo root, so an extra defined only on a member is unreachable.""" +"""Test workspace extras and documented commands from the repository root.""" from __future__ import annotations @@ -58,8 +58,7 @@ def test_known_extras_are_present(expected): def _inspect_cli(tool: str) -> tuple[set[str], dict[str, set[str]]]: - """Introspects the real parser rather than regexing the source, so it checks what the - parser actually accepts.""" + """Inspect the live parser to collect accepted commands and flags.""" import argparse import importlib @@ -117,8 +116,7 @@ def test_every_documented_backend_exists(): def _documented_commands(tool: str) -> dict[str, set[str]]: - """Only fenced blocks and inline backticks count; prose like "levbench must not import - lev" would otherwise match.""" + """Extract commands from fenced blocks and inline code, excluding prose.""" found: dict[str, set[str]] = {} sources = [ROOT / "README.md", ROOT / "Makefile", ROOT / "CONTRIBUTING.md"] sources += sorted((ROOT / "docs").glob("*.md")) @@ -127,8 +125,7 @@ def _documented_commands(tool: str) -> dict[str, set[str]]: if not src.is_file(): continue text = src.read_text() - # A Makefile is all code apart from its `## help text`, which is prose - # and mentions commands the way a sentence does. + # Exclude Makefile help comments from command extraction. code = ( [re.sub(r"##.*", "", text)] if src.suffix != ".md" diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 9f58e30..830f091 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -1,10 +1,4 @@ -"""Presentation checks (ADR-029), opt-in Score order averaging and the request row limit. - -The checks run against `FakeEngine`: a real `DecisionEngine` without weights routes, -renders and counts every request, as serving does, and only the logits are scripted. -So a probe lev would reject, a row count that disagrees with the engine, or an answer -shape the checks misread fails here without weights. -""" +"""Test presentation probes using real routing and rendering with scripted logits.""" from __future__ import annotations @@ -56,10 +50,7 @@ def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: class FakeEngine: - """logit = content[text] + key_pull[key] + slot0 (in slot 0) + a packing term that - grows with the questions per call, read in every order the engine renders and - averaged as lev does. Routing, orders, row counts and the row limit are the real - engine's.""" + """Use real routing and orders with scripted content, key, slot, and packing effects.""" def __init__(self, slot0=0.0, content=None, packing=0.0, key_pull=None, **config): self.real = DecisionEngine(model=None, tokenizer=Tokenizer(), config=EngineConfig(**config)) @@ -86,6 +77,7 @@ def system_one(self, state, questions): rows: dict[str, list] = {} for variant in prepared.variants: q = prepared.questions[variant.name] + assert isinstance(q, Choice | Score) items = list(q.criteria.items()) if q.type == "choice" else list(enumerate(q.criteria)) shown = items if variant.order is None else [items[i] for i in variant.order] z = [ @@ -98,6 +90,7 @@ def system_one(self, state, questions): rows.setdefault(variant.name, []).append((softmax(z), variant.order)) answers = {} for name, q in prepared.questions.items(): + assert isinstance(q, Choice | Score) p = average_orders([r[0] for r in rows[name]], [r[1] for r in rows[name]]) if q.type == "score": answers[name] = ScoreAnswer( @@ -186,7 +179,7 @@ def test_a_planted_slot_zero_penalty_is_measured_exactly(self): assert r[kind]["first_slot"]["decisions"] == 18 def test_ties_are_split_between_the_tied_slots(self): - """A flat readout ties all three slots; argmax would credit slot 0 every time.""" + """Argmax would incorrectly credit slot zero for every flat distribution.""" r = run(FakeEngine(), ["a", "b"]) for kind in KINDS: assert r[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) @@ -203,7 +196,7 @@ def test_a_choice_key_pull_cancels_and_a_position_effect_does_not(self): @pytest.mark.parametrize("mode", ["reversed", "cyclic"]) def test_the_identical_check_reads_one_order_whatever_the_engine_averages(self, mode): - """Averaged, a pure slot bias cancels (cyclic) or hides the middle slots (reversed).""" + """Order averaging hides the raw position bias this probe measures.""" single = run(FakeEngine(slot0=-2.0, order_average=False), ["a"]) averaged = run(FakeEngine(slot0=-2.0, score_order_average=mode), ["a"]) for kind in KINDS: @@ -223,8 +216,6 @@ def test_the_gate_is_the_proposal_and_can_be_moved(self): class TestCallGroups: - """Calls hold at most `max_rows` rows, counted by the engine for every question.""" - @pytest.mark.parametrize("mode", ["off", "reversed", "cyclic"]) def test_every_call_fits_the_limit_and_asks_everything_once(self, mode): engine = FakeEngine(score_order_average=mode) @@ -244,11 +235,13 @@ def test_the_grouping_does_not_change_an_isolated_readout(self): engine = FakeEngine(slot0=-1.0, content={"Soon": 1.0}, score_order_average="cyclic") assert run(engine, ["a", "b"], max_rows=5) == run(engine, ["a", "b"]) - def test_identical_and_permuted_questions_never_share_a_call(self): + def test_identical_and_permuted_questions_never_share_a_call(self, monkeypatch): engine = FakeEngine() seen = [] real = engine.system_one - engine.system_one = lambda state, qs: seen.append(set(qs)) or real(state, qs) + monkeypatch.setattr( + engine, "system_one", lambda state, qs: seen.append(set(qs)) or real(state, qs) + ) ask(engine, ["a"]) for qids in seen: assert len({q.split("|")[1] for q in qids}) == 1 @@ -303,8 +296,6 @@ def test_the_cli_is_registered(self): class TestScoreOrderAverage: - """Off by default: a Score keeps its level order unless the config opts in.""" - def orders(self, question, tokenizer, **config): engine = DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) return engine._orders(question, route(question, tokenizer)) @@ -349,7 +340,6 @@ def test_schema_first_never_doubles_the_prefix(self, rich_tokenizer): ) == [None] def test_cyclic_averaging_cancels_a_slot_bias_on_equal_content(self): - """Each level sits in each slot once, so a pure position bias averages out.""" k = 4 orders = [None] + [[(j + r) % k for j in range(k)] for r in range(1, k)] biased = softmax([2.0, 0.0, 0.0, 0.0]) @@ -365,8 +355,6 @@ def test_cyclic_averaging_cancels_a_slot_bias_on_equal_content(self): class TestQuestionRows: - """`question_rows` is what `prepare` renders, so callers never recount rows.""" - @pytest.mark.parametrize("mode", ["off", "reversed", "cyclic"]) @pytest.mark.parametrize("order_average", [True, False]) @pytest.mark.parametrize("noul_readout", ["rating", "binary"]) @@ -408,8 +396,6 @@ def test_schema_first_is_one_row_per_question(self, rich_tokenizer): class TestAveragedTokenLimit: - """Only a request Score averaging grew can be refused, and only past the batch budget.""" - def engine(self, tokenizer, **config) -> DecisionEngine: return DecisionEngine(model=None, tokenizer=tokenizer, config=EngineConfig(**config)) @@ -424,7 +410,7 @@ def test_a_long_state_with_few_averaged_rows_is_refused(self, rich_tokenizer): assert self.engine(rich_tokenizer).prepare(LONG, question).rows == 1 def test_without_score_averaging_a_large_request_is_never_refused(self, rich_tokenizer): - """#4's batcher runs an oversized request alone and unsplit, so main accepts it.""" + """The batcher runs oversized requests alone.""" prepared = self.engine(rich_tokenizer).prepare("x" * 400, BIG) assert prepared.rows == 80 and prepared.rows * prepared.width > MAX_BATCH_TOKENS assert [v.order for v in prepared.variants] == [None, [3, 2, 1, 0]] * 20 + [None] * 40 @@ -486,8 +472,6 @@ def test_the_server_answers_422(self, monkeypatch, rich_tokenizer): class TestCommittedReport: - """`data/presentation-checks.json` is what `--compare` reads in CI.""" - def test_it_parses_and_carries_every_metric(self): path = Path(__file__).resolve().parents[3] / "data" / "presentation-checks.json" @@ -502,7 +486,7 @@ def test_it_parses_and_carries_every_metric(self): class TestCompareGuardsItsSettings: - """`--compare` compares like with like: settings first (exit 2), then metrics (exit 1).""" + """Settings mismatches exit 2; metric failures exit 1.""" def cli(self, monkeypatch, tmp_path, engine, *extra): from lev.cli import main diff --git a/packages/lev/tests/test_progress.py b/packages/lev/tests/test_progress.py index 97e2e8f..e57879b 100644 --- a/packages/lev/tests/test_progress.py +++ b/packages/lev/tests/test_progress.py @@ -1,4 +1,4 @@ -"""torch is in the `train` extra, so these skip on a bare `uv sync`.""" +"""Progress-reporting tests; skip when Torch is unavailable.""" from __future__ import annotations @@ -13,8 +13,6 @@ class TestProgressLog: - """A silent run is indistinguishable from a hung one.""" - def make(self, total=100, every=10): return ProgressLog(total, every) @@ -27,14 +25,13 @@ def test_logs_only_on_the_interval(self, capsys): assert "step 10/100" in capsys.readouterr().out def test_always_logs_the_final_step(self, capsys): - """An interval that does not divide the total must not swallow the end.""" log = self.make(total=7, every=10) for step in range(7): log.record(step, 1.0, "A", 1e-4, tokens=10) assert "step 7/7" in capsys.readouterr().out def test_modes_are_reported_separately(self, capsys): - """Mode B starts near ln(K); blending it with Mode A hides both.""" + """Mode B starts near ln(K), so averaging modes hides their separate losses.""" log = self.make(total=2, every=2) log.record(0, 1.0, "A", 1e-4, tokens=10) log.record(1, 5.0, "B", 1e-4, tokens=10) @@ -52,13 +49,10 @@ def test_window_resets_between_reports(self, capsys): assert "A=1.0000" in capsys.readouterr().out, "stale window carried forward" def test_throughput_counts_real_tokens(self, capsys): - """Counted from the attention mask, not the config's average, which was once wrong by 10x - (ADR-016) and would have hidden the mistake.""" log = self.make(total=1, every=1) log.record(0, 1.0, "A", 1e-4, tokens=4096) out = capsys.readouterr().out - # Parse the value rather than substring-match it: a fast window makes - # the rate large, and "4096000000 tok/s" contains "0 tok/s". + # Parse the rate so large values cannot falsely match a zero-rate substring. match = re.search(r"([\d,]+) tok/s", out) assert match, out assert int(match.group(1).replace(",", "")) > 0 @@ -75,8 +69,7 @@ def test_hms_formats_hours(self): class TestWindowedRate: - """A cumulative rate never stops paying the startup cost: the 0.8B smoke read 0.33 it/s - against a true 2.50, and the ETA was 7.5x off (ADR-017).""" + """Windowed rates exclude startup delay from steady-state throughput and ETA.""" @pytest.fixture def clock(self, monkeypatch): @@ -100,7 +93,9 @@ def test_rate_reflects_the_window_not_the_startup_stall(self, capsys, clock): second = capsys.readouterr().out def rate(out): - return float(re.search(r"([\d.]+) it/s", out).group(1)) + match = re.search(r"([\d.]+) it/s", out) + assert match is not None, out + return float(match.group(1)) assert rate(second) == pytest.approx(2.5, abs=0.05), second assert rate(second) > 5 * rate(first), f"{rate(first)} -> {rate(second)}" diff --git a/packages/lev/tests/test_release.py b/packages/lev/tests/test_release.py index 975bebc..2b890dc 100644 --- a/packages/lev/tests/test_release.py +++ b/packages/lev/tests/test_release.py @@ -10,7 +10,7 @@ def fake_checkpoint(root, step=18750, calibrated=True): - """The files `save_checkpoint` and `calibrate` leave behind, contents faked.""" + """Create placeholder files matching a saved checkpoint and calibration.""" out = root / "4b" step_dir = out / f"step-{step}" step_dir.mkdir(parents=True) @@ -97,8 +97,7 @@ def test_a_missing_path_that_is_not_a_hub_id_fails_clearly(self, spec): fetch_checkpoint(spec) def test_a_mistyped_local_path_that_looks_like_a_hub_id_fails_clearly(self, monkeypatch): - """`checkpoints/lev-instuct` has one `/`, so it is tried on the Hub; a - missing repo must read as a missing path, not a raw Hub 404.""" + """A missing relative path may also parse as a Hub id.""" # Both ship with the `train` extra, absent on a bare `uv sync`. huggingface_hub = pytest.importorskip("huggingface_hub") httpx = pytest.importorskip("httpx") @@ -115,7 +114,6 @@ def not_on_the_hub(repo, **kwargs): def test_model_card_describes_routing_as_it_is_served_and_trained(tmp_path): - """The card ships with the weights, so it must not carry a stale `27+` Mode B threshold.""" out = fake_checkpoint(tmp_path) build_release(out, tmp_path / "release", preset="4b") card = (tmp_path / "release" / MODEL_CARD).read_text() diff --git a/packages/lev/tests/test_s1bench.py b/packages/lev/tests/test_s1bench.py index 267a744..bd7eb1b 100644 --- a/packages/lev/tests/test_s1bench.py +++ b/packages/lev/tests/test_s1bench.py @@ -1,4 +1,4 @@ -"""The eval door opens only onto blocked subsets and has no route into the training mixture.""" +"""Test that S1Bench evaluation loading remains isolated from training.""" from __future__ import annotations @@ -22,7 +22,6 @@ def test_every_blocked_subset_still_raises_on_the_training_path(self, subset: st assert_clean([subset]) def test_adding_an_eval_door_did_not_unblock_the_hf_ids_it_reads(self) -> None: - """The loader reads `tals/vitaminc`; the mixture still must not.""" for spec in EVAL_SUBSETS.values(): with pytest.raises(ContaminationError): assert_clean([spec.hf_id]) @@ -41,15 +40,13 @@ def test_aliases_resolve_to_their_subset(self, alias: str) -> None: @pytest.mark.parametrize("name", ["ag_news", "imdb", "banking77", "some/private-corpus"]) def test_training_sources_are_refused(self, name: str) -> None: - """The door must not become a general-purpose dataset loader.""" with pytest.raises(ContaminationError): get_subset(name) class TestStructuralSeparation: def test_s1bench_cannot_reach_the_mixture_builder(self) -> None: - """Importing `mixture` would give the eval loaders a type the training path consumes. - A fresh interpreter, since in-process the suite's own imports are visible.""" + """Use a fresh interpreter so existing test-suite imports do not mask dependencies.""" probe = ( "import sys; import lev.data.s1bench; " "leaked = sorted(m for m in sys.modules " @@ -103,15 +100,12 @@ def test_definition_is_self_consistent_and_names_its_source(self, name: str) -> @pytest.mark.parametrize("name", sorted(EVAL_SUBSETS)) def test_record_counts_match_the_board(self, name: str) -> None: - """helpsteer2 is one record short of the board's 250: the manifest's - token-length filter dropped rows.""" + """The pinned helpsteer2 filter yields 249 records, one fewer than the board.""" board = jev_board(snapshot())[name] expected = board["total"] - (1 if name == "helpsteer2" else 0) assert definition(name)["count"] == expected def test_jev_numbers_match_the_snapshot(self) -> None: - """Read from `data/s1bench-snapshot.json` rather than restated, so a - regenerated snapshot fails here.""" data = snapshot() board = jev_board(data) for name, subset in EVAL_SUBSETS.items(): diff --git a/packages/lev/tests/test_training_loop.py b/packages/lev/tests/test_training_loop.py index e543079..b2588f0 100644 --- a/packages/lev/tests/test_training_loop.py +++ b/packages/lev/tests/test_training_loop.py @@ -1,4 +1,4 @@ -"""torch is in the `train` extra, so these skip on a bare `uv sync`.""" +"""Training-loop tests; skip when Torch is unavailable.""" from __future__ import annotations @@ -72,8 +72,7 @@ def smoke_config(tmp_path, *, epochs, checkpoint_every): def run_resumable( tmp_path, monkeypatch, *, max_steps, checkpoint_every=3, fresh=False, persist=True ): - """Checkpoints land on disk, so a second call in the same `tmp_path` resumes. - Returns (saved steps, batches seen, summary).""" + """Run with on-disk checkpoints; return saved steps, observed batches, and summary.""" import lev.train.loop as loop from lev.train.checkpoints import TRAINING_STATE from lev.train.collate import DecisionCollator @@ -105,8 +104,7 @@ def fake_save(m, h, tk, out, step, cb=None, state=None): class TestCheckpointCadence: - """Only data loading, the backbone, the forward pass and the checkpoint write are stubbed; - batching, routing, the step counter and checkpoint decisions are the shipping code.""" + """Exercise real batching and checkpoint decisions with model and storage stubs.""" def run(self, tmp_path, monkeypatch, *, max_steps, checkpoint_every, epochs=1): import lev.train.loop as loop @@ -124,13 +122,10 @@ def run(self, tmp_path, monkeypatch, *, max_steps, checkpoint_every, epochs=1): return saved def test_the_final_step_is_not_checkpointed_twice(self, tmp_path, monkeypatch): - """A total that is a multiple of `checkpoint_every` saves once; on Modal a - duplicate is a second multi-hundred-MB adapter write and Volume commit.""" saved = self.run(tmp_path, monkeypatch, max_steps=12, checkpoint_every=6) assert saved == [6, 12], f"expected [6, 12], got {saved}" def test_an_uneven_total_still_saves_at_the_end(self, tmp_path, monkeypatch): - """Dedup must not swallow the final save when it is not on the interval.""" saved = self.run(tmp_path, monkeypatch, max_steps=10, checkpoint_every=4) assert saved == [4, 8, 10], f"expected [4, 8, 10], got {saved}" @@ -140,9 +135,6 @@ def test_checkpointing_off_still_saves_once(self, tmp_path, monkeypatch): class TestResume: - """A preempted run continues at the step it stopped, through the batches it had not seen, - on the schedule it had reached.""" - def test_resumes_at_the_saved_step_and_sees_only_the_remaining_batches( self, tmp_path, monkeypatch ): @@ -163,6 +155,7 @@ def test_saved_state_records_the_schedule_position(self, tmp_path, monkeypatch): run_resumable(tmp_path, monkeypatch, max_steps=6) state = load_training_state(tmp_path / "out" / "step-6") + assert state is not None assert (state["step"], state["epoch"], state["step_in_epoch"]) == (6, 0, 6) assert state["scheduler"]["last_epoch"] == 6 @@ -173,16 +166,14 @@ def test_fresh_ignores_the_checkpoint(self, tmp_path, monkeypatch): assert summary["history"][0]["step"] == 0 def test_weights_only_checkpoint_restarts_the_schedule(self, tmp_path, monkeypatch): - """A checkpoint without training state (pre-ADR-021) restarts the step count - from zero. `load_checkpoint` is stubbed, so weight restore is not checked.""" + """Weight loading is stubbed; this checks schedule restart only.""" run_resumable(tmp_path, monkeypatch, max_steps=6, persist=False) saved, _, summary = run_resumable(tmp_path, monkeypatch, max_steps=6) assert saved == [3, 6] assert summary["history"][0]["step"] == 0 def test_rerunning_a_finished_run_trains_nothing(self, tmp_path, monkeypatch): - """7 steps at checkpoint_every=3 ends between saves, so the final checkpoint must carry - training state or a rerun resumes it as weights-only and trains from step 0.""" + """An off-interval final checkpoint must carry resume state.""" run_resumable(tmp_path, monkeypatch, max_steps=7) saved, seen, summary = run_resumable(tmp_path, monkeypatch, max_steps=7) assert seen == [], "a finished run must not train again" @@ -198,8 +189,7 @@ def test_a_final_checkpoint_between_saves_resumes_where_it_stopped(self, tmp_pat assert [h["step"] for h in summary["history"]] == list(range(10)) def test_resume_across_an_epoch_boundary(self, tmp_path, monkeypatch): - """64 rows at batch 2 is 32 steps per epoch; stopping at 33 is one step - into epoch 1, and the resumed run must skip exactly that one.""" + """At batch size two, step 33 is the first step of the second 64-row epoch.""" _, full, _ = run_resumable(tmp_path / "ref", monkeypatch, max_steps=36) run_resumable(tmp_path, monkeypatch, max_steps=33) _, seen, summary = run_resumable(tmp_path, monkeypatch, max_steps=36) @@ -228,8 +218,7 @@ def test_stale_checkpoints_and_calibration_are_moved_not_deleted(self, tmp_path) assert set_aside_previous_run(out) is None def test_fresh_run_does_not_resume_from_a_higher_stale_step(self, tmp_path, monkeypatch): - """The hazard: a fresh run writes step-3, step-6 beside a stale step-18750; - a preemption's auto-resume would take the stale one. `--fresh` moves it.""" + """Stale higher-step checkpoints must not survive in the active run directory.""" from lev.train.checkpoints import latest_checkpoint stale = tmp_path / "out" / "step-18750" @@ -238,13 +227,13 @@ def test_fresh_run_does_not_resume_from_a_higher_stale_step(self, tmp_path, monk saved, _, summary = run_resumable(tmp_path, monkeypatch, max_steps=6, fresh=True) assert saved == [3, 6] assert summary["history"][0]["step"] == 0 - assert latest_checkpoint(tmp_path / "out").name == "step-6" + latest = latest_checkpoint(tmp_path / "out") + assert latest is not None and latest.name == "step-6" class TestModeAProjectsOnlyTheAnswerPositions: def test_logits_to_keep_selects_distinct_positions_and_rows_read_their_own(self): - """Mode A must not materialise (B, seq, V): the model is asked for the - distinct answer positions only, and each row reads its own column.""" + """Project only answer positions and select the correct output column per row.""" from types import SimpleNamespace from lev.router import Mode @@ -256,8 +245,7 @@ class FakeModel: def __call__(self, input_ids, attention_mask, logits_to_keep): seen["keep"] = logits_to_keep.tolist() b, v = input_ids.shape[0], 10 - # logits[row, j, tok] = 100*row + 10*keep[j] + tok, so the value - # read identifies which row and position it came from. + # Encode row and position in each logit to expose indexing errors. keep = logits_to_keep.float() rows = torch.arange(b).float()[:, None, None] * 100 pos = keep[None, :, None] * 10 diff --git a/packages/levbench/src/levbench/__init__.py b/packages/levbench/src/levbench/__init__.py index 6eaf970..42c86e8 100644 --- a/packages/levbench/src/levbench/__init__.py +++ b/packages/levbench/src/levbench/__init__.py @@ -1,5 +1 @@ -"""Benchmark harness for any `/v1/systemone` server: Jev, lev, or an LLM baseline. - -Import submodules directly (`from levbench import runner, metrics`); the package -binds nothing at import time, so importing one module does not pull in the rest. -""" +"""Benchmark System One servers; import submodules directly.""" diff --git a/packages/levbench/src/levbench/batching.py b/packages/levbench/src/levbench/batching.py index e80458b..e763022 100644 --- a/packages/levbench/src/levbench/batching.py +++ b/packages/levbench/src/levbench/batching.py @@ -1,10 +1,4 @@ -"""The batching sweep: one state, N questions, one call versus N calls. - -Measures the central economic claim: input tokens are billed per *request*, -so reading a large state is amortised across every question asked in the same -call. If it holds, batched cost stays roughly flat as N grows while split cost -grows linearly. -""" +"""Compare one batched call with separate calls over a shared state.""" from __future__ import annotations @@ -16,8 +10,7 @@ from . import pricing from .runner import call_once -# One shared document; all three primitives, since output-token cost differs -# between them. +# Include all three primitives because their output costs differ. QUESTION_BANK: list[tuple[str, Any]] = [ ("mentions_retention", Noul(instructions="The document discusses data retention periods.")), ("mentions_consent", Noul(instructions="The document discusses user consent.")), @@ -96,17 +89,18 @@ def sweep( errors: list[tuple[int, str]] | None = None, ) -> list[SweepRow]: """Run the sweep, appending any per-count failure to `errors`.""" - bank = bank or QUESTION_BANK + bank = QUESTION_BANK if bank is None else bank rows: list[SweepRow] = [] errors = errors if errors is not None else [] for n in counts: + if n < 1: + raise ValueError(f"Question count must be positive, got {n}") if n > len(bank): raise ValueError(f"Asked for {n} questions but the bank holds {len(bank)}") selected = dict(bank[:n]) - # The default sweep (1,2,4,8,13) sends 33 sequential requests; each count - # is isolated so a late rate limit keeps the rows already paid for. + # Preserve completed rows if a later count hits an API failure. try: batched = call_once(client, state, selected) batched_cost = pricing.cost_usd(model, batched.input_tokens, batched.output_tokens) @@ -117,7 +111,7 @@ def sweep( one = call_once(client, state, {key: question}) split_cost += pricing.cost_usd(model, one.input_tokens, one.output_tokens) split_seconds += one.seconds - except Exception as exc: # noqa: BLE001 -- any API failure, report and move on + except Exception as exc: errors.append((n, f"{type(exc).__name__}: {exc}")) continue diff --git a/packages/levbench/src/levbench/cli.py b/packages/levbench/src/levbench/cli.py index 00bc770..4dee4d6 100644 --- a/packages/levbench/src/levbench/cli.py +++ b/packages/levbench/src/levbench/cli.py @@ -8,6 +8,7 @@ import argparse import os import sys +from collections.abc import Sequence from contextlib import nullcontext from pathlib import Path @@ -20,8 +21,7 @@ def repo_data_dir() -> Path: - """Find the repo's `data/` by walking up from this file, so it survives the - package moving within the repo.""" + """Find the repository data directory relative to this module.""" for parent in Path(__file__).resolve().parents: if (candidate := parent / "data").is_dir(): return candidate @@ -41,9 +41,8 @@ def _require_key(backend: str, base_url: str | None = None) -> None: sys.exit(f"{needed} is not set.\n{hint}") -def _task_files(path: str | None) -> list[Path | None]: - """`None` for the built-in fixture, else one entry per task file; a generated - eval is a directory with one file per source (ADR-015).""" +def _task_files(path: str | None) -> Sequence[Path | None]: + """Return task files, or None to use the built-in fixture.""" if path is None: return [None] target = Path(path) diff --git a/packages/levbench/src/levbench/confidence_id.py b/packages/levbench/src/levbench/confidence_id.py index 189ea69..69ebba3 100644 --- a/packages/levbench/src/levbench/confidence_id.py +++ b/packages/levbench/src/levbench/confidence_id.py @@ -1,14 +1,9 @@ -"""Identify which statistic the server's `confidence` field actually is. - -TypeSafe documents it only as "a statistic computed from the probability distribution". -Jev's is `norm_max_prob` rounded to 2 dp (docs/FINDINGS.md §3); LitJev states normalized -Gini, so a LitJev server is a known-answer test. -""" +"""Identify a server's confidence formula from its answer distributions.""" from __future__ import annotations import math -from collections.abc import Callable +from collections.abc import Callable, Iterable from dataclasses import dataclass from typing import Any @@ -43,8 +38,7 @@ def top_two_margin(p: Distribution) -> float: def normalized_max_prob(p: Distribution) -> float: - """Chance-corrected max probability: a raw 0.5 means something different over - 2 candidates than over 20.""" + """Normalize maximum probability relative to uniform chance.""" k = len(p) if k <= 1: return 1.0 @@ -69,8 +63,7 @@ def top_two_ratio(p: Distribution) -> float: def detect_precision(values: list[float], max_decimals: int = 6) -> float: - """The quantisation step every value is a multiple of, or 0 if none is; the API - rounds before sending, which sets the floor on any match.""" + """Find a shared quantization step, or return zero if none matches.""" for decimals in range(1, max_decimals + 1): unit = 10.0**-decimals if all(abs(v / unit - round(v / unit)) < 1e-6 for v in values): @@ -79,8 +72,7 @@ def detect_precision(values: list[float], max_decimals: int = 6) -> float: def rounding_sensitivity(fn: Callable[[Distribution], float], p: Distribution, eps: float) -> float: - """How far `fn` can move when each probability is off by up to `eps`: `max_prob` - passes it through, `norm_max_prob` amplifies it by K/(K-1), `gini` by about 2K/(K-1).""" + """Bound how probability rounding affects a confidence formula.""" base = fn(p) raised = fn([min(1.0, x + eps) for x in p]) lowered = fn([max(0.0, x - eps) for x in p]) @@ -97,12 +89,11 @@ class Fit: @property def matches(self) -> bool: - """Within the API's rounding plus how far it moves this statistic; a flat 5e-3 - rejects Jev's `norm_max_prob`, which amplifies 2 dp rounding to ~0.01 (FINDINGS §3).""" + """Allow quantization error amplified by the candidate formula.""" return self.max_abs_error <= self.tolerance -def collect(answers: list[Any]) -> list[tuple[Distribution, float]]: +def collect(answers: Iterable[Any]) -> list[tuple[Distribution, float]]: """Pull (distribution, reported confidence) from answers that have both.""" samples: list[tuple[Distribution, float]] = [] for answer in answers: @@ -116,17 +107,15 @@ def collect(answers: list[Any]) -> list[tuple[Distribution, float]]: def identify(samples: list[tuple[Distribution, float]]) -> list[Fit]: """Rank candidate formulas by how closely they reproduce `confidence`.""" + if not samples: + return [] everything = [v for dist, reported in samples for v in (*dist, reported)] eps = detect_precision(everything) / 2 fits: list[Fit] = [] for name, fn in CANDIDATES.items(): errors = [abs(fn(dist) - reported) for dist, reported in samples] - if not errors: - continue - tolerance = max( - (eps + rounding_sensitivity(fn, dist, eps) for dist, _ in samples), default=0.0 - ) + tolerance = max(eps + rounding_sensitivity(fn, dist, eps) for dist, _ in samples) fits.append( Fit( name=name, @@ -140,8 +129,7 @@ def identify(samples: list[tuple[Distribution, float]]) -> list[Fit]: def identify_by_size(samples: list[tuple[Distribution, float]]) -> dict[int, list[Fit]]: - """`identify` per candidate-set size: a formula that holds for one size reads as - "no match" when pooled, and candidate count tracks question type.""" + """Fit confidence formulas separately for each candidate-set size.""" by_size: dict[int, list[tuple[Distribution, float]]] = {} for dist, reported in samples: by_size.setdefault(len(dist), []).append((dist, reported)) @@ -151,7 +139,7 @@ def identify_by_size(samples: list[tuple[Distribution, float]]) -> dict[int, lis def worst_residuals( samples: list[tuple[Distribution, float]], name: str, limit: int = 3 ) -> list[tuple[Distribution, float, float]]: - """The samples a candidate fits worst, as (distribution, reported, predicted).""" + """Return the worst fits as (distribution, reported, predicted).""" fn = CANDIDATES[name] scored = [(dist, reported, fn(dist)) for dist, reported in samples] return sorted(scored, key=lambda row: abs(row[2] - row[1]), reverse=True)[:limit] @@ -184,7 +172,7 @@ def format_fits(fits: list[Fit]) -> str: def format_diagnosis(samples: list[tuple[Distribution, float]]) -> str: - """Per-size fits and the worst residuals, for when nothing matches overall.""" + """Format per-size fits and worst residuals.""" out: list[str] = [] off = [abs(sum(dist) - 1.0) for dist, _ in samples] diff --git a/packages/levbench/src/levbench/metrics.py b/packages/levbench/src/levbench/metrics.py index e9de062..372051e 100644 --- a/packages/levbench/src/levbench/metrics.py +++ b/packages/levbench/src/levbench/metrics.py @@ -1,9 +1,4 @@ -"""Accuracy and calibration over typed answer distributions. - -ECE uses top probability, since servers define their `confidence` fields -differently (lev: normalized Gini; Jev: chance-corrected max probability). Noul -is represented as {True: p, False: 1-p} for every backend. -""" +"""Score typed distributions; ECE uses top probability, independent of vendor confidence.""" from __future__ import annotations @@ -11,8 +6,7 @@ from dataclasses import dataclass, field from typing import Any -# Log clamp, so a confidently wrong answer scores badly rather than infinitely -# badly (the scikit-learn convention). +# Clamp zero probabilities so confidently wrong answers have finite log loss. _EPS = 1e-15 @@ -34,8 +28,7 @@ def predicted_label(answer: Any) -> Any: if kind == "noul": return float(answer.noul) >= 0.5 if kind == "choice": - # Not a recomputed argmax: they differ on ties, and `choice` is what a - # caller acts on. + # Preserve the model's choice, including its tie-breaking behavior. return answer.choice if kind == "score": return max(answer.probabilities.items(), key=lambda kv: kv[1])[0] @@ -43,7 +36,7 @@ def predicted_label(answer: Any) -> Any: def top_probability(answer: Any) -> float: - """The most likely label's probability (max(p, 1-p) for a Noul): what ECE bins on.""" + """Return the top-label probability used for ECE.""" return max(to_distribution(answer).values()) @@ -134,10 +127,9 @@ def calibration( def selective_accuracy( records: list[tuple[dict[Any, float], Any, Any, float]], threshold: float ) -> tuple[float, float]: - """Accuracy on answers at or above a confidence threshold, plus the kept fraction; - if accuracy does not rise with the threshold, confidence is useless for routing.""" + """Return accuracy and coverage above a confidence threshold.""" kept = [r for r in records if r[3] >= threshold] if not kept: return 0.0, 0.0 - acc = sum(1 for _, pred, truth, _ in kept if pred == truth) / len(kept) + acc = sum(pred == truth for _, pred, truth, _ in kept) / len(kept) return acc, len(kept) / len(records) diff --git a/packages/levbench/src/levbench/pricing.py b/packages/levbench/src/levbench/pricing.py index 62a7ab2..1d341c6 100644 --- a/packages/levbench/src/levbench/pricing.py +++ b/packages/levbench/src/levbench/pricing.py @@ -1,9 +1,4 @@ -"""Per-million-token prices, and cost accounting for a single call. - -Jev prices are from typesafe.ai (input $0.042/M, output free). Anthropic prices -are first-party API rates. Both are vendor list prices and go stale -- override -via `PRICES` rather than editing call sites. -""" +"""Compute call costs from per-million-token list prices; override rates via PRICES.""" from __future__ import annotations @@ -26,9 +21,7 @@ class Price: } -# A self-hosted model costs GPU time, not tokens. An unlisted `jev*` name is -# priced as jev-latest; any other unlisted name, including an unlisted -# `claude-*`, counts as self-hosted and costs $0. +# Unknown jev names use jev-latest rates; other unknown models have zero token cost. SELF_HOSTED = Price(0.0, 0.0) diff --git a/packages/levbench/src/levbench/runner.py b/packages/levbench/src/levbench/runner.py index 2cf3228..a96a302 100644 --- a/packages/levbench/src/levbench/runner.py +++ b/packages/levbench/src/levbench/runner.py @@ -1,21 +1,18 @@ -"""Backend-agnostic evaluation runner. - -Every backend exposes the same `system_one(state, questions)` call and answer -types, so the benchmark is written once and only the client changes. -""" +"""Evaluate backends through the shared system_one interface.""" from __future__ import annotations import os import statistics import time +from collections.abc import Sequence from dataclasses import dataclass, field from typing import Any from dotenv import load_dotenv from . import metrics, pricing -from .tasks import Item +from .tasks import FileItem, Item load_dotenv() @@ -27,8 +24,7 @@ class CallResult: served_by: str input_tokens: int output_tokens: int - # Adapter-only retries (schema-invalid LLM output, transient provider errors); - # always 0 on the TypeSafe SDK, where schema conformance is structural. + # Adapter retries; the TypeSafe SDK reports zero. schema_retries: int = 0 transient_retries: int = 0 @@ -85,11 +81,7 @@ def build_client( base_url: str | None = None, timeout: float | None = None, ): - """Return `(client, model_name)` for jev, lev or anthropic. - - Jev and lev share the TypeSafe protocol. lev defaults to localhost, needs no - credential and uses self-hosted pricing. Anthropic uses the LLM adapter. - """ + """Build a Jev, local lev, or Anthropic client and return its model name.""" if backend in ("jev", "lev"): if backend == "lev": base_url = base_url or DEFAULT_LOCAL_BASE_URL @@ -103,8 +95,7 @@ def build_client( kwargs["timeout"] = DEFAULT_LOCAL_TIMEOUT if base_url: kwargs["base_url"] = base_url - # Never forward the hosted API key to a custom endpoint. Empty local - # keys also fall back, since an empty Bearer header is invalid. + # Use local credentials for custom endpoints; empty keys produce invalid Bearer headers. kwargs["api_key"] = os.environ.get("LEVBENCH_LOCAL_API_KEY") or "local" return TypeSafeClient(**kwargs), resolved @@ -126,8 +117,7 @@ def build_client( def _token_count(usage: Any, total_field: str, base_field: str) -> int: - """Prefer the adapter's `*_total` (it includes billed retries) over the SDK's base - field; a genuine 0 counts, but an absent count raises rather than booking it free.""" + """Prefer billed retry totals; accept zero counts and reject missing counts.""" for field_name in (total_field, base_field): value = getattr(usage, field_name, None) if value is not None: @@ -167,12 +157,11 @@ def run_eval( client, backend: str, model: str, - items: list[Item], + items: Sequence[Item | FileItem], questions: dict[str, Any], concurrency: int = 1, ) -> EvalReport: - """Score every item, with up to `concurrency` requests in flight and results in - item order; concurrency lowers wall time, not the per-call latency reported.""" + """Evaluate concurrently, returning results in item order and per-call latencies.""" from concurrent.futures import ThreadPoolExecutor report = EvalReport(backend=backend, model=model) @@ -188,14 +177,16 @@ def run_eval( for item, result in zip(items, results, strict=True): report.calls.append(result) + labels = item.labels for name, answer in result.answers.items(): - truth = item.labels[name] + truth = labels[name] + distribution = metrics.to_distribution(answer) records[name].append( ( - metrics.to_distribution(answer), + distribution, metrics.predicted_label(answer), truth, - metrics.top_probability(answer), + max(distribution.values()), ) ) @@ -225,8 +216,7 @@ def _format_summary(report: EvalReport) -> list[str]: if n: lines.append(f"latency p50 {report.pct(0.5):.3f}s") lines.append(f"latency mean {statistics.mean(report.latencies):.3f}s") - # Under 100 calls the p95 falls among the few slowest calls, which are - # mostly connection setup; report the slowest call instead. + # Report the maximum for small samples, where p95 is dominated by connection setup. if n >= 100: lines.append(f"latency p95 {report.pct(0.95):.3f}s") else: diff --git a/packages/levbench/src/levbench/snake/__init__.py b/packages/levbench/src/levbench/snake/__init__.py index 762b949..9e3763d 100644 --- a/packages/levbench/src/levbench/snake/__init__.py +++ b/packages/levbench/src/levbench/snake/__init__.py @@ -1,9 +1,4 @@ -"""A decision model plays Snake, one `/v1/systemone` call per move. - -Ported from laya-mlx (Apache-2.0, github.com/mizorewww/laya-mlx) with its rules, -planner and prompts verbatim, so runs are comparable (ADR-022). The planner scores -both Noul answers live; the compact prompt states them (docs/FINDINGS.md §12). -""" +"""Snake benchmark ported from laya-mlx (Apache-2.0, github.com/mizorewww/laya-mlx; ADR-022).""" from .game import DIRECTIONS, SnakeGame from .policy import Decision, ModelPolicy, PlannerClient diff --git a/packages/levbench/src/levbench/snake/game.py b/packages/levbench/src/levbench/snake/game.py index 8c0e8ec..585208c 100644 --- a/packages/levbench/src/levbench/snake/game.py +++ b/packages/levbench/src/levbench/snake/game.py @@ -1,9 +1,6 @@ -"""Deterministic Snake rules and a Hamiltonian-cycle safety planner. +"""Snake rules and cycle-order safety planning, following laya-mlx. -A safe move preserves cycle order without crossing the tail or skipping food. -The shield rejects moves outside that policy, including legal moves that do -not cause an immediate collision. Rules follow laya-mlx so runs are comparable. -""" +Safe moves preserve cycle order without crossing the tail or skipping food.""" from __future__ import annotations @@ -61,7 +58,7 @@ def __init__(self, width: int = 24, height: int = 16, seed: int = 7, initial_len def head(self) -> tuple[int, int]: return self.body[0] - def _spawn_food(self): + def _spawn_food(self) -> tuple[int, int] | None: occupied = set(self.body) empty = [cell for cell in self.cycle if cell not in occupied] return self.rng.choice(empty) if empty else None @@ -84,6 +81,7 @@ def legal_reason(self, direction: str) -> str: def moves(self) -> list[MoveInfo]: if not self.alive or self.won: return [] + assert self.food is not None, "an unfinished game must have food" head_index = self.indices[self.head] tail_distance = (self.indices[self.body[-1]] - head_index) % self.capacity food_distance = (self.indices[self.food] - head_index) % self.capacity diff --git a/packages/levbench/src/levbench/snake/policy.py b/packages/levbench/src/levbench/snake/policy.py index 423dee7..04b5fe4 100644 --- a/packages/levbench/src/levbench/snake/policy.py +++ b/packages/levbench/src/levbench/snake/policy.py @@ -1,8 +1,6 @@ -"""Turn a board into one System One call, and the answer into a move. +"""Turn Snake boards into model decisions using laya-mlx prompts. -Both prompts are laya-mlx's verbatim. `compact` states the two Noul answers in the state -text, so a model that reads its input scores 100% on them; `detailed` uses prose. -""" +The compact prompt supplies the two Noul truths; the detailed prompt uses prose.""" from __future__ import annotations @@ -27,8 +25,7 @@ class Decision: executed: str safe_directions: list[str] intervened: bool - # `dead_end_risk` is 1 - the `risk` answer, which asks whether a safe route exists; - # the `*_truth` fields are what the planner knows. + # risk asks about a safe route; dead_end_risk is its complement. Truth comes from the planner. dead_end_risk: float food_reachable: float route_truth: bool @@ -46,8 +43,7 @@ def to_dict(self) -> dict: def describe(game: SnakeGame, prompt: str) -> tuple[str, dict[str, Any], dict]: - """The state text and questions for one board, plus the planner's view; separate - from `decide` so the wording can be tested and logged without a call.""" + """Build prompts and planner truth without calling the server.""" if prompt not in PROMPTS: raise ValueError(f"prompt must be one of {PROMPTS}, got {prompt!r}") moves = game.moves() @@ -120,8 +116,7 @@ def describe(game: SnakeGame, prompt: str) -> tuple[str, dict[str, Any], dict]: class PlannerClient: - """A stand-in server answering from the planner in SDK shapes: the reference row - every model is measured against, and a way to run the display with no server.""" + """Return planner decisions in SDK shapes for the offline baseline.""" served = "planner" @@ -146,8 +141,7 @@ def system_one(self, state, questions): class ModelPolicy: - """Asks the server for a move; with `guarded`, executes the likeliest safe one and - raises if no safe move exists.""" + """Ask for a move; guarded mode picks the likeliest safe move or raises if none exists.""" def __init__(self, client, *, guarded: bool = True, prompt: str = "compact"): if prompt not in PROMPTS: diff --git a/packages/levbench/src/levbench/snake/run.py b/packages/levbench/src/levbench/snake/run.py index 6dae240..da529bf 100644 --- a/packages/levbench/src/levbench/snake/run.py +++ b/packages/levbench/src/levbench/snake/run.py @@ -1,8 +1,4 @@ -"""The game loop: one decision per move, rounds, pacing, a replayable record. - -Rounds and the JSONL record follow laya (ADR-022). Shielded, a finished board starts the -next seed; unassisted, the first round's end ends the run, so survival means something. -""" +"""Play and record Snake; guarded runs advance seeds, unassisted runs end after one round.""" from __future__ import annotations @@ -122,14 +118,10 @@ def play( keys: Callable[[], str] | None = None, on_step: Callable[[dict, dict, dict], None] | None = None, ) -> RunSummary: - """Play until `steps` moves, `duration` seconds, Q, or -- unassisted -- a round's end. - - Ctrl-C also stops the run. `fps` paces moves to a budget; None waits only - on inference. `display` is a `LiveDisplay`; `keys` returns pressed keys - (SPACE pause, +/- or arrow up/down speed, R next round on the next seed, - Q quit); `on_step` gets `(game, decision, stats)` as dicts for headless - status lines. - """ + """Play until the move/time limit, quit, interrupt, or an unassisted round ends. + + fps controls pacing. Keys pause, change speed, advance rounds, or quit; + on_step receives game, decision, and stats dictionaries.""" game = SnakeGame(width, height, seed, initial_length) policy = ModelPolicy(client, guarded=guarded, prompt=prompt) recorder = Recorder(record) @@ -171,6 +163,8 @@ def play( "food_acc": 0.0, } deaths = 0 + round_number = 1 + route_correct = food_correct = 0 best_length = len(game.body) served = model timestamps: deque[float] = deque(maxlen=60) @@ -178,8 +172,10 @@ def play( started = time.perf_counter() def next_round() -> SnakeGame: - stats["round"] += 1 - return SnakeGame(width, height, seed + stats["round"] - 1, initial_length) + nonlocal round_number + round_number += 1 + stats["round"] = round_number + return SnakeGame(width, height, seed + round_number - 1, initial_length) try: while True: @@ -229,12 +225,10 @@ def next_round() -> SnakeGame: ) stats["steps"] = len(decisions) n = len(decisions) - stats["route_acc"] = ( - sum(((1 - d.dead_end_risk) >= 0.5) == d.route_truth for d in decisions) / n - ) - stats["food_acc"] = ( - sum((d.food_reachable >= 0.5) == d.food_truth for d in decisions) / n - ) + route_correct += ((1 - decision.dead_end_risk) >= 0.5) == decision.route_truth + food_correct += (decision.food_reachable >= 0.5) == decision.food_truth + stats["route_acc"] = route_correct / n + stats["food_acc"] = food_correct / n shown_game, shown_decision = game.snapshot(), decision.to_dict() if display: @@ -285,7 +279,7 @@ def next_round() -> SnakeGame: seed=seed, best_length=best_length, seconds=seconds, - rounds=stats["round"], + rounds=round_number, deaths=deaths, best_score=max(stats["best"], game.score), ) diff --git a/packages/levbench/src/levbench/snake/ui.py b/packages/levbench/src/levbench/snake/ui.py index e5eba5b..741ff14 100644 --- a/packages/levbench/src/levbench/snake/ui.py +++ b/packages/levbench/src/levbench/snake/ui.py @@ -1,10 +1,6 @@ -"""A fixed-cell terminal composition, shared by the live display and replay. +"""Live and replay terminal display adapted from laya-mlx (Apache-2.0). -laya-mlx's layout (Apache-2.0), with the right-hand panel adapted to a client -of a remote server: the backend and served model replace the local engine -lines, and the planner's ground truth sits beside the model's two estimates. -`rich` is optional: without it the loop prints one status line per step. -""" +Show server metadata and planner truth beside model estimates; Rich is optional.""" from __future__ import annotations diff --git a/packages/levbench/src/levbench/tasks.py b/packages/levbench/src/levbench/tasks.py index 5761c2d..af8a75a 100644 --- a/packages/levbench/src/levbench/tasks.py +++ b/packages/levbench/src/levbench/tasks.py @@ -1,14 +1,10 @@ -"""Built-in smoke fixture and file-backed benchmark tasks. - -The 24 support tickets below are too few to measure training improvements. -Use held-out task files for benchmarks. Each JSON file has `questions` and -`items`; each item has a `state` and `labels` keyed by question name. -""" +"""Smoke fixture and task-file loading; use held-out files to measure model improvements.""" from __future__ import annotations import json import math +from collections.abc import Sequence from dataclasses import dataclass, field from pathlib import Path from typing import Any @@ -225,15 +221,14 @@ def load_task_file(path: str | Path) -> tuple[list[FileItem], dict[str, Any]]: return items, built -def dataset(path: str | Path | None = None) -> tuple[list[Any], dict[str, Any]]: +def dataset(path: str | Path | None = None) -> tuple[Sequence[Item | FileItem], dict[str, Any]]: if path is not None: return load_task_file(path) return ITEMS, questions() def detectable_difference(n: int, baseline: float = 0.8, z: float = 1.96) -> float: - """Roughly the smallest accuracy change `n` items can distinguish: the one-proportion - normal-approximation half-width (comparing two runs needs more; ADR-015).""" + """Estimate the accuracy margin (95% at default z); comparing runs needs more data.""" if n <= 0: return 1.0 return min(1.0, z * math.sqrt(baseline * (1 - baseline) / n)) diff --git a/packages/levbench/tests/fake_transport.py b/packages/levbench/tests/fake_transport.py index 6be8c14..6882ab7 100644 --- a/packages/levbench/tests/fake_transport.py +++ b/packages/levbench/tests/fake_transport.py @@ -1,7 +1,4 @@ -"""A fake Jev endpoint: real request parsing, wire-shaped responses, no API key. - -It tests plumbing only: answers are deterministic pseudo-random, so its accuracy is meaningless. -""" +"""Fake Jev transport with deterministic pseudo-random answers; tests plumbing, not accuracy.""" from __future__ import annotations @@ -16,33 +13,34 @@ def _rand(*parts: str) -> float: return int.from_bytes(digest[:8], "big") / 2**64 +def _probabilities(key: str, options: list[str] | range, state_sig: str) -> dict: + weights = [_rand(state_sig, key, str(option)) + 1e-6 for option in options] + total = sum(weights) + return {o: round(w / total, 4) for o, w in zip(options, weights, strict=True)} + + def _answer(key: str, question: dict, state_sig: str) -> dict: kind = question["type"] if kind == "noul": return {"type": "noul", "noul": round(_rand(state_sig, key, "noul"), 4)} if kind == "choice": - options = list(question["criteria"]) - weights = [_rand(state_sig, key, o) + 1e-6 for o in options] - total = sum(weights) - probs = {o: round(w / total, 4) for o, w in zip(options, weights, strict=True)} + probs = _probabilities(key, list(question["criteria"]), state_sig) return { "type": "choice", - "choice": max(probs, key=probs.get), + "choice": max(probs, key=probs.__getitem__), "probabilities": probs, - "confidence": round(max(probs.values()), 4), + "confidence": max(probs.values()), } if kind == "score": levels = question["criteria"] - weights = [_rand(state_sig, key, str(i)) + 1e-6 for i in range(len(levels))] - total = sum(weights) - probs = {i: round(w / total, 4) for i, w in enumerate(weights)} + probs = _probabilities(key, range(len(levels)), state_sig) return { "type": "score", "score": round(sum(i * p for i, p in probs.items()), 4), "probabilities": probs, - "confidence": round(max(probs.values()), 4), + "confidence": max(probs.values()), "legend": {i: lv for i, lv in enumerate(levels)}, } @@ -58,8 +56,7 @@ def handler(request: httpx2.Request) -> httpx2.Response: questions = body["questions"] answers = {k: _answer(k, q, state_sig) for k, q in questions.items()} - # Input scales with the state (billed once per request), output with the - # question count: the shape the batching sweep must find from responses. + # Bill state tokens once per request and output tokens per question. input_tokens = max(1, len(state_text) // 4) output_tokens = 4 * len(questions) diff --git a/packages/levbench/tests/test_offline.py b/packages/levbench/tests/test_offline.py index 8606f84..cb01ac4 100644 --- a/packages/levbench/tests/test_offline.py +++ b/packages/levbench/tests/test_offline.py @@ -1,4 +1,4 @@ -"""End-to-end plumbing check against the fake transport. No API key needed.""" +"""Offline checks for benchmark metrics, SDK plumbing, and reporting. No API key needed.""" from __future__ import annotations @@ -6,23 +6,19 @@ import json import math import random -import sys from pathlib import Path from threading import Barrier from types import SimpleNamespace -PKG = Path(__file__).resolve().parents[1] -ROOT = next(p for p in PKG.parents if (p / "data").is_dir()) -sys.path.insert(0, str(PKG / "src")) -sys.path.insert(0, str(PKG / "tests")) +import httpx2 +import pytest +from fake_transport import transport +from levbench import batching, confidence_id, metrics, runner +from levbench.pricing import cost_usd +from levbench.tasks import FileItem, dataset, detectable_difference, load_task_file +from typesafe_sdk import Choice, Noul, TypeSafeClient -import httpx2 # noqa: E402 -import pytest # noqa: E402 -from fake_transport import transport # noqa: E402 -from levbench import batching, confidence_id, metrics, runner # noqa: E402 -from levbench.pricing import cost_usd # noqa: E402 -from levbench.tasks import FileItem, dataset, detectable_difference, load_task_file # noqa: E402 -from typesafe_sdk import Choice, Noul, TypeSafeClient # noqa: E402 +ROOT = next(p for p in Path(__file__).resolve().parents if (p / "data").is_dir()) def fake_client() -> TypeSafeClient: @@ -31,51 +27,48 @@ def fake_client() -> TypeSafeClient: def test_metrics_are_arithmetically_right() -> None: dist = {"a": 0.7, "b": 0.2, "c": 0.1} - assert abs(metrics.log_loss(dist, "a") - (-math.log(0.7))) < 1e-12 + assert metrics.log_loss(dist, "a") == pytest.approx(-math.log(0.7), abs=1e-12, rel=0) # Brier: (0.7-1)^2 + 0.2^2 + 0.1^2 = 0.09 + 0.04 + 0.01 - assert abs(metrics.brier(dist, "a") - 0.14) < 1e-12 + assert metrics.brier(dist, "a") == pytest.approx(0.14, abs=1e-12, rel=0) # A perfectly calibrated set: 70% confident, 70% accurate -> ECE 0. recs = [({True: 0.7, False: 0.3}, True, True, 0.7)] * 7 recs += [({True: 0.7, False: 0.3}, True, False, 0.7)] * 3 cal = metrics.calibration(recs) - assert abs(cal.accuracy - 0.7) < 1e-12 + assert cal.accuracy == pytest.approx(0.7, abs=1e-12, rel=0) assert cal.ece < 1e-12, f"expected zero ECE, got {cal.ece}" # A badly overconfident set: 100% confident, 50% accurate -> ECE 0.5. bad = [({True: 1.0, False: 0.0}, True, True, 1.0)] * 5 bad += [({True: 1.0, False: 0.0}, True, False, 1.0)] * 5 - assert abs(metrics.calibration(bad).ece - 0.5) < 1e-12 + assert metrics.calibration(bad).ece == pytest.approx(0.5, abs=1e-12, rel=0) def test_every_primitive_flattens_to_a_distribution() -> None: - """Every primitive must flatten, including the fieldless Noul.""" items, questions = dataset() result = runner.call_once(fake_client(), items[0].state, questions) noul = result.answers["is_urgent"] - assert not hasattr(noul, "confidence") or noul.confidence is None + assert getattr(noul, "confidence", None) is None dist = metrics.to_distribution(noul) - assert abs(sum(dist.values()) - 1.0) < 1e-9 + assert sum(dist.values()) == pytest.approx(1.0, abs=1e-9, rel=0) assert metrics.top_probability(noul) == max(dist.values()) choice = result.answers["department"] assert metrics.predicted_label(choice) == choice.choice - assert abs(sum(metrics.to_distribution(choice).values()) - 1.0) < 1e-3 + assert sum(metrics.to_distribution(choice).values()) == pytest.approx(1.0, abs=1e-3, rel=0) score = result.answers["frustration"] by_level = metrics.to_distribution(score) expected = sum(level * p for level, p in by_level.items()) - assert abs(score.score - expected) < 1e-2, "score must equal the probability-weighted mean" + assert score.score == pytest.approx(expected, abs=1e-2, rel=0) def test_ece_bins_on_the_top_probability_not_the_vendor_confidence_field() -> None: - """lev's `confidence` is Gini concentration and Jev's is chance-corrected max - probability, so ECE bins on the answer's own top probability instead.""" + """Vendor confidence formulas differ; ECE must use the answer's top probability.""" class Server: def system_one(self, state, questions): - # 90% on the right answer, but a vendor confidence of 0.2. answer = SimpleNamespace( type="choice", choice="a", probabilities={"a": 0.9, "b": 0.1}, confidence=0.2 ) @@ -88,7 +81,7 @@ def system_one(self, state, questions): items = [FileItem(f"s{i}", {"q": "a" if i < 9 else "b"}) for i in range(10)] questions = {"q": Choice(instructions="?", criteria={"a": None, "b": None})} report = runner.run_eval(Server(), "lev", "stub", items, questions) - # Every answer is 0.9 confident and 9 of 10 are right: perfectly calibrated. + # Top probability is 0.9 and 9 of 10 predictions are correct: ECE is zero. assert report.per_question["q"].ece == pytest.approx(0.0, abs=1e-9) @@ -103,12 +96,11 @@ def test_eval_runs_end_to_end_over_the_built_in_fixture() -> None: def test_sweep_arithmetic_over_a_fixed_billing_shape() -> None: - """SweepRow arithmetic over the fake transport's per-request billing, not - Jev's real billing, which only a live `levbench sweep` can measure.""" + """Synthetic billing verifies sweep arithmetic; live billing requires a live sweep.""" state = (ROOT / "data" / "sample_policy.md").read_text() rows = batching.sweep(fake_client(), "jev-latest", state, [1, 2, 4, 8, 13]) - assert abs(rows[0].cost_ratio - 1.0) < 0.01, ( + assert rows[0].cost_ratio == pytest.approx(1.0, abs=0.01, rel=0), ( "at N=1 batched and split are the same call; ratio must be ~1" ) ratios = [r.cost_ratio for r in rows] @@ -119,51 +111,53 @@ def test_sweep_arithmetic_over_a_fixed_billing_shape() -> None: assert "batching sweep" in batching.format_sweep(rows, "jev-latest", len(state)) -def test_confidence_identifier_recovers_a_planted_formula() -> None: - """If planted formulas were not identified uniquely, a match against a real server - would prove nothing.""" - - def server(conf_fn): - def handle(request): - body = json.loads(request.content) - answers = {} - for key, question in body["questions"].items(): - options = list(question["criteria"]) - # Varied, non-uniform distributions, so candidate statistics - # actually separate instead of coinciding. - raw = [1 + hashlib.sha256(f"{key}:{o}".encode()).digest()[0] % 97 for o in options] - total = sum(raw) - probs = {o: r / total for o, r in zip(options, raw, strict=True)} - answers[key] = { - "type": "choice", - "choice": max(probs, key=probs.get), - "probabilities": probs, - "confidence": conf_fn(list(probs.values())), - } - return httpx2.Response( - 200, - json={ - "model": "planted", - "answers": answers, - "usage": {"input_tokens": 10, "output_tokens": 0}, - }, - ) +@pytest.mark.parametrize("count", [0, -1]) +def test_sweep_rejects_non_positive_question_counts(count) -> None: + with pytest.raises(ValueError, match="must be positive"): + batching.sweep(None, "jev-latest", "state", [count]) + + +def test_sweep_respects_an_explicitly_empty_bank() -> None: + with pytest.raises(ValueError, match="bank holds 0"): + batching.sweep(None, "jev-latest", "state", [1], bank=[]) + - return TypeSafeClient(api_key="x", model="planted", transport=httpx2.MockTransport(handle)) +@pytest.mark.parametrize("planted", confidence_id.CANDIDATES) +def test_confidence_identifier_recovers_a_planted_formula(planted) -> None: + """A match is useful only if the identifier can distinguish candidate formulas.""" + + def handle(request): + body = json.loads(request.content) + answers = {} + for key, question in body["questions"].items(): + options = list(question["criteria"]) + # Non-uniform distributions keep candidate statistics distinguishable. + raw = [1 + hashlib.sha256(f"{key}:{o}".encode()).digest()[0] % 97 for o in options] + total = sum(raw) + probs = {o: r / total for o, r in zip(options, raw, strict=True)} + answers[key] = { + "type": "choice", + "choice": max(probs, key=probs.__getitem__), + "probabilities": probs, + "confidence": confidence_id.CANDIDATES[planted](list(probs.values())), + } + return httpx2.Response( + 200, + json={ + "model": "planted", + "answers": answers, + "usage": {"input_tokens": 10, "output_tokens": 0}, + }, + ) + client = TypeSafeClient(api_key="x", model="planted", transport=httpx2.MockTransport(handle)) questions = { f"q{i}": Choice(instructions="pick", criteria={c: c for c in "abcde"[: 2 + i % 4]}) for i in range(6) } - - for planted, fn in confidence_id.CANDIDATES.items(): - client = server(fn) - answers = [] - for state in ("alpha", "beta", "gamma", "delta"): - answers.extend(runner.call_once(client, state, questions).answers.values()) - fits = confidence_id.identify(confidence_id.collect(answers)) - winners = [f.name for f in fits if f.matches] - assert winners == [planted], f"planted {planted}, identified {winners}" + answers = list(runner.call_once(client, "state", questions).answers.values()) + fits = confidence_id.identify(confidence_id.collect(answers)) + assert [f.name for f in fits if f.matches] == [planted] def test_base_url_routes_to_a_local_clone() -> None: @@ -191,23 +185,24 @@ def handle(request): def test_local_base_url_never_forwards_the_real_key(monkeypatch) -> None: - """A `--base-url` server must not receive TYPESAFE_API_KEY (the SDK always - sends `Authorization: Bearer `); the hosted path still authenticates.""" + """Custom endpoints use a local key; hosted requests retain the real credential.""" monkeypatch.setenv("TYPESAFE_API_KEY", "sk-REAL-SECRET-KEY") monkeypatch.delenv("LEVBENCH_LOCAL_API_KEY", raising=False) local, _ = runner.build_client("jev", "litjev", "http://127.0.0.1:8000") + assert isinstance(local, TypeSafeClient) assert "REAL-SECRET" not in str(local._config.api_key), "leaked the real key" assert local._config.api_key == "local" hosted, _ = runner.build_client("jev", "jev-latest") + assert isinstance(hosted, TypeSafeClient) assert hosted._config.api_key == "sk-REAL-SECRET-KEY", "hosted path lost its key" def test_empty_local_key_env_var_falls_back(monkeypatch) -> None: - """`LEVBENCH_LOCAL_API_KEY=` (from `.env.example`) once reached the SDK as "", which - sends a malformed `Bearer ` header (`LocalProtocolError: Illegal header value`).""" + """An empty key produces an invalid Bearer header; use the local fallback.""" monkeypatch.setenv("LEVBENCH_LOCAL_API_KEY", "") client, _ = runner.build_client("lev") + assert isinstance(client, TypeSafeClient) assert client._config.api_key == "local", ( f"empty env var leaked through as {client._config.api_key!r}" ) @@ -235,27 +230,20 @@ def _write_task_file(path, question_type="choice", n=5): return path -def test_eval_runs_over_a_generated_task_file(tmp_path) -> None: - """The lev -> levbench seam: the harness reads back and scores the kind of - file `lev data eval` writes.""" - items, questions = dataset(_write_task_file(tmp_path / "gen.json")) - report = runner.run_eval(fake_client(), "jev", "jev-latest", items, questions) - assert len(report.calls) == 5 - assert set(report.per_question) == {"q"} - assert "accuracy" in runner.format_report(report) - - @pytest.mark.parametrize("question_type", ["choice", "score", "noul"]) -def test_every_primitive_round_trips_through_a_task_file(tmp_path, question_type) -> None: - items, questions = load_task_file(_write_task_file(tmp_path / "g.json", question_type)) +def test_eval_runs_over_a_generated_task_file(tmp_path, question_type) -> None: + """Exercise the task-file format produced by `lev data eval` for every primitive.""" + items, questions = dataset(_write_task_file(tmp_path / "gen.json", question_type)) assert questions["q"].type == question_type report = runner.run_eval(fake_client(), "jev", "jev-latest", items, questions) + assert len(report.calls) == 5 + assert set(report.per_question) == {"q"} assert report.per_question["q"] is not None + assert "accuracy" in runner.format_report(report) def test_a_task_file_labelling_an_undefined_question_raises(tmp_path) -> None: - """Otherwise the label is silently dropped and the eval scores fewer items - than it was given.""" + """Reject undefined questions so their labels cannot be silently excluded from scoring.""" path = tmp_path / "bad.json" path.write_text( json.dumps( @@ -281,8 +269,7 @@ def test_detectable_difference_shrinks_with_n() -> None: def test_pooling_can_hide_a_formula_that_holds_per_candidate_set_size() -> None: - """The live Jev run's shape: nothing matched pooled, and the pooled view could not - say which samples broke it.""" + """Grouping by candidate-set size can expose formulas hidden by pooled samples.""" four = [0.7, 0.1, 0.1, 0.1] three = [0.5, 0.3, 0.2] samples = [(four, confidence_id.max_prob(four))] * 6 @@ -306,18 +293,17 @@ def test_worst_residuals_surfaces_the_samples_that_break_a_candidate() -> None: distribution, reported, predicted = worst[0] assert distribution == breaks_it assert reported == 0.99 - assert abs(predicted - 0.5) < 1e-9 + assert predicted == pytest.approx(0.5, abs=1e-9, rel=0) def test_diagnosis_reports_whether_distributions_are_complete() -> None: - """A truncated distribution makes every candidate wrong for the same reason.""" + """Incomplete distributions can distort confidence formulas independently of fit.""" truncated = [([0.6, 0.3], 0.6)] assert "sum to 1 within 0.1" in confidence_id.format_diagnosis(truncated) def test_tolerance_accounts_for_how_much_a_statistic_amplifies_rounding() -> None: - """Jev rounds to 2 dp and `norm_max_prob` amplifies that by K/(K-1) to 0.010, so a - flat 5e-3 threshold rejected the correct formula.""" + """Normalized max probability amplifies rounding by K/(K-1).""" rng = random.Random(0) samples = [] for size in (4, 3): @@ -355,7 +341,7 @@ def test_parallel_requests_keep_item_order_and_report_wall_time(self): class ConcurrentStub: def system_one(self, state, questions): - # All four workers must enter before any request can finish. + # The barrier makes serial execution fail instead of passing unnoticed. barrier.wait(timeout=5) return SimpleNamespace( answers={ @@ -380,7 +366,7 @@ def test_cost_is_per_million_tokens_at_list_price(self) -> None: assert cost_usd("Qwen/Qwen3.5-4B", 1_000_000, 1_000_000) == 0.0, "self-hosted is unmetered" def test_billed_totals_win_over_base_counts(self) -> None: - """The adapter's `*_total` fields include retried attempts -- what is billed.""" + """Retry totals reflect billed usage.""" usage = SimpleNamespace( input_tokens=10, input_tokens_total=25, output_tokens=2, output_tokens_total=4 ) @@ -391,14 +377,9 @@ def test_missing_token_counts_raise_rather_than_count_as_free(self) -> None: runner._usage_ints(SimpleNamespace(input_tokens=None, output_tokens=None)) def test_a_substituted_model_is_flagged_in_the_report(self) -> None: - """Pricing uses the requested model; if the server answered with another, - the report has to say so.""" + """Report model substitution because pricing uses the requested model.""" report = runner.EvalReport(backend="jev", model="jev-latest") report.calls.append(runner.CallResult({}, 0.3, "jev-1.13.0", 10, 1)) assert "requested 'jev-latest' but server served ['jev-1.13.0']" in runner.format_report( report ) - - -if __name__ == "__main__": - raise SystemExit(pytest.main([__file__, "-v"])) diff --git a/packages/levbench/tests/test_snake.py b/packages/levbench/tests/test_snake.py index 6c67406..b973f8e 100644 --- a/packages/levbench/tests/test_snake.py +++ b/packages/levbench/tests/test_snake.py @@ -4,7 +4,9 @@ import json from collections import deque +from pathlib import Path from types import SimpleNamespace +from typing import TypedDict import pytest from levbench.snake import ( @@ -20,37 +22,43 @@ from levbench.snake.policy import describe from levbench.snake.ui import compose, layout_size, status_line -SMALL_BOARD = {"width": 8, "height": 6, "initial_length": 3} +class BoardSettings(TypedDict): + width: int + height: int + initial_length: int -def planner_move(game): + +SMALL_BOARD: BoardSettings = {"width": 8, "height": 6, "initial_length": 3} + + +def planner_move(game: SnakeGame) -> str: return max((m for m in game.moves() if m.safe), key=lambda m: m.advance).direction -def unsafe_direction(game): +def unsafe_direction(game: SnakeGame) -> str: return next(m.direction for m in game.moves() if not m.safe) class StubServer: - """Answers from a chosen direction and two Noul probabilities, SDK-shaped.""" + """Answers from a chosen direction and two Noul probabilities""" def __init__(self, pick=None, route=0.9, food=0.9, follow_planner=False, invert=False): self.pick, self.route, self.food = pick, route, food self.follow_planner, self.invert = follow_planner, invert - self.calls: list[tuple[str, dict]] = [] def system_one(self, state, questions): - self.calls.append((state, questions)) - options = list(questions["move"].criteria) + criteria = questions["move"].criteria + options = list(criteria) if self.follow_planner: - pick = next((o for o in options if "Best" in questions["move"].criteria[o]), options[0]) + pick = next((o for o in options if "Best" in criteria[o]), options[0]) else: pick = self.pick or options[0] probs = {o: 0.04 for o in options} probs[pick] = 1.0 - 0.04 * (len(options) - 1) route, food = self.route, self.food if self.invert: - # Answer both Nouls from the state text, wrongly. + # Contradict the compact prompt to test scoring against planner truth. route = 0.1 if "Safe route: yes" in state else 0.9 food = 0.1 if "reachable through empty cells: yes" in state else 0.9 return SimpleNamespace( @@ -71,11 +79,10 @@ def test_cycle_visits_every_cell_once_with_adjacent_steps(self): for a, b in zip(cycle, cycle[1:] + cycle[:1], strict=True): assert abs(a[0] - b[0]) + abs(a[1] - b[1]) == 1 - def test_odd_by_odd_and_tiny_boards_are_rejected(self): - with pytest.raises(ValueError): - hamiltonian_cycle(5, 5) + @pytest.mark.parametrize(("width", "height"), [(5, 5), (3, 8)]) + def test_odd_by_odd_and_tiny_boards_are_rejected(self, width, height): with pytest.raises(ValueError): - hamiltonian_cycle(3, 8) + hamiltonian_cycle(width, height) def test_same_seed_same_game(self): a, b = SnakeGame(seed=3), SnakeGame(seed=3) @@ -98,17 +105,17 @@ def test_following_the_planner_never_dies(self): def test_eating_grows_and_scores(self): game = SnakeGame(**SMALL_BOARD, seed=1) length = len(game.body) - while True: - eating = [m for m in game.moves() if m.safe and m.eats] - if eating: - assert game.step(eating[0].direction) is True + # The planner advances toward food without skipping it; one cycle is enough. + for _ in range(game.capacity): + if game.step(planner_move(game)): break - game.step(planner_move(game)) + else: + pytest.fail("the planner did not reach food within one cycle") assert len(game.body) == length + 1 and game.score == 1 def test_wall_and_reverse_are_illegal(self): game = SnakeGame(**SMALL_BOARD) - game.body = deque([(0, 0), (1, 0), (2, 0)]) # head in the top-left corner + game.body = deque([(0, 0), (1, 0), (2, 0)]) assert game.legal_reason("LEFT") == "wall" assert game.legal_reason("UP") == "wall" assert game.legal_reason("RIGHT") == "reverse" @@ -147,7 +154,7 @@ def test_shield_executes_best_safe_move_and_keeps_raw_probabilities(self): assert decision.proposed == bad assert decision.executed in decision.safe_directions assert decision.intervened - assert max(decision.probabilities, key=decision.probabilities.get) == bad + assert max(decision.probabilities, key=decision.probabilities.__getitem__) == bad def test_unassisted_executes_the_raw_choice(self): game = SnakeGame() @@ -242,14 +249,34 @@ def test_planner_never_needs_the_shield_and_reads_its_state(self): class TestRounds: def test_guarded_run_continues_past_a_cleared_board(self): - """A 4x4 board with a planner-perfect player is cleared quickly; the run - must roll into round 2 on the next seed rather than stop.""" + """A small board clears within the step budget, forcing a new round.""" summary = play( PlannerClient(), "planner", "planner", width=4, height=4, initial_length=2, steps=60 ) assert summary.rounds >= 2 and summary.steps == 60 assert summary.best_score >= 1 + def test_live_accuracy_remains_cumulative_across_rounds(self): + observed = [] + summary = play( + StubServer(follow_planner=True, route=0.2, food=0.9), + "lev", + "local", + width=4, + height=4, + initial_length=2, + steps=60, + on_step=lambda game, decision, stats: observed.append((decision, stats)), + ) + assert summary.rounds >= 2 + assert len(observed) == 60 + for n, (_, stats) in enumerate(observed, start=1): + expected_food = sum(decision["food_truth"] for decision, _ in observed[:n]) / n + assert stats["route_acc"] == 0.0 + assert stats["food_acc"] == pytest.approx(expected_food) + assert observed[-1][1]["route_acc"] == summary.route_accuracy + assert observed[-1][1]["food_acc"] == summary.food_accuracy + class TestDisplay: def test_layout_fits_the_default_board(self): @@ -288,7 +315,7 @@ def test_status_line_is_one_line(self): class TestReplay: - def test_recording_replays_every_frame(self, tmp_path): + def test_recording_replays_every_frame(self, tmp_path: Path): record = tmp_path / "run.jsonl" play( PlannerClient(), @@ -303,7 +330,7 @@ def test_recording_replays_every_frame(self, tmp_path): class Screen: def __init__(self): - self.frames = [] + self.frames: list[str] = [] def show(self, canvas): self.frames.append(canvas.text()) @@ -312,20 +339,18 @@ def show(self, canvas): assert replay(record, screen, speed=1000.0) == 8 assert "RECORDED RUN" in screen.frames[0] - def test_broken_timestamps_are_rejected(self, tmp_path): + def test_broken_timestamps_are_rejected(self, tmp_path: Path): bad = tmp_path / "bad.jsonl" - bad.write_text( - json.dumps({"type": "metadata", "format": "x"}) - + "\n" - + json.dumps({"type": "frame", "at": 2.0, "game": {}, "decision": {}, "stats": {}}) - + "\n" - + json.dumps({"type": "frame", "at": 1.0, "game": {}, "decision": {}, "stats": {}}) - + "\n" - ) + events = [ + {"type": "metadata", "format": "x"}, + {"type": "frame", "at": 2.0, "game": {}, "decision": {}, "stats": {}}, + {"type": "frame", "at": 1.0, "game": {}, "decision": {}, "stats": {}}, + ] + bad.write_text("\n".join(json.dumps(event) for event in events) + "\n") with pytest.raises(ValueError, match="strictly increase"): load_record(bad) - def test_reusing_a_recording_path_replays_the_latest_run(self, tmp_path): + def test_reusing_a_recording_path_replays_the_latest_run(self, tmp_path: Path): record = tmp_path / "run.jsonl" for seed, steps in ((7, 8), (8, 3)): play( @@ -344,7 +369,7 @@ def test_reusing_a_recording_path_replays_the_latest_run(self, tmp_path): events = [json.loads(line) for line in record.read_text().splitlines()] assert sum(event["type"] == "frame" for event in events) == 11 - def test_an_empty_latest_run_does_not_borrow_previous_frames(self, tmp_path): + def test_an_empty_latest_run_does_not_borrow_previous_frames(self, tmp_path: Path): record = tmp_path / "run.jsonl" events = [ {"type": "metadata", "model": "previous"}, diff --git a/pyproject.toml b/pyproject.toml index ca0e3d2..1340402 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ demo = ["levbench[demo]"] dev = [ "pytest>=8.3", "ruff>=0.14", - # Resolve the SDK rather than the local modal/ directory during type checking. "modal>=1.0", ] @@ -32,6 +31,7 @@ lev = { workspace = true } members = ["packages/*"] [tool.pytest.ini_options] +pythonpath = ["packages/levbench/src"] testpaths = ["packages/levbench/tests", "packages/lev/tests"] addopts = "-q" diff --git a/scripts/publish_hf.sh b/scripts/publish_hf.sh index ab01e4c..b732b6a 100755 --- a/scripts/publish_hf.sh +++ b/scripts/publish_hf.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash -# Package and check the 4b-instruct release on Modal, pull it, add the hf/ model card -# and upload it to a private Hugging Face repo. + +# Package, validate, pull, and publish the 4b-instruct release to Hugging Face. # -# scripts/publish_hf.sh # interfaze-ai/lev -# REPO=interfaze-ai/other scripts/publish_hf.sh # another repo -# DRY_RUN=1 scripts/publish_hf.sh # everything but the upload +# scripts/publish_hf.sh # interfaze-ai/lev +# REPO=interfaze-ai/other scripts/publish_hf.sh # custom repo +# DRY_RUN=1 scripts/publish_hf.sh # skip upload + set -euo pipefail PRESET="${PRESET:-4b-instruct}" @@ -14,7 +15,7 @@ REPO="${REPO:-interfaze-ai/lev}" cd "$(dirname "$0")/.." release="weights/$NAME" -# A token in .env (HF_TOKEN=...) wins over the one `hf auth login` stored. +# Prefer HF_TOKEN from .env over `hf auth login`. if [[ -f .env ]] && grep -q '^HF_TOKEN=' .env; then set -a # shellcheck source=/dev/null @@ -22,20 +23,23 @@ if [[ -f .env ]] && grep -q '^HF_TOKEN=' .env; then set +a fi -hf auth whoami >/dev/null || { echo "not logged in to the Hub: run 'hf auth login'" >&2; exit 1; } +hf auth whoami >/dev/null || { + echo "not logged in to the Hub: run 'hf auth login'" >&2 + exit 1 +} modal run modal/app.py::export_checkpoint --preset "$PRESET" --name "$NAME" -# Load the release as a user will before anything is pulled or published. modal run modal/app.py::check_release --name "$NAME" -# The target must be an existing directory: given a missing path, `volume get` -# writes every file of the release onto that one path. + mkdir -p weights modal volume get --force lev-checkpoints "releases/$NAME" weights/ + cp hf/README.md "$release/README.md" cp -R hf/assets "$release/" echo "release ready in $release:" ls -la "$release" + if [[ -n "${DRY_RUN:-}" ]]; then echo "DRY_RUN set: not uploading to $REPO" exit 0 From f7f851db2438a6ecec23f409bfad3bc3d49cd842 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Wed, 7 Oct 2026 23:30:37 +0530 Subject: [PATCH 15/39] refactor(train): share the checkpoint load and scoring forward --- docs/DECISIONS.md | 2 +- packages/lev/src/lev/train/calibration_run.py | 41 +++++------------ packages/lev/src/lev/train/evaluate.py | 34 ++++---------- packages/lev/src/lev/train/loop.py | 35 +++++++++++++++ packages/lev/tests/test_training_loop.py | 44 +++++++++++++++++++ packages/levbench/pyproject.toml | 2 +- packages/levbench/tests/test_snake.py | 2 +- pyproject.toml | 6 +-- uv.lock | 8 ++-- 9 files changed, 109 insertions(+), 65 deletions(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index bc4610e..008fd2d 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -634,7 +634,7 @@ Accuracy, RPS, Choice and Noul are identical, to the last digit, to the runs bef Calibration of the averaged modes. The shipped Score temperature (2.80) was fitted on single-order rows. Refit per mode on half of each bench (stratified by the gold level, seed 0), judged on the other half: ```text - T refit held-out negative_log_likelihood held-out ECE held-out RPS + T refit NLL held-out ECE held-out RPS shipped refit shipped refit shipped refit en (144) off 3.96 0.935 0.909 0.130 0.108 0.152 0.147 reversed 3.16 0.839 0.838 0.111 0.119 0.126 0.126 diff --git a/packages/lev/src/lev/train/calibration_run.py b/packages/lev/src/lev/train/calibration_run.py index 1eb3fc1..79a5137 100644 --- a/packages/lev/src/lev/train/calibration_run.py +++ b/packages/lev/src/lev/train/calibration_run.py @@ -69,46 +69,29 @@ def collect_logits( limit: int | None = None, ) -> dict[str, list[tuple[list[float], int, str]]]: """Collect raw logits and task families by calibration bucket, skipping abstain rows.""" - import torch from ..data.build import load_split from ..data.sources import family_of from ..data.splits import Split - from ..prompt import Style - from .checkpoints import load_checkpoint - from .collate import DecisionCollator, ModeBatcher, RouteCache from .config import PRESETS - from .loop import build_head, build_model, candidate_logits, device_of, to_device + from .loop import load_for_eval, scored_rows config = config or PRESETS["4b"] - model, tokenizer = build_model(config, None) - head = build_head(config, model) if config.train_mode_b_head else None - load_checkpoint(model, head, checkpoint_dir) - model.eval() - if head is not None: - head.eval() + model, tokenizer, head = load_for_eval(config, checkpoint_dir) rows = [e for e in load_split(data_dir, Split(split)) if not e.abstain] if limit: rows = rows[:limit] - routes = RouteCache(tokenizer, config.max_label_options, Style(config.prompt_style)) - collator = DecisionCollator(tokenizer, max_seq_len=config.max_seq_len, routes=routes) - batcher = ModeBatcher(tokenizer, batch_size=batch_size, routes=routes) - device = device_of(model) - buckets: dict[str, list[tuple[list[float], int, str]]] = {} - with torch.no_grad(): - for group in batcher(rows): - batch = to_device(collator(group), device) - logits = candidate_logits(model, batch, head) - for i, example in enumerate(group): - width = int((~batch.candidate_mask[i]).sum()) - sample = (logits[i, :width].tolist(), example.target, family_of(example.source)) - # Banded for serving, unbanded as the fallback for thin bands. - for key in { - CalibrationProfile.key(example.question.type, batch.mode.value, width), - CalibrationProfile.key(example.question.type, batch.mode.value), - }: - buckets.setdefault(key, []).append(sample) + for example, logits, mode, width in scored_rows( + model, tokenizer, head, config, rows, batch_size + ): + sample = (logits, example.target, family_of(example.source)) + # Banded for serving, unbanded as the fallback for thin bands. + for key in { + CalibrationProfile.key(example.question.type, mode, width), + CalibrationProfile.key(example.question.type, mode), + }: + buckets.setdefault(key, []).append(sample) return buckets diff --git a/packages/lev/src/lev/train/evaluate.py b/packages/lev/src/lev/train/evaluate.py index 5b18507..539c07a 100644 --- a/packages/lev/src/lev/train/evaluate.py +++ b/packages/lev/src/lev/train/evaluate.py @@ -100,25 +100,17 @@ def evaluate_split( batch_size: int = 16, ) -> tuple[EvalReport, EvalReport]: """Return raw and calibrated reports from the same stored logits.""" - import torch from ..data.build import load_split from ..data.splits import Split - from ..prompt import Style - from .checkpoints import load_checkpoint, resolve_checkpoint - from .collate import DecisionCollator, ModeBatcher, RouteCache + from .checkpoints import resolve_checkpoint from .config import PRESETS - from .loop import build_head, build_model, candidate_logits, device_of, to_device + from .loop import load_for_eval, scored_rows config = config or PRESETS["4b"] profile = profile or CalibrationProfile() - model, tokenizer = build_model(config, None) - head = build_head(config, model) if config.train_mode_b_head else None - load_checkpoint(model, head, checkpoint_dir) - model.eval() - if head is not None: - head.eval() + model, tokenizer, head = load_for_eval(config, checkpoint_dir) rows = [row for row in load_split(data_dir, Split(split)) if not row.abstain] if limit_per_source: @@ -131,23 +123,13 @@ def evaluate_split( kept.append(row) rows = kept - routes = RouteCache(tokenizer, config.max_label_options, Style(config.prompt_style)) - collator = DecisionCollator(tokenizer, max_seq_len=config.max_seq_len, routes=routes) # Bucketed like training: each row is scored once whatever the order. - batcher = ModeBatcher( - tokenizer, batch_size=batch_size, bucket_window=config.bucket_window, routes=routes - ) - device = device_of(model) - collected: dict[tuple[str, str, str, int], list[tuple[list[float], int]]] = {} - with torch.no_grad(): - for group in batcher(rows): - batch = to_device(collator(group), device) - logits = candidate_logits(model, batch, head) - for i, example in enumerate(group): - width = int((~batch.candidate_mask[i]).sum()) - key = (example.source, example.question.type, batch.mode.value, width) - collected.setdefault(key, []).append((logits[i, :width].tolist(), example.target)) + for example, logits, mode, width in scored_rows( + model, tokenizer, head, config, rows, batch_size, bucket_window=config.bucket_window + ): + key = (example.source, example.question.type, mode, width) + collected.setdefault(key, []).append((logits, example.target)) resolved = str(resolve_checkpoint(checkpoint_dir)) plain = EvalReport(split=split, checkpoint=resolved, calibrated=False) diff --git a/packages/lev/src/lev/train/loop.py b/packages/lev/src/lev/train/loop.py index eeed601..7bcd3c6 100644 --- a/packages/lev/src/lev/train/loop.py +++ b/packages/lev/src/lev/train/loop.py @@ -179,6 +179,41 @@ def build_head(config: TrainConfig, model=None): return head +def load_for_eval(config: TrainConfig, checkpoint_dir, model_cache: str | None = None): + """Build the model and head, restore a checkpoint into them, and put both in eval mode.""" + model, tokenizer = build_model(config, model_cache) + head = build_head(config, model) if config.train_mode_b_head else None + load_checkpoint(model, head, checkpoint_dir) + model.eval() + if head is not None: + head.eval() + return model, tokenizer, head + + +def scored_rows(model, tokenizer, head, config: TrainConfig, rows, batch_size, bucket_window=64): + """Yield `(example, logits, mode, width)` per row, batched as training batches. + + Callers differ only in how they bucket the result, so the forward pass lives here; + `bucket_window` is explicit because calibration and evaluation have always passed + different values. + """ + import torch + + routes = RouteCache(tokenizer, config.max_label_options, Style(config.prompt_style)) + collator = DecisionCollator(tokenizer, max_seq_len=config.max_seq_len, routes=routes) + batcher = ModeBatcher( + tokenizer, batch_size=batch_size, bucket_window=bucket_window, routes=routes + ) + device = device_of(model) + with torch.no_grad(): + for group in batcher(rows): + batch = to_device(collator(group), device) + logits = candidate_logits(model, batch, head) + for i, example in enumerate(group): + width = int((~batch.candidate_mask[i]).sum()) + yield example, logits[i, :width].tolist(), batch.mode.value, width + + def device_of(model): return next(model.parameters()).device diff --git a/packages/lev/tests/test_training_loop.py b/packages/lev/tests/test_training_loop.py index b2588f0..89de56b 100644 --- a/packages/lev/tests/test_training_loop.py +++ b/packages/lev/tests/test_training_loop.py @@ -264,3 +264,47 @@ def __call__(self, input_ids, attention_mask, logits_to_keep): out = candidate_logits(FakeModel(), batch) assert seen["keep"] == [4, 7], "only the distinct answer positions are projected" assert out.tolist() == [[71.0, 72.0], [141.0, 142.0], [273.0, 274.0]] + + +class TestScoredRows: + """`scored_rows` is the shared forward that calibration and evaluation both read.""" + + def rows_through(self, monkeypatch, n_rows): + from lev.train import loop + from lev.train.config import PRESETS + + rows = [an_example(a_choice(4), target=i % 4, state=f"row {i}") for i in range(n_rows)] + monkeypatch.setattr(loop, "device_of", lambda m: torch.device("cpu")) + monkeypatch.setattr(loop, "to_device", lambda b, d: b) + monkeypatch.setattr( + loop, + "candidate_logits", + lambda m, b, h=None: torch.arange( + b.size * b.candidate_mask.size(1), dtype=torch.float + ).reshape(b.size, -1), + ) + config = PRESETS["smoke"] + out = list( + loop.scored_rows( + StubModel(), make_batching_tokenizer(), None, config, rows, batch_size=8 + ) + ) + return rows, out + + def test_every_row_is_scored_exactly_once(self, monkeypatch): + rows, out = self.rows_through(monkeypatch, 32) + assert len(out) == len(rows) + assert {e.state for e, _, _, _ in out} == {r.state for r in rows} + + def test_width_matches_the_option_count_and_logits_are_trimmed(self, monkeypatch): + from lev.router import Mode + + _, out = self.rows_through(monkeypatch, 16) + for example, logits, mode, width in out: + assert width == len(example.question.criteria) + assert len(logits) == width + assert mode == Mode.LABEL_TOKEN.value + + def test_bucket_window_does_not_drop_or_duplicate_rows(self, monkeypatch): + rows, wide = self.rows_through(monkeypatch, 24) + assert sorted(e.state for e, _, _, _ in wide) == sorted(r.state for r in rows) diff --git a/packages/levbench/pyproject.toml b/packages/levbench/pyproject.toml index 7307d71..9419238 100644 --- a/packages/levbench/pyproject.toml +++ b/packages/levbench/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "levbench" -version = "0.1.0" +version = "0.1.1" description = "Benchmark harness for System One decision models (Jev and compatible servers)" readme = "README.md" requires-python = ">=3.12" diff --git a/packages/levbench/tests/test_snake.py b/packages/levbench/tests/test_snake.py index b973f8e..f730753 100644 --- a/packages/levbench/tests/test_snake.py +++ b/packages/levbench/tests/test_snake.py @@ -266,7 +266,7 @@ def test_live_accuracy_remains_cumulative_across_rounds(self): height=4, initial_length=2, steps=60, - on_step=lambda game, decision, stats: observed.append((decision, stats)), + on_step=lambda _, decision, stats: observed.append((decision, stats)), ) assert summary.rounds >= 2 assert len(observed) == 60 diff --git a/pyproject.toml b/pyproject.toml index 1340402..005b66c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] -name = "lev-workspace" -version = "0.1.1" -description = "lev — umbrella workspace: the `lev` decision model and the `levbench` harness" +name = "lev-4b" +version = "0.1.2" +description = "an open System One decision model" readme = "README.md" requires-python = ">=3.12" license = { text = "Apache-2.0" } diff --git a/uv.lock b/uv.lock index 0a92e96..0c74dea 100644 --- a/uv.lock +++ b/uv.lock @@ -13,7 +13,7 @@ resolution-markers = [ [manifest] members = [ "lev", - "lev-workspace", + "lev-4b", "levbench", ] @@ -999,8 +999,8 @@ requires-dist = [ provides-extras = ["train", "serve", "modal"] [[package]] -name = "lev-workspace" -version = "0.1.1" +name = "lev-4b" +version = "0.1.2" source = { virtual = "." } dependencies = [ { name = "lev" }, @@ -1048,7 +1048,7 @@ dev = [ [[package]] name = "levbench" -version = "0.1.0" +version = "0.1.1" source = { editable = "packages/levbench" } dependencies = [ { name = "python-dotenv" }, From feb9865f0ad886f95349495c1e1db0d404c01591 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 16/39] fix(modal): score the ordinal sweep with levbench's label rule --- modal/app.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/modal/app.py b/modal/app.py index 3586ba5..4fce9fe 100644 --- a/modal/app.py +++ b/modal/app.py @@ -394,6 +394,15 @@ def check_release(name: str = "4b") -> dict: return {"health": health, "response": served} +def _predicted_label(answer): + """levbench's label rule, so a sweep is comparable with a `levbench eval` run.""" + if answer.type == "noul": + return float(answer.noul) >= 0.5 + if answer.type == "choice": + return answer.choice + return max(answer.probabilities.items(), key=lambda kv: kv[1])[0] + + @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=2 * 60 * 60) def diagnose_ordinal( name: str = "lev", @@ -426,9 +435,8 @@ def diagnose_ordinal( picks: collections.Counter = collections.Counter() for item in items: answer = engine.system_one(item.state, {"decision": question}).answers["decision"] - probs = {int(k): float(v) for k, v in answer.probabilities.items()} - pick = max(probs, key=probs.get) - picks[pick] += 1 + pick = _predicted_label(answer) + picks[str(pick)] += 1 hits += pick == item.truth row = report["subsets"].setdefault(subset, {}) row[f"{scale:g}"] = { From 281704b101d18cb953fd4741f29effbfadc5d058 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 17/39] feat(serve): apply the release adapter scale when loading --- packages/lev/src/lev/model.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index 00a7eaa..145e4a2 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -535,11 +535,16 @@ def load( score_order_average: Literal["off", "reversed", "cyclic"] = "off", max_batch_tokens: int | None = MAX_BATCH_TOKENS, merge_adapter: bool = True, + adapter_scale: float | None = None, ) -> DecisionEngine: """Load an engine from a release, training output, or Hub id; otherwise use the frozen base. Release metadata overrides the base model and prompt style. Load the checkpoint's - tokenizer, head, and calibration when present; warn if calibration is missing.""" + tokenizer, head, and calibration when present; warn if calibration is missing. + + `adapter_scale` overrides the manifest's `adapter_scale`, a multiplier on the adapter's + trained strength: below 1.0 it interpolates back toward the frozen backbone, trading + in-distribution accuracy for out-of-distribution robustness (FINDINGS.md §19).""" import torch from transformers import AutoModelForCausalLM, AutoTokenizer @@ -548,9 +553,11 @@ def load( # Load the base model before applying the checkpoint's adapter. resolved = resolve_checkpoint(checkpoint, cache_dir) if checkpoint else None manifest_file = resolved / "lev_release.json" if resolved else None + released_scale = 1.0 if manifest_file and manifest_file.is_file(): manifest = json.loads(manifest_file.read_text()) prompt_style = manifest.get("prompt_style", prompt_style) + released_scale = float(manifest.get("adapter_scale", 1.0)) if manifest["base_model"] != model_id: print( f"release manifest names base {manifest['base_model']!r}; " @@ -578,6 +585,9 @@ def load( # Merge to reduce launches and fix graph weights; keep separate for adapter-scale sweeps. model = PeftModel.from_pretrained(model, str(resolved)) + scale = released_scale if adapter_scale is None else adapter_scale + if scale != 1.0: + _set_adapter_scale(model, scale) if merge_adapter: model = model.merge_and_unload() head = _load_head(resolved / MODE_B_HEAD, model) @@ -612,6 +622,18 @@ def load( return engine +def _set_adapter_scale(model, scale: float) -> None: + """Scale every LoRA layer relative to its trained strength, before any merge bakes it in.""" + from peft.tuners.lora import LoraLayer + + layers = [m for m in model.modules() if isinstance(m, LoraLayer)] + if not layers: + raise RuntimeError(f"adapter_scale {scale} requested, but the model has no LoRA layers") + for layer in layers: + for adapter in layer.scaling: + layer.set_scale(adapter, scale) + + def _load_head(path: Path, model): """Load the saved Mode B head, or return None for Mode A-only serving.""" import torch From 0a2a650a4a42c6d5201edc61f27d90d6ec31ceac Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 18/39] test(serve): pin the adapter-scale multiplier through the merge --- packages/lev/tests/test_adapter_scale.py | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 packages/lev/tests/test_adapter_scale.py diff --git a/packages/lev/tests/test_adapter_scale.py b/packages/lev/tests/test_adapter_scale.py new file mode 100644 index 0000000..ca08469 --- /dev/null +++ b/packages/lev/tests/test_adapter_scale.py @@ -0,0 +1,71 @@ +"""Pin the adapter-scale multiplier: relative to trained strength, and survives the merge.""" + +from __future__ import annotations + +import pytest + +torch = pytest.importorskip("torch") +qwen = pytest.importorskip("transformers.models.qwen3_5") +peft = pytest.importorskip("peft") + +from lev.model import _set_adapter_scale # noqa: E402 + +TARGET = "model.layers.1.self_attn.q_proj" + + +def tiny_base(): + torch.manual_seed(0) + config = qwen.Qwen3_5TextConfig( + vocab_size=64, + hidden_size=32, + intermediate_size=64, + num_hidden_layers=2, + layer_types=["linear_attention", "full_attention"], + num_attention_heads=2, + num_key_value_heads=1, + head_dim=16, + linear_num_key_heads=2, + linear_num_value_heads=2, + linear_key_head_dim=8, + linear_value_head_dim=8, + ) + return qwen.Qwen3_5ForCausalLM(config).eval() + + +def merged_delta(scale: float | None): + """Weight the merge adds to `TARGET`, with the adapter scaled by `scale` first.""" + base = tiny_base() + before = base.get_submodule(TARGET).weight.detach().clone() + + adapted = peft.get_peft_model( + base, peft.LoraConfig(r=4, lora_alpha=8, target_modules=["q_proj"]) + ) + # lora_B is zero-initialised, so an untouched adapter is a no-op whatever the scale. + for name, param in adapted.named_parameters(): + if "lora_B" in name: + torch.nn.init.normal_(param, std=0.05) + + if scale is not None: + _set_adapter_scale(adapted, scale) + merged = adapted.merge_and_unload() + return merged.get_submodule(TARGET).weight.detach() - before + + +def test_the_merge_scales_the_adapter_linearly(): + full = merged_delta(None) + assert full.abs().max() > 0, "the adapter must not be a no-op for this test to mean anything" + for scale in (0.25, 0.5): + torch.testing.assert_close(merged_delta(scale), full * scale, rtol=1e-4, atol=1e-6) + + +def test_scale_one_is_the_trained_strength(): + torch.testing.assert_close(merged_delta(1.0), merged_delta(None)) + + +def test_scale_zero_leaves_the_frozen_backbone(): + assert merged_delta(0.0).abs().max() == 0 + + +def test_scaling_a_model_without_lora_layers_raises(): + with pytest.raises(RuntimeError, match="no LoRA layers"): + _set_adapter_scale(tiny_base(), 0.25) From e4351bd34731e2b2d6d830f7e996043e39973be9 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 19/39] feat(modal): refit the temperature profile at a chosen adapter scale --- modal/app.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/modal/app.py b/modal/app.py index 4fce9fe..71e3d7e 100644 --- a/modal/app.py +++ b/modal/app.py @@ -394,6 +394,115 @@ def check_release(name: str = "4b") -> dict: return {"health": health, "response": served} +@app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=4 * 60 * 60) +def fit_at_adapter_scale( + name: str = "lev", + preset: str = "4b-instruct", + scale: float = 0.25, + scales: str = "", + split: str = "calibration", + search_rows: int = 6000, + apply: bool = False, +) -> dict: + """Refit the temperature profile with the adapter scaled to `scale`. + + Shrinking the adapter trades in-distribution accuracy for out-of-distribution + robustness, so `split` cannot choose the scale: it is drawn from the training + mixture, and accuracy there rises monotonically to scale 1.0 (0.6233 at 0.125, + 0.8133 at 1.0). The scale is chosen instead by leave-one-family-out over S1Bench, + which holds each family out of its own selection; that put it at 0.25 for 6 of 7 + families. Temperatures still belong on `split`, which is what this fits. + + Passing `scales` sweeps them on `search_rows` rows and reports in-distribution + sensitivity, without selecting. `apply` writes the scale and profile into the release. + """ + import json + import random + + from lev import load + from lev.calibrate import CalibrationProfile, fit_for_transfer + from lev.data.build import load_split + from lev.data.sources import family_of + from lev.data.splits import Split + from lev.train.checkpoints import CALIBRATION + from lev.train.config import PRESETS + from lev.train.evaluate import score + from lev.train.loop import scored_rows + from peft.tuners.lora import LoraLayer + + release = Path(f"{RELEASES_DIR}/{name}") + engine = load(str(release), cache_dir=MODELS_DIR, merge_adapter=False) + layers = [m for m in engine.model.modules() if isinstance(m, LoraLayer)] + if not layers: + raise RuntimeError("adapter already merged; nothing to scale") + + config = PRESETS[preset] + everything = [r for r in load_split(DATA_DIR, Split(split)) if not r.abstain] + # The search only has to separate scales that differ by points, so it runs on a + # shuffled subsample; the chosen scale is then fitted on the whole split. + search_set = everything + if search_rows and search_rows < len(everything): + search_set = random.Random(17).sample(everything, search_rows) + print( + f"{len(layers)} lora layers, {len(everything)} {split} rows, " + f"searching on {len(search_set)}", + flush=True, + ) + + def collect(scale: float, rows): + for m in layers: + for adapter in m.scaling: + m.set_scale(adapter, scale) + buckets: dict[str, list[tuple[list[float], int, str]]] = {} + flat: list[tuple[list[float], int]] = [] + for example, logits, mode, width in scored_rows( + engine.model, engine.tokenizer, engine.mode_b_head, config, rows, 32 + ): + flat.append((logits, example.target)) + sample = (logits, example.target, family_of(example.source)) + for key in { + CalibrationProfile.key(example.question.type, mode, width), + CalibrationProfile.key(example.question.type, mode), + }: + buckets.setdefault(key, []).append(sample) + return buckets, flat + + results: dict[str, dict] = {} + for swept in [float(x) for x in scales.split(",") if x.strip()]: + _, flat = collect(swept, search_set) + accuracy, ece, brier, log_loss = score(flat, 1.0) + results[f"{swept:g}"] = { + "accuracy": round(accuracy, 4), + "ece_uncalibrated": round(ece, 4), + "brier": round(brier, 4), + "log_loss": round(log_loss, 4), + } + print(f" scale {swept:<7g} {split} accuracy {accuracy:.4f} ECE {ece:.4f}", flush=True) + + print(f"fitting temperatures at scale {scale} on all {len(everything)} rows", flush=True) + buckets, flat = collect(scale, everything) + profile, report = fit_for_transfer(buckets, split_name=split) + after = score(flat, 1.0) + out = { + "scale": scale, + "fitted_on": split, + "per_scale": results, + "search_rows": len(search_set) if results else 0, + "temperatures": profile.temperatures, + "calibration_accuracy": round(after[0], 4), + "calibration_ece_uncalibrated": round(after[1], 4), + } + if apply: + profile.save(release / CALIBRATION) + manifest = json.loads((release / "lev_release.json").read_text()) + manifest["adapter_scale"] = scale + (release / "lev_release.json").write_text(json.dumps(manifest, indent=2) + "\n") + checkpoints.commit() + print(f"wrote scale {scale} and refitted temperatures into {release}") + print(json.dumps(out, indent=2)) + return out + + def _predicted_label(answer): """levbench's label rule, so a sweep is comparable with a `levbench eval` run.""" if answer.type == "noul": From ae21270f2685a4b72826313004201295f71b6db1 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 20/39] docs(findings): record the adapter-scale result and its selection --- docs/FINDINGS.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/FINDINGS.md b/docs/FINDINGS.md index c53ed27..a9c2d35 100644 --- a/docs/FINDINGS.md +++ b/docs/FINDINGS.md @@ -677,3 +677,38 @@ A user on a 3090 reported that lev "suffers in boundary conditions. When the ans **What should, in order:** graded or smoothed Noul targets through the existing `soft_targets` path, instead of one-hot 0/8; a paired consistency loss across whitespace and paraphrase variants of the same row; distillation toward the frozen model's Noul distribution, which these measurements show is well behaved at the boundary. Stripping trailing whitespace from the state before rendering is a near-free partial patch. **Limits.** The sample is 30 items per subset with one seed, so per-subset rates are noisy (civil_comments, the worst, is 8 of 30 counting the layout flips). bf16 on MPS is not the reporter's CUDA. On the same weights, batching alone moves p by up to 0.07 in bf16 (ADR-030), so small differences between perturbations are within that floor; spreads of 0.5 or more are not. + +## 19. The adapter scale is an out-of-distribution knob, and it is worth +3.9 macro points + +The released adapter is applied at full strength. Scaling it down at serving time interpolates back toward the frozen backbone — WiSE-FT ([arXiv 2109.01903](https://arxiv.org/abs/2109.01903)), except applied to a LoRA scale rather than a weight average. Swept 2026-10-07/08 on one H100, over all 13 pinned S1Bench subsets, by setting `LoraLayer.set_scale` on each of the 128 adapter layers. Scale 1.0 scores 0.6892 against the 0.6893 measured in §17, which is the control for the whole table. + +```text + 0 0.25 0.5 0.75 1 LOFO scale + aegis2 0.4320 0.8360 0.8200 0.8040 0.8000 <- 0.25 + boolq 0.4200 0.8533 0.8467 0.8367 0.8267 <- 0.25 + civil_comments 0.8900 0.7867 0.7767 0.7800 0.7600 <- 0.25 + helpsteer2 0.3133 0.3574 0.3855 0.3896 0.3855 <- 0.25 + massive-de-DE 0.8000 0.8257 0.8486 0.8429 0.8229 <- 0.25 + massive-en-US 0.8257 0.8686 0.8743 0.8686 0.8571 <- 0.25 + multinli 0.7893 0.8495 0.8662 0.8729 0.8896 <- 0.25 + paws 0.5160 0.8520 0.8360 0.8040 0.7760 <- 0.25 + pubmedqa 0.7040 0.7160 0.7160 0.7160 0.7320 <- 0.25 + squad2 0.5017 0.8227 0.8161 0.8294 0.8127 <- 0.25 + summeval-consistency 0.8264 0.8056 0.6250 0.3958 0.2708 <- 0.5 + summeval-relevance 0.4750 0.3792 0.3458 0.3667 0.3583 <- 0.5 + vitaminc-dev 0.6912 0.7279 0.7179 0.6828 0.6678 <- 0.25 + ------------------------------------------------------------------- + macro 0.6296 0.7447 0.7288 0.7069 0.6892 +``` + +**Scale 0.25 beats full strength by 5.5 macro points — but that number is test-selected.** +Choosing the scale on the same 13 subsets we report is fitting the benchmark, which is exactly what the contamination guard exists to forbid. Two honest selections: + +**The calibration split cannot do it.** Swept 2026-10-08 on 6,000 of its 48,691 rows at seven scales: accuracy is monotone in scale — 0.6233, 0.6508, 0.6810, 0.7112, 0.7393, 0.7942, 0.8133 at 0.125 through 1.0 — and picks 1.0, the scale already shipped. The split is drawn from the training mixture, so it is in-distribution, and shrinking the adapter *costs* in-distribution accuracy while buying out-of-distribution robustness. An in-distribution split is structurally blind to the trade, whatever its size. (Uncalibrated ECE moves the other way, 0.0619 at 0.125 to 0.1400 at 1.0.) + +**Leave-one-family-out over S1Bench can.** The 13 subsets share task families with training but no datasets. Grouping them into 7 families — safety, qa-bool, nli, paraphrase, intent, summeval, rating — and scoring each family at the scale chosen on the *other* six gives a macro of **0.7282**, against 0.6892 shipped and 0.7610 for Jev. Six of seven families pick 0.25 independently; only summeval picks 0.5, because summeval-consistency is the one subset that prefers a weak adapter (0.8264 frozen, 0.2708 at full strength) and the remaining subsets cannot see that when it is held +out. The estimate is robust to the grouping: merging helpsteer2 into summeval, splitting vitaminc off NLI, and leave-one-*subset*-out give 0.7447, 0.7282 and 0.7447. + +**This needs no retraining.** The scale is a serving-time multiplier on weights we already ship. + +**Limits.** The grid is coarse — 0, 0.25, 0.5, 0.75, 1.0 — and the optimum sits at its low end next to 0.25, so a finer sweep may do better; it would have to be selected under the same leave-one-out discipline to stay quotable. Accuracy is an argmax and so is invariant to temperature, which is why these numbers hold even though the shipped temperatures were fitted at scale 1.0; every *calibration* figure at any other scale requires a refit, which is what `fit_at_adapter_scale` in `modal/app.py` does. Per-subset n runs from 144 (summeval-consistency) to 599 (vitaminc-dev), so a single-subset move under about 6 points is noise at the small end and about 3 at the large end; the macro, pooled over all 13, is tighter than either. Closing the gap to Jev takes 3.3 points more than this buys. From 5117993b1658ee1b7a4f02a9d2b979c7134aa8b3 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 21/39] refactor(train): derive the bucket window from the training config --- packages/lev/src/lev/train/evaluate.py | 2 +- packages/lev/src/lev/train/loop.py | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/lev/src/lev/train/evaluate.py b/packages/lev/src/lev/train/evaluate.py index 539c07a..f473f01 100644 --- a/packages/lev/src/lev/train/evaluate.py +++ b/packages/lev/src/lev/train/evaluate.py @@ -126,7 +126,7 @@ def evaluate_split( # Bucketed like training: each row is scored once whatever the order. collected: dict[tuple[str, str, str, int], list[tuple[list[float], int]]] = {} for example, logits, mode, width in scored_rows( - model, tokenizer, head, config, rows, batch_size, bucket_window=config.bucket_window + model, tokenizer, head, config, rows, batch_size ): key = (example.source, example.question.type, mode, width) collected.setdefault(key, []).append((logits, example.target)) diff --git a/packages/lev/src/lev/train/loop.py b/packages/lev/src/lev/train/loop.py index 7bcd3c6..b4a5b3a 100644 --- a/packages/lev/src/lev/train/loop.py +++ b/packages/lev/src/lev/train/loop.py @@ -190,19 +190,14 @@ def load_for_eval(config: TrainConfig, checkpoint_dir, model_cache: str | None = return model, tokenizer, head -def scored_rows(model, tokenizer, head, config: TrainConfig, rows, batch_size, bucket_window=64): - """Yield `(example, logits, mode, width)` per row, batched as training batches. - - Callers differ only in how they bucket the result, so the forward pass lives here; - `bucket_window` is explicit because calibration and evaluation have always passed - different values. - """ +def scored_rows(model, tokenizer, head, config: TrainConfig, rows, batch_size): + """Yield `(example, logits, mode, width)` per row, batched as training batches.""" import torch routes = RouteCache(tokenizer, config.max_label_options, Style(config.prompt_style)) collator = DecisionCollator(tokenizer, max_seq_len=config.max_seq_len, routes=routes) batcher = ModeBatcher( - tokenizer, batch_size=batch_size, bucket_window=bucket_window, routes=routes + tokenizer, batch_size=batch_size, bucket_window=config.bucket_window, routes=routes ) device = device_of(model) with torch.no_grad(): From 06b43a8da36979a0d8c1f5a78457bf2a506d283d Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 22/39] test(train): cover the ragged final batch in the scored-rows round trip --- packages/lev/tests/test_training_loop.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/lev/tests/test_training_loop.py b/packages/lev/tests/test_training_loop.py index 89de56b..163339c 100644 --- a/packages/lev/tests/test_training_loop.py +++ b/packages/lev/tests/test_training_loop.py @@ -291,8 +291,9 @@ def rows_through(self, monkeypatch, n_rows): ) return rows, out - def test_every_row_is_scored_exactly_once(self, monkeypatch): - rows, out = self.rows_through(monkeypatch, 32) + @pytest.mark.parametrize("n_rows", [32, 29]) + def test_every_row_is_scored_exactly_once(self, monkeypatch, n_rows): + rows, out = self.rows_through(monkeypatch, n_rows) assert len(out) == len(rows) assert {e.state for e, _, _, _ in out} == {r.state for r in rows} @@ -304,7 +305,3 @@ def test_width_matches_the_option_count_and_logits_are_trimmed(self, monkeypatch assert width == len(example.question.criteria) assert len(logits) == width assert mode == Mode.LABEL_TOKEN.value - - def test_bucket_window_does_not_drop_or_duplicate_rows(self, monkeypatch): - rows, wide = self.rows_through(monkeypatch, 24) - assert sorted(e.state for e, _, _, _ in wide) == sorted(r.state for r in rows) From 0bce0d376c23ac5de9a46faf1c5d37842ca741d0 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 23/39] refactor(train): tighten the training loop's types --- packages/lev/src/lev/train/loop.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/lev/src/lev/train/loop.py b/packages/lev/src/lev/train/loop.py index b4a5b3a..5abbd38 100644 --- a/packages/lev/src/lev/train/loop.py +++ b/packages/lev/src/lev/train/loop.py @@ -8,7 +8,10 @@ from collections.abc import Callable from dataclasses import fields from pathlib import Path -from typing import Any +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + import torch from ..prompt import Style from .checkpoints import ( @@ -77,7 +80,13 @@ def build_model(config: TrainConfig, model_cache: str | None = None): return model, tokenizer -def decision_loss(logits, targets, config: TrainConfig, ordinal=False, soft_targets=None): +def decision_loss( + logits, + targets, + config: TrainConfig, + ordinal: bool | torch.Tensor = False, + soft_targets=None, +): """Cross-entropy, Brier and ordinal loss over padded candidate sets. Args: @@ -400,7 +409,7 @@ def training_state() -> dict: step, value, batch.mode.value, - scheduler.get_last_lr()[0], + float(scheduler.get_last_lr()[0]), tokens=int(batch.attention_mask.sum()), ) step += 1 From 6efa5d7a0b2a4b43f017667b31911707c21e1b17 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 24/39] test(train): tighten the training-loop tests' types --- packages/lev/tests/test_training_loop.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/lev/tests/test_training_loop.py b/packages/lev/tests/test_training_loop.py index 163339c..f64b09a 100644 --- a/packages/lev/tests/test_training_loop.py +++ b/packages/lev/tests/test_training_loop.py @@ -78,7 +78,7 @@ def run_resumable( from lev.train.collate import DecisionCollator saved: list[int] = [] - seen: list[tuple[str, ...]] = [] + seen: list[tuple[object, ...]] = [] class RecordingCollator(DecisionCollator): def __call__(self, examples): @@ -295,13 +295,16 @@ def rows_through(self, monkeypatch, n_rows): def test_every_row_is_scored_exactly_once(self, monkeypatch, n_rows): rows, out = self.rows_through(monkeypatch, n_rows) assert len(out) == len(rows) - assert {e.state for e, _, _, _ in out} == {r.state for r in rows} + assert len(out) == len(rows) + assert all(any(e.state == r.state for e, _, _, _ in out) for r in rows) def test_width_matches_the_option_count_and_logits_are_trimmed(self, monkeypatch): from lev.router import Mode _, out = self.rows_through(monkeypatch, 16) for example, logits, mode, width in out: - assert width == len(example.question.criteria) + criteria = example.question.criteria + assert criteria is not None + assert width == len(criteria) assert len(logits) == width assert mode == Mode.LABEL_TOKEN.value From 594e284332cafc5887ff1fa4dfc42fc5435cf07c Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 25/39] test(packaging): drop the dead help-comment strip and share the doc scan --- packages/lev/tests/test_packaging.py | 44 +++++++++++----------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/packages/lev/tests/test_packaging.py b/packages/lev/tests/test_packaging.py index 13f14e9..b926f52 100644 --- a/packages/lev/tests/test_packaging.py +++ b/packages/lev/tests/test_packaging.py @@ -20,18 +20,24 @@ def _extras(pyproject: Path) -> set[str]: return set(data.get("project", {}).get("optional-dependencies", {})) -def _documented_extras() -> dict[str, set[str]]: - found: dict[str, set[str]] = {} +def _doc_sources() -> list[Path]: sources = [ROOT / "README.md", ROOT / "Makefile", ROOT / "CONTRIBUTING.md"] - sources += sorted((ROOT / "docs").glob("*.md")) - for src in sources: - if not src.is_file(): - continue - for name in re.findall(r"--extra[= ]([a-z][a-z0-9-]*)", src.read_text()): - found.setdefault(name, set()).add(src.name) + return [p for p in sources + sorted((ROOT / "docs").glob("*.md")) if p.is_file()] + + +def _documented_values(pattern: str) -> dict[str, set[str]]: + """Map each value `pattern` captures to the documentation files that mention it.""" + found: dict[str, set[str]] = {} + for src in _doc_sources(): + for value in re.findall(pattern, src.read_text()): + found.setdefault(value, set()).add(src.name) return found +def _documented_extras() -> dict[str, set[str]]: + return _documented_values(r"--extra[= ]([a-z][a-z0-9-]*)") + + def test_root_forwards_every_member_extra(): root = _extras(ROOT / "pyproject.toml") for member in sorted((ROOT / "packages").glob("*/pyproject.toml")): @@ -91,21 +97,10 @@ def capture(self, args=None, namespace=None): return subcommands, choices -def _documented_flag_values(flag: str) -> dict[str, set[str]]: - found: dict[str, set[str]] = {} - sources = [ROOT / "README.md", ROOT / "Makefile", ROOT / "CONTRIBUTING.md"] - sources += sorted((ROOT / "docs").glob("*.md")) - for src in sources: - if src.is_file(): - for value in re.findall(rf"{flag}[= ]([a-z][a-z0-9-]*)", src.read_text()): - found.setdefault(value, set()).add(src.name) - return found - - def test_every_documented_backend_exists(): _, choices = _inspect_cli("levbench") accepted = choices["--backend"] - for value, where in sorted(_documented_flag_values("--backend").items()): + for value, where in sorted(_documented_values(r"--backend[= ]([a-z][a-z0-9-]*)").items()): assert value in accepted, ( f"{sorted(where)} document `--backend {value}`, but the CLI accepts " f"only {sorted(accepted)}." @@ -118,16 +113,11 @@ def test_every_documented_backend_exists(): def _documented_commands(tool: str) -> dict[str, set[str]]: """Extract commands from fenced blocks and inline code, excluding prose.""" found: dict[str, set[str]] = {} - sources = [ROOT / "README.md", ROOT / "Makefile", ROOT / "CONTRIBUTING.md"] - sources += sorted((ROOT / "docs").glob("*.md")) pattern = re.compile(rf"(?:^|\s)(?:uv run )?{tool} ([a-z][a-z0-9-]*)", re.M) - for src in sources: - if not src.is_file(): - continue + for src in _doc_sources(): text = src.read_text() - # Exclude Makefile help comments from command extraction. code = ( - [re.sub(r"##.*", "", text)] + [text] if src.suffix != ".md" else [block or span for block, span in CODE_SPANS.findall(text)] ) From 3031d43dbc1465d70b1b53278b9a676f01578c50 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:47 +0530 Subject: [PATCH 26/39] docs(claude): give agents the project context --- CLAUDE.md | 71 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 208444c..e09cc73 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,34 +1,57 @@ -## Comments +# lev + +lev is an open System One decision model: `f(state, questions) → typed, calibrated distributions`, served over the same `/v1/systemone` wire format as TypeSafe's Jev, with no token generation. It is `Qwen/Qwen3.5-4B` with a rank-32 LoRA adapter, a set-attention candidate head, and per-bucket temperature calibration, released on the Hub as [`interfaze-ai/lev`](https://huggingface.co/interfaze-ai/lev). `levbench` is the harness that measures it, and Jev, on S1Bench. + +@CONTRIBUTING.md + +## Where the facts live -Keep comments rare and information-dense. +Read the relevant doc before changing anything it covers; most "obvious" improvements here were already tried and are recorded with their evidence. -- Do not add comments by default. -- Do not explain code that is already obvious from the implementation. -- Never narrate the implementation line-by-line. -- Do not add comments for simple assignments, conditionals, loops, function calls, or standard library usage. -- Prefer better naming and structure over explanatory comments. -- Comments should explain information that cannot be expressed clearly in the code. +| Doc | Holds | +| --- | --- | +| [`docs/STATUS.md`](docs/STATUS.md) | What is built, how far each part is exercised, the current headline numbers | +| [`docs/DECISIONS.md`](docs/DECISIONS.md) | ADR-001 to ADR-030; the next decision is ADR-031 | +| [`docs/FINDINGS.md`](docs/FINDINGS.md) | Every measurement and head-to-head, in order, with provenance | +| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | The design, and the trade-offs refused | +| [`docs/TRAINING.md`](docs/TRAINING.md) | The training order, presets, budgets, resume | +| [`docs/SETUP.md`](docs/SETUP.md) | Local and Modal setup, volumes, deploy knobs | +| [`hf/README.md`](hf/README.md) | The Hub model card; keep it consistent with `README.md` | -Add a comment only when it explains one of: +## The model -- non-obvious intent or rationale -- an important business rule -- an external API/protocol assumption -- a performance or security constraint -- an edge case that is easy to miss -- a workaround for a known bug or limitation +- **Readout.** Mode A reads label-token logits at the answer boundary whenever every label code is a single token — 68 options for this tokenizer, since the 69th code, `BQ`, is two. Above that, Mode B scores candidate text with the trained head. Training and serving route the same way (ADR-025, ADR-026); serving also skips split codes (ADR-028). Routing is in `router.py`. +- **Calibration** is per bucket, keyed `{type}:{mode}[:{band}]`, selected by leave-one-family-out transfer ECE. `calibrate.fit` refuses `test`, `eval` and `holdout` splits — fit only on the dedicated `calibration` split. +- **The release** (`lev-4b`) is preset `4b-instruct`, step 18750, chat prompt style. Its `lev_release.json` manifest sets the base model, prompt style and optional `adapter_scale`, and `lev.load` honours all three. +- **The released weights were trained at commit `c6ccad7`.** Changes to data, sources, prompts or the training loop after it are not in the weights until a retrain; do not attribute a benchmark move to them. -Keep implementation comments to one or two concise lines whenever possible. +## Running things -Do not write multi-paragraph comments or verbose explanatory blocks. +- **Anything that needs a GPU runs on Modal**, through `modal/app.py` and the `make` targets. Do not download checkpoints or run models locally to check something — probe the deployed endpoint or add a `modal run` function. +- **Pass `--preset 4b-instruct` to every Modal function you call directly.** Their defaults are preset `4b`, the plain base-model run, not the release; the `make` targets pass `PRESET=4b-instruct` for you. `modal deploy` likewise serves `4b` unless `LEV_SERVE_PRESET` is set, which `make deploy` does. +- `make deploy` replaces the live endpoint. `modal/app.py` must import inside the container, where `python-dotenv` is not installed — keep its import guarded, or every container crash-loops. +- Modal volumes: `lev-models` (base weights), `lev-checkpoints` (runs and `releases/`), `lev-data` (mixture and splits). -For public APIs, use docstrings/documentation when the API contract, parameters, return behavior, exceptions, or usage constraints need to be documented. +## Benchmarks -When modifying existing code: +- S1Bench is 13 subsets pinned by Bespoke Nimble manifests at commit `62076b4`, in `packages/lev/src/lev/data/s1bench_subsets/`. All 13 are banned from training (ADR-009). +- **Never select anything on S1Bench** — a hyperparameter, a scale, a prompt. Select with leave-one-family-out over the subsets, as FINDINGS §19 does, or on data outside both training and S1Bench. The `calibration` split cannot select out-of-distribution knobs: it is drawn from the training mixture. +- Compare against Jev through identical task files, one complete run each. + +## Safety + +- **Ask before any paid call**: `levbench` against Jev, the Anthropic backend, or a sweep. They bill per token. +- `levbench` never sends `TYPESAFE_API_KEY` to a `--base-url` host; a custom endpoint gets `LEVBENCH_LOCAL_API_KEY` or `local`. Keep it that way. +- Do not read `.env`. +- This repository is mirrored by hand to the public [`InterfazeAI/lev`](https://github.com/InterfazeAI/lev); the two diverge, so a change meant for release must be ported, not assumed. + +## Comments -- Preserve useful existing comments. -- Remove comments that are made obsolete by the change. -- Do not rewrite comments merely for stylistic reasons. -- Do not perform unrelated comment cleanup. +The code should explain itself; a comment exists only for what it cannot say. -Default assumption: if the code is understandable without the comment, do not write the comment. +- **One line is the unit.** A comment is one line, a docstring is one line. Multi-line is earned — a module's two or three lines of orientation, or tensor shapes and wire formats. A second paragraph on a function belongs in `docs/` with a pointer from the code. +- **Do not restate the code.** If a reader would have to check the prose against the implementation to confirm they agree, the comment costs more than it gives. +- **Compress before deleting.** A real fact buried in a block above a statement usually becomes a short trailing comment on the statement. +- **Point, do not restate.** `(ADR-028)` beats a paragraph reproducing the decision. A contract the code states plainly — a guard that raises, a named check like `_refuse_held_out` — needs no prose. +- **Public surface is the exception.** `lev.load`, the server, and the `/v1/systemone` types are consumed without reading the body; document their contracts. +- Do not rewrite comments for style. When changing code, remove comments the change made obsolete, and do no unrelated cleanup. From b8f876005ec7f10066a96d41be01d351d8cd252e Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:48 +0530 Subject: [PATCH 27/39] refactor: replace hand-counted padding with format width specifiers --- modal/app.py | 4 ++-- packages/lev/src/lev/cli.py | 4 +++- packages/lev/src/lev/train/config.py | 16 +++++++-------- packages/lev/src/lev/train/evaluate.py | 2 +- packages/levbench/src/levbench/runner.py | 24 +++++++++++----------- packages/levbench/src/levbench/snake/ui.py | 2 +- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/modal/app.py b/modal/app.py index 71e3d7e..7744e6a 100644 --- a/modal/app.py +++ b/modal/app.py @@ -336,8 +336,8 @@ def export_checkpoint(preset: str = "4b", name: str | None = None) -> dict: print( f"release {manifest['name']} -> {RELEASES_DIR}/{target} ({len(manifest['files'])} files)" ) - print(f" pull it: make weights RELEASE={target}") - print(f" publish it: make publish RELEASE={target} REPO=") + print(f" {'pull it:':<12}make weights RELEASE={target}") + print(f" {'publish it:':<12}make publish RELEASE={target} REPO=") return manifest diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 0cd616f..93b9c43 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -118,7 +118,9 @@ def cmd_data_build(args: argparse.Namespace) -> None: f"(oversample {ratio}x)" + (" <- raise --limit-per-source to lower this" if ratio > 2 else "") ) - print(f" sources {len(manifest['sources'])} ({', '.join(sorted(manifest['sources']))})") + print( + f" {'sources':<12} {len(manifest['sources'])} ({', '.join(sorted(manifest['sources']))})" + ) def cmd_data_eval(args: argparse.Namespace) -> None: diff --git a/packages/lev/src/lev/train/config.py b/packages/lev/src/lev/train/config.py index 2b41c8a..3363f59 100644 --- a/packages/lev/src/lev/train/config.py +++ b/packages/lev/src/lev/train/config.py @@ -123,18 +123,18 @@ def summary(self) -> str: prompt = f"{self.prompt_style} prompts, Mode A to the tokenizer limit" return "\n".join( [ - f"model {self.model_id} ({self.params_b}B, {self.dtype})", - f"adaptation {adaptation}", - f"prompt {prompt}", - f"data {self.n_examples:,} examples x " + f"{'model':<17}{self.model_id} ({self.params_b}B, {self.dtype})", + f"{'adaptation':<17}{adaptation}", + f"{'prompt':<17}{prompt}", + f"{'data':<17}{self.n_examples:,} examples x " f"{self.avg_tokens_per_example} tok x {self.epochs} epochs" f" = {self.total_tokens / 1e9:.2f}B tokens", - f"steps {self.total_steps:,} " + f"{'steps':<17}{self.total_steps:,} " f"({self.examples_per_step} ex/step, ~{self.tokens_per_step:,} tok/step)", - f"compute {self.total_flops:.2e} FLOPs", - f"H100 estimate {self.estimated_hours:.1f} hours " + f"{'compute':<17}{self.total_flops:.2e} FLOPs", + f"{'H100 estimate':<17}{self.estimated_hours:.1f} hours " f"({self.estimated_hours / 24:.1f} days)", - f"memory {self.optimizer_gb:.1f} GB state, " + f"{'memory':<17}{self.optimizer_gb:.1f} GB state, " f"{self.headroom_gb:.1f} GB headroom of {H100_VRAM_GB:.0f} GB", ] ) diff --git a/packages/lev/src/lev/train/evaluate.py b/packages/lev/src/lev/train/evaluate.py index f473f01..f5d7dca 100644 --- a/packages/lev/src/lev/train/evaluate.py +++ b/packages/lev/src/lev/train/evaluate.py @@ -54,7 +54,7 @@ def summary(self) -> str: weighted_accuracy = sum(s.accuracy * s.n for s in self.per_source) / total weighted_ece = sum(s.ece * s.n for s in self.per_source) / total rows.append( - f" {'WEIGHTED':<18} {'':<6} {' '} n={total:<5} " + f" {'WEIGHTED':<18} {'':<6} {'':<1} n={total:<5} " f"acc {weighted_accuracy:.3f} " f"+/-{accuracy_interval(weighted_accuracy, total):.3f} " f"ECE {weighted_ece:.4f}" diff --git a/packages/levbench/src/levbench/runner.py b/packages/levbench/src/levbench/runner.py index a96a302..b919b62 100644 --- a/packages/levbench/src/levbench/runner.py +++ b/packages/levbench/src/levbench/runner.py @@ -212,29 +212,29 @@ def _format_summary(report: EvalReport) -> list[str]: lines.append( f"{'wall time':<18} {report.wall_seconds:.1f}s ({n / report.wall_seconds:.2f} items/s)" ) - lines.append(f"calls {n}") + lines.append(f"{'calls':<18} {n}") if n: - lines.append(f"latency p50 {report.pct(0.5):.3f}s") - lines.append(f"latency mean {statistics.mean(report.latencies):.3f}s") + lines.append(f"{'latency p50':<18} {report.pct(0.5):.3f}s") + lines.append(f"{'latency mean':<18} {statistics.mean(report.latencies):.3f}s") # Report the maximum for small samples, where p95 is dominated by connection setup. if n >= 100: - lines.append(f"latency p95 {report.pct(0.95):.3f}s") + lines.append(f"{'latency p95':<18} {report.pct(0.95):.3f}s") else: lines.append( - f"latency slowest {report.latencies[-1]:.3f}s (n={n}; too few for a p95)" + f"{'latency slowest':<18} {report.latencies[-1]:.3f}s (n={n}; too few for a p95)" ) - lines.append(f"input tokens {sum(call.input_tokens for call in report.calls):,}") - lines.append(f"output tokens {sum(call.output_tokens for call in report.calls):,}") + lines.append(f"{'input tokens':<18} {sum(call.input_tokens for call in report.calls):,}") + lines.append(f"{'output tokens':<18} {sum(call.output_tokens for call in report.calls):,}") if pricing.is_self_hosted(report.model): - lines.append("total cost self-hosted (GPU time, not per-token)") + lines.append(f"{'total cost':<18} self-hosted (GPU time, not per-token)") else: - lines.append(f"total cost ${report.total_cost:.6f}") - lines.append(f"schema retries {report.total_schema_retries}") - lines.append(f"transient retries {report.total_transient_retries}") + lines.append(f"{'total cost':<18} ${report.total_cost:.6f}") + lines.append(f"{'schema retries':<18} {report.total_schema_retries}") + lines.append(f"{'transient retries':<18} {report.total_transient_retries}") served = report.served_by if served and served != {report.model} and not pricing.is_self_hosted(report.model): lines.append( - f"WARNING requested {report.model!r} but server served " + f"{'WARNING':<18} requested {report.model!r} but server served " f"{sorted(served)} -- cost figures use the requested model's price" ) lines.append("") diff --git a/packages/levbench/src/levbench/snake/ui.py b/packages/levbench/src/levbench/snake/ui.py index 741ff14..5765639 100644 --- a/packages/levbench/src/levbench/snake/ui.py +++ b/packages/levbench/src/levbench/snake/ui.py @@ -208,7 +208,7 @@ def compose(game: dict, decision: dict, stats: dict) -> Canvas: c.put(height - 2, left, "SPACE pause +/- speed R reset Q quit", MUTED) elapsed = stats.get("elapsed", 0.0) clock = f"{int(elapsed) // 60:02d}:{int(elapsed) % 60:02d}" - c.put(height - 2, right, f"ESTIMATES BY THE MODEL {clock}", MUTED) + c.put(height - 2, right, f"{'ESTIMATES BY THE MODEL':<29}{clock}", MUTED) return c From 7dfdd05256b5a06529a9fece40c0a13b6cec1ec2 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:48 +0530 Subject: [PATCH 28/39] fix(levbench): align the jev-vs-llm comparison columns --- packages/levbench/src/levbench/cli.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/levbench/src/levbench/cli.py b/packages/levbench/src/levbench/cli.py index 4dee4d6..264ba99 100644 --- a/packages/levbench/src/levbench/cli.py +++ b/packages/levbench/src/levbench/cli.py @@ -104,15 +104,18 @@ def cmd_compare(args: argparse.Namespace) -> None: cost_ratio = llm.total_cost / jev.total_cost if jev.total_cost else 0.0 speed_ratio = llm.pct(0.5) / jev.pct(0.5) if jev.pct(0.5) else 0.0 print( - f"cost jev ${jev.total_cost:.6f} vs llm ${llm.total_cost:.6f}" + f"{'cost':<18} jev ${jev.total_cost:.6f} vs llm ${llm.total_cost:.6f}" f" ({cost_ratio:.1f}x cheaper)" ) print( - f"p50 jev {jev.pct(0.5):.3f}s vs llm {llm.pct(0.5):.3f}s ({speed_ratio:.1f}x faster)" + f"{'p50':<18} jev {jev.pct(0.5):.3f}s vs llm {llm.pct(0.5):.3f}s" + f" ({speed_ratio:.1f}x faster)" ) - print(f"schema retries jev {jev.total_schema_retries} vs llm {llm.total_schema_retries}") print( - f"transient retries jev {jev.total_transient_retries}" + f"{'schema retries':<18} jev {jev.total_schema_retries} vs llm {llm.total_schema_retries}" + ) + print( + f"{'transient retries':<18} jev {jev.total_transient_retries}" f" vs llm {llm.total_transient_retries}" ) From a107f63f2ccf896f1d6055bc126fa3816f124cb3 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:48 +0530 Subject: [PATCH 29/39] fix(levbench): take the jev model from the sdk default --- packages/levbench/src/levbench/cli.py | 8 +++-- packages/levbench/src/levbench/pricing.py | 9 +++--- packages/levbench/src/levbench/runner.py | 8 +++-- packages/levbench/tests/fake_transport.py | 9 +++++- packages/levbench/tests/test_offline.py | 39 ++++++++++++++++------- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/packages/levbench/src/levbench/cli.py b/packages/levbench/src/levbench/cli.py index 264ba99..e7522b1 100644 --- a/packages/levbench/src/levbench/cli.py +++ b/packages/levbench/src/levbench/cli.py @@ -184,11 +184,15 @@ def cmd_confidence(args: argparse.Namespace) -> None: client, model = runner.build_client("jev", args.model, args.base_url) answers: list = [] + served: set[str] = set() for item in items: - answers.extend(runner.call_once(client, item.state, questions).answers.values()) + result = runner.call_once(client, item.state, questions) + answers.extend(result.answers.values()) + served.add(result.served_by) samples = confidence_id.collect(answers) - print(f"model: {model} answers with a distribution: {len(samples)}\n") + shown = ", ".join(sorted(served)) or model + print(f"model: {shown} answers with a distribution: {len(samples)}\n") print(confidence_id.format_fits(confidence_id.identify(samples))) diff --git a/packages/levbench/src/levbench/pricing.py b/packages/levbench/src/levbench/pricing.py index 1d341c6..6a97304 100644 --- a/packages/levbench/src/levbench/pricing.py +++ b/packages/levbench/src/levbench/pricing.py @@ -11,9 +11,10 @@ class Price: output_per_mtok: float +# Every Jev version bills at the published Jev rate unless PRICES names it. +JEV = Price(0.042, 0.0) + PRICES: dict[str, Price] = { - "jev-latest": Price(0.042, 0.0), - "jev-1.13": Price(0.042, 0.0), "claude-opus-5": Price(5.00, 25.00), "claude-sonnet-5": Price(2.00, 10.00), "claude-haiku-4-5": Price(1.00, 5.00), @@ -21,7 +22,7 @@ class Price: } -# Unknown jev names use jev-latest rates; other unknown models have zero token cost. +# Unknown non-Jev models are self-hosted and have zero token cost. SELF_HOSTED = Price(0.0, 0.0) @@ -33,7 +34,7 @@ def lookup(model: str) -> Price: if model in PRICES: return PRICES[model] if model.startswith("jev"): - return PRICES["jev-latest"] + return JEV return SELF_HOSTED diff --git a/packages/levbench/src/levbench/runner.py b/packages/levbench/src/levbench/runner.py index b919b62..f4507c1 100644 --- a/packages/levbench/src/levbench/runner.py +++ b/packages/levbench/src/levbench/runner.py @@ -69,6 +69,8 @@ def served_by(self) -> set[str]: DEFAULT_LOCAL_BASE_URL = "http://localhost:8000" +# Label for Jev runs left on the SDK's default model; reports name the version served instead. +JEV_DEFAULT = "jev" # Modal's 4B cold start measured 20-55 s, against the SDK's 10 s default (ADR-022). @@ -87,8 +89,8 @@ def build_client( base_url = base_url or DEFAULT_LOCAL_BASE_URL from typesafe_sdk import TypeSafeClient - resolved = model or ("jev-latest" if backend == "jev" else "local") - kwargs: dict[str, Any] = {"model": resolved} + resolved = model or (JEV_DEFAULT if backend == "jev" else "local") + kwargs: dict[str, Any] = {"model": None if resolved == JEV_DEFAULT else resolved} if timeout is not None: kwargs["timeout"] = timeout elif backend == "lev": @@ -191,7 +193,7 @@ def run_eval( ) served = report.served_by - if backend == "lev" and len(served) == 1: + if (backend == "lev" or model == JEV_DEFAULT) and len(served) == 1: # The label was a placeholder; the server knows what it loaded. report.model = served.pop() diff --git a/packages/levbench/tests/fake_transport.py b/packages/levbench/tests/fake_transport.py index 6882ab7..7a204db 100644 --- a/packages/levbench/tests/fake_transport.py +++ b/packages/levbench/tests/fake_transport.py @@ -6,6 +6,9 @@ import json import httpx2 +from typesafe_sdk import constants + +JEV_VERSION = "jev-1.13.0" def _rand(*parts: str) -> float: @@ -53,6 +56,10 @@ def handler(request: httpx2.Request) -> httpx2.Response: state_text = state if isinstance(state, str) else json.dumps(state, sort_keys=True) state_sig = hashlib.sha256(state_text.encode()).hexdigest()[:16] + requested = body.get("model") + # Like the hosted API, serve a concrete version when asked for the SDK's default alias. + served = JEV_VERSION if requested in (None, constants.DEFAULT_MODEL) else requested + questions = body["questions"] answers = {k: _answer(k, q, state_sig) for k, q in questions.items()} @@ -63,7 +70,7 @@ def handler(request: httpx2.Request) -> httpx2.Response: return httpx2.Response( 200, json={ - "model": body.get("model", "jev-latest"), + "model": served, "answers": answers, "usage": {"input_tokens": input_tokens, "output_tokens": output_tokens}, }, diff --git a/packages/levbench/tests/test_offline.py b/packages/levbench/tests/test_offline.py index cb01ac4..fb35dc0 100644 --- a/packages/levbench/tests/test_offline.py +++ b/packages/levbench/tests/test_offline.py @@ -12,7 +12,7 @@ import httpx2 import pytest -from fake_transport import transport +from fake_transport import JEV_VERSION, transport from levbench import batching, confidence_id, metrics, runner from levbench.pricing import cost_usd from levbench.tasks import FileItem, dataset, detectable_difference, load_task_file @@ -87,7 +87,7 @@ def system_one(self, state, questions): def test_eval_runs_end_to_end_over_the_built_in_fixture() -> None: items, questions = dataset() - report = runner.run_eval(fake_client(), "jev", "jev-latest", items, questions) + report = runner.run_eval(fake_client(), "jev", runner.JEV_DEFAULT, items, questions) assert len(report.calls) == len(items) assert set(report.per_question) == set(questions) assert report.total_cost > 0 @@ -98,7 +98,7 @@ def test_eval_runs_end_to_end_over_the_built_in_fixture() -> None: def test_sweep_arithmetic_over_a_fixed_billing_shape() -> None: """Synthetic billing verifies sweep arithmetic; live billing requires a live sweep.""" state = (ROOT / "data" / "sample_policy.md").read_text() - rows = batching.sweep(fake_client(), "jev-latest", state, [1, 2, 4, 8, 13]) + rows = batching.sweep(fake_client(), runner.JEV_DEFAULT, state, [1, 2, 4, 8, 13]) assert rows[0].cost_ratio == pytest.approx(1.0, abs=0.01, rel=0), ( "at N=1 batched and split are the same call; ratio must be ~1" @@ -108,18 +108,18 @@ def test_sweep_arithmetic_over_a_fixed_billing_shape() -> None: assert rows[-1].cost_ratio > 5, ( f"at N=13 expected a large saving, got {rows[-1].cost_ratio:.1f}x" ) - assert "batching sweep" in batching.format_sweep(rows, "jev-latest", len(state)) + assert "batching sweep" in batching.format_sweep(rows, runner.JEV_DEFAULT, len(state)) @pytest.mark.parametrize("count", [0, -1]) def test_sweep_rejects_non_positive_question_counts(count) -> None: with pytest.raises(ValueError, match="must be positive"): - batching.sweep(None, "jev-latest", "state", [count]) + batching.sweep(None, runner.JEV_DEFAULT, "state", [count]) def test_sweep_respects_an_explicitly_empty_bank() -> None: with pytest.raises(ValueError, match="bank holds 0"): - batching.sweep(None, "jev-latest", "state", [1], bank=[]) + batching.sweep(None, runner.JEV_DEFAULT, "state", [1], bank=[]) @pytest.mark.parametrize("planted", confidence_id.CANDIDATES) @@ -193,11 +193,26 @@ def test_local_base_url_never_forwards_the_real_key(monkeypatch) -> None: assert "REAL-SECRET" not in str(local._config.api_key), "leaked the real key" assert local._config.api_key == "local" - hosted, _ = runner.build_client("jev", "jev-latest") + hosted, _ = runner.build_client("jev") assert isinstance(hosted, TypeSafeClient) assert hosted._config.api_key == "sk-REAL-SECRET-KEY", "hosted path lost its key" +def test_an_unpinned_jev_client_takes_the_sdk_default(monkeypatch) -> None: + monkeypatch.setenv("TYPESAFE_API_KEY", "sk-test") + monkeypatch.setenv("TYPESAFE_DEFAULT_MODEL", "jev-1.12") + client, label = runner.build_client("jev") + assert label == runner.JEV_DEFAULT + assert client._config.default_model == "jev-1.12" + + +def test_an_unpinned_jev_run_reports_the_version_served() -> None: + items, questions = dataset() + report = runner.run_eval(fake_client(), "jev", runner.JEV_DEFAULT, items, questions) + assert report.model == JEV_VERSION + assert "WARNING" not in runner.format_report(report) + + def test_empty_local_key_env_var_falls_back(monkeypatch) -> None: """An empty key produces an invalid Bearer header; use the local fallback.""" monkeypatch.setenv("LEVBENCH_LOCAL_API_KEY", "") @@ -235,7 +250,7 @@ def test_eval_runs_over_a_generated_task_file(tmp_path, question_type) -> None: """Exercise the task-file format produced by `lev data eval` for every primitive.""" items, questions = dataset(_write_task_file(tmp_path / "gen.json", question_type)) assert questions["q"].type == question_type - report = runner.run_eval(fake_client(), "jev", "jev-latest", items, questions) + report = runner.run_eval(fake_client(), "jev", runner.JEV_DEFAULT, items, questions) assert len(report.calls) == 5 assert set(report.per_question) == {"q"} assert report.per_question["q"] is not None @@ -361,7 +376,7 @@ def system_one(self, state, questions): class TestCostAccounting: def test_cost_is_per_million_tokens_at_list_price(self) -> None: - assert cost_usd("jev-latest", 1_000_000, 0) == pytest.approx(0.042) + assert cost_usd(JEV_VERSION, 1_000_000, 0) == pytest.approx(0.042) assert cost_usd("claude-opus-5", 1_000_000, 1_000_000) == pytest.approx(30.0) assert cost_usd("Qwen/Qwen3.5-4B", 1_000_000, 1_000_000) == 0.0, "self-hosted is unmetered" @@ -378,8 +393,8 @@ def test_missing_token_counts_raise_rather_than_count_as_free(self) -> None: def test_a_substituted_model_is_flagged_in_the_report(self) -> None: """Report model substitution because pricing uses the requested model.""" - report = runner.EvalReport(backend="jev", model="jev-latest") - report.calls.append(runner.CallResult({}, 0.3, "jev-1.13.0", 10, 1)) - assert "requested 'jev-latest' but server served ['jev-1.13.0']" in runner.format_report( + report = runner.EvalReport(backend="jev", model="jev-1.12") + report.calls.append(runner.CallResult({}, 0.3, JEV_VERSION, 10, 1)) + assert "requested 'jev-1.12' but server served ['jev-1.13.0']" in runner.format_report( report ) From 32bb003701e195b9d12d70ed3c3b86a928d9ef5e Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 09:17:49 +0530 Subject: [PATCH 30/39] docs: move internal docstrings to why-comments, keep public api docs --- docs/charts/build.py | 3 --- modal/app.py | 22 ++++------------ packages/lev/src/lev/batcher.py | 2 -- packages/lev/src/lev/calibrate.py | 8 ------ packages/lev/src/lev/cli.py | 1 - packages/lev/src/lev/data/build.py | 2 -- packages/lev/src/lev/data/contamination.py | 3 --- packages/lev/src/lev/data/export_eval.py | 2 -- packages/lev/src/lev/data/mixture.py | 4 +-- packages/lev/src/lev/data/s1bench.py | 8 ------ packages/lev/src/lev/data/sources.py | 21 ++++----------- packages/lev/src/lev/data/splits.py | 3 +-- packages/lev/src/lev/labels.py | 2 -- packages/lev/src/lev/metrics.py | 2 +- packages/lev/src/lev/model.py | 26 +++++++------------ packages/lev/src/lev/presentation.py | 9 ------- packages/lev/src/lev/prompt.py | 19 +++++--------- packages/lev/src/lev/readout/mode_b.py | 1 - packages/lev/src/lev/release.py | 3 --- packages/lev/src/lev/server.py | 1 - packages/lev/src/lev/train/calibration_run.py | 5 ---- packages/lev/src/lev/train/checkpoints.py | 10 +++---- packages/lev/src/lev/train/collate.py | 12 ++------- packages/lev/src/lev/train/evaluate.py | 6 +---- packages/lev/src/lev/train/loop.py | 23 ++++------------ packages/lev/src/lev/train/progress.py | 3 +-- packages/lev/tests/conftest.py | 13 ++++------ packages/lev/tests/test_adapter_scale.py | 1 - packages/lev/tests/test_batcher.py | 13 +++------- packages/lev/tests/test_cache_fork.py | 4 +-- packages/lev/tests/test_calibration.py | 3 +-- packages/lev/tests/test_collate.py | 4 +-- packages/lev/tests/test_contamination.py | 2 +- packages/lev/tests/test_core.py | 10 +++---- packages/lev/tests/test_data_pipeline.py | 21 +++++++-------- packages/lev/tests/test_engine_forward.py | 5 ++-- packages/lev/tests/test_eval_export.py | 5 ++-- packages/lev/tests/test_evaluate.py | 2 +- packages/lev/tests/test_loss.py | 2 +- packages/lev/tests/test_packaging.py | 3 --- packages/lev/tests/test_presentation.py | 15 +++++------ packages/lev/tests/test_progress.py | 7 +++-- packages/lev/tests/test_release.py | 3 +-- packages/lev/tests/test_s1bench.py | 4 +-- packages/lev/tests/test_training_loop.py | 17 +++++------- packages/levbench/src/levbench/batching.py | 1 - packages/levbench/src/levbench/cli.py | 2 -- .../levbench/src/levbench/confidence_id.py | 11 +------- packages/levbench/src/levbench/metrics.py | 10 +++---- packages/levbench/src/levbench/runner.py | 4 +-- .../levbench/src/levbench/snake/policy.py | 1 - packages/levbench/src/levbench/snake/ui.py | 4 +-- packages/levbench/src/levbench/tasks.py | 2 +- packages/levbench/tests/test_offline.py | 21 +++++---------- packages/levbench/tests/test_snake.py | 5 ++-- 55 files changed, 110 insertions(+), 286 deletions(-) diff --git a/docs/charts/build.py b/docs/charts/build.py index bee494b..78d68a2 100644 --- a/docs/charts/build.py +++ b/docs/charts/build.py @@ -30,7 +30,6 @@ def pct(v: float) -> str: def bar_path(x0: float, x1: float, y: float, h: float, r: float = 4) -> str: - """Square at the baseline, 4px rounded at the data end.""" if x1 - x0 <= 0.5: return "" r = min(r, (x1 - x0) / 2, h / 2) @@ -62,7 +61,6 @@ def table(headers, rows) -> str: def leaderboard(rows, vmin=0.2, vmax=0.8) -> str: - """Ranked horizontal bars. Rows: dicts with name, value, var, meta, bold.""" label_w, meta_w, row_h, bar_h, top = 196, 150, 23, 13, 6 plot_w = W - label_w - meta_w - 40 x = lambda v: label_w + (v - vmin) / (vmax - vmin) * plot_w # noqa: E731 @@ -275,7 +273,6 @@ def mean(scores, key, subsets=SUBSETS): def majority_rate(subset: str) -> float: - """Accuracy of always answering the most common label.""" labels = definition(subset)["labels"] return max(labels.values()) / sum(labels.values()) diff --git a/modal/app.py b/modal/app.py index 7744e6a..f25bad0 100644 --- a/modal/app.py +++ b/modal/app.py @@ -309,9 +309,9 @@ def serve(): ) +# Default entrypoint: print the budget without spending it. @app.local_entrypoint() def main(preset: str = "4b", dry_run: bool = True): - """Default entrypoint: print the budget without spending it.""" result = train.remote(preset=preset, dry_run=dry_run) print(result) @@ -394,6 +394,8 @@ def check_release(name: str = "4b") -> dict: return {"health": health, "response": served} +# `split` is in-distribution and favours full strength, so the scale is chosen by +# leave-one-family-out over S1Bench (FINDINGS §19). `scales` only reports; it never selects. @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=4 * 60 * 60) def fit_at_adapter_scale( name: str = "lev", @@ -404,18 +406,6 @@ def fit_at_adapter_scale( search_rows: int = 6000, apply: bool = False, ) -> dict: - """Refit the temperature profile with the adapter scaled to `scale`. - - Shrinking the adapter trades in-distribution accuracy for out-of-distribution - robustness, so `split` cannot choose the scale: it is drawn from the training - mixture, and accuracy there rises monotonically to scale 1.0 (0.6233 at 0.125, - 0.8133 at 1.0). The scale is chosen instead by leave-one-family-out over S1Bench, - which holds each family out of its own selection; that put it at 0.25 for 6 of 7 - families. Temperatures still belong on `split`, which is what this fits. - - Passing `scales` sweeps them on `search_rows` rows and reports in-distribution - sensitivity, without selecting. `apply` writes the scale and profile into the release. - """ import json import random @@ -503,8 +493,8 @@ def collect(scale: float, rows): return out +# Mirrors levbench's label rule so a sweep is comparable with a `levbench eval` run. def _predicted_label(answer): - """levbench's label rule, so a sweep is comparable with a `levbench eval` run.""" if answer.type == "noul": return float(answer.noul) >= 0.5 if answer.type == "choice": @@ -512,13 +502,13 @@ def _predicted_label(answer): return max(answer.probabilities.items(), key=lambda kv: kv[1])[0] +# Scale zero is the frozen-backbone control. @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=2 * 60 * 60) def diagnose_ordinal( name: str = "lev", scales: str = "0,0.25,0.5,0.75,1.0", subsets: str = "summeval-consistency,summeval-relevance,helpsteer2", ) -> dict: - """Sweep adapter scales on rating tasks; use scale zero as the frozen-backbone control.""" import collections import json @@ -562,7 +552,6 @@ def diagnose_ordinal( @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def diagnose_candidates(model_id: str = "Qwen/Qwen3.5-4B-Base") -> dict: - """Compare candidate embeddings alone, batched, reversed, and left-padded.""" import torch from transformers import AutoModelForCausalLM, AutoTokenizer @@ -666,7 +655,6 @@ def _probabilities(answer: Answer) -> dict[Any, float]: @app.function(gpu="H100", volumes=VOLUMES, secrets=SECRETS, timeout=30 * 60) def profile_engine(preset: str = "4b", rounds: int = 20) -> dict: - """Time CUDA-synchronized engine stages after warmup, excluding network time.""" import statistics import time diff --git a/packages/lev/src/lev/batcher.py b/packages/lev/src/lev/batcher.py index 5c2c207..c8eb954 100644 --- a/packages/lev/src/lev/batcher.py +++ b/packages/lev/src/lev/batcher.py @@ -174,8 +174,6 @@ def _fill(self, batch: list[_Job]) -> None: rows, width = grown_rows, grown_width def _take(self, block: bool) -> _Job | None: - """Return the next request worth computing.""" - while True: if self._held is not None: job, self._held = self._held, None diff --git a/packages/lev/src/lev/calibrate.py b/packages/lev/src/lev/calibrate.py index 3d8074a..5b85e20 100644 --- a/packages/lev/src/lev/calibrate.py +++ b/packages/lev/src/lev/calibrate.py @@ -83,8 +83,6 @@ def fit_temperature( def family_weights(families: Sequence[str]) -> list[float]: - """Give each family equal total weight.""" - counts = Counter(families) return [1.0 / counts[family] for family in families] @@ -101,8 +99,6 @@ def leave_one_family_out_ece( families: Sequence[str], method: str, ) -> float: - """Measure transfer ECE by holding out each family once.""" - eces = [] for held_out in sorted(set(families)): @@ -131,8 +127,6 @@ def fit_for_transfer( split_name: str, min_samples: int = 50, ) -> tuple[CalibrationProfile, dict[str, dict]]: - """Choose the row- or family-weighted fit that transfers better per bucket.""" - _refuse_held_out(split_name) profile = CalibrationProfile(fitted_on=f"{split_name} (transfer-selected)") @@ -288,8 +282,6 @@ def fit( split_name: str, min_samples: int = 50, ) -> CalibrationProfile: - """Fit one temperature per sufficiently large bucket.""" - _refuse_held_out(split_name) profile = CalibrationProfile(fitted_on=split_name) diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index 93b9c43..f420054 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -247,7 +247,6 @@ def _weights_dtype(engine) -> str | None: def cmd_presentation_checks(args: argparse.Namespace) -> None: - """Run presentation checks; exit 2 for settings mismatches and 1 for failed checks.""" import time from . import presentation diff --git a/packages/lev/src/lev/data/build.py b/packages/lev/src/lev/data/build.py index 2612786..f742175 100644 --- a/packages/lev/src/lev/data/build.py +++ b/packages/lev/src/lev/data/build.py @@ -74,7 +74,6 @@ def read_jsonl(path: Path) -> list[Example]: def verify_round_trip(path: Path, sample: int = 1000) -> int: - """Check sampled rows round-trip exactly, including option order; return the count.""" rows = read_jsonl(path) step = max(1, len(rows) // sample) with path.open(encoding="utf-8") as handle: @@ -104,7 +103,6 @@ def build_dataset( cache_dir: str | None = None, loader: Callable | None = None, ) -> dict: - """Write each split's JSONL and the manifest to `out_dir`; return the manifest.""" out = Path(out_dir) out.mkdir(parents=True, exist_ok=True) weights = sources or default_weights() diff --git a/packages/lev/src/lev/data/contamination.py b/packages/lev/src/lev/data/contamination.py index f49236a..6e9e09b 100644 --- a/packages/lev/src/lev/data/contamination.py +++ b/packages/lev/src/lev/data/contamination.py @@ -70,7 +70,6 @@ class ContaminationError(RuntimeError): def normalise(name: str) -> str: - """Canonicalise a dataset name for lookup.""" cleaned = name.strip().lower() cleaned = re.sub(r"[\s_]+", "-", cleaned) return re.sub(r":(train|validation|dev|test)$", "", cleaned) @@ -87,7 +86,6 @@ def normalise(name: str) -> str: def resolve(name: str) -> str | None: - """Map a dataset name to the blocked subset it belongs to, if any.""" normalised = normalise(name) if normalised in _BLOCKED_BY_NORMALISED: @@ -118,7 +116,6 @@ def check_mixture(dataset_names: Iterable[str]) -> dict[str, str]: def assert_eval_only(dataset_name: str) -> str: - """Resolve an evaluation subset or raise ContaminationError.""" subset = resolve(dataset_name) if subset is None: raise ContaminationError( diff --git a/packages/lev/src/lev/data/export_eval.py b/packages/lev/src/lev/data/export_eval.py index a8fc3af..1cc15f0 100644 --- a/packages/lev/src/lev/data/export_eval.py +++ b/packages/lev/src/lev/data/export_eval.py @@ -15,7 +15,6 @@ def truth_for(question: Question, target: int) -> bool | int | str: - """Convert a target to a Choice key, Score index, or Noul bool.""" if isinstance(question, Noul): # The target is a rating index; collapse it as the readout does. return noul_probability({target: 1.0}) >= 0.5 @@ -30,7 +29,6 @@ def export( split: Split = Split.TEST, limit_per_source: int | None = None, ) -> dict: - """Write `.json` per source, plus an `index.json` describing them.""" out = Path(out_dir) out.mkdir(parents=True, exist_ok=True) diff --git a/packages/lev/src/lev/data/mixture.py b/packages/lev/src/lev/data/mixture.py index a985fda..a97655c 100644 --- a/packages/lev/src/lev/data/mixture.py +++ b/packages/lev/src/lev/data/mixture.py @@ -26,10 +26,9 @@ class Example: soft_target: list[float] | None = None +# Negated wordings flip the Noul target. @dataclass(frozen=True) class Augment: - """Per-source wording and option variation; negations flip Noul targets.""" - paraphrases: tuple[str, ...] = () negations: tuple[str, ...] = () min_options: int = 2 @@ -67,7 +66,6 @@ def validate(self) -> None: def build_mixture(spec: MixtureSpec, loaders: Mapping[str, Loader]) -> Iterator[Example]: - """Sample examples from validated sources using the configured weights and augmentations.""" spec.validate() missing = set(spec.sources) - set(loaders) if missing: diff --git a/packages/lev/src/lev/data/s1bench.py b/packages/lev/src/lev/data/s1bench.py index e81ee79..e4e77ed 100644 --- a/packages/lev/src/lev/data/s1bench.py +++ b/packages/lev/src/lev/data/s1bench.py @@ -24,8 +24,6 @@ @dataclass(frozen=True) class EvalItem: - """An evaluation record with a Choice key, Score index, or Noul bool as truth.""" - id: str state: dict | str truth: bool | int | str @@ -33,8 +31,6 @@ class EvalItem: @dataclass(frozen=True) class EvalSubset: - """A subset with published Jev 1.13 and measured s1-fast scores.""" - name: str hf_id: str jev_published: float @@ -66,12 +62,10 @@ def subset_names() -> list[str]: def get_subset(name: str) -> EvalSubset: - """Resolve a subset by name or alias. Raises unless it is S1Bench evaluation data.""" return EVAL_SUBSETS[assert_eval_only(name)] def definition(name: str) -> dict: - """The vendored definition: `instructions`, `criteria`, `ids`, `labels`, provenance.""" return json.loads((SUBSET_DIR / f"{name}.json").read_text(encoding="utf-8")) @@ -254,7 +248,6 @@ def _read_pubmedqa() -> Iterator[EvalItem]: def load_eval_subset(name: str) -> tuple[Question, list[EvalItem]]: - """Load a S1Bench subset, validating its records against pinned ids and labels.""" subset = get_subset(name) spec = definition(subset.name) by_id = {item.id: item for item in _READERS[subset.name]()} @@ -273,7 +266,6 @@ def load_eval_subset(name: str) -> tuple[Question, list[EvalItem]]: def export(out_dir: str | Path, subsets: list[str] | None = None) -> dict: - """Write `.json` levbench task files, plus an `index.json`.""" out = Path(out_dir) out.mkdir(parents=True, exist_ok=True) diff --git a/packages/lev/src/lev/data/sources.py b/packages/lev/src/lev/data/sources.py index 25b0606..982ae7a 100644 --- a/packages/lev/src/lev/data/sources.py +++ b/packages/lev/src/lev/data/sources.py @@ -34,8 +34,6 @@ @dataclass(frozen=True) class SourceSpec: - """A dataset and its question, label mapping and optional row reader.""" - name: str hf_id: str primitive: Primitive @@ -67,11 +65,10 @@ def _read_race(row: dict, rng: random.Random) -> ChoiceRow | None: return {"passage": row["article"], "question": row["question"]}, options, index +# Includes ARC's numeric choice labels, not only letters. def _read_keyed_choices( question_field: str, context_field: str | None = None ) -> Callable[[dict, random.Random], ChoiceRow | None]: - """Match answerKey to choice labels, including numeric ARC labels.""" - def reader(row: dict, rng: random.Random) -> ChoiceRow | None: labels = [str(x) for x in row["choices"]["label"]] texts = [str(x) for x in row["choices"]["text"]] @@ -119,7 +116,6 @@ def _read_nli(row: dict, rng: random.Random) -> Row | None: def swap_two_words(text: str, rng: random.Random) -> str | None: - """Swap distinct content words, or return None if no pair is found in eight draws.""" words = text.split() slots = [i for i, w in enumerate(words) if len(w) > 3 and w.isalpha()] if len(slots) < 2: @@ -136,8 +132,6 @@ def swap_two_words(text: str, rng: random.Random) -> str | None: def _read_pair( first: str, second: str, adversarial: float = 0.0 ) -> Callable[[dict, random.Random], list[PairRow]]: - """Read sentence pairs, optionally adding word-swapped negatives to positive rows.""" - def reader(row: dict, rng: random.Random) -> list[PairRow]: a, b = row[first], row[second] label = int(row["label"]) @@ -179,8 +173,6 @@ def _read_strategyqa(row: dict, rng: random.Random) -> PairRow: def yes_no_from_choices(reader: Reader) -> Callable[[dict, random.Random], list[PairRow] | None]: - """Turn each multiple-choice row into two Noul rows: gold and wrong proposals.""" - def wrapped(row: dict, rng: random.Random) -> list[PairRow] | None: produced = reader(row, rng) if produced is None: @@ -610,7 +602,6 @@ def _read_snips(row: dict, rng: random.Random) -> Row | None: def family_of(source: str) -> str: - """Return the adjacent-source family used for calibration transfer (ADR-028).""" for group in ADJACENT: if source in group: return "+".join(sorted(group)) @@ -618,20 +609,19 @@ def family_of(source: str) -> str: def adjacency_map() -> dict[str, frozenset[str]]: - """Map sources to those excluded as abstain donors.""" return { name: frozenset().union(*(group for group in ADJACENT if name in group)) - {name} for name in REGISTRY } +# Rating 1 would mean P(yes)=0.125, so binary labels map to ratings 0 and 8. def _noul_rating(label: int) -> int: - """Map binary labels to ratings 0 and 8; rating 1 would mean P(yes)=0.125.""" return 0 if int(label) == 0 else len(NOUL_RATING_TOKENS) - 1 +# Leave names such as Sci/Tech intact. def humanise(label: str) -> str: - """Expand snake_case and camelCase labels; leave names such as Sci/Tech intact.""" spaced = re.sub(r"(?<=[a-z])(?=[A-Z])", " ", label) return re.sub(r"[_\-]+", " ", spaced).strip() @@ -665,6 +655,7 @@ def build_question(spec: SourceSpec, names: list[str]) -> Question: ) +# Shuffle before the limit: corpora often ship sorted by label, so a head slice can hold one class. def load_source( spec: SourceSpec, limit: int | None = None, @@ -673,7 +664,6 @@ def load_source( seed: int = 17, load_dataset: Callable | None = None, ) -> Iterator[Example]: - """Yield examples through an injectable loader, shuffling before applying the limit.""" if load_dataset is None: from datasets import load_dataset @@ -746,8 +736,8 @@ def _blank(state) -> bool: LARGE_SET_MIN_OPTIONS = 15 +# Large taxonomies keep their full option set half the time (ADR-026). def augmentation_map() -> dict[str, Augment]: - """Configure option variation; large taxonomies retain full sets half the time (ADR-026).""" return { name: Augment( paraphrases=spec.paraphrases, @@ -760,7 +750,6 @@ def augmentation_map() -> dict[str, Augment]: def default_weights() -> dict[str, float]: - """Reserve MODE_B_SHARE for large taxonomies; balance the remainder across primitives.""" mode_b_sources = sorted(MODE_B_SOURCES) sources_by_primitive: dict[str, list[str]] = {} for name, spec in REGISTRY.items(): diff --git a/packages/lev/src/lev/data/splits.py b/packages/lev/src/lev/data/splits.py index 2d09c2a..0bfa500 100644 --- a/packages/lev/src/lev/data/splits.py +++ b/packages/lev/src/lev/data/splits.py @@ -32,8 +32,8 @@ def row_key(source: str, index: int, text: str) -> str: return f"{source}|{index}|{text[:512]}" +# Python's hash() is salted per process; splits must stay stable across runs. def hash_position(key: str, salt: str = SPLIT_SALT) -> float: - """Map a key to a process-stable float in [0, 1).""" digest = hashlib.blake2b(f"{salt}|{key}".encode(), digest_size=8).digest() return int.from_bytes(digest, "big") / float(1 << 64) @@ -84,7 +84,6 @@ def split_examples( def check_coverage(splits: dict[Split, list[Example]], strict: bool = True) -> SplitReport: - """Check observed labels appear in train and offered labels appear in the data.""" seen: dict[str, set[int]] = defaultdict(set) in_train: dict[str, set[int]] = defaultdict(set) offered: dict[str, int] = {} diff --git a/packages/lev/src/lev/labels.py b/packages/lev/src/lev/labels.py index 8439649..eed2bdb 100644 --- a/packages/lev/src/lev/labels.py +++ b/packages/lev/src/lev/labels.py @@ -27,7 +27,6 @@ def label_codes(n: int) -> list[str]: def single_token_codes( tokenizer, n: int, prefix: str = " ", skip_multi_token: bool = False ) -> list[str] | None: - """Find n single-token codes using the prompt boundary prefix; optionally skip split codes.""" if not skip_multi_token: try: codes = label_codes(n) @@ -60,6 +59,5 @@ def _is_single_token(tokenizer, text: str) -> bool: def noul_probability(level_probs: dict[int, float]) -> float: - """Collapse a 9-level rating distribution to p(yes) = sum(i/8 * p_i).""" top = len(NOUL_RATING_TOKENS) - 1 return sum((level / top) * p for level, p in level_probs.items()) diff --git a/packages/lev/src/lev/metrics.py b/packages/lev/src/lev/metrics.py index 3a43203..b48bfe7 100644 --- a/packages/lev/src/lev/metrics.py +++ b/packages/lev/src/lev/metrics.py @@ -6,8 +6,8 @@ from collections.abc import Sequence +# Multiclass Brier: squared error summed over the whole vector. def brier(probs: Sequence[float], truth: int) -> float: - """Multiclass Brier score: summed squared error over the whole vector.""" return sum((p - (1.0 if i == truth else 0.0)) ** 2 for i, p in enumerate(probs)) diff --git a/packages/lev/src/lev/model.py b/packages/lev/src/lev/model.py index 145e4a2..39602d0 100644 --- a/packages/lev/src/lev/model.py +++ b/packages/lev/src/lev/model.py @@ -62,8 +62,8 @@ class EngineConfig: pad_to: int = 32 +# Rounding up to a multiple gives graph capture a stable set of shapes. def bucket(n: int, multiple: int) -> int: - """`n` rounded up to a multiple; a stable set of shapes for graph capture.""" return max(multiple, ((n + multiple - 1) // multiple) * multiple) @@ -73,8 +73,6 @@ def pow2(n: int) -> int: @dataclass(frozen=True) class Variant: - """One rendering of one question: the candidate order shown, and its suffix.""" - name: str order: list[int] | None suffix_ids: list[int] @@ -82,8 +80,6 @@ class Variant: @dataclass(frozen=True) class Prepared: - """One request validated, routed and tokenised, ready to share a forward.""" - questions: dict[str, Question] routes: dict[str, Route] prefix_ids: list[int] @@ -102,8 +98,8 @@ def want_hidden(self) -> bool: return any(r.mode is Mode.CANDIDATE_PATH for r in self.routes.values()) +# Average probabilities, not logits. def average_orders(prob_rows: list[list[float]], orders: list[list[int] | None]) -> list[float]: - """Restore canonical candidate order and average probabilities, not logits.""" if len(prob_rows) != len(orders): raise ValueError("one order per probability row") k = len(prob_rows[0]) @@ -114,10 +110,10 @@ def average_orders(prob_rows: list[list[float]], orders: list[list[int] | None]) return [t / len(prob_rows) for t in total] +# Shared with `lev route`, so its preview matches serving. def serving_routes( questions: dict[str, Question], tokenizer, config: EngineConfig ) -> dict[str, Route]: - """Resolve the serving routes, also exposed by `lev route`.""" return route_all( questions, tokenizer, @@ -288,8 +284,8 @@ def _respond(self, request: Prepared, logits, hidden) -> SystemOneResponse: ), ) + # Score levels stay canonical unless Score averaging is enabled (ADR-029). def _orders(self, question: Question, route: Route) -> list[list[int] | None]: - """Choose candidate orders; keep scales canonical unless Score averaging is enabled.""" if ( not self.config.order_average or route.mode is not Mode.LABEL_TOKEN @@ -344,8 +340,8 @@ def _render( for name, order, r in rendered ] + # Last-token logits (N, V) and optional hidden states (N, H), in request order. def _forward(self, requests: list[Prepared]): - """Return last-token logits (N, V) and optional hidden states (N, H) in request order.""" import torch want_hidden = any(r.want_hidden for r in requests) @@ -364,7 +360,6 @@ def _forward(self, requests: list[Prepared]): return logits, hidden def _forward_single(self, rows: list[list[int]], want_hidden: bool): - """Run right-padded prefix/suffix rows, using shape buckets when compiled.""" import torch device = self._device @@ -386,7 +381,6 @@ def _forward_single(self, rows: list[list[int]], want_hidden: bool): return self._project(states, last_positions, want_hidden) def _forward_forked(self, prefix_ids: list[int], suffixes: list[list[int]], want_hidden: bool): - """Prefill the prefix once, then run all suffixes against forked caches.""" import torch device = self._device @@ -417,15 +411,14 @@ def _forward_forked(self, prefix_ids: list[int], suffixes: list[list[int]], want return self._project(states, [len(s) - 1 for s in suffixes], want_hidden) def _project(self, states, last_positions: list[int], want_hidden: bool): - """Gather each row's last real token and project only those to the vocabulary.""" import torch rows = torch.arange(states.size(0), device=states.device) last = states[rows, torch.tensor(last_positions, device=states.device)] # (N, H) return self._lm_head(last), (last if want_hidden else None) + # `logits` is (V,); `hidden` is (H,) or None. def _scores(self, logits, hidden, route: Route, question: Question) -> list[float]: - """Scores for one variant row: `logits` is `(V,)`, `hidden` `(H,)` or None.""" if route.mode is Mode.LABEL_TOKEN: return self._label_token_scores(logits, route) return self._candidate_path_scores(hidden, question) @@ -458,8 +451,8 @@ def _candidate_path_scores(self, hidden, question: Question) -> list[float]: ) return scores[0].float().tolist() + # Unbounded cache: meant for fixed schemas, whose candidate set does not grow. def _candidate_reprs(self, texts: list[str]): - """Cache candidate embeddings without a size bound; intended for fixed schemas.""" import torch key = tuple(texts) @@ -622,8 +615,8 @@ def load( return engine +# Scale before any merge, which bakes the current scale into the weights. def _set_adapter_scale(model, scale: float) -> None: - """Scale every LoRA layer relative to its trained strength, before any merge bakes it in.""" from peft.tuners.lora import LoraLayer layers = [m for m in model.modules() if isinstance(m, LoraLayer)] @@ -635,7 +628,6 @@ def _set_adapter_scale(model, scale: float) -> None: def _load_head(path: Path, model): - """Load the saved Mode B head, or return None for Mode A-only serving.""" import torch from .readout.mode_b import CandidatePathReadout @@ -651,8 +643,8 @@ def _load_head(path: Path, model): return head.to(device=next(model.parameters()).device, dtype=torch.float32).eval() +# Binary Noul calibration is kept separate from the trained rating scale. def _bucket_type(question: Question, route: Route) -> str: - """Keep binary Noul calibration separate from the trained rating scale.""" return "noul_binary" if route.reason == BINARY_NOUL else question.type diff --git a/packages/lev/src/lev/presentation.py b/packages/lev/src/lev/presentation.py index 34b9020..b033e96 100644 --- a/packages/lev/src/lev/presentation.py +++ b/packages/lev/src/lev/presentation.py @@ -65,7 +65,6 @@ def identical_questions(kind: str, text: str, k: int, instructions: str) -> dict[str, dict]: - """The identical-option questions of one configuration, keyed by key assignment.""" if kind == "score": return {"": {"type": "score", "instructions": instructions, "criteria": [text] * k}} return { @@ -79,7 +78,6 @@ def identical_questions(kind: str, text: str, k: int, instructions: str) -> dict def probe_questions(lang: str = "en", kinds: Sequence[str] = KINDS) -> dict[str, dict]: - """Build identical-option and permutation probes with structured question ids.""" questions: dict[str, dict] = {} for kind in kinds: spec = TEXT[lang][kind] @@ -105,7 +103,6 @@ def is_identical(qid: str) -> bool: @contextmanager def configured(engine, **changes) -> Generator[None, None, None]: - """Run the block with `engine.config` changed as given, then restore it.""" config = engine.config engine.config = replace(config, **changes) try: @@ -119,7 +116,6 @@ def single_order(engine): def call_groups(engine, questions: dict[str, dict], max_rows: int) -> list[dict[str, dict]]: - """Group questions into calls within the engine's rendered-row budget.""" rows = engine.question_rows(questions) groups: list[dict[str, dict]] = [] current: dict[str, dict] = {} @@ -142,7 +138,6 @@ def ask( kinds: Sequence[str] = KINDS, max_rows: int | None = None, ) -> list[dict[str, Any]]: - """Run single-order identical probes and configured permutation probes within max_rows.""" max_rows = max_rows or MAX_ROWS questions = probe_questions(lang, kinds) identical = {q: v for q, v in questions.items() if is_identical(q)} @@ -165,7 +160,6 @@ def ask( def slot_probs(answer: Any, question: dict) -> list[float]: - """An answer's probabilities in the order the options were shown.""" probs = answer.probabilities if question["type"] == "score": return [float(probs[i]) for i in range(len(question["criteria"]))] @@ -193,7 +187,6 @@ def report( kinds: Sequence[str] = KINDS, slot0_min: float = SLOT0_MIN, ) -> dict[str, dict]: - """Both checks for each kind from `ask`'s answers.""" questions = probe_questions(lang, kinds) out: dict[str, dict] = {} for kind in kinds: @@ -255,7 +248,6 @@ def packed_consistency( lang: str = "en", kinds: Sequence[str] = KINDS, ) -> float: - """Return the largest probability difference between packed and individual probes.""" questions = probe_questions(lang, kinds) worst = 0.0 for state, packed in zip(states, answers, strict=False): @@ -282,7 +274,6 @@ def settings_mismatch(saved: dict, run: dict, keys: Sequence[str] = SETTINGS) -> def drift(report: dict, snapshot: dict, tolerance: float) -> list[str]: - """Every metric that moved more than `tolerance` from the committed report.""" moved = [] for kind, checks in snapshot.items(): for check, committed in checks.items(): diff --git a/packages/lev/src/lev/prompt.py b/packages/lev/src/lev/prompt.py index 6e03c0e..e7aba43 100644 --- a/packages/lev/src/lev/prompt.py +++ b/packages/lev/src/lev/prompt.py @@ -18,15 +18,13 @@ class Layout(StrEnum): SCHEMA_FIRST = "schema_first" +# The prompt format must match training (ADR-027). class Style(StrEnum): - """Plain or ChatML prompts; the format must match training (ADR-027).""" - PLAIN = "plain" CHAT = "chat" def label_prefix(style: Style) -> str: - """Use a space after plain Answer: and no prefix at the start of a chat answer.""" return " " if style is Style.PLAIN else "" @@ -43,10 +41,9 @@ def label_prefix(style: Style) -> str: } +# The prefix is reusable and the suffix varies; the suffix's final token is the one scored. @dataclass(frozen=True) class Rendered: - """Reusable prefix and varying suffix; score the suffix's final token.""" - prefix: str suffix: str @@ -69,6 +66,7 @@ def _ordered(items: list, order: list[int] | None) -> list: return items if order is None else [items[i] for i in order] +# Two Noul codes select the binary readout. def render_question( name: str, question: Question, @@ -76,7 +74,6 @@ def render_question( order: list[int] | None = None, style: Style = Style.PLAIN, ) -> str: - """Render positional label codes or Mode B text; two Noul codes select binary readout.""" if style is Style.CHAT: return _render_question_chat(name, question, codes, order) lines = [f"Question: {question.instructions or name}"] @@ -119,7 +116,6 @@ def render_question( def _render_question_chat( name: str, question: Question, codes: list[str] | None, order: list[int] | None ) -> str: - """Render ChatML criterion and option sections with positional codes.""" lines = [f"# Criterion\n{question.instructions or name}\n"] if isinstance(question, Choice): @@ -164,13 +160,13 @@ def _render_question_chat( return "\n".join(lines) +# Sorted object keys keep the rendering deterministic. def render_content(value: JSONContent) -> str: - """Render JSON content deterministically, sorting object keys.""" return value if isinstance(value, str) else json.dumps(value, sort_keys=True) +# Shared by Mode B serving and training, so both see the same candidate text. def candidate_texts(question: Question) -> list[str]: - """Candidate text shared by the Mode B serving and training paths.""" if isinstance(question, Noul): return list(NOUL_RATING_TOKENS) if isinstance(question, Score): @@ -188,7 +184,6 @@ def build( order: list[int] | None = None, style: Style = Style.PLAIN, ) -> Rendered: - """Render one question against one state, cut for the chosen layout.""" if style is Style.CHAT: return _build_chat(state, name, question, codes, layout, cached_schema, order) state_block = f"Context:\n{render_state(state)}\n\n" @@ -202,8 +197,8 @@ def build( return Rendered(prefix=prefix, suffix=f"{state_block}{ANSWER_CUE}") +# Score the boundary after the empty think block. def _build_chat(state, name, question, codes, layout, cached_schema, order) -> Rendered: - """Render ChatML evidence and criterion; score the boundary after the empty think block.""" head = f"<|im_start|>system\n{CHAT_SYSTEM_PROMPT}<|im_end|>\n<|im_start|>user\n" evidence = f"# Evidence\n{render_state(state)}\n\n" criterion = render_question(name, question, codes, order, Style.CHAT) @@ -213,12 +208,12 @@ def _build_chat(state, name, question, codes, layout, cached_schema, order) -> R return Rendered(prefix=f"{head}{catalogue}\n\n", suffix=f"{evidence.rstrip()}\n{CHAT_TAIL}") +# The full question catalogue, so schema-first caching can share it across states. def schema_block( questions: Mapping[str, Question], codes: Mapping[str, list[str] | None], style: Style = Style.PLAIN, ) -> str: - """The full question catalogue, for schema-first caching across states.""" return "\n\n".join( render_question(n, q, codes.get(n), style=style) for n, q in questions.items() ) diff --git a/packages/lev/src/lev/readout/mode_b.py b/packages/lev/src/lev/readout/mode_b.py index 54410ef..46429d5 100644 --- a/packages/lev/src/lev/readout/mode_b.py +++ b/packages/lev/src/lev/readout/mode_b.py @@ -39,7 +39,6 @@ def forward( def ordinal_penalty(scores: torch.Tensor, target_level: torch.Tensor) -> torch.Tensor: - """Expected squared distance from the true level under the predicted distribution.""" n_levels = scores.size(-1) levels = torch.arange(n_levels, device=scores.device, dtype=scores.dtype) distance = (levels.unsqueeze(0) - target_level.unsqueeze(1).to(scores.dtype)) ** 2 diff --git a/packages/lev/src/lev/release.py b/packages/lev/src/lev/release.py index e57d53e..dfbdcd8 100644 --- a/packages/lev/src/lev/release.py +++ b/packages/lev/src/lev/release.py @@ -23,7 +23,6 @@ def build_release( metrics: dict | None = None, prompt_style: str = "plain", ) -> dict: - """Package a checkpoint; default to parent calibration, otherwise serve raw softmax.""" step_dir = resolve_checkpoint(checkpoint) target = Path(out) target.mkdir(parents=True, exist_ok=True) @@ -63,7 +62,6 @@ def build_release( def model_card(manifest: dict) -> str: - """Build Hub metadata and usage instructions for a release.""" metrics = manifest.get("metrics") or {} metric_lines = "\n".join(f"| {k} | {v} |" for k, v in metrics.items()) or "| — | not recorded |" calibration = ( @@ -127,7 +125,6 @@ def model_card(manifest: dict) -> str: def publish(release_dir: str | Path, repo_id: str, *, private: bool = False) -> str: - """Upload a release using HF authentication; create the repo if needed and return its URL.""" from huggingface_hub import HfApi folder = Path(release_dir) diff --git a/packages/lev/src/lev/server.py b/packages/lev/src/lev/server.py index 08236f3..807ea02 100644 --- a/packages/lev/src/lev/server.py +++ b/packages/lev/src/lev/server.py @@ -111,7 +111,6 @@ async def system_one(body: SystemOneRequest, request: Request) -> Any: async def _disconnected(request: Request) -> None: - """Wait for an ASGI disconnect; if none is reported, wait without polling.""" if (await request.receive())["type"] == "http.disconnect": return await asyncio.Event().wait() diff --git a/packages/lev/src/lev/train/calibration_run.py b/packages/lev/src/lev/train/calibration_run.py index 79a5137..43b5233 100644 --- a/packages/lev/src/lev/train/calibration_run.py +++ b/packages/lev/src/lev/train/calibration_run.py @@ -19,9 +19,6 @@ def fit_profile( config=None, method: str = "transfer", ) -> dict: - """Fit bucket temperatures on calibration data; optionally select by family transfer. - - Save transfer comparisons and preserve the previous profile before replacing it.""" rows = collect_logits(checkpoint_dir, data_dir, split, config=config) out = Path(checkpoint_dir) / CALIBRATION if out.is_file(): @@ -68,8 +65,6 @@ def collect_logits( batch_size: int = 16, limit: int | None = None, ) -> dict[str, list[tuple[list[float], int, str]]]: - """Collect raw logits and task families by calibration bucket, skipping abstain rows.""" - from ..data.build import load_split from ..data.sources import family_of from ..data.splits import Split diff --git a/packages/lev/src/lev/train/checkpoints.py b/packages/lev/src/lev/train/checkpoints.py index 6325b77..fe1be76 100644 --- a/packages/lev/src/lev/train/checkpoints.py +++ b/packages/lev/src/lev/train/checkpoints.py @@ -10,8 +10,8 @@ CALIBRATION = "calibration.json" +# Highest step number, not newest mtime. def latest_checkpoint(output: str | Path) -> Path | None: - """Return the highest numbered step with adapter weights, regardless of mtime.""" source = Path(output) steps = sorted( (d for d in source.glob("step-*") if (d / ADAPTER_WEIGHTS).is_file()), @@ -21,7 +21,6 @@ def latest_checkpoint(output: str | Path) -> Path | None: def fetch_checkpoint(spec: str | Path, cache_dir: str | None = None) -> Path: - """Use an existing local path or download a Hub id; report ambiguous missing paths clearly.""" local = Path(spec) if local.exists(): return local @@ -40,7 +39,6 @@ def fetch_checkpoint(spec: str | Path, cache_dir: str | None = None) -> Path: def resolve_checkpoint(path: str | Path, cache_dir: str | None = None) -> Path: - """Resolve a step directory, training output, flat release, or Hub id.""" source = fetch_checkpoint(path, cache_dir) if (source / ADAPTER_WEIGHTS).is_file(): return source @@ -54,7 +52,6 @@ def resolve_checkpoint(path: str | Path, cache_dir: str | None = None) -> Path: def load_training_state(path: str | Path) -> dict | None: - """Load resume state, or return None for a weights-only checkpoint.""" import torch file = resolve_checkpoint(path) / TRAINING_STATE @@ -64,8 +61,9 @@ def load_training_state(path: str | Path) -> dict | None: return torch.load(file, map_location="cpu", weights_only=True) +# Restores in place so the optimizer keeps valid parameter references; head mismatches are +# rejected. def load_checkpoint(model, head, path: str | Path) -> None: - """Restore weights in place to preserve optimizer references; reject head mismatches.""" import torch from peft import set_peft_model_state_dict from safetensors.torch import load_file @@ -91,6 +89,7 @@ def load_checkpoint(model, head, path: str | Path) -> None: ) +# An interrupted save may leave the checkpoint incomplete. def save_checkpoint( model, head, @@ -100,7 +99,6 @@ def save_checkpoint( on_checkpoint=None, state: dict | None = None, ) -> Path: - """Write weights, tokenizer, and optional resume state; interrupted saves may be incomplete.""" import torch path = output / f"step-{step}" diff --git a/packages/lev/src/lev/train/collate.py b/packages/lev/src/lev/train/collate.py index cf103bd..b04fe6b 100644 --- a/packages/lev/src/lev/train/collate.py +++ b/packages/lev/src/lev/train/collate.py @@ -18,9 +18,8 @@ IGNORE_INDEX = -100 +# Shared by the batcher and collator so each example is tokenised once. class RouteCache: - """Cache routes shared by the batcher and collator to avoid repeated tokenization.""" - def __init__(self, tokenizer, max_label_options: int | None = None, style: Style = Style.PLAIN): self.tokenizer = tokenizer self.max_label_options = max_label_options @@ -42,8 +41,6 @@ def route_for(self, example: Example) -> Route: @dataclass class Batch: - """A training batch with one readout mode.""" - mode: Mode input_ids: Tensor # (B, T) attention_mask: Tensor # (B, T) @@ -78,8 +75,6 @@ def render(example: Example, codes: list[str] | None, style: Style = Style.PLAIN class ModeBatcher: - """Group by mode, sort within length windows, and shuffle batches without dropping examples.""" - def __init__( self, tokenizer, @@ -99,9 +94,9 @@ def __init__( def route_for(self, example: Example) -> Route: return self.routes.route_for(example) + # Character count stands in for length, to avoid tokenising twice. @staticmethod def length_of(example: Example) -> int: - """Use character count as a length proxy to avoid tokenizing twice.""" return len(str(example.state)) def __call__(self, examples: Iterable[Example], epoch: int = 0) -> Iterator[list[Example]]: @@ -131,8 +126,6 @@ def __call__(self, examples: Iterable[Example], epoch: int = 0) -> Iterator[list class DecisionCollator: - """Collate rows sharing one readout mode.""" - def __init__( self, tokenizer, @@ -231,7 +224,6 @@ def _label_token_ids(self, routes, k_max: int): return ids def _attach_candidate_pool(self, batch: Batch, examples: list[Example], k_max: int) -> None: - """Encode each distinct candidate string once and index into the pool.""" import torch pool: dict[str, int] = {} diff --git a/packages/lev/src/lev/train/evaluate.py b/packages/lev/src/lev/train/evaluate.py index f5d7dca..482ec94 100644 --- a/packages/lev/src/lev/train/evaluate.py +++ b/packages/lev/src/lev/train/evaluate.py @@ -11,7 +11,6 @@ def accuracy_interval(accuracy: float, n: int, z: float = 1.96) -> float: - """Normal-approximation confidence interval half-width; 95% at the default z.""" if n <= 0: return 1.0 return min(1.0, z * math.sqrt(max(accuracy * (1 - accuracy), 1e-9) / n)) @@ -69,14 +68,12 @@ def summary(self) -> str: def score( raw_logits: Sequence[tuple[list[float], int]], temperature: float ) -> tuple[float, float, float, float]: - """Accuracy, ECE, mean Brier and mean log loss at one temperature.""" return score_mixed([(logits, truth, temperature) for logits, truth in raw_logits]) def score_mixed( rows: Sequence[tuple[list[float], int, float]], ) -> tuple[float, float, float, float]: - """`score` for rows that each carry their own temperature.""" probs = [softmax(logits, t) for logits, _, t in rows] truths = [truth for _, truth, _ in rows] correct = sum( @@ -90,6 +87,7 @@ def score_mixed( ) +# Raw and calibrated reports share the stored logits, so they differ only in temperature. def evaluate_split( checkpoint_dir: str, data_dir: str, @@ -99,8 +97,6 @@ def evaluate_split( limit_per_source: int | None = None, batch_size: int = 16, ) -> tuple[EvalReport, EvalReport]: - """Return raw and calibrated reports from the same stored logits.""" - from ..data.build import load_split from ..data.splits import Split from .checkpoints import resolve_checkpoint diff --git a/packages/lev/src/lev/train/loop.py b/packages/lev/src/lev/train/loop.py index 5abbd38..bcb9678 100644 --- a/packages/lev/src/lev/train/loop.py +++ b/packages/lev/src/lev/train/loop.py @@ -29,7 +29,6 @@ def build_model(config: TrainConfig, model_cache: str | None = None): - """Load the tokenizer and backbone, wrapped in LoRA when `config.use_lora`.""" import torch from peft import LoraConfig, get_peft_model from transformers import AutoModelForCausalLM, AutoTokenizer @@ -80,6 +79,8 @@ def build_model(config: TrainConfig, model_cache: str | None = None): return model, tokenizer +# logits (B, K), -inf at padded slots; targets (B,) gold indices, IGNORE_INDEX for abstain rows; +# ordinal (B,) bool or a scalar bool; soft_targets (B, K) distributions for abstain rows. def decision_loss( logits, targets, @@ -87,14 +88,6 @@ def decision_loss( ordinal: bool | torch.Tensor = False, soft_targets=None, ): - """Cross-entropy, Brier and ordinal loss over padded candidate sets. - - Args: - logits: `(B, K)`, with `-inf` at padded slots. - targets: `(B,)` gold indices; `IGNORE_INDEX` for abstain rows. - ordinal: `(B,)` bool for ordered targets, or a scalar bool. - soft_targets: `(B, K)` distributions for abstain rows. - """ import torch import torch.nn.functional as F @@ -126,8 +119,8 @@ def decision_loss( return loss +# (B, K) scores: label logits in Mode A, pooled candidate embeddings in Mode B. def candidate_logits(model, batch, head=None): - """Compute (B, K) scores using label logits or pooled candidate embeddings.""" import torch from ..router import Mode @@ -173,8 +166,8 @@ def candidate_logits(model, batch, head=None): return logits.float().masked_fill(batch.candidate_mask.to(logits.device), float("-inf")) +# The head stays fp32 beside the bf16 backbone. def build_head(config: TrainConfig, model=None): - """The Mode B matching head, in fp32 beside the bf16 backbone.""" import torch from ..readout.mode_b import CandidatePathReadout @@ -189,7 +182,6 @@ def build_head(config: TrainConfig, model=None): def load_for_eval(config: TrainConfig, checkpoint_dir, model_cache: str | None = None): - """Build the model and head, restore a checkpoint into them, and put both in eval mode.""" model, tokenizer = build_model(config, model_cache) head = build_head(config, model) if config.train_mode_b_head else None load_checkpoint(model, head, checkpoint_dir) @@ -200,7 +192,6 @@ def load_for_eval(config: TrainConfig, checkpoint_dir, model_cache: str | None = def scored_rows(model, tokenizer, head, config: TrainConfig, rows, batch_size): - """Yield `(example, logits, mode, width)` per row, batched as training batches.""" import torch routes = RouteCache(tokenizer, config.max_label_options, Style(config.prompt_style)) @@ -232,8 +223,8 @@ def to_device(batch, device): return batch +# Validate before loading the model, so bad data fails fast. def prepare_data(config: TrainConfig, data_dir: str): - """Validate data and contamination before loading the model.""" from ..data.build import MANIFEST, load_split from ..data.splits import Split @@ -269,9 +260,6 @@ def run_training( max_steps: int | None = None, fresh: bool = False, ) -> dict: - """Train with periodic checkpoints; auto-resume the newest step unless fresh=True. - - Resume optimizer, schedule, and data order when saved; otherwise restore weights only.""" import torch from torch.optim import AdamW from transformers import get_cosine_schedule_with_warmup @@ -445,7 +433,6 @@ def training_state() -> dict: def set_aside_previous_run(output: Path) -> Path | None: - """Move previous run artifacts into a timestamped directory, or return None if empty.""" stale = list(output.glob("step-*")) + [ output / name for name in (HISTORY, CALIBRATION) if (output / name).exists() ] diff --git a/packages/lev/src/lev/train/progress.py b/packages/lev/src/lev/train/progress.py index 8277e2c..fc0e612 100644 --- a/packages/lev/src/lev/train/progress.py +++ b/packages/lev/src/lev/train/progress.py @@ -5,9 +5,8 @@ import time +# Throughput counts real tokens, not padding. class ProgressLog: - """Flush periodic per-mode losses and throughput measured from real tokens.""" - def __init__(self, total_steps: int, log_every: int): self.total = total_steps self.every = max(1, log_every) diff --git a/packages/lev/tests/conftest.py b/packages/lev/tests/conftest.py index 834b950..8fcb061 100644 --- a/packages/lev/tests/conftest.py +++ b/packages/lev/tests/conftest.py @@ -10,8 +10,6 @@ class FakeTokenizer: - """Control which strings encode as a single token.""" - def __init__(self, single_tokens: set[str]): self.single_tokens = single_tokens @@ -22,17 +20,17 @@ def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: return [1] * (len(text) + 1) +# Space-prefixed A-Z and 0-8 are single tokens. Two-letter codes are not. @pytest.fixture def rich_tokenizer() -> FakeTokenizer: - """Space-prefixed A-Z and 0-8 are single tokens. Two-letter codes are not.""" from string import ascii_uppercase return FakeTokenizer({f" {c}" for c in ascii_uppercase} | {f" {i}" for i in range(9)}) +# Bare A-Z and 0-8 are single tokens too -- what follows an assistant turn. @pytest.fixture def chat_tokenizer() -> FakeTokenizer: - """Bare A-Z and 0-8 are single tokens too -- what follows an assistant turn.""" from string import ascii_uppercase letters = set(ascii_uppercase) | {f" {c}" for c in ascii_uppercase} @@ -40,15 +38,14 @@ def chat_tokenizer() -> FakeTokenizer: return FakeTokenizer(letters | digits) +# Only the first four letters are single tokens, which forces Mode B quickly. @pytest.fixture def poor_tokenizer() -> FakeTokenizer: - """Only the first four letters are single tokens — forces Mode B quickly.""" return FakeTokenizer({" A", " B", " C", " D"} | {f" {i}" for i in range(9)}) +# One id per character, to expose padding and last-token errors. class BatchingTokenizer(FakeTokenizer): - """Encode one id per character to expose padding and last-token errors.""" - pad_token_id = 0 padding_side = "right" @@ -88,9 +85,9 @@ def batching_tokenizer() -> BatchingTokenizer: return BatchingTokenizer({f" {c}" for c in ascii_uppercase} | {f" {i}" for i in range(9)}) +# A throwaway copy of the smoke preset, safe for a test to mutate. @pytest.fixture def train_config(): - """A throwaway copy of the smoke preset, safe for a test to mutate.""" from dataclasses import replace return replace(PRESETS["smoke"]) diff --git a/packages/lev/tests/test_adapter_scale.py b/packages/lev/tests/test_adapter_scale.py index ca08469..6b9a6d6 100644 --- a/packages/lev/tests/test_adapter_scale.py +++ b/packages/lev/tests/test_adapter_scale.py @@ -33,7 +33,6 @@ def tiny_base(): def merged_delta(scale: float | None): - """Weight the merge adds to `TARGET`, with the adapter scaled by `scale` first.""" base = tiny_base() before = base.get_submodule(TARGET).weight.detach().clone() diff --git a/packages/lev/tests/test_batcher.py b/packages/lev/tests/test_batcher.py index de8a811..0206737 100644 --- a/packages/lev/tests/test_batcher.py +++ b/packages/lev/tests/test_batcher.py @@ -14,9 +14,8 @@ def request(name: str, rows: int = 1, width: int = 10): return SimpleNamespace(name=name, rows=rows, width=width) +# Holds the first forward so later requests queue behind it. class GatedEngine: - """Hold the first forward so later requests queue behind it.""" - def __init__(self): self.forwards: list[list[str]] = [] self.started = threading.Event() @@ -33,7 +32,6 @@ def answer(self, requests): async def submit_while_busy(batcher, engine, first, queued): - """Occupy the worker with `first` and queue `queued` behind it.""" head = asyncio.ensure_future(batcher.submit(first)) while not engine.started.is_set(): await asyncio.sleep(0.001) @@ -148,9 +146,8 @@ async def run(): assert after == "answer to c", "the worker survives a failed forward" +# Every forward waits for one `step()`, so a test controls when each runs. class SteppedEngine: - """Every forward waits for one `step()`, so a test controls when each runs.""" - def __init__(self, fail_with: BaseException | None = None, short_by: int = 0): self.forwards: list[list[str]] = [] self.calls = 0 @@ -228,9 +225,8 @@ async def run(): assert asyncio.run(run()).forwards == [["a"], ["b"]] +# Disconnecting does not release GPU capacity already in use. def test_an_abandoned_running_request_still_counts_as_pending(): - """Disconnecting does not release GPU capacity already in use.""" - async def run(): engine = SteppedEngine() batcher = Batcher(engine) @@ -264,9 +260,8 @@ async def run(): assert asyncio.run(run()) == "answer to a" +# A short response list trips zip(strict=True) outside the forward's error handling. def test_an_error_outside_the_forward_fails_its_batch_and_the_worker_keeps_serving(): - """A short response list triggers zip(strict=True) outside forward error handling.""" - async def run(): engine = SteppedEngine(short_by=1) batcher = Batcher(engine) diff --git a/packages/lev/tests/test_cache_fork.py b/packages/lev/tests/test_cache_fork.py index 999c64a..efa1a6f 100644 --- a/packages/lev/tests/test_cache_fork.py +++ b/packages/lev/tests/test_cache_fork.py @@ -12,8 +12,8 @@ BATCH, HEADS, SEQ, DIM = 1, 2, 5, 4 +# Shaped like Qwen3.5's cache: full-attention and linear layers mixed. def hybrid_cache(): - """A cache shaped like Qwen3.5's: full-attention and linear layers mixed.""" full = cache_utils.DynamicLayer() full.update(torch.randn(BATCH, HEADS, SEQ, DIM), torch.randn(BATCH, HEADS, SEQ, DIM)) @@ -62,8 +62,8 @@ def test_fork_does_not_mutate_the_source(): assert torch.equal(original.layers[1].conv_states[0], before_conv) +# Hybrid caches do not support batch_repeat_interleave. def test_the_old_approach_still_fails(): - """Hybrid caches do not support batch_repeat_interleave.""" linear = cache_utils.LinearAttentionLayer() assert not hasattr(linear, "batch_repeat_interleave"), ( "LinearAttentionLayer now implements batch_repeat_interleave; " diff --git a/packages/lev/tests/test_calibration.py b/packages/lev/tests/test_calibration.py index 197a085..b79a80b 100644 --- a/packages/lev/tests/test_calibration.py +++ b/packages/lev/tests/test_calibration.py @@ -17,7 +17,6 @@ def overconfident_samples(n: int = 600, seed: int = 7, sharpness: float = 4.0): - """Generate roughly 70% accuracy at 96% confidence.""" rng = random.Random(seed) samples = [] for _ in range(n): @@ -137,8 +136,8 @@ def test_banded_temperature_falls_back_to_the_unbanded_bucket(self): class TestTransferSelectedCalibration: + # Large easy families outnumber a small hard family at equal confidence. def family_rows(self): - """Large easy families outnumber a small hard family at equal confidence.""" rows = [] for fam, n, acc in ( ("easy1", 400, 0.97), diff --git a/packages/lev/tests/test_collate.py b/packages/lev/tests/test_collate.py index cc3912f..8ed1296 100644 --- a/packages/lev/tests/test_collate.py +++ b/packages/lev/tests/test_collate.py @@ -19,8 +19,8 @@ class TestCollator: def collator(self, batching_tokenizer): return DecisionCollator(batching_tokenizer, max_seq_len=512) + # Right padding makes seq - 1 point at a pad token. def test_last_position_is_the_final_real_token_not_seq_minus_one(self, collator): - """Right padding makes seq - 1 point to a pad token.""" batch = collator( [an_example(a_choice(), state="short"), an_example(a_choice(), state="x" * 200)] ) @@ -117,8 +117,6 @@ def test_batcher_and_collator_can_share_one_route_cache(self, batching_tokenizer class TestLengthBucketing: - """Test padding savings without global length ordering.""" - def rows(self, n=512): rng = random.Random(0) # Bimodal, like the real mixture: short intents and long reviews. diff --git a/packages/lev/tests/test_contamination.py b/packages/lev/tests/test_contamination.py index 6c3185b..8e56a60 100644 --- a/packages/lev/tests/test_contamination.py +++ b/packages/lev/tests/test_contamination.py @@ -72,8 +72,8 @@ def test_aliases_and_variants_resolve(self, alias, expected): def test_innocent_datasets_pass(self, innocent): assert resolve(innocent) is None + # Includes subsets absent from the completed runs. def test_subsets_that_did_not_run_are_blocked_too(self): - """All evaluation subsets are blocked, including those absent from completed runs.""" unrun = [ "massive-de-DE", "squad2", diff --git a/packages/lev/tests/test_core.py b/packages/lev/tests/test_core.py index 08c9afa..ebc042c 100644 --- a/packages/lev/tests/test_core.py +++ b/packages/lev/tests/test_core.py @@ -34,8 +34,8 @@ from lev.types import Choice, Noul, Score +# Every space-prefixed letter and letter pair is one token, except `missing`. def two_letter_tokenizer(missing: str | None = None) -> FakeTokenizer: - """Every space-prefixed letter and letter pair is one token, except `missing`.""" pairs = {f" {a}{b}" for a in ascii_uppercase for b in ascii_uppercase} if missing is not None: pairs.discard(f" {missing}") @@ -267,8 +267,8 @@ def test_binary_noul_is_read_both_ways(self, rich_tokenizer): [1, 0], ] + # Training presents ordered levels from low to high. def test_score_keeps_its_level_order(self, rich_tokenizer): - """Training presents ordered levels from low to high.""" assert self.orders(Score(criteria=["low", "mid", "high"]), rich_tokenizer) == [None] def test_rating_noul_keeps_its_scale(self, rich_tokenizer): @@ -381,7 +381,6 @@ def test_route_uses_mode_a_past_the_split_only_when_asked(self): class TestRoutePreviewMatchesServing: def preview(self, tokenizer, request, tmp_path, monkeypatch, capsys) -> str: - """Run the route CLI with an injected tokenizer.""" from lev.cli import main stub = types.ModuleType("transformers") @@ -431,16 +430,15 @@ def test_a_dict_question_is_parsed_and_routed(self, rich_tokenizer): with pytest.raises(RuntimeError, match="need Mode B"): engine.system_one("state", questions) + # The server maps ValueError to HTTP 422. def test_a_malformed_dict_is_a_value_error(self, rich_tokenizer): - """The server maps ValueError to HTTP 422.""" engine = self.engine(rich_tokenizer) with pytest.raises(ValueError, match="at least 2 options"): engine.system_one("state", {"pick": {"type": "choice", "criteria": {"a": None}}}) +# Concurrent access to a fast tokenizer can corrupt settings or raise Already borrowed. class TestTokenizerIsUsedOneCallAtATime: - """Concurrent access to a fast tokenizer can corrupt settings or raise Already borrowed.""" - class OverlapDetector: def __init__(self, inner): self.inner = inner diff --git a/packages/lev/tests/test_data_pipeline.py b/packages/lev/tests/test_data_pipeline.py index 88576e1..86573af 100644 --- a/packages/lev/tests/test_data_pipeline.py +++ b/packages/lev/tests/test_data_pipeline.py @@ -53,8 +53,8 @@ def select(self, indices): return FakeDataset([self.rows[i] for i in indices], self.features) +# Grouped by label, which is how most real corpora ship. def label_sorted_loader(n_labels: int, per_label: int, text_field="text", label_field="label"): - """A corpus grouped by label -- which is how most of the real ones ship.""" rows = [ {text_field: f"row {label}-{i}", label_field: label} for label in range(n_labels) @@ -120,8 +120,8 @@ def test_choice_options_are_humanised(self): class TestSampling: + # A head slice of a label-sorted corpus may contain only one class. def test_limit_samples_rather_than_truncates(self): - """A head slice of a label-sorted corpus may contain only one class.""" spec = REGISTRY["dbpedia_14"] loader = label_sorted_loader(14, 100, text_field="content") rows = list(load_source(spec, limit=140, load_dataset=loader)) @@ -133,8 +133,8 @@ def test_sampling_is_reproducible(self): b = [e.state for e in load_source(REGISTRY["dbpedia_14"], 50, load_dataset=loader)] assert a == b + # A binary label of 1 must become rating 8, not P(yes) = 0.125. def test_noul_labels_land_on_the_ends_of_the_rating_scale(self): - """A binary label of 1 must become rating 8, not P(yes) = 0.125.""" loader = label_sorted_loader(2, 20) rows = list(load_source(REGISTRY["imdb"], load_dataset=loader)) assert {e.target for e in rows} == {0, len(NOUL_RATING_TOKENS) - 1} @@ -155,8 +155,8 @@ def test_unnamed_label_feature_raises_rather_than_guessing(self): list(load_source(REGISTRY["ag_news"], load_dataset=loader)) +# The state names its own source, so donor tests can trace it. def traceable_example(source, target, index, n_options=4): - """One row whose state names its own source, so donor tests can trace it.""" return an_example( a_choice(n_options), target=target, source=source, state=f"{source} text {index}" ) @@ -180,8 +180,8 @@ def test_splits_are_disjoint(self, examples): assert not states[Split.TRAIN] & states[Split.CALIBRATION] assert not states[Split.CALIBRATION] & states[Split.TEST] + # Python's hash() is salted per process. def test_assignment_is_stable_across_processes(self): - """Python hash() is salted per process.""" import os import subprocess import sys @@ -212,8 +212,8 @@ def test_label_only_outside_train_raises(self): with pytest.raises(ValueError, match="never in it"): check_coverage(splits) + # Train coverage alone misses offered labels absent from every split. def test_option_never_observed_at_all_raises(self): - """Train coverage alone misses offered labels absent from every split.""" splits = { Split.TRAIN: [traceable_example("s", 0, 1), traceable_example("s", 1, 2)], Split.CALIBRATION: [], @@ -222,8 +222,8 @@ def test_option_never_observed_at_all_raises(self): with pytest.raises(ValueError, match="never show some of the options"): check_coverage(splits) + # Binary data observes only the endpoints of the nine-level scale. def test_noul_is_exempt_from_the_offered_option_check(self): - """Binary data observes only the endpoints of the nine-level scale.""" rows = [ Example("t", "n", Noul(instructions="q"), t, Layout.STATE_FIRST, "imdb") for t in (0, 8, 0, 8) @@ -269,9 +269,8 @@ def test_the_threshold_is_the_single_letter_alphabet(self): assert LABEL_OPTION_CAP == 26 +# Adjacent sources may still answer the question, so they are unsuitable abstain donors. class TestAbstainDonors: - """Adjacent sources may still answer the question and are unsuitable abstain donors.""" - def test_adjacency_is_symmetric_and_excludes_self(self): mapping = adjacency_map() for source, related in mapping.items(): @@ -496,8 +495,8 @@ def test_noul_reader_targets_land_on_the_rating_ends(self): assert [e.target for e in examples] == [len(NOUL_RATING_TOKENS) - 1, 0] assert examples[0].state == {"sentence1": "a", "sentence2": "b"} + # Both polarities stop yes from always meaning a good outcome. def test_every_noul_source_carries_a_negation(self): - """Both polarities prevent yes from always meaning a good outcome.""" for name, spec in REGISTRY.items(): if spec.primitive == "noul": assert spec.negations, f"{name} has no negated question" @@ -721,8 +720,8 @@ def build(self, out): loader=self.loader, ) + # Late-bound loader closures can cross source contents while keeping source labels. def test_every_split_draws_from_every_source(self, tmp_path): - """Late-bound loader closures can cross source contents while preserving source labels.""" from lev.data.build import SPLIT_FILES, read_jsonl manifest = self.build(tmp_path) diff --git a/packages/lev/tests/test_engine_forward.py b/packages/lev/tests/test_engine_forward.py index e362ec7..4bfa231 100644 --- a/packages/lev/tests/test_engine_forward.py +++ b/packages/lev/tests/test_engine_forward.py @@ -49,9 +49,8 @@ def test_single_forward_matches_the_full_logits_at_each_last_token(tiny_model, w assert (hidden is not None) == want_hidden +# Ids inside the tiny vocabulary; space-prefixed A-Z are single tokens, as label codes need. class TinyTokenizer: - """Ids inside the tiny vocabulary; space-prefixed A-Z are single tokens, as label codes need.""" - pad_token_id = 0 single = {f" {c}": 400 + i for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ")} @@ -61,8 +60,8 @@ def encode(self, text, add_special_tokens=True): ) +# The token limit never touches a request Score averaging did not grow (ADR-029). def test_without_score_averaging_a_large_request_answers_as_with_no_limit(tiny_model): - """The token limit never touches a request Score averaging did not grow (ADR-029).""" from lev.types import Choice, Score questions = { diff --git a/packages/lev/tests/test_eval_export.py b/packages/lev/tests/test_eval_export.py index 867be83..74f4caf 100644 --- a/packages/lev/tests/test_eval_export.py +++ b/packages/lev/tests/test_eval_export.py @@ -35,8 +35,8 @@ def write_test_split(directory, rows): class TestRoundTrip: + # Sorting cache keys changes what positional targets refer to (ADR-024). def test_same_options_in_a_different_order_are_different_questions(self, tmp_path): - """Sorting cache keys changes what positional targets refer to (ADR-024).""" forward = Choice(instructions="q", criteria={"a": None, "b": None, "c": None}) backward = Choice(instructions="q", criteria={"c": None, "b": None, "a": None}) rows = [an_example(forward, target=0, state="x"), an_example(backward, target=0, state="y")] @@ -51,7 +51,6 @@ def test_same_options_in_a_different_order_are_different_questions(self, tmp_pat assert back[0].question is not back[1].question def test_round_trip_guard_catches_an_order_blind_reader(self, tmp_path, monkeypatch): - """Inject an order-blind cache and require the guard to reject it.""" import lev.data.build as build from lev.data.build import verify_round_trip @@ -152,8 +151,8 @@ def test_an_eval_too_small_to_measure_anything_raises(self, tmp_path): class TestVariableQuestions: + # One task file cannot represent different option sets per row. def test_sources_whose_question_varies_per_row_are_skipped_and_listed(self, tmp_path): - """One task file cannot represent different option sets per row.""" rows = [example(CHOICE, i % 2, i, source="a") for i in range(MIN_USEFUL_ITEMS + 10)] rows += [ example( diff --git a/packages/lev/tests/test_evaluate.py b/packages/lev/tests/test_evaluate.py index 0d65d51..1ecd353 100644 --- a/packages/lev/tests/test_evaluate.py +++ b/packages/lev/tests/test_evaluate.py @@ -35,8 +35,8 @@ def test_interval_shrinks_with_n(self): def test_matches_the_normal_approximation(self): assert accuracy_interval(0.86, 200) == pytest.approx(0.048, abs=0.001) + # Perfect observed accuracy does not imply zero uncertainty. def test_a_certain_estimate_still_reports_a_finite_interval(self): - """Perfect observed accuracy does not imply zero uncertainty.""" assert 0.0 <= accuracy_interval(1.0, 200) < 0.01 def test_no_items_means_no_information(self): diff --git a/packages/lev/tests/test_loss.py b/packages/lev/tests/test_loss.py index d0669c8..01906cc 100644 --- a/packages/lev/tests/test_loss.py +++ b/packages/lev/tests/test_loss.py @@ -13,8 +13,8 @@ class TestDecisionLoss: + # Padded slots must avoid 0 * -inf, which produces NaN. def test_padded_slots_do_not_produce_nan(self, train_config): - """Padded slots must avoid 0 * -inf, which produces NaN.""" logits = torch.tensor( [[1.0, 2.0, 0.5, 0.1], [0.3, 1.2, float("-inf"), float("-inf")]], requires_grad=True, diff --git a/packages/lev/tests/test_packaging.py b/packages/lev/tests/test_packaging.py index b926f52..2048e2d 100644 --- a/packages/lev/tests/test_packaging.py +++ b/packages/lev/tests/test_packaging.py @@ -26,7 +26,6 @@ def _doc_sources() -> list[Path]: def _documented_values(pattern: str) -> dict[str, set[str]]: - """Map each value `pattern` captures to the documentation files that mention it.""" found: dict[str, set[str]] = {} for src in _doc_sources(): for value in re.findall(pattern, src.read_text()): @@ -64,7 +63,6 @@ def test_known_extras_are_present(expected): def _inspect_cli(tool: str) -> tuple[set[str], dict[str, set[str]]]: - """Inspect the live parser to collect accepted commands and flags.""" import argparse import importlib @@ -111,7 +109,6 @@ def test_every_documented_backend_exists(): def _documented_commands(tool: str) -> dict[str, set[str]]: - """Extract commands from fenced blocks and inline code, excluding prose.""" found: dict[str, set[str]] = {} pattern = re.compile(rf"(?:^|\s)(?:uv run )?{tool} ([a-z][a-z0-9-]*)", re.M) for src in _doc_sources(): diff --git a/packages/lev/tests/test_presentation.py b/packages/lev/tests/test_presentation.py index 830f091..35bd7d1 100644 --- a/packages/lev/tests/test_presentation.py +++ b/packages/lev/tests/test_presentation.py @@ -40,18 +40,16 @@ def softmax(z: list[float]) -> list[float]: return [v / sum(e) for v in e] +# Space-prefixed A-Z and 0-8 are single tokens, as in `rich_tokenizer`. class Tokenizer: - """Space-prefixed A-Z and 0-8 are single tokens, as `rich_tokenizer`.""" - single = {f" {c}" for c in ascii_uppercase} | {f" {i}" for i in range(9)} def encode(self, text: str, add_special_tokens: bool = True) -> list[int]: return [1] if text in self.single else [1] * (len(text) + 1) +# Real routing and orders, with scripted content, key, slot and packing effects. class FakeEngine: - """Use real routing and orders with scripted content, key, slot, and packing effects.""" - def __init__(self, slot0=0.0, content=None, packing=0.0, key_pull=None, **config): self.real = DecisionEngine(model=None, tokenizer=Tokenizer(), config=EngineConfig(**config)) self.slot0, self.content, self.packing = slot0, content or {}, packing @@ -178,8 +176,8 @@ def test_a_planted_slot_zero_penalty_is_measured_exactly(self): assert r[kind]["first_slot"]["argmax_by_slot"][0] == 0 assert r[kind]["first_slot"]["decisions"] == 18 + # Argmax would credit slot zero for every flat distribution. def test_ties_are_split_between_the_tied_slots(self): - """Argmax would incorrectly credit slot zero for every flat distribution.""" r = run(FakeEngine(), ["a", "b"]) for kind in KINDS: assert r[kind]["first_slot"]["metric"] == pytest.approx(1 / 3) @@ -194,9 +192,9 @@ def test_a_choice_key_pull_cancels_and_a_position_effect_does_not(self): alone["choice"]["identical"]["metric"] ) + # Order averaging hides the raw position bias this probe measures. @pytest.mark.parametrize("mode", ["reversed", "cyclic"]) def test_the_identical_check_reads_one_order_whatever_the_engine_averages(self, mode): - """Order averaging hides the raw position bias this probe measures.""" single = run(FakeEngine(slot0=-2.0, order_average=False), ["a"]) averaged = run(FakeEngine(slot0=-2.0, score_order_average=mode), ["a"]) for kind in KINDS: @@ -409,8 +407,8 @@ def test_a_long_state_with_few_averaged_rows_is_refused(self, rich_tokenizer): assert engine.prepare("short", question).rows == 3 assert self.engine(rich_tokenizer).prepare(LONG, question).rows == 1 + # The batcher runs oversized requests alone. def test_without_score_averaging_a_large_request_is_never_refused(self, rich_tokenizer): - """The batcher runs oversized requests alone.""" prepared = self.engine(rich_tokenizer).prepare("x" * 400, BIG) assert prepared.rows == 80 and prepared.rows * prepared.width > MAX_BATCH_TOKENS assert [v.order for v in prepared.variants] == [None, [3, 2, 1, 0]] * 20 + [None] * 40 @@ -485,9 +483,8 @@ def test_it_parses_and_carries_every_metric(self): assert drift(committed["checks"], committed["checks"], 0.0) == [] +# Settings mismatches exit 2; metric failures exit 1. class TestCompareGuardsItsSettings: - """Settings mismatches exit 2; metric failures exit 1.""" - def cli(self, monkeypatch, tmp_path, engine, *extra): from lev.cli import main diff --git a/packages/lev/tests/test_progress.py b/packages/lev/tests/test_progress.py index e57879b..efaf1c5 100644 --- a/packages/lev/tests/test_progress.py +++ b/packages/lev/tests/test_progress.py @@ -30,8 +30,8 @@ def test_always_logs_the_final_step(self, capsys): log.record(step, 1.0, "A", 1e-4, tokens=10) assert "step 7/7" in capsys.readouterr().out + # Mode B starts near ln(K), so averaging the modes hides their separate losses. def test_modes_are_reported_separately(self, capsys): - """Mode B starts near ln(K), so averaging modes hides their separate losses.""" log = self.make(total=2, every=2) log.record(0, 1.0, "A", 1e-4, tokens=10) log.record(1, 5.0, "B", 1e-4, tokens=10) @@ -68,12 +68,11 @@ def test_hms_formats_hours(self): assert hms(3661) == "1:01:01" +# Windowed rates keep startup delay out of steady-state throughput and ETA. class TestWindowedRate: - """Windowed rates exclude startup delay from steady-state throughput and ETA.""" - + # Set `clock["t"]` to move the time `ProgressLog` reads. @pytest.fixture def clock(self, monkeypatch): - """Set `clock["t"]` to move the time `ProgressLog` reads.""" now = {"t": 0.0} monkeypatch.setattr(progress.time, "monotonic", lambda: now["t"]) return now diff --git a/packages/lev/tests/test_release.py b/packages/lev/tests/test_release.py index 2b890dc..3aa5f19 100644 --- a/packages/lev/tests/test_release.py +++ b/packages/lev/tests/test_release.py @@ -10,7 +10,6 @@ def fake_checkpoint(root, step=18750, calibrated=True): - """Create placeholder files matching a saved checkpoint and calibration.""" out = root / "4b" step_dir = out / f"step-{step}" step_dir.mkdir(parents=True) @@ -96,8 +95,8 @@ def test_a_missing_path_that_is_not_a_hub_id_fails_clearly(self, spec): with pytest.raises(FileNotFoundError, match="neither a local path nor a Hub id"): fetch_checkpoint(spec) + # A missing relative path may also parse as a Hub id. def test_a_mistyped_local_path_that_looks_like_a_hub_id_fails_clearly(self, monkeypatch): - """A missing relative path may also parse as a Hub id.""" # Both ship with the `train` extra, absent on a bare `uv sync`. huggingface_hub = pytest.importorskip("huggingface_hub") httpx = pytest.importorskip("httpx") diff --git a/packages/lev/tests/test_s1bench.py b/packages/lev/tests/test_s1bench.py index bd7eb1b..4355338 100644 --- a/packages/lev/tests/test_s1bench.py +++ b/packages/lev/tests/test_s1bench.py @@ -45,8 +45,8 @@ def test_training_sources_are_refused(self, name: str) -> None: class TestStructuralSeparation: + # A fresh interpreter, so imports already made by the test suite cannot mask dependencies. def test_s1bench_cannot_reach_the_mixture_builder(self) -> None: - """Use a fresh interpreter so existing test-suite imports do not mask dependencies.""" probe = ( "import sys; import lev.data.s1bench; " "leaked = sorted(m for m in sys.modules " @@ -98,9 +98,9 @@ def test_definition_is_self_consistent_and_names_its_source(self, name: str) -> assert spec["source"].startswith("https://github.com/bespokelabsai/nimble/blob/") assert s1bench.question_for(spec).type == EXPECTED_TYPES[name] + # The pinned helpsteer2 filter yields 249 records, one fewer than the board. @pytest.mark.parametrize("name", sorted(EVAL_SUBSETS)) def test_record_counts_match_the_board(self, name: str) -> None: - """The pinned helpsteer2 filter yields 249 records, one fewer than the board.""" board = jev_board(snapshot())[name] expected = board["total"] - (1 if name == "helpsteer2" else 0) assert definition(name)["count"] == expected diff --git a/packages/lev/tests/test_training_loop.py b/packages/lev/tests/test_training_loop.py index f64b09a..4820982 100644 --- a/packages/lev/tests/test_training_loop.py +++ b/packages/lev/tests/test_training_loop.py @@ -36,8 +36,8 @@ def make_batching_tokenizer(): ) +# The 64 rows are 4-option Choices, so every batch takes Mode A. def stub_backbone(monkeypatch, loop): - """The 64 rows are 4-option Choices, so every batch takes Mode A.""" rows = [an_example(a_choice(4), target=i % 4, state=f"row {i}") for i in range(64)] monkeypatch.setattr(loop, "prepare_data", lambda c, d: {"train": rows, "calibration": []}) monkeypatch.setattr( @@ -72,7 +72,6 @@ def smoke_config(tmp_path, *, epochs, checkpoint_every): def run_resumable( tmp_path, monkeypatch, *, max_steps, checkpoint_every=3, fresh=False, persist=True ): - """Run with on-disk checkpoints; return saved steps, observed batches, and summary.""" import lev.train.loop as loop from lev.train.checkpoints import TRAINING_STATE from lev.train.collate import DecisionCollator @@ -104,8 +103,6 @@ def fake_save(m, h, tk, out, step, cb=None, state=None): class TestCheckpointCadence: - """Exercise real batching and checkpoint decisions with model and storage stubs.""" - def run(self, tmp_path, monkeypatch, *, max_steps, checkpoint_every, epochs=1): import lev.train.loop as loop @@ -165,15 +162,15 @@ def test_fresh_ignores_the_checkpoint(self, tmp_path, monkeypatch): assert saved == [3, 6] assert summary["history"][0]["step"] == 0 + # Weight loading is stubbed; this checks the schedule restart only. def test_weights_only_checkpoint_restarts_the_schedule(self, tmp_path, monkeypatch): - """Weight loading is stubbed; this checks schedule restart only.""" run_resumable(tmp_path, monkeypatch, max_steps=6, persist=False) saved, _, summary = run_resumable(tmp_path, monkeypatch, max_steps=6) assert saved == [3, 6] assert summary["history"][0]["step"] == 0 + # An off-interval final checkpoint must carry resume state. def test_rerunning_a_finished_run_trains_nothing(self, tmp_path, monkeypatch): - """An off-interval final checkpoint must carry resume state.""" run_resumable(tmp_path, monkeypatch, max_steps=7) saved, seen, summary = run_resumable(tmp_path, monkeypatch, max_steps=7) assert seen == [], "a finished run must not train again" @@ -188,8 +185,8 @@ def test_a_final_checkpoint_between_saves_resumes_where_it_stopped(self, tmp_pat assert saved == [9, 10] assert [h["step"] for h in summary["history"]] == list(range(10)) + # At batch size two, step 33 is the first step of the second 64-row epoch. def test_resume_across_an_epoch_boundary(self, tmp_path, monkeypatch): - """At batch size two, step 33 is the first step of the second 64-row epoch.""" _, full, _ = run_resumable(tmp_path / "ref", monkeypatch, max_steps=36) run_resumable(tmp_path, monkeypatch, max_steps=33) _, seen, summary = run_resumable(tmp_path, monkeypatch, max_steps=36) @@ -217,8 +214,8 @@ def test_stale_checkpoints_and_calibration_are_moved_not_deleted(self, tmp_path) assert (moved / "calibration.json").is_file() assert set_aside_previous_run(out) is None + # Stale higher-step checkpoints must not survive in the active run directory. def test_fresh_run_does_not_resume_from_a_higher_stale_step(self, tmp_path, monkeypatch): - """Stale higher-step checkpoints must not survive in the active run directory.""" from lev.train.checkpoints import latest_checkpoint stale = tmp_path / "out" / "step-18750" @@ -233,7 +230,6 @@ def test_fresh_run_does_not_resume_from_a_higher_stale_step(self, tmp_path, monk class TestModeAProjectsOnlyTheAnswerPositions: def test_logits_to_keep_selects_distinct_positions_and_rows_read_their_own(self): - """Project only answer positions and select the correct output column per row.""" from types import SimpleNamespace from lev.router import Mode @@ -266,9 +262,8 @@ def __call__(self, input_ids, attention_mask, logits_to_keep): assert out.tolist() == [[71.0, 72.0], [141.0, 142.0], [273.0, 274.0]] +# `scored_rows` is the shared forward that calibration and evaluation both read. class TestScoredRows: - """`scored_rows` is the shared forward that calibration and evaluation both read.""" - def rows_through(self, monkeypatch, n_rows): from lev.train import loop from lev.train.config import PRESETS diff --git a/packages/levbench/src/levbench/batching.py b/packages/levbench/src/levbench/batching.py index e763022..2023521 100644 --- a/packages/levbench/src/levbench/batching.py +++ b/packages/levbench/src/levbench/batching.py @@ -88,7 +88,6 @@ def sweep( bank: list[tuple[str, Any]] | None = None, errors: list[tuple[int, str]] | None = None, ) -> list[SweepRow]: - """Run the sweep, appending any per-count failure to `errors`.""" bank = QUESTION_BANK if bank is None else bank rows: list[SweepRow] = [] errors = errors if errors is not None else [] diff --git a/packages/levbench/src/levbench/cli.py b/packages/levbench/src/levbench/cli.py index e7522b1..60ad20f 100644 --- a/packages/levbench/src/levbench/cli.py +++ b/packages/levbench/src/levbench/cli.py @@ -21,7 +21,6 @@ def repo_data_dir() -> Path: - """Find the repository data directory relative to this module.""" for parent in Path(__file__).resolve().parents: if (candidate := parent / "data").is_dir(): return candidate @@ -42,7 +41,6 @@ def _require_key(backend: str, base_url: str | None = None) -> None: def _task_files(path: str | None) -> Sequence[Path | None]: - """Return task files, or None to use the built-in fixture.""" if path is None: return [None] target = Path(path) diff --git a/packages/levbench/src/levbench/confidence_id.py b/packages/levbench/src/levbench/confidence_id.py index 69ebba3..92fe9f5 100644 --- a/packages/levbench/src/levbench/confidence_id.py +++ b/packages/levbench/src/levbench/confidence_id.py @@ -11,7 +11,6 @@ def gini(p: Distribution) -> float: - """Normalized Gini concentration: (K*sum(p^2) - 1) / (K - 1).""" k = len(p) if k <= 1: return 1.0 @@ -38,7 +37,6 @@ def top_two_margin(p: Distribution) -> float: def normalized_max_prob(p: Distribution) -> float: - """Normalize maximum probability relative to uniform chance.""" k = len(p) if k <= 1: return 1.0 @@ -63,7 +61,6 @@ def top_two_ratio(p: Distribution) -> float: def detect_precision(values: list[float], max_decimals: int = 6) -> float: - """Find a shared quantization step, or return zero if none matches.""" for decimals in range(1, max_decimals + 1): unit = 10.0**-decimals if all(abs(v / unit - round(v / unit)) < 1e-6 for v in values): @@ -72,7 +69,6 @@ def detect_precision(values: list[float], max_decimals: int = 6) -> float: def rounding_sensitivity(fn: Callable[[Distribution], float], p: Distribution, eps: float) -> float: - """Bound how probability rounding affects a confidence formula.""" base = fn(p) raised = fn([min(1.0, x + eps) for x in p]) lowered = fn([max(0.0, x - eps) for x in p]) @@ -87,14 +83,13 @@ class Fit: max_abs_error: float tolerance: float = 5e-3 + # Tolerance allows for quantization error, as amplified by the candidate formula. @property def matches(self) -> bool: - """Allow quantization error amplified by the candidate formula.""" return self.max_abs_error <= self.tolerance def collect(answers: Iterable[Any]) -> list[tuple[Distribution, float]]: - """Pull (distribution, reported confidence) from answers that have both.""" samples: list[tuple[Distribution, float]] = [] for answer in answers: reported = getattr(answer, "confidence", None) @@ -106,7 +101,6 @@ def collect(answers: Iterable[Any]) -> list[tuple[Distribution, float]]: def identify(samples: list[tuple[Distribution, float]]) -> list[Fit]: - """Rank candidate formulas by how closely they reproduce `confidence`.""" if not samples: return [] everything = [v for dist, reported in samples for v in (*dist, reported)] @@ -129,7 +123,6 @@ def identify(samples: list[tuple[Distribution, float]]) -> list[Fit]: def identify_by_size(samples: list[tuple[Distribution, float]]) -> dict[int, list[Fit]]: - """Fit confidence formulas separately for each candidate-set size.""" by_size: dict[int, list[tuple[Distribution, float]]] = {} for dist, reported in samples: by_size.setdefault(len(dist), []).append((dist, reported)) @@ -139,7 +132,6 @@ def identify_by_size(samples: list[tuple[Distribution, float]]) -> dict[int, lis def worst_residuals( samples: list[tuple[Distribution, float]], name: str, limit: int = 3 ) -> list[tuple[Distribution, float, float]]: - """Return the worst fits as (distribution, reported, predicted).""" fn = CANDIDATES[name] scored = [(dist, reported, fn(dist)) for dist, reported in samples] return sorted(scored, key=lambda row: abs(row[2] - row[1]), reverse=True)[:limit] @@ -172,7 +164,6 @@ def format_fits(fits: list[Fit]) -> str: def format_diagnosis(samples: list[tuple[Distribution, float]]) -> str: - """Format per-size fits and worst residuals.""" out: list[str] = [] off = [abs(sum(dist) - 1.0) for dist, _ in samples] diff --git a/packages/levbench/src/levbench/metrics.py b/packages/levbench/src/levbench/metrics.py index 372051e..f96a838 100644 --- a/packages/levbench/src/levbench/metrics.py +++ b/packages/levbench/src/levbench/metrics.py @@ -22,8 +22,8 @@ def to_distribution(answer: Any) -> dict[Any, float]: raise ValueError(f"Unknown answer type {kind!r}") +# Choice uses the model's own pick rather than the argmax. def predicted_label(answer: Any) -> Any: - """The argmax label, except for Choice, which uses the model's own pick.""" kind = answer.type if kind == "noul": return float(answer.noul) >= 0.5 @@ -36,7 +36,6 @@ def predicted_label(answer: Any) -> Any: def top_probability(answer: Any) -> float: - """Return the top-label probability used for ECE.""" return max(to_distribution(answer).values()) @@ -44,8 +43,8 @@ def log_loss(dist: dict[Any, float], truth: Any) -> float: return -math.log(max(dist.get(truth, 0.0), _EPS)) +# Multiclass Brier: squared error summed over the whole vector. def brier(dist: dict[Any, float], truth: Any) -> float: - """Multiclass Brier score: summed squared error over the whole vector.""" labels = set(dist) | {truth} return sum((dist.get(k, 0.0) - (1.0 if k == truth else 0.0)) ** 2 for k in labels) @@ -66,9 +65,9 @@ def accuracy(self) -> float: def mean_confidence(self) -> float: return self.conf_sum / self.n if self.n else 0.0 + # Signed: positive means overconfident. @property def gap(self) -> float: - """Signed: positive means overconfident.""" return self.mean_confidence - self.accuracy @@ -94,7 +93,6 @@ def mean_brier(self) -> float: @property def ece(self) -> float: - """Expected Calibration Error: sample-weighted mean absolute bin gap.""" if not self.n: return 0.0 return sum(b.n * abs(b.gap) for b in self.bins) / self.n @@ -103,7 +101,6 @@ def ece(self) -> float: def calibration( records: list[tuple[dict[Any, float], Any, Any, float]], n_bins: int = 10 ) -> Calibration: - """Aggregate metrics over (distribution, predicted, truth, confidence) rows.""" edges = [i / n_bins for i in range(n_bins + 1)] cal = Calibration(bins=[Bin(edges[i], edges[i + 1]) for i in range(n_bins)]) @@ -127,7 +124,6 @@ def calibration( def selective_accuracy( records: list[tuple[dict[Any, float], Any, Any, float]], threshold: float ) -> tuple[float, float]: - """Return accuracy and coverage above a confidence threshold.""" kept = [r for r in records if r[3] >= threshold] if not kept: return 0.0, 0.0 diff --git a/packages/levbench/src/levbench/runner.py b/packages/levbench/src/levbench/runner.py index f4507c1..a751e54 100644 --- a/packages/levbench/src/levbench/runner.py +++ b/packages/levbench/src/levbench/runner.py @@ -83,7 +83,6 @@ def build_client( base_url: str | None = None, timeout: float | None = None, ): - """Build a Jev, local lev, or Anthropic client and return its model name.""" if backend in ("jev", "lev"): if backend == "lev": base_url = base_url or DEFAULT_LOCAL_BASE_URL @@ -118,8 +117,8 @@ def build_client( raise ValueError(f"Unknown backend {backend!r} (expected 'jev', 'lev' or 'anthropic')") +# Billed retry totals win; zero counts are accepted, missing counts raise. def _token_count(usage: Any, total_field: str, base_field: str) -> int: - """Prefer billed retry totals; accept zero counts and reject missing counts.""" for field_name in (total_field, base_field): value = getattr(usage, field_name, None) if value is not None: @@ -163,7 +162,6 @@ def run_eval( questions: dict[str, Any], concurrency: int = 1, ) -> EvalReport: - """Evaluate concurrently, returning results in item order and per-call latencies.""" from concurrent.futures import ThreadPoolExecutor report = EvalReport(backend=backend, model=model) diff --git a/packages/levbench/src/levbench/snake/policy.py b/packages/levbench/src/levbench/snake/policy.py index 04b5fe4..376d179 100644 --- a/packages/levbench/src/levbench/snake/policy.py +++ b/packages/levbench/src/levbench/snake/policy.py @@ -43,7 +43,6 @@ def to_dict(self) -> dict: def describe(game: SnakeGame, prompt: str) -> tuple[str, dict[str, Any], dict]: - """Build prompts and planner truth without calling the server.""" if prompt not in PROMPTS: raise ValueError(f"prompt must be one of {PROMPTS}, got {prompt!r}") moves = game.moves() diff --git a/packages/levbench/src/levbench/snake/ui.py b/packages/levbench/src/levbench/snake/ui.py index 5765639..e8d97ef 100644 --- a/packages/levbench/src/levbench/snake/ui.py +++ b/packages/levbench/src/levbench/snake/ui.py @@ -90,8 +90,8 @@ def network_label(backend: str, base_url: str | None) -> str: return "localhost" +# Probabilities describe the displayed board, before its announced next step. def compose(game: dict, decision: dict, stats: dict) -> Canvas: - """Probabilities describe the displayed board, before its announced next step.""" width, height = layout_size(game["width"], game["height"]) c = Canvas(width, height) left, right, top = 3, max(58, game["width"] * 2 + 10), 6 @@ -227,8 +227,6 @@ def status_line(game: dict, decision: dict, stats: dict) -> str: class Keyboard: - """Non-blocking single-key reads from a TTY; a no-op anywhere else.""" - def __enter__(self): self.saved = None if sys.stdin.isatty(): diff --git a/packages/levbench/src/levbench/tasks.py b/packages/levbench/src/levbench/tasks.py index af8a75a..d824c97 100644 --- a/packages/levbench/src/levbench/tasks.py +++ b/packages/levbench/src/levbench/tasks.py @@ -227,8 +227,8 @@ def dataset(path: str | Path | None = None) -> tuple[Sequence[Item | FileItem], return ITEMS, questions() +# Comparing two runs needs more data than this single-run margin. def detectable_difference(n: int, baseline: float = 0.8, z: float = 1.96) -> float: - """Estimate the accuracy margin (95% at default z); comparing runs needs more data.""" if n <= 0: return 1.0 return min(1.0, z * math.sqrt(baseline * (1 - baseline) / n)) diff --git a/packages/levbench/tests/test_offline.py b/packages/levbench/tests/test_offline.py index fb35dc0..fce0812 100644 --- a/packages/levbench/tests/test_offline.py +++ b/packages/levbench/tests/test_offline.py @@ -64,9 +64,8 @@ def test_every_primitive_flattens_to_a_distribution() -> None: assert score.score == pytest.approx(expected, abs=1e-2, rel=0) +# Vendor confidence formulas differ, so ECE must use the answer's top probability. def test_ece_bins_on_the_top_probability_not_the_vendor_confidence_field() -> None: - """Vendor confidence formulas differ; ECE must use the answer's top probability.""" - class Server: def system_one(self, state, questions): answer = SimpleNamespace( @@ -95,8 +94,8 @@ def test_eval_runs_end_to_end_over_the_built_in_fixture() -> None: assert "accuracy" in text and "ECE" in text +# Synthetic billing checks the sweep arithmetic; live billing needs a live sweep. def test_sweep_arithmetic_over_a_fixed_billing_shape() -> None: - """Synthetic billing verifies sweep arithmetic; live billing requires a live sweep.""" state = (ROOT / "data" / "sample_policy.md").read_text() rows = batching.sweep(fake_client(), runner.JEV_DEFAULT, state, [1, 2, 4, 8, 13]) @@ -122,10 +121,9 @@ def test_sweep_respects_an_explicitly_empty_bank() -> None: batching.sweep(None, runner.JEV_DEFAULT, "state", [1], bank=[]) +# A match only means something if the identifier can tell candidate formulas apart. @pytest.mark.parametrize("planted", confidence_id.CANDIDATES) def test_confidence_identifier_recovers_a_planted_formula(planted) -> None: - """A match is useful only if the identifier can distinguish candidate formulas.""" - def handle(request): body = json.loads(request.content) answers = {} @@ -185,7 +183,6 @@ def handle(request): def test_local_base_url_never_forwards_the_real_key(monkeypatch) -> None: - """Custom endpoints use a local key; hosted requests retain the real credential.""" monkeypatch.setenv("TYPESAFE_API_KEY", "sk-REAL-SECRET-KEY") monkeypatch.delenv("LEVBENCH_LOCAL_API_KEY", raising=False) local, _ = runner.build_client("jev", "litjev", "http://127.0.0.1:8000") @@ -214,7 +211,6 @@ def test_an_unpinned_jev_run_reports_the_version_served() -> None: def test_empty_local_key_env_var_falls_back(monkeypatch) -> None: - """An empty key produces an invalid Bearer header; use the local fallback.""" monkeypatch.setenv("LEVBENCH_LOCAL_API_KEY", "") client, _ = runner.build_client("lev") assert isinstance(client, TypeSafeClient) @@ -247,7 +243,6 @@ def _write_task_file(path, question_type="choice", n=5): @pytest.mark.parametrize("question_type", ["choice", "score", "noul"]) def test_eval_runs_over_a_generated_task_file(tmp_path, question_type) -> None: - """Exercise the task-file format produced by `lev data eval` for every primitive.""" items, questions = dataset(_write_task_file(tmp_path / "gen.json", question_type)) assert questions["q"].type == question_type report = runner.run_eval(fake_client(), "jev", runner.JEV_DEFAULT, items, questions) @@ -258,7 +253,6 @@ def test_eval_runs_over_a_generated_task_file(tmp_path, question_type) -> None: def test_a_task_file_labelling_an_undefined_question_raises(tmp_path) -> None: - """Reject undefined questions so their labels cannot be silently excluded from scoring.""" path = tmp_path / "bad.json" path.write_text( json.dumps( @@ -283,8 +277,8 @@ def test_detectable_difference_shrinks_with_n() -> None: assert detectable_difference(0) == 1.0 +# Grouping by candidate-set size can expose a formula that pooled samples hide. def test_pooling_can_hide_a_formula_that_holds_per_candidate_set_size() -> None: - """Grouping by candidate-set size can expose formulas hidden by pooled samples.""" four = [0.7, 0.1, 0.1, 0.1] three = [0.5, 0.3, 0.2] samples = [(four, confidence_id.max_prob(four))] * 6 @@ -311,14 +305,14 @@ def test_worst_residuals_surfaces_the_samples_that_break_a_candidate() -> None: assert predicted == pytest.approx(0.5, abs=1e-9, rel=0) +# Incomplete distributions can distort confidence formulas independently of fit. def test_diagnosis_reports_whether_distributions_are_complete() -> None: - """Incomplete distributions can distort confidence formulas independently of fit.""" truncated = [([0.6, 0.3], 0.6)] assert "sum to 1 within 0.1" in confidence_id.format_diagnosis(truncated) +# Normalized max probability amplifies rounding by K/(K-1). def test_tolerance_accounts_for_how_much_a_statistic_amplifies_rounding() -> None: - """Normalized max probability amplifies rounding by K/(K-1).""" rng = random.Random(0) samples = [] for size in (4, 3): @@ -381,7 +375,6 @@ def test_cost_is_per_million_tokens_at_list_price(self) -> None: assert cost_usd("Qwen/Qwen3.5-4B", 1_000_000, 1_000_000) == 0.0, "self-hosted is unmetered" def test_billed_totals_win_over_base_counts(self) -> None: - """Retry totals reflect billed usage.""" usage = SimpleNamespace( input_tokens=10, input_tokens_total=25, output_tokens=2, output_tokens_total=4 ) @@ -391,8 +384,8 @@ def test_missing_token_counts_raise_rather_than_count_as_free(self) -> None: with pytest.raises(ValueError, match="refusing to assume 0 tokens"): runner._usage_ints(SimpleNamespace(input_tokens=None, output_tokens=None)) + # Pricing uses the requested model, so a substitution has to be reported. def test_a_substituted_model_is_flagged_in_the_report(self) -> None: - """Report model substitution because pricing uses the requested model.""" report = runner.EvalReport(backend="jev", model="jev-1.12") report.calls.append(runner.CallResult({}, 0.3, JEV_VERSION, 10, 1)) assert "requested 'jev-1.12' but server served ['jev-1.13.0']" in runner.format_report( diff --git a/packages/levbench/tests/test_snake.py b/packages/levbench/tests/test_snake.py index f730753..c02ddea 100644 --- a/packages/levbench/tests/test_snake.py +++ b/packages/levbench/tests/test_snake.py @@ -40,9 +40,8 @@ def unsafe_direction(game: SnakeGame) -> str: return next(m.direction for m in game.moves() if not m.safe) +# Answers from a chosen direction, with two Noul probabilities. class StubServer: - """Answers from a chosen direction and two Noul probabilities""" - def __init__(self, pick=None, route=0.9, food=0.9, follow_planner=False, invert=False): self.pick, self.route, self.food = pick, route, food self.follow_planner, self.invert = follow_planner, invert @@ -248,8 +247,8 @@ def test_planner_never_needs_the_shield_and_reads_its_state(self): class TestRounds: + # A small board clears within the step budget, forcing a new round. def test_guarded_run_continues_past_a_cleared_board(self): - """A small board clears within the step budget, forcing a new round.""" summary = play( PlannerClient(), "planner", "planner", width=4, height=4, initial_length=2, steps=60 ) From 15bc6ffbc57b20413a51fbfac546edfdd6a08da2 Mon Sep 17 00:00:00 2001 From: Abhinavexist Date: Thu, 15 Oct 2026 09:21:40 +0530 Subject: [PATCH 31/39] docs(claude): adapt repo references for the public repository --- CLAUDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e09cc73..dcc546b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ Read the relevant doc before changing anything it covers; most "obvious" improve - **Readout.** Mode A reads label-token logits at the answer boundary whenever every label code is a single token — 68 options for this tokenizer, since the 69th code, `BQ`, is two. Above that, Mode B scores candidate text with the trained head. Training and serving route the same way (ADR-025, ADR-026); serving also skips split codes (ADR-028). Routing is in `router.py`. - **Calibration** is per bucket, keyed `{type}:{mode}[:{band}]`, selected by leave-one-family-out transfer ECE. `calibrate.fit` refuses `test`, `eval` and `holdout` splits — fit only on the dedicated `calibration` split. - **The release** (`lev-4b`) is preset `4b-instruct`, step 18750, chat prompt style. Its `lev_release.json` manifest sets the base model, prompt style and optional `adapter_scale`, and `lev.load` honours all three. -- **The released weights were trained at commit `c6ccad7`.** Changes to data, sources, prompts or the training loop after it are not in the weights until a retrain; do not attribute a benchmark move to them. +- **The released weights were trained on 2026-09-23 code, before this repository's first commit.** Changes to data, sources, prompts or the training loop since are not in the weights until a retrain; do not attribute a benchmark move to them. ## Running things @@ -43,7 +43,7 @@ Read the relevant doc before changing anything it covers; most "obvious" improve - **Ask before any paid call**: `levbench` against Jev, the Anthropic backend, or a sweep. They bill per token. - `levbench` never sends `TYPESAFE_API_KEY` to a `--base-url` host; a custom endpoint gets `LEVBENCH_LOCAL_API_KEY` or `local`. Keep it that way. - Do not read `.env`. -- This repository is mirrored by hand to the public [`InterfazeAI/lev`](https://github.com/InterfazeAI/lev); the two diverge, so a change meant for release must be ported, not assumed. +- This is the public repository. Development happens in [`Abhinavexists/lev`](https://github.com/Abhinavexists/lev) and is ported here by hand; the two diverge, so a change made here must be ported back, not assumed. ## Comments From 7220285a72c47170c7146a1e072a7d112293e2f3 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 10:57:53 +0530 Subject: [PATCH 32/39] feat(modal): serve a packaged release with LEV_SERVE_RELEASE --- Makefile | 4 ++-- modal/app.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 808d89a..5ba5612 100644 --- a/Makefile +++ b/Makefile @@ -96,10 +96,10 @@ calibrate: .PHONY: serve deploy release weights publish serve: - LEV_SERVE_PRESET=$(PRESET) modal serve modal/app.py + LEV_SERVE_PRESET=$(PRESET) $(if $(NAME),LEV_SERVE_RELEASE=$(NAME)) modal serve modal/app.py deploy: - LEV_SERVE_PRESET=$(PRESET) modal deploy modal/app.py + LEV_SERVE_PRESET=$(PRESET) $(if $(NAME),LEV_SERVE_RELEASE=$(NAME)) modal deploy modal/app.py release: modal run modal/app.py::export_checkpoint --preset $(PRESET) $(if $(NAME),--name $(NAME),) diff --git a/modal/app.py b/modal/app.py index f25bad0..573d7ca 100644 --- a/modal/app.py +++ b/modal/app.py @@ -101,6 +101,7 @@ def _serve_overrides() -> list: for key in ( "LEV_SERVE_PRESET", "LEV_SERVE_MODEL", + "LEV_SERVE_RELEASE", "LEV_SERVE_COMPILE", "LEV_SERVE_MAX_LABEL_OPTIONS", "LEV_SERVE_PROMPT", @@ -285,9 +286,16 @@ def serve(): skip_codes = os.environ.get("LEV_SERVE_SKIP_CODES", "1") not in ("0", "false", "no") # A frozen-model override must bypass the adapter checkpoint. frozen = os.environ.get("LEV_SERVE_MODEL") + release = os.environ.get("LEV_SERVE_RELEASE") if frozen: print(f"serving {frozen} frozen: no adapter, binary Noul, raw softmax") checkpoint_dir, model_id = None, frozen + elif release: + # A release is what was published: its manifest's adapter scale and refit temperatures. + checkpoint_dir, model_id = f"{RELEASES_DIR}/{release}", config.model_id + if not Path(checkpoint_dir, "lev_release.json").is_file(): + raise FileNotFoundError(f"LEV_SERVE_RELEASE={release!r}: nothing at {checkpoint_dir}") + print(f"serving release {release}") else: output = Path(f"{CKPT_DIR}/{preset}") # `latest_checkpoint` skips a step directory without weights (an interrupted save). From 7d0fcdacc34da5b5fa2fd6c0a64c9124df6dfbde Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 10:57:53 +0530 Subject: [PATCH 33/39] docs(setup): document serving a packaged release --- docs/SETUP.md | 1 + docs/TRAINING.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/SETUP.md b/docs/SETUP.md index cf0aaab..e51fe8d 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -78,6 +78,7 @@ Set on the machine where `modal deploy` runs, from the environment or `.env`; th | --- | --- | --- | | `LEV_SERVE_PRESET` | `4b` | Which preset's newest checkpoint to serve. `make deploy PRESET=...` sets it | | `LEV_SERVE_MODEL` | unset | Serve this model frozen instead — no adapter, binary Noul, the zero-shot baseline | +| `LEV_SERVE_RELEASE` | unset | Serve `releases/` instead of the training output, with its manifest's adapter scale and calibration. `make deploy NAME=...` sets it | | `LEV_SERVE_COMPILE` | `0` | `torch.compile`. Off unless asked: measured slower than eager here (ADR-023) | | `LEV_SERVE_MAX_LABEL_OPTIONS` | unset | Cap on label options. Unset means Mode A up to the tokenizer limit (ADR-025) | | `LEV_SERVE_PROMPT` | the preset's | Override the prompt style, mainly for a frozen model | diff --git a/docs/TRAINING.md b/docs/TRAINING.md index d4fd4d2..4070cbf 100644 --- a/docs/TRAINING.md +++ b/docs/TRAINING.md @@ -260,7 +260,7 @@ make publish RELEASE=4b-instruct REPO=org/name # -> huggingface.co/org/name (HF ### On Modal: which checkpoint, and `serve` vs `deploy` -`make deploy PRESET=4b-instruct` serves that preset's newest checkpoint; the preset travels to the container as `LEV_SERVE_PRESET`. `LEV_SERVE_MODEL=Qwen/Qwen3.5-4B make deploy` serves that model frozen — no adapter, binary Noul — the zero-shot baseline. +`make deploy PRESET=4b-instruct` serves that preset's newest checkpoint; the preset travels to the container as `LEV_SERVE_PRESET`. `make deploy NAME=lev` serves the packaged release instead — what the Hub ships, including an `adapter_scale` or calibration refit after export. `LEV_SERVE_MODEL=Qwen/Qwen3.5-4B make deploy` serves that model frozen — no adapter, binary Noul — the zero-shot baseline. `modal serve` is an ephemeral dev server. So is every `modal run` of this app file, and each one registers the `serve` web function under the same `-dev` label — so running an export or a diagnostic while the dev server is up steals its URL, and the URL returns 404 when the run exits. `make deploy` gives the server a stable URL that runs cannot take. From 0ff1e8385d7da371e9d8d6c5b677c343df764da5 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 10:57:53 +0530 Subject: [PATCH 34/39] docs(readme): note score order averaging and the presentation checks --- README.md | 6 +++--- hf/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7d1488..6eeb07a 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ flowchart LR style O fill:#2a78d6,stroke:#2a78d6,color:#ffffff ``` -Each option gets a short code, and the answer is read from the next-token logits over those codes. Choices are read in two option orders and averaged, which cancels position bias. Codes that would split into two tokens are skipped, so this reaches several hundred options. +Each option gets a short code, and the answer is read from the next-token logits over those codes. Choices are read in two option orders and averaged, which cancels position bias. Score levels stay in their trained order unless the server runs with `--score-order-average` (off by default, [ADR-029](docs/DECISIONS.md#adr-029--score-is-read-in-one-order-measure-the-position-effect-and-offer-averaging-off-by-default)). Codes that would split into two tokens are skipped, so this reaches several hundred options. **The router is the part nobody else had.** Every other implementation picks one readout family and hits a wall when options stop fitting in single tokens: it caps the option count or rejects the request. lev routes those questions to a small learned head that matches the state against each option's text, so there is no fixed option ceiling. [ADR-005 →](docs/DECISIONS.md#adr-005--dual-mode-readout-the-differentiator) @@ -265,7 +265,7 @@ The data build refuses any source that resolves to one of the 13 S1Bench subsets ```text packages/ - lev/ the model — schema, prompt layouts, router, readouts, calibration, loader, server, S1Bench export + lev/ the model — schema, prompt layouts, router, readouts, calibration, loader, server, presentation checks, S1Bench export levbench/ the harness — accuracy, ECE, cost, latency, batching economics, Snake modal/ app.py — train / calibrate / serve / check a release on one H100 hf/ README.md — the Hub model card, and the charts it shows @@ -276,7 +276,7 @@ docs/ ARCHITECTURE — the design, and every model it was derived fro STATUS — what is built and how far it has been run SETUP, TRAINING — local and Modal, the pipeline step by step charts/ — the lev-vs-Jev comparison page, built from the logs -data/ sample state + the S1Bench snapshot the analysis rests on +data/ sample state, the S1Bench snapshot the analysis rests on, the presentation report ``` ## Prior work diff --git a/hf/README.md b/hf/README.md index afc1f69..44edae4 100644 --- a/hf/README.md +++ b/hf/README.md @@ -187,7 +187,7 @@ The 69 ms is engine compute for a short request (a three-sentence state), measur

State and questions go through one forward pass, then label-token readout or the candidate-path head, then per-bucket temperatures, then typed answers

-- **Label-token readout.** Each option gets a short code, and the answer is read from the next-token logits over those codes. Codes that would split into two tokens are skipped, so every option stays one token. This handles yes/no, scores, and choice lists up to several hundred options. Choices are read in two option orders and averaged, which cancels position bias. +- **Label-token readout.** Each option gets a short code, and the answer is read from the next-token logits over those codes. Codes that would split into two tokens are skipped, so every option stays one token. This handles yes/no, scores, and choice lists up to several hundred options. Choices are read in two option orders and averaged, which cancels position bias. Score levels stay in their trained order unless `lev serve` runs with `--score-order-average`, which is off by default. - **Candidate-path head.** Past that point, a small learned head matches the state against each option's text, so the number of options has no fixed ceiling. - **Calibration.** Temperatures fitted after training are applied at load time. There is one per question type, readout mode, and choice option-count band. They were selected by how well they carry over to task families left out of the fit, not only by how well they fit held-out rows. From 25590d465d206ac789db49f4cdf78765b76da4fe Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 12:26:37 +0530 Subject: [PATCH 35/39] feat(release): read the hub write key from .env when publishing --- packages/lev/pyproject.toml | 1 + packages/lev/src/lev/cli.py | 4 ++++ uv.lock | 3 +++ 3 files changed, 8 insertions(+) diff --git a/packages/lev/pyproject.toml b/packages/lev/pyproject.toml index 9330159..ed18196 100644 --- a/packages/lev/pyproject.toml +++ b/packages/lev/pyproject.toml @@ -28,6 +28,7 @@ train = [ "accelerate>=1.2", "datasets>=3.2", "huggingface-hub>=1.0", + "python-dotenv>=1.2.3", "safetensors>=0.4", ] serve = [ diff --git a/packages/lev/src/lev/cli.py b/packages/lev/src/lev/cli.py index f420054..bf4e1b6 100644 --- a/packages/lev/src/lev/cli.py +++ b/packages/lev/src/lev/cli.py @@ -193,8 +193,12 @@ def cmd_release_build(args: argparse.Namespace) -> None: def cmd_release_publish(args: argparse.Namespace) -> None: + from dotenv import find_dotenv, load_dotenv + from .release import publish + # The Hub write key lives in .env; `hf auth login` may hold a token without org write access. + load_dotenv(find_dotenv(usecwd=True)) url = publish(args.release, args.repo, private=args.private) print(f"published -> {url}") print(f"\n uv run lev serve --checkpoint {args.repo}") diff --git a/uv.lock b/uv.lock index 0c74dea..2c299e6 100644 --- a/uv.lock +++ b/uv.lock @@ -966,6 +966,7 @@ serve = [ { name = "fastapi" }, { name = "huggingface-hub" }, { name = "peft" }, + { name = "python-dotenv" }, { name = "safetensors" }, { name = "torch" }, { name = "transformers" }, @@ -976,6 +977,7 @@ train = [ { name = "datasets" }, { name = "huggingface-hub" }, { name = "peft" }, + { name = "python-dotenv" }, { name = "safetensors" }, { name = "torch" }, { name = "transformers" }, @@ -991,6 +993,7 @@ requires-dist = [ { name = "modal", marker = "extra == 'modal'", specifier = ">=1.0" }, { name = "peft", marker = "extra == 'train'", specifier = ">=0.14" }, { name = "pydantic", specifier = ">=2.12" }, + { name = "python-dotenv", marker = "extra == 'train'", specifier = ">=1.2.3" }, { name = "safetensors", marker = "extra == 'train'", specifier = ">=0.4" }, { name = "torch", marker = "extra == 'train'", specifier = ">=2.6" }, { name = "transformers", marker = "extra == 'train'", specifier = ">=5.0" }, From b24de30e7f72cc3b12efc073142514a6835e7e32 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 12:26:38 +0530 Subject: [PATCH 36/39] test(release): pin the hub key precedence for publish --- packages/lev/tests/test_cli.py | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/lev/tests/test_cli.py b/packages/lev/tests/test_cli.py index af22e87..10ac262 100644 --- a/packages/lev/tests/test_cli.py +++ b/packages/lev/tests/test_cli.py @@ -1,3 +1,4 @@ +import os from dataclasses import replace from lev import cli @@ -42,3 +43,39 @@ def run_training(config, data_dir, **kwargs): assert outputs == [override, default_output] assert preset.output_dir == default_output + + +def published_token(monkeypatch, tmp_path, env_file: str | None, exported: str | None): + from lev import release + + monkeypatch.chdir(tmp_path) + if env_file is not None: + (tmp_path / ".env").write_text(env_file) + if exported is None: + monkeypatch.delenv("HF_TOKEN", raising=False) + else: + monkeypatch.setenv("HF_TOKEN", exported) + monkeypatch.setattr(os, "environ", dict(os.environ)) # load_dotenv writes here + seen = {} + + def fake_publish(*args, **kwargs): + seen["token"] = os.environ.get("HF_TOKEN") or None + return "url" + + monkeypatch.setattr(release, "publish", fake_publish) + cli.main(["release", "publish", "weights/lev", "--repo", "org/name"]) + return seen["token"] + + +def test_publish_takes_the_write_key_from_dot_env(monkeypatch, tmp_path, capsys): + env = 'TYPESAFE_API_KEY=x\nexport HF_TOKEN="hf_write"\n' + assert published_token(monkeypatch, tmp_path, env, None) == "hf_write" + + +def test_an_exported_token_wins_over_dot_env(monkeypatch, tmp_path, capsys): + assert published_token(monkeypatch, tmp_path, "HF_TOKEN=hf_file\n", "hf_shell") == "hf_shell" + + +def test_without_either_publish_falls_back_to_the_hub_login(monkeypatch, tmp_path, capsys): + assert published_token(monkeypatch, tmp_path, None, None) is None + assert published_token(monkeypatch, tmp_path, "HF_TOKEN=\n", None) is None From 136725ccddf845daace5354f3d73d55a581c4a00 Mon Sep 17 00:00:00 2001 From: Abhinavexists Date: Thu, 15 Oct 2026 12:26:38 +0530 Subject: [PATCH 37/39] docs(readme): report the adapter-scaled release on s1bench --- README.md | 44 ++++++++++++------------- hf/README.md | 46 +++++++++++++-------------- hf/assets/accuracy-by-subset.png | Bin 175950 -> 176474 bytes hf/assets/accuracy-per-parameter.png | Bin 102550 -> 103213 bytes hf/assets/leaderboard.png | Bin 240773 -> 245613 bytes 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 6eeb07a..31ae9c2 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ lev is an open System One decision model and the harness that measures it. Give Read full blog here: https://interfaze.ai/blog/jev-now-open-source-lev

-

68.9% on all 13 S1Bench subsets. 4B parameters. Zero output tokens.

+

74.3% on all 13 S1Bench subsets. 4B parameters. Zero output tokens.

-

Qwen3.5-4B + LoRA on one H100. On the six subsets the public S1Bench board completed, level with reflex-4b and behind only Jev and three open models of 26B–35B.
Accuracy receipt · Speed receipt

+

Qwen3.5-4B + LoRA on one H100. On the six subsets the public S1Bench board completed, behind only Jev and two open models of 26B and up, ahead of reflex-4b and a 35B model.
Accuracy receipt · Speed receipt

Quickstart · Why it works · What mattered · Benchmark harness · Snake demo · Train it · Decision log · Model card

@@ -22,27 +22,27 @@ lev is an open System One decision model and the harness that measures it. Give | subset | task | **lev** | Jev | always the most common label | | -------------------- | ------------------------------ | --------: | --------: | ---------------------------: | -| vitaminc-dev | claim verification | 0.668 | **0.801** | 0.503 | -| massive-en-US | intent routing, 18 scenarios | 0.857 | **0.874** | 0.163 | -| massive-de-DE | intent routing, German | 0.823 | **0.871** | 0.163 | -| boolq | yes/no reading comprehension | 0.827 | **0.893** | 0.580 | -| squad2 | answerability | 0.813 | **0.836** | 0.502 | -| paws | adversarial paraphrase | 0.776 | **0.900** | 0.516 | -| multinli | natural language inference | **0.890** | 0.836 | 0.361 | -| civil_comments | toxicity | 0.760 | **0.803** | 0.893 | -| aegis2 | safety moderation | 0.800 | **0.804** | 0.568 | -| helpsteer2 | helpfulness, 5 levels | **0.386** | 0.341 | 0.422 | -| summeval-relevance | summary relevance, 5 levels | 0.358 | 0.358 | 0.458 | -| summeval-consistency | summary faithfulness, 5 levels | 0.271 | **0.812** | 0.840 | -| pubmedqa | biomedical yes/no/maybe | 0.732 | **0.764** | 0.532 | -| **macro** | | 0.689 | **0.761** | | - -lev and Jev ran through the same harness on all 3,880 items S1Bench scores, pinned by [Nimble](https://github.com/bespokelabsai/nimble)'s manifests. The Jev run lands within 0.8 points of TypeSafe's published figure on every subset, so the harness is not the gap. - -- **Noise:** at these sizes a per-subset difference needs roughly 5–9 points to be real. lev's leads on multinli and helpsteer2 are inside that. -- **Where Jev is clearly ahead:** the minimal-edit pairs (paws −12.4, vitaminc −13.3) and summeval-consistency (−54.1), where lev rates most fully faithful summaries one level low. Fine-tuning introduced that: the untuned backbone scores 0.826. +| vitaminc-dev | claim verification | 0.726 | **0.801** | 0.503 | +| massive-en-US | intent routing, 18 scenarios | 0.869 | **0.874** | 0.163 | +| massive-de-DE | intent routing, German | 0.829 | **0.871** | 0.163 | +| boolq | yes/no reading comprehension | 0.853 | **0.893** | 0.580 | +| squad2 | answerability | 0.819 | **0.836** | 0.502 | +| paws | adversarial paraphrase | 0.844 | **0.900** | 0.516 | +| multinli | natural language inference | **0.849** | 0.836 | 0.361 | +| civil_comments | toxicity | 0.783 | **0.803** | 0.893 | +| aegis2 | safety moderation | **0.836** | 0.804 | 0.568 | +| helpsteer2 | helpfulness, 5 levels | **0.361** | 0.341 | 0.422 | +| summeval-relevance | summary relevance, 5 levels | **0.371** | 0.358 | 0.458 | +| summeval-consistency | summary faithfulness, 5 levels | 0.806 | **0.812** | 0.840 | +| pubmedqa | biomedical yes/no/maybe | 0.716 | **0.764** | 0.532 | +| **macro** | | 0.743 | **0.761** | | + +lev and Jev ran through the same harness on all 3,880 items S1Bench scores, pinned by [Nimble](https://github.com/bespokelabsai/nimble)'s manifests. The Jev run lands within 0.8 points of TypeSafe's published figure on every subset, so the harness is not the gap. The adapter scale was chosen by leave-one-family-out over these subsets; scored only on families held out of that choice, it estimates 0.728 ([FINDINGS §19](docs/FINDINGS.md#19-the-adapter-scale-is-an-out-of-distribution-knob-and-it-is-worth-39-macro-points)). + +- **Noise:** at these sizes a per-subset difference needs roughly 5–9 points to be real. lev's leads on aegis2, helpsteer2, multinli and summeval-relevance are all inside that. +- **Where Jev is clearly ahead:** the minimal-edit pairs (vitaminc −7.5, paws −5.6). The adapter runs at a quarter of its trained strength, which narrowed those gaps from −13.3 and −12.4 and closed summeval-consistency's from −54.1 to −0.6: at full strength it rated most fully faithful summaries one level low. - **Constant baselines:** on civil_comments (89% not toxic) and the three 5-level rating subsets, always answering the most common label beats both models. -- **Calibration:** mean ECE 0.115 for lev, 0.091 for Jev; lev is better calibrated on 5 of 13. +- **Calibration:** mean ECE 0.097 for lev, 0.091 for Jev; lev is better calibrated on 6 of 13. summeval-consistency is the outlier, under-confident at 0.303. - **Speed:** 69 ms is lev's engine compute for a short request inside the container. End to end from a laptop, Jev answered in 335–346 ms median and lev on one Modal H100 in 414–654 ms across two runs. [Every run, per-subset breakdowns and what each run changed →](docs/FINDINGS.md) diff --git a/hf/README.md b/hf/README.md index 44edae4..37b96af 100644 --- a/hf/README.md +++ b/hf/README.md @@ -26,9 +26,9 @@ lev answers typed questions about a piece of context in a single forward pass. Y
Apache-2.0 Qwen3.5-4B Zero output tokens /v1/systemone compatible GitHub Blog interfaze
-

68.9% on all 13 S1Bench subsets. 4B parameters. Zero output tokens.

+

74.3% on all 13 S1Bench subsets. 4B parameters. Zero output tokens.

-

Qwen3.5-4B + LoRA on one H100. On the six subsets the public S1Bench board completed, level with reflex-4b and behind only Jev and three open models of 26B–35B.

+

Qwen3.5-4B + LoRA on one H100. On the six subsets the public S1Bench board completed, behind only Jev and two open models of 26B and up, ahead of reflex-4b and a 35B model.

Quickstart · Self-hosting · Benchmarks · Speed · Why it works · Training · Boundaries · GitHub

@@ -88,7 +88,7 @@ print(result.usage.output_tokens) # 0 These are real outputs from this checkpoint. The answers are objects, and `result.model_dump()` gives the same JSON the HTTP server returns. -All the questions share one forward pass, so asking three questions costs about the same as asking one. `lev.load` reads `lev_release.json` from this repository to find the base model and the prompt format the adapter was trained with. It also applies the shipped calibration and loads the matching head, so there is nothing to configure. +All the questions share one forward pass, so asking three questions costs about the same as asking one. `lev.load` reads `lev_release.json` from this repository to find the base model, the prompt format the adapter was trained with, and the strength to apply the adapter at. It also applies the shipped calibration and loads the matching head, so there is nothing to configure. Because the probabilities are calibrated, you can gate on them. For example, act automatically above 0.9 and send anything lower to a person. @@ -135,27 +135,27 @@ print(response.answers["team"].choice, response.answers["bug"].noul) # technica | subset | task | **lev** | Jev | always the most common label | | --- | --- | --: | --: | --: | -| vitaminc-dev | claim verification | 0.668 | **0.801** | 0.503 | -| massive-en-US | intent routing, 18 scenarios | 0.857 | **0.874** | 0.163 | -| massive-de-DE | intent routing, German | 0.823 | **0.871** | 0.163 | -| boolq | yes/no reading comprehension | 0.827 | **0.893** | 0.580 | -| squad2 | answerability | 0.813 | **0.836** | 0.502 | -| paws | adversarial paraphrase | 0.776 | **0.900** | 0.516 | -| multinli | natural language inference | **0.890** | 0.836 | 0.361 | -| civil_comments | toxicity | 0.760 | **0.803** | 0.893 | -| aegis2 | safety moderation | 0.800 | **0.804** | 0.568 | -| helpsteer2 | helpfulness, 5 levels | **0.386** | 0.341 | 0.422 | -| summeval-relevance | summary relevance, 5 levels | 0.358 | 0.358 | 0.458 | -| summeval-consistency | summary faithfulness, 5 levels | 0.271 | **0.812** | 0.840 | -| pubmedqa | biomedical yes/no/maybe | 0.732 | **0.764** | 0.532 | -| **macro** | | 0.689 | **0.761** | | - -lev and TypeSafe Jev ran through the same harness on all 3,880 items S1Bench scores, pinned by [Nimble](https://github.com/bespokelabsai/nimble)'s manifests. The Jev run lands within 0.8 points of TypeSafe's published figure on every subset, so the harness is not the gap. - -- **Noise:** at these sizes a per-subset difference needs roughly 5–9 points to be real. lev's leads on multinli and helpsteer2 are inside that. -- **Where Jev is clearly ahead:** the minimal-edit pairs (paws −12.4, vitaminc −13.3) and summeval-consistency (−54.1), where lev rates most fully faithful summaries one level low. Fine-tuning introduced that: the untuned backbone scores 0.826. +| vitaminc-dev | claim verification | 0.726 | **0.801** | 0.503 | +| massive-en-US | intent routing, 18 scenarios | 0.869 | **0.874** | 0.163 | +| massive-de-DE | intent routing, German | 0.829 | **0.871** | 0.163 | +| boolq | yes/no reading comprehension | 0.853 | **0.893** | 0.580 | +| squad2 | answerability | 0.819 | **0.836** | 0.502 | +| paws | adversarial paraphrase | 0.844 | **0.900** | 0.516 | +| multinli | natural language inference | **0.849** | 0.836 | 0.361 | +| civil_comments | toxicity | 0.783 | **0.803** | 0.893 | +| aegis2 | safety moderation | **0.836** | 0.804 | 0.568 | +| helpsteer2 | helpfulness, 5 levels | **0.361** | 0.341 | 0.422 | +| summeval-relevance | summary relevance, 5 levels | **0.371** | 0.358 | 0.458 | +| summeval-consistency | summary faithfulness, 5 levels | 0.806 | **0.812** | 0.840 | +| pubmedqa | biomedical yes/no/maybe | 0.716 | **0.764** | 0.532 | +| **macro** | | 0.743 | **0.761** | | + +lev and TypeSafe Jev ran through the same harness on all 3,880 items S1Bench scores, pinned by [Nimble](https://github.com/bespokelabsai/nimble)'s manifests. The Jev run lands within 0.8 points of TypeSafe's published figure on every subset, so the harness is not the gap. The adapter scale was chosen by leave-one-family-out over these subsets; scored only on families held out of that choice, it estimates 0.728 ([FINDINGS §19](https://github.com/Abhinavexists/lev/blob/main/docs/FINDINGS.md#19-the-adapter-scale-is-an-out-of-distribution-knob-and-it-is-worth-39-macro-points)). + +- **Noise:** at these sizes a per-subset difference needs roughly 5–9 points to be real. lev's leads on aegis2, helpsteer2, multinli and summeval-relevance are all inside that. +- **Where Jev is clearly ahead:** the minimal-edit pairs (vitaminc −7.5, paws −5.6). The adapter runs at a quarter of its trained strength, which narrowed those gaps from −13.3 and −12.4 and closed summeval-consistency's from −54.1 to −0.6: at full strength it rated most fully faithful summaries one level low. - **Constant baselines:** on civil_comments (89% not toxic) and the three 5-level rating subsets, always answering the most common label beats both models. -- **Calibration:** mean ECE 0.115 for lev, 0.091 for Jev; lev is better calibrated on 5 of 13. +- **Calibration:** mean ECE 0.097 for lev, 0.091 for Jev; lev is better calibrated on 6 of 13. summeval-consistency is the outlier, under-confident at 0.303.

S1Bench leaderboard over the six subsets every listed model completed

diff --git a/hf/assets/accuracy-by-subset.png b/hf/assets/accuracy-by-subset.png index eacf868e72809678654fbc32b25039eb40192638..79a43c073d1cbeaacdc638bbddd7609463aa8bd2 100644 GIT binary patch literal 176474 zcmeGE=T}o*_XP}N!2+V9AQGw~D*ck)5fM-jl-@x_dha!$AP6E|dI?oJp@$YgKtOsA z5D2}OP!k}OcXQu*-OnHJe)x@NJQ>3ea>6?S5 zzP7R9x^7)edEuP2>N9O+?Pt{@lLQG{)M%VY>DedfsLrcJ?}zh3H_~N8?9?GS(wL>f zay0G2HntNn8ImLtk1b0g+g|K3FkI|TimH`g_B`08)Fm-h}b> zXw?9}$LT4H_ot&ts>g2)Vpvp+qUTd+Nll}}elSwWc8u|jXGK0Er(RgYAu^BfXjzx;qNMXS!!J%>(2PS;9g z{j29ezE7bFA?=%BiHl5--7*R#GT%JOYZJhK(bK@nP_rf1kbflivpOAwj@ud@t1VV0ZzMgpbO5vqvuPV|kgEEt+$sj%l)6 z)+&py&or*lFX&eL-zR=Ny++Kpk<}RQ$Q3J z+v|emo(JYIt#2nTgvr}#u9VIre;w89nMGDxWFI2O8#l=%$U|+YBQF8F^6j-blv}$|2vtC>Fel< z(Zf9ptE~0fjQ79Hxs07pUtNH738kkB{qKoHeFygx>W)M_O!yxubbd6Rk60DQTW{^7tyXJlySj@Zs-ljz6UU11BBTh-g zW$+C1`4WjBO0K@ff3JrXk*%T>*i|Z?b!@IO$@J!H7tbAlJKXI4_bVSFxv7k}rcowW zK+wbVS-rJ?Dt3xo_~Cx|Q(b-(~+uTi)bMpAR$3(|`+da1^}N`uDY; zhA2OrEr~liAm#lx=@4Z+KRG(M{(=WR+W)_&-ajz^G2amb5BYbTjLiN0{q32QZLs=` z|NW59c_TkroslE>Xk85jW3f_3zzYgnMQpKel}R-wG>dzVQ0rsN~3d|NU;p z-E(Ar|MT?g|CI|;=Kohl@_%!F{{J~D&G>U3RaPK##q(KMPK=eS7rnX1rk4Ail1qR5 zZ)CKwT;yfh-jZb)$yH-3(7_uPxbH!pU`5^?3DSrkx#Ufzq&lsQ2+iPvX#_?@Z0gOn zmTdRKhb!$OUttl$q>sd1PwDUkC0VCZ?Q#np(IY%%;hWS(^^y-S*$h&B_$-FUS=Dka zNB1^FY)1XbR!etd2YLiW%tz8tV&;Pk{7&r@Tp6SB(-kC`RgBBz@NliPJg5XPqt?zi z9?RZ_bLyFLY9bYjc5#@~J(NMQl@4O;i~Clz*vt(p_nd$m)GciD6^0+`JQekg2U{l=;sOb)S<9rt%}Z%R#iO0aduEue(W zoap5!GlOL)Bj8JnBf(LS@{4fz@OAuBvdhM}P=)=x9Ggys<&V%H@QQJ8gL+Ifmw~avLTAOhCa+TG zbsWO?x;QWT9o3(=J<_<@yEa`|xee)nNf1=79x!o(Or-lbwdFAX^DT&zQr>WVYIl1S zo8`}=1AgzHo(U%?UaElF)1NiYV>u=dX!{ere@c_1g6YND{ZF<_`OF7LLY9Y{W{O?6 z?h{rzdi26l$mx@69QV!#+Aky6?#8Wgg#PsPa)cAmCk8t3S;eASq33A;GK2EPA}|Yv z9c!iEd{JBjFYfvANC({sb~osfOh0h=uol~gGssZ>0GU>!Q@TM$!)MQ2FBipXM0%$a!DpeaQ&MI* z+TI=mpYlRYc5n=2oz8oy!}Xh3)$?PQkMW}}5_lD(zTtc=!&5#8bwn@NgRToZ6}$-7OMeM*3*L*EP}Z1cRV!Tc z;?%8dun)w9C^lb&kuoG&Tw>M@yEcwWb^W3alsGt?Oc` z2eNb`e{`{Hv3ht*%@35+(Egc_srru}AO7Nf&m8x#Io1&gqV>szc#sFHQIXN=y(=i2 zFfXVd3FSl^x!QD70pGLmF z%;0JI!vU6U=h>eTcqcSjEVR_~z?W@kK8U-dMZju|0$ptQh0k)N%}*$G@Wm;?M#^e? zF7PF(sXAPH-s=vFaY zSTc?Qg4v+TfN@tkM!(RqDjTuvfI8yYaEs^tZJQv|OTntzws3rmD9}N4%YA?R?spi~ z|6^6Jm@4PX4dtrmsjtW4wTkWie#twu&h@}XRG*#D@{llk?Vq5pAy}Hj>QCa0zcBRm zb;(EQ1;wmE)|F~q?K(JqeWi54D$FA(UKz>Ex2Wf9Zg_F&vwOgGemplT#s{ zxBU2q;6Iz<5HTLl5iI|xMQ4xoQ=S1*H(qmT2%q))s!T~=nT_L4m_$$1c>m+?nhzC@ z29ERJr1~TTEz~#oS(h4DhYLSSax@?8w}R~w9*ec*=~jI;YHcHL8t=I;{nc35=h~mg z;w}XawKURO0Ww_Z7*%FE+TIm>%h7De+yE7TjcJk_^da6^ud%7O^VVRl;{D2u7%Wt2 z_2Xup+#Av`7#S|mNylhNcJFT)PGAXZrLbd-$F2iyaVtX>l?Q%l&=WG64U+jIW!FH6 z*x?NLa*kt{Py3>;eC}O(<8O__vFwE28H7Hzw(U>w5d&Sx1;`Q0S~{2q81bq z#vcc#N_`p8F!0(qe@@I`kyBR7x?fi~N!Z!0p39)Fv+lIe`|W-PxrFcK<0UV+IGgImBsQqQp70<_ck@lY{51PY{n=X1?@#Xmn3C@2r zbxQLnJ+@rK;H#Sl;kvBmY*EB}FE<`N*y!h71&Ba-{bIM1Lv)$-#KV>2y7kjwDzBpi ze1So|c++~k%a1c8 z9rX%bHyR=P%C4=(FG3E+CY5^WL8>zaP6-v!(a{0|x1rI+a%IF(w-QQ35>;}lKzwN$ zgBthV`y1`_`D)E`3j6MwWu{Nqv`RixZL7LWzp{=l|C6IW);^w$=16dc6j7;E7TM2} z=pdX6sMskhA~NN)4z}mx*ogncX_(;^AQt`kD1W>67l;uNvB*6Am&b&?zsURdOaI@6 z|IEbyp(%+rCJOuTTKwR9fp$4-lT(t2ONG=8vF0%ML-yUc&o!Hkr1|c9D}Qz&X({ZW+S=zlralpnFi+hPp4zRJ1Rzt@UPDE3=tO^f7?ZD6+LG+HFdDGx zvAZPsHz4M2X&>!`$y2*#Vhb<0F_SWCypmibA_gLjM&G-uB2ojlBE~!q;xxlbkeNT~^li zQ{ng!YW_EP|NDiDQ35rqg(7FbgSwE0*EFm^v-n>PrXe|4$kcumkdO799*G`Xy*kf> zwaQud(TtaoYrZ$cU)6i94j16&V+=;C7LyGFdnXU)V^aAITdwI;+NN@7m$h}3zsZ!N z%rmI3bJ`gH4RD!pV6239-7yZ0t$6$MJhr6wObU!*RkQDbj=cM#4KS*qxIXjv4+R3- z%;6o5cpZ>4-izbl^(Q4xtHUOhh02*<)zf8ycfH~I$T8#YM9QrZa5of(O`ND(2^rmC zURRO`3W%>*eHXA6z9$*$<5dG-ZQjK5{{s&-^mGyi^?Gyq&udq4J>toKnl9$~(ip-}BcSqR`=&66SBLT}0LLuOKU{=)TQ+{ygMs_X7Z`WNt7j?Ft@frupAr1mIAcu9xM;aQ z1fYK`b|ozOthPtxxxx|EcrAX!h3kThD~3&o@J;9!Q#u+RV@v;4?Q(N!!4mTSM#l?^ z0)?uzMc5ZtvX~BTT~zg+m;MFgvqB>4|51i_>|x%yE+BWU`%&qa;V~YQe%yTkN)J{$ ztr~+E%pwrB_P1IY)x9UBX=2n%T3e$mtz=Y|eWY@G`hUf|_+^~*~Ta3$EkHqOWcL_gP z09C^#ya-kmrzZrHN(HjEESQ%}^J4zn#U6=P9pi=0xLLkL26DUO371JD4ShF1X5U7b z0LFD-qyF?9D5Yx6>%^pYcB8dyYBs9t$Wz0HOD*6?&Y34Y;)HMbgJkQts@V{c_4H8j zZrdcEZ)O8OG}X=Y4)$lgaBWPXBVZW~F$hWDL+70?fl)9+46Zd5T^?8@SCbQoOiKtI z-Huy%x8vFf%giBS(yIgQ?TBz?VFyX+@;bmmL01-^ryp=uPI)58Vje5qUvOY{sQRo^ zWuJ+tcl%W!K~kR9cLEsa&UhWSsH##dq^$FqS^W?B?B#(hw`pbKKQ%1E@0LkbzCpbg zIm!u(={gqOZezOdUT}j!d^}h^Fvk6p%aZM9v6KDVPnxJlEA7&u+rJ+>X=+DD#HO5}FeS^Cl6^zKX3vD4qY zCuyuJ`$9xET&dptnNv6Na|)dOrr&JpmKp4j5J_p~7*%KX@6SGiS~NJ5Dr6BN^do^S zGK$gyRah?1S=Cv0xU$-S9t!Z734BzQyr#7`@LB@>`w?sfmu}6Y{$+N2N7@u)?ESbUR4y6R{uZqeNRDBfsdH;dfC@9jwGJ zO_JRz<|%a$*2O#BtF!HKzoeL#%jg~lT#bqBkY<__cG*~waW(SudF3Zu{EYd(X@U`P zvv=;k--T(iBtR+bjJ!Q1jlQZbu=A|&d4Y)}#>t@`lSV0lgq1~S-*!*EP`4_8kX^h7 zHaN+(2g$B8F9qPwZ+0>D7te-UQ-m$_Y%aQ71oc*=UF0f1yRs;PWg^6IBeUeF#X)-@3Ha(c_AzhpT+ecnbr{uk8j7+uxWju( zj!2AY1y=34+pKc$Titm#qDEyhOP6Qx~ke zV_%Cen_z2qDo~mtgO_g5&z<+R1^2LimaY`hzPPm!x@ax0- zr_)~;?$hV_F91?72KJfxYl-9URN}RB(d+VD$eSavgm$)YrVxzhj)K4qCBd$s?NJlh z7=!mWM=~^k8y{v{L!Dq}K$~d;Uh+CMvs+P^g}b@;@#mpD4ISS4qiy-;DOoLRhN0_b zzyGnDd5%{JUWu15Y57)fIh;?8>yaQGukJ5hEdCU#l9DB);0fMHbxQPcT$B)Lwcb6W z{D1DZffP(`r&r^=KJEe5QJX5;Ogs^#?=fVhLvphbdAO1nO|=gTTzKq$Fi(X{v8_w6 zkcRyRng3Sh`d1n29A540L~TwNjGM+(TU;KzuD!-98f}cNUR6YJ4dCwb_C(3B=6*|6 zEz})-sBp-0+z*(10Kr1<8ZwkqGWFJfmnw|zB5&36`2W7gYk%+W>^$GIrXXFE;O-+C7EJ8xlv4rP7fP7q7E2J8k`M7 zVkG%YF_L}R{jpdp*ajwUpM0XhS`8Q0p9rH&^IKN#aA=R55U^Nl4O{X;x19ytxI>Tj za(^b1wa9Wt`fs=X9w41fkBImpX9Q%^mfSeexR`Myq|FhHh&}Z2)2-V zl>wP?b>1+_f#x4Z`;)lqbYnWdzWz?SdmQ+P9sy?dp_pm^>Yyo`-)jg9#oRG|^7Se5 zMfiPv(?O;g@nV@PW(im5SY}A$;g5K{kM}g1ofeZ^tlyeuSgnHk7P`;QE1+uZK%e<_ zp-P!3JN%_~McTTi!&@kB^bt9_5TH)xw88g^>@fgCxxT~JkcVn$Rf}v?iXHFy*Tn#2 z+jw1Mtv8^x7B{x~2UE{6pUpHgywNvg49NO`U@~pcs4lF51R6ZnKmeHIk|OT7ljpT8 zMLmJ^fL9s3?0kg`svXlGCpa&)E&-Pafpi^XGvQL26 zgXPK$XkZ#-$x2+4@%XF{2*Ol5qqM_P>SbBoENn8s_C9DBlUr(pb)6BnPysGp<$LYMk2@Ez(cC$WYh6&CRIgj73kOs$)B$=-z_Je`q z62$r^4rbTW7^(Ce!;KbNXl#nkKxdPaLV~g72Z`kjj5XcW`OB2k!6?aTe;J`>lCLFl zMw1&gSWGOwFOe6e>rk#UDP=a%H@7o(Cj&}o8W%>oZp~c7tF#Sfy@mxWl9Bufkq|Gg zaw_Zclb8e}{{Z*_Dec|^ZHyap*wxH_uQ-m&ewt$LyKVpUgny$KYf&%Io^RiJ34$#p z{A0WX8|dexxjC*37Z{crAM5xlFcWzn*`*}8El~fBG-42GZ$aOb-*bO6VAWTqJpe*8 zv`;O54$+=SOw8-BC=+tuwEuzY_MxrU1=p}Dhs8_!3_T8ck4`{wdFQ6!+7^B#n6`K6 zdKWe=;uYxB+U+1eJT!Gq~za`1hgz|f4!)8MLE{-MKt(ar5b03snwd=8?*K#@lX_;b`_wKdmLp(dc!m=%6WA{r1;}Pitl~j z0MO3$kZip=oFWP38eG{Z&>(nB%jzK37mOsCa6U^sS8te7?3$^@GW5Sg=WhxqTyQ-YU&>LBnrMkiM_N4e8p9`gGpeQ);n(WV;`ca^*zXMcM= z+pTg2W|bUwN$LWDT6^0Ujo@KjpgyP@Cf?4gI@(cUZOW z-YL{7HHH1&-ko%KUv<%n38HqJx8x!HcftSeg{S(@o<@@Tv?t{3s^K^K!)>! z-}{l#i;h$~ug7~$077F4I5;`pYP>Ss2nA@?{lbAGZdUp7tgnc*?=q>i+wFP!jJNQ?!WzCXP|fG*+M;awD~JjKXhC~Kj#lY@BN5*)DqD%E zDS-Ma*@fp03_u<41yDKJYvPAOg5^?g>Tr%q*6yn6Fsm*W6WCLbKD7!8Q;|M01R-&H z#Ipc3=}BJa#3J!^Y?RqTuGTf{!>{De|B$PNy%bH=Dv9X;YWnyIdt5Z9-XFgIR6l$& zOga9p*Y@0Ra+C$2>)duT%?*nxaiwo0Bi%X<_h{H_d>~N*mLqqcK$hxdm`l3F z3A8nP!{~@R-7iv~h3}X?0I!!B;dDa#tPU)qk*TJ}0eth|Q;5*QT{dOVUyN*wTpJhQ z;IRJ?zQ9jHrC+!X(8D53X!>*W1&Gq!zWP%XU_v+0b%c%EC_@TL~>M+~>Mk^#yKpyfgO@rrX%W-G&P{+&hHqyGe-|^r{`5(*?^cc^CaS z<0B1M26LQ8jbd6oF|2B=vbr(fdRV?cyA#z)*lY^zhYxH6T{SGpzWw*cKiGS$wNvu^>3AmOz!|Q{B#Y)lA`pKQCooWtG}`v0w_${&Sn`s#8in`&coXJ z{TX=;MXTMVCr^B9fBJfFM<3^$X(pP^MlKT?LM2Qgf}#Tig=A6YP50mw(wO}DG-zB! z*5qaB$Vy4x*9-PKzpAa>k&;2)IMeP_%X%q z$s7E^W%pIsLxuPe1pz+0dW$%7uQZr9{d*V`=jM-E0Hrv!!gcFCXbjj7E`Bqi(=K|O zY9x!3h$MN!5Hm5K1_OIs4pwfBg#CFt58?Ci6p$zHKU;jf;es1A(E@77j2nr^Y5`&$ zK+kSly?QU0@fFi}eydwgZb^})uUNq(yw`G_x$2L;T8yg?ao0PJ=42(m2UymwhvqpG zg|M?I_ri{O-BpF94GpOQhZrt{ZtJRfV?4Ie&-cPr4!G%#L4eHW++6eI?T1IyPj2`x z6u3?MEdsSJVw9G)zszhlV0D)oRCG`z3`Jh*-WZCPL$s~r*^G3kvq=s7Ps?SY{M#$*Y3I=zkIY8V!EcG#Y4B1cl)J;9?ypRhA7Ozd3x`UFs7%#+!!HanDh$0+*Nc&f%)f+!C$e^zES_ znb;5f_KZi!OUr%fUnT%SA~(w2s9xm+cY2-9AJ6tr^;!wreV?e7U>ahKfrDG3ZR3`H z_U`*bCrDJv8>!&wY5Vt|1F?WB+G9D!j_#9OX7E@G3|Lj;Uj=*misvgJ0In@0*mV69 z8sbA8HPU~0dnLv9dP%NYo^~35EM}xs#h>n7WC=F@s`9bEP8wuEe@ z^qFgiEu)D-4nP)5lP2Y=w0Il$azR(+zck<}?*SQ0YRfDLNbZ@#?j#YToWv-|UX$4^ zLhsWbz!>%kxk1@`1d#iup1iPGe;Vt6DM?w|{4)i7S$=OizEK1q@b+!2#$DGP(k98yW&`y^WV&1ZcG+G3}N*eggk=%8G=c zM|hQ1fR%MTT$Y~PNi}r1Z!^MD`vfALzIZJ&g;j*YAGbEj)|9D|#mRXsK!zy_$hNe0 z(DkwM0dF_}R#S!yUi{$I!&PZ3naUN9C8}RM{Gg&{~ z1D{u^bOrj+#llD8!6PELkz{9#8^FB}xyl z=`yP3#P#+vv(LWbs53DYnoM%h$5iaw{9Gi@r8nC3@XDF?YpBf3%&Kjx(LT_l3|IwT zo%hhgM206m&w0m|L3lXhuVxyJ7wXmQdat?!-y+Gf*O#U3>pR4s4g(gvz#BggBHwOR zi~F&r*iL8ZdbEyp`E=8lni8KeD$@*o{6?$HXWcYtL*OHv;;D-w2bCWRVs_iQ@$*&Z z!)22Zkcpz-(F{6gP36kRq~DjjO%LRpPv{rEm-c`vCn^I_eqaKZ?5eV2NdJGqRRf0Y ztnFs%Cih7k%2@;`7kiTv(6>u~7O9n^oXO5M7zWWUY!|Q|kKM&AnyaebaOV4PNy)I> zeVuLdicQ;Y4#gl)5dxNe7Dh+`&QU0xzA4S*dUCJ`3)t4H1F~2TCvrF98Y(CJWV-`i z1hxZBR0j!zlKr$FmFvB3spV7k3wUaiMCz@5U~{?DeM-KPogQMB`sOCG2Wa%}l1;j( z>{T|UwC7XydX=_yq`lAdypPFnD|v8Y@%l!ZVDrAk9ByaHU9FSNCVZS?Vj;OIiR*i6 z!A)6kZm2MnZ|w= z2Xh0vlYIB*fz})-9EgC34Vlt#B(msLm*G7bWIywyDP7SpfJRBDhtreZVGn?GC)%|v zlTUv$eXan+b`G{=C~o;0bGW^aPjZTqR9YV~>&rWk?(8RrKoTl;op9)x_>}(Txfq_( zQJU0*Vrt382;fRArg$+r2MCYKjd7;eC5~)sz-B4gy&HU3g{|}8LBgKFHzsO+)xI{y zO6a?b^({Q2LI>pg-_@LWY89I9sVHt?x0+{$7RiUo9Zt z|LdO#69vwZ6z|iM!Y|&H`OyM9bhZuWK1F{05-oI_FZyJ6fKkBy9vkmsCr}&6OFu+I zA`RT;GugXf>Hhsd-y2JIU-{jDR>QpLq3(Hru^&>?7*mp^GZIoTn&*ASoXq$lUGGex z6ZraApM(ksmjewYj>X^EG`cysf`tRVoR8H!r`db-?Dr3QHK5YU=;E!0a-*OGtJ4N2 zu@}9fBI3ajE5qw|S|(KUUr-E$1;lL77N?UMdZITqu&`P0LCSCv;Aqa7U=obg9GhzS1p zkXZa=KQdr-u)(eKNg&@{S&#g7LN=A#V?I}q79SOcE5Gw^|0JExIP>Z92I8KSmwmkn zknu76=7TR#r1bz8D`B&go&jAaf;4EOauyd0mqgB8CWDw#>Dqb?_FV)HriwEi695H8 zc}l*UH|}mCNuT&UV?nm+*dTwke50lm%#t=Pd&TQMl?A(m7FtYPm&=e&mvJMeW0JX6 zdRwt=Ec+((dfx+!&o9{_TRT7ps_B6nbwq!{=V-tS#SZ3fTf3QLW(-b$aS4Ddn3f!9 zcJSuyR`1f6>CxFWPd}l-Q#LrQj}3_fo@HaO`L1)b5cG2~ho|W@nQ2dX0+KEEHz#jj zcWq)>B5bvu;}k3a?05=FQEmEs;`9XX*|{zN;%x~Bnz+t*vBRY$0(XJo*d;Z8tC6Bf z&@B-!5IK`XnFwXqd=~uvcnl&ypB2X)?_i8u6SAJMj-pmhFNZuB8W7bMDs#P>G)>-9)$C{Hhj9Sj;fp2-eGp`VN`wsw^8m{ z2bPbU(7_oOTn(|~b69wV$563rE zvN&O9?$!My>p9npl5qk|o$LT~(pO9a2q!+_x-Kmo@9Cq`OXR@rzq1$$yL7<4B)8DBMzv_UFmdpbuixPgkPX_uSKoT1h)0xyi{-C`r$@n00bJ}e)ug&X!}p_5-D?Z5v@^TTxWwD zY+JY_5s!eXRyE%=_(&EkrCQvM@A8~|(juJBuQyRzTF_=^}_`{F-D=Bd6^AkUOU?#oDH>*Q2TfH+Mi zy-%$g9qQ(y&r(-m)xy}B&h-?araGtP{$GDyj1fLss%>=cfx_xAVYHROyRy}fXRFu4 z9aOz5e>?kgS{Hd6^nW}Lyj7S#3T|d~)(bw32MSoP*Z#DK$ljpJU+2{}>q5%8lk{#8 ztZoA6x)YF~GY0I@h8815sY5v`=>C4(nnJx=p89asYX+c3BGt0r{6xY*lvTmNmf`y| zss+#`FzPHfB(7t zl{~I>RH~HKtbg#?Zff#Y$zNaey@5f5Gx_U$IwH;oUfgJ!3Y$r5aGpdLQ?O`I@*xl~ zL0;L@Zp=n~H7ptIap=LXMbNhr1ZZQ}zxm7^A%3`d;mo`Nx^RL61nfw06X^4s2r*L= zl7X3~8aC>dw2FcwfXs-cBxENZcK10SHjOd&1Iu_5XOll!={X5c8|kkU<-qR& z*$&~$(?El)U)d&2HXSq`;Ffu^Dx+GG;S zp#&h+#HCZ-kz-7%)Mb&~-lq4M(-;H)k-3+VR>S#m{N5*?z>=OnRG`zdGL&bcSM6MW zYt%A3md7OIcz>2CLCm6}D*=zNny4Nkxx>EX^Wr$zu-XX$Qc26PE@wb_3^*vzd#K5qd*YFgURMCW!$^KyX|0t_1=@ObuwbC zLIS@X@kbBeYD~q>kweeeMVr&3k=fUk>sQ^H4uPEL5=85+>5->eRdUXQse9)f(Nkw| zT;|*faKwv@=mS&TbiD#uvQ6z)HQB+z;_hmEi>c-~Xq6#1>lgLlm^Uk8g&o;S-mYY> z66igFaZ?asMbD3Lt8iSuJXdu+r5srrk4d*pnU^49HA&PkQp!B$QBq1it$U zD>T1LlKbxExOqODV&Z<*FR6D+zo-nJNl_~UawCo?$JA+(onEGQ4V#bNnr*4F{UIF` zJ^aH8-9Yd>9@4P(*pbZ)s4(QKUge(p!mw7-!G$=+OEi?2_oYeWM$$top9&5(5|fS_ z0sU3~LLc0@s~lSJDvtY8PbzBf*CGtvs{fYe5c11Ac+v|!dAKVy86vpdmJK)BS?F@c zis37t{>&m59IJnoz~8k|y`w0ynqP`!tV&>hmf8oezwT6z-+-pk#O)Ypl&UKrM9U2d zl!fd+DC&=1S5`>>J~(yIg)-1NJ(<*m>$g%9F^ba&SeJp8?V^{)B99*iWM1sOlygNW zW$YF}fh~8AcV6q_HGCH)Tqc&!-{O;TUU&b#Dp|lNGu^pce`5bglGWFdV1*b<4;8bf zWK}K7e{%r~tR|~osBBt3nV~`zv`6yS4L1`H$*&O51ko{hEqW45Dkn_q<=VWH56o33 zi^MO@Rl7-o+n2|yAIS^6;{#yuk^Tuv|i$49W}HcILR zwA3tKtFb|0H*~d3$KwXI7wFRj8{Nyq#LXQV>@L$U!oXCG`CT15sc~A}fb>$5EDK?_ zqa$(QXMJ$BY|VSA|Hxrq!lieQJfxmFoE%V98mZMdTd}ECJ2tPoy%TBUI4m4GEa>Zk z_}wY9zCd)JC1tDrHDxzI2}EH6ApS>IADb%O+y;VOwLc1^O7y&jt{HyP#pduuBxB?w z1$(kk`(rWz&DCM6ej61lPrg`wtKm*R9^rcsF>}?ymT|@vx^=w03fD4?O|_6z4zHhB zSAu{Gljg4WP-Gq89OUP^K*dJdE_fG;pBZS^I(d3ZBx-Gq8b5Ev)%lZP2m!;ZdSWxM zz4IKwx0I!dOz+t%?6Um+cS_525NDkr za$3uX=o9i2!;3N?b2s#RG0A+hMHg0t&xT6ev;7b!BVA@yllLHXVW9Wqk-kdSD?16D z_0rdaLMgoFtv6mB6TZarJDDG1#XNA=t|{yu)~sJQRa3SDe1#l;u(s1P-UE(;)P##p zQ;^_=PCfB8r0HISp^t0Ab76Wr*Fqp-?PpkPs{S)MuUmlJ1GBmS;6(&`OkR)ai@6Ph zv!;i|WU8-);MGj}auwvI7*>6z-^5h<6nkz%2{=Gz9qJi?q*UnTrEY2+Vu!Ja$Kyr8 z@v9tw?YcmpW0jAhoP@nJmHf&L@%@hkJu)>=VjLnNuM>Iu_#kGt-bH;DKH6l`<-%wV z>L@cC@|wR}kLR;?17`jHC@8B|Nyhxcz1S18&9|uijD8jO$(8xhY6TjR+*Kv@7K`UM zGGC^9?@wRu!19gjq4CwR%sRlox0BR?7IB_0BB4~(z&*LOs5VIPL8 zOF_#569D&{qfb|Y0Pvh+v43jR#>H>c{^1OPBs|ccZVG&qMC;_`>-xb7+Rido*DXx2 zTpi4DICNSL&Q;2FHXCK}RN~sw1bv^iXOUeA{5tCSdNmJ^@zqW%&9&H*%d~G16J9k0 zB;aV|2$$vlp>EOD{N0v0?@4W(T!dK-n@(Y3!6r^)4Dmd2Xk99z3fp_)*zl3TaxJ#l zF;k)LuNGh}cGlhkmX*nsA-KsG7r}9>+i?f0a5L+E6iZ~*2w2@(|E){I*>+3!YJS{QMyNtH1#i{adP@yO0+itDX> z^}k=i`wU>A!)S1nvg%kFIC6Q8^rFstEYHV`V^7@qhY2-6RtzN|BM_W=j$6#s$r9m4 zG&hJ@W}Rb5EQd5~1M}f*>K!k>TJ#+@0u><&05Jm+TE}MGJ`W7vo7 zS%k0-?E__Q40x<9{Sjm< zHEUnl;Pwa$k2hJgRk*P_Yijf6ba5^#CXyZt_trZkiB5?(kIa;wGmNdJND6T60wyY)&VB3{ET zU7s$~eUPQK%K+znMQ5H&!(cMIipiqC)!1SQ_(G?ri{b9DF)DLjZX%+#fR7JD-!P5R zAto0TTRhFDRGE;9_JH^sBgTPIG_nS4{;@2KWPCekjsUdmQfoMqOl8Ca^K7+r>00#y zU9+B3>_LG3w(z?lqs=Kv=e6R}wZQ?!4%=sGw;7JbmPd-y^U&~?hBs`;#o^zJBgKa6 z+iZnbjtH#jyZeTrMzL+0%-W7h9L`Znzc~&q0kR7T2q!hC?VmTnGJ;MHgKegXr||NC zNhY4hefP0|lHpBarZX;bj7gUrZldl|xp`9Ucq=^!lF+j{(8`DTqEl-cP8fG=Oi>n( zC(;J?%##v^4ZdECXGg)ON1DYCs>SCoMyIUxafIAhr=kBXZDL9*o#}DbJ|JWy!nZ7kD{y>XxJxU#nQ$+XWV;HVLxNp!) zx+f=$cWjkv-342N*T;K7S?RKZ6y4Q~S@U+@FJUG2=5B9PN#%sUh)I?5-fF~=GARx& zx^=wj$b8e#7X0R7ciShuytg2B z?zj~r5J+-UxV)C;MVJSFlau*_KIslsGDG)#n}G#|Wo&C!k3N+aUB&vtYRlQwb*+vU zE7H`+w5ROqj~7&CQ%z6fqFTK9W?t?21O?tcEsInX7g{-XtQov+Y6)N}Y6)Ux;{Li% zAAU-^;bv~)nOy%vL7w42rCxH)|5fm=(o-Hc{K-G`4oGbMW{=)H1r!k1Zd)|ycz&=! z9vB}k&H~GHSui!vSV7ETT`qkQm)hl+tlCYJp$(_@tW7Nfpdhvfpbby~%%nQCyfaIm z2v`TWELnI`qrMG0#3}<%579Sq0vX2IqORAFXk7{m%$V0Y)R?(Xj~smT0DCEDIqzD z*AKm@dE6aCF7gI$$nJV!ys=_bH$T&tnjf&dQYPXt?!3F|q4!}iQI*}rZGJvx!cP71 z>ByVa&R_w|_kvk}@UE4&vJbC8h5c2VPTpcYq?jphSWJq~*!>nnz0o{sJUxk-wgKl_ znCG1GU)Ey}omR)keMuTUg~faA@2(eUEGDBKy_cAkcSJ`#M;)(O@{EQrO{&e-MTakR zknoL?t~>Va=-bUlku!@og`Vnr>_zP|N*>L&f|KT>$2UZ$gcTmw-he_6y@sTdu9QvQ zAkn@hG}&FamUx=Y^Q}%J*M0HG5D9Gql3jA@1^;f;iQS@0{TLEI0h_LsSvA_nf5APe zez9jBJ{bghsLdz%qaEr(m8l;@ui%E8Q$L-1#PBkn8z5oGy|CymdUN772V8WuD0hPp z;&((uYdPQm4H4b0=uxll##<#ZS7ArNaqSB8vpJVhCN8IuI*&1$ToYg2Gy@nA98;ZgMp zU*vD)HOnSY$H;|9%oi2aQ`B8t+IqN@{vy5(sl5o3?k5-zGYx)ap2|G^BhP{zV}N9_)!yvJk6X4 zQvX36eKI|p+LP)i4wd1km8)sDS1vPDP8I~M6u>c|=0v?0w^qorCJnsT)vy4370x!!j^F4oPE$QkP-S_MND~eE`B@p3!O1x9W~~mht_-TWp!ED42e&! zLDqZQysdi7$1Zx<)@0rMU1lZw33P8o&H8y9A`#B=fNN!*fAVwAMN>s`Vtfqwl^&49>@P_+A$t*|S&M z%%}<<>`lMz<|Mq-`%a@W<2M#t<$?-G$x3!_=Znv~ob!zF>J0&V`%%Rs2aR;!VYPLt z+nF*~`HD#{`g_3PriI2CDg$>RDc=N0 z!%%O5Kj)bP@sZP8rG3%g7SGr4Te8*?>HfK2=)Ia}QZWl&fW@5x86{%9`;ykg^;@IE zjmv~pU<25yOHZgi{ygl)(Q`v$zk%<4-PWN6XU6c>=emxegt}N4%bd*(AUL|TW{gSH z9geM1qg@|V zGbl-w$fyO>#gyF`w3sNe^CdMN4APzS76z1?_CZ#3&C*Ew4HJrprQ)$@Roo_(&18X- z#=FeA+ZIE)MuDz`0tC{3#&4L=d>iQmuM&yw`~R_bUSUnGZJ0*fh=RbjB2hp^iXfms zM7k8|y?0c4N2+uzfJpDsyY$dI0TiWo0-;BG2_*CYNnk$q|L?hGj^}J<)}i4tD{Fo2 zEzkXU{in=**2RhKUT#s3a2!ScKD?BuU)^D1FH_u%-5XUFo3&>m zqsVO-R@Xmso!JHukfve&d3^Dvok0i;KRIi0J$?-}hKs6wKySK!PkN8ehVQMlqqqJa zviOtKYUSdqWrA|AQrcCglO@Rem%lH{l%5Hmj=al=pv>?-OfpLQ)*LXumJ@j>8XN?= zpssUYzPDzaNUG@Tzs5@)zjo~I&TLALJlTq@9^FYC2mxBP)q#+M_oYpdo~yq%2um4g zj-j!Fcbu)A4891XeA6pwcjc2t=!zeN;Uu_y^W{M=((Iz!Oy-tHbDc6_gDmdE*k@@z zc=qzCRhlB-hWudOmQ)Tg#S5&G;+S6@YTM-hwoas;OSto zZ)|-BIsdca`#*>Y!aH_G(rGMsoIJi8hhS~AA zrn-tQ5@g`9nowt}%lr0qsOT)Ul01)}CEN1@LJl-f7Gp+TD@)QFY&M5w$yzsqtYY3n z?KW!GNi;=nmo;w`?N5(Y8C?ihcG^Gv2+1eDRKlu}@9lUkh9gJ4MNPaW&FLVzV`4egFQ(}?^S^B!H@sX#jAF__q}^_3tJx%JQ*#yJe%0LY}8 z)8P5^re4)-NQ~FzqWO~*1BVbc{wO-=%fd&UrgNg==voM$=+X8?jJJWV=l_Y{H+bu@yPX?+jgm)zUSr zWry-MJHTbq+UDHRoERy6);e~bXuFdqV@H`p$u+jS&={*Tr{cN+_P;c8s#`n=m)zA@ zNrs7(tkt@<6%najy4j;+dhhTaJEGavgac=h4pE z4*SXBzemldLoTrJ5u;RYB|z+i!9-@qS858n(DG20;O$?eY$_s^~42^?CN|f>}dkh zrG8k}cL%r^W>1aoZfjhM^m>7!VtozTJ-i6v+*M*``1@=8sc$L{eqH6|VkAWK%i5?n zg$UO!ahvD?`yl%u$4epja80YLU})w0T}LN>1N;r>i(@`gNxW`pXx*H3`GCmHSl4>&rSFvp3M&w05r!pP-EIz^e`&CGSU1oQ(N|rP2mtaCz*Br8-tH+b^ z>WAhY)AFvfDjm;bzet^7w%@eRR3we#(2n)bB+2h^I&wCFMz{`pTZ$*yWPBT!|8C)0 zpK!!SY{7m8toV#Ro1~vxUB==L(&~T^rO{2Vb7el~Po+ys8hy8ZrP1Pp z)`x6C7VDc6p~hb(>acE@=iwa)=IVPDA8RwQG$My`+=io~QW+@`{DkY>U?COLydvfX z8?p5~&P&XWcnh*~rj+)qr!A_e?qGWNZ+HhH=og%A+#`A@kt&p2AStgqU%UhZ_Ej!( z;~*5DAP*2X6eL&OREsL_W|4X5 z*e2~ks^()_0nl~C@3iwKf@?9AC$+CD*?Dw}*i%bTIHq;2daoqv$gUgBchG97zg)L{hOUEibJ zAS;kA&%_mY>fanH$ddL~z-PZN`0;}=ORGWN%qd?LJGq)(m-;<@Qk;3H8g4ROS7v(| zaVnLAAzXWXf?JqfmM_wbm|;ZkHBAa#qsb=5Ko|}hjBZ?iAE@4a|G-#_X+nzosKCXk7O7+Ewvo(;EM=!%VCjJu0XNQyah5m=R{raxLW4 zC~fptGNWo|*HoR&uhPTr&cjW*_hMve;^>%&E5z$V6p!0+vnPf(N7ype*ciQhl4kd| zq?q>zGEB-JrAauNN7z`y-)i59i$C7-fym_(M`5Nv(4>(}u7;U|ih#59bIpf!4X@Ej zzF~LU)y{uGj}hCJJGGcqb;@1t8sxbZasjj`LwCbFU(V(@aGll=PYOw(UZgVHL}qyr63Zy z)Kmy0@KQLxSFt?Oi{!K$J8Qv8*|D)e6EsA`M8;iNHp!1&Ea6ix(rFe;E^td(yHQc} z;fJH@xVX>XrL4m&p<|X9nl$9EzV4fYCvnJvxInMALh`!WH}FG#)cbaahU1klje~kw z9SO8xtBIFTQ^5}fse&_oLmc|V*cPR<|!LPmWZ5*_rX}M zqu9<@sI#QY{UhdF!X>+5zupY&d?+IxXboPpAr?#nzSZq$u?~YZb5Sk=EognhjA}W%A&QPOF3%o zIr7cT&E5;1Y8PX~8edTfv72P`1kSrubw$kX4c-hhJx#5Sy2KEFr;qB?^7hmxUBYpT z=C1VKlSe0MInuuUT6s>=A{ZBr)Mzt%TYZb+pZ@-uail?+9sIsJ$4uDq(!o1D$1b-E zUA{_B9lOw(zuKA2$cOaC5@!=*@zDzp@DcHE(AnHzoR8Z=gT6vKa@1bWGfp#C(j@4j zCgVN)Ep2}um3&>DC^wHgKKjV_Wzj9j|8R1)_PP-+wxa*hL)J5gYF}rz@LKBYf<+() z`-l3iRuSgp>ew|dSHI-VbjQ`)_v7!#c*U7aeC$0Uk476Z1qCg}CT2SaA?xa*J*l+| z8Hu)OLtpCeQy{bHxwi!CP;Tjh{C4T`BqWFKVPG?W*l^oC(j*=g;0!9!X5!@4#qdjk zBTe2zYcKPC@rN+#atJO`bmiNAXNmK2zdJOyaKIrOvFElDMhE+$%=-IobI=!Es^YAV zEcf?sakQWxu@WA6D|-!=vOi;08!xwq-V0VX%NQjLio1fuaGQ9oBOYfaO@5q}6M&FZ zpt53TzG1v#cZ8`VrLTPIC7s|+HP(_0H6<5nG+Itd2oz?CTPX<{yJ*0=V-q%&{`!-F z`*?oyO7tu=?G?HLf)-sz4k}6c12xYtBWI>B%7xe&>?RIl{@?1an5rkO&*GsZaSD74Cq#6TU2zK zI^)>eFhzCUd7S24LZCEdnxXAkNwg~aunS-@G)a^C8~+`+)lEJ83DIMAmibzjxq(0| z$L7W=yXRels%tR4xH(b1`%wz+5YHJhZdGIEA&CSX5hJ!!aU8RdZ}HqrKXw z2K7oQ!ZI23gg36G=~lVb^>^U}gsAF`C!GqBzW6O8xD)ic23%Fk-$cZ|hN}pPn>HTG z#Fb59PB2#)Kdh|KdT(DaSlF_yVMNOE1pe@o{5rSVb&Y8THC$WV@D0<5$6Q6V{|?1A zVs~fftx9-|v%*um)7u2&jDzLx^?wtcz0Iw+>6>rogfBk0J1#>sR=XHIel0$Lc-n-W zY0*Sit=zVr%l0&6x?ByjasAjbiol=7X{gl9#Ff}9?UhO44T%DM6t~0t>=NeiLQlj5 zP6~2n@3DLNLg0Cx8hn-6-56h43+BCCvu-1FGzg1vW(fqv4!>V#uyI+07KcuQn<{!? z3Yx^2zw*l&>DTFKs1tdhiw-<{k9_KDCevF4x=vofOW#)*%?}<%UD|V+6nKu9q2Kv> z0AwD5b(X0po~CK-Y_uOwZIaZZMeN3VMJ8=m;VhR+{;k475!fU3JcU;c%cyvvDNp&e zwb&ukUts#MO1h8l^hL~SE-2w?;FjS5BUbp5?Z^yUpfKI@%c_$RiY!TzBbPjL=cJ)$ z)hxKi&TXLX>*G$#zF5sje)S9bna!8WBCj1K!i0!`z*TuXA*`EOeYdSyRgIM(^t8{}$^*c#h>y`mE8$Hmu*6P*i=--sk7LmktN z-CxCa7V)cy8O*Dr{Vm(12M6sieU37(xgYgw}%Jf(E(8p!zEcq|@MA-ZfX z_-v$$DcsAGP$6T~@Ud>rXH-cwWA=t{+Lxl$RIW~j>CuA$0%~ut!Twd=9cq!Kp{obG zE*~L(ptPTDlx^wNU*_S^YBp|7m`1wIyC@HN#Z87djoCCM7`>-a?Dug0M62w3dTfb-7T?U_vY8p* ztF^6bO+m3%FQufkTH!3SJ=I;i`^4s4SkxDuvL=?IDC=J8FFc5BNgRB!r&xzYexd4r z^KR$|xeO=sZTXy)InPyloOc~&b_*2mdz_kDco9_wE?m~vodY?NWn`&(vhe9TCZ3al zyf$B2KqDj5N3~fUb5n%3z8gVHVhac^yHqJgY4j0m#nB|oZ}+Q>AdsP(gGm7vZ8T!_ z9qlC%0mHcTmC|AS=wH1yPc)9UaFye-mjcnrOM?12&5)nV{kdq3_KAfDHGoUuU~(gz#TED4W>ZBo8-I$_`YrssqSm{ZLA?Hrox`N5yNVlA}8g33OfuO^h8NEK;>T~o25FkveTjK z#l8wa+!)xKyjzmU^k#w%k_kMyr)(Qmu3VX>m%~NF$HjT7kPxphmEvd2(zTjBuu?e{j(TZ zFwc??I@rE>1ZdA3RBA|SRK}N;7yqy{51Yrf+~VMERpGhCS!r7xs;mlYIf3*t%9L$x zU(^!OzVWq4yIhn>EOSSUdrU=J@}>4oj>ckKBPnf~j}*F}i^C(aR4qp%>qQUZk)#7m zrD48)QN`&(ID~4fK8FF@oh$96)K=syV{jJnR5HZs5L- z*V}tf39O> zTQRB@dyi?bH0lh#?=VpAGEl=i@M2VHK-hEl5kD?wUJw=xvMM zQ`P+*T_$+y1juZJ?JoCVjcGy~(9jFMMS&4RqC3B0 zOSJE$)i^s>8`O);PdwH8XH|8tOOj&V^%w)unIU~5`sm_H?e*!$+<&GWQh7fM{oZ1AYzo!5EDRXp|H%cEPSf{& z#+X#@>PtFun}}LUe*h6G>v@Fg$1O}>UlaPwQo`cq&w>vx!wEJd>YlvNtHnQ7hT5sC zO4LS$q? zn2Tfe@QB{=j6OAJu-j{4ADmSG)(tipTKze3rgv}0bPie7xQ)Im_CPG1U3}$lLnZJc ztXl2D+GUGFg1hrKCOa#K4jN}L(9Fc1YGiss7UZIqw!QLK^b7RTAh#RsR0^Nov`ltS z!tB`PlH~$5nk1#S=_!0Pkz%xw5*ko_pPk>UFvRct3|||d_}OXon1iP|Oo|L@M!jc! zgFIxk<@)I9k4;8B(hgyTV$j~ww1Gd94G(i@#GJ~+UHFBGeO2qYF|!K6b!3aM5bB*? zbe{QLa{k9X51GJ12@*Goz4 zw7!_OI>J9YK6JXlROb6&9#IOkSI)cwz^AR13H2_Rc_zt9dB7rD=^5mW%k~fQX(fKt zQbZGj|K>CA?H|FUtj+`04Hc!#@(%(;`Hl8{vyN#*34bou`JWu+L~c4^U$C(e09X*| zr#!8zocKA+Lo9o{110Td6x>b|`5u;eoT{E>*L5lpzUXNWpU{Y)if#C3-8`w^?CC*i z1r%n!?7SQ)wqy3^`H9AS#uNTWXdj_sFa~WO**_6PZp+}u3sXEp2Am+iIc~yL4Y!Cc zF1T+zKbT_9((mF0R#q_lGl#0$&Hu36is3}sG)Y8-5vMtku$hP2@R=< zxTVQP+!Gj~mo5J8^{~CFGje*&R-3#+oIEyrPD3C|c~%g!3e%sf%9&I7p!ra9U@4@N zu?}>6v23XBnKyZ#j?ankv>~hIV)s=|!Lv(XJ5bb!G=XPSBjehoqn4D zf#FUy*`UPQk=*)|(UZsCLyq2LS-z<@>DDvlg+)$<#X*JJztU2%>AxmXG?vmiOaNrG z*^?3i;nu2~L)zi|q(4Zx_af~SGIP}|dY?0xyZZ;jLe&Q(skqPZs67W%=5?ov&&q!c z8Wnv|{WiMsze8`EPYo6C2A>MjLvF@jJ~k4`;$1|^%m)hoeN-(>ycBN|M7VyiqfbL{ zD>d)cPM{ahXp(L`%FAt(q0`DWePEB)%X8WVEe48=a(~;WJ=StYUZ#c;jJ&sM9P|pa zwg3dGYnVr8xb_oBRTNg+j;uX*KP996Zo&`k@#~?H)1VLdJrxQa z+tTZF55+%gIm=g?cEjWkvT5t>t)Up31Th7p$niUAANa~tPfW924~IS1BJQLyecuul z)nSEc#!rADrqWjTmdkbv+JP6*F!9+5EFgbn;(L%c`@a3aVPPlp69e>Dwf*#X+KaF| z&xGNI+Svy~#7kLLs}BTKHL)Y9nF1~ZPc`Fh2pl0Plp6G|I92u`#clRAGF>J^RbFW3 z{3~({nA}4hmTKJ3lx}luJZs_WxtuOHcjb#Hw~;0_+n2M+tBlWQjF$dLQp*(}TOl-r zi_3nD{+py3_bEsS>H0-^>Ff;+qRgS9-tj}xjwk*%4j#!&|A`bkUGqbR$Y_5o2eSL0 zM8uV$qw*1nc|VBo5sG0)DOta0jR@cAK(C)UjBTJgkY)~yA*u~*tv-n?@-z^wY~RgT z6=BTEzN-C!X8f_nply7;Cn)=p;;a{16WFzQ2C^1|nf0}YH&AGyhYT71hkA%V_}{dr ziKkP9^hF+r8C~3z)^{fT2DY=BVl|=a&&ej#(y`q(u&Dd``RSe~)^(!I_yM77b+nU4 zg53H?scE29tM%FYA3xV}=BMf$v3}H`yZY({trz`j^Q|2K1EeoZxTd17Y~pkL3UNtd zE4Jlyqj=vx_<4Fk)_BG}115>v9q+lP&I(-9_^w>*-R8r@bv#~x*~5vu(ZPtA$G9p2NI?mN(c@lbkt z1{yZ?D$Q%@ADJ5TKBl-`)9j{3mwP`8zhE_8*n0Lj?IK_%%tjvValE>_Q`+V_)W*nJ zXB8nh{LHa>OG|`s>!~eVHRPA(Bv=cps{UCEZBx37q|RWly)u;b55|HXFP7`ctdf-j zbye(o==$-p{0uMlrvx3#QXI+~Ni?pqD7~7-{;2w<-VmxW`*y_h?yUdWOR`LN_gCoE3)h(EY9&x0|1OoTKQGtQ+nwZGagR4T9!}p@-ahb* z-!?X>)<2^#<=c=8&j5O8XCyO^iRv1<2vC{vVGQ1z&p?0NH`~l{akz1)GCMS@a({EI zx1TxspNXK+shl=5C}+I5Y+pCGA#Hs$U8KBpGfZT+t9_jnpfTKQNz~n-X474J5*gMj?slGIWZl zfO``W=Q01fz|0=Zn#F*Xm0^{%eH*c?1BHy}TI(%SEyh`z*G-+@2AL)S0&59UT_b#x zAuyqOXtn5?2s`~la(Y+QpiUcQ$}JkV*46eE#85#pcv8<{(GR?+OHFJ75P}<6Mg+%E z4bu4FC-EA_5AH>u_=X|8BRr*^n45qyjTG4!4<3?!7tV$UUC1-o4Q9xci#C3G4zA+b z>VL4DXw3A}8}=xJp)6E1REEK?3rewp%WQ~a*O{!LDtsfutcmz`XG%62OuNXF0}oEh zctqIq#}4@Rsip|BMq&`U%q8uSX3%JUkcg6OnY|8QBqHm93!T+j7Re?kwm7*UJ`1j8 zewzKFaD1M35S3;!Cq(I@LZ@igcl=hvfZ*VMHeq5tKMf;#7v5pu*f8mLdYpfi$$9_O zm5_PNSKYrxO!et`d<|Rk$)jZ6u?`}zzlv$FmnxI%d~%9j8!z>iaM3@?Xs~L{S$xRJ z)cQj)qv1^CbXS49!IZ&2Z3tJN;Ns6MOOq@lU4$&ajMJ6IHXh;GhW$43XiZ#u<)*_- zSh#p0a_&pf^rI$KKO4<@?1W@HY7;bW{>_dZ;qm`L`H@JhRKc#tCz?3777wdT%S0tr zxrZwQvXA(mttl1jyCc8P(!c6}81YP3o+`!W=s>7zt!miaD+4(sWIO((m$Q@Jzq!V4 za>QN;DCu%(Z&N99)0Av!rHNN#hf;;S26y^GUhanJp1_p*)d7i<#s)t}Th$uctT5Hx4tMMQ9h(FXh z6{u*b;s%g(N-yl`ait*3IziQ6Y#%R~R?L?lwbrDNb`_B%gRVzrB@Ir!}q~JK!evi-dWv_PW=FdTFyXjfWaH-#eyMTrRL>3a4jFQPrYV)5|OR12~}`iB*j#c)A| z?2U`)Uy|5WP~CJD$pr-`cmD+mku!5+*_#Lo?>#|DMPB`s~Yx zCvi_~;?$Trd%59jkdK&pqPs_Bez&UI?mVt>%o(t{Voe>XdmId7~Bv$N~l+zwr% zYI+WzQLpP$RXVJiNU5YYK{cCPwac+|{qW2ymF>*7c-c5EsGMjG906>f!p9Gdw{a7SyghD+bE+7K~4p?=3RmKjGJ(+n=c1Ths=(|rHTK1>X-Epw}x!r_qKn6yhP>)}x@*rY{gk2d+ z{#IbFmiY8U#9|l2BYT3O&NFxEO!M%}YVUn+*7Y}1PMlW6cu)K>;mX$f^x}l+79v0{ zYRu|A+P4o*xUhKxyCd4WW5wGHWGcWZ7GkOjAIs)ZrXW+4Z@Yvr4|A;3ZZSS0% zZubh;MyOM0<7NEKTr>8#%S&WI+53{sfvC<}Y3GJI%uv9C0JAqiiSf_8kDc`%oK3h} zt+e)D57j+&+t||_x#mKTE3(UJ#j*i|5TPK%pyp)kzefX0%M>-4hxU{<-v)a`p9uNm z&J!?9eEaZB^^vLI4L`s81<`nBh4?Um#%HX|AaddWkyG7VS&a~8L{^OK$&_-tWP$=0 zoX^Iy3b2S9IyZO`$62oDasc!wD^ax5I|C(;6_%tgMCeJ<5|!MZ@8E6-GBmHRq|CNF zOV)t9Cu@EI92s-_NNxM^XzW5Os#u1(6@X)3cu3r_Rri42U;m>c;+pIGT-vlCu?CWY zpwtq%q#@KcRq-=K8oMKrj04FTp)2^=Qk^N<&k2F5i;;)q z`QEI<0wQXaDy)-JhpuYe-MVnQ^H@&4_f!zOq_W(MP~9NsJ@NJ;ig?o}4jHOUx^*)r zHlA!{c(In)Y-^Nh8zEk1N{ezPTIG>LA2cZc8heo|ph)O&?dNtH*RwQdgVKhM&*Cxu zZ3hvlPyKvO_6j~Md;uJ|dHbPLaePEjIAqEIaCujFh87V{Fg&}V=%2QWMr*h1eKq?} zz8dHJdWrod=1R@v>u7BpJjZ$%0Z~P}2RbC9UQPdiT?+A$GpJ2cyBH{~!TwV1_22gU zS&(v!{~z(Xts<`0l`u8agf%w=%%~HT4sC(_=c{hV+2^=>qciX3_m9As>jQQg3(&u4 z+%CW%JOpacyg!7(E^T=uemsEKH_?b3MNvMwsceN>PBa^}%o-|v7u(^UjC_4lFj%R+ zXwJ(6i0s}!_>lr5Z}I9r5izexE4-@j-eS97U))ThlXqR~^fzO89QTro&Z7FU^YX0s zuqCEUV=6d(#W$FvOYP+isc_7R@`&I;D6N;Z(axuPa7U#|pAI@p{n;nVwIze=Q!Tz* zD=7}HcwwlsjVG(=K-_yU?FYcL=cCvJvbO1(0mW~BBAN(TU*CM_!FYca+_cH6wr59%h(VnzeW(?A7<<#*?Y^!3Qvpx2??8c~bkrEp2`Cxp%`kARA3y24 zl|DMmgw}l6xR@{28rFz&Ph9BX?0$h7_-Y1Q+z{3n6Pi;$E*}!O;&yMM$piZ>M`TRz zVd?ASyW;s+AASnKKb+~_#*ExU#cP3l7iV@t{lf~7O=TXNIjh6M_7!Uc{j?W+U!|G! zB-`o2rOy?a@CJ~>C2onoV1*gW(?))kF>&h1g|0SHk)aNnqP)F*uFrz_fPf> zA@5>!sM&5=aT?SjY$vAHlpEdD<2PQj$U2m%bbn_EV!!zPKpJgXnOLEmTOGk=+}u^9 zUAO_E#^uH)%*=_pzAb1iJ5UstFrK(1g@+y>5+9OGZxRepnX9 z1Q z=keNSuDqQU`4^P-PHIJ6+B;ktpCq`Z7af2+VvW%`|`Bc3zmx4kYt zApGug-EQ?f0MjbdiodYWulYkFr~Ic(^XCz7L3AJQ3|7b3EuJ2bpfDc3I_oc9r9G)m z`&D&%#6)v}WMcYUCQ9-vQyO`W6%N#=5#4u6kkK}iHV;NrL7T5#YJ)vJ&ZgvcqVn*V z@ytgD(l0?A?~biy4_%UY?U;itKF3!PPl39*;o8sy?<-2H-DIot4vjA+hnB6Nk@JW~ zFx`p;E~jzfr=CgDTpMm1>Q6aaj;{i3 zxpbd6_Y~tKFYwvu)|JvHG?WHnmKfTLgRYSQPm9_2A2YeK^41zWo>M32saF z*?BSPKUcs_rp*6xIsX3#|NoKvpACizzIJ1CU>kByBLM8M&%nI#e|o^a+_*NBJCtZT zK1I$nK7sIm-syJ6qD47fNFG<2UaFv9DeQDcJj9_~wm=|R$rQP1)n(QD<+RqkE5FwF z)a2c4>&tLy?Sl3z+G_z02^5Q+;ZXC4evSFLY&s7ko<_;g-SH2gihIEbnu( z^>-A`7{c2^;?sBV*%5g27@N*e6tDXegV%TQB5$U@hjooC-dwWt!HQ1{T9n@s+0pMc z$!c8A1qK(BKrmpjYU1?44Xl6vP8e^Nl}x!0Qa_Vay-LzA3a~~yvBWVHum1b-eTKjI z1QgBtD{l-O?cej_dX&+VY|fgxvo5f2`0wAC1qHAKTMr~P9~mAcuB3K{4*u)1bcB6N zoqX@Rr`hg;%d0A1y!+kfn;yU;i~Af>J-u$E)8K3_v>zq86(vbiQ(f(^lLT}+(UD@qY|_3m~|ZBl%<>tN#-nD`p>0mKsSEXrzMb*b_(?0uKKmEEhv-#w9dZ| zyNiJok~`htk}pC;XmF`ssWIDmi+B0?*IlSroRPP^33p`oDhvP+lK~-g3?M6PO{pRF zz-2`C&mK?!dH{fs8T#F3MNsO&Y#j<5L*YsDjlhF(+QeU}>Vepq9d7pQrI&0@xjlNE z^L&HjFltmp1gzjtepO89WlJ z21KXNt#yDKmNn=iayTK5wfS#9Xp%^pZx13DT?Ge&nJ?7qLs_35tcC&E8|cL3q|F50 zAMKcCw1f9y!|GOy0yi*8wV8a&ZRHJ4ea)&CwkM`jK;}%mcibrp4E$vN>`^m{_7OMB z@jw*)&lRxAl=*?z3&DmzDK0Zy8^JZAfk`VyyUIezLty2bgS$PdMLYB51^f!S%zoro z$awQJO@7AEKvDZ3MpfFAAoYDj}@qmM)3lwgY}>=vD#ofKh?P??cGY!IPg*{ z)~(2<>~LsV*5=S@X$FjvegNjG+V8A!n4KbXw$(1H1>TM_!dQT&nq}q-1DnD>ml@*) zs??nu9Zea)w__Lxqi?_S2Hu)m0T-!VTUC+-nTcNU@FHV)qy1zhpo%fj@4WCgQ}UJ` zTqoFnSpL4v;tm9LzX?B@#r*=O`*HQu?3Y-f$*rPHc&U@QIS ziun?7X#l`nW>myAZ9s1DAa-4A>PgwEGePf%tVi<_0_*|J1mx;le>Y>#Ef#mO zUuoyrXyLHngbrT#m>oFVIkaQ~5?B)&put}6tq!_mq=`!Y_YPj}{yo$d-?7UYQKny$ zOj~~QtLGWvn3uX47$l|E06M^F>eC;9a$pKFw^2=}sP5&*jtQfHCW7|csA2=aH6-1VFE8@T`2c?eyY3if;7^yY2MV-L zif{e|Ev^?^Ng@2}gt*5|(k9gw`>!fLC$LazxL4B(SCWW#0&})e6S354IQzN7rmoIPU&i24 zCII+X^EtP@w|X>Mj`H_N1S)aqnHGzF$T<`oZ}dUGzzd+*Gpa26Yo+42P3DsM9iv4Z zhX6Ci4)F7}(R;taSolvaAV*rM*q{#f@3A8$6fB3(Lj8#t=A^+}0~v;=i4P=a))MdM z$b?q{aXu2z^YXt;^I`iwkTb0POafrFO|=|u3WOC{w9;1Db;~p1K-IJftdlCmPVdmY z!>c+fP#A2<;6fhVT_XOF{acom4e7|9}j?I;XWfhrlE5M)_T{oh9& zWe8U9O~gfcy~;;>4L{vBW+p+pY^x_#WPeD~;p6)Z$e#b{F)QGzvu>fwS}G-sqyAnh zKWu{R;r;i*m6C)fi@=m+AS{^&3Z}k3zq=7(Zlx5cORN96{IP2LF(3Y28wt)E3@$^x zMpgX*dTOy5uw7b2itd&xCBGO3OsaH0Jfcuz_TYp7FxATv=}tgJ9dN#t0^1sgbJ=G< z)D>_k>Hd4q_m2xi;@iDyxva$$4INttCtgp!bNcia)8PEICwA6#53u6^=%z%Ew-j50 z)J>{1F9qxVxpjy=@#FyG2Z|eRu^r^rQ`LpQdU+Ut)-k8>{5~Ufu+7%G^}U{cZvNR^ zMt}6;jEi~aq-B~tzvujTWuC$oP+3%hMsD379|P^c41{eaiRLSCHwkZ7&>FvwF4b=s z>4;=>Jclb#8i0ogkZGI>+~GixCn?0#a}Nq3a|@syxk|_LD_-y%Q8g?0?{JrGAq6%Z z(?&t}YE=4vKDV5Fo>KR=m|0@Jk8`%ypfH>4NfQv0${>&CzS|psfn*#sjW}vW`IXw| zA-m3ilDYonODa5IX1Y-k&)KL4pvULW8s+c-g)^U*bgPN;dLBjq_m{Ps!9)b}o?T}p zS;A%D_N&r7zI&^8jx9eXPrgBo4~U7Kn2h%I*j^8JeUp#pFaVAvMqSsXn2e`t?JZOI z?cJF&`SQ<=zGhbe(9c?E{_~u>afT>YeaLrkZin@yrMixEV_g0<1b$@F0z_0>e7V2= zw=}=lGv>(pSum?q5dC8FOgJ^ zPV;Z>A5xv@-4EB0x?g5(kpE@*($)=kI~2yx5=GLMzZa6$H28RepJcLA`!4`~OnF{f zM~TvRI3GiYKD3N#<3{S{s{{0y)Q6m<_ruFcMvn18AIT^y97$pVuKyRw=s6QAR$A?g z{kH5!N)m8(>A#_8fXHXkWHp!PU=^F#dq(}AP5m`ZcGSw4OR>H-@G0#4eg@@);Tc@F zAACR#Ch<-KY`Fs^?UQoAuh*;D7%P3#F0I|_cToWW);9Z@iD$KMe>d^I|ZNvN(=c!u0@yzNp3I7I1^xbbQCC)R^NjE>>Non@jd)*sWJQnn5Ue3 zJ^Bb?j^;iLmaQIxDsoBtyv+3h5|Z6}|K1P$W$5kF5@0&4=7?%^3-#Tf#~VjQTL8=D zDtiO|eAM@7UJ6V3crJV3TNXq6JIu<**#T#%zu>h^i681aZS&FKwTtQTgErM9`x7E`JSZ< zA#KKBY4gVbO8pwR{GKD~s)>iT_9P@r(0}p~U{sXTvKiKwQ)*`$S@fr_2l5$|o*yKD z|27?iknPGFfdqCs1W+(7f*fEaNeLSVW<%*9#_!4~=fvdFg>L zI+31#HbdYI-COcLUFm~Ot z!fvX%TRQTz{VOfE1Aeo~jx0yV~0;@S2}_aqX)3Eco-zOzMP zfSh-TG#MQ^D|NPlgx@%+Lwc620%orsfWVakGT$YVm&ULDo4x_wylo&ZxWl1U6bDX~ z>yAm+kNRA6x6(E6KLAJ5@I#<$!PU$<`jhsUf-g-aJifnW83bvp3xjC5u4k^s&} zWBmra-iJ@Xewlvv@uCU#?$II*Ccg(jS)&pGs_ma^^EWtRtgP4w{Av4C0?>?lUL`Bh zdd=^nq1!(}>$)xYu3JqqLr;tMmN7K&~U}HS3Cgb7aGIqo_@;#UKB|v5l0-6oS zzb3cu*xmFIvH@b-ZpGH2!f1R!}&fukolh6uWErsj152BPi2o%n|UI9^IWe!9Is z?Y=qjhS+-C1DsFaT)aehE#l3P=$As8U<&u=_^h`OC=`q=SeBmtBJmBhp)LK)1{}Rc z^orM;NNL0x*4k{~NANwHQvEGc@QTTf{~Kp`=e=q7bNSE(m^?9g!_1Vo`|1F}b5$bJ zxHIiF=*6xnVXN?V4gHuka_M9|rTXr(G5tuZ(F z)!qux{v4PH;Qi$`W5ovf14gr{0=$-ePr)ifN(#CEJBUE2I`1(go}g8yHQ>h`cin+y z-BhZ8%Vz7_uBZoxUF|f}Ls{OK)qkMOdOLW>*2cC45EX>upRwOMJO;LQAh0R*j!XxJ z2W|>d>pV@Q$@D_*(ygPI3nCD;8=)&%$6Iw-ZZc|pAdxOEwprDI!&0%arR(Q*KiSu|i z;H=UARL=?^lB)sg$l@~e?PRlO72sIp*ZL6!g-+HSfbXl3f@bOLUWZkjLKJvF4SQ7* zffRZmoXQc6BxPwuOaT|ar1@GavgrlxCGh+Q06|$DSox}ygZZUDXbgYo(1eExZOyn0 z)B;4QfpMPT4|s&o0GJUL^n!#8I6k2Gqy;B-8vUS4Iw6zi7Ot(de&`qdjjBH7l$l!V zlrfgAR;B4jMmYC8CM8^#&B!AQ8r+Lh*0>Ht>M^xjVy5x)L@JG2D5TCbE9bE|q?|E-8tJf8g6=2L}gtG%4w)+}hgl zYG)1ogV@AG)(aOtkdm~;x4j~9EdqeOloTc}Xv|?}Y1Q0I<8Htlclak@^LZ!z$}P55 zUPa77P-uT+%-|=}L;dQ(A}tQZ)eH7??%S^`8w8xu_8t@ZG1h?9zW&w)l@}VTs8n9& z6q4~mkB67nd^KY0yFLpKd(UUK&Jp$Hz9io3H*Y@TpLvlp=`vyuoGzY#R`b{|U%FV( zZY@f64h)qJTM%>wi`>GT2+QXBXk8fzi4!vzEB~xo^*v!@r*|?CAuw|5%dbY7otY=o((^H#$(#? zWVEsGnn~4T@)t<}hj?O9 zQIFS!AsbL!iH3XQy0+)v#Y9E@aY|9T%inWIKWz?7Z^rNTCRt3L9H12`c}uhD_%Vje z{h%%Pfxvjm>_t3IK~FE~S4YQJe;meQ7TI$6#ZzPQB{|Oq0Rmrm%)!xnRVXa%YxSIN zr-GT8S**+Z<@m(B%*>Y<_^NRstgvFhyXF!7i`OSd9lyh)QdS1}bzZJ($txs2c{W&B zUOr^l!1q(1QLJM9F3^FN58zxQX5MwCjR1UjmEs^C>wlIafZ=aFF1RP?DqHI?`4(ej zm|Duee68~JkJ9URZZ2&*<~c3^Ks_fKSqdHO?e5ll`!-vt8^82egG+y8PW`0$HutGw zOl*wO;8J<{(612&7EeEcTa7gS$LE&Ya}0H4&o|G~<36 zd-LC1K*3e|=ZeB2BKFgHx%c9MA?&Xck1KKD=Gx{xbMy0ift3Yoi)hR4P&-ZUvbwhZ zqn*~C8|SYbnILnW(7)weR9qbYbypp|ms(uk;4SNI^({L?i2HkUv!Sv<25*g0(j_)3 ztrzrp_4Qp8E+~Rv$o?_y5x$gUHPYWl?Q7`Q zKCG7(Fq6$UL$yfh)w&i6A1~ECa`<(*$z>w(n^kSn+rWEggibNVp-e~D1FBtMGQ#{= zKn~y_g?0f|xCdl5`kp~c1Uz?huY7aGd-BhkdGuW*KQvfPVFCExO3qQ=eb4nt8v!%gupo_+DJM3oKSrfYD1P9iY zn$JN&Ju3c(F1#r+2b+@$hq~giqN~8qPY$;yZeWTo`CI->yK1%XAA4*oDtmkPhW4Zg z_d+M>^}vwmXf@}CqoX4V5)vHTjg$1+e>!&OB(PO` zjBr@T-PLO1_xtlh+LPXlGrK@O4RerjTCfhh5)$IQtila{gvV{gV*OUFT?nh`XBCBW z!#3Z}sXdx0z{lR-?1YN{+n+pU*NA~K{{scR`fV-^-^JBcOVaGt)8#?u{WUd^R`l;3 z^gC^J$3HQt?fcAoa)-umUEzDBjKciEy_zECcUa?Nw8`1Sb2NT+plBWH?9_uLHRS8p z7@<;^(W37Q3vVYIOoN+GPi)6i+!%xL8;Y4Gr@OQ)sdC?*D*$`GHd#RjRC(hA$^%M=kGlr>FN9tqaakFtu`jmo z_rkT9Ja?QjllZGtlkVy3m$999UN~jWc$^VyQ8M8WPQWS-Ei@c{x~|iD8h&tZ;NY+E za$sJ;7zaRV-&7^NFVNh3A*-JagAHg#@WC3_C#&*>PbL<3mu^I+>~U~%)@Y?#{n@X) zHMO>Pypj`{yl0bXKb@VEz1)N%MqH6_c5zW!R=2gEsvfR(8(lrv_h{j`pk4lbUl)?O zW{MVgQMs1p(Kpod%(SCNr}YFnjS^vDkv?}uKHk|Ilyi2jw3{gZp)Hs9BlHp<$oE)Z zA6nZR?Cs_CNB4TV>3+I44_jF3QxFN*D~YPFg=z1{haoSKJg-FtagE!y=ao5=4;{PC zg=r5|TVgmC@W ztr1XAQi5tRdl5S36+ba#W$hN55cPX{dX=~rYGoCacyao~k-rD{p1X`cIR;n{`>jEU ztrb82*-A>vKKr<*kiJ&V-~&$R@7qIH8HA+>M4}R?6G5&I*$Fl~PB1_}OX&qr< z-@i!WTILcGZyB65%|FD0#okkRd^4=H85o8z>uMSBjTN$DPH`Lhlj`R zLFanvz0o2?gEy~aI%Q=>pTG6;DJ^=;!Oh!#b96K^#ZCXm!j}R0hN!CE298I*zVx{N zLEd{sMV&V7-fhAWMN~v3iwYCMBDk3>H zu>q0TAW3qDU9IEuzVElcwa@m^?t_`NW@e2Y{&(F~SN-a$Q70Ek7blIl)mQq87Vbq5 z|NUlG?D-Rfb+s*Y(?)##U%xe9ixj7i-Im|FXbCaXTW>;HkCEOz zBz-gI;RDU9|1iI9Tib=G!Owg$@OzR`(YBgDZKpl2;jPCd;+I-l=YXwX zHa>QI<{BnA%JoY#*5aO%vT`!AO;W~Ot8lyE0>&K6dj9i1j{0yS4e2(C)&$lKeBqehN${UK&ZVHyIer$mo zE(+5^#HVPW#O3==cl98&TU@}_xOHGi0^x35?2zts~PD=_HK(zJaO7#LpTN2y)M zb)#F1wg;MfBI%V;nJNR^0z+bl5pTELGIFm+xUrdK*eCnJ5%`(i>sweMh{#Kyqnv5e zkc%q}=yF8rmQQm>E23{6K>Sbu4G=Bbv_OFdC7Q%*irA;jOC6LHlf)L~j}d7aQht_8CN8 zoz)?PY|g7*vh{w-H!)6!;LVL)K@c#Bmu_>I(fWQWPE|-sJfii${z0fyU1wm__K5xE z=xn^R+0m2q@3S7%yp4ZxG?YbDw7kI$$+PCYzm3{##j9vDE6m)EC3_J3VA5+jt>vU{ zjm7KEb}~%qGN@wZHLJC?wIPv_SFc@D9>CPrshl-4Gg}^hiTm6nj*=ls+3XI#AHKL` zhlc9Zsl_*{p#`!KH9~-6VR-yhFBWdO`tX(*%&Etrjx#;VkP2PKbnklT<_wiP3mrT2 zWV<$c8`_&OhRYP#%*j{7JKwOs%4k=oI;6h^(y>ufQ!fpi*MA=pa%Mnem#$)uV8x2C zcXkf`_3Iyt05Gx~otfc~4WthzInB=7#-P#M)!TE&RW&ty=eHJOAsMQfzWTGc;ZcpZj zz=TAeV&W#HkJW5SF|3cuox^%MapvIv^?s<_rQx!{cIF)!na0rJE!hH0}F-gM4#1uWj=9~dScij&Xu#amc)}QWm)o< zbP)GbxxM8H3NLbPC0DUKD{PX2`!X{uz3jT`O)w`#u-cww-AvM_=NBosv6r%7V4yjulea>Px+w*sM z5SKeS#YokOO&^NFotKP^H5QSAs+QoPPjPITna6WW;r{*hyX)fimmWH6p$AZ?w#bvT zw>~q&Qp%gt9hcPzGg>;CDQRi1%iV>do(8*?xSe#{o9Ho{oBC)@^Td;~gWfZTt|ynu zKvEJ~ttwG4h`s3Zd^;i=lPM&W#N*-rw8B_4A6@?QJsceSo*)4}*i`r{Xt1Q`QdD>E>t4y2BxGiLkD8TvV!|q3EgFZ>CJi(p`S0v-9=M65vGju#PdcprBJtf#GJ} za5J3_BsQDh*U>zZqGyDjyxd$@L+&p8uIAf$*asfmeW;_u9`M~&5$bnldHL-YqBMmV zsT8w?v5b(|E{~bTN_Us0@__H*D=TA@>(S9VRGAg4!$L}rJ2lkR)eD|%@@`HgQ#KRT zcEyHb@#(1X7wf}euvW~!t2c&dpMP9j$VSiBlRNk-fS_j)pC&p|GcybH5qkDmUTNK^ z((-a4?R49NPIi_0amjOCIV>V5Rw1EYJ>?W?HVTxhi2t7Q@ulU|F7i@rrH&OxoZ~($ z35jmM%Mp=dY?69cb-7vZPl4LHUi+@|9N_A{#wI3F$N!-^lNJ!O>iS6XGNWiXYg0Iv zAbM;;?`iSNSN%t6`}?(fs%)c=pD}BW<@DTI5!hxB_K<^}N~Sp2uy!=nUCIaR+p78~ z-yN@?3#_z z3pR=maJ0F{>gtZSC*W{0>>Q0>yNj|Moyu`lp$Dt}QENwNUd7bgoo&7PC&N#y0@YcnuE|-2g@s4keXFa}G;N8u z`a+Y6KAoIwWc=mjo5}UA56Q}FLpY~^W5!tJNZg9Eg9Gn@2A^jylmd9--jpE+&RM)W zJ7fRdeVySNckT_t4$k8?<>L}=JjRjK<5NZ;7Q4kPH?}nu4&2Lf2`CnHmK%u(hYI2$YL-7*2wfvCdC$Q#EHcAF*t{Qj5- zA5)9;qe!N-WnD*&*;kyOX%B{1c^b`yM`%4$Mj|m5wp~F$$+I&xfp9?Od5Hs?Z6oc2?>nN zamLQeY6bU9-e0+*B!p@IAdwy?ii=TTHn8f?)ePsx?^G4DRO(2L_~t-m$*^FID0r5h$MFaO44ZMrV4B?=tEH_*0B8hYurf?R*K z0M)_Se8tw><>mE=CS_^bxJP&`SJ%>P{i54$etu2x=$LBDxRqHGN^X%+(y;GtQ@#gV zhsM!1iExl~3Tm`P5I#6VvVV13yVF2A^YiI^3knj#w9>YDFRrbH57<;c)YH>5sar#u z-cvrbKR?t`sWHT#ZurP$e}3t%R*^$#S5HslTbe@ara*de>*tZvcw7ELr%|?hytmXe zdafNnIR5R*AbwoJRz^XZ>sX?%8~N(hD|t`PN@Fv#{_yR%+=Oe_>uuNij=VZDIy-w^ zqAE_3IPusa#KKk3#TAug*!t)Xo1oT=4BkhPzKH z6%LF~Oc0P+aA&?x1L>zz^i_OHuB(3vnQ`3OW?(5*> z=G|}aW|TSd$q3}g<;izM91TxqgHam2_$AWQ*79-M92#szx0%^WM|^3NdybGDZk)yo zPnKrP&RU~#Z=FFTjQ!W)U7g1FHpk1~yBD%wwORJkPgd^n{r4Yq6Pp`g^~>tp^oWQn zN-^J!4KVkF9X8&_-VDCBzeOB2{`G^I^`pFk$m2R)%!gxuq z-XoAq%Ii+Ojf7-LQ7-6ye>L}m&Q4VpmWhwr#E}tZ&+TtI%#DtIhJN$z_#Is(fo9m0 zWwH%VN-2&XpC?ljaeN@Aw4_At&YhIsdg3p;X}PDgF0%lIe`(wp)@@h8|@8Oh-zHE`p^ zi8p@K^-o=0i=Ij%HN#_KtPVzf`jntJpA{xZ`^)3O&!0b2uvj$@50At5i;4tPwI8tN zWBUV$7C&fvSlp)0d(~3=aL854As@YS%-?H!1GO>*)Qdl);JNPV?$+I`m)ayjb#5I@UmydfVK`#?fC%s?sE+H30gM0`wqXO z$|qChXLEHV5tahczWMiy_L=E2X!8?z$q)Z5@;`T89e>IuI->9}qP-OI<3GPa4oWmg zy}orUY%W?Ea?eYClnf!WvDOecBj$$=UAdX!x3VB91=4WLP%aLqv9_T20a9TFL&LupMgud}1-z)(jW?ktA|2No4#l(rbYrse<1C^dqe8}Th7i*OJlEOILofkr&2_1QAGRt7wx1^-c zo1xTt`UzF**RLzVu$ktJ%Q}i$EGmkoz<4oTqpv^%meNk#7_>KT3Rh;0?Raduw{zqS z{h24>#EFSUHYRWLBRuX`u3oKI!}EX4%>^c~CrSaWT}X^3E>6XTUl!{@H^lHXlqr34q0sJsJU-Bu`M0OZ`Q$Sbcr>U~? zT^_Qj&d$D$SIyQHqKx7};W%R-RJ!{$eaOH!w~69xL&HV#ywMqf9luhTV;?{di`0Aa z&&tX=W)E@>a^|-xU+K0gSZy^Ch|_3lYC$^eKy_lgjl=L-KaCZZMVM2v|4R@cB8B;p z9qkg=uipGRvh^e3F&|YLd`mX2Iy(NP=u?sp1_uYDXM1xEyiryeJ3AhDT8wPa{l)c# z@5YruK|vPUY0pC9+aS?yUg|99M9p}5A_ul~B&|NC6#KH%P$Y(PK6=7XrwM)M>xg#! zzcCwOUI=+@i>J(%z26KUZ>O@lB3i<8F8sXKGk^a;f5CNvrIPeHjJZX?P6djZTcj>c z_`rb!M8@*GPq^l`g~7GbckHGsW|Wka<>yRw1#Ni?ElgXZIk~uU4kG669{D%w`3T~D zjKI3Tz}6t?x-Ra{=%`F2`8f(cSoeL6?VfQXB&xOerY0Z^pLn*Jo6 z#rKSfIAj4>VHYB00%qkRFt(%HE$9o3m z--F;$K3AlZ1{vh@=g&=AqSZrU9i_f}af|NfE`xaR$XR#fp0-6sbF_G`+7CT{+zosT z86-g&XBZfaiuGS4WoJK}B;KCkp~YuLt`F;8$*o%A#`k0gP?NJilU8F9~dBh@;7WCBJJ;n)wgwQeyOdTa4 zj)a$$iD*9&m$7Vouv|!{xNNI`aejXOAOdsi?{rT>i)wbllg*`6*7lN_dG}P=}Jnjyl5%F=n6IE zW7VSgE&MG8aLz64Gn?GOo6G0_L14-L-n2e~0~M~xrDzv?%NYl+lS(h*#oeRMnJiRp z2U_=6G@NTUznT2(-h&6hFV_R@p6XG!VLR^PKqQMrCRkohDZ-`b$ye7B0?)CMOYk zCvq=*Qnwx=6oK-Eu7^4|_ze}?v7GDO-Q8(sHuCoQckak2tj|YyE&m2JKXu=ce!Ej4 z_K*Q(coUzXnfsl!q+P?5(4#c)@)~G7RP9~ey^mISuy?f;P22g?5|u#ILRl%b-6|UA z+bS!{QVzf!DgJJH+>ig|HFow7dxyySaL1=RYMQ$`s-^AZUL&LwA#>5pZeE3g}RgcC~seWmKPlsV5?50NlMw5vI zSzLBD4B!h3b84JDPfa}pcFo)$y6)F@i=;P%rVIAV5(%@4gH~U{6B2#|FhUPUJtX90 z{gs)UL*+;LhZ4SjzK3agkC4*QIRDQN{}fHTmAL^;7(h68YkP`X5>}K5u;3$-5(8|q zY|n6GJ^Fb!H`~0}>w=ihGchsINQi;$l+#timo!&50K$%1-TEVFXofs^FqFcXlx)EN^Nkt4!s6nf*})Jf`f}7n@tKW74=(FIhzRN!w$t!T{ocG$FLRd9TbK$#bHDoB)I5`Cj{mF#iv9QjEiMu<;v<*IZ z@SqbD(p#(bC!tJ%&|_JoViVmtk&S6N_uVN77%(kW)xhYO zrC+~pbaRB#W7+Xhg20uWId#GOeCt)@BhoUWrVti%L%xy4q^Wy$RX(rNPb}*;zw`Jn zW?_f%JW~AM*xC{ql#xz&{^ejl_R^q6&R;FSzH+)CF-#CB>@)BI4$|tOV8Z5lzG0U>!-pcd2G9XYVuTa?BV&kun7Z1CI>xf_f<~f2A=WF@9 zTQLK*Q;XnhXI4emxkjXAJs_ofs{KcFsM#x8NEE`Ne_CdEb)nw<}B-bl8Hof=K?yT=Z*ZvBOXYf|f?4O!Z zXQH8*X1xN(xL9lxV=Lr}U;JLa&{)2}#T%5kEcanPxtmHCXC2Ij-U%N%zoJ9C-O03X zzLi~8ULFupTs)iCs%Z;wT|_#1FL0GLB?7tqcICvfp1bbnhc7;Tk}6b^PM*Z_Dl`S?N_c0 zkAEo2-J4rynJ?Vi8xG;tc}d+jU7Z!KGwi%Q*HZO>p3gM<_itdwVqxXZCp(zEz<+zt zUCwIyZfuJ>M(<;3+u%EkRHd4`Wf9UaaSpW;!QY3hHycVD`7&x%F{@XcFqRRT^yRke zYPY76Kod+kU!~Ughj$?@#<(@MlvS)_^CAfl2#E`0L3^!b47v;xmv0GbjlA~dljwgw!VFfHeA|XV`=mr_IS89+kY9Ylj!GlZCJ{0z~W{~-QLTBDWl=4o?t?q>yG=wb6TO4Ehqpq&D3wCG0^t z4ki8**Y$C(%AE7v6k*77x`9M;9xqZMcv=zAkW3kwImwi$SzjLVe^>Jc=u+sVE7ufR=T z+(10g0z+k>3ua73tSD4}?6o{kVU5#yrZ^U#-XJeO8C!%TtkBuO=R7l*E579Puqunc zzO+yM($)pgwZch*TyAek1cs*`HIrnAb1Zc9I4*9MXDDsXyHs0kRSUNFJh8EvXI1M& z?yV53<#e&@Jh6}T#-o^aK54v3A?D2Wt3HI3&NOazsBrx_rMcsc5u+eUE^q8XDGa%S zf?Mkc696yTw`?E#yrmJv)oLDe`T(p$k9T!N*P)xaRr;1QmUoSe^yv_Nefo4|k?WO+ z$G-@6%J>^HFQRMQoiu9c-#m|2p_`^lb9TYmu-plVXp? z57#;61Z<{5IZc$VT`zPL|J=yT-a3IfDI!u;&)`@X@0K zJr?DK-@1h(cwLt^eN1Q0m7+#&mphd;Tl1L|Afw1sX?I}ar;F>R#f={Fb2~dbSGc*` zR$d?#>)XHAT`+z{PcfoobSQfQC<-&PrZ6e#@=u>GY8P3i9;+eGzHvV*cV%sX5Gn*1^Q;*S5D1eM-OZpPlI2u)t~!NI891JHny zl6qmKVQwB-Gr`40%-LC7U9~E>_u^D4lWI)zh`gzc?}zX(Z3BleQin%d-{rGJa^2hD zAc?JZ@)v>i;B?4EH9FQ3u}rXO>G)Oh@uNA1nEwrAf7SBJ!!*K^jl2<1y%7(0@w5P1 z=rGGManLISpP133d!C6G7B)=_AiLAi!GoK7h*w3n83I&tGAN_a0jqPBle4Agxi!H3 z1ztl0)3!0F`a?^WkzItX3lx`H{mjl=Zn$J;XJd8uf~xmh#MURpR=e=dC|{9~y}8x3 z32wWIOSbAU-8h{2>i!HW-Q3nqHK0JsYTenCbUN&&I{r<>Y@o5D=PoC+VKk_@tegU_jc2L;F|SpUmMV0b(HJQE*4d`HZ~io)IG~}qIqwx4DEfd@ zb(j_-cZw}%jQH)G?43%GsQuQcC^jxPn{ELChtlZ;DTHM^Y#&X-v5~UoZA>$@ZtasK&WOeT`7+J#Zd~uxe_rk@s_+TV*GA!&F-bk$>T>Q zcY-Yj!XisFPqMN#fx}UAK0sFeDgIwTys6r3k)25NV-y@<5_u{IcePEX-AY;wai7Rx zV9_D05_yU{w{k1O-0J#*&Aii^vWLgc-5@&p71x=f7@KHr zA*JfXeq<$G(G{y1BW(9?up=`o=F!4%W%(5H2ge7c+DLfo}xY)y>)(p`(?ODu(eN~DX3_v-!E~6?uW}Fx*u(at61$g*sq5)VVo!E zR5`#wHO4`IPvka2lMaH|%`a9pPR0#H$+9*txxs8Y#E&J1Gl=s}z+j;!-h1VH8Qx4j zvp(-sg2wfVcx>ctj#lx+NusvrTq4mZK+KK=ia;*XukY6=lxDCpY*+IxZR@rP(O6MY zS$McniNkEA=c%?4#j<%wNN8$ywo_kAv~%I2Y2FJza-2i}*cJ@$YzoD+-_?CP-5h-2(9vk4)U=fP zL}@=ImX@6u;sCC>)Z z9fERdJcdt;`n-C+a}7DX)l;l|BRDqpI;G@_$uvGacVl~7-c80gR>ZZFekM5AyXK|X zpWkpRvTc8ZZD|?3tHjIOIRRS04RytQPa^;%RKfK5I$R5;0~>FsCg_GYOhb*PJmQjN zgX+QmVZ66`FYF~W_h1Y_NzQrctGuw+PNZ-+t^z11w%=&J4~KS3hd67Bg-SW!9KFL0 zVR=x+0BT2_NBh29d4FL>^jShe0_(uSP`R!{TWsmL{m@W(12myiF(4ru*Z4ZAK2kUF zLPy_d*=kLlzK)|}<89fD&{UIiRKuR25y|d1`iUCK^NQQp+Kj?2BkZmn=9fB70xeBH z?hpj5uGEritxN(PWUx!Pd`8Hlq{c^v_;zPWvpU>+cNuMZVW+Ifs>OlA)R!_S6gFG- zY3L72cxxT8Q>n=`CVXt5RQ%d~q4x6BvJ9QqWDHR>z2gbs}S=7bF zWz&0jyUJsyL)PKPrvs=~oz3LW{fa?Q7_8$lmVJdRZpVtLfQx%C_%%>)u^p4iZ~(TGsmgaOq8B zTcTpH${^=?EG_zlpsF5~2LAIkp)rir#xuF~% z)7~700<(3lfd%N70|*)`5ohE{T+S)|)!Ei&Kw?^`!@_uhOY*B5EU~WyCE@Dvg)&)0 z0!x{ix_ZxXpL2K(v#p5={fUt&MK@Xgmp37!>90yfVzAxeRlyzX(UWAY2KPjc%5cc6 zcnDl6(_u;$CqGU;{*n5dMP66B3R**RZE9H&#v+Cy6z)7Nf!=@7Ms-x+ePGrF+M54F z1wzgLWK(GVuqm55)t5UErv06@X-78VjxU7g<+YjZSq`lGx>g24CIq%mXa#6HUN2d7 zwg~w0<=|%9Os;=!F1o9$M=p4kp&1_1kHXd8z;#``q4;1bcx=>r2o<`mDv+9-Rhv^( z$|AAmsVyXUCx7f))5hYW117U*Pd|*>q-XsmsfS2(kvfng0E#r`?3pu{FsTNO#myMo!5fGU&)@5vZ~CAuP;aCHdS0#av_2 zn7k28H}DL!#tJ}a-YBD%YFhOFw?ma6ZLu*jF~OOBFV3;AKuPy`7RdCese(wtSRTuzBRMbA?9S)H)zAdF~rrCFYqr-`?2{%+gS} zoSYqIgUX;2rZxiBNHVW+3R6U{zUN)oG{DNjQVS}Kt~Ii`CtKg*)jf4y)FeI1CNn4J zo`Rxc^DG0R!bSW9=5`=Cssw2BZN< zhsK0k(qD&%4RjO_#dm8&lHdu5_r*^oRa8_;*Q<^yuLf#-zjL=%?$>6&uxt=xFd(q< zx4$@oS}~0xlp2+1oLwpkhfH-n31x%u`P(p-@?&Se{vk-hqYXX!?tA(7hW*baDD?*dQrYe29m4; z$FHIOL9%jIKF$t>Dtw+0-;&dd>Uu9zL(Rs<#&OfKib4DTi?o#Ml{k@@miB-C(^@!5 z&48B$QSb_o|H05}a%NTnP{DezuT1f9x;4+i09{gSCZWvq?O3uG?b+a8l)3<@|`hQ*VeL_jL&|*D#MsJ<*K#{~wyAvFqjZ$(oax z?EXTtV(R9SCIEbNR-WE^c58HOhNGych&ACiz*1mXBLY0_@F4v(10xp|Xc#ak*zoMo zc5Pdm%4BPKgBs$16zb142@t`<|8b!;k}kBr=RSisd6b0 zw7&?5PX~}x>JVU|c(_w@0ZJqsC?63_d?el_mCqcD9jFQIv_uf6&T~$f)N0txz^sJW z5rmrOqc{MWN&kaDUq0%IRMG*pnP)tR@TcLIs@oc6HU0N`0G2QPKX2{-b-v{P7LL<= z7tpP2ZzTJ9&0d`YK4jhMW+Vh7_EF}a8Hb#l(V_!Bac(n3iQg&&)wFXd%#LvK{pD5= zI?w+%ZpHDrz!4l1ll(6sAp{~Ctd;(x5{`M*@sw8oSRfEB{|RMWhi=m%KGps3Vb1+Fm&s z^nRpfEJZPbt5XM>jt(#%OG4e)Fh*tNrHarI1k*8%o!xTL!Su{bg)>y^a*(fdOEPo4;PHkI(iOLR4glkJopY)rwBh9;uV(cpN2e7JpMzw0MPI>E?2W z-vYq*P790|Q%zDsB4RmYgXn`_THs-l^|SIC7(GR$0162DbcD1<32LR@kaQ(y6FXL7 z;VLnK^tH3x<>tr_(hSt|#Ed;DUj|3{q%L}uMx>!d*{#v}DNBf0_LIv6_ zm*X|2lIwcg%@)nj^$HxXA-56uto#Df2C8}p-zR9qj6ag@8&EVfNu5EZ*XXWs9*ye; zmak;Ec!vm#h@7MMenapG#E*i0*9uj_?H6YST$j$idHot&#DZs!E=Ae$s$Zpzj>TXl zy-a1wGM>^1J79rA(Xl|)yd!=I8mq&nq>_^_wTzk56>bV~-vIt@8OC#Xp1t!GpcBk4 z9^mE{>K$DFIW#cn?&cP46f0a^kq-6QFmg!?olH2TJ-+aJ3mp^ zwX`VD1N9GStNN6!mpT28&|C z;Fe^6gdxs+-2#V3PJq50y2z3IE7QHX z)$n!5>BY`f+t7>JR1_h(8=B=Jd_G--F;qcfLLmx3{_Ak~L7G=9#I$B_ZX{EVuT0a= z?C7N!>>o%g0KiZEza9#6VDi&gw7EG>kU|8t>C@;5+QHf3Y86r*4`f2spl6#WDa)F* zZ)|KFe?j>@v=Az6h&pfv!+N3x=g2ZJ8DS|Yy9FMbssj!by5HWRN$3h|f<@$Ayp(S2 z>O6yu4Y-Gt)sjEC*EHvH{R5z~(I(L2y#%-o@BZYG5ckQq85JFyBG6Yl`#+Az1qycl z*pAZc$89Pf#m2=UXZTkxh&V=4SA2+0Fj{~`T=t{JeszG{7Tk_qPbv8*$EqTK1BE2~ z{6@oPvJ#n}Mhl%x{OAnPOefUhHT04d3g1B9G+{iJPp-s{0^?Q3tZ3QY6%hZ83!qPGDU$C)rQCx*m&NFjdcfKQBG?MeDR?(Ovj zAxS2&r}rUc8Mkx+>mO3kgkj&{*0rBmx%EHQv!bu}CccDWE+KKxI+e(aM&I6AINu+E ze%Cm3{jP8>R`0JLCynv`z7y@3z4uYK>Y@huT5OV$pJ;8}6DOL&i znR-Cw$tdFt%0BM|UC&CnpHW@s6;V;evZIIf9B?g@Ep#nnv9DZ)U>_R))RSE%gq|(v zpjnaOd_lM`2j|vB%-b&lIifB`B1ddb(H*@($kIGYZE9>>-x?>Xq_sR=T*Zj|%n5z!I*>y-;p@0){Rwq$d< z%?oBA;Dzm`5NaiLT(n4mB;%SaX#&J?W|BF*Z5+OK->xpTrgp;`<*dSQBq}E-PPDo0 z$mZtKd{Qw3qXDs!-{x9)WJzyxWe1HA&?A%iAN1>Qg3gewm#+tn`KFf=pKpCmTP?#~ zbNM&;dT&n(RB8RVd&Dz$_Ie78uVutcX!KTXoS*Lh+4#(>VKXy zL_|Ae7{Kwg4uZ!HOWWR*-=spS4Lic$Vo1g`zl=)C)U1Wcer zxngJ&uFeroojP^3W^5G36quFQ@Q;(9X(aNe!;IRz3r4TQ=9EqgX#l#t4hF0QnH4*q z?S?pdmHG-@mVGCB-hcR=VE22btp?UoJ*mVY(#7Bx4M(9Jq4s2ZH8fG$ zw-J8$=I-kZ%m6@=Y&QaR+f>lDFIU$iMHkXc_kG_n07kndq-(iH(e;B_x_Og=p8sRN z&{GEarZTkaZb(W za!Zbghuf#~Gk?)JoQXAO)Hv%-2uU0*Tx13+lm!6t~m_s=@jMoQW zHr)mjmb-wt*bJ;~dEk&kZhOV31MkRq31|&;dTV;e7t{>Zxvs?#^Q2=kLPKTG|%X!?^1No21wGoysu%)5(R81a-XEZ9T?f&JVf3ROix+ z!EWbaMG9j2z8BhKCm(KYsFIf&0`xKX2VdOQu-~Wdksjgt9fo6n2;{)G{y%%>ebRU+ ztX7xuk4_yAGTc^ZJ5wFt@mesYVn#tPTvX7vj?B zV+A%tIuF&C2ZpOI?t5)gmyayvR<30pGdpwU%($X~SN(@$R{s=&x1Q_rJE3v({!aRD zO#7^5cVif9EOcFhJZ1(|qBx$ch)o0-GHIetN&1Udo;4KMd;-f04{DM2CAie<-5;eEHm9on0GGp$>Fz zFbK<{o!td*KJUx2E4I6S!~3mjgM;4thb9*i41-&JH`lB8k?{|MirxB-Xhl49RKm_x zw8o1M%)0(A^Kw*Zn;nf|5T;~}#4ZWi{g5hM*xN={2hj=;)DkOJd%TrR8gspN>5frS z3e8|c#{arqF#oCxOzqe4pOzA*;N#DW;&aKtC`i8u`ChpY(GnvV^;mi!lH!7$&Bb_} zApW9Uab+9%S=y>ky++Mw@4{<`xVYHEJ!bkSFs ztM`uA#xTD|!y@)M-PdP%h$G)Wc4^fF$7%E>)gcEPksYE7a;Bzf8B?1-HLFeC18Eb) zV3+R_+$EuqgZJkdzBm?37@aHr&WrrKwZ6bTyfK-K%W@!fz!UwL!jndmWT3KU>sRx-vX4LudBk(++v5%af&RGN?779;Tu+sD7iMg| zcNGh_*Rfx6U16Z933;a^>!$FsD&-F`j`18!7PaRqA{628=86&nRta{Sy5A0#DEuO{ zTP9x`Qm$1R8$N(2xj-UL1Wjj4Sey9m?mv6>3}=_dgWOI%pxl#jT~~_g!r3du!}fkP zb?xtO5eYEP_N`gX;vaLz@9#9CySlpM98^OrgnA-1M)f|%)RhW35Xh8kQocc=(~N;) zQp~t(sv~W;XMU)>`E4xOc6Pg5mI;UnVdE`?12guG~Cj|X0i$hs6*OLpl?q} zO^tTPIM}Q4V#0U=57J`pcPLO(l)^CWkg;bFqd34NBL%L@tf;`a)9r_~6Lo5;bJq}6 zHxjOKafJ(5_3)SP|M)B|!jj-RZDX+bYvnZJzRoKxeGThMvhvsNLIfGa&Gi2ofclp{ zX*qG~_W%@vAqavae_V_Mvsnb{vlOaQl`d2HXEt{}eMg=YG2UEVS=%*g)etu*m{(;e z=-(M71dX_0aLJ2WGn4i`5!Rt$&inWW0#dbz8trS~J}Izlh&74!6&b5j$-^<3-%jnp zQR6p7Y1^%b3c9%xHY+Oo&kpb+lY4&A^WPD+zf{<;h`lsExW!+->lmnl0u*OFBfZ+l z%O-L$*=_x#OG%}#DZy;*3p?|!`%HvC!Aw)PQP=_ZbGCFDhN#Eblx|4oYUSVV5h|=K z1E;6xW(v!UiV88R)~m9+-cY$&5C{V4m4zO^^BPdfhW;_PQ=X}Rwy5)Yk%X4X@G^a z&waJNyRUqGS18p)d+?lY2wl85$UUUE7CnyMvfMMMxM7F(vbp}kftO+d=PHc|LA$?X+XRnUtT^v%@CfJa`_SLClLE=7(SM@JWG0+* zDcKB->WiMct@D}Be)P)b3SPyyZGLDnlJ=BEZQDDr5&(?{huqz5qu}f^8Q$LGb6C`y zSq>wl&89}|b?pfATN+I+3=a)Pgoj5bd@S`(`10jBYtv3STC`fibE{r_{X56`vFS}$ zlSXBsmI%5uKwoj+C6KnesbM0S;Pi#tysep3rfyrW-OI7QgK*@+P+;)>(lg$dTgytw z5mzy4Iaz-MH{V`gTDBQf+;Ib@M@_NY-`*&q!;938A{?&+e`5ZOg03f~$8>RVaj9=i zg?ew6DqQI~lruUG~8*?4&y2PcOdL!;g-lft@n zwQ<9fO+qhYaCoGciT^QkEG7!vSmu?Kqs3}%M3KeR^z_z@vIB2lVW0Rajx@nYD&H~=*9d+dJ@II6e2M2^*he5v zIt$#m5xrE%dhN@I$3Zam7znf+gOfjo z|BRZ|{1pC%OKQH??p8xzzEMk?aDV@#{-KLQdtcV{6>37E4LX1vK12K5yuQ$^jqzb= zfmQE4z6jYYAFi%b&%rNrXe1xYpasTiHOp2R^&hXIa-T(927nb+q9=VBp!tU4FLB@a z>}c`rvTfYZM&n}J72Vk(O7iW4Em{@tt}or68Yt`0M2NRy#~4*At4R>3(MQ1{=V1PB z>k(RlsZvt~o%zS5FScHI!QZV zVz|S-HeN8*cd{tX;(E#Bz%{WSIjjo4A%d9xz13Xr=;c_CTdPVhNX8>LqyHF>JW8aN zfqbkw1lB{No2opwQ!u7FL5av=iQRFk{sPy+A(3789pY+lOdMUxvRhZK*XHqts*5R| zjhA+HXEvvYammvjVBSL62n#2;Nqh>`L5t(U7~>@i*_c0`t2z8;m;^FJyD-ovSf5r0 z?MllqdSM5xs;#j7V4zB(o%KX~U{zTV$f|JHnii|vx$`n3q~r13>aO0*u*gUW)%#i( z;ff6gE|W&w4I7n}#80oC_d|mO+%_ZU2t}RVQr;OEIr(1#4zZs7XQuxlt4j2B3=fZ2 z5{Zh7l)6(BBp=GKAPL#S=2mYtGk4{REXUi;A`97b1G(rAXCt)QmR}!BCOdKAB1ElF z94#mlgYFBSB;10_d!uGy!f8f7>rH324+|TcEI5F0(a_MG%yP6THF*YEnT!TT@7l22 z(lNg6RF|hEvA8unLg@t`@@Q|hx3>j1MSYL9_dXe|wS^pBN;;|z{q#0?s&&rtU^|Jy zxt{7=ll{c_2=HV2BRnWPKsg2-vmoH-mALuE!T*FSPYgAQwUA^y(<%LAYbEUBQB3Fh z{1B4x#=xIsa?;nhaF=#!oeaLBaL`^!-Qrv4HK9=Fg_4%w6~DB!j^{ja$R#Jr@b>ZjuEz9D}XShzVGlj4Bx> zdB{Z36h2*i@{l=6h(i9h+sb>Gn*p(+xoE%(yv{oD||Lz<+vg&&`db;AP4&d|O$ zr&hFL+P_VkWZsupXpc3ClJI3*UK?0=uY2zLdm`FBr{9xQeqFhGLk{9`w4G87eK#-( zR5sI_E{7?SS9(6dge;^+SFYUbYhI#}^m+~!KXXZS?L96q`G0;WEhlgq%v52bn$jK;W#Z`MyiJu+JHj-I+H~qjFf>(lVOWo_*3nA6B`$|r*$!q2kQ4~} zt<~vV=CKd5)~fz4;#IV|EB#S8T%)!*S|Ggv=N9k1hYv_Q)R^6mYH>LSA*HOu*(vPR z@db;5-5yK~+>b2|19L743*Sc^#Q(?W>xKlGIX4(MYB&^s*Lvw!yyxvGaL2sGi?Eap z16)gYI~15ON~L;^lYwM>$W)VW$W50&Y03F?WGf-*H^AbSpFu`Xu_Ed_HFbgHi;=Be zsG#~VkZ^>baB%JktY0ymuTyy)(W6!DTm+32-HJ+2<8RGJCZDKa<}L2oKM0=Q>iFgP zR$nP|ZjzGWf3f$TVNLCA+h?$DK-8@wf|RW^mEHwuHlzhqkX}S;fY5tav0$P1u5=-& z5PB7q9;(u-KmZ{iUHW@1Ecbrqede7xj+qZL$4oxlA8t2FlC{?VD(Cq-6|Hhe07l61 z>{Fu^7N0F9H$^#!|B*wG)O2p&n`IzG@il^x&hwTn*yw)gRU#=OJI`@(gxueIus$@S zLs8^-9EbfpNr6zNoTPNN_s+G43}sWFUdxv}Fl!W~dd-$+%XS!b?mvI?NjkasT@1I@VP~q;~K)jlT={NICA*#sstlBRVHvuoi&M&~4d}~~(GeZTA!Nato=6Gt^ zN8~8{LF!*XZIqaA{)vv^uMbyg>OrlPuT8@wB?sEZzSpD3QizB?P1uaK9n}_bPnAGC zu5%RyvU;B5`l&cg8g_O$*+`SlFEAwg?e83#jCHt#JJl|K8f8ZH=Tl-h`!6{Pmj-O~ zLnFfEz=a6MG5QTIFo~7aaF{_6dHT@`nmq+kp@Qkuzr30v)0;_#>rX+zp;=(C<+fP* zZ>wg`n1CEw)ZFVZ;O73AHM#y{)*N_7K{=juWJur(i-1XUIN9C<(G;id{I^P!zYrzL zlqGnYiJcm7fv~X6@`VWii^rr#ZJItHC8Z%*PURzbcK4|OmgATAavvSFb<4 zq~!&xuQD$}ySu$odnYusqRG=iF!y_zfx^e+i>Uk^6m+<&q_|jKLnAVZCnPRz+~#!L z;_ExY+}zy!CNmd{j%8_=XkEC_K=7brPqWugGyh9PRrTB%3AgV2j)di+@d@zT({ z6WGA*D`;;are$pWC`+qI$8BYX6_yTo?KEmhFE6iP#4MP4=W=f+!60xi>hN#K2`YA? zT|}w(_5WJ^0kbg{gIbzu4fsf%*4>JlX3(B`=8?1&hMVKNe;dM zUZ`(rJbr{D5QewGjhD64rU>;@&tt|C?+CB!2>BLwe(CI#HNGBISnL#*4IjSU9vj;~ z26*0nQz;gP>)M|CpEy_=H$K8IM<%Tp#>tryC#g_c2zz4pRoFcBF9FCjY)mVKn${k> zfBNzTjgrRb_kDYlOQg7p1$Cf&Ulpk9=0U}wRBiDv|D_$UM|4VJH{vOc{xU%&F8=&k z%zD{Z;uJF~5zr;QIrqSB{dd7{bcy*cE%R;~xJuoy=Y&RH#BAhAsqaPk@Kn)=NKpRz z0#L(Zzd8Nz|NOrYI6?zuVx?oM9`b$?aX+q+IUM>!L->D|sO7(rf`CXXq_9wx5_M{M z`L?dE<96OFd6e`Q?YC4yofZ#6Iy7yaL^%p`V5rIlvnW7(ID&M-$D+GJI9z+D;%6XV zSD?^-;%v}9Z~MI{ojB+!etxq$kG9SC3soneL*i;V;3t>=s6w*uc}wWuf*E3Q>sP?W zBCo<{AagKyW7aDWk&4G(JIo};(j(e)TO*JMY}2wfvPY(dynTR~DAvy|I^`29=D6^> z79HvI5R?}R7O;J22&(QZGBS-?q&RdaI1q+UupoiiR{Km5pa&7LX9{qQj{W_2&kP7W z7mZf4#I9tXgFg;BcM%<=B=r&z6uY$CQ|E%heRC*O+!RyLiiR227H66IPiZo zAp2Ta6bXrX>FUOD>K1EUXy9lnBCDkF`*XJ{VU8{UgCuhJ%HHP&)sJJOQ&LlFC`_H| zp%B?6rM&ebokqV=2Qg?0z&(lpUJxTut_F-Fz@mG6|4>4-B{rAItuMU{pQY0On%c9P66z`E7dIc=WMjYP)IYOcBwwbggDO$9B{W5YF*z0q;FG)I{S#mY`Zt&XeFu59#gI0`T!Jctnl#`b_;KpCMZI_MJPdQM6O&l`qdu z^YHM1FATfVNe2voz2WntqbZ=4fH9YdhzOw9@-t@TK=OSh>cFS#*Wn68rrE+3)52i+ zlGn4c3K>lRMnqo$Hp~DtK+bbEWIjA}zmGbbxC?MZt^#cGaM!_u`xAz;3+sy)7II7` z00x&vy`mV&du#p3DF6y1G?Rzmh>xyJzl_n$C|bpwIDp|z?h_nTx|(jR5b+cg@`}-d znm}dx9UTGMwDpyjLaVe>wG7!Ub+RI1oIp3s)6O1wl7D$|X(@*bR)C-{=)EAEp8zhx zW;`0a9t~!)phPgbU{3dAZ7pV_Uxr#>J-0an(_du?wO4RL0=s}I;Uo=>I++g#+3!Nb zXFBu%JzNqYFvBzM$zeT4BXR`h^$D~#pPOvC&1be zjkIe1wHvihK|7C7Kq(xR>Hyl1^5$FC3x-R2z4yMnp+?xw8ChAp0w!Q~ySFDCX38Qx zYMJ*2L6}s!-cX@vto*N1Q~N{5J&OvIKws+RtNR1h;Jl%E^ydcf$Lw!{@W7_nlT@6| zcUs33u3s-gcCmny3x+DWkJNGVvWmJo4+LGZ!i}AaYiw)`1IsJ6_t_(Gj)43LgR>ea z_A3Y|fG33W|-*86Pz@)aIdE~zZh>*4GIuDsLH1>!MiD~|~MQPm2 zKfkC_ipJ$n3*!ptL|cedmk*G^eE{L=nded)AMrFDDCV70sp0{ zb?kkQ7wiD~x7cYiDj$xTOLL`M73<@WsL_^Wmr@el{L{B_L-1o=OQXOSK02d|;8m~& zsVZL>NADiotntHYF+h1*B z9srxi5I*kEHI1^VLkjDNC@_8O zz6#&GL_$4IU2=*Av}ceZCSzgUf+wbjkM7=yu?a*u2Z9MgoD z=&>l(-a?@c`n55|Sz360@NK+&@6SL>Yh0jz@2egng(kla!>VLBaQcdY8_f#)bVNJ@ zCJ({fd*TvhO?&}Nmqgf28b0re$Y&Nc%f9Kf3K|kE7f;bVLrU_jn{p-h;53(SzrU9) zx&8YAxO(1-|NOlx9p$V2FU^)JfX0jmQ+s>-Zc@X^<5e$q@fm%@LP23n`w5tfhvBq^ zwLdg6_SsomTSu9Z1k9Hr*)}E>Ps6!F{?{QqrD-UHkBHLX66Nx)FjCovN;=)V`Hq_H zWyEA;q)9>}7$0DfT@4QXmjH&Iwu!MFWsg+DASL^vJ-*$f=7r`Sl>R>GdDU4wL-6<3 z?0WJn(vaz5vGW{v5>CXaBUM?%dW^p9l@}0o_&iNQLW0pfOO=-&8Vy%o=C3R68Z2fg z8u~ODb}>^87YqoldHmqrmFXdUWK3BkHUXQ~xE|vBTE+leHRe+G}F#lS`KzvEq60!$U}Aa`!su--<)9kkuadUOL4$x3zp?wQ>Z$bGEzTI zadYWjQ@&0h+`v%tR8mh!fu(kq$@?ogEew3g%~n|18ZzIOUGQ^Xjg}sVLMXS-wEpWS zwwp+Ybg*K{m{!;!-NDgb;OfC4uW7Chm6aCn^$_uuAEQnqO4_Ry%^-ikEqV`ZdQ8Mo z8gKfNBOy7+^A!*S(q7Ar`hV^IiVUyH!UUizIf*>LlmPWAzPh=1>~vpCJ}1mU=V5G` zurrg!b`yppYz77fCb}@_C^dN`0t@7oAIJGEyLtP(pw$iiJ~*-fn{{Pj>p>%bU|7{T zk(~Kt1j7{%Gs*Rz~ z4-OAEr!<58EaAx$Fu`;`;-mr_#aPX0(_J1?#`*L4i7B`Zp)@EFl@cVe`_E=0{3CRy zGw{}D3m27K=Z|;?HZRzeK5=nb{|j}_lfc2lAcDytZRuK+t0;HBk3dc6ZDU-^A`)iZ_sm(WP-KH)j(N=*S0u5Wv`(slEu)PEC;p z--=RAIJ_TS{)-BXE_!Z1f6!-|fvXuH*c23$(YopyHdeaQtEj#lpGtcv8tRjJZWTV2 zPIFzcvt$FL6bkohJr(po zZue>5QkfmxwTH7Sp-^b(dJDgT&Q`Eu)*}ogPsvzKMAz72_Q9)-uWk1?BsFq7l`frB z{pyh18)hwwL-|O&^t0H9nn8N$zx7VHS}9zEZv7fKfDgBt9;~D`?ScW#?c41}uE+$f zucBp>o|YD)&3N3N+YEuf!fKgq1DgK^$Omi2x=V&)TD%D46o*g3#1S%%Lg3I7?Kc6V z^6r$mayc2n>(6|u9m{e&g8D(fdsW}34&R*rL^BSP*L-6*3>RQSIEepiy073Zb@tMG z93@Cj0au3LQN33CXp&*-ov(B?TwQOwAUQc1On?$bAM1jU_Xm{4AlS*pBcQ;$bCWiGixo=r?pL2^eK?vWR{J?%GjM;irTU264%y!1@@&1sFp3uv z5(01z52Eyg(hN+@cgO14D_Etr>I0D4!K4CmA5;jzp`k`q3@~U}+ZK>IYHdB|H0R9c z-0zx}oW_LgE9yIxJ+-T+Hg zVX$E#Sd1uvv`@g>yK==%7PO7Xl(OdrGS&$mp4uU1up?laD@tEqfn*lrx>f_b_Y=hiTVnIe ziy?nAb9;`Q^T`ZY4Ded2o&ec63Iy#Dz^{P7tV1Azi6<8m>~0lNa&&ZTf2%L$y7ay_ z<%XGAh^MZO4x-7pt*y=hga9B(zk#k-9yxnJa~kx7(XG35{#*JMU9)4AFS*mS&{CTS z8aP3z4^rQ~yQ!qLx^6O;T{0KGwrCx`I_TMDSu)(IO?r^(ucqs$_D!wq{LjzleC(bp zDbwAe?I(N5MiJaR*z==oU>tURVR4a#nR#Fz>!8}X*Q8n=)tfi}fgL<6JVW4O<@E9@ zXS<2yEYXX4)ahvS=p?q&Q+Xgh15p>=dNH;5i`qjxP@Kfri&`>3N34hTcU^bzFD;qG z9-k>JDT!H`RO(#aQ;b7aweYVVgXgo$w1%D?D{wG#A0(OE4glnEHw|J$w(>uL`lz$Do zu~&aA#Mvz6JXWFkE*m%z78ql%uQL5ZPTui}uwIHw$PHjn2r&jwa?8liEsSJEU``W- zBUD9>i(6IDGa1ix&l7VCA0H}lCIv%oW%MlV5y>AnGr3=TY~`sd)(ODG7Q|s$fw3R`Gx&lh^n7F`BVHMvLWdVQfAS>7yJ;DSNs@{xp^SFV1~q*y~@M z`%ih9g++j{AXNh=SY6Qb>hZt-ZhHfOdxe~QUry{m%ip-@sezJ$eFyeO+5DWjJpG(J z6V%zBc)gky%nMOM?%Cv~px970@ z#kXg>xyObCqVC-b3uSYigZn(+DuED%F~h2<>R1+tFJ4P6>Uwkf#sQ5FFXa_2U8R%4 z`01L=Do39>k=^PI#@#=_XKb93s+D$sZY|-obs7YR8s^7|TKHcSonPj%;j-V&$AZ7U z@B!#hqNBK>;sjo8G#l3k2Y=kRK9No!j~`ux81h}ZtWj_$fV-msQVm<1n4QpW@2bh0>Pm`8J?I#Np|+W5x!hl7?vI2 z0K0EHBlwILrr4RH!Z9GBe!j6LY?+XtkPdlA{C$|ZP`jn4m@mW$=j^Yk0962MH`^-% z1Ae*Wp_f&AS>4L#Zr1Nh6H zGK)0QYE{)0ZH@NZZZi<0t$kl158OkMfs;Rhp-Y8o__A=Mm+F;I<#i0@-bYmCPql3TtWbt+(R6zKMpu@89?-! z_vQ!@r>4%Y4z4D`P*1}^sc5;7ud^sN=6?;=kD)(a`Q=ZiUP+DnKLqQW`Q!|D_KgFI zm=D{w)G4hUNI*!bAJU1$&pIy-NP9N7ltCR70f!~X2IF?Yr9j3~xOp>hV1=&z5QA8g zRn%;O+ZPJN4+?viD9FE?LcBVNn+kz4!==puvjL4+@8L$GC|RK}?{AuKB{g<+HZJvw z@#YVgj@_lx;NakY**axlng|2}g~F^r0Z@@aWp^=3cuU50_`?&$zFa`+=DvK)P8t~* zIRh$?p!$&1$WEia0&8rW7nq+TU|bi)XBdv{2}*i`J}NLErVMcm6F5Nge-`%vJKs-T z0ATuUNQu8$$d%OSzL<=sb+S*Ub#--FIXMvm2!sPEAj1>wxA&D~WslffWP$mPf|3$` zhwuyFs}ke5IlnUhp7I%;@A3?0c5!im+cgVDN~z;LFV!wWK%}8|d_;^zbH>OIs);xY zu7IacPoTOE{F$6P(CwO_uY<>k;5i!w1`0^nv?#!}7jbi_afSd%^~r`MIA2ste0}la ziI7>Ew7D^~!)p-83_B~L|0(FdRe?SU7`Ro{8N51Ow1Fm-|7p4xSi+MGTBl&6=-kC&Gi5+{Xf>Q9plaAEmbN6_W(-J7Rh>!x6W5s zOTvD{gD#FTNx;y-6&x|54!k{TQ?D-*e1FJ+cfZ>t;rRhkt@-19Z!6$Aex?=ZFGvUl zn=I5Re^LT`EN=W%aiDbU|E;{J46E98S(}@ivq=|D8S99z-@cif4Cx$pYgU&>_}zcpiiMUA zvo9tLy-z@+0GDOqW6>d-w}r*U0=u}3--{9Wvj4vg|Nrx4{okCG@N*+~ zV@I1sso8iBN(OQwI={%%Oy6LiI7Wu5Ug>T91gq1NDBc;p)6d4-gfFyj^?Ry{^g-0O z12UQ_d`xOi&)@dWLrJSZ`~VoBJ~kUtPk3pl+?@pn5n|Bp{j>ZvdsQJ!VU7Y?`=31y zF7XTj0tEJ;q}~5;FYv*S1$Q>>((yMSy#_Gkfw8glQ$Ta@U79=t+;|AHad^HW1%px0 zK%jx(0@JP!$2xP<@YjL0ot#Xc*UYK{_W%nJSAa)s1egzdJ%40Hx9#a?x31{FG)v8W z^$8V?^D5DFX{P_Zu6(1saeMN41XZ#-1lWDFB!02X#q>hvlN!Pck&`>vG{?xucw3*x z4&16pJ#*;vNp_V~wx=N~iv;WTj)2Bz;|eKw{O3(ZI=aqOADM?yfbTwwv{i5dfG;)Z z#R~`f4o3tx-u(7G*mT#1A3CSxysp|O3j7P#?dX^X5-qhA zl7irUSSTg-yyX%cgQ}VkFQAMpm0sOMVtKTR`c;2q=@-Z#gZYA?a!>aZC{4GwEE#+Un9VfAGAk;mQj~hQy2T_ zZ42ivSyy1Hq7WmR=c+_E%TdfrBMz4KhA4>R2}L$17o70-WH?L_vqI~uhlo6*Kp)yG z@<74ZTXf~=0!5|}I`Afp11c>Uc(${mQ0~92tXH17}eBtgzfbr8Z6ihv)%w% zMvh|iyLLvHji-i1fd(BDMwFG7_9@~y$N5fs7E)-t)NnBL!RuM1r{5AgZ3;B}W3;ra zP#paYH_e~-#7@U&7fKGsn_*7`tqimAs5d8Y7ePTDfX=H2o%-R`S`wOV-{3P9O+ImC@O)C#NJ3pr`a>? zB3Sf}H-JihqaDf;0Io#9#D>sBm*>4Bi7?d=oPX0B4CqY;B_&DO+pwqK|NEeZ%jBL3 zte*i^-;WokJai}&%y#vSjUhnJ)`YFFVvO*BYLSjolFUoKJG`Ko357dks>|Ewhs#D? zy$ZW=UnkdBB9U!-dmtq}y*1W!FO>#ysI=0T7wnC7pY=xCFNybObsRN8OwZS~y{BE| z6VlW^o8|dSrjgGdHwK%`9#q$*-(^=~h#4yqe{l{f2YzuYU&YvqJ!(<6RaCevy0XF{ zuvwvq`YVh}8Js@I-k4@QdY5r@0IKmjJZ=`HRaL6oMhf*`7p@z2vdZVa|)@88VgfkI$fXjY0=1UMI7dJoP$^iM1$5yMWv!!77IbM71rB@| zJp4?b`{w~W&3+J31{6D9Qr`-RiaGZm_J;m)jp)^yjQW3m+U5WU&4h2jnSu{IGEyn;v?nE4SNe7P`HBX1-;5 z$y>_X-kWU|Nz;ngPg~UIPJ{J}f*i*01(VceAWSf1tDiY@hDO5QYgV`1(l3g~-r&y7 z2$PkmvnZd&u8+r1*(wNSNPlY~0%A~tzl+*WG$3mKJ6HPhu^~)SJF##=K*TjbB)-8Z zr>n)W?%`MuI~v83TuKHBJB{|Nak0hgeTj~~02MHTD;b7RmIeK=R|q~lQ_zVEhBmjv z5yAtb)hy|bEf?KwZhGWoIb@PwW?Q3ZZ+p*>?EdB3+S(SBac?p+S$TMrVZjB{IA>5$ zNguqxc`i_Db9=QNGO~~f9IGV6T5u1!?Oh*blHviGLj-sXWf@(DFYit_bo3!agB6$z zS=t3MlIxRuq0O^0$u*;vS8~da8hOq20o;OyA@7p7px{JQ#>8?38uqB@@2-y;1J7KA z6w7OnSP>*Ls(_Hn#D9A5whxU=jS)nzX7+vAmiRKG_ObKrFeGu<7sr$I0YP1nKb+|* zYJl609cdgvAKvpuM-^}@x)R0qQK)AqL&0H-okzR0J zTRV2@=s9=_1w)ulAOZmZZh6k&)0KCFEQ5x96V*o~!5bVyMG_1-w?e%7x5)i zt^TJY*CcB|a=m8plhmdj;>h*t5;0ys@ExXBV4RXETF&o7+jOKUGnH(?h@HiKbvB56 zl>O<&zs&5ECL*_Vbak$qc$VuZ6z+hFQL}c?$X%Q?nyG#mr(dB2x+X42jPFA?)F>Qz zeIWJsEI?j<48rbjDrrxoF0D;14&+%xz+s_VT3SZGjh-#Fe^n%uHoQ3#1uBo@kcS43 ztUGVY07AVkdgl_ijuk;Swp;pP^t*V8al3{2d1_SU1U&!nJr=-2uZr^Z-M7{r!Nh;& z2FL)iG~VkBdW=%7O-SvWhlQHp_-87-m`pV-sc2(3qMW4~ibk4g^l-VS-$IS|HZ!Es zIi5S;eRI!^XFVBQ|euqOndV_eu5_ume^=t^$P`vna<7UPKXBYN0j)2ES z>P^`XZ5`>pa1$Rf18COgB_$;%Xs8unB#!%{3A2iYZTGn-Pe#ufTUguWGFbN)&Zpvf za;4UT99Y;*O^dcxE+N|#NZY}#y7X4fAlP;Y;3z^%9x=lQvrko$9j_AKikpkh$6ny& zy$R(Zws~h9e66@V_f>9{yrhxOS2&iY4joZmI;!5aawKe@4QY3OSgWIx@pZ3_o@d!F z>88JvRC-(20d{tQv@y5TS1*d#L&1v0yZcs1MR zRE(B1&4N!~ya|7?<4%-7+jqnJm%-W?`$f^aM)-~kGLF}|2`92yT@j{qiYxv?m7mm%3>l=K5yP; zhAb=`o6h?HZO-=-sGCqYgCpZV-6)tmrDG=PX{c0Sl)?r~JxYF~x|@jU2zXJIhr}EN zzrQ{6m)~CjW-EoDqqZwDOAL+*I+J2-+({E^9IPK`9d6N>TSM0@fb1j70;D#7+3j1F6-{g#uIr~ndo~>o`K<&u>Bo})aQf9Gf(k-RSX?IfSaNQskz=8AyP(%twCMJ;^?^=m10$FK!R%tpwn+)3AG?fag zdaws5F#b&?Q*6KfEo9w^O})eK+;5u(m}qP;PkbQ;gq>#l&jU%8zfTCy(^yw$wxTfwN;;{>jYUWHjZ;$}?xLXQ;? z8YzU14CNk;=^{sUkAi)gxm4I8Haf|@dF$O+f855*laGXAGE}xc;Hj{QVcc{dW5r!_ z>WlwvG|V4|FNi29dR}f}VIg`(-QW=qXbtUuxWHM!zp9z0B&y^6{jMF1ngSRE)IIkf zgzOhz2ugnbgxF)8`^`St5~yrA}J!5a<>DAcV5k7|q}78x=YU2mzQ%!md~;gx3V% zJ*iYN%%e2{G=M%pnwe5~zB!#i!}CehISxDe^uQHwhzvoy7r<#ZHqRa}II(;6S3VL< z&XDV2M)^#u{2ZhC2)8EQg8~g^S3u2vf9!b24cM|9&BaR~6^)Z&V!1Rd^^OLao8zFNU9Ys}0g2sYI5n^5 zHGZdL@$N*VbkRfbiF^y^yGY#1GnTw*`3pC`C!1HY-fD-gF3m zet?zE9OMR1y;o;Jh*?no@Q7DNy(FXr@jFc3oTloQ14L-8FUL9?KaAxeq2LDLbis0G z3~siQFBP3&)z<YGPw~z_~E=phc!nolDx#?<;F>N+S^8%m2}!BRftvBYQL8tqz6 z_xVsxRm=eZ0f!iNO1>#B)`G!MOxep*qPHPDZQL#+TZ{uF7bkw*3*1tDO-Y#NU_@CP z-f}kH+4ckpiIWpND#h#TWFy9s_kJafb6x%b%)E|7LlCtZ_2qLx-|(F7`7;W_#EcOK zXIo1zB7UV4d%iqy-CE&xyH`h5e^*zn$BKmGw`7dM>^;ww&X(<$Q?O$Wn9ZayFc+bK zvv=3;U#n5!g(LT=QGO~i@w8c8U*B|VRRy~p2kqZ}=?xf!C0?D3;i1yLa^;HRUmeG^ z&`EdBZ+m$G^wT1omEqz)Qd?8X(W($$2C=e{lQDc!7DM6YE*%-_NAn!mUgUFfylZ}s z&r)=Qff+~?!ZP>&G-ug3B2Ewdr#|blGn$&3?J#r)NfEb|THUJz!{3W%%9BX4I`xZg zb%?Rdm4{M4D1Gu2k`_$-s^AE&cg@Wnb~avQ-P80bglieGNWz>hqq4}hhVyvgInv$t zkUW`6SQ}XFH+|zk=keo%JDh_&N3;S`bcG>c9kVCWT5{dD=w>b-4&TOWI#W2$@8wZC z{QUBMs@C_XUZ4`Mnw{pwZhdLDk#Ti*R{--bS1jgy+!V+*->N-=aLJ_M;o*}{1mp`y z(3r>feL1mP_Mx&Fu~Aon+6Jfhzn0JbFY_Nn{Ac-`MkB!pf&mZzimB8XEO7qT-c~1w1$K1@`2FW_6Z!$#{kk+MAUQ36w=nl~13a#=J3H+EYil zwgKYo_MF?83_SjXy%Z3hswqV_mZz<)USf`_m`KQsJ{R_E*~!B7J-8}q{XQR(&~izH z0!|y3W|U3dpCxxT|EpK8kVTP6>8AI}>|V+2+=h)G@1Nbl4Pxux%%W$@oG+1Q1O`e| zP-^~z-|u8V{%-D=yvAJ`jei2E;#ialM)k(5dcvRgKR3$k4mVmJOj(VuWxQ@Emv7l< zD7WpoD$pP0K4(ASAKNn1v^ggl(0tw=tMIO==}@ks>?xxHJq{B#rRe?<+gu)_7~>m@ zmG~Rl4>P+XHF5<>RnMP)`qWcYolUDXl@!P45U+U}mwwA@o5``M)d^ec&k!~xU?LAT zLzJ{N^oWVtets{*c7Ay8oM&W&bVTGOmP*Y5X_%n}YNcnuY8MRCD*(cU3YaQ2mY3D1 z8f(A}ljeU1rZyQ*jx^REuQhHRK9h>pGMy6V?>*T+P9T1$KC+GKE zZxa5(^U7cZDbrxv|8;7L6=T{GsfP7Z&vZfB<&K(VB%}~=c%de-a8^2SK$<$g%lErK z3#Tp-2)!pi5)cTg7KK5tX>-+*R-cOH`)d(lhr?AdjNYdhN}oO3~ag6(0+%X5UPtUcUT?1>V{(4*WBqTIxw0@{5g9&D(u55lRPgT~V2f(F7a zev@+>fk?S ze@j7-+}?%lcu^IGM}k^>i`|9+F&n+XikZ5>U|S&cc(*sf+ICF&e4zfrp7 zQ2rgDou60s{6>3RiA-8~?59i%g>nmhcu=K@o(mN50=Q^(S z_4W1BjLNHk+>RJ;oD&HUN}oDJWxBMcsybHbv`S7%S>Qi+Ry2Ye!ZAgV{Bo7B+*S%F z%jQ@K?1M-62T5aYoAjB(HJU{|82snfch)?SY1dQg} zS4c!^h6^Sj|8U2flUPwTkbK0AxaaMUYBsi)pgTKYW)%~{?jI9w3UH;o2TTd!%a8W& z2j){RzoejG6K7r?9coGS&w%;J=-ixjIBaMcX2Gd`x8SXqGq)t*dU5|&n@Ln$*q2!+oL!rmB``+|t)x|eT#wAqBD*irdXeZaVjl|?RM4T^ zj{d#|hq>+iluLWg96L>89bRAWo{R+V#;6exQ!X6G=oG&K=ZbKw*o_zYr!P4zJq22P zK5c=0*Wuh3{(jiSShx>m+r!bf_4G_2z{Ic3JR<3a3Yw#F1his5bpfc)(T^p1a}=rQ zPjPi6*$*vEjj}9G@L1+@fwh5Kzgb`+)z1EHtUJWiqokF`&;GpRP;Muvv>axmjJfJ~lworQ;{Dmo7u$KNP?Rl^grRr+J zNa0Xk^PPvW{`7JZoSIQlISx~HDrNS#%MTxGkhT7Od-;gmiI@9b69nf)KauQ)U+{Y+y?tC8m&(BnO|BGBz-h#iR!ZI zekJk`mSbvofSH8QzMs|=?Ym~(Nc8xLbGa9V5SM#jbsUs)SjX3h62TWAI4!YmKQ z59XR_6G%%7405L@B!awx{Ft@(MlJ@M3bxYQw^!=7VJienFwlTDxdMZpl0NPI`^)BU zI6i&KdkgZg?EQ>B{xHv$=J{o!97vesah6waZ3u@1ym|bUlc1SY3h20*)=D=qJIf8| z;gXSUIwD9e^_>%-06TxKPQ-o)!WHDz+ZVq)qX%HhePlPS`~0No&#$jici8K6m_S#% zu;H0kuk3Ome@9Uvx4HP%#Uu|;PXbA)b&(Yy+3!|794m^k7rXJg<2Jci*xc* z?1cAi9o>O_sL+)>+}li{vIgspZC(=9+Lqgh#%DOy`vpUQjJOD*uEPW89p=;Y4Q(EA!x*H+IuyFhH>WehhUJ zjegnbe)SQ#X@9>2*lQgm*nhX%D4(l;=Kd(u#Z$jGBQV^1`2YU_e0BdEgZ zU#C;Pj_I67-4zs3FjPredOs^B8UglFt~n~ttkuW-u+^R|d!;&jYBXtpu&^e&y$3b9 zwGN4_f|T&%z_$;>@X+k`WQh}PfsYdp44@4SAAVL>Ez?v&FV3UL?;dmj6244+=?~T?x@Sj%BK51d4%9UKhIZxg){yM1)r?B&2Mhxf!{y}Gy?b~nJebwz`)gT zPF=QJxAvweCrIAL?q`g_RkD(1Xf=Vv0fXqIE(xUjQ@nVbhK6Tq3S(D7clxw3M5VA@ z^P3#f&*2y78<+#9%x$gPXO*QEW5L*{@PfKMOS7zDhDpdKaiAQ?E^OE6c>lS5?078& zYH457?+A^hD_XZ+Bb?K{2W5bZj-e*x7_Vw7C>PnB(Kfd*7ZaC3qw^rM{l3grv$q>b94B6 zEj!k9?d-T=K2cej=u|uHfh>vyaG#DHJ0PdtonxFt{)otBa`aUsx0^P4t{Pf=)1y>5{(|7-?2U3j<~7>p1-S`wtX_y_X`O`x1M zDZ2aNESXPy&F?+*k{ApS7P@PhA|NNZzL}wqK&XMpnE3V29Sr&VE;)SnIYE800Y4>> z<>@izg!$C$Ptr!m~P{3UN3H3g-$QLnGtL~pid|BXuQ%?>vgp%z&Yh2$x z4&9q^r-cn9)M|$a$9xL~8r1F5vW>hK9r84B)5a^YMTjn?Kw%|3`g_Z+dJz*#6#MOpMykv0rccT!I zk)6#CEQFF0@gJ?sTu??goWOBL@!AHH3m?`V@gsbCP6JeN6{zCa;kHpw?=E(H9@UYW zNz7?mv7q5LYAju&{8U|Coz>XfoTF!-2lSsCXV+IF)+kR#{c}Nr3yn%FdHq|vIcaQX zXV=7UCvEiP4liBh40@0mo-}z`jTgPkjn{y#>Rd94zut>r#B3pZg~wyQ(N5y!%a;(2 zYdrhbWpUZ5AQO@;qlV2ILNQ=_{CGGZZLt*+o2ym7e*E;QAgk*FgJ<03%O8mE)w=c_ zI3RyNj}cYO@#k8Om|tBLY4qSwoRYolRX$MOP+NNgdar_#3bhYoMB-DhHDMT1$p|ma zCfnQQRUx$|<7?ZRt;1ksXP9JH`?E+`??i9GV$otpoI#=jCB6Cw7O}*?y-h|`)6rpp zN2Bq=ScX#{B?Scwt8qdR6HP*Ej@MXv8?iGUQTl9gRPY%z7&3X65>^1u(%8oQ1nu~o zE41xsTA3#{-?E40#_c1GpD_X~VsAeE#$AZ>ihU{l&AyT z#H?&=O7Ic?83MSyf=|BT+Yxp7h4_Ksc&AQZHn^(oM5UB-_;ZtAz0#9;$=G3RPp}*c zHzGc+uPu?u%IC9T!+~%tXa3CqsQFrZ_C7RHy!RTQ;?ox>1h#>_|< zGC<}EN&*1>!l{{~D2&zOvBtSnQ&@-_HTSQjMjt>GXG%Ic3K8HacD%qLZ`|AX=x5 z%<;c=_-W`3Mo+x4CzOI9!qRJRZ&&my@Iv|1UA%dcOUsf?WmniREK_r%L_xic;zZei zob#pFTOebC4uA~YQdT&~dRSp&SGWpkNZrHS-X0_&jFlC*_GvI?W`TLe%z6XB){+9|m*L+-F z)aAR+=299@qk@|3==k^-ev{f25*wIkmcwYue>`A0M8^VUirtv(o6_w7ZzNT6tolyo z*vJh=z6~G%$_QKapJP{!eMe~qU!`#sZCG@4FR>p9WeQKi%?o?4!6Mw1(a z`mf~L?n2v#o1=5y5$gJ$cWV3@OdqiA{<>Nn`6j>)HeNo2O57NUxQvpxB4_)aQ={-E zqxYs?xFhfn!oc$7I)7=08>XWR9}dnn9#{6rF)j(o%@tp$O9GbD#oPqKSiK53(ynbU z)k-z^9j_fXC_2{qg3gmQQPg(97bH+6#@^cJ1dJO_fL1#oqtfpgomnTw@#TSwbca}3 zSRx&JduJwtm{adf)TbfuC*}BwLGPWtsT65hctwD7&$?vh?s)dA_luW8yQ20_XQ%43 zkdWM^6n#OT%;=bCNU>;ev$lCZc>2egqm|Tz-F_qQ;-!+O7W#vy>HTgVK+Q5h)9<$L zxRdyrYRod7*JLRV0H<5Vbk;>nu(_bZ`tAadSza=p6^54T(j?t2-i~aOd@rtf<91N>s{PMFC8|;STpC+N0c;vNh~r&&(dg^ zW}!7AL*FrubA4;SI$TCpNln+Pdgn_FlYy%>>TZY8e!(wys5+fbtJ~U7l#!u)EH;rRhUEv_W{8YGR|vMbSKqM5-C zrt`D{Y`2u+#8^R(!uv%ShlyOAObV#KdPKsqicw495>3_4;+Y%-iEzTDA}F&bdg-aKel2@-fAv5=8TY)O$yENB zCYg^r)Kor0jd#3qcUCJ_J^cz(_tXj#wV;%E z{+4<&_M&T*_|V@RiL`w8lA}~)UeZbQ(yL6og4J;Z$S_M*OuE_^A)Y6>NMdC^pb_BY zKxf|$f^nmQy!f$#O(5@OkZioi=Yf0#g^% zdHzE6TYwP1)o^n=Or3?3Q|F$cA;FO9E`$r71DTx=38FM&hH|WRJW7#Gsh(auxuKSN z5zs*D@U+u)U^qq6nE_|K{Yjj$<3i$l3B7q@46twxOo2rf=0u;ZN}8SFK3s||U)|aX zbeYz%#OF+aznR2HgZw5w?qO=5KWkkkkW||d&|ZBA`&iW@%OaQg2Zbd?F-3RTm10?- zVCiDWG+deMIkzN$@HpJexE3V}zxteo8Y!V>q$W+uSJQd`e? zk^Ik}KOdBIbhj*9+bt7`qsK#BVH=*Cb8tm!pdn0P*Q z9?YqJayaTuEbMx^<9K$zoYms!zQ4=_W055vy7e_E?$9o`TwY5z$BQyUs7lC4^$q-` zmG2`DbA&L@i{^}pIBe+RL^}c7_L`O7q1&d2maaKVbMe)3X&S*08>FYF$A;`Jz)f10 z6d=J3!A?$wc>B8l+9advmXH>CgC2u1HJ$(|t;LE?6>Z`{MA^Y?Ce%c!zn+uf(euvB zQ(=P_jK!{#ubvpK%!p!ZJmw$q_<2kFET7@1Ump%Ou@b9jGL>2_W$~x&Fpy5dHsR%O zO!&zu()XFTD=NNN9%*RN>ETa(xMo_u@a1iNZ=OZg5hDx5PcH@qmyiGyNgW9mDAJDa zeinD%o*@MmejM_sB?qN8jRUt{sVZow&^PV2H$^pb-NGz;3-!Rr4EilCD=UA?zGx$2 zysp_JKG>R=^hb5186^qHSVQE~F&o0Cm@fP8cb}1)E)^ji=HGvBr4$!8sFu=S3_Qyr z<)SRPwUq1hp&^L*Ny_K-xREK-c!B#$(6Uduni`wPf3CdmRNG|;Q7UaZPkRUFPNLin zL%lBXIDA=h`E%NsAG;*xjk*r*i1Pi*ml^cVzrJ4=qAY1_)%&d}^xVONF)41N1pmI+ zvZZP!$3k@N&TQCF zB}HmUW_K4yo^Tk~`jZxX^2+kc>fIIp5pV+Mte}}qqZ=-|p3oTfx%vs17$tIyrWTaq z6s}$^qy9J}vI;pj7FD$4BO~WKOq+rgIc(a5&DoXcBj9w&d%-G_2JMP&r}$SXl4OWL=OnV~;}4vg8=#YI+C^#q9ik(WrT z%SvE>*31kCmVht&k%z6jGxKE`#@^a5d(3!4pt`e~orPW~S$LF9IsPoP;cDr@XX3)V zMTb-iuW426)j6FtX??6CwS{+8K%lt~o0*kG*9^J4L5%??~9*z(gE0Z6l2nQ&1K5g0^91hEEHI+fYt{azX@hjjA9a0VZM*2b z(0mc=fc(82oQ21{Lc_gIw02jWh#Sgh&c6`$HFIO|DYnA@jW+&54UCfD6hQ9}Kx=3e zf)OfO)ILQG#d>NaKD2y30LT|C+_RwilKUbDYI2=G4wKvwby>+Y6gTE_jBagAGjgJSG3U~O+ zy}V2Y{_EgDvsR8Cm|M>3NQN!U(Q;hs`32NpzGO^Fa4aopYiFn=A$L4(dAds(=$zmz zL0+Ub^DuaL)&+g8UTE&KZh&GEz;Ln|>E|MH)y(XFv|gSrcytEvzvpdjwv28txnUGxzQEII;p%zt1Lr2_7lA-j8|HHPD4iI*p^}tw~g+g{m!(*yxtfY#KkC3}h0md>>8GQ8yVKiGTgsHpe;-5bT& z1{NZMgas%FNK1n#NUM|#B_c623?YrJNJ%#+9Rt!0N=SDz14uVWH}kx|xOMOQtl#f> z&N_cQYn^q@{IS=4uYKPNGxPn#`?{{zg+5$mY-q@?#MT>q zf_GeA-lN9Y_*@FxsgWazDGAgCe-1Q_)ou$zeu zP`mv-bhI%X7Yiz{DIUPGX)_!)j-eKRt8UCoHQff&8LvcN#(o-%Uf|wx-8^vtMUKDdk9 zp?I?GI|&>&&4L0Rqdp;6K3FR`FeO*79{2es_9lk{{QiIOVmAGP$43cJOfBwy9u0kr z%HFWDTwzPM0NMRiAsYz^2~^xrX3n%#N$NGFrSb*JP)9XjD|nkmT6E(JX!vKM2kqy!zS6=y3LuKwj3 z5i75uA)5&TaCoiTL-hJ82n6toivPJYDwnSm983|%{AjxK31z=Kjqf!O`fvI(%_d^8 zTpc$d{co%q|NQM69?Fs|(+_%Z+uibk#rZ?vjm%J5I7Ge&mwWNZqkSG8%4ISk0?1{Q zfx5+fV#Q@!7J|MbHSrPLCf&Wh{=wHnxv@yJB3$@YBO@?Nw&6TCeWh&lWi0DnA{v?6TyR7g2t*z;y zn?L35No`1ybXIO*A%COmNYvJ!4r6nbeA@>QAr?IH=gBTCqr23i*tn;l;f;bISZ;qk z{H1s!Eh*1QVD?1ks{%`;qNYZ5v%os_B#*0ui0?}O{W=F?B8LW9S;$B*H#V{i_2wFl z*Atz6F4I&&#VOK-3>59th0?E7Rwgg)VD>GWHYkg<#b?Nbg@spEma7qoOnQBBN~*=K z9U=!cPMSyr_%5h<60)I@Ax4%t_2q*^U&DX=R{M#F%>O}d6A>Y2v%Pl}{$Y-olYhVd z@4rCaiT}yBWDk#l*8yr1^2#fOZ)z0z*8iZ#z1I&5tApa-fVDS5aJ^iA*XJOX_+yTe zcGfhYscC_nNMybRfW2|5L`21Mx_1+09P;n){dvW2-*6t_%2WIERP4_ugH!%5U%-}I zXy{v_Ji&j2pHrpMi~)Y`V9;H5{PV@OKShGpbfQ-`1-E~Gn2@!U<&tG=Ox``X7|>ni zlmQztpw~6S`NS0zd=b+E!>j4^Ha6lrqS z+PAdM7r|sa1Qz@qN5_#AG9Sco1N`!j$j0^xrQP5`b?eJOFF~Yk7|lC`L zfa{@#5;IUhPZLeZ{k@tHxzda&CmR?V8I6Y9D(~T5p+)r_xP=ncTfXSRrU$1Lrjg9Z zts=4p%mkbkjI&7e=1K{oM~;wiO&>dU>}f~s8usFt zH?pG{Qij6b0TzYO#AVf@r@?mAfF{#IZb*v@UcxP7ypUE6sI#+M{CUMI*zf}UaLCfJ z_sWxa`ZO#Mj-N;z2{50H(7aV11dc07$FhrwaKoQTsh_6NUyAb>yR}4q;|%$@TH&GX z?v^WYklr9gf~m`P6N6P1pqae7wX(9pj6-y~VNhTibg)EjATl03cC?p@0GduuE|03X zm!uz%JNLQH{W&#&YpJ0JdyR>StL}$)vrX<>*pd6vQp$D01T55H^zpPkf$a>9vk_(x zQKZ0EhK?Nr{ZOya%gYO`8n-n;#l=nLPo|QywV9K$ls#vZplEB&LKQpMvT1FE9bT`6 z4(WqL1y_E5M}E+J^uAerBa@w@w=crqADx668Yb=S(}Z0SCcC7FVTIf24L<2}850@n z?(Q!29O?P<1_70HmCV!I+o>~J%}Gzh=fQH^n|%`pt;uBj$!b4WN}JkiQW2S-{pWA_ zw67}RK{U*SFd5D}sJ25gYHwf!QX9fWTl@N056F|xNWs%LZV#G~Pfz9;zB7#F(kE>_ z$hme63PJypUZP2ZF^H!XxWY&nFmsFpo9+^MMkXESOte%)m~>!0o_qMaJTeZ3w{xnK z^3L91A3QA|#~Rfxwy>pVY?k}SX#_(_7$OCqA>;beXOW-JtJfd&oH&|JyZLcGb#IxB z8EVvWPQ9Sw`}ZD`uBdAa<39OX4ODj(|4P)xTc3ku0sC^7mkv03i|`? z0j`o-zw2$N?-R~&gotYeq2bs+zdLfg=_z&y4357`d@P(;eEd~QZIJ8*o}f-$2 zXv5=gsO1=+(T4*sxPz=-qucarfi)|8pHp{=lWF}u+iXWxLvKVMzbtzB@JGm`+v9$$D4 zvg?U4g`5WrjSajZKVG+|sM2$@$epS3#Kh6C`*Xm>Q%}Qk z(UjMPMFVUEy1h9jvc1N|yV;h6os&n2@W@Pb@AXyi3GiU_^0!M4UtOLOxXF!3K$X$~ zHT-62-hzd;*#|hYxwxQ0<^-uZq-a$OTH&5_m7ZG;o(dU}k-@=Brw4cF41b95f}Oob zg2~bJj#?1r({7YUFH(YLC-2o; ziF^9!Ya9m6k1+;y zUBBk=bLMg+coBWofQxjL3LJv{;X8Zpo0M*vFe*VGM);ch&`AdbH-8sb3x+Sklewx&x~!BgJ42eS z^RL}5Y8f0-H{(b@PA|qX-9p*w;66J;42DwQLgtqdVa_jXm%p|Xc7STo2}hgbRNK0K0$WnDl2!dQu5q2JOuU2;bG; zNiK{etURjwOnQjKM}pQ)(J@uCCc}1K6P~){$&DmIV{1ZeT|oAAW@ke2+KA(KJJphH zA(*opEQLWO_ea@Ko|@)QV!8`MbX|g_E+FBJiAD6cCn+)Mj;Dr??T!nr6>XTu`I7EJ zW0#LmC&6hnS<8eXIc;#Q)TMHHWT%Y0RVx~eCPz#H9+HeA2@heTHk8< z7v9&Za|yF;mj7Z5#iuWm;1GnDq<+nTMaRm(@Bx2)v$$l%k)NoU8f-mzCU9pDEUu{m zm6&0=6U#OD{t%13u3O_qh6};jZeujER*k9O&*K75j-RAffmO}2tDwWGJDIX$!yIww zp^Kn}`XnmExn+?yk7zV#PpGJ7?J@wQnKAh*aN&5Y?B)>wF8 z{`t9E>e|nr-jK7eJ*l<%Ts7X8Vv3!aS=MH@mu|prp%7FqR-V?DCFBc6)J%cmjfQJi z)HrM#&ALeGSPL85qL%Ph@Z@9&=+ULyqlD_%59Fhj^V@|80cE`O=Ru?!=?HptPBs9R zO@7iJRFbm(73n&oa_ddB+h1>#F3k^cYx^jtPVgo)s#iu^?S@2_Y?E%RR|#K2fWxHM z48JZH4(xtE8q`=Dxw{^+{Uerk&o4)0`+_-WGO3n==xZOcD%BaNE|+fCbyfE5)V{6U z>lE7XSe7yVgXY7|?69EX(mSTPW`^3w9`o&g#bv2tP)vu<1JPfpuR3)byh zW@+dg59{q^{AJGkAt4M9LmuQ#*wJarKyEQx=TP2v=OQstF*zt%EF6%Q2{8Xo&oURC zqXq5HMjZ6^kF$(319*7@V+unBbfrSAA#8Ex{P}C(3G)dJ#U*mLma$wYC2Q+KoV2vmo+ZIG;`89lC5!@>krt^fQ_Q6VQ28!kU@r`SBD}`|h;OG5 zV(Fxona0>^sk(&gdrL81gR)g|ck19iB77n8gEHR*`nc}H)^o5PeS&8%*BAit9#q24 z>ZZ!z*a9W54(tX{|FCCl+WR%|%yCKdv-hQ^Gu8OS#a<$3YD)};PMDDK%+5~Iz#yoi zlHs0t@_g$oFO03#3!aI>o(f3k+1k9kXJEY#RBP$(z9!)n6EYm&=l2dO3SOyJQL#Po zyR$q$Fc)-;JfmU5=&%RmQV`a-`h4~rkb{sE+)TFxcrE~9;A)D73t#8kvRkAHj>8wU z0=3KEBC%?SzCEJ7wS;Zf`v?H+-8fI)+D-3Vc>WPvg8(7F33cgymLn`g9JHEy??&DQ z!>$r~7BC;1-bEtiV7w;#G7?e+?hcsbT!keivjh|i2n0MDh?mHsh!?GbO7zkC;I^^! zTw7rd7A6jb6EQP9!*9IKU+0NVO_l4nb9l{5UVO0?9CAt6X3)V)3?6fsY|2pZm=^T~ z)demgO&mFmI0^7*>n@FXJk(IQLdqa#xW)?+SQZJdxY{b=g;$WWft?{r4c=H^m#xm+ zQ5TmTqb1Qf5h*uS+S8{mLEA7-gTE+`(e8_b4*~lf%46aKoAk6;--D%3d$~E+!b)z| z2JEAq!Nc^YkTeB&Y2@+vzS#Wyo&%f^z557OwD*x@es}IbcnsdohF2WO2+w7=EZ`V9 z2YX{36mLHTU*{Q9j~2PJ;jvBer)0E#suCYJ@J-Lc zJ;!b_F7R)Yw6#!04I=2XD5+|fuWG~DBm+Tl)qnv19&A?*)V&PLSj#wwzAcR`RaI70zNa6~ zAE*}qLV(%Y)+!Vq*JHVg4KiBoPta-&1X!1-%o|PTbna_dHIdXCI4rb!5p2Dhf5d_b zZIA{V@N9uB8l1C*X(mU&?xY=X1P~paM*NxYed%qV;b)HZ==GGkjI;XPfMZx4k^*c0 z2|xTJ^|0{S{Xw0`c%tCx*|Q_LDae3QTA1Kfpl?u^1B-3#G6e@6@Vbbic>a|1*k8mx zg2K`0qU<3ONGAjwIQ;gWl2R<1EC;-^$IqVvg~TG9PZ=xx(mOri&2Luxs8!q1*p9xbY`V1aeX=HHofXs?|oDGOA->Q zDYtSsxu8(SB&)Lf#p@3Ua44=UmLm%lmlad-N{ny3;r(#c)ytntVNEjY)YsFi{YHF! zY@M%5W_q|Wh)o)7&LeQj_I>tfP|nUS7;j6cLcItB|1=nW=){?UQkAI-Q@|CPr1rE0GMcl{PE3BHD%hUu z^PC*k-ico-f8#aL&O5Qh#mybE`V_8JHLbd9!EO|xQbt>9OqzjkrQd$Z?SW`AoU@GY>sQeHZtZWAU=s&hs zL3ibN$Dh0Wdb`1|KLm6u6@x*x4or(7-17&4@&IbOT^0(gzVsGU2vDib*N5vY9n^V zx3qRLu+u^pTk%6JEtm4)$r1~Tg$&1yow4*oT;ZPv-Gw6E+^D+eguv_Exu9`%yp^u) z^NcvRS?}W{%X6r2o(;j7@qjlq>)+3j+X%;enN$A081SRS|Kr*`Z(^!BAHvGlrOT?qTSNDQF)Pj|YL`3&g=hVry<;`oLy zW2-8}A}9YSPs=ycEf(~G!-^zeP&%7~?x=^3)EKBOR1A6Mux8W~hp8|qOowytJxxv1 zPz!$B*_(9}LEYRe75&gCh#9J|u-l<^@lQy2e&#II z4JGAkn1!Lc3WCFY1*Ed znM>AdfWq~M?i-FZS>O>`(Ftl{s{y2b`W6keTxb93Y{S!OoNl~k!f_4;F+6oOH8okB z(Zg@2xdF*?b&ZqP4Zfu+oR#+st{vBQPUpxg@$Q}T|F7QkYfXiJ z{{OF=K?&kAO2Osf;~lf-$d4gn%OmuCxR$-Q??z zbmbl&g@~vie1MLuPJcJ(3jA-CfA?BOskItXk{FuC`am5BG=K8;B|62+MqUDgy-6nw zLuy{n+(0OXLQb3a3?2pD5f_(~kx9WPLE5?&F5dNQefYks&~gSTV&GO6_3eO*ab)77 zVt!a8!$;!JP_V!@G&k2jxS+5)@9S236k%gSG!mj{TfcV-kzDKKeX^pWB~<)2SqfWn zLAQF28VK3r;l_hRxWK#-jQDz5@i#16jw+v^x%aUpnp78-siBefjWJF{JJ;Sp@nX0* z7gy&P0LOu>PKO_^))mpUvB;@4x(n_-)W~PHR+m!j|(kxJY0Ge?;f0?6;3FhU0JbS9J@gH^5Qr-hz0>g z(9@(3yVBE|)~$*Gf|Q6N^kW0U!Kb}l3?fy`a7FQH>`m7RJ)-|4B}#X9`}JNFMjwrt*FGlIsBSx~Um^%^9W4z!K<=_ywy1uz-^Nc?*!t^!g3cGgM9SguaT}bx7X1L*WGV2uwu&wR|Fc;2G z3F*gV0>^)(eo|ow_Q5sPs;t)>jC_3JpagNQaWqC|UQoGz|M829B>H}DSQ$$%mNsC( z-`k=%2@&>3AjT8_Za>b8Z*Ol$#)Y!?pB$4g=9GaG8##}yEi82=9NZT#HfNoLJ{#Z0 zq}0@aiVBN3zPREXgIyKk^Wpq)*|ly*7fh^A04_oMVXU$(IXFe3QBCuIQO^Ug{gWfYhxrLmxRBe`ma!P_~((ey&v-c|vJL`fNB z=gehttYta?`cb&z?Ccze4Ut9i<(uhB?FmPjDkPw@9JwBK0m0+P#lj4RrkLd35IyeQt`{(zAe_Uidb94VeAOvV{r0!aVC>Z)qU;RRm4PAtbf)9 z2B0)l!&#*gZrg82F0>3fqu6}2bbS%9R)9V@K3hQ*g2H&8hzR-%JgI^CnDO@z^TOXC zdA+%@>^l~x*Cvi_KdP{*`st(ib;|0jxP5gyCj|^{BNz3jVAFc3}!9AZXo!wy-A7CyHzMtCdgCAnx>}UyJK_qoP+dK@B$GXMQwa_ZccB}87 zULLMrY6>mAFCYK|Fd%^eN#b{kjAuMiNq7>ChHpm1Z*jVLdbU5i?Z7!;v6Rj^^D5tp z-V@kqaXB!wZ>0dEM;u+Sa(z}+SCf2E(c6M2?|;t%ic(x-YhT^yir$NiiM=^-!L*Dz zw5)7@n-KG!Z)+;#>sOKMUpk423K;fN;+KFPF%nC=9l!lEHn9G19L@qn$8B7xvjQ@7 z?#9Z?^lR|_lVvAPaa7hPvj=eJvD)%!sIy%_$fX{Xo7 z#k<(S7uT1HX_=TOrEKkHe9{}euMNgN4cqLfzBW|kiSNs&VaK{F^3ow<)dN1F1S(!1 zMh5u^KU}&K&IVCLK=;FGEck@_G6CA@=IHmmzx>CTyVrs@F5PJSL}r-%%P9&n2d=M( zn+k1fgU!^J3;lX`Jfel$02>=Fctui;TM{moeVgzYwK2|uI_`rM8pw(Th8Nld=`M3s z6?Q_{Uv?`Ss3q@V_3X>}8ub`$Y;1hQ3*1Vv(CPy*F9Y=&{u!qcXN5#R` zT(e)@GG@r>{fNykOhYdftFZ8ZJ=G0Bc+CDRvWi6ZF_!_4mJ93M@&n3!+FtQ> zQSw^)K>ElN|%U1_s`RDy1|EdXF+scQC@F@?xpGc{~{%)ev40k&XJU5 z-`+QL?`^$Naum&v#{ zT1fz8XW!QL_NTpGlXs&j3-Iq~<{^FLRKAmSd!lDthzSe}ofb~14yi=0g@8OPeh5=G zWBeCUxv*O-bg{8#XlPh0V3KE7dv?0KnW)eyd;bt575taecjuv4C`mP5B|Qa|Ed?I2 zk;HhRjyVi0m$ilSC08KU-1#k@tVbbISSH@bnl4>LC={jRlpWyt^dAN70;jR2mZVUGlM7;6wIrHB0{m1mqRdgGF$<%d- z7IW!^U)NT-BJSz;0K!B!r@1t@_Ni*YRFL3i*U#!W_`!0j{kmj7U=lUd!*ruozO8;c zOv|n!+k=1-AD)Q07qBv)29wLHrC&5Zp!ABBceZfIfdP6rv4n_LnHqbDG;Mq-GH7`M z!th?*&{q!#^kWK_x2#=PoKiFSj_RY@xTn8iON?x|0CNR2O_u|l6V_P_(;rx!C8Sb! z4N_^{v#2(_$@JhOc_?JIb4nQ98WXUyQX2qbmI|%L5rbt$iassk7rJ!;(jwpu81KWwp^}0%^~M7rT6q{ z_3qBr=xCq|BcwnTAm3-uD286g{QR*G+D_fcAo?^%JoT|%G1Do4>}v7mTj8KD;#HHS zl}HvSk1WM$XL`VU-etaUY$N-XI)NF24A%;6<~X-lOXo|tU3|rqA1$^8y0k8CF7sM% z13@05xz`s*(;O>V@>+GKjM_5h|Hy0l4nic#|7dG2x<1wQDfP;P;&)`?qY$!Eww10x-mTv50LrBcPTXpPoez4R>|EGc8W(1TgY4cKA+q(o>KT3os<2%7VO1%X z0>=LK#9LMfABY9TD(8I`P5~>4Cxd;+nBRU)R-7@sG) zyRcSTmz-9@i0F9=8hbOpH9itOt40c#BZ!z)vA>UZA4CYuzV8F|g>ls{TEKQVD0 z!^FhI(Qz4}2{t*;VY&nZ4zW@;Pn_K9g3z7nr{{MR75#WqulV~1)Y4+ViZF?m{H$cH zU0)zY<;aHf$v)9}G8#It{e}t>#jqp>xCITAF7hKjwZpXb)p+A9Iu-C;*a=b&6|MCb z&gNKSFt$9;y;iG~T3T8bx0jmgY_%L8fW(z@YKWrkP=olqQRTZF0cm-8GoC04ZsQ<< zjdqD**OhF6pI@tFti5TLMk99vH!d)ll&&VqyPyEuQ#V={*zn4&{0)g2#TIU0I}Lq3 zPFr$1DGovab)`GF+>wFO9cI$zhH!qB+bNHexUhLGQi+{PyZ}oJMBEn}wSlEicZ-=A z8D)Ox9McZlRM$Xxr7>%DEj4>f5qRSx=ApT74#ciZoKXO^gIKI}av}!DtU^-8P2~%# ztSsh!KBJ~?Tix7TnbsdWWGHW!CY>cvbPt&VmqRJb;(93zJ@Ss zx~P^7BjbG@jXj@*yS*rU4aOKPvY?+h)BW9q3#m@(0hK}OSEp*nrv_xl?eoI|yXZ$I zuV~ORS}EQC82nK?U~_&E90;ogTYCDsxvKFUEY#t3*oa|{CLyLB$ITjm;zF~sB1QpK z%u#pLEPzE#kLT@)Uq6wn!?ArN_8!onvZP}V3p7L}ZIe8DJdiUf5N7p0Z}<#7fy!MT zZI4!7!?`yK^|AJEVZlAQYOjb2j;JQFEd8nT^#c29wTjeW>S z^f>KXLC4X*ldKT5UD`QNz!3QA4ve!o*ZKkkm;fV14tqS;@>^4r;8=goo}M21N0Uc6 zz*!5iNyK6U*W&c6^RnmU<>e`awO`;#a?Y6qQv`?8VphzwlS|M|!1Ry_y-5;ljOkiF zo1U(+OMh4SonB~QTwyb}`4tIIPM+{_iE+-&8ZVcpsE*i}m}>XJX8Jv=*c=^+{>k7_ z5@cLfXnrP&JbmYWWR@!jjmW zPnOg53_5c-EOxT9>?b6I9VJT^R$S0%lXIue8}z2b==>fe&u3|D$34UKD9F3Gz6Br^ zYVW~13mBM?n^-|gd~95tl$@NW)oUR+6;vcFyxBd<#s}|GR;U*}OK-^e_VREYlvvd7 z6xrV`JjeRf_+)(R=TYs7Ce5)pv&Sg_cwp#WXJhJ){q}b zSy@Ju&Ii}E(8RWo*Izmd+VcK#0NR;}J?$!RR0t zKwuL3z`~gFY{}ZrsPaOF)0Q%?%PyXzN+ZvkdA@inXB)gw{wjo@{Ln45mNE~H0=B_K zC{L*y^H|&z-lYdXMF6lpW^N0;2Rq^w&^hg+(ut)r%}fM)PZXN zVyxg(?%VA-uezx+9O(@e!oxUZ-U6fdi_J#;Z%|-{=Hy}FY4S1Ehu98)y z_wMdM#5n|2FDheQExZbv>#c!wmoACgfA(^k5kpHK z19uQWcTP1sB0u(^Yubb35{Y3{m*Sh{Se5IUTBc25ZK@l!&>*Yzo);UZ}Y`A|oKNK9IQzvi2 zJcJK9=YRK#yr{Lis8WAthMYzHrbz>*<6p;4B4enKs3AQ%PiiAZ^zz#kxK`Kn#m#n< z?0T5hY7sWcp|L73|DpJ#fWQ?A51;XfE%(H%{7#N00VdJsqMe7!$}LxCC^%HSz*Pk< zUP)+NLf?KFA){q$e*a5M+|)Ebj(yzo&;!IzCle~9Q6S|%yR`U_{6=Rnzd;=S~CgDv;H{!H8} z#ET3eTPJ8^HtQrmcdmM>BROS0=559Fl_L;)3!8b z0fIQN2nMQ;8MG#FJDC;o%WS-BuFzl|j^zshLPoV>BQ8KP#3 zL8e}-Jf$B)$tWmvQF+;M9h{UI_#4#ZU=%9$Z;X#tV)2Yp5uU_ep*+PqrT%Nh^?Y-g zjBFGdx%y2XpFVZU0P45`5ig1q1qq)Oe*K7VuX~%#41nx?fge11qxk$yHjA)CPjp&% zNa=uoZ3M_4g)9DKWJ9YYUGe*>4@`3-ZKj)7^&r)8Ic%RR|0~x+dB?041x;9O zGSv};Bl5~~^3XRcsSG}JiLWZ*4LR)UadfIid<1Oc1JcNw)uzRVxC?{?1j^L!KVv?5 zQXcAIZ!RSm{%j4FJJnmMJrq+zZQ4}AM{Y*gC7$Wr+StghSB-{%h-@H9Y4UT=q%XIr zuv71$!uWJoy*BaQbNE#wimuM(*$QDqFWdI+uhh0Vl?i#AXg$ounLuGKJmbpA6Do2? zj0DR~!SP*a{W>EHyL9BV)kd=gWwXH+=Siof6Ux|X4^Ty)9(H9t`RV$RRnYzM}|$q zTSS^JG=a!|hQY$aHujWk2xDh1PmZ?@S~xkT8Z)sl`n-D=dd$Erg$>y+z_Fr%*48^H z3MQ-oK<{J++uFcjir%k<*COlJ=)AE$G@7%hrur5uTA4daW6jC??%Q zLMYpSXQ0z<}fu6ejWvddg~RKj)2)ih8{CDA@=pKmUq4 z36I}D-+^wF|0wy0ZJzwM4wGFhqxOHqoH73ya}MJVWJxPtJ={~slixSXM=lF1))BNZ z8QW~jFYMZeZWd!gwr67uM*lCk_54=&@tD1Uaiu1f<=?aJA9sGux;?0Q`fu2R^AQed z%+v7Fh5U-jDg}Q@16x~T#7D4Hp~e!@-+Rg5WbX8&7Q77Wg$<6=swdy*t*W>dhNi2x z)GQ5+%XvI_*#d*f#GN~T*0{0b9N#1ocHRS)6PZTBezEt;yMz`0uV&b{kr_4>OYa%u z{_TS%WuAZ<33@ECwo$60^%00mAwP%L7j%FTEMpvYoJOF+R0bl2dsN}AWecAkj8Kv} z;$TA>^|NZ;I3uwl4Sw54`>J#mls;#9r~;@IOkL7tWo0;OsE9Dy?+Pr{Sbdw01p`Im+*5#Bkn&)<7Lp0NT5arf&_R z&JBD7KE%Y?u#w9E=2nFM2CXo0O1*%)L+*_)92EWmtTMe?MgXf2*0;a@>+?2<{9`i- zyAI2jkepLJ6-RiuusF`2?CjZ~otH0ORN`=31zSczpZ$5e+V;lW`GtkjP*xt347FdV zs+GxQqdW5;saY}qj;a5MXe9&m;g`!7Z{9ZzI7Dr~XETu+FK!9Yvvu?GN`v#jx!;lI zxg)=QCgw=0b??<|gubQ|umG~S>)dNz1EQ$FR$hZFe1BW=lI{|bJ0C||BbK=HXowpC;xJe5Y3e=u+gv!_4eUioIOj4i1zqk zdw-HEaZFemH_wIJP<)&F2ls3K<&Sg3)q(uC6X2`HV@5-ELloo#-9W)Yws;V2rJQ$l z7Zw+NnwxLF{~+%TMHbVZNMFeRnx|bwNk!UNCdHkK3zfQtvNax{2T%!wHg5rJHTBl?{ zcy_hJbG-oBTeq<^{&Xsfg56>$#wJn+4270gSH3uIlgbC(JmT5a-F=a(!+&V1S7o!n z?k`uI*zXU|JTNQ5cT5kv`;(aT9l*{M$LfO_fPVuzyzvXqmFdoEK$lcB9hJI#c_vu} zI_dPvf`L#UEbQ_rv0(2i&@iQhP&kg{euq4$)u#IL#oT{Z!SZ}1UHK=w^_11pEy3B8zC19cBbye`N~)n3 zxA{zC0?eC{ssen|m)jAItxNah5!D2h?zoJ`wJ9f) zJ}~6~CUc&c*5L~{QvRdU;U9N6rdAzy<^~{eZ;+lj1gC$u;D5Wrq2@hh==0@F zcaQg6(j;2o7ln?H9u`-$ERz#r(vP}WsvEA{eofe=G{Cwyb+$V_n%(KU%#q{AAv7cV zd+l|lxyPiOW88lY1SB!Is?x#U2y7AbSRll=d$Nv$A7;8e{ojXcN`VTEg!59rX8~D~ z(<%S0NgPfF-jD;#NpuE?R$#sR@#{=XWb*Q?lKc+evkaFCQI!f1!w#)?ymcC33GH+3 z|0gE?96Tc|!17=0FEp!xo*i_qNiTfo;gT`!$;!x>@x6puwn0`;?t%#$oG+drdGZ37>&(~L2Jb&?)#J6;4!Uz^Iq==?PQxagJOLq4Nu@Pji*~|8_Fqz2@6GmTlM6d$ z2>jDEPHQeHbk)Eolr%J&e%kUmmU-CfM7W!qCCAzcqGhW;=dzQ2zP?w~u=it9QtB1I z95{4PQb{+~FCd_HcgG>NGXwgsxwD6iuxdrmg3&97{<93jy7usVsm@rWYM#M+jSguz zoTcoV$D%QDd`Hp0PUJjm*1&^zqe`G?kaPwJ8=&th2q>nFX%q zC3odfg9|zJ^-DHD5ZZ#v!E7f`7J@rXK0bKBZZGp$HBdJkml}>#AwEFB%{?Um%2F+U zh}@;*tYtH5xjguwKGDZnETF?V5) zCp%z9V|2d_&~Xz>i3!!uXXi-Ioin8#xC=}kcIH~sr%Q1pag6$($Y#33cpZ8Vup#Vb z%rs0@$`3q%uoKQ(^vMR)BXlT$~zFby++BY<`Ekjc*Jfrm?L{4Z- zsN}eQW_XM}yl%{%^G-nvo*Oa|Jj_i1ecq||W zz(q8X2oDr~Da&f}AInQes-n934e*$FO9$qC-pevKTmOGL$V(ZF{#P92WmKF*b9M+) z53E@sTZrMMqT)`zMzV6MA7qK7os&=2q85uEf4hy8;+j6IJhk_Ebdg>lXN{MS^nqD3 z1UXE}%M3c|5wg*LSk5Q5S*ko~*w#$^uQ3nX{M&Ml%t+Rckj^HlSw#fFR8VyQs~~$< zK85T{x50mFJg=Ybz_iV`Bg_M*zw1S|hdvB!ln{LtywSYrZM)EV7a3xLsQv-C8F zsCDp2+yy)VbsMWK9CSMmcO8LnXnN6H*P+)HE4OCGDOH|8z5fnCqr$kxq z(ZGWx?0iD+&ZR#4BIs;xj1*@0_U#+H%eUK;xGt@eIlEL^My2ZwfTi(LL zh&?QOKUMK0TXIrzy`9NGz*RV#BY>-5ZWHmhA+KeZ=0P|-4ZPpVd^2Xm(7&=P~p;sRT#n_?#V(& zBYfcqhdB;QhF|w_k+rpLDi=(l25Ru3;-hO3%GJQA>zlNooH~md#`pEf8qHm3xj8OQ z#uOVHi;(G)9Dz;~%QU&6tf&~|M*Yh#4|fJvF+^Ve1*|q$dhVrHl4KR2!xP#0{(`HyiM_Zch{5*Kbw}87N(HYc(xrZ z*uau9mzX3IDBWow)B+c@UWbHpx!f<{j@dwo>po1dUVvsIw; zq$|Xplpkew`Kh|hZxJrReApxcxS<0d$;?W679R;m#l^Q*XlWI-8?+F&_Z@)U=z}j_EK&i8hp;|74hcf zqK!BJTRf)$8|vIO5^*qO@TzLA4;}NlY2bZbLdf!}k|v=_cm(3>i-So@2*IY?V+$0M zAagzMYyvnO@Te03aC(DE&7HM=-@QQfH)&x%D0K{AE3}>W$yH9dxvv>9%E<)X6y3j{ z7)gX?EWY$#T#DQY#Jgk0TSu|E%0Z9Ej0lU?5WakO#E?Zj?_%ltMiT(rwZXl684@Sc z?F(5C^+U;|5+TvOryZG_r5|KRad8OsYW&@XW9#=Xo;CQrO;m;L7SAGpSK*xnuejIU z<%G8GjakrqWr0CxArD%8>o%>YM;dqryb-$-^YHF+yl^nlXbnT8 zk8YiCh@yG-mqES7GQ#@q+9=@fT2*^dvJl`Y2VzgM>E$a|WFPw$>3hNP*JksXeMvqq z@7SZZI9XDO?wvHzp~<_GJg!X3f*DD`^$ORh=qpD!UOZfqN`E32Qr1eZAxiBQ>M&lq z26OdBNK@y%)N2T#^Agxh(72_;;k{XufCBt>Zn^*s~Eu@hnI?bptj5nOu&$z#+NAakg zon4K-@D}giCu?)F=og1v%MDhffTyCUs4V4g%>?7!>FiNeqw&_JVBH7WAJJ$V<~}VZ zRoL}?;KmP4qh?2p;3-ub3&>Xn`v=|~xGl9{i8I?Do#wb9&2HVxi7=628q|G2G(2`` zrfAhA%?$x-{DlyTew{>!@Bp+W!atylGcZbvVOE0!U5bJZSbXa(!DGdPR~df^x@jOV z;g<3u<*R0kvM43WFPJQ}Q9$5)amcom$%TL$7(ohtH_J~pG=P+xWen%A_wev;7gXJ{ zp7PrsA{XXyd5Zu|n6a(@!(S`+H=P>t1wHIf*8c*tA*nnoD;fr^^G<7(+&XYnKnmTE zC9l=x>q@dLl5At=qyG+90uFw>%FD>cHyqq8Eo_VP19lG}kOn;!Um);(dv$)mOtbB| z-`NeYAUz&SKod6DN8?!ucffl(ni=V!Ne}#DPv!qwG8eZ${7W!Dn@iUOq5z`!y7G%B zqaLQ*6oXBGP&}WDp7jq8@0+`2ayP)=pAP20?8eA_(a|j;#vd@jUqe1H*EunOdS{942NJ`bgYZt!vj}M-wOL&6->^kjxubh*)_-2I zo5qsOdWHi2Ic56?F)8r(H-$$?BcI`^B+!LlNFssB-ivN2RsB~ z>vkMmBHRGU)w|jIJ}=Y?h2@rg9$o8WKu&IrsQg9ZwptlAU#Ar#Ee?MX?n0Yc&bp6R zB!Z=AFJOc0CSz%Ltwbn@=pVreO4%b1ye9p{bb)L>8X9q$x(w#a_PoRhpz$ zQk4@ADG(oD+qzh3awsK}gPjpc&>)BR$)jM|^n0=Gh;eD3xPuuS$zJ|k_7Aa|y=fka z*|7a9W-|$Wj(el)x$|a#(_+_kBh#Dlp(U(KAixjeLw9OHRJ{tr0io3&FK3mrAxu(R z>NJhhbA~_=x2kr1^CuOdm^d|B#}%=d$kI~BF^!z z@bJK0L1N_7TbhzY*RkC#+Al&WG#{O|R>5Pn{9yidtb#`7q(9gfKU4+1|I!Qy&!(OU=I2ia#12Z-wh*j;nhK>jW}WNRO7N zmt{Sxp0n+|RJ?$KK(zw1%hxF5@ zF&kf#r%lCg-+r+@0$>$F@n#bE1Zy{43p-M}PIl{jzgnBwB-k}3ma2TL$Im}Nb8UU| z(jI1~c?rD6NNphGs4htdu=s+5du%H{2iIR@7aaq>cW|KxfX35q8fNqQ(Z)9i`mkV5 z_f(Cb-?IR4F;MgOt1BjatN-pXJ-VJA9k*W}u7s9M%MNKY5@KgfxFY<6d*+-aJgK;q z1peCws*Fl|S^ICgPlg_WCzl#|kNliPoEB^1>t)N2IZ;tj;agc|Ja|;BZYeXF?rtn; z-CSdxe#F3VTpQTgFAX zzW<_NE>O@VVjy9o456enSae8Ai{#MK4F;f~fOLnH!~nuDbO;L4%uvD*QbP$SDSfU7 z*81(=|D3mHzuJ3VES4X1;+gxouj{_Pg_G-MA_W5Sgfm?||e2ri1RcvnECuu10e@#0;K`cY2s@fIXF# zGJg{B$BxZ`Q($$Uh6X1{dz5|bu7K8xbf5uJVnB*$(Y$7&V_k?Ib1l@)fASuN*~ejJ zRyGA+x;HUd{l^*fiYo+_*udhl{P*9yfl?=F@?D+n29JeEzMV8UnK7HD|q%gI!+n+pTis0gz+ z1`W}xqtbP;|7DY{)<4BRBt2_OCZ+{VwJQV6o@kn;_6GLex#_B0f=(8pS0t3ccK>`j zEjMV6jM<}#%+;FXN|&ytcGL5~EZR8JuG0Ps4l_ilBOr6{LsOHq2G;ZqMWDdFgAtod z&K<9AA(jR|$se6MPiurj|5fOr6%tJ&!SO<+zfBHh25THl_v$EL{0khr{b#%wn?zm@ zQ5i-x-jW&x_AW9FN2si@8;0ftW99h8KQs#d;M7tmH<|hf4$BOT#alDD9=p%l3IL9R z6@?)Q3pB`*f#Xy!v8u5{nnVy@_5FhoC;m@_IJ)=jsZ&pTPf?NCEd9rkAOo80Xq)=h zK^@Rw{$1|auNnOz{2I-5dCt%E`Y54K_%nu@BOjJJ?7y5DG9`X$L*lu(d3YM*_?J>q z^a9Reh$FVk(pi5$KR=B~80S}#{)LA*fJVV7uHvd0Lq=wG;$NgfjCndPgT+=X75!<)CQ|cwR%tz#{5dJbWsY(YZEre#+4?32`3nKbFQgZth<&IyMc)yf>Ae~6<=^#Uo_%(9na6S`sBk&H!igLyFpN>9d7)_ zzh_-wv0wV#8`n^Ti~yn3rh`j{zWJUxw)%5gNgrQdDG!fI@ZFM@m5oEL_nZ3&0v?7UrToa%rvVq)4?t(;lD$_(ng5j3k;8rh<(7c=VorMM_S&VBk;eX z*&hj=s(|+*Xym|jh9FKhUg`En5XG>K7U8hss++mOC zS_Wn+xPXYuLqZ$@q$iW`RW%8^A_vH_N=r4eSen1|^*tC6t~f*nwBt|})$pYuvKo1? z7F1DJMKb0}O5G^QZot1SiwNC+Dfn+q^1nL{`~h)5{P#CCpa1VK{(rb6+8|amXK2bg z%NGPb(A^;1E#g@LRs2oLLqcGZ2z} zyac1V{l8+d?;-8_I&7(X5i(!TFAdrm?^VjF(!K8rAgO~fVaNL)BS5~G!h--xpw2md_`>0I+zfJ%C z#L*dqUO^P*yx;%;*#zHuFj_hJMx}!#kid@m{F=565=dJQL9D5|05g+_yCSl+@tBK* zO^Ph_&8q#-&d$NAAXF_#stm|WOzi6J0eP{i-zF2k?PFxl3u!boqM}}JKHZH0Q7r&! z>G!GVO^fpwO@JlM`9v)B>h(Zccza}1)cbA%Q=hT^BsEhlF3U^2Q0b%~e-)-#sHb4c z^z?2da2b`m2{FF6fVl`va6pD*2!QI|HmGj`dvMu{Kr{P$ItRA0b>i@jMQ!wZ5a5I= zcxqNuR_4Kk!nq>HgBvW3sy=SL*y7!^LRS6`9gOnj0_4DPTSOgWEl%T73Q#xGC8wk8N*lL8@Y><7CcUuLUhnRxRbTkPzP3 z4wEmh-@^igd+^=9ZNx2Xd>=6R3asYLl;3e$@7yh)>o3bmPk)Gnhr%6zxbsp-*~h7M zgVoo!k9Y$sf#apThi2a9=iBhRF29Zw^^yllq+HtD|KT72*JqGwud><%5#h{d7$<7& z!_l2iX#}?yr`6UWc=!241(Z=3?u^@7JZ*Z@bzWY1&}CiY;OK3+l#(n7^dqGFJ0Z@+ z`_Zy7OI>y{|JVjNQdx6?cO3%g`vksI>t9~_jgGe4L&oOMKr;>ee8$O<5q+OC+fW3g zq`}~0c{)@{OC1ILJ{~*#_pnI4=-~+v9RW4=I#OW&YjA>vD zL2_-YKYmn{PZYT3wl;tJbAz&iuw{SzO|8eB9f}+QldMI@OjLmCYFPW~4bt4BPBvDg zkiR1=N$=&j;PmUtP;C83o-C-~5RBA+ECJv}?}Y4?vKm!#^5>l3 zhz+YVD)T-}gPfarVbK(J&4hpZ_R+E7#Ot@*%>ic%Cams27C>e8Sqi`+guKsvW|G*uRajUDA_oq`Oic{+WXRLRXKOkrPukMb zvV8M&FBsg%c;>9y_;CM=^ZfBvLouLa_Iha>ya}x?5jg=0dzFV z1Iq<`|HP#|MmL2$U?>S zmt1Q@H(QR|B`ye0-k!us$83B^#)o`82G#)rPVyR5ERaC5w*n^W=(%fDNB?{pE3hQ0 zQBYEcY$Sbtd*m4SNu25$2xR!Q*x0}%V{2P*{+1Ht$`T4q6kNuccTKEIVM;hb$TVPn zl@VsQ{cs$+4j!Hj!9ly^ucyspZ#h|L$1l*GAZOM9)FEHik0x*mZtx zET+!241|QZ*qMlk$!xnBCG5)MKqk@aTvjpY9a6*u(@9h6usgsLh(0^{v#$`w;Vg6g zK6}+u8>zjyre4lF{N^WbJYw|t`3%|pwW+ZE(?#lfJO{-E(9fLjm!u|$u))_G(i+Rx z42CD;PSsvY?(Xh~$h-r(i*@Gi?j}@jNGd6XeEB*T23T?wzflaY<@Jo5lUIIsh~H#k z3HkeqgiN7v0`=_r=26LoArC_!AT6$&BuYMh90j36(U$Z=QBN>VJuSQ7@H&-01a5Jy z1Gf-pT5zFEeTI;!oRL#qec>u+fgcv#iK|`N_#VUkJGeVrtqIoLRY$kCnMWvtUhe_a zCECyuXydVS{x}L$sdWEKqtuLM2ovJqno3C~z|s3>FZ#r;=+=k}%^kRI67yA?jO1iL zY=49Eua;Hipi0NptMtL&zt53uF{$_(IEIQ7L|R;Y8exBG>a|T7#B-zl!NUG=)yAToa-)FR@?&MWgUD)$ z1Q8rrS26=KV=xBeaL2z)!eE3s;J7)r*i^mC_KAoQM{-bV9=IBY6$vfg8WLgqd7JG?RMw?FRy$1Po)yHaT>D<;scj3ZoPA@_jMJOnb)y;`Bfr1OU zJ+@_)a3OyUcXjYujsvTkbFI6xvzcCYuf2+-A*ZsTWdR6kqB%m!eT$t-JWsxd2+F1N zT#goLFBvu86u5S?yz%!hIHDvUtHv~Vxnh%BhWt*G-{%v-X0a*UZyF`N$9F@ zu`?Rna3D=WWAufd!aU{qHylRGs5>hh3i$2LV|q-nIDWKVuC=Ge^z?LrDgJIBLp5Ti znj@Ybc&cwuv)%Q0+x+h4LbXXx>6nC*q^@UzgIl(&m#6T?>e=e8Gz}7DH4@4kUN09U zTrjDvt8HC>e?=k{Ts5?HbYOewCwQmlP7U`IcoDXNxH;fpH`14Hh;Ar%Z$ z;0B)>bQ*dO9D^8fYAR+h=3xa2Ok^dDl2d|2)J9$_&RyEA)!V%cm?H0P&kFaqjyKPF zE;`Szi$?AI?tV7aajCBY9SR=9-%xou;qNZ+MiD#7W5#-T*EH6|i#K<7{$xfiNgc(&1X(`6=;`5G5j=T6*|D;;AITtRp-QMf5v z>3jPAzJNkJ>%(tbSFWc6KO<3Z%`b?cWnI}C#}bwLcnpkX-`Y=g;9p(A;~#+ym35SKgq2Qt<41f7Ll1tIJ8rro`Q?C!d4$FS zpegC2_*5yp_K^->o%}Qv)!OyvXJ<4cEx8 z-JQ)cq2Gmx#K_*AU%M`IJTz@ve;Q6SLONE9hk}euXpqR37-D8{AY5;Iqt|#{bZ1(D zw1r09$16^mi0+ociFjCBZFPzmj#7`Ysc$A~F*^ScpB}0#r%1(F2fZ&Ic5POvM7UXb zx|Kg?r{Z`yARigYSd4+hWeQ(=t0?R0?T0w4zRSDL>kE7A#2$``?X{I&jCa;c2$<4< z1W0C{WLn9r0?G?yWN~=0deT#3%-$`QdmOn~4~b8=*EzhxNv&Q{U5>wgTuS#R5v{8L zi&*17#I1!hb!ajx+{*J>(&BoaOYj=@++?LuW7Wkn0^0vSL-z9iOVL2FAdD_7eO)qu(s|B?2X5G`S_gHCq;F6o3|!ccKh=- zXPP^GSh`sa_cM!6#fLcX$U4Njam5jngw@5E!(`GNNS zMtR37x_HpByvvWOn(Aawy6yoo>1_5T+d|oiM7PlNea1C=qVItpSs%zH`fTdc0gNJT zb$otF9ZA%DiT>)(7I)Jex+Ibi2ocTh-t#XQc`KK#hLOExfYV5Spg|L4C$WzsOGs$N6YoEN{zTns>}itiO9(}GW~iGU&9H2+ zAn*PB>Y%)})AwH^Jk%zqXihYuc6W+PD~~d|D^^teC5J3>=!Ry`(;{EpK{}I)N{<#7 zd8^#IiK8@ahk4PN==3xV7eN26bKh}X{&*Vb@cF3%ckdBZJau9f?Gl`C;635;%%#c2 z@}_V1<$0~hOk4Xf3%f0cwZ#htz>eSL%SJ|M`0?{oCY)O&A3pS@$G$*W+ND32S5o>= zDnD7m?|vt(RsgbN?|5yCXArTfn<|mMN*ooxUbuKJR4lP8|K1zgKoh+2Q0$<#5nbsW zFJc7h(5FJ5zXQ&&g&o85qBYMeGicsaJ`c|eC3-Fr{k0LK+RR}2Q+3~R$bv+`hZ0Jk zK@_l#{(RgqDQQ{mNkPXiG0LjTRiyiF4&R|FYj~{m-3(!0c zYG-uz#Pg$!VQLsH)zTcc$C-ilD4UO4WykGwt2om&3XP2uVmBAO#GV=yHzy3bU1bqy z!qRt!;xycTHHb#cEUv6@O$ubR247NDPdjw@NW5M{Z`^DJPxa<@sFFjE()Pvr=!y!V z^;x|gR>)81vm8che5UmS>uojvLuB-{S{Zjgr;$$Kn_ux*h0gB<_>wgNjX(F<9MMk- zx-{T8NWu^0$360JC zRZ_*TmS{6kUaB{6ylD}-LrzY9ik_Y|@~*yqa>ep!0ND24028cm@V8BU7|uuLovnx8 zIcLZ6_)l($)+H+Oz43ce4%`tj#>Z~sEZ#&wcs*tB>=qkH<4NN`H=1C>?^W>)bE>D5 z!TLm-5pnU`i*VO}1LroB%8==7;U|LzsgCue@jny|mi>3%ftw0taoR{|KP?kS=>%!$ z6BtBSyI5#GQ1Pssn!1rO3xcO;2WtB797V}X16#9+yJ3*l-0V$$P`3Ld#Gz^rbEn=E zIJpmve1~&nZwaV`W2E0>w2GTd5e(bX7Az@n9*Hl)-!czRCuM_Cff zS`RT9O$*%-c3lm_cB#0mFL-f{C~ClcA7+y1qN%&SRxNw@eJcVc)->yUCK}c~3_8q<$aaD+vp+v89i}#kt_=x>6y;mkVXiRORUuYF4e2 zWR}h?m)}>#-IvhtYF1bIv$?0z@1+D~OYa>(vblQweXqcie>$QNAwAg^-|8SR89*I@ z%!(ns<#A|h6Lz}OsBU9r@z*_3+}&{M(Gk3gg1h+Lg&+m zJ0dMw?7367)Gp=jULj<&>j4H*m#V5nLc-!$A?o8ctw7M$_^zxLPb|Am**ArpX7Gbi zMZH~*1&B$;FOcDyAc{yCuo~Tv)Q%6k$tNi{ZCBwqr@6EQ(!hy~-L+8Z$jY^<4 zsyMP(X!EDt;%7gmZ@lJixK&e7JlnQcu1TAkeym%h3$FMxDzo^zfeB)b@Q)s?Zg!;0 zU0BC6I7t>;4Wb6xzCRng%EP7_!J%cG7uGzT(x}g9~!E5Uv7p%wKy@7d!v{ zz3nWfSPI%ZpShWeTbg|ZLzK~u3xSbHqt{$nQ88YB!Q>kx;Cuma&ur!utyrH*k7Mh@ zquJ0+QE$h7Aon}M1@>v-zg|<5tmA!opddyZ++2$`3vCR|7AbiWw8E!Q7Y*|mDakt* zi^36`;|SJ}IzQzv#0Ck<_S0$_!i5G6j*Ttfg54I}#NdRM7EeoH{o|Q%mHC>~#}(lu z*17mwH`UobFY#KO=%mIhqLCy(Z zyO&}DckIE}`S;>7XZM|M*#Ch7nC_omCQ&~#XZq(uvaAvJ7km#}|5LfT#F-Au8G3%O zMNJ=_(tIBqdh>yT{NH3X;dLH_?NQ@+GZtf_nntB-+S_xtrCnF%$86$p=e8GSHxnOh z{W}ZDlQvLScNu@5sJ2mDnRHPPgxSLA@A=OMTxVGkqJ-Sx)_AAED?G_w=As+Fgzb{V z*S;}wy8n?}Ukqp;@5&6d9rid8QFTo}SJB zx#ePam7l+HfP*8?d~#tiJO}LJH{uPoh8wlNR7xq6lc_2xv97!D!=U)_zyODKGR2P# zMKBULyk6Q91;9cX&);Nc{V3^v2%H9^YX>Qm9Mu0VQwApUU-b=*WNkiHlXtld@yc>j zVi9WR$;oUo(E)`qy(a$LmOZi%Ol+q4Dk9_PRqn#v-h-#Pxifz*q_ypS=)S3J6=h6? z?I!8Q+4YoBRkk)Nr%MxYb6G|5R`P+FRYiC;i?VkEaTb0P5d3G^9}BX}=X+z_8XjIs%a;YB%wqZp`BS;&3!s@P5)!^)Fbrnv zt0LwTK{&xed{cioDl)dCL4&A_)a{ZU?$gLmbp}g(Cfh>?D>}?WI2u-TPQbX$aD6c? z{Xy%;M+W0h(SNCg+C1d39;(H%2t)AGdNIU9vlnaN>_71{@maks}H)2J5g(luGN=2?kEpTbe$EB6Fwd&f-K6E%EE&nXM4)I+_$ z>3LzOyAi{Ue(G~3f$;IsJ;d6v(#@$kx|Rz>>tN-Z``z(8P5G$SpoX-L@35JEz(|0$Wxb(1USiUm|Xnk5#-(pt~uuaw3udroih zxw4oyhCGRc~1ll<+y86X5yMr>`l z13w}RYtb!T9~k?DM3lN?BL>e#_CxdTo(9b3aHq{>L6i&~ubE1+PqbWi1jev^-kGcS z?YlN*13|C3ZZCcvIMgXG&Y*U~K!4Muz~pgvCbaEdAw(KZ52R%Sjg`ouASY~@UiG>XsCOqCPHf*F7#Lt-g#)Nn+ra|| zentWhR7wU_@+>_y^*%D;VrPFRH+u_kk5FHEsN>vA%~J#XMm!%4HXT!AYoN$spd255DPR2 zzHYW~AEC2X`dwM+PPUeyjeTkwMK3CXbV|-a!N$gp%TFGZPFVA^*O9Ac!?quwF(Z}o zI!3+Y8ZW=&8b6AKSJE#s*h z7@gPBItbQew18-fd**Um{bb3tk~>uM6;f7^1##4Yw(SOn6W^I;Us`t_248G@7Z|gz z&t<<9`C8Y34!q~#kxR9Q7KjeFWcU7^&0*6$!sgx|KC16M$=?5yt^5}poRsh%EkEp3Tzis~1FHIc?Lj(< zTsaS7*`9FWM-vjT(wm>?8G+swRVGXNVE?%YV_kmzdX5VWME5RhuF&3oI%8!AbqK*mE0S?lFvJsKrW${(Z z&Z;@+mm!8uPov5`bNuXSNq~~#*sCF)y|0u@&8mD`VsGb*q}+$(81h>slrNa~=JJln zmapm~iL&T^Y-Xv@?cc#jU&yLc_E-~ZaSa^FR~?W7@FKp69^_GH*rTj5V;nr;At9_X zk*p!$4u=MPBjSPIG{Kjn$1E4i6N-%H>3GbpqSRPJ-(Bd5o;i2+Y=h2a47QK4Q0~Za zdPA01$kq6vq`z-p9gd8c!D3Sqq_Tz(jI(OPZ$D8l@qrY{)8kZ!*%qNkBy2jrZ2lbIZ zzB-)+(U--8G9UnE6d=4#Z<^qF-B>gq8%ayq=bX69&&(|G;>F9k$UNAsSp~Q2&&xBR zkeBMZw!bZe6QrYd4jxf+^=KM7Z8wyqYMz<9GTR%o1hQUfxgzskUF692@(5K{Q3d-X zkPZRWFVIV;<-hqzWb20qSEM`y8_C8yrc}P`Yocui9QrQA8y0Lon;L-AL7&>i z@%=sf<~{=bF#?86Zy+8HZ2X#{UmR#`X$kw-df~y9ckDXlIyT$FA32mzq{h0OQBRr~a0*IHud5nP3N{yBvN$0!wouZ+C z$0UmP?5o;#gPwyDka#Hj)wc0$^I>-#gi zU6>g{hpxRz%_tk}H0&Y6t3@8bC2;l~jFGdGIRH zEV|oYbRsl&VzLdb=sB%4d3LYYd$3=-b7^3smyz@FlZa}HEQuE!|MF&xx)(}wQyG}D zyAU1c;&b!J+alN=rCUA*8<8}D4ZJtz@Y99=Q zwcaR+s=;5(5VABsLsQsFX*`hTlvveWhN-qLR#jxXtorJnESc*FhxAOMV($WGEwB+~&k-Gx+Q$K73Vg3<*_*hkBKGYXb zQE7a7>hr~Fm>u}~5j~eKaT?Sg2OuI|gBMCpODtbIJ#Al(2A6p(gW>3xH=`zlI4)Q2 z$r;t`t1K+iO2D3k9@#$VZ5XMCcj(_)03ew$SHzn)rczF{j^_j29J4Ihh5%lH41(9e zE*YE9$-deg8VU}S@={XoA^RIWm{o+e>{Y7|Ja2yFBD>Gpuvhy)4})mgy~V{P!|;_m zPJpeyvGV%etk)me+4~j1M$D{w%;vo1Ad?3*vPW;O&Y8QHyT-y49cyJ?9IcRXuOaXh znri0$>ePr$SeE?dt@_;^6Hiajmc*^*h`O!jfP%*>6^pTIgH6-Q87%^Hb+xG`K?$VNthZH+XW6u`N=dyT4G)$%@wGpQ%+)~+NRW}S z7gf!%Yga0TLuDLa)o_ZcZbn2-z1I0v7R{f}`R1H=|sfoQ6F)Onn@kj5WW4MX_-ltayghVjpyS8= zVhuw!yVcmj#cp-I7?CNUq^L>S-N!u+n$FCCP&}-?%UqFqYg>h7EFiBDAE$1(?37M^ zZRq{|@sZB1Pxa1M))f01?SqsIuX??wODA_P>i1l%c&D4bcJC#V3Avo3Bd#S@uy-p* z|3&N8`qKDPy9ift#&Q)?(R}expzpnEuf?0_p^DP3B8DD2kL9UHG&Pkgq*&5UyjxtL zwHsCVKJa=}e3^f+2#g-v*M@h!-zMG?&yuMN$VhM{yt1CO%6{KBB#nwQ!+-GE`mNx_ z+nz}1m2`EDp-|XZS+JhZC~U}oR(Ay5nf}hh=6+(su4Zy8SOK?IudL*(Y2C|598INO zd#x_%-Fd}kq<3!v1rWbNi$GcK-0xhyYI$Af-)WTM@2diJ-ABN@b=b&Dc0&N)+q$+i z+5C>LEtqIkJ!p}g6BTuCohZW*(_3XJO!aVu2e!P6E~6%*+4*o_iu6}&?=s#wZ?bG{ zx_(e&CT8bd#ef&{%Cl2@=d6;jzf5y!nj_h`Mr56xOSZPoR&#f=_VZr0nv{n?=IU7K zi03blM6u)39AJ)~s7oK3?eN zE=>N6J2uCHL_(^!R`O_Zr6%o+NToKx05{NOVCgpLK+~uFHePrNwdIOl8DY z-q=I{purt|Vcb~HlZ~x~$>w;cp^1E93>ksg>CZrw0UMMliy<}yfty=@Y$SreI>jB) zOFw^&T!DUPSUSwXjjkq4^n>!t%N}ta8>>YNEwf@f%uHSuo;$yTm_n+yH=?gdt^Mp{ zgNc4PgWyxluW>3DQs3mb()z+|Uaa&7sZeGafcWThwMuQ%C`_>a5=_c#^Mi6^1s-m1 zE4F*I(kYp5-H>!$nQ{0`#Gm~2^{n2lkrsf(jYhvnsnzuMQx2V)AX-=7rsde!bVkBf zCDR~#7JVQFrr!corpvZGwVG{!vX7$gq^zxfl3)t`Yj!Q;(rb~(M30S3iif23SZ2QV zI1PQb4LSmGb0W`^4R{z_$yyb(ZCeeL96b45!wW(4C3RI5z8-WIW_M`l`s)wfE=%y$ z(R5gzh}4T(3smcpjpJ^tN~n_G-OlrhSy?EXwOSe?JTY4s5?-7yUx;bw-dZA2C&OVm z(%+ZsZ0FFP=b{bzBy0&-pUARj^~XV{B>bUTqCMeyK8%oRR0_Lj8E#dtlcIZSHvZZ) z(nKePQ}(ase4#7Z>CW@AT$o@uO>d$3L3m?ILGIcs-$OWY_Y0L?n%$>Ba0GSd)I}TDH6(DmGs-Ccn8zSJAS8XGrfKO``1yOAGBbEAmmx-P+)*E-Iev*aysc z{{_tLs>9U0r+ABIB#-_qcYqUCD^u+&CdNYCCSg)ss}Zeelrjq*)XmnO4Cc5DRXWWT zyPKvr)?m}gy(_~;bspj1+Lc$Yw_4L@z2JTeWRpm*oiU@r7BAi1g~Qg9*&Nl}Yy-<{ zzdG)nAO-{s!xP}R7ED@1&)W_(Kc14cRFabRqPKL|M6`05SKT#$yI-G=jg>7*{r z+dflb$?*34+G1B|HQ(npQ`9#??@n5mAokNr-0w#xehAGjSU;2cG?hV{NYyKXiMkZE z*L|YSx{-R{TxXo@=S7P_=!>Y|ELPxy0PQIrRo>uy{AX7x(=rF3KYi#XGykQPEn|Oj z8=RZ3pS&rvYkADX!v0s4Tr5uQ+oxW-`~{tnRSQ~ii692M6773`^SHL0%c$&hpgvD! zdaCKLpnybRZaI4Fx}Wz$ty;(`ihjN|RJr+`qgTz+h*%V!76goKNkIA0n(xsU@?`V@ zv6r6|#CJ%eJnad3Cg7#9mJxob-#|C}X$8kE^}sp)ZhqaS;;Z=KBDLpub*Li$uk^b&s}{de-5CxJKSkC4*JD1({kx6^o z+SFgYJ77SVIcI{=_N8VpW~t#0?g|xY*Axa_6y0bTChHUaWWGdD0wkuoF1c&Zc$11W zhSY-ZyPY8eo~53yRRr2;dMGs$si9=v&3@h_f!nrUB)JkBY7ZZimB~QdnZ?mmvQ6q) zU57ERZir3>*z$W}bBlwPK6}QWRy!C&SXy!n>;CXSCS$gwB<>g!&=BH=PN;gi9i^d; zS;BU4cM@`h7%X~&N1|xs!Z1J22|4Gx|M|RWyb}dFtePPb>xR1<7u7iyH<6;J6Trg> z2@f}-3Y?JA1rz6s7R64N5V`Y-A+J2btlP>A8{eS2oli3=R^rCUlNZ~#c;TbclLq*# zFyL>gogbYxP>`197G=WX-2T`|`xse__*rGMQfWiFZ%4L;*jUcxOd+abrI65T4X&-@ z8X4GS?o9*RbPO$t-{6=xw>JK>j8=_dc7>U8qidEs@eZg#ijzMNgXwTwu3h@CmeM(` zJU{Us^SvV#f)*fGO#i~6o>H;pDNo^>n8)XZ3}4Ge+un>C z_sF!709=Ar=~EwyafO@WBri01CZoWfF&Oq`gqC6Tz-=IhNOoo2EO``jQ$g=2VF$;sop;ag@Lo#snBdhhnFTg1W4DO%es?WmLVBbpQBWOW-v9nE0o zG^z_y@3mTYtbQ!oP~>g$?s2KTQ3uIe9X?tT9ZB{;D@lLQ1=LLiuCw*EKF7vK{FrVx zfA9B&Q!f9YFAht1KAWw&xvHNoaF_VrVVY3%aMtYG2ewbVT9-b1tchL(G8$?9oQS)# zk5MF>mRTDZurt!U3QHqb|Ga+2q&r#sfp@5jqFJ`bV>dfpXOir@#FvZq^9)3H0ff7u zUFV{TU6edXM^y={+tEaNa_gqdWGxIFELn6Dyyn*_lcm;Y;sR*FUJzp6sv&n^nA z!l`JwZafgpb4Z@T3`@T!^Gt8$|xW`AT(gRF!f{dh&2)=n25m}Q`jQma@5rM;Y? zVNQtsw)N%r*lM#w)me;1$GXH~{HwnNE>-xRQb%ds`D7%6?UcS~nL>Nvg1P)eUhkV9 ze#aSDG}IpFyRBK#TsM7k%RR~f8628wdfhac`)vQCI-RX-CWKA$J1vuSmUkRJ!fb=y zwCIsTamMp-u8qeIT5Y<1nx$#U`m(ZbDRyvHgHJ1uXi54}GtfuK2#Hn)R9VHVVv*CF zL*uG|MzJHN(nm`J@sLIWVitdLDa6h&q>+aMHkX=~t`=q8@KEpUhBkd+&rz}@0m?H~ zsOX>*;aolZ`=4117JrA>2ouMyPJ-vmO$}_vvo=}=6_AP-u9uobpA^@!ohB>wy;WGf z-J{PCuQgWblsEtRIYK#kzWfj6Wad_81@)KewRu4#0zd;uC$sjRAtRG0L3`@hc)>l; z{!9Dtu>N^*Q=c zF0F^1Fo2iNtJ+YSQG#h~%jU(~w;v6;Y+CvSKYS^(%`oEtj&#)RcmV!e)@3-VE;ckD zN|es-#!|(KoYnmM5Sf^qsiLy|#fN)agu19^oX%1EAI|k}V_URuxWXF@x1Sl1@^3rS zn5*-Qbi)(#@P;0_?NUoLAZ~fzAcCSL?qYJXrR;;&Di1e|w}JPH-G&i{tn^&}2iZw! z{PV?9JJPp;G?_FA0V4@8i1jv1kIkaMNPdE{O>;Vx<@UQLk=MZB+G}YTCyRQ{NvI6c!lm?s!}$BTPCs zgWHjbWMXI8*BXG)VWm3^`OM=fE2XNiggSJwEuD-7kpg49c6b`qt zX#hPJ4BRnz=p**~>D1izkZZh<aLJh8wL})v-Iuii#J()F9V3*7b?>eZN2@8rS>|7|W8peGwr%{{~FeWTG5I z51`O&z~p;EZ~T$;4Q+BV#S0HM4Plez6LA4?|+3uBlI?f`a9wxRR21Rjc0ajSG6A-Vcc}ZLyp2E8A1rMVXP2 z#V{Lb1iAS&0oTHnc)K|J>Hb!r^h4jXY0edth*KZLqF++P8V_)HPFtFqcS9oiH;|T5 z038}eZ_nu9I2%Tpi*ilg@lFWylroq{z$7v3D>SFZMA_+ zzL|?{XW3(HY)pA>#r~F5(D9y4jd-)vGDxHRhgVaSF+G;o!;-|G@0Hk+D5{Q39SP$X za;n!qlNMnbMiY?=)B{u0xi@crj^rmW4lE7+v^MG>A5H7 zB%UQ5#S`~v!>woY@!4t<55^T9yG-z$)Q|L)T7dv_U?NjcQDGk4NwF8Xtdl2F2O-mO zcuI91mnIdrJ1N}xV4fDX&X1>*Z0dY@It<3f>%{q=2z7<%V|FLy=yAC??yn#++)Xz( zdV55iWu(T_Z)I8RO?qn#q{&S?X*$d-XHph_a_>{JdqMyzA`Hj@g}%R!NUEkgd%f-Q zjdrs6asvj=SvK*$+|pV>NRc#ea|nzo3l5LBY(vGGT)#Cnu-(kcH=KM#a7b5_ek=K? z!qoF?rTl%=&2xQ)L@Zxt!_0)kH1(Oi^H{)V@N0yQ*x`dhqGz~nWJt)dZs-=%VPJWFENlVwnnqF#+acRPX9SyEY{T%bPYcWf&UsF>@n$u?Ecna}nKzWwn zP{Kra3!`1C4f1qmm>KNRU`v$t!S3GMRFd{Xk*aDRMJ`k z#?{6df@#_9Il+5(?*b=bgvZKU!1CAx1tKYcpxJ!A)(d$Z$v80&IMwlG)!(W zHIu0IjcgA3T!{LOTAme68Wqqfk5)8pa~h7hb(4)v4%lY~q*E$%LszdeaxV2xY4aci zqUi}$>!lv#s*5@7V^_VGEN}OG@9tLV00a2O)hJ6_+^?MD^xP$Pn{Q(*@cz-cI%Uy6 zQY|_@xvwkrm0nS+g8R@a(Lut&S{K>}<1EL5f`TvIWlTHd0 zpAmP|vomequ~xKCUnD?zl5_yP=>a7rrC~7bmT7ij0WE+3^*K^>v44P!!JEK-R#>T( zKUSaOEW;7>z2*CFV_o{RrE&NgnqU8&(lT~I(CS5L5XDjIzmN-}O|eh8niT`Muk%Pw z(#7HF6@iAgn1ZW3bI5!l*2u&pn%6WO-8Hpk}+)r6Z76KfO~ZP*UL3%ZbZ5D-*EvZ!mszHQ!}fsx3@PgQN$sOV5HQ3^d`%Fv6bM|lBxEwsSBFN6})-k+Ffj~HVLpDw_6z>uoj znEL#nF;Ehe&RafDr{x9U_oEGQhx|FDC9wiHee5|_RTBtKe>RW)bA3V951Wu`+N1j% zneRaQ)mTwlXfz%2pg_T3e{_$=7U-sLV#~|lUf@fvb=^LCoZGI#qQ68ukY0o} z*|I;XSsBIyun2{OD-EGevE&pRuSgdr_}+CIa>(1ZrE<5Qk9M9FabKO50N?9};KvBI zaz@~#cQ6sQU=S4e9X%J32_J=C1?#bn~DSSo)N&k=~)O2NaBQ}1A6F# z59nHOgovk__yW_Bwd*!Fg++Vcw*4l+Cw4UuT?aTL!U!EWAeRXx>YrR!u zyx`MoY;4^_BCU0G_n>)agTSZv>2k3Gl^mMqm-;f8n)?cUuK&TW8^z%}(7?DtrZGM| za^R1oPpEWDt$CEWGB7y-d?|&0_)_SA=B)~PWvOY>{3Ws^AfBaO6z$#EnfQk;1%xwi z^V6^nwPOdE2RW>IGT99c4Wr^MKxMD2qr}k9@)Ph?k_o2f*|W^D8+vu8scf?l>KQsS zb5#E@XKM^kXc>6&p|jkxHqYhpK@p3C=lpS;oJz5HKOJ8C!3;~>BLE$hlr=FRqLVC& ztX70NIu1J52$`=M4tpGUZL5FkUlKcNuQ?)%WJ2Cn9UV3(r{{e$SuRc5<*(Ns5NbB^ zE+tZ_Q$_yLCEWNB$&cJhWZHtT&VSI67RSzhNy&^P^Cr9*1hG(*$=>M18zpuR+2{5i zVwL+i>)s#!&t_EpZzG_c1-f71(~x$5to#~N8cywT>!L`w+ zXy(EDtCGBiKkeFAQepC=6eaXe*E#xOVlk#1_Qf=)PTuC<6-1k{JBc^R6d#qrccz`k zczy!qLFBoV4=ozxd1=_Ua>Y4JT@59B$D zxl>&>tIpWoMhe+cno}(i7nMGGMA9AKhYpzVr=*g$o%6|_$#&~*<_#; zOBn_wfSTAO6VsWYAO&!`ogO%iUU~jpoRH;U4&vv;k`fhqN>+$Y0#%5Vl>8YaWpap3 zX=`g6HRyS_mYm=ImiWf%g^O@I93cBxdBn%(a2gOIN#i8Lrr=1Wy;e}MsCdCzV|LvX z5ikL16G4UP_^epvVz}P}mC6n*wlN@p?fg<#ms0DBG%k778%qBEZ81Mm0Raq&cCn(y z=MI)Nmpr3MO<(;P7zqiI;1ZUJu*PFb%4J+#%TAv?tCjpHc;J>pnX`+FU=HX&m&R*$ zJP4l*m;pTt1FlUY@MkQA1O3-Dn0gzSDmgA)N(O}f-HTZT$a4dYg=U_E`ZEXf%Vg}- z|GH6?1BIAJoqjg74fFrjV7Ag#s8Hr?maLiBt1Q=Abq&&5ED}VVNM)S=L+RH zywuJ(*2cJ|Mx0RYqz9orK!`TfD6{|c)1QcDu_<#1%31Zm`-4d*9gppMptc7)&ei=a zF0!4leKSmJGT1x8xm_RobJkQ6>ou%cRu$|@Zq+tDxp#e&#ocJ|znqT=x z$u@%^P6p=QQ0S%M13iU9L-@@)zjwDpt%oWaRVGw=Aq!k~LKfyYKjGw&#Ypu8jOf5w z_$6Z8yy=iR>1D-m3i@vUhTdKU`EZSTtb|V#yOq-7so?OBg7 zd@lZ(Hn%hX`mI}vAa1=1gtLJGua6!0rVBjwQ@j%rX?_FHQR$}XNyd@-knSikS`qE z3`oI`G>hzjOG7iHQV*XkE)tW4PxNqipWE%3W7oxYP(}?Hc741JOJ49_Qzx>blYiqs zx125X9Mq&Sd=tRK=!dsB$EIVw;?t zX>Bl{CfhJbvii#k>)mF zx<;*0WLw&@KCczMk|LOAz$Fd&6`uM^P%Zf^8jFN0->zJ zhwsx%Ts@~C)t3#U7$<=~k!Z&P)~4v<6O zUb4!a6zb_UMm9n~6K1r)GtT@?2WMEd2lDGm#Qv2~Y z$|i92*aVlyCVR#)k-*2W3myD*Y*OIt_t{m_BL_KLoIbG-23~mW%Wqysi`n1$81xYv z|05gJT4vVv;DP6M!~V%6VqW07+PU48AT0yLP(gY&SVijq1pr1Yo$+-Lb(*~l1;t4d zv|Q(H^x;uI%~;i}w-4wRSuL#+zMso^i!zB!+E-&XroPb%5_Dri9M>1L!FrhRht|y& zPtqeLZIOCKWOH|E5%{_GGYC4uIxjjYX$4%9f8TZoZyeQEBy)FD7F6Nf^D>T&nIX*x zpD6Y3yJjvt9+1&9kQIiAU}wujs{C+&5X*@~LYS9Msfk{9P9L@M|}xT|N$44xEPNC?_OV z+*!v%OGdL_1Imxj`+F|m2U=7ac76sB!RrA=*4Ay_{ zAQDK?HEOQZ7(rK^rt%#)tuz?U)c7^a` z<6m!1g)p=x8m@nLSOl&9_m=jp^3Kr5fJmWd2vZmseE=p>$lhf(et*8A6>`sKAvqMz zm4maySvNgIu&G-NM!n0b%x9qI-}+@jIBxv(FPNI}@0x<(D^9aN)V;I2uR6ht z0^7GuJ1=}Z#A>*_@y)3##9}nz?)_(lCKL#zG0T^^4;F}&fg z5tk)Q85VJuhZ(v*8ZngI`zdXk@w>_m&pr^?W+slyqsb#z;Pl+8_3AxQ?W}EZ+Qcm# z|HO&YWn38{eCnO+Cg%omi%;eS*1(7v`W<44?C;mR!>W#TTmSZQUha1xDm(El2M!ju zQF<5IOgVY!FS>*6yWnL+?NmV4I%xGHR zM=@RGk+FBV@8-h4V!^bQWCsz`T*C2V$9Nw#wb6?%5ai|M`MegmDpmzIo9Nycl-Xqn zf2>_UU$`*~6O`;PJBDh%R1(h2h_7`A8LNn;^v%2JnZ1$~xwcm?xjS&&lAZdg-FFe{ zc)JsSQJ-ug0AuBXpydYvjTxh3+^Z6MeNLy2V!fxir*~!4iGYfz{~84Y|I+Pcx6X zN@_*rS6!jLw(8V3nkBK9)QiakM8?8e%`z>OuUnip z5Bguty`{8(CQq{IkuXJiKGa|ad}?hT`%Uq27Fy^_yJ#{mq)Q)*|XJR3fA zm~$D%jLB>`77Y)ksJOQrLMe;>!520FxS)qM5g?{*tk@W~K14=;u`g*G!2&pK6N^)z z$_UYj?Cu8rFcT~5{n(=n*@|tLR=7} z_(ggegWywu4kb#J9pTesy|2gfen-0k6c&!t$@skJVlwD+Llz zl)uNiEb*sQZ)p`CcV3JZPR*b7*x$~rjpn3#x3g`y&v&^VT|CSQoqIlYMsP1Z1-uT+ z%r69q;qlAEqwuw+(Jb-skt2=!+Y^imCv~WqHF6D@m#Q{mo!oKOjI81=>!9Q%^VxHU za5)54og%y*>sOeh)?p@OwwY1caSacKoB)C{v8}mUXM$$t_6(7zSxHfuwZn^a2 z+3c3t_pV(~sMB%6U6RdmI@n~xWJVnnet`Q5`j!CPYBfqG@6@qRq@jW)V{wI!G{y5Y zg($1{@eP3cEi5dg!nT>q$tf3=N$JY7qIK7QoskUMUMlZ9E@e^FM(;ReW@tcBZL&La zLKSV>L1hvBOjPpb=Mlpcuk`@2l{aP-sp{u8MjYd6r3&}5)o%^P%96+DleKCZx|?O* zT6Gs&?WkRMP}Nym_O_SYU*5rhh0A*Ivsrq|5$&5_kkD!ZR{2hxDq&Yyhpe!U%6@eQ zh=U&CdbtT}OA)-*fg^5Ph$NjDcJiXoJ)Z0iS&I3hke*hRVlstL8nFtKVNEwZNw?Jp zvxMTf-7;_+-P?8`!Z3HUh%%ASChzcZ>&l;!s)5`SsZlMBcfH=O6Kmy_p$gA8Sfb(pfB={NOE2)a7BlxBayDBzE-ZT-E5OK4J>x*}lX!VLGPir23M zt&SFtN;G@B`kmwW2!JI$cW@j`K8`zv-4pIpil-tJT3HvpiRjO{PEFelJP-Dk z!-?%-8a<}zm;pq6L63WHTdtbdq{$M&q%Rn{F#I+Vm683O|@(m!oG`iYUWT; z#q~7+D=RwGe||`TE|f{_^tImA(*7#zD&fBPE^X#0jhp_oqP;urmSv7hR)cM`ZXN5U zMug}AwlW`TM$WZyP&NLx(9Vv=e;&F%Z(ZeABACE&*b@U(S0*m5sP-eM6SCPhERtOH zE!@D`ybL|}Meq#V9bA+PC^XD}`e|o^kxSRBEYLV{rA=QXO5;(8f`&V{-D4pWJ-s%1 z>IouIbzDUEmx{CdVvsK(TkC`#ZZ5&{hKhR>bFWmOKdu8LAAFJ)7TGWeV#`jW5uVPG zoUtiA!U>YN<_vh+P7+($PCf;pC@d6>ps=u@)|r&maULw))@YpIP@3)o+rD~A->4nF zb)D_9u4zXqI!ZRo+F)_ByHwRq3ag%_5wadZEk2s15!SPfj#{cuRba+8SXNnM#n>!< zya`O*jm9bAmu))Yzpzwy$fiaX67Zm5ie8dWUn#iC5cWmd2Z4qtxQJ8tnom5eDIImw zF^@De(};u-N{4{0C05)4X{=jLdiYhrG2l`qBU zcL=EbBU@DG%tCiG`NAn0`jq)@+b7X&b~gIDuV%m60~^p@%Yfo%(c#`E8g_ZVOuxWL zXB`LtGMrsADvq-}d^3~f%-X=Am(VNHD0|nIk`$mycpp=ED|_X#(vz@nihWrNYd3&D zhRGrAnaXjBvsO@3Yul~3pjjO*(~XFe777kvmwI~9a5k$HHtR?xPTIXs$k8vCRp`Hk z067e7v}5M)PW!QDv9!OcWLdNS;kLJlrKCQrAf=iLSAesqB0@v?aB#-&d>`l}?_Q2C zZCSmyrE68%qozGG#8!?~m2VMHrA!FQvS`jpi*v$lT~>(j4bJk%d8-Vv%>klv<Ri%>9TXV}q$ZgUlw!HZ4(O)$0Sw z-Fbny;SU!2NpB3kpEjs)0B2P<&7nwkZ;iiZKGQgNZQe$7h+LJ+n!F`hK|?1mI9QW6a$J_xJiFTjy=ZYYwk0*9NG$i08`5%ge zJ*)+jfbA_jJ*m?5P%X=|@FU0%iS7HGnR2@4%|#`2qj=rWb4w=Go-b4keZ$=Tt~-Q! zU-;GpB$-zvE}(=k!>$6sW?f?vv+mCd6k)1hPJK8`0S>p6kL?cqTCsco9x<=PDFsIq zeum!Ll-_iojj`j7RcYkxSh?@}_qNUzxMP0){`^60VQD=V>6pHL{d!MP@xA46S>5p* z$C-{Vk4nFiFlDCa)g+=Hd?FM#r#yCXEqAQf41Z@}7V^z-f5l{TE!W-58a-ul_=3)G zQb0!jHqMGDf?+tTQGohFi~ZKwmr^jT6~~K~OH~vq-Jdj@7aR_?D!3lwVLa8M+tLnw zI01Dz0i$Vyt{d3T>(h)Ap&Xr48(OirTzub~SlRjb#FlkY&?%SV=j|7hMt8O}A(O~j zy~L`aBZ0-W=iyyxW@=~Htu)in#|}C^_E`_d%Rg?apDMrcCAej#rZ4CSNu( z(t6Q5y1)LB@&*J%kK4JS>D9s94*WV?M1axr(m7h1vkX=`i7`UY5^s$qVERohO6BfM zqrs0GpW(Sx4|R91wgC77RytoZMm|h<%&Kq-i zW^W(zY2sURUDyBCnZ}-@Rsr6yr90<#S#}E|nzY!F%&pM4d|kV0PcOY2Ca;?@1k+b< zv47uZk7>fsox$b}mf2^yt`DTKeE8JqIgdcja!W~yuk9X0ZUedvQiy35| zcOjjaTb)N_Y!_gPydew#A@~>@$VtF1-=SFAUYno3(OB9R0TAuyyeAtFzB1XDHk`65|(-fWR|Yvx39bJn$MYm1CJS4YXTHU1Odu>>lWc2 z$XM9KtGP$$DDK@8dU!%_p}W+NKeR_9vn-B)vkJ^xK5Evt_+8W$0VH`&@oW#Ydpw$2 z(aL-HA|t#rXz#&ss}VipA-fq1U-*wFKd_Dcjob&L)|07+0}sW&iMzBFrQkseiG6tMYE_?X6k-c=r(8byfk-Hh z%9EYG-IhS2UQ|sO5@-B1PJ1$eXll2)8S59_J$pJy1tHGr(wzW1Gqb>iscUw)l6BX zgUy>yFC(bu`v!HrHs%H6HON|Fm^N8HFd9y7XwO(=hBrR&bw9rW!WPBA`$5(>==qy` zVc%!hydDIg<(4lWMBKSap@i(8FMDZlx#OLQcaAYhav6fbj~V4TXQr&BW%DzLFJ94f z?JGjKmTddd6FZ}S6By_Y7#76tbq2cx;4xDRly<9I~o?LK<$NJ32p3ptcwYAKRKJ9CO|5Q(tnKS*R z5)rf|T4=CO*PuT)Egitq#g)2sK9e`>9WG~kc7OM4HmSI($}%%d(^)GSZJIG~2 z6-}J(l#A^BJHGQ0q>ma1eyIZ(b_&>@SWumA3*l&8qY9d`naV}!llyVf1na2l7NZzI zSfygTiUR`vie)W?9?}mmU-0ecP|{mFZ^Q_;x^GgerbTVKgdC9>b=^(L$fo5peFKAt zhRXMx+glz6+%b?j8Tpu@J}u6b$zT6MGrD*;y#{SLSa?$aJ#*2yba8TMHWz-2Rb+_iKp+%)%2Hd0+Jw7R@&{BVTK)cW;p>$y?%H+T_HMaEu)I4qE zUN2(|82>uYM3KGw4RT7U`eKS+UJzG)wgQU47qZwTIfu|cv^SCz2soN0nT}E`hE!=e zTH#XRsiCYEvI6JoL?2n_t~th(%iZ7a98>7?f7BD6brv-S)J4=>c$#xF`$@vE= zlI}B)5WMrjjgoT`Y3lk4yzCIrPDFmVyFtU>f`oOM z8K!d7M~ax~YXtRfoMUH!r90r7qjCc7f^~0;>Is&MA3!DV?8#F!T` z$Q7>65|lt#%L*0&5UF~Kq#8cGDj$6f`P82CeKXt>$>{R+mEE0EL8Qv`Q#3-Oy@m*%2;oFT)qEa{`y=)v>BDZ}RO{ zNY}z4SykQIQ39wEjsKvp>}Nb_)UIpiH~c{d|4BMB%#7Lr91_~gyJFf;57W^-gi1hT zPSwgPrzLjRKbrO02UbCOkQ?Zzm1S3XcnXJve2l*S=@WOVEz7lQ4SF~;{1HS+19IX= zgE*{C>5%izF(Zh+gt4&Rzfvz{6G)OVX|oO&8NM9-0IO3J`Zg%_9>`!Uhw=>Of^e6j zK(+c2Fqja9`VsWa{04?zX`rU)%H2n8Pj0U-^3w=bIBx_3vO~5nXBb;O6>sKv1eJdA zKNE2ozOVP>6!?3%>7EMVVJZ&X--gDZtMbPRx8kw&Q|)n2hNtcWLi)oht|mBAr^5V| zS!XH}b*x{~HIZaw&b5Ppeya`$z z+}A=Ac0;G65GiN_Aj9!(BSdWk(ifqVfXQ*-{C5C<2ykjD7eMzA9CTH&A;F6hYVD=_ z^Br!R&QZFAbRZf zoKr03w*2)*RyQB3<<4n}sER2Kn&vwaf-FJVfK0nV5ZRPdB6LQ@>^V7Hx44f7iwDZ{ z4Ci>!G1EwXQZOVj==WmvuTY$1ZUA@9`ut~Xd@9swJWpqAw#7KlvER4^ld6i|w`gyF+WG;(!iuoz|KBttCpopr z3d#0sUCO7DQr@_uo*0N%O4kju?!EE*+9S&tA|w6h>;K2r{c|Dy-=+MO9z~5suC;B6 znGKa_p{l1W$7z8_mcVDr`WO7s^aHy7;1 zT}9qh&Lws{QBs1ZsSjce!61G1x7rpJ*0`UYH}z%XJ(%T6_I~>ops8_J_r&CxE<~lC zSO-QJ_^LKaz1$l5^`%a$LV<0aEttH@#%wusaKX@`(=2U)r~l&z8!3QqCOa+}sOSQA zGv7!q7)0H&4vOy~{Z*C(B1>2YzC#v=T@36ZEjeU*Pc_PuMM6Rmu<|ZnCZT#`r#1yTj?r3XNWMj%B54VPMm-|&Fq|xOg|$RQ z`GfUK1}-k^GwBGK4jNS)Pz;59=m6UU$SZYk;&~`Rt-u4E8Cd^#pxjPY&w_H>P(|f$ zuz-Bn0d}0k<6w9bMgR3C4lAIC>^CY@baXb?xVd!?^ctiMM`t%!>8|VN-vjAWG7PK{ z6jufZwXbpe-k>+H*O8Nf?z>0s)%r|}ELe|Lwt7n)JKGWlfdTiRgH0_LqT}d3JlKQi zOCyBLd?_DF?Ebi-U2Nq)-WijOwapPG&61@#c(LWwvl)v`@wvL8|2T3sok^n8k zu(4kitdDlle(}-YM{dwTK?%o3i|)id@4R*99`ywQJ-87E|1BZ(yx>ECqg;bGPX6iB zlWEO`7JVanX$i9W_mq?hYG@dLl0^FyvFYje07sXtT-U5d5(3v7c%~NVu%AEeW~)mY z>4u|+@Bt)7hBg*90C)2=s>z4v? z0x&_E%v*%oFWdfqm3|_lEZFp!?CS=ftJNlt(;XCkX*41_X2=bK6x+zx7#)NNAK^7= zmSXQPHGM_Dc3D)E5WO^1stWte)82qZ@GkX(gHX%ZW7|Jl@6%9=%Nay$rVli&A*Vj^ zj~_lZ39P#1DPY9|&fA~NCoh>lS2R|V6>ejwrw7e+A%vlx+7f=385fatM1zWhNeVCfC@sX8dIj2b__f)uPCpZ|Q={AaZyyi3jT zU!+@xxYi)?sy=!iZGPt+FIM_i%VuCLtL^2%8cXDW*_9ecGt|F8DDShZ(p-{2lwGrf zMddX87x{<)Eh>qGWiY)PF?)Z81P0@m-z-8xcjljT2Q5}3AF8@%;Rg_`JoY72(U8!6 zb1q1u!}J)>a4{PP$Fnkda^Z95)zgTBaPvT&-QJ?~MAtw%95M$ft@fl{_;$6ec{%vi zkzaFzg4$CSO~AGOaenJ?Kk(gi?hNKWhX9r-ligc}aWY{@YgI~Lx5^zW%*gjVy<2cN zjtaCzV6}&E%D>Xc9@sXO_8LRNSQCuYFM+`aiJMZ$!cj%j8`dvgM2)dY|0D6Orilj> zsx3ECgMqHxtTR6ao+JZK8mxKe+}W7v)XzYQi;6eyX`1{P5ix7?-&tYk6ap8JBtdu^ zE^Gn)5g@OF`W7mkhPP+xiDC4T?kz*9_)8REZ94z2BwW+85ieUrwo%DyZ#Gb-1hz|V->#{tVY+eS9z;Mr&U_52_NMSp6WHcM z?8AG$lg%wVyc1XDZ3idgrC%%dt|uu7djC@m0@Sj_TM+I#g6oVbdtfKiBgzr~kY?=aB)SwtNcKOoZaf3mE4!#eG4cMgd6 z5UX<#X4TRuZ3NdyPhxvP_2A&@=*p>pkP0o6#`T9|6S z|I?ExVP60brYcoEfY8z(IigE9nq9XBrfFC*#Q;}Vr26R=h;^AV%*;-YFI@2&iH$a90wSwd_I3=ia2oL6Q8}q2{ z08kaPHnfL)^VhHIA$}j^ITZi$NQpVna2ve;0K5506FbO|e5g~qb;(~%Xw1aRoWFAi z9lF0!FBx$q!jezEb1hTkrED`$+|fy=rjD=3y_XIx3_f;PGJJf6I+M1YTrV} z$d7e`Nu$5Um`do8tIkn(G)kWR!ldz+KHAszOhj5q#;pM(`S#+;Ctua(V}v#$FUuD`}9);;Fkki3;_ol=!p zr*+|scO$u)d%Ik3B}T7k$1SN|Rf@b)4H7UgPmAHj+Lo7>sWwPex%>4x#uaYjyW-4O zuQozPYAb2IAa1{Ad;{^_jcqx6BDHrH&t0@j-M;C3Nnf1;uYY{_WH(SnG}#Z)jjh+nq9H;QPPxg{SbT&gBjuu~}ow2dE+p0(U-(l|GtN zix6}21v%yYTen{BOaKI~+H7xwG}$J)WZNIBv1KZR2XB3;TkrMx&q>h|ZaNxR9oEs- zSPl=D**lx~xc$Fjp12ON8vU0UJ$3>&H+uB}F24 zYiY%s=0Wy^C{ca=Xqbror`W+L{K<8B&qc9Mx7^sD(geo5OM-kqAZ$2Op`w8OXL2?^MV>@fCr~$LX>Ft zjxHfo+-i6O^h26FUHBAejN8`JI}V2RjTymSeWT|p1vW1=8%zxfYj1I9w%4rPEvmS- ztg+u4+uOnFb2g%SCQZ_B z6d=wCt+sqaL4f&T%G)JK@9_2)blUs=;ff{0qkUrDETs!{Mpu9SEdOC#x=N<7)bXu% zcRY!q+9@SPMNj3rNDpTmHELlYj+(k<<2))X)`uJCOZyT|3^|4i5#*Y*=rnbK=ue$M zeK3Z$&NWJkGjo8&IctoQO1_RwM<(o)^o5z<+S}X5x8Mi*YiTb~yMQ&*LMMN15no;- zU>|$dezl+bb@K+1VA3WNKs&KoDIb2L^AA2sqnGqpJ`tytWV1L20=igJONRZ)D);BT zxP7&f#jymh)H>}xtKo|^5sZr_qP&b9a2{dT6MX#jXoftr5#^PSjbRf~rX*+@>QsEhRM~)OgY?Sw! zD0XfBdAl~NY3qvSdcP%^Y!qAUlE8Fra;B+NFtomeOG|s>O>>e{(gv2ekT-#xx6eWF zVn}CR0?*)-Jj~tX+=h*h%?t3yLq!&7P(jcBn2zs*2of*RR&;CT7UT_DviYw{3@kn| zVso)PSCHewHE52W^rZn0Df92wL@6^MuX$fdDfc_XY2{!ly1j9qOFPi!qBl%<+C~{A zJtRwm0T96~DteHBXVz1u9@0Gcl8xZjl)fU2agV7QEuFq`C24AYj|3{ane=PGqz#1t zPub#}VPL+7+2P)WoFzm0`Q)d0jZ6$nXQOaBTc|R<{ z=83x4FLA+_PM}NRXb5K?*gZ?UH%@~W1%m|Qu?Uy0%$?Vrlqc|Di!F&?f%F`mqpGK8 zIc1*Vi<>bADgkqGgzcUHp)m#NfjKR3_P)Of!CYBIiUa|4YbjAeBuJ%^WM*Ng(L+LK z&9Soc@~T2MQWn+PaiZHDwcoxz5kWYaZ&jWWbk-Eq0tYO7J&XT^QA%e(Ze4^ygQO6q4u`c46qrmB zi%0k{xu!Qd%3JhqK)kHRJ$#M#Z;X;I2n0emMk+QqwTpM*0)J;rEiXJgAHN7wkxF2W|Hc9UP%>OaDtNbGQQUCnDQ>&TsSs3rf9&>YV zdd*EJu5ZvZbYn&CRvTfWdvH9x8c?pUb9*)jgu4 z8U_aLYxARO;apQw5xkQW-{fHTRL;lg})>Qv@Yh9BIJaGLY>E<8~bI&Ze#$6mlJB5P}ldD@?M3Sw`rfbCZD zVB`B=(OB$uc|{~DO3FZFl1z2!7JD}D^W{Gq+qph$lBQ%IKTZ^$4XZ?g)xlNDswB3j z6;hnh!w$#ipa97&Wq~;B`4qBmV_&==#-6d{M-Q)n$jP>UfJ8jR9zMGV{ucy8JHY{W zsc97WT=dvPr`1pO3Mn11d~{cF#BEw1!P&-qCvHqY zUeT#@^TKv#aWllttxa&wuq%`#U8N3ZaQ<~_wx{6gLI2XzLZ@?YP`$&n1dav;I?e0z zk{wj07r6)pq6TNV3{2O9q693APZ)?nIL-ityilH@Rk(;gB*D)Oia?GdxJr9`oG*aZMv^ zPm?+2i=nK7Lk~IeNiSB@FL5bxsfw%6>+mO@8K9t`hOmA;> zx=Ki2NjGNJ?bz|-*}ZPra;3r%Dyu*KLJpjsTfM74HS3r^Yx?(gx(T4?^&<*Qj!gmu zvFPRTb53JlUSC`{vmgBhz+>({g$P@(!h)JW%zShR#6QXH1K#ih%8BqNw@u68qCk zO1H|wu5y+JGu_^#v{d)Y1aPRtVX!d4TSNa=myf zLg=6IOL__*!BP+FfbAG$PCuVdynAP-DxO5chI7(u(|XZ{jHI4pK51lYu`x31JhHE(5%G@ z=luk8UzC%fB?LjhuWEKIs0w_|uvc{q$67E@@~i^cCgHmv*@Y^2?cF^bb)H1A3tc@nEamCFO#jUdAUNz!I1{QTz^zfLog8zVzvs zeWS7X%OM(Je4>VL0lmVcnx^1*)I<#yc_t<%HNfM@Gb`B7i1BvGG7%e5_^g>c&y2%Kja=sqn~{5#r(%Py+In0ahLvVYM6_zQ_dD17@Qelr!I*A_Ab ziCy`QOAL@4@&U%i>SfXY_-XmnueB9g(LZiG3GJmhts?VRls?cSykdVDI=2|YlW*_C zSQOfZ>%roW99B+UxqBbHKu;G+D500mc7Wj-+miYZr{S4EwxP)(znfmKHA zc%yv#y>oOP9v;GI{S&AXiGK$iW4=h2UKnIJk%HFae*)q9&-2$97#I-8eq-}e-Q<6I z0nNOUVPVnHPup}~dpEo?o$1Oq%971(Z)v$fY;<*Xm9J9-gD<CBLo_jhEQJbD=2$!glptN& zc{fOi-#(vqq1> zp6zR10PX3*Bf|I}?8skei_|YIbuHr1hhIZl(>af*2W1RS$#{{K+zR&nE9|fPqx}2*!oSM7|87k1%^WSJ169p`k8r-U z3^KEX#tz;=4R~Hme!)v!jH8ws{wH+_c>$PV{`*88eDnX^*fN{LP$7hNcjIk$esK$9 zrrzmg*VNn+e)hd28UpcvjR6UmK=vZDaY9z%#xqwDv^%2&{$ERy14j=2!q@J`S%12@(mD&0#>I_+#6sva%9{@InvYoZ~7u+?p0uqXN;PczY~{>lZ&QSZ2OUTE1JK4G()Q&s`>%v zT)o3gXKB{lO!Hdby3H!P2Z^JAu=-F5xnnHa++1{+Y#<18fj{|Px!3$u24Mv(a_m7y45lWv23_{OH3Jhm{tsG(&HBd zUfKYC0_ei5MSEEb;sy@OMcI*+VO+_n1YJ;5@h&3;1@D_Aa#0=HnHF1%hZ)QA3CC%9 z)KGd_MsXB4RRCyix+@##dsqXE_7Z8@&EyDr%}v5?#>Qfqub=Lk;>W|srbMy%69r`H zq7+!SEu;irClV}12qsinIkz)re|cuMZhvOurzdrg-#)8ToD`>v(0usv*Dv#VcCIz! zn?tV~FhNqYH*ZPir?lg!u(zRSxwP{;;NTC$Sx85VE7c2NLwKP^FylJSFme-8YH<(Isv`0a%2c_AQ^(BId+s~f@UTJIqJ4LF4Mcsif zYT|>&KNDX~`6=y_k;6mMxs1?UzC#RJ@rXe40$+wfg>w}BpVVfjv;R!qd4D&ys5X&B zKKf~Ig;x1@hsbyh$56l(Jgw4m+?#5P;Ajrz41}$CA+HUP$cP3LFz~}WqQb153ry<^ zlh6N(#YyW}h~KTy3-CUyEbin~dipW-n<3@8Q=cY#rYiKp2>2^M0_a7}GxrCJEUekc z0LO8K;`F+lvQ1ts4#@+7T(zJJsfthwiTxqfvnq80Ymoa6cWG;E*Rf@EaD~hY{yJKv z5Y{b5FX*0FL6vG6dJc=8m+S?W2e zQ9sGl@f%L+=Dbr0H4KqJu)7m5C%lDuj6&8X)5{7^-}MSkkbXT-<;ptz01xeSW_C8`f?AP5 za)FY~lPNW=Ub^9gp7_-3;*Sj|bnT}V9Z!?#MMI58GMMiw$`S|I>Rw;_A0bbv--nu5 z98(@RwaTARoGYqB_bpUX1$q!Scsr8F3w6kzBw^HNrIZKGl5f!_#xYM8V-s@HOn5Qf z^qzB_RTFe$y+6baqL4+oeVw*rXUD|LJ@oKliu-eB_3cN9k8;UnbxJQlJ%r*M0i;js zsh?gkYBAlD8%JWQ9s}=C)n0WEbz1!Ikzu+YJzpM*Z;kjM>y7CJE@~4IhXp3bQTyD& zqC-kO@xD|ggYQmuPq`U{48C)knfCE1q-(oY!6kC!!5&7s%I|9(kq_Nv*?dTo{q6v2 zj7QjhC0W?9ce@D0BU65FLTNOMy?;TB^i*>w!+=37QNXg;EXj-OjuFd*D>%1vEL~ z_p9+L#4u=hcT>9s%<6p#$_(eieg5Z~OuD7lg};`&a&BJ0cOh(+Xm(V89V1Qt_wGLK+*Z=b?I$Q+|NB5zJI$dN_kOty~;x$l%@BfFI?v|W|V@b79 zqM^ARD%G;|nKq7#yKLyyAv(gjtV~&#wKC8yMRwGIbfr{Y&fk$Z$U5puN}+sIn3l~z zYjI(xbMwloU(Di-5XL_bDR1QS@G^^-2R(OomIbEct9cB`Hs#rqbG#JZxN|GZ%O4=q z65l@D)6=t>&P8y~X2a3nh{!6`7}7tF*v>Uj-`B z3!3l0B1gJV=HCPizf!XQ(ler#n2FEaYwg`|0VdvTcSeDHxX{43wJmzIIV7WX9m&kr zIfDfa<;9*%jOnb2$~1}i03s$82z)WoTGR0;o1buuWC0Q%Q=+sCV2^FfVTJ?DZk1W_}ND0Jm=x~C^9!nT(0?J&a= z;u!r6xEsvkW$!BrgayD6#65W*3{diQ{!v*`tjxwTROzC04z7aJx){4z&?OK>WsN2$ zr?eByaI|kWe@aVoFFEaA?@U_I)Oyhf9;i_5g2n9Bh7AyewR>1S7m9nMNuj(dF*9~w zduybR&`o~@&40sv=eAj&M2lXr6X`Cddq10T*v#SU>P!W6b&T8S#pkeLG^p*(&10x( zOBy~z(nWcO<-XQ)Z^|cjiKAfOir9!L=N}V>2=Z-_A~!D0R2<;~uW>ZrGe^OV2huu3 z%G^fi-pu@JR>_t znn=^_++KNfz8YuUeSCam&scQWL4$g|*)C5lYn-b6Y||i2zpJg{Dt9@bN5xJPB7aPZ z?hkd?+zCi0kv6hy^tsqudQ`PVGSV5wB_X#&qKLP=p^XsiWHTdon9cXrJ4$-96qxD)*2PP3)h? zk5iqNH1yC0n3vSoxCB|W;QYp} zr04$Z-OgROB&U69e3}I%?)oE7?e#9^3Vw6ihsfK|zEKl*Q)dn0!Ec>ufo{xbWhDbg z)(bqSktT5jkEc2%vqq?B3y|s*F4#CMLwb?(m^Z`i2M#KuWvwPvC4DhKPa zx98^4I$1nqTfQlV-}^bZevjN7)swWuE*|OHQJqP6+e_T=!N`2k)bKYMMXprI0&=H@ z!JfB1XWsGzqLxV!;2He`FY&<4&jCIBoPd_h|HjD@zAOw>Yjp%8lfg=yq-ld14wl|_Z4x)i0+BuB2 zT}_`s6(N~a*luUe7I#4kJ+Q|)|M|3l{iZ=qGjZ1OBDK|;o8|E^I1n>hXefKr0+r``m|E<@v`^Gp=`){p>UbV7!tpL)&;#Qw;GApScp1u}Gsu;d zg_M6>A|g$$ah+Fw*}DjcTvNlfCb)CjHh?~?sqV9+Uvf*^-zjehEpjBZ zJpVj-_Z~2oBmj)d57z1Yc|d54hvL7!-p~jDg&Lr7(3vd*Fbf4=r?T-7JF4cw0s}zv z9zZ4KOadw2jvmH<;%eJD^E?z`D=enla!v8cVkd4E+KKZE=tRBR%soa+)T~)z=12Ig zecaf9D{BLYrtT+Y?U=7M@elK$nVnkeS!pMH{d)U_-_&`NABzO}za-m|2FWWF^~Y?3 z^Z+a%&tmS0iktK1{Kh2t-u+T5K=J{4`*v_vZkuJ0o%4wdP@0U;FwxMw1Nb49aGhi- zduVz(D}W81)x#J1w_gO>^8DK`E`bs3U~TwNk&dQAmuTNyIsMdtnULdr$Fo!I-L0-D zA_+guoq!0emPHa(gQxmv&vriGzjR>nOq10lb2@&9ygehCHyKiK6?6gvgyc#SaL*q3r5%k9ucwTTfl#~ zp@5qC5yAs$#&kVjR7}(0^7E*sYA-bqQBv{2^>ItD?^$k@E9^K^mHo0E2(OZXXcFeRPY$`ElPhWlSVz+!E|K#0SbTphODsr19v4lfB zwuA%l;tcfyMfbqHxPa_8EoJ~K(!|5oO%FT;uR?vr%iYdhkdDABI}6xO;Dj`%zcn$r zgEe7d#&UYlqST+{8EB)wlAK_9$N#DDVtSG1vM{3L$+O_;;kh}K0eFxPQhkRS(@1=W zh6b7-zK#uZVzHi5G{yJ8G_;|iqEd@N6eor~c5CFHRQs4%sS_{PPc>d$i~Ilnq#=e9 zwV|WGJC5&(yxpv4i;k_}!Py*(L@w{z7 zI)s7Pmj(V{YeCgO1F5rOMFWLhQ79^BO6pRS` z`?(nNS01h+k!qKxSl21`_@%6LkuRExpXIC?nUNjTIjdPGyATbeYa3AuTK@s2_f<^@ zM+kx)^;kX2y^1o^ZRimZwIS55PQ$&O1Wq4yEf9`3pLu>Gf2Aft3CK$SjiTm7Pyqs; zRQZ3C%Z#bZKf#5rKUp>05-qQA?n$-b2>UT%m4fK|NHCzzhC};yL2M|KVN!$Ty%VZ!q^HZfbFgTmpRbaHUZV}*){Vo z!9;CjSb)XW2zIaUJaF!aqxb~{hN_d_yKU>I}h zh<2=WS~4_y6GJNGTIFw$I9*223&7ReEw_gD&zon)79}ubQA{@e-PH{)Yd-3#sx|=r z*f!VYHvLVaw4qQv?diI^rN z6T3Z^_W7xYe3tx|a&6SpCnzms#!e=Ge=8*j7*`?+IKz!n&u_808;r!HnXH3*S& z$T~~RpQ3zvDE{gK_S@%svKRc_!m^Y?o zDGf*g+w@;prj=GiABZWYvFq0wi~L43fX0b%zpGb>{XWRh70oz3hq^8Q`AU#wTIog-r*l7r(_H`iH{^P<4nFN{dt5r&1k9u6 zjLDLDm;st{txmmpIVNCiJzYt^^R~&{cHwum!fKX?=a9Zj=PTLu?k}M$n@Z$LdcKr^ z8@($@q1nzk*&%oI*mdKZR@y&D3DDn}1e+3{0E;Q-0}Nmh=)=?lLz>)KN$HG>#RjKz zC3qG}zA7kO=XoJmw zT{E8_97;WQtYaZUCY~xXw?GoCJnbQF)ZlTziz8uVd{BoL9|x2s<0A&6rI}pt5Wp=0 ze=qSk7k(M9=U*-NUS=#8FU_ZoS&>?wi!gkYzD{;=EW6V0k{j(0#Y;B5GvuzepX|Hd zMYM2PDZ@O1KKH~=E;jA&?>YUa7vO8K&^G>X<9Q^+AVd)j$j+(IH%TltX;flJel;9# zU^({$$oS~P>GCzj{GrUs<~SCOv9_K=&!towxc$sto*iKKtB8I@D%1iP7%S~}2nD`e z4U#&g7>VAnj`vMPq2>ht?=brd(BdS`nb?|$GpUTPz=GS-%`okr_KFT zr+P_oSm14H-Oag(l63ww800U?@N+12j|_7>Q@JH_+DQUyIBYO*|K@$MBBx|wVX=Sc zZMy!2RW>!?=1B^`S|4(s_PZX9a3mYp93=PfpDR@N*?NyAAt0~;c13l3fI+uKoV)3Q z1TrGH0MZYq9>0?-WGy@&K^x?Cw#_9#)@AnSMUf6s%7$-fO-joaHZ?r4ZU`*bvL@^+0Fx#qk)Lz|=xz(B)qJ)2u3Z$u^uVjCK^lYiKAwuM zHoy2J;L)&XKvqX<$diSZB)&e1=*cVBNdT6s1%D=laEa?jFTtve^5+lr;PyKKn*Iy> z5PG}XbLg9@Vpp-m5xd!{!nt8)IRmCvAy0>mbPk`Ew~0wgi)D!p=5V%UA4N6B*X2sm zUmeyiT$J9wE!d4Or~Wi#bpfFiJqTNcq?Sgwj&=nY%IR%RBlO!4G#1gWNJLWhY1rfW zq85R?%o6%%-b!O;!GIsA-rv}Fn*B(p!DHX`j`G`dta^M{8B^fA*9T~Y*RQvUmw8b? z9MPC|`D^9OXC-FPNhK3i1XK5R!$QO0hKKL;ofP4-c|<|c@U)q7>dyQx1=%*b{hNzh z%;Cb)F*@lVa)MZtL2k@f|0A^GeUs$O&x~~uS;ctQSwrf#y82nDi->-sq$c=~5YT5T z8kdi}gbbwlZaK`@jpw;9cCOULAJm|u&f$yo75={J%zf~dEQmu6M@Zf77H26}N6Flm zax;tv+G#1^hCaV2n@ur8aK?Rv^T=v%+HRhURp#Qhy?oB8f16g%5K#X(3eO>benoO> z!~Td-p!Ffwa-GVma}Pb2ME)#Qm6!c8eEK~dgw8fKV`#~=8qO#QkkI3}7+yd9xl6cu ze;2Q`-12ywFEH6 zfwrK-X4LUO9gR%JD`g*o$EzZqqV*0Q?^y}r85=bCp9}ItgzT)pUrS z>m4+d@37Z5qTd*beDi?}RsY?CLS4QoasT3x>Md!Q(PUL$_1&{VS*m*NeQB8+|o)er(X9 zw*>Z1PYxMo4mf^k=(WsozoS$XVq35DzZnz@_0MSFTgZv95mN!}OolLIAzdQDN{2$!k zL%=jocG_OVn%_~|3BZLW9P1KtI4K6cU9%d#-7h;Z3g)HS7-ZO4;_2SM_J-Ad{!9P0 zA#hfj{UTE8=oUbX)q*r$NVWsieM(XaXR{0*3_bc0L2Gii^(eVhnsHYQY5J_yMkNrp zSZUm9#hyUS>$c6wGvkpPme>i%`~^rRZm&sNev2`J0%13EM$fJq1JQ?fW|{ZW&6-^| zo_XqvihIT=)z3S(D_1B9)9b-lpUG@ecP$PErk_^(^VjDDVAR zm}EI z2gdKY=vro%{wV;?y$sEh1Sx2PzF*PDxJq6cHy+_8GA*bY&j8LnEc?&T{#@MoF_Q7;GG zu=H(uY!)Vn&aN_L=o18U#b1ST%zI!c`7H+;;hQtUR+D|-+)eudkwSyN689{os_dZy zDc%$-Ma?K&IZBU-sYHFPD|*Fu+6rg0!Ius5E?+sDk{3M0VBrRTyQU|FkvCAh30#X^ zLtZQWQFP^4J&ZaPi{qor1zB$mTuuX?2==wZCnRyzjZ&Ghr_f#U+hGO!5aAbf+=}zDDL!EyHbowbS>r1+<;6_j>aOVg&LU%$5^!RxVryUSD9q1xoKz|0&XuqVI`g zx})TlQf}*6ov7S*3=YI6+my;`+ffp)wGx9SdPibwW zx+Cx_-s~%-r0*1t=kN0FJ>_PvO#nOC$~}Cc&0SHh@ZB-bYIt4%Dj2Bpxyys=i^b^A zumi>b)Zd`Ig>PE*1g{^Jita#AlMnZmcur*p4)a@Xf0NhsDLH<27$BJD8Veq60BxoY zy-gWd*KWKX!(lhJ!~h-uiz_twvLU1c3&Z=Z>CBPK^`MlgdfP;yCdtr@($J z;$EeC_mE@y42Lk~Q#?ql8jfk8P$^9ToiS)emh|U}H{fYT>m(HcNO9RXSFo%8bbKb9 zs~uCKT|U5<)i52dsf7{F`VrOOWe%IymOC?Ox&SAv76V*0=?8FvouR7u6y3Qy(U%D#o3>Uw5@DSsjaI zC}$waooSq9Hs~%VbZ8mxl1=~4Un&_QqZaWa{qx;+IlX0*!?uB=h^-*(DU(_|V)^oP z689c4rG@W|rqL3BSDRF#*Xgl?QW1Tm66{h+*Q~1#QFbl;e!%Y{`S2SgIM+R|CF??w zOf$(pPv6!qQLmBYu))F3-T&3Wy*$xotxAcQYf3@uuX-BaPP>=N7xb9|+_Ju}lMQql z!9aJ`+NyD>$^WcE2LYYuM`XLpM?O@I$tP|4NZ!Tmzw|5}P0?n<#!qfVcCqtwF_M%O z%axatXfU2FgBtzJ^d&bX0#*;d*vz-Mn@ z1n<^kY5^B6+W92x{r1j_0~6%S-CpK_Ap8TPR>9Ba1IV(|)CdDpm`{{&=4qQywtCk7 zs&IaYsCJj1KLQAm1L-QA?i|d{fkyV6L$KpACC@6ZOJ-5>a|_j}ebi z^r$yr+TFy#bpAR!w)y)6lp+SRRO0dPOY2nd{~Y$-eDS5)`t~{$vP+Z{wiq!M^G$Fm z$*7OlBI>k_ugl7H{}D3F8#ct(Z!e~_(25k41yxLw$oibF_xxxLG1${#CNywrx(rXh zjk~dwxH{k2lI4Yz9A$~dwpv~Ks!vp}GL)z%c0{-OPV1zPT>GH3N*&j4yyK;??lA~` z-@Ahh-%e7J9MnwI=`&IA^s%B?DF0-1|4^`~_%`Rbn|u2ZtJW?v|E<^VX+?ip$}fc$ z-no{WDFX?B{o&r7YWLZ|OqtDZd-?wNMsvM7YAwDZ*R4N3VhK+AdLaF> z3-~POTrZX1ReT)#u8|Qj@<4h8@l8vyDNCu`MRClBY3_K&7@cWD=PeP3gYBA?C1lr+ z^^j(&SjPbipHwY>A>BhissG9yX`6WYeBjNxp>(FSkXcJDzdz>p^cqY7`Z_U=X_qi7 z<_K+faB5EyC|CEz=ePL|l%e$IFW;DiGi=x+@YqFmnBrJT-)(5bq_v#UihE>Ju^@3q zOSlA3-E5oA88hLc(CIvR4gQnXcG4Nn+-7ILCcEGp?{O4&^q6QyVjg`(ps0h zV%=H>LA)#8{Bcdomd_U2&*iywJXTG2_u2$Q2l*%XJYE%gL=!%gv){YSaw0chCJ3LX z)0(Sr^^WdeIGoYi9X25d34rR;$1>o(AYgeVCaG=-vVBSij=8Y0znV5qNN13ICa`S0 z+@=&fD*hn!<}y;9cwfrX@5<+S&iS?eC1% zUya+xi*u&+TGc*U$KK+3T~%UG*~KSH>MrQMTQz(0>%Oun%=pW4`A9-HsQan?4zoGP zdSq{gdgiozjGys)!(S%$2Q$EJ$0HC6`-tHYj}9l06uY}Uvr@5CEQFrbdhuEdT2UMd zQhJzx`)tWH>%uYLHVgB!hF)iOFb|>^eY@E%U0oc;x)szI<@*RnFrgOCZeobpeh#ri zVrfRO7~ow(LkL;?68vVHe7`GnbQGq)`!ndB-`eKuk`;{D1CHJG4(u!XvTi7QZ;o^viI;n*q;Vs>ZT0vcIPh?pzBg>Nw8 zu|@icRI1NvzKSL2W#YjT7~kQz$~>BgQF*8qt?KA4azagf@w3Dj7ByzXe2sT~0>~F|pW6n?1xJEd zwgSd-Sq{Jt;$clrhbka((vAM7+kz@lA8WW)MK0V(yYB#Zsw?>AYEpwk%onLcX`8MO zW@V&Xx0yEmqS$W;PgLoHw5Ct`JX{n5PkPKqRcci|3@b8gD1hFj_Z-l2kyK~iwIwtK zO=w?;3jPU0=ZuGPD_?Ttw$s~W>e@Hc*`R zt`CF>q0Doy^6l3Nx9X*IQ9jKMUx>PselBLOL0fQ_mM%#{tZVtFhteNx{Yi3BO`_); zPdZJ~$sW&lfByVxRa+J}?Tha<1WaZoyVB?aV3FzI>aB=6Dp)z7u}0qj4kbnZSUkA z<>%}kM$!;6fnHc&99et62*SaplNE9vFE+f(OAF-vj+fy47p#`KgUIqb+1jjl=gP2S zwITIRhA_h6X*?mrwDGgxeAun~`qMEff{f{5J! zJ|{7;2VZmTjpk@&g4nSi!ZAay)s?sy9tT4DOWgDKNp&E%Xg{<;W})!2mGiZ{0T$4- zC3HOI#~D357)nJF-?i?KmiVZ#^&FZs$$K%>cw_|yy|y4q)xMeh-Qy6e&M2Sz;sW{{ zU&X(pdf0tKyq}SCOy=*fysE6E8eZF+LbseQ{le;pwUl}P;id$2wp`Wt(Fwu;gF2gjS~PA<4t>I1{nDSf%qcAO-o3VG&FvpkzyR=ReXeq9$x z#CJ@R`No_3=8GK}XChZ;k)@vWIfYg>f>;a-_++V|AGJ(zxMHXtRBv5h@}oBvO$jCT zT+gz)1S#E!G3-$zb6|lSI5$maktX za~O9jy~n#^Y^p{3Hm`>_CvOEp{8oRKW>Z9L4KT6D+V@!%-wIb|>89%TI?)YDvb(i~<=^Hg8mK4c;vgKt0?|#g3;wAyyyst7y z&=*@!-mU>l`N8oXa@zxhzNcN-g{%;QSNiV zFvisF>MoGd8#3Odu*I5byY&ddCy|jIzwpwy>E2m|KEMil;7|R$#6a(kl6OXS;z~}O zREKKa>3se=hq!YseAnrSt!MMn247yY)To8sjLLyi`0Eck!7D!CK3gUKltC@q{ur@v zKZtm4v@ue(Trs~5ep>70{EXtrTO4~%q+gzuOlq2ZmMQSL7MqbS(>C3Oal;y$Uw32{ zT!&b5v(iiD!5~q$N=mK#Gg&e0cT#^3(To1Rc7cWiF2_%qbNa9`@7ib)T0kQ+4U1T9 z;Jl!k`u+yu$5SV}4DJ;pM81<-MQAQQf_Pkq(^T;7tsjq=!i4Ccy%RLQdhFvKSJdti zZi^=uN*gX)$icDVK&KjRKfXWuah)aJ==LOawy_VjMD7%x!bWTG{RGMCSyy0iYT-WZORhTWf`S5`X)#e(JeoS))FqZHJW(@U@9;!$u zFmHjeppE)-q6sgO4h@NJpLNkBY4tHmnCZUE`n|p*ahvYinTV^Xw~F|L^SxZ^tP1rJ z&WGz~U(ewNJKkWM^WL~ZjlbWI(iuAG`~g0YwCVnEIRf57Op>K+yjC5Cmqkh7#A@BZ zA#4?s_hahws9N4mTvFcz^zLfBBMW+Wzlcu^&_#C>IPqYwzjjimv>fzy`T7MaVu0>39Nu_275B zc-pH=s(^*(!5V~Z0TZ}63fpHn^PCJ1AYMG&VH|NzP`rm^6N>%q8V{b>TT$d>rlj8j z*54?ogdqlR=AkRKJyznoP70E;_Z?~c2Tl98E{(32n7gCEsQ_4RabC7rTy?-Tmsv}y z&&cq5sv1S-<{NoXp1Drq7K`|%##U55@5O0mk^Rg1Mb)%1LB^ygdv&%v)p&!1lB`mj zuTSzRvxm+xL{^V1$$-OR-Bhrtg!TGkbi2U1{DhT=6Zbvi{aFm8aYFiNtZB$PgcC#}g(Q2SxHAMvA)mKAj!WZ}qBp!7m}~JG^FkLK2{t zDswWdbM=8n2cy%Md40CCpj-7>@kD?XZB(B zk`<7&w#sJOcmIu($Hx3Qwnl&nb_|#L&~%{`j?pq1vGdYi$o4{037Ec7)}$ zpK}SivH**CyZp2=rATU-z16cEJMivNC)sPaV!&v?GAcy-+U(YY&=#%S#Nn#ZpWQxr zpZESjSEO8B`)`tfQatnRZ8JmbO~htxIWw)%qpC;KAZUtK-N<{YRF3ZibphsI<+#6g zCPXJVxG~O7xUo}U$3Wj~)~>e)H@3RIB5r>4@2IpcY{`27?&A8Heh=X}((#rEWMthF zL@;v+(pjS+mw3ZoJK~^?kAo^`BU;{L%v^WCQ(`BaRp+6d@f|^|3%fwa5=DReFk7xBek*LBncs{; z*kq$$P}6r7c0<6r`9G76P1%7)GyS3thSqjg;C9n5h_c0|&lB&)f5ST121h+Xttso2 z-n0>}fx<(Z(bYzi2G z%RW;*_^*Z2eIzL=kULK|%z!=bf=&Ble7F}e2Lwx zfHyDI$vEFcL;8H~&jf4Ud5HzJ4+q}%Hy)B7tef0wZT_{muaF0utAjLpmpIJN8_Et`2#b!b%QLrMOJf@BX3j!C&!%PW<~7vQ@IpS;j)*YHfS?{#hXGoG&G` zjM`e}{o8wKs6)a7IdUz$G>v$fYIhB|YJ6Rv^{NkjHXx>GsQ89VJBeb2mpIHt63pxD zUf9zU-)Jb*d)T3NG@;eqMmA8d#(E-l-I1Pa=O6droUj**9D!&&~f8?t6g5ag9r_@i-%E84zk*F!ZM3OlD>D5h ziEnPX>Qi7}sTj&?mlCnIPHILkim+dbnzVt?7xw%EBnl5>Rb3w~x#SsO|4i5+k)s0e zx#^m*a?vabY>Lx#!#%ojJgt1VdkqK8-3+0@)}gP)rx^)S_gQiu@*&9{hg?;~DX_d$ z(@dWz&USfYie~~yQs&2{)^#6^a#YOpiJ4OSJL0eq9q?rer!6#i)S(-H#+)8Mx{zrrTSJ6B&HcgWKsUZSKpg|?rBWe8ImSWynE8MzmVarhdzZuUinn)(-) zb&F*{_Va~K$J5KRKF%wD!m{JE&H>20I{C^BF55)>HVhrLOh&cNi<#++I(e^YEgP#Y z98`$3N_R4^{qq2UX?14jwSs?})n+sM?>o4{))?cHwKx2lZyuqrEMoEtaCL1IcotaMKIlD*$Pc_$pnV!5Ubxw1|WFEwAU2zta!` z;&AnTwpZj4NfO655SJybwpIAfhoXF;hA#X0s%#(Jy8AmFieSzg8WaQNWb<0Vi{@q& zdXl+Vx?3!#o)Ws~!j>OCAAs&70E!_{w$(*nhl*2j*|^2>-&WEx^qYqezi^U%R+;iZ zm_mNq=a6(=xH&I2eV#WqyGJh)QKCnFc_B`3=|{h7ZtOCc3;Wi8u+XsJapd$`^8MZY zN%fqJfr>wdNsnQJp7ejb=&bhm)?AyD-;I|+q@`(|-6zL%M6$<^-q;HmwZ0D%gMMyq z&2$JFqmfWcCJ)L zN=6E_)VQD+_&$WG@5Dl3p{3Ox7gGQ@<#=uO?Saft>2m%KoCy| z92P%HMP;X$K~-3G%l-Twe03%IL?v_^cyV*bd$$I=O-G8pldi`aEo2k|ukp`4_zQY6 zO_h~#^koL$NH&#_b{CrvD%r{>7Yqe1zmpA*@jRsj6b@LOI882pgl>(}b~A1``42wT zIE}0q;G`U6ps;F2g)6W>DvuOHcet)KR!%)fJw=R%$4=5attmTU5$*w086FtN1)JS! zY8*}9)A4Kzg`V!tx~rR(>ml5iz2|kX0Pb#saeZp==H1rxg`Ie$KM=N2hY`;Jol`z$ z-9OAJ#UYF$7bqR}a$wo0$NxpiYH&5M%cwEYc9J9pduK^m$^2aT$WGsVS7VxM)g6=^ zxrUG{_64%0#9dH=NW%^PmQZ)w!nIC&Xoi9WStf*Vl2mF-x-`G%gN=?7p_qOD=3w_Zjejv2;c|8XB4wi7w>y7Hy`!mWiQLVn!?$I!^ z;t6O+O4xE*-q0FYJ1=XE;#8(MP_0b-f<^Xt<9jrnQ9Iv2^X-Pwora#KznIERufM>T z7Nd_{eWT@?&rt5M6LJ(ZbWna^W4?d?aS*=%8{v7~9~!FH29(dkLm;7LdJX*NJyoW6 z;v~eH^pQ*>nL-fRO!E!I`R2gcgG#GF^Z3?Z1U|gVsYE_qF^C1`BpTUL0HxgTzf`vL z`KJUc2~^v@8;~LtR#H8(dtt9_M7f7XO8oeN&Ka%vCoiAfJD)pb+jc5#S&=3AJXDEm z7aXw+lzTXNAIxCzKwlOD`J4-&89xt~d)roH+Ubh;V@l8?MU{9knsY_qBb#6D<=rLj zFsm)n?XMQ|^7^PyinzS z9p*2a;r08>_XRg(kKL*)kcxfbVPjxs?!Jo!&&8pXHzC}|E5&H!TNkwfuHO8YC~fhW z+jSe(KEfQS5CkpkuK6tw?+5K+IzfL~={l@d7t7zAWDOLsW%v7~?WDkjW*=K(Kfz5x z&=K?izySfuNP}Uj@nQ`XGt#C2NvKbbHjp*Qy--^J+w#j`Dk=@uUK<;`H!%_6X zVz5v&^3P+gW#jA;&!5ivsf58hY=Vq|x8sL{{Txlp=QqQFS0UcrQ^)kO8Y)2=j?&@J zA$Q!}7d8B)bT&iVL$zMqVFUvmIP;ZlxPEava&Ym#lMlzqXZj~p6$9nu-fnO-YGPsI z!Sv1h;y_-*H4Z}Jgxm7D8N->U<>a+(@4l(#$XQ(v%IisRwtA~CD@A4^yOSh7)JVao*)v1y zwED<|n~UiK1!p5~4q=DaLc_N)WMce>7+~4u8#@7r0Ud}dL2*gC6_PH_?v$BWl^~wv_`P^G9S;d#v@jz$~v1> zPhgsRDrHh`E?dLpp2|lKV7xP>%m+v}ZN5};Ypb6=6>K$aCZLY#S?*fSo2U@r4W!@7 zQ~vt?M4-T&krN09%tq-FJ;87sH z91?7@X&4ZKH{^x?KrmQTR)b*uNV{2Kb8luX*nIIW?>LOX;X-uiKJLj*S<9|?yfW4U zd4W%J08+H_@|4i?fUAWEmsVEtScpPPg6~C?GgomM+~*;RYoNc2heNG!rTD{l%Ev(jD@Yfsdq+$>vpF1W|<%U5D& zq>TnF)EjI-CEbJ}2HY^d*pWXVlx(>^5IH%)TGp)LtE38-?@&X0eY9NPaCrN~K$6)1Y&d5^*bokes4aQ-VVWFSycXoT@7GW###0D+-EkG`0b#w9uuZQPHHcl+>zUc)-pFM|1=_$ zg3>A}Cr_zpzG=p&L15lXebwEaxurk(Emz=8KTO}-6Z>O>O46%yjI!SCTy=lOVnK=0 ztaAGKSMUAm?*nIJvvDX^QY1|K=;PS)f$i>u=7kFgz z-dkdh8nXaAW8OMRACe-=a()Ogp|YKtN_8SPPj@&8MxP(5#J;hum22~htrOgc0ZHU+28?JB!Xfjz105G3phGGf#5Zuw@nhGYGg{S zCSH_E#v>z?MP$noe}Gaqh;(DlHliv3pM=~L0*nrk*`tJqT%Hb-)B<&tw)JPIJ}0|E+wPd5f*JUl3v#NY8ZEVp2fYCKLzHZ!%`m{o z+gZi*BjOXFHIX=dsP0z*|LSX#CV#+IwG}t~kC+JlVuqexli;KFJ1U(yUGQ{#MigJs z?IvjBG2~U8+HQK_$4-A6PpM~w5h;DxN6=fF3!s{80!|XU2l7uh>-|sE*Z!y^eX|G4 z2p<(Rq@KstcOaN1;$sA1oF=9-vUgkm%8-#Lx$3hdVh-n}Dk>$32Z>Vtf#D8_6HoWwRXZVHbz;P!6 z6YXYQG4Av$OFnkth4^l+`i^Gzv%cKIEq^PkmM zdrMnw+muus4Axem+S#yH+^?Ncq=h=xIiP>jE0P=fkH5==97!_=i9}<(Hd;| z&tJAC0)^Ml#br?*-SXI`(p8F_cD|@L2VtFzGJ;wyn5{s!yW7ngAZ6-fGL8!8P)+71 z#kVP4>g~&EH$xs{8C4sRx#T$!{Xv+gQIAWF`e-O;T!=mKeKx+47_$cuBtjso0SIcD|ncNe<){<=NmEh_Mu9q8;VcmY^q!1rz&va z#C~!o6DLtKX9L{inrHwyJc-;HugnvitI0eQBnl`MhAF`@Yae ze*fdAwVlT@(smwQkzxRv(_f)6wyURKY<`UEd^dM95CVxYhB3bvOI8{4Db3aop=s@X zdI%cUW+*Z99xHQi)A##V6HG=|GZyuiF>|hfp({>-m}muY9y&juk2~p&d+M3ku~}H< z%6R)KAt5_+VrNjAQIlSvW3knU3U_vYUgX+vK8j3z~E`9$R ztxB7x4mQrxBrB6k@js2R zQD4npbNS`^ehBlPPBqG?+tNc6BmWBPD&DmsQ`8D5Qt~!OR-`RAzHB(IGma;swr9p8 zBjp2d%MD4uI4T`L$vFpdS@baMi*Ki0lFZo|l*v{6&r5S{`G+Y@lm}2nFP*&VknaNA z6k70nWo`AgvR`e?;HejY&#;ZJ%Etiowm5OJ#z-Pj<`nCssvs%rFw`=Zj3B{vgp8L? zjeFp@?`P#}Uh9udLkb*pbiX?Nc8l%WOwR`dhJuR}Q#;!_H}thk0B!N+zz$Dd)6I3j z&DD1|T|}2{fAXNCQaTlXUD}i`8y%F~ZrOegKFJFZJ#eA~uyB7F0(*UaHQ>+$Mw$Zc z5%HXKbQ?eZ4~OypzYNSCGZNSBfmg$_9~^J4+%16+zdV4!mS;1bmp3t#A!IgHq6bg| zmz)5;o4L%%Osz@NAs8!~8kql20RV2QH^ z%z5U(xX%~T`3mrj%WuFN$)r=iQilUDgcN|_QRfPXFL}nNzloH-y37V+0*t7SrN_?m zcH`&CPL4g{GTIx;`NB=Ew~QH>oz;0h&F-!`H#Rnao)s5 zalCkj1$)CDH;;MGNBYj03h&ApxI^?zwOziD-^CxhP`8HNH$3*!Psahs!>KgqU8VQt zHsEyy@&w8=dBYxu0bA$J15~t|V-m z>mitglVvksI}oWe>+y_=8$Hi6$?LHZXZJq9daQW~A$R??s;Tgbz9!ty&+XuMrZB3B z74sT6n1VxQ@6pjoIPU&PsJIwlyc>pzSOG@h@oiZa4*lA{fCJHFKafY)8hv1JfJ9Cj zrDF2Mtp7>Qa~sJZsf3rb#<@%X!zX$ZTY<=ql%e_*(KI$G-jqBc ze5>2l;7utJ0YRa}zcHv>Gx*f)PrnLGd*fUjl|K(UNB#24C54eTwo4EtU6 z>XY;+2i|--olsZ#CkZ2CfpzKT$pkP1`HyzV97dKv-=l%-gw9*^{9u0bi2g7Y7-#Eb4yu!dhhjQE;n4M$l`E(khy70S1i20LFZp*KToMLqntX5su2x zi(D9BgSDTjpZRCLmRVsTE5T;|9~ONRU_H;$uXS#H`^FQn^^OBDp7GzGih^(Bc7Xgf zaq~BOXsxP-F}LlJ)(-chWl1zgCJviacO*^ATfoNaF(*w&3j;)owF&&6l!_F68z@zg z$rr=*UdKN%--n+D1^{*DbjwnPkndEL%|e&k!5G7dyGcGE@R+OY&H!LOZ{3y(AzQ^b z#{qXYV2pd;&7zZlN~g0QDPM;Mh|Q~)qG8Y>U-59!f4A|8dM2tuLZZ>M?h^0^%h1Pe z&#!nIks4wcco)}o-_LVh?_cnKc=^D_ zMyy$!bF6cn>pb?~zQ5XEiNoM~>fu-<@z=)68+ zeBWgzHZOONN}Apkpk7@!dA873aTgEm8lA%Fiu;h29%Axv{ZR6pPhUCpP@nl^6%<6w z3#BS6zQBdjx?$d3?c`I|NX#ch3MH&?-(6=T*@psk*PHE-k@wbeEzn}YGSJWme&xi< zLBY|(mU4eYh5?g*#xh51qN)qWu2)gV-}*HlDHhp`Tki!Gwg_W@0q0mveVDUFskZ7E z4%f~0+BuA3NSpNdHABKNTkey)-yGEn(;KV-ukXvd_fmRrH6s}saCTK_@E%z!*wLsf z%M^seedS4|xF5Oqj!01g@Rk3b0Nx>|`~xR+KZ3xYZ20Yi>cFR~1eD3w2abWb^4c;% zr)J`eRDkE3I_eYO*Diyh)%PdP+_%kk?$-gPiG|tvjpva&C0@8Hvr(d*>Q)(Lz%HN{ zAe&TapAdq(aSni)=PVfCZO#`}O8C5NbEnF#)05_NIJzOVb4v)22OVFon3lkeIWvmUo;n6Mj&uJ}Lr+!XH9{Z-(G zBt~r-6wn6jSM&h5n?i{NA?n;McEUFLZPO8>s15QdLlpy6vR3f8+&gxy=9_F*?Dz|;8oLr6d)fcYe0;Bnph2f} zTyc7?`|+Iy4j0B7XzPzk@)W<8j@@I*wC$>UZ(R9Wnp4QXBM4;d274+-S%-Y;0^-V2c7@XQ8W*v(Q-W`_%#Uo(&mjCo_h-^@ zzb-M!j=?w$#NK@Out6e3SDRm~ zclGdJtn65kFF00h0q~m3kixXs;dudUIIv9eIgk~^JErfGS$!TrYwg33v zLBgHyjqTk-V}KCYdspP7UaA3_&*CAGQurA6emiaP1Ts6teJ@Wx{!+4IQ&uAVXL3GR zZ9O5^x}l$nfT#XAIiL12yl8ms)4V4C8;+at`seGj!zan4Gd^Qp6dm4kzg|{=5wyVE zFx*Gc4nU#e$UkDGB#KCML8l`+cBB_O;f z9-1lwFVX}w1NbwU6g7CH+X|cBpgc>3DN)sTDY|`B9PNK%azLDUcg^IR z;l0~u79TI8bFVLgHYI4tJte8Wy)q7NCj`iw<>TPR6?oDEBW(|KmWo?z&y6HEPxwlb zoyo!#oDj&2iryK!Ni8Jm03=seUKP)BVWfK2{QC_}tEUTKW1@iAmYC{u^J(m5DV9z5 zv5uw$(cScrWpU`CdR#kUM|wdo;Aict7{FEHOH%`@?K;?)ofTk{J>MR0mf?ap_)Ek)#$htW>&XbBabb; znBLkoND|SAA&}8!w&nWNhFi zqqd{Slwsbd$IbEEJu9-=-AIk1!#B(LTkw@@8d0xe7W=>#J=YO+LJ*1+3Fs&*m0a`B z!m~QmELxfC-L+E0_znB+R5DU;d#j`_`% zYK;}EndWCJZRax)7A%f;-mB}GMcXjzwtO~LB4P}_iPHVq)LMaT)(eg41O$DL_ayTB zw(iEo-*O2%g(?}@0PWzSA&2z(QEfnSq#511n9O%8KHwqF>2O3NsasoT+q;i<$t!T; zMm1#t!FYDDhRP z5e(VQ=ZKBZiw^~?5~PM|D~EjdyH6HGmlDMccZkmD(Ex|)Z$&Oz7Xhb+-8{T|_yqIS z`e#xhSZpM@BMTj^_QBMzwA;(q!(#l;JoS+YHU-DF><8s_*+hofjsqA_5=~j=baBa8 zn0&b{oq2>rxI+Wxlq9n#l^RyGjtXeU$o8^2kIaT=W%O=;R7 zCXr0qiQws2w?bbfuR}QCdkRGmRZ||?wlW{0+@5OYq*in?uB)xzGNMQwK7fe^L$=Gj zwjAd^?1ofV@sl0HYU}HGa4%9`cq!?k@Zn8DoATd|TqJRR@X2h&tyN3W=p|5m%EBTbo_gBJ;JgCuZt~} zH%GORQ0kr-9~|fHK&p|vtAiCYJ@o;$m=BA=BoQ1(NL%fynw;xv<7@#r{4uAov-@ol z2%L!n{Bo)*OWWNj*Ez$dZiG|@%1p`1fFZ!<)E}+7fSl`3TsP6d(d;_9WQX2z#(T(; zkF%q>STo6n^EtY{6n->bVpo}6yJPnO5$r1ZbqeLzRmdP#-bsg~o_na_hyw1p;w3u9 zRhGgqOi=zzIL=wmfxFtytr-dglG?#lEOaQRDp_DYg5PUaqUlKbNVgZy<-*$Pli{rc z#xgdWWurO(E<0{VNYv>j*JV*D`fX~rJSb?G^pdv&HSAQI|5#%rp1XNV-*aBewMDPd zyI%2FM-?Y_jV*N>!0GOD5z<`3mGX2b&ke=>-A_i45aRnkKhf$K5YlIw zQ+=m%H6cfL&+@NZwf=7Qw>yup&HUCues!}<=Htm&CE=ZMq1OIJh=AvEq?KL(*Jb8B$3f_gZNQ6>(S`l?JPTg8jZn=Nmu>*Etl5me z8P7icUC|;yJ)#``%HQO0eH|9;z4tqlx|5I06qp$c#9ZrmmN}oXOu7wPcJ)?`o`(ex zkI{85+g8%eICkh#LyV61-(HKh4NV;N+iPwfNfuMisl#KnwrC~0Uspu<5GskroaQDv^U17OKT7x?Ed6l@2U_sP;@2# zeSXiOAaCU8Z!MPU?9n2vMY4Ng<7uL>4_mx!mapjF>b_mzK9;&6$4X`{IRFOrBbRj= z&Ib33xFREk2r?xCJU!q6jxZ*&6|j{i?cXtdSPpul%6LhU3-U>L!$A@LFC3CMT2n9 z!K9-;BdQ-gF(~qm&tBL=I_x;h(~hqup$Nyppep3-lld101|3#&F-ySW~n=FCs;;0*y}wCzF6V~_RogsLlVhGy##cr8JH;G) z=8#|5i5V^c)e+3mMzC##y}64T5*j3n4;K1X@*w?Yl)KO%{hw zK>a(l7rx^u{DdDBBCm*6FZ4+CRxb(To4v1-!_xOV5mS>TQ25epS)l^;{o4;tfW>&e z%+9e&FvA`5uKUZ&fDcYFe^;~t!dT~aR3KsTJhVf$OC>XZY{gK`{a({kU!FUy1K&6@ z#?#PtjYHwLpy)>1e7TS#Vi(lM(v>3-&)(%%1gW-W;1=ct%X{L7`#ICqcP@%F#RvNi zh+l>k?4`XXV-r`Tz>M^Dp6SMVE$yBf3=Tp<7ZuCHhYgw$`{K?Pu*?)fbLGJrtN!$t z+ec>-H|HNkRHOy4Abr~OUOOJIeGnd<-&1^@#NqQdD#*4L;VSE-cw)PC$^2!pVG@m9 z%q6Ld&?Ig0?k{eF96@W$hBm!Z_Cu2m> z&*dt^l^7dj&ul_-0aJHw0*J+TU9bv7(vTdiKuWQhyxX`xML%Ky(<6g(7 zoWg~*$lyw7`tW}*oyC~TJ8eG)VYcKgU@XTGTc+tKpzH6|kpd5Cb5W?K8eltb-k?{} zKR)(f3oD)fK-xYyEaJWXBEnHP;G6NpSTww}^@(M>q~*5xH`s@FErH<<%l@r)NUv8~ zOZy@|3UXAea%ak2nvW<``RWcU(HpJAWC{7hY2%aq}qNemQE-X4Zo7Gbv4x zMa#dpAvwzaWEP|{+O`pAKbp1pcAvZg$sVr2SpL&M2blMRX%b{VPSl!#I{xCrlrr0e zJSd-2x>_jN`svc>eCB#Vy;POd?os*Xi5v(ywq0M2U@7uktaptaU_al%nu!P!dVJH*l%MiUH{F&B`A#?JVZ2gnuom^YHksmNye`e$_p3KT$)f*3Z zKR>vYvduwDA>Jcs)Q<=`K+m7-d&3O2FCJmr*tw5bi1+G?+>1n{;R7cc#EovecbFJ- zNm13e$sQ%6S2!f)d;vYn8@+t*CC@mn{aIYa;|5ZeL%tcI3`fT|1~pX<#@VM5`8n@| zPrO#(Y=!w2VFOp?GvgznFF{{~+d*c2B<>XOJ8konY^-^|iM!^K_YFjERDPH10?cZP zI2sF|#_|+GdzHP%QGbjw&S8Lo2>VwKf@HB&*&w)hv<>8)W!%jR!XA_|QLhlXvUH@^A(XCWrd!``qAs<3a5XR&B5hdz6JztZ^oR_)gAIo6SLZMOWcqrWdDCMTYodnzU zQk$bOkU$o4)E4sNsKUhYZQjDNj%*RXE@?CU4~Cm<0D(t+x&HW(vOZuhgvmFyNPN); zwro=6$$4$9(!_(LUqOi7?8=2sZ+D6Fz6~jX(BP=6l;lI408_Zahpq0``l@4$-FsS{ zMtg(wh{Kux?gg}6tA4%!Ugx-+0l2xxDV}9-X>2<7X2;n2BRg_x7;^PmYz$&OLaj%3 ztfNFnL$!}6v8iji`)zb2J_En9t340Zgbt63FPf#_*HvyNu z`7>ZCl2l~)+IV>zo^4iOevb&(Z9D?sj7wur;~`V5Uiv^Dh!VKgG8e;kPA4sp%2RJH z78gds_H$u%{G0LU>`CA9@lf8IS4oS%ldD&iUx;vJUv+#_Y0dq-^v|o+n(lzTmS`dI zx2Vhw0Be)@0D-2&9hM5ah)Q3?{>{zQd>jT8c{{BGvK4@T5z{5TC} zA;Mv&x2IPedOw%~{*pyyf82+8djzj!Xel-`i{sU!sQgP?)p(qnk6CU*_`hUjsfKxB zT*F>`SN#Rc+L~OB>S{9aqS;mNrr0$KNk<;JG}fnxx}Z*7H^KDcZDCQUoX2eyvKtNR zHp%Zo+(anX&5ewr`r|OdHw@1`mnLP%VutZ7E7VUOdULMstyF`H<%U*k8Zww%&yvkH zquagN@`gfQIwinwU}9VMEww4rB)vFyR7D*Z1K)LA3$Cj0w-42;sT{Pxu}Tz8#FX0J zJ31!Z@YNaGcKNyd@$~Bk6B27m=eTkHDht@zg>qS;Q6lT1cePN8G^U^e$pv6SZ2klzifOKZdWD z5)yrE3AqK!WfOUG?Xmbf;mtqu%&_x_E6-xiFJ?D|kMjT+HQI9?IP0$R{hHQ>Cl z^4>fZR*67eZ^$hc$z~DNB5iWz9NOIyGsTk=Rks#0F4#dz2D!;W9zdQ{h9RK@qz{=k z78bNQo#TNgA3aT1T^T$u^LjTS7`5U2XvWI=<}?HQYM;w38#DS~tmvNdOy+dtDD(&cG)x#d6N-Pt-n zr0i`==IK7dWeB7r1r^)cIlc$QK_9on(9y=)P`qybX!S(|;HW*nO&}2s=1|ukoaifO z?y?xJDtPv4n!dfBUw=W&?o4@I^HH3REqNoOGt0n@%m(hiXS?ref6aFN9>4U7-lTNz z>D&!|_}@|)waxI+2ss0iST66qjO*!^bMZ{R6$W;-_`CcT%G;K?3*1>3XxcQ`&iGry;^r2Xaj;*M3e z^dk$yCY0xbk|~9tIaY?dKf|#1TA7>-is#JJ_fl+Y{fO6|OVy#mZo2D+X0NWnn?;GS zW`D;MOUk>9U6OvukM=b0t5VQ)?aqLJ=rDzc^L^BJ?l!vZ8)}c1hFcskcT;l=e|e7K z)8C{dLGeALyvonKr+K^!bZ!N7%ftg1S;cMDjn#nqsgN`J%JLLK^u>+svEs?xT7m;v z?bO)4V2e@4xzN_$q7*Tm=J0l*n>J+41tTivpY$SzJa%7gLm7?|_u>PS4v943{%fp& zLGreA3!mth>$(%?c}I%S;$=~j^)R3ZR&%KG0VAiwYI)o?k!lo^q41?gztTB)!mv+> z9u(6#cVOz}aU=lkwMpuqTo<))87=T9OBT!@w_W^@?jHarr3ZO?@XxxFvlgBP!^J|E z77`uDYVwjNCvl9+$<}@*`}xHUCW910?FNJ#ups@wc8Hiv$89QJB_``6Me)+|inPii zR|7nC4Brgrb@0f$B93>fxuTI6xf~~Jt`3oKVb(2Rh5`@HK%nZm*scAJpg*16IuK(a zlWh>vMZeVhQJ7?xl3)|E_*a$UViBTb;|(-OWC*XYsS+leS{ z=xRWkJxDV#F!5;cx_yJU$Ff(FQNpQJz=;H3%Mz~|uc8u`;W_StTC%QNYG(TWXkNf+ z*uphzZF3j1vs!Yn;t~K37bV}JllgJ zdj8ouvdE}%mXo~=bMFm5c-KNrMO=2^AE*q}vn8`1h{k>^gjcA3psjI|bM>s;tRgg> zlv*8AvD^^g7eDHsmt#RFak9iSb^iP`Jga&vEBp1DS}Pq^ui>(SZY|Onr{YyI+mWbD zv=zl-_Uld_(6-)Cp79oZMa;g9MV{pEqH*w9l*Ekjd?WbCVSk4I)Gl<#QIv4ig!S>_ zn3S9~I#-{He(f)Ui}%RA0q*_yP?g)ecFlo_<3+~7L+MSYz!c+%C;-H3{3=z~R zNXJp)U0$~$FOw8WQQVIm>J$azVNGnbXb%sucYZyDPxvG5HvQr`gXgA2%`V`B<*SKa zM`!rH8I7*Q4+J~%plzD3ayXj$gBQ99x^yWY4p^*!|D8|RAVao%gv%|893 zz^|fUmG!^tLezo=sU&dcmR-$6lov~2yf=H@oH6hyQRJNYz1d>ic19;9er)k z^vo2|MuY;;Tl?h$EnxRn*5xRsU`$R^&860mSerp2 zS=zxZ?FJjmLl@_+WcFEhOZ6fhh6$0@+*u$n#Jo=MiADnF*Xdfx9(trM$cc|TJo zV)%rfIopd&7>O)Ti%X1jRoM_7piZ$@3_^}QfQg_xHQanZ^ye+n`pptmjxe@Vh^!>% zcrVv|ruF_RnRh=j7g8f37xP2G0by83Oonq-{|WJWMbf}GO-=8tASO*@Q{1mg-DXFN z{`G;M?sZYxBrJg`TS)#Lc-d+7Pg4OpJlE1FL`5NN9wEjYyY^&pE#81^03u&iv2w)H z^Wk$gE0<~A`&(guwtx)Ujh{&;qqHzG`&yst|p zIm~N3@;q72_&s*%sC|a;IkjKmxj4<4#P6mkw+5ZBl|3J2y~^u4ITREtZ#)43C#C`Y z>9rf8#`}eNv0Q8r29gK<8!YSiRST036Mrh%Y;h0aI#As>%UQU86dmJ5c^Xfjp~A=( zWy#J1PNM3Cn)d8?<9RU)A-gFmcdnq$C&m+!LcM2Fe?L^}U*6cLs^1bMx6kw>@UIhE z>Z57F2%ElCeB>SCh45wrnop$QWK$&~n%`WfxNR|h-OL1)h9;8-LKmdw^*h<(0BH86 z9Ul4V0KB2W5Apt@KV+7v==9m2M4E;db}#%5_VYmc%UahRK7KO=SDc$TXgzr#h{bTF z7uR~7yD2Y&ilh5l;n_6y*D6++xWLU`T9da>tMWRAq^(H@Ld-JZjzb5} z6;bSIJ)LefpQMJwc2LgCDQj0e0;4j1zt4XA8QO9-GNkYG9W`~LBSt%_!EV(&_K`8+ zx0*~7-lP_MZlONYR!Qp*TK@qgX4deX3u>`lI^edL+!w!FV||aPq+j@u z{PeKa8MS7S;oFYo(m_62w3l7+Ihe<>r2(}Hu^Nc%sg!>9wgw=;Tnlnr{5o$+&+&%D z9-RSJ$&w?z832+r?hnZP&3WY=yf(N zFuVq~jqL!L&q>aEGbYY(h1>2!B6-Jz>El`GL|qERYQ!w@F^WI~Z@LlKbI2W9#pDg% z*%(UzJtQ|i&M~C$JWmj7pWmO$d1?GZBm#bX^yIRRW1gih8TS*bBF|1BjY2$)2Yycp z0Q8EnM@%r5me(l8a*W%1icF`)XnL|DPpM@hJ_0%@{2kbtloXl)%}mqEo<)ASJt`E2 z&F04Z4H1b36Yh5Q399?bxPdrZwn zK7y3KqTJX&rQ2o}zEi&#F_Alvyx&s+acYBws|*?s6zhYJVs1fZ>u@MEwd&_6=5OA8 zBj4i8yqPS;d;9c!wjS`E>vJOvwnEWe zkJfO#8<|0YpDEN#mCog&b1oa$j=tSGwYp&z>~2Q-#7e^4fPI|JLWbcY!DG>qRG)2o z5&eq;o-_`N^|JfSG6`GgMi`0X`MLi2M0md>>@+6nb?koE17VhhL6B+Jvu$C%B@xM6 zSFVs!Ug`pzj=xi;xuQE)(Yj);)d7?wBz&(x>m0tXp2J9)<3wBw1}=q&$i6)Y>7NsT z+~ZudkH29tSsvJ9U0lBz^)SEj!*bVSIS2i_a$M7{7ygl4A&HB> ziJwZ-rwThxZ33-f-Pg$wJ<8UFZ$qy2D=3`)#h$s)U~FmiSZoO=+8|5eQ?zinA`R>z zJzqiFyiC>IV7Iqdmg@qf5!65`6YW$k8jRo7*P;Hdvo{OUvvdxp7vnYtNp>QD%>+=| zt>Kql zp*kMSrK|$RY|Rm#HqbQ&G*3QL})X4xS6$@ML5v^C(#B9&)! zVAGarlb0XJUi+NAhD{Xz_~Eo1>-4)?{`8Y{jFHjph3hw%9T;Ro4sOAIIYbn#&rHLR zOh5dyV|LZ^`rV(~PWo34xyFj|B*Pn!m6z7maV#F&6OD;TSu@p2k-Nj4K+l{K0-t-V zTF~yC91T1xg#qgp-5=Wa_0z0_YswkSBajPB&Pdi>DiJ5=_SyRcQL=jW8&>OgQP(k_ zN|%V(?pc>LNE?q*VWV-xn7}4geXg^quVSdjyhQ#Kxs4oR)lnF^g+L=CUn6C`wR=nr z84>gKYvRn684R_q>*b=V)ohmkdp8P|kn}`d(ov#UJau2xKP(`+G0rDxIT$0F7ROU$ zZ4<>n60vnjtYP*=T=gyva%O9V{W-!K(e>z*K(XyQbe+AJTSit&nk*Tlj5~v;Pa$W5 z-RNg#P!NaM1_YUORAHoP9ljK%nxy(+%{&YjecB3#1DiszwaXVDFt z#_>}ZA%2R~9!}~QJW*(T!5>c5MT36GoddeDo#K&(hFr6pz53EWJfNlKa4l{BRM|#% zIR|7MsZPVUHK|K|QsboeI!qQf5#8vJ@=SZnommbQm!=dzXrY#wv@`_}Q&W@ghoe1J zxHaJh3!mgx3KRI9yzKySQ`X?3pw@54Z&!E5?mf;!krT3*W>A!_Xhz3BzTd6-l11^Q zJEH~dN*Iu@mU^Q)!c)7rC+#Tj=~&nTsnSKH3Hc6zUM*l6mcPTGHWTW#;v#LH-;k?CaF$m08M! z5BwS3PL-}20Qh6JXKd4oZ%Gk_YnQRbBp(sR-W;C2;`SGUv?%J2FkX;k zg=12VkjD<_O51IY$X96=Po<1SQF4Fx2pkaeI{R4!o#u?>Pzh3`N4k8uH0wBZ`A7)W z)F{2P(J?#xq_#xx24f^^gtZM#i+4noX$Tz8hc4;BI_@m#@tgH%9>ol6+ka;SKeFUf zzI`K9;w)N5mkF(}ZSaC{Ou4c`Il3GlB2rXcbg3b-q+>+!qT8aGTg{pl`G-gE-)0J# zO!aisHI6yZ>^GE|hM*HReD8|>A>`*(2E@d`Tab7X%(4q|jG*1L0w+=50yM(&`NGf@ zHIID?+0NZ^0tEfgoE;h)@|&H+>09)C+WBr{%}yGS24EM%=%$nS$qNujP^J{sKEvpw zzy8^+@y!jCymi#+pKH5hnW&lrNvae)wxq~}epY%Y%~fGDQ0g*E!`B%9^iGRS2eWP1 zQbvjT`w=dChlEc&lq^kd7q4hp!bU}{`ozM&3)+5=VG}Lu)X09z+Ia$aNJ%Qh^>ejZ zGSMU&ZTxuk6-Q(ANfHA7g5+_2z|pCg9rV_NE=ot$dy8DUv9jW(->XQsIlW)ex(YCr zRmnZ~oGnMo(E|4+?86!ffawA>muL$HyUWd&XeqDZ{LgP|Y{i4yK-S_XDyyouEg6WU z;ZY`bhC79h+edA(G{#v+C(C&)Z-d>|T`$fM+q1K0*xAvdKnltuO!ww_+yWKof0pDB zn1W~X$kho^!4{p{-c#*!fK#+1i2f~DD%=#jCM*0J{(D9!n(Ij_hz&vmEWY6sohGO^ z$@`I6TN*u%y{@{koHsbukH_)f`9GpM%Yg;=leLmZ0boGSLMt0U|1He7`OpZ6;=J0D4?PM62No6bA0x;QK@^1bMPjfiKEfYaPx zsBXk>@o-PHI-4yP)fb_xsRnv2+@#z0K{0=)Zh^$tm4Gms$Q!;KD5|{9azn6-La_7d zpT|{_cT)Hj@L4G8U8)l?qhr}4lZV#f&x<97EGvt&WPAml#4m)5@qR}9=Qs*~Wx4^! zu`JhoopnO$cG~!gmr>Gs^kc=BZR8?1Ga1NiQy{z9<(H?On1$wXa`B^VkTITrR1A>G z10RtAa;nMr-_PyW#`KF_W=Uy4Pew%<0ZIDzX8c+=4<-6;BI=IaW9;cqi-A|rl>_Rb z1~2$fvHk_)LE`&&bfbd?_ZNX!p&IvXEw1>_VPdfL&C%3*|2ee$|CL{-ZuyURI;pIJ z|DR9yzwvzkucz}-(}QyUnKl>{)4kReatqq}cOm}$SyroGNY#DUs7>#m!GlbuFK5HH z(yNgz|M%|>Wo0zm@cr)~06I&GgI+Z~q`@fFUp4ffPaGttW}Jnl|4cWO>hfzyxYZy6 zT^Z)ULHPgmdf%OEe*AFXf7?*&HqayRufxAkn9$aVDJk7iD|4|Niz! z!NfBE$r!93WIy9shL;&i4*ti#5QCZu2?=@Tsp`IF{*6PfqIU^zy9|S zbrluIrPYB&33Qdc&+rA;;?2ZF{WHpcoxSA=PZNq-O{#vqCt*mR8tNGTua_|@DEeU~ zDSp<{m8+qyu6Ne>uXp#s_tHTrY_*h2Kge?Mj2_nqrv2w%%dMwbpX#jV{yx+I2-Ocp z7u44OytG*&zQ2FpTil8524GezP9I(1bi4jBazU~$f8f+PeNr|AM8qrrwn|-1Ek5nv zBS`G^^q^$PLot=zLKBfa;f(8>{nsyaVs@-f)t$P~Fa3Y~SZS=fIII8X8AjTiH)KOt zi*J#)B=F~WTVI^~dvspqR)7?2CnXyr|I z3%}#JuDARn-nEne9FnuS_XXMZS@9_9BW^ZU^S;#c#!c`AP&|}qAP4V%J|Y>v07VD* z(_IXfTb5mnWj(66OG78@kgk}o{_K3lZt248qU>MgW;un`t8?3R?LefR?QEf|z*g^~ ztcVo*6Zp+j1y`D*v1pEe7FU*Ig0;dj^!@wyJ_4-DrFUuiu$+eyUZ*%5Cnx7lE|C5$ z&>QxT6PImqI$e0ff3(m>QfAZ9gYHcdnzebGyF?E%1WKcNyZJMTG3V3Xd$pPPr<|NM z8frS5CXMD>G_aX}9waZhDEGMxw_bt4WGOusr%1^iFYxv2*KVLTC=&QM;r~iH{f*H5 z{yzf(d=XiCdU5s2m5YmMOlrlID_3q@J|YubQ9l`J_0y074EL{Gk$a;gRrJch@BaWG CeEG)! literal 175950 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

RNndugS^JjEnmOd`esitvytOnBQ_hYPs7xE> z3sCXc1ac);uFYh+_#MwG3I?|eT}WKZ!c|5sUgXp>O6zB zlroF$H7)j%t{BT}ZQa8+*3W_bJSD{EzoCwHhZ^L&Eoe6pPR%&4&gKFZx40;@CM(y; z>R9d%TKbRy0Y2@Pg2zr4g{xXQZ`|Y);0>r~A67Y+rdwZuTs+gI5yf7q`@l@8%9;5& zn~1;-P||^vp_l&e#0?6@VM<1kcY`}&WYj8nD<@4b3534JOeCBWQfa}pZk>hC~a)eccZ6tejxL-K7OO|$~ z@1D9HQG83Lm#X<+G~KpVj!cfk*7gqwCI8F3GouVw?s)bUUnv#9Ik|m(&m3+=^OsdW zX#Xx%@7;3mPqThRNivDaz0|~|m}|>neN~!}pEvo! zdEv0+Vk}>4VP~O1W4Mxs>J9Z*h6@(snaQlU0h0#nZq6=krY?8~p*Z{;vv88 z4Qnvt<23ct_lJVoDYH_@pX*;A-J213H7>!g`JZE%qLy55;QRdMWK|=W2)1=PM^`IY z-?V#kle@x}0yI6H;}Lo6i6A$8?w85S~b!&5OGwFz`&OImL0F@yxvC1vs z;n?|b6d9kuN8Sgh+0I8P_w`mwt&PC2`bddMbo)*RRc(|�Y1#3Z9!r>>G=N_i--0 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 literal 102550 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

qZ*ABK}7{#a~pRst7zfciSZn>+1gOk{k(O$ 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

(B?U;{jF0ymC|9C&#Ua>v}&+ku82RlXb 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"m6 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�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 Date: Thu, 15 Oct 2026 12:26:38 +0530 Subject: [PATCH 38/39] docs(findings): record the served adapter-scale run --- docs/FINDINGS.md | 2 + docs/STATUS.md | 2 +- docs/charts/lev-vs-jev.html | 6 +- docs/charts/logs/lev-s1bench-2026-10-15.txt | 356 ++++++++++++++++++++ 4 files changed, 362 insertions(+), 4 deletions(-) create mode 100644 docs/charts/logs/lev-s1bench-2026-10-15.txt diff --git a/docs/FINDINGS.md b/docs/FINDINGS.md index a9c2d35..7ff0b05 100644 --- a/docs/FINDINGS.md +++ b/docs/FINDINGS.md @@ -709,6 +709,8 @@ Choosing the scale on the same 13 subsets we report is fitting the benchmark, wh **Leave-one-family-out over S1Bench can.** The 13 subsets share task families with training but no datasets. Grouping them into 7 families — safety, qa-bool, nli, paraphrase, intent, summeval, rating — and scoring each family at the scale chosen on the *other* six gives a macro of **0.7282**, against 0.6892 shipped and 0.7610 for Jev. Six of seven families pick 0.25 independently; only summeval picks 0.5, because summeval-consistency is the one subset that prefers a weak adapter (0.8264 frozen, 0.2708 at full strength) and the remaining subsets cannot see that when it is held out. The estimate is robust to the grouping: merging helpsteer2 into summeval, splitting vitaminc off NLI, and leave-one-*subset*-out give 0.7447, 0.7282 and 0.7447. +**Measured end to end, 2026-10-15.** With the scale and refit temperatures shipped in `releases/lev` and served by `make deploy NAME=lev`, `levbench` over HTTP scores macro **0.743**, from 0.689, and mean ECE 0.097, from 0.115, against Jev's 0.761 and 0.091 (`docs/charts/logs/lev-s1bench-2026-10-15.txt`). That is the selected scale scored on the subsets that selected it, so it sits above the 0.728 held-out estimate, as it should. summeval-consistency carries most of the gain, 0.271 to 0.806, and the worst calibration: ECE 0.303, under-confident, with accuracy 0.89–0.94 in the 0.4–0.7 confidence bins. The temperatures were refit on the calibration split, which contains no summeval rows. + **This needs no retraining.** The scale is a serving-time multiplier on weights we already ship. **Limits.** The grid is coarse — 0, 0.25, 0.5, 0.75, 1.0 — and the optimum sits at its low end next to 0.25, so a finer sweep may do better; it would have to be selected under the same leave-one-out discipline to stay quotable. Accuracy is an argmax and so is invariant to temperature, which is why these numbers hold even though the shipped temperatures were fitted at scale 1.0; every *calibration* figure at any other scale requires a refit, which is what `fit_at_adapter_scale` in `modal/app.py` does. Per-subset n runs from 144 (summeval-consistency) to 599 (vitaminc-dev), so a single-subset move under about 6 points is noise at the small end and about 3 at the large end; the macro, pooled over all 13, is tighter than either. Closing the gap to Jev takes 3.3 points more than this buys. diff --git a/docs/STATUS.md b/docs/STATUS.md index d565a44..ffbb300 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -23,4 +23,4 @@ What is built, and how far each part has been exercised. | Mode B head | **trains and serves**; weak unseen-taxonomy transfer measured on massive-en-US ([FINDINGS §12](FINDINGS.md#12-first-head-to-head-on-s1bench-two-named-failure-modes)) | | `lev.load`, release packaging, Hub publishing | **done**; the release loads through both `lev.load` and the server on an H100 (`check_release`) | -Three checkpoints have been trained, calibrated and scored on S1Bench against Jev through identical task files: 0.489, then 0.697, then **0.725** macro against Jev's 0.754 on the earlier six-subset definitions. The released checkpoint scores **0.689** against Jev's 0.761 on all 13 subsets as S1Bench pins them. What each run changed and why is in [FINDINGS §12–17](FINDINGS.md); the reader bug that corrupted the labels of one intermediate run is [ADR-024](DECISIONS.md#adr-024--the-mixture-reader-merged-shuffled-questions-and-the-instruct-run-trained-on-it). +Three checkpoints have been trained, calibrated and scored on S1Bench against Jev through identical task files: 0.489, then 0.697, then **0.725** macro against Jev's 0.754 on the earlier six-subset definitions. The released checkpoint scores **0.743** against Jev's 0.761 on all 13 subsets as S1Bench pins them, with its adapter at a quarter of its trained strength ([FINDINGS §19](FINDINGS.md#19-the-adapter-scale-is-an-out-of-distribution-knob-and-it-is-worth-39-macro-points)); at full strength it scored 0.689. What each run changed and why is in [FINDINGS §12–17](FINDINGS.md); the reader bug that corrupted the labels of one intermediate run is [ADR-024](DECISIONS.md#adr-024--the-mixture-reader-merged-shuffled-questions-and-the-instruct-run-trained-on-it). diff --git a/docs/charts/lev-vs-jev.html b/docs/charts/lev-vs-jev.html index 3eea664..751d8e2 100644 --- a/docs/charts/lev-vs-jev.html +++ b/docs/charts/lev-vs-jev.html @@ -51,9 +51,9 @@

lev: a 4B open System One model, against Jev and the open field

Qwen3.5-4B with a LoRA adapter, a candidate-path head and fitted temperatures. Scored on the same S1Bench task files as TypeSafe's Jev, and placed against every model on the public S1Bench board.

-
Accuracy
68.9%lev
76.1%Jev
macro, all 13 subsets · higher is better
Accuracy, board subsets
71.9%lev
76.9%Jev
macro, the 6 the board completed
Calibration error
0.115lev
0.091Jev
mean ECE, 13 subsets · lower is better
-
Where lev stands

Behind only Jev and 3 open models of 26B and up

Macro accuracy over the six S1Bench subsets that every listed model completed.

levJevopen models on the S1Bench board
20%30%40%50%60%70%80%Jev (board)77.5%TypeSafe API · ECE 0.076Jev (measured here)76.9%TypeSafe API · ECE 0.090simplejev-qwen38-27b75.8%27B · ECE 0.121djev-full74.9%26B · ECE 0.166simplejev-qwen36-35b-a3b74.4%35B · ECE 0.136lev (measured here)71.9%4B · ECE 0.123reflex-4b71.9%4B · ECE 0.085decider-2b †70.3%2B · ECE 0.114laya-gpu62.5%421M · ECE 0.130laya62.5%421M · ECE 0.132jeff56.1%400M · ECE 0.075jeff-gpu-full55.9%400M · ECE 0.074qwen3-8b-full53.5%8B · ECE 0.425open-jev-deberta †52.4%435M · ECE 0.067reflex-08b51.6%800M · ECE 0.243kev-05b †49.3%500M · ECE 0.149gliner-base43.2%194M · ECE 0.316gliner-multi42.6%287M · ECE 0.181gliner-small40.0%74M · ECE 0.224simplejev-rwkv-mid38.0%size n/a · ECE 0.298simplejev-rwkv-std32.7%size n/a · ECE 0.282simplejev-rwkv-small31.3%size n/a · ECE 0.279

Board models were scored by S1Bench's own harness, lev by ours, on the same pinned items. On the same model our harness scores Jev 0.6 points lower than the board, all of it on aegis2. † self-declared training contamination on an evaluation subset. Models stopped after one subset are omitted. Gemini, Claude and GPT have not been run on these subsets, so they are not shown.

Data
modelmacro accuracysizeECE
Jev (board)77.5%TypeSafe API0.076
Jev (measured here)76.9%TypeSafe API0.090
simplejev-qwen38-27b75.8%27B0.121
djev-full74.9%26B0.166
simplejev-qwen36-35b-a3b74.4%35B0.136
lev (measured here)71.9%4B0.123
reflex-4b71.9%4B0.085
decider-2b †70.3%2B0.114
laya-gpu62.5%421M0.130
laya62.5%421M0.132
jeff56.1%400M0.075
jeff-gpu-full55.9%400M0.074
qwen3-8b-full53.5%8B0.425
open-jev-deberta †52.4%435M0.067
reflex-08b51.6%800M0.243
kev-05b †49.3%500M0.149
gliner-base43.2%194M0.316
gliner-multi42.6%287M0.181
gliner-small40.0%74M0.224
simplejev-rwkv-mid38.0%size n/a0.298
simplejev-rwkv-std32.7%size n/a0.282
simplejev-rwkv-small31.3%size n/a0.279
Accuracy and calibration

Further right is more accurate; lower is better calibrated

Macro accuracy against calibration error (ECE). The ideal model sits in the bottom-right corner.

30.0%40.0%50.0%60.0%70.0%80.0%0.000.100.200.300.40macro accuracyECEsimplejev-qwen38-27bdjev-fullreflex-4bdecider-2blaya-gpujeff-gpu-fullqwen3-8b-fullopen-jev-debertaJevlev

lev's point uses our harness for both axes; the others use the board's.

Data
modelmacro accuracyECE
Jev77.5%0.076
simplejev-qwen38-27b75.8%0.121
djev-full74.9%0.166
simplejev-qwen36-35b-a3b74.4%0.136
lev71.9%0.123
reflex-4b71.9%0.085
decider-2b70.3%0.114
laya-gpu62.5%0.130
laya62.5%0.132
jeff56.1%0.075
jeff-gpu-full55.9%0.074
qwen3-8b-full53.5%0.425
open-jev-deberta52.4%0.067
reflex-08b51.6%0.243
kev-05b49.3%0.149
gliner-base43.2%0.316
gliner-multi42.6%0.181
gliner-small40.0%0.224
simplejev-rwkv-mid38.0%0.298
simplejev-rwkv-std32.7%0.282
simplejev-rwkv-small31.3%0.279
Accuracy per parameter

lev matches open models six times its size

Macro accuracy against parameter count, log scale. Jev's size is not published, so it is drawn as a line.

100M300M1B3B10B30B30.0%40.0%50.0%60.0%70.0%80.0%parametersmacro accuracyJev (board) 77.5%simplejev-qwen38-27breflex-4bdecider-2blaya-gpujeff-gpu-fullqwen3-8b-fullopen-jev-debertalev
Data
modelparametersmacro accuracy
gliner-small0.074B40.0%
gliner-base0.194B43.2%
gliner-multi0.287B42.6%
jeff0.4B56.1%
jeff-gpu-full0.4B55.9%
laya-gpu0.421B62.5%
laya0.421B62.5%
open-jev-deberta0.435B52.4%
kev-05b0.5B49.3%
reflex-08b0.8B51.6%
decider-2b2B70.3%
reflex-4b4B71.9%
lev4B71.9%
qwen3-8b-full8B53.5%
djev-full26B74.9%
simplejev-qwen38-27b27B75.8%
simplejev-qwen36-35b-a3b35B74.4%
Head to head

Accuracy by subset

lev and Jev on all 13 S1Bench subsets (3,880 task items), same harness, same laptop.

levJev
0.0%25.0%50.0%75.0%100.0%vitaminc-dev66.8%80.1%massive-en-US85.7%87.4%massive-de-DE82.3%87.1%boolq82.7%89.3%squad281.3%83.6%paws77.6%90.0%multinli89.0%83.6%civil_comments76.0%80.3%aegis280.0%80.4%helpsteer238.6%34.1%summeval-relevance35.8%35.8%summeval-consistency27.1%81.2%pubmedqa73.2%76.4%

At these sizes a per-subset difference needs roughly 5–9 points to clear sampling noise. On civil_comments, helpsteer2 and both summeval subsets, always answering the most common label beats both models.

Data
subsetnlevJevlev − Jevmajority label
vitaminc-dev59966.8%80.1%-13.3 pts50.3%
massive-en-US35085.7%87.4%-1.7 pts16.3%
massive-de-DE35082.3%87.1%-4.8 pts16.3%
boolq30082.7%89.3%-6.6 pts58.0%
squad229981.3%83.6%-2.3 pts50.2%
paws25077.6%90.0%-12.4 pts51.6%
multinli29989.0%83.6%+5.4 pts36.1%
civil_comments30076.0%80.3%-4.3 pts89.3%
aegis225080.0%80.4%-0.4 pts56.8%
helpsteer224938.6%34.1%+4.5 pts42.2%
summeval-relevance24035.8%35.8%+0.0 pts45.8%
summeval-consistency14427.1%81.2%-54.1 pts84.0%
pubmedqa25073.2%76.4%-3.2 pts53.2%
Head to head

Calibration error by subset

The gap between stated confidence and observed accuracy. Lower is better; 0 is perfect.

levJev
0.0000.1000.2000.300vitaminc-dev0.1410.099massive-en-US0.0560.071massive-de-DE0.0670.059boolq0.1260.035squad20.1030.036paws0.1780.028multinli0.0370.057civil_comments0.1180.044aegis20.1340.050helpsteer20.1040.258summeval-relevance0.1360.230summeval-consistency0.1740.086pubmedqa0.1210.136
Data
subsetlev ECEJev ECElev log-lossJev log-loss
vitaminc-dev0.1410.0990.8831.571
massive-en-US0.0560.0710.6231.377
massive-de-DE0.0670.0590.6671.218
boolq0.1260.0350.4930.281
squad20.1030.0360.4850.347
paws0.1780.0280.7360.293
multinli0.0370.0570.3160.462
civil_comments0.1180.0440.6060.444
aegis20.1340.0500.5800.414
helpsteer20.1040.2581.3864.672
summeval-relevance0.1360.2301.4451.841
summeval-consistency0.1740.0861.5031.446
pubmedqa0.1210.1360.6951.600
Progress

From 48.9% to 72.5% across four iterations

lev's macro accuracy per model iteration, against Jev and the frozen backbone it was trained from. Measured on the six subsets as this repo defined them before adopting S1Bench's pinned items, so the scale differs from the charts above.

40%50%60%70%80%run 1Base, 9 sourcesrun 2instruct, 23 srcrun 2+ Mode A to limitrun 3chat, 29 sourcesfinalserving fixesJev 75.4%frozen 4B 71.0%48.9%61.2%69.7%72.5%72.5%
Data
iterationmacro accuracyrecorded in
run 1 Base, 9 sources48.9%FINDINGS §12
run 2 instruct, 23 src61.2%FINDINGS §15
run 2 + Mode A to limit69.7%FINDINGS §15, ADR-025
run 3 chat, 29 sources72.5%FINDINGS §16
final, serving fixes72.5%logs/pre-nimble/lev-s1bench-final.txt
Speed

lev compute per call: 169 ms → 69 ms

Inside the container on one H100, before any network. lev only; Jev's internals are not observable.

0 ms50 ms100 ms150 ms200 msprefill + fork (original)169 msprefill + fork, conv kernel140 mssingle batched forward81 mssingle + conv kernel (served)69 ms

Benchmark throughput rose from 1.02 to 6.36 items/s (new path, concurrency 4); a question costs the same whether a request asks one or eight.

Data
engine pathms per call
prefill + fork (original)169
prefill + fork, conv kernel140
single batched forward81
single + conv kernel (served)69
-
Sources: lev: logs/lev-s1bench-2026-09-24.txt (Qwen/Qwen3.5-4B) · Jev: logs/jev-s1bench-2026-09-24.txt · board: data/s1bench-snapshot.json (build 468a014bc5) · iterations and speed: history.json
+
Accuracy
74.3%lev
76.1%Jev
macro, all 13 subsets · higher is better
Accuracy, board subsets
74.8%lev
76.9%Jev
macro, the 6 the board completed
Calibration error
0.097lev
0.091Jev
mean ECE, 13 subsets · lower is better
+
Where lev stands

Behind only Jev and 2 open models of 26B and up

Macro accuracy over the six S1Bench subsets that every listed model completed.

levJevopen models on the S1Bench board
20%30%40%50%60%70%80%Jev (board)77.5%TypeSafe API · ECE 0.076Jev (measured here)76.9%TypeSafe API · ECE 0.090simplejev-qwen38-27b75.8%27B · ECE 0.121djev-full74.9%26B · ECE 0.166lev (measured here)74.8%4B · ECE 0.091simplejev-qwen36-35b-a3b74.4%35B · ECE 0.136reflex-4b71.9%4B · ECE 0.085decider-2b †70.3%2B · ECE 0.114laya-gpu62.5%421M · ECE 0.130laya62.5%421M · ECE 0.132jeff56.1%400M · ECE 0.075jeff-gpu-full55.9%400M · ECE 0.074qwen3-8b-full53.5%8B · ECE 0.425open-jev-deberta †52.4%435M · ECE 0.067reflex-08b51.6%800M · ECE 0.243kev-05b †49.3%500M · ECE 0.149gliner-base43.2%194M · ECE 0.316gliner-multi42.6%287M · ECE 0.181gliner-small40.0%74M · ECE 0.224simplejev-rwkv-mid38.0%size n/a · ECE 0.298simplejev-rwkv-std32.7%size n/a · ECE 0.282simplejev-rwkv-small31.3%size n/a · ECE 0.279

Board models were scored by S1Bench's own harness, lev by ours, on the same pinned items. On the same model our harness scores Jev 0.6 points lower than the board, all of it on aegis2. † self-declared training contamination on an evaluation subset. Models stopped after one subset are omitted. Gemini, Claude and GPT have not been run on these subsets, so they are not shown.

Data
modelmacro accuracysizeECE
Jev (board)77.5%TypeSafe API0.076
Jev (measured here)76.9%TypeSafe API0.090
simplejev-qwen38-27b75.8%27B0.121
djev-full74.9%26B0.166
lev (measured here)74.8%4B0.091
simplejev-qwen36-35b-a3b74.4%35B0.136
reflex-4b71.9%4B0.085
decider-2b †70.3%2B0.114
laya-gpu62.5%421M0.130
laya62.5%421M0.132
jeff56.1%400M0.075
jeff-gpu-full55.9%400M0.074
qwen3-8b-full53.5%8B0.425
open-jev-deberta †52.4%435M0.067
reflex-08b51.6%800M0.243
kev-05b †49.3%500M0.149
gliner-base43.2%194M0.316
gliner-multi42.6%287M0.181
gliner-small40.0%74M0.224
simplejev-rwkv-mid38.0%size n/a0.298
simplejev-rwkv-std32.7%size n/a0.282
simplejev-rwkv-small31.3%size n/a0.279
Accuracy and calibration

Further right is more accurate; lower is better calibrated

Macro accuracy against calibration error (ECE). The ideal model sits in the bottom-right corner.

30.0%40.0%50.0%60.0%70.0%80.0%0.000.100.200.300.40macro accuracyECEsimplejev-qwen38-27bdjev-fullreflex-4bdecider-2blaya-gpujeff-gpu-fullqwen3-8b-fullopen-jev-debertaJevlev

lev's point uses our harness for both axes; the others use the board's.

Data
modelmacro accuracyECE
Jev77.5%0.076
simplejev-qwen38-27b75.8%0.121
djev-full74.9%0.166
lev74.8%0.091
simplejev-qwen36-35b-a3b74.4%0.136
reflex-4b71.9%0.085
decider-2b70.3%0.114
laya-gpu62.5%0.130
laya62.5%0.132
jeff56.1%0.075
jeff-gpu-full55.9%0.074
qwen3-8b-full53.5%0.425
open-jev-deberta52.4%0.067
reflex-08b51.6%0.243
kev-05b49.3%0.149
gliner-base43.2%0.316
gliner-multi42.6%0.181
gliner-small40.0%0.224
simplejev-rwkv-mid38.0%0.298
simplejev-rwkv-std32.7%0.282
simplejev-rwkv-small31.3%0.279
Accuracy per parameter

lev matches open models six times its size

Macro accuracy against parameter count, log scale. Jev's size is not published, so it is drawn as a line.

100M300M1B3B10B30B30.0%40.0%50.0%60.0%70.0%80.0%parametersmacro accuracyJev (board) 77.5%simplejev-qwen38-27breflex-4bdecider-2blaya-gpujeff-gpu-fullqwen3-8b-fullopen-jev-debertalev
Data
modelparametersmacro accuracy
gliner-small0.074B40.0%
gliner-base0.194B43.2%
gliner-multi0.287B42.6%
jeff0.4B56.1%
jeff-gpu-full0.4B55.9%
laya-gpu0.421B62.5%
laya0.421B62.5%
open-jev-deberta0.435B52.4%
kev-05b0.5B49.3%
reflex-08b0.8B51.6%
decider-2b2B70.3%
reflex-4b4B71.9%
lev4B74.8%
qwen3-8b-full8B53.5%
djev-full26B74.9%
simplejev-qwen38-27b27B75.8%
simplejev-qwen36-35b-a3b35B74.4%
Head to head

Accuracy by subset

lev and Jev on all 13 S1Bench subsets (3,880 task items), same harness, same laptop.

levJev
0.0%25.0%50.0%75.0%100.0%vitaminc-dev72.6%80.1%massive-en-US86.9%87.4%massive-de-DE82.9%87.1%boolq85.3%89.3%squad281.9%83.6%paws84.4%90.0%multinli84.9%83.6%civil_comments78.3%80.3%aegis283.6%80.4%helpsteer236.1%34.1%summeval-relevance37.1%35.8%summeval-consistency80.6%81.2%pubmedqa71.6%76.4%

At these sizes a per-subset difference needs roughly 5–9 points to clear sampling noise. On civil_comments, helpsteer2 and both summeval subsets, always answering the most common label beats both models.

Data
subsetnlevJevlev − Jevmajority label
vitaminc-dev59972.6%80.1%-7.5 pts50.3%
massive-en-US35086.9%87.4%-0.5 pts16.3%
massive-de-DE35082.9%87.1%-4.2 pts16.3%
boolq30085.3%89.3%-4.0 pts58.0%
squad229981.9%83.6%-1.7 pts50.2%
paws25084.4%90.0%-5.6 pts51.6%
multinli29984.9%83.6%+1.3 pts36.1%
civil_comments30078.3%80.3%-2.0 pts89.3%
aegis225083.6%80.4%+3.2 pts56.8%
helpsteer224936.1%34.1%+2.0 pts42.2%
summeval-relevance24037.1%35.8%+1.3 pts45.8%
summeval-consistency14480.6%81.2%-0.6 pts84.0%
pubmedqa25071.6%76.4%-4.8 pts53.2%
Head to head

Calibration error by subset

The gap between stated confidence and observed accuracy. Lower is better; 0 is perfect.

levJev
0.0000.1000.2000.300vitaminc-dev0.1070.099massive-en-US0.0440.071massive-de-DE0.0520.059boolq0.0600.035squad20.0660.036paws0.1120.028multinli0.0470.057civil_comments0.0790.044aegis20.1110.050helpsteer20.1140.258summeval-relevance0.0550.230summeval-consistency0.3030.086pubmedqa0.1050.136
Data
subsetlev ECEJev ECElev log-lossJev log-loss
vitaminc-dev0.1070.0990.7321.571
massive-en-US0.0440.0710.5531.377
massive-de-DE0.0520.0590.6351.218
boolq0.0600.0350.3800.281
squad20.0660.0360.4340.347
paws0.1120.0280.5140.293
multinli0.0470.0570.3820.462
civil_comments0.0790.0440.4820.444
aegis20.1110.0500.5030.414
helpsteer20.1140.2581.4334.672
summeval-relevance0.0550.2301.3431.841
summeval-consistency0.3030.0860.8471.446
pubmedqa0.1050.1360.6681.600
Progress

From 48.9% to 72.5% across four iterations

lev's macro accuracy per model iteration, against Jev and the frozen backbone it was trained from. Measured on the six subsets as this repo defined them before adopting S1Bench's pinned items, so the scale differs from the charts above.

40%50%60%70%80%run 1Base, 9 sourcesrun 2instruct, 23 srcrun 2+ Mode A to limitrun 3chat, 29 sourcesfinalserving fixesJev 75.4%frozen 4B 71.0%48.9%61.2%69.7%72.5%72.5%
Data
iterationmacro accuracyrecorded in
run 1 Base, 9 sources48.9%FINDINGS §12
run 2 instruct, 23 src61.2%FINDINGS §15
run 2 + Mode A to limit69.7%FINDINGS §15, ADR-025
run 3 chat, 29 sources72.5%FINDINGS §16
final, serving fixes72.5%logs/pre-nimble/lev-s1bench-final.txt
Speed

lev compute per call: 169 ms → 69 ms

Inside the container on one H100, before any network. lev only; Jev's internals are not observable.

0 ms50 ms100 ms150 ms200 msprefill + fork (original)169 msprefill + fork, conv kernel140 mssingle batched forward81 mssingle + conv kernel (served)69 ms

Benchmark throughput rose from 1.02 to 6.36 items/s (new path, concurrency 4); a question costs the same whether a request asks one or eight.

Data
engine pathms per call
prefill + fork (original)169
prefill + fork, conv kernel140
single batched forward81
single + conv kernel (served)69
+
Sources: lev: logs/lev-s1bench-2026-10-15.txt (Qwen/Qwen3.5-4B) · Jev: logs/jev-s1bench-2026-09-24.txt · board: data/s1bench-snapshot.json (build 468a014bc5) · iterations and speed: history.json

3u3(9)UwTHfm+}aCws^|V8MxB72oDXP}L!xiWmNbgBGV_lA*!#v2 zPbya|Vvi(C18g%Sgif7y@idwTAQRV~uK zE#%@q#WcUH`!3s>)FRM3ZJV=GiOYUU9X};EBWc1+G z-fEp?&m+0iz(b_)&tD#GRI=r}C>nRB8iD)a5`LTJ=$b$O4x?w1fbon2fU-E4o##s8|jK5VVep9bz>%itsg4V}A^OwzV9O6njg zsMrmSKE&B>zl0Urr{dgKOev*+Mht87`#HP-=tN%?;Z1}|vq9jr5I%GXFqg}RY~COF zIa>Jcc%$ZHC~7c6TJ#e{7fg2!pim%qoRX!yjE(N@N)uj2=U||%f&fIs1bMUS_9D5n zgZs9QSNl^`m=LIs*a2vjgZa_AtrC;IXX$&@4b2%b=>GgV!4y zyo$rDuYi2Nh|~Q&lSDI?8zbbMPdbWF@~8KH9{b{FyA6i=oZl0XbcWE1kZ;rT=&=9v z0S^c7#rml~2T7mouhS-N@IYD{Evaw8Z|(7wc>#p&D~%+cqfPpk?tqHBwgvY0C(Qbv z;{68R((}J(sB_u`xW_~=lQrjXvVd8}%SHHKi}{|myQ$ye%KW`0owg;_zBVc!l3 z_|sZ@{xcxlL4{~3uF=C%n)-6b-T+zpU({1#>JUVq- zIso`X#8;%y{f~F~s&8w1D)$qB6ji^6S4a4gQU%Jc=_Sp#T+dd3E+Gh$+sn}Pv(SSX z%!z=Pc+s{D>hJ3DWyWj3JFk%;HA3oj?fBqsjB+F?K`zn{@G}gaStyR;DqAFeij&tu zd}rwEwc2Qu1xYR{TX*?nrTlX)&$pb=yHh?hwkb0On(PF3TH2>>>Y0t z9_g-&r6h<#R)gql+~-f|(o1w7DfjDKsVL6EIs>YWYo8g$xNL1c=m&6Wr!Laql(Z6B z5(qH&nKl!3y4=L$d<%ZZ&HK_|`Qtd+++Ec`2!ioyom)skDR6G$+ZI5;Jkt?MzBoTc zS2G8fg2EnzYowSS2GzB<9WI;>R6YCZ;_RJrwS(N$4?8aX$wRcjqQzJ1<#Z6cm+Mpy zi(hL^n1L7&$Ank=jb9{h;bDs=0B=qkGj+l$<6WZZcEUwIujhtG`&G$Nd%gv{AJ^p? z>`|=De^76ja9}HZfF@?9jz%T&uAoC4Wh+g^8yUKQPF-PQ4I7qxL9K=F`b+}|C;Fbi zv;@L{b8hzX#lnS2FI(4(%pNG<>d|gM((JJiA|K~h-0fn>-|#R)q+%>hpZ(?n#I$q( zkc}6XG6ml&u{X#G*js~92sRFDWXsQQO&2Z0Xi#``_AP_mYM}9F@p3z(2P<`mP~h-J zy-n_x^gy9U;zHPEWDX`>T(+b0aSytkHOLbs=Z7Xv=~Gq?JmP8v0-K%IgKEQJ4B~V% zXeiXTn1#FF?^5Tp8sai3n8F*F+cY4N&i%cqUuMM8*gO6(T+rx%s#@RjU!QAAv~1$j z%>i77VJMf0&{KQ^44}YgUZx9?ydNKX2>L8m)kMP@enrw4z^a)xUoX$H^r=FiK27_h z{Sgp2Q7bDLSz@~d$WUD+mvD!3DV)&g;uronD+Ay=hP=_M4->NoPw(ffP$tuya(WGoH3T0=^E(+HUlT#nXEvp8Vd3_@755x-3b8kSB$nL zOvztFF`b!JltO=!Lo;;Sw_Y=3`6aN%YH&hqVZnf>xtHvlghY(qmH=UTC(jCz5JS%1 z0u*5pD(`Qz;(O3U`ze-jWY~_IV8Hn{aE)3?%c{4RyWxN`wS}%EOV~QfQe>@{JNrK1 zI}wxa0t!PKPYrfLpFf~EOTYkJS)A1ivyPXW42?=*c5D1=<0+G=TW%bMbZi37Z!sjr zo?1%xxe2J}(I7nVvHWGLAMay<$0WPf(h4QUV}PpT2At-&Gl3(p0EdZdPZ10i{DcBs z6gPb3{Q_LXa^z0XkHS|DCBz@%5Loeogm`T33N&M+S@+QtKkRl)f>r5He4(c^kc*wZ z?buQEjuH66n-sC(+dy(m1H6Gz!Le5t+*@}{HN=nThg*)<(lstGPyrX`Rxfwz-dyWz z`6Z`$%{mst4D{K3Hl~I0!Nk1&68_s(=yyD(d}@aPf|BbWeVv~?X$nCW{`jJcdi{c| z3Q!$kHp8uel}mN3Xt4CAWtoRMB!ocEol9%>!FW&JZh&VGz$nstV`6=VrRK0N+a%d9zo1=#r`j5$bUj&G_fWV zB@5G>>_gz(sJ6m<=i@Cr;7A(YRPV!ne24$tEd+_R`@)9(DvQ)UNyeI$#e{N&R&) z-FdRyGvQCmX<;_=7QgE$?D`Sk-c7Em3n3iLwu1o6#Ow0~71n_16(umG1KX&__auF- z8%=kV$U1MZ$fVxnkQaU&6-+05T(UAbUYdx1s<^ZN=YZocxq4;|+0Y{aQhYq(@%S{m zUY!s})-Yf}z)pA_?78EGjmV-O$}sS#iG-X?tzpZ8VEzsvK$D%7=s1?g*&O4{PkJN> zCotjV^jc1Pa|R3VT$o%?vgR9Qa1wt&!LF-J{m(m43&*)Ez^X8_%2>&ekl+q*=gPEL zXeo0>0@UEM+s=>d0bp)iwwsk> zu@a6npT>0`h;8*J3)J*`5wPMC4uIv1_f(F2qwCayEqFVZc4dQQzqQW@P;t8oBET>K z)7o#zPN$e`gs++YUBUTl=FS_1e?5*mk}F=Y1!G_3<4u=LcxxqHNc7gp>Bs$VDFBA2Xz&0oYAlL=JV#LInjRSuCkH8_Mt= zRW380Ll08C5?T#u)3)S-4yN_qww)iO%dr}j84Ys%X}#Wcn<|q->>#Gd67yyhI5yd- z0mxJ|vo{jd`u%4<7y526;#2r~P4bjH>=(qV60mP7WU0I=kWU7T%nBL9AOJiNE&d4wd+ zAAP~js6Y4`b|Ck;bP5<8bF1%@*fPE6&yYd7Y3ZimHm$G5sR{XE_Ky6F&1S8+Vt_Yk zmRz3$3#`i=2Ku`LB5;0STD^J7MN(YpLjU(j0@hW|nCvU0>R=~XWhVd54U{8Nfbifz zNIS%y83@brIooGbW)e)sCiCU(9RC{^5<}^#szvog0~9m5Z&4qpM=1_=gKM({6+fvs zPF6Zhp5XVnc+_tW{peER(oct$Y6KE^N zcZC3;DL5pFDGz}2bX!T=BA8R|w8f|7M|7{~sdYpS%0N5$f{) zV%Gm(N{*?K0Dc5yC~)Nq6Oz(BMz&%rPu`5*D+D1V>&1Cd{CF`Op@c!!Z5Mk6aco`; znuW^Lq2s9%KCvl(CUh--o{|*mA8ip_&|iA6p{=K-C$HDZ3Oy_ISxwH*SjAU-nXQyM zt0c#*^4}ONRs}TsT;MSMJB&esFOsBZDY&${&0hfVj{n&QfBT{u&t1s+*Po;UA7Bc1 z*-~YYEoKJ{iBp$oSDbyx`I$Ee0UBz-O{RGo0SNq@azc`n`ZNor_iA69YltOA0Mfc^AKtY4W9TPk>lX;+nrN`Ys;gM!C!+I=&&_1e1&k8)1) zdqCRe2R?cc${O`;OC!!9uh<*81gbL&BT|UNJWe`?>gF9^$ynR=^V71{hFFG+U_5^b z*V+2d$2M4AZF`$dWoESA|lEXTp59B2Slzv3?1?+VaDzrbO1N$&bIsvl}F42MKq< zu09n%`}0#WXsA+EVqeyPRWY)}^@o^XvvG8O>iSgc;^zFxEpkDIzdsTCopYe3rGnC6 zGQbh=agrlAmQe&yE((>_Z5XFL)fCY;7u*GCLJ}yu792 z?rIIaULkdn40-v_>utJT&dyp2N8m+b#@2+p$)(Sa^JZ#oG_|1g(t+uh>&3a%q zjk;1X^tA8#ySu74e1{fW{RZx;NtE@z$NZ}WI0hjXTboM^n?9Ym_TR5D{e88@y@z}Z zeDX2ud)m-Km-IOIQ~|#z5Dynu;b)X9d(%K)W~_McaDTSduYp=mQt$ylkBX)euiHF-Ny^Cp7vxw9#(|$EjQH9{Y~g0q5fI z@Q8L?1b{3ezdIn&fUMw?#vR5PwS!u`L-){x=ehsI`TAQF95_nvXr8poB5Xnh7-y{n z<;E@9Z1iib)irg4ZU2@%@TPH90PG4O(gd8ZvA|N z^*TS@Jrk>(vbR4V+eJ*GaHBgoL{>jS?(_ZEtg5NjLDH3*F6w0N6*5nBp~en`u7Iyn z^*kYUt9SFtf@~G%DKEgfQUwMj#wK$}5r7n)vnVr5k<#qq<<@nuqE{6ksF^og!l!N7K>(kK;*Vc6+K!tIj?=Fwp%w4@Q%hQulFNXI^p3)PVRk*6 zI98a|X*;omWf0=9kF2sLuyy4CeAqo{la2lkG1(GdFiW3=5*SXR3mtN_N;EwEB(dpk zyH&q*CAK+$v>oM(f%Qp)b*C`ChF;KaaX#I(x8yQd2EaLHxcgQH6GsE22tzGEYiMGo zVT0(ApA;Ng-9WG~81%8xUT>o=L$={2&qT2=P-UnS+Klaw0JVX1)qWam^K|V#+Ez55 zQ(QeGk3u8(@?OlvHl#Ar$9dq~fY6u{r{5raa$qsE$W*1;;79+mQ*6;>VtXqltL*3i z*uG}r!1Zbi6*oF1r7t5Rj>}ds$KGI@9Ga+`0yck#p!UHg%V8J!S~ZCa|Dd}SWzh31 z$-wKMj?!;OzMOhk33PO^uDTL*(O}oFbks55pqH@icz3PTiTT|!*{HNOcOKmLCZ~}T zB@Fjm#x?_YwCh^moL?c}Y4DBMZqY)z(E@PYf>*nL<7SQCDb8@;rAp>XT%l zUbT{~r(2w83{bpA84OyKT@nYt$#bWAV*&gA>sbCL;)hZv9b8_O*jfp9o+%-ZqQQ)x zi`RT_)^TGM-P^~q_suf4hkiv+&3w9(+C?K|ms+Tj>gyQMMm}@TeE~IbypM)i0dpX0 zyIb3spE%gcE>vndz}o`Q>4)I>IOA4WsplS9X;Eb7zDt|aQM2%3C6sKjVN7F44DGq; z`*q%yA9D{ngh}Y;zxiUy84j5%sdUm2?^BwBuJtiGfQR&TLxQtLK$avpms*z8;NI)A z&eb~#T{EUL4I-;67mE7rZDqh?Sp2nVb3JX>EqH1JfJs$z&6OiTu6t~C0r5lA#`^WP z7Rw3p^X!S(ad(xwc;-T2X~;IhlCBFOLi}^xLUZFB8Y3QMta|L1rkP|+|75W~Y`EN^ z@LKzCvi=4Yq?xp==DoJA%$U|&bjR;gmJHpGN5jGyV8vp;Zi*VatZAcV5u?wCo+6l@ z&x*=K=^6*l_+Q|>Qi9;Ee$jBmChN|3!o3EWmnM+lt(=GtSVr&1Zih+$s()@{W_;-Bb^|^rGo%cgv z;e&CG<;Z3XL;J4!cO%I*uUM)nL%#}~5enh4lHQHsb?1ro5E#u3yU6Zp+ddqUK7Y*H z@+ZV?zl|A%Ow}Q&76a}_x0yBF>kIckhP=js4Oh`nlA~!t`7p_5q{xD~lkX17K-ek} zgf%hv$`_lx2fivh-##&s&6=RI5ee*$0Q&yA{+q|g3;PTL{!=52gAm_B6KTXW+KE~b zpZf6S@RKVF3-N(cuK94Q{`8a3fO3QOK|}w2md=PMabAo0{pa1SDkKNyOR z^YAoCbL44XCK_uCaOUS4G5h0dg_~Ikt%P&I{rCViqHV&Ps(6l&kmAUxCLhkEYTId<K4Y6o1vTiCdwrfntrQbNry4@1ea)9%K&+MA?@U!>_G+~Q$M>$4zAI5u2>-Kdn zMAxY`kK-}@k)VxAw9ED$yg72iLz0Q;jKp;?55n8*X|W@%4~OiP?JE|Wg(h82VT;~4 zApx7%i-0f961DIxI=@gimCfcrcVl8hGQd@W!t3r_7}@lx;-RkxQ z(2^Q|kmGn(WJkpk=^yPeYjt!yn?ewIgZ4c{S7MRzd-bYw;w!lI_P=un7(G&|ZUZy`lxs)Z!Zo*c76Ud*f}BEQV{ zh-e1yLFTR$4eb5sDO%+dt6R|islRS+A9Ffp(QoQAgHSKB$t3V(M#??XZ>SaX-ruPd zS>r*LH>B%2#wjBJnA?6N)Y%;$d41rs)2>~r_)WGXq>%5Nu)}U^Osq*;ZU2O~GA3*a zv*+;UaweJtGm$cwi3pjktDgYrX8=3+>xU=XpPUEIsP)Brw2&qcT`~)inKo>Cs+&Ld z3u6auvxVoacJ>sd+X7h95}voz`{(sD2L&PgW#fR|qwKW61&QXK6o7Rm7j_BNiO5P{ z9M+IrFDuCBA-Dj?o4L}dzM_Y6)5Ky%8zRTyv~=>@mQ+`edm`)@X91*}u2 zHNG^>nFwc_oz%761Tm9zbK){VeyD+9blnJA_TvO76EVilqLJRQb0OFmJ`|A@yonw?217JD5QI_Xt!o%5_ zrZ7De|HHhbSAa%vAp2s?!mmd3$i`p{U7Yya7B`nIbIr|sM2S(Uh?O*eEIY zU|!?}T>vZ{?XZ4E%<~wqmM-YImU@es;lG~sXAQO;f5#$cGKtzm=3$Q}B8wcKOqd~; zm3XSY^VEGc*qC3vMSoDGqRf6DyQ&$m>zA4_+>fRi<=?~{j-ka^qU(YbK?qc*#4d1d zFPjcMw4zm4i+>+U0})vanx?hFw->@)QrV#w!Q3d1a`iI#k^L%=CATAm1u~=k8@V1* zmO~2n)?M_RWV?xoI}t~jl`Jsvsyw&S+nK{Sy=5OUdvEuRcxdiHDEXy=^SDg6qJG;j z+`-|RUj|Y=*T|!R()wjC5(5tu$@1r)uOwU$EM-$Mh4LLS_;Tl2R7?hd;2Py48liqg z#Qn0wI3nxfgz}KA3WJL@!A4YNbH?TjLiwTyJzZhCp)#lv)hD7*u(CirB<Jc~H z*%Uqokv{w5?|HJ7p8fWhCcs7*e2;&}g#M6&pkKsx@9WAuW9b$ov%NA`IuY(E%>x2c zNp1vT78-<;|DX+=Qrc#&)bk&!7^0my7Yg*1ND|CA3T;oy5Ajx)_3( zP@NKq9tnzW8D@=@jIxr7Gpy86d=sV(8xpIh-{#2aT;YeA zuY8+1xJy(nfmN1n&wkCda}-{~y9q1si)KK3yXL!PzFNNSS_sLKblB2rCfQ1T-bG{* zZf{TmY2(~n%k-;lt#u5j7En3b+1DKtcief!X4*E~vUmOWk0S|{2JfOdB;?x+<1=nf zd~AV2T%io&oiocI`Ha*L1vFx7cK!DYhMOl|yA0Rh-U|dp9*acw6y!*;zwQv}w2S>A z0fBxZu=ko|H&ycXh~2q!&8FCXewee1eD%w1-ks#+c%}bA-Jm4ogO0~!n6GQ`(dlQW zwkk3s#uMR?jhULFO@BEnKYN<>dD`&GhvU~|E<;z|By=CCR$Ciwz5*Es1^p}Yz!hu% zRdX!+NwKd3haN*^muYQmRZxrgh7ntEUFV@F*4`?u(vIjJkNve7#-Ot=k{7@j)K^$r z<1p@A?`9IdM?70NzxuiI=J++msc$gE1eQ{Ms#=LsL!fslUH-JE(iJ^Z#Y++^Z0Rx%HSiZT!*!3-!9190z|+H9ldUckT`!D zFG;KEl2w6Sj3ywfS73BN1(V#5&vvoF`Kk{+!|IXH_@3jy*0LeeVo+k6Yc5Z%i(UKH z{bjm#4~HT-F4&aq^1PZH=a)uJ2~0^zCM#YykNmLtl?BsM=C?fe$7k8KLcqk}Bm6pt z*v3OsnkH=l|BglGb~)A?tyl53uiJ_IRj$yR#teO+t2zrmEybqPBC% zT8OV~3-WqMyR+&an2m_(-jh)1=8G$Sad+go-PT1#Y*L|@?f__c>{VMB-)xOvLo46N zFH=)ImPMa&Ovci6EJgOD=Xyf+h_B|h%1!$W2Gv~DVQ(LA%B37dT$|?9^b4B)X!oH-e0IWDrUIz~DRW_>;#W4wfD8Czy~lF+Gich9_t$TJ@{!z1CEy-(Ks` z;-60;+o?SGPfsNmruMq@O(0ao?-Cdc0`&Q97^g_&TgLfS)+7aSZ6cbAJDZlr;a!Xk zt+W)=M=GbY9fyroo=qGtix{}tf~i%YuzfO`!zdLd>-Hm9_vEiuwC2$%Y8Fl|W_dii zugGl{-JcBnxs|3gq9TS~z-Pu_P`k^?9u$BKLOg?(>|UpI^pG+U;ehQQstiA}$2jU&xo290Jx%;5|{+QLe6!G?Yd9)YbHwdGnw$U6uD z%3+`H3We;$2%a+Y(I#!|Wb0tlfJirVtys42HsZZzFdKf@ys0MFHqhM3N+%i;+tI;< z4E~Q%EoEy^TF-<}>anWW+Sti9ZtjG4Bm1&lbolQW{Fh|fW4$4jnLCEac`taYusl15 z1vN4L(erH$Nj{@lW6F*Zsp43ABK;GBt9NJWH9Y*M_IGWpd^S-Y{#wzmaqcC-pUD*< z(woycPXgxZca?RN%wf37YnI+@*6w>Q1{PW4kj7svA%d_dEpp+PEpsoJd(I7yq{teA zwr3T>$uf9>H=3$_aVtFiE_u#@Heq{SHGJQsiwKima=oS!Ip}e_`di{ z=!U*ZYlBg$(}G!o=hdRDK**0pyAs4F1K07^%-P1*c|&JfO2s=WEmPt>`Eu-(99lOZ zgPZBE$}G9lc3#G4VBA3Mr%6GJA5DfIKCv>`p!;@RMjEj3_{re^GFEE%2r8$-F&oc&Xl;I9$1o+3zP#-^+>A^q!b+~3 z=o{6-SZv+zAh-MY2%B5Ba;Gs*Cz4>{+XRLp3$_V6&t-aEUV#i0g?PIjU7REIwiGMm zDx1$umtF)X_()aAF^%9yt_LlpIr${M7*h!V$9I9kUqR=TOFA)H_Z&DZ zRiwRxr^kWNG}HNNHzGiU@)#140vxFh-DxP|3<`l|3Sk065`Cy#buFsjyIuq{78JJq z5uGZe#>u$l>k1S%Tv#B{j@v>XQiGCC)WyQ!59+ly;B^NXX?6T0#ldZH)S|l zd@m)`Kjcbo9gNDsb*P*cH$?J!e4iqDxBlCb&1E^^twsqU{aD=&)jNg754mZ1E~-q* zT0|WpVk@Jdx!RS8K;0zKKxxyI&z~)|n3@R}w!)@HUOR zod!gc1!L`WG`~LU@>aoct1b<1dl#+d=o|NbriLFUFpZug&JB9Bp!=WPZ;km#Gw641 z3nT9PwcKwC|zlet#W*zs9*qR{-A_VZqN$XZ?_^0zZ9cP zyVjjUTmVY1(seI`m&UvH>Lg6_59=S%)Nb@0)lw-D3ZsXduPadrz9abcxvE`a-}`_I z#4_mp)=1^Imc-yr&j_#neDA2V6@ft`$OmKhkzdA)c6a3*$u?ZffC?Ug@MTNcaoN*B zuB2bZIF>v<@>bNUMw1;GVmM~UDEzdJ&QGKj!`wYq?c`6pEhxP)qj7xB3?oSmjIiH1DST zXO+KGcl#yrLzlkflTng#zdO6yBGL?w#Q1QX0}kz+ScP2vCpjS_zHLMFUelvy4zu+~ z{wk8u4;uPf^`^q)8?P))(DY`!Hz#Br2mWTqg=I{O{_rOr#~&p6l~jDGK}L9ug7Vo0 zNn(bZboikE&Qm0r$X7q6aSQP~VZ@9r$?8w~8a(ZCQN@XBEc{!RLE>g|!`OKp+bz$` z&(*|jPY2@kOJJz{CD%uUgauIZSR8JINZZS3KJ7lq`wgXv@3L#w<9*DTNEHHnjvsYY zj;SLWN+N1BwE|RO{81LwLfL^;N|IXSyCqax$-kAj16mvFmdQvZ48Eg;9Mw9cFOGrV z7BdY^`}5MGk|N&OiDKf1sE%T7vl(6Ss>~zDKJ5(77V>iPy?+D>7QF@Ei^#Nh49c%W zFniUhak+0BCSMerg*j3zR104Y-84xoe9c6nWBNfZ0Zs1PBz<=ns0P>uao~|VKC#As zusp+9chOjo2_$Pxg9ZtGut^^Ih&Yzwd?;GHc;|Po)nsv?b30ZjDnOi)Ji`$Kc_PyY zO!GV&0b6Td%{?{bWPZj0^~x>S{>*RjEE+i>_)xUmVpANgClOm0 zq!qbLquXll&jRB;%jDC^sKf>Mm7I*8`3UJN5Wop!IO?c&g=9SE_u^OHLAs;_o1h-b$Dl>+%LteIVZxFH{!PEGYq_Z3^3btUYzkumbL~1Gx zO$@pouMA1|^9;1t&&#Us zK4@HV%I<+YzQ8z%k%d^j!-8eBnSNzk0o7A6j`s(|RX~NKr+)3vz(W6wWSoY>wDqq% zkO6g@W{RC6K`~~ny_4ayX3F)X`Y*r)xpxAA2j@__AK7xJ$(KZ!(+6?NPA?vMC2)Sm zw2+5)w%klI)yY=x3J<_)j`>22_YQ6($hx1LFL+VID$+dYNRr-;97PW9Dn@l}fvAGI zwaszo=N4>~_s98EWP*gYZcyecna>?0^sit$KjT!f2?V<&zjjN?ms)$1=%}9!;I!o3 zVY?pR6xe2}6y52E_YcPe;57q@BI5U#CK`pSK6zogONWjM)=uVYhNhn+=!<@^rO%9V z3rUJ9@(_fJ&oxc1*+E-vLDJ4J0g;^r*R@ECn2%r(w_&*NL>qJ+(=`Y#8j|<%pD1=7 zspfLXHYOh7nqw(wthnyWP;z=La#(6>Xbi6c=JRQs{5yuZ#jLBnKoN8*u+y-x>cqrz)1HVQ z(qudVy4dSCIeY}h02=(r?c@)YspXnaG~d7F-uTdrhSHxSae()2T}JDlAH<$wznG{| z*4G47Lps4prQULqB)%TQ?|FN8y36>ZSEeV~rkDbTzdUrU7DvZ`>?EP5BnHP?rxpA!h0!pj+Xm9U!F-UB&@&1s14 zHNB8T%*Pt{#D8-6rNN!J1~p9!c|^pFO%$E0+vdfN+1bZD;ZUa}i!>SSIynR0wkqyA z%8ub@B4|h;qu2bt@Yh`fU*-`9B@GvUc$;K>fB}Vd_tte4{z3z@es-BWR~yJ)v&ASy z?dYk-FeKAlUt;csPGBWeMzvZg@|vK|yIu|-g(a3+;7tsl+oUWyop#UcmN#Jm|!1nh-7x4VWLC0XY8_u*E+GLW-D}_-`PG@b2s_J z&CXym7hbD+H%DefDW2XfV@&w@GW06?JDu)#57_h#;jQe$RC z2}~-IZI8L6MJ>`R74Jba$m$Jq|6xB@SV4bX(_(P``hYUxdI43Kt=MGl^S)xK?TiMv zut}g;=Xs^e8?9GShi%PEiFlPV^nvzGDpt^UP5u2j^*lQzZ(OQ_vEEo@=Wk7TiC0qr5wQM zec2_2o}yE!fbO*bY<+DN26UyYZv2mK--$wNdzmW1M-}zi$Rv;7f&)3 z*8XR+lqlk+ooY4NmaflQV|)tRY9jX_40is>FG=a9ku6eQ>)1EH)4a#ujyL_Bzup9o z+j;vuw+kNMoAlqFf>)^#H!`NiAv}f=Mwph|v{vU<(F-O2hB|J8pGfE|??v~G!(&$c zTBp)g<$RrRqL`9F|CVux78yRXR-t2++nEMZ$w7PzS3s^zVI_05=?W>tTF8_z2})w=^0V19)7M8L@?9oVwaCU~w{ z%xnc4yqUAn2z7f$o;f>3>0jG=N5oOW+u^swpcuxmJ$PBOL?zz$^F|JqNqcNK zuwe1F?e&~YW_?fKg$lB?sk|J{2IXKl3tfGg_f3AApL(s5yw&n$I6sI5U)Q}!lMp-M z5r_0nB%u|mze%$&#V)gwC^DAJozr_%pxENVrpp1goEc!TCk4V%mF8USWhbN>8Pkkp z?ZJMBJMN%8i7ci3XjrLuRHUObv9{Os(S?u?_yUH9CoW6hj zwEV<0%A^{uD^|VvtweY-8kRP9cO}It3uW)3UfuDX81~Iihx^)sa{0%H-da14;A;&` zZZG$(*Z2w9I_b%NDdpDXT5OH8qjS~!a6Lt*zLP8PmYL>5wOrH&q-RFhW28c+5U4r) zQ%f1M3hy%&kdIUnjsfEr#cdQvC(p;5-&f zo#?Q{#gDiBQ>@hv1zX2^dtNjq54EwLO!H>0reE3g#ujFc3D4}~`1LqtQCC@zoss~))mfqu}7)Kx4%TWwXLzl8Epw`V>6Ou(fAHo zw&sOvO|HKbf%RqsbJ50hPJmzaaz)6iT$+WbGw`GUq;uR6u6leH_Ztm)RlVYw#WBJY zCtnNQlnh?EkFUS)x4aD*u_IuCXxseY)?1Gf8tb;2UzDS^=pT1hF4#}_<_u3$4e!Xf z%CapblrnZ5Pmdiju`1fJ@f3CZ`TJ&kvR<=iMFnr^-51UEySb;g>O`G+&&0D_3K4eW zu8M5T`@55R`SM@-zs)Z{|J}S=n*aUMC`!eZ?DR&v$dMkaS>gP%uGVPfdN9SyDrCuB zBc^Y=1Y98JjiFk+JhALL+E!B7?5$nho;K&sODdjMrg8!MVMe4p6G|R&D#4*xaQ^Ds zP|w>r(42Ar?&pFXHIE2V7V2xC1~c6LJXI4B$RSWNPF5F}dI^T9?P5!q1O7^)820xE zzH#OTX>kH`^$bM0xubzH}7Os6EaiPRW;kJWtRgv-HvUgA$gMi^JqRi* zsCwPENH#n+rE6#)?ODSChI@eWQ^>(@{r4BKE>Yu0Cb?#WVR5Cn!Gw*rCD!ivN2CbQ z{*7<5&|Gl{HQ2Y~vg#L^`Ds_m_#%H_pJkpuJl|E0NyFuX^UaqT(c}pmLZQC?#UDOY zifAip+@#r6sQA>dfQ?d!pMDlFpf-_H=(S%(o z>Rx|xp1q%rlLIj^4tmAb#T07Hz^zGoBGS+j4@=_sw)b4VPO+C4HkmC95$Tx%oEn+PI6!{pkdVA2kYbq1pOGQ@LBi@yOX6fZ?I3SvF^nX!6)~>&c-#> zW^JlNM+C0b&&MAi zawhWO41sx4ylMtpkP2s)-bJm(ur~^XqYsTJ-j?#(`&^tcHT1cf% zvA=YPO6{mOa$>WM{fF`_dh;FW`kw5$7a8(M`|(eiV@X!I|EMYC+JUB(f4cN5T{>jKu92HejG;7xnFu+6N9 zQP=kzk{IJPhiZ7u;O}YnOaocC{~uX6okoZZ{X;#vB-qK@1ik^Y05H08F4#y6;|8m` z80;F1gr>Fga?G|Th&hlG#V!xAsnE{o2JBm3XxLU$I!AbC26>a3%7oyRC!T=2qJ2rM zQ@5_Wq^>|?1J4NH;eaf?vt{I-GmSfJ{It7@^{7hb*6c|xT_Rk#)Y;1HHsf|RUDQ*dbpLV z4xh;RX%mQSUr)8$#gAQI(L;EErgL@oLVer0agSHc1YZBRj@3`7MbWd#97Qi^81Rbq zu)}HTjnZ31O`j-NggtdJm;$~iO#O!l+Uw&Io2+YXApP;;osCg^x5TNdU4PJ}1C&7R z-n^}P8YL=!Qjvo@cg?Ax2l(1_jeNqImJj;+ahL@wM3KXsXNuV~{KZw~Q(TG0`Nl!L zBg!f((AJ56fx#v>aR(x2ySIHT=9 zzSI6d;4 z&2;iliqKEldc|hjv^7V|^TmNvyUR;_v75VLc5__f$ZJsCmTrYrV*H2ZmFF1`>u_7X zoR8IU$7a#9`BO(zMs_BQ+!)cEfVIuG035kQDdqySqnU*ZvFe&eUYIL4Z0Aq1&1Ko% z&fnG+vAG*9TOVD1Y`EL(3ytlYP0FQj5u--Ddqr8d_8?L+s2!A>J)1Eq{Ut@UG}Rwt z>wgo3stLo*PSOT(;ZggF?>>ek-Uaqx)tU`Mzz89(2gq&mUl0g+3{IiTSITwY@WpyV zz4C44__cZzckep#%HqcB6l$lKW}Q6F{eZ`urP)fN^qv~Q`~_9DH&YjRwv=vQ>`^~5Al2$6gxeY@ zIS3w=SUP`1Jr~dt+thwt(LCi{p2J%07-^J8A-Oq{l*YWlAfRxM&z*O!{le`p+GQYf zOx@apO$3DFl(P;jE9I!oMjN3DUOoZ}f_w4ZpcGUHNW@e8=3u`kP%ykNWxhrZozb**yl<{u8#wg>0hrU-pL|IlDdc_V z&1ym>0mEn-tz%11N7St9F1%76%gBJAB%V#jqwUC+ zZAZ4^ASlU3>)~hwy3jy@2!8OY)MIB+tC8YQ%WACBfH<r!MIg-TP~|& z$%ZNZ{>kaKjj(g>gHQUX&Gl!f@)OOFKN427MB49JzxW)kCGxpkdj@lf5V?`LA)$bx z;@%kose^N}Zx@S}60Y7|XvRDSO1@CmEym1hq#8axwRYC4V0rvLifo;-0T5DTH7PT7 z?lSWHo?l{<^;ltr!$4tntNzc35NMK#OIY~xyH<>o*~zC|b?amG$7&aULYb# z*d7%b`w`vW&Pii4`nHXOSb_?bDysV@8NL6r^onbDB`x#yqicrhk4h6BFoJAt?68ZG z3{`_xXcQSy{WzLEcnOlDCm?>mBr#3u8JQ0*GB~B{F@8d=31@e<Q3rh@^NS%WG_oZ4D*_kfn|NZ9B# z!ppAX=)D$G4mZ&g-z4_r77mK`<=wIJ2n2^IX7l46v{!}+w3YQtl!#2?I7WpZ zMlQ+LvEpw9pYV|x!;Z(PO&{e4=wD2>Wj`qzOw+wU(!{C4+M7<+4bmT+JQJqQ!7|=# zaZ=Yfo}6>U%(wLd>?q2h@IVfR8L{e75rNZryd0)P9z|J;8*CXyJQB;k-n7>)s59$n zMZJw9s+}s=?)!Ya8uxW9+pgh=c5-eK<7@3V5xB{!TH7CQ&Yk(rB}AhR{+#nmfXrM- zeRwkxHs;th>v`zhRe0x!Vt2GILZ#BeKN)Vt>?);mpl`;xHLG(|NYb5dvcAl?#nCJW zBpKDA<`0*R6ci+gqzSRzQIM>yTzD@r>xgW{NV&~bG)zx{Q)Sj? zyY~dt3JhLZ4y#}M)tR2o!TbhQ{xdsl1lV%?Jv)Fc^*e%>Qwoar4sGig9m*g{z4`3Z zh5Ld!*v~7uj!@9ppsm$=RDqph!4%W9LORFv?4G>s_od8Xt#+NB1duJq{F`bGU>vn< z3tzGVY`Y}?sPu0XB0mcZ_V2VY5R|s zdmb{`GD04FxwIq`nI7%BEPFhjJY3u2GGAm%Cgz`!Nxw0ODW;6AC&PasC<$AVoVsZ! zw>6m6Ede{!uP|wdH*T>|i4{`IWsYQ+U7WC03VsNe5fU)?fZwlM-6lQb{w!~khHv?< zz{JgtO}PWi=PQprs!C7i{#M>d5P#dd3imkKl1tNc{qk-jJa(ES{bsLhQ2L|kSDwvz zk|F$B9Jl7*x%eRDf&js@1DUB_Gj;I9=iqUTdR7oOoFPpO1i0pdQscsWw=?ap&%aAz z8Y@wuTP_&U<_{#yp#7azIPt>q+4B6$X6~$O7_|k81wVMeV4!5bW0yYM(NzxnV>1IX zlg2KRlF1QH7vyo)ggnRYN)#V{K)?NWMxQq7a*LEL)nje0=0*6PdGpQz z=Z^P{mGtfFyKZ~@!-9hDA=e>1?`U7?&zU#uEo5|9iC_b{gN(#Cl2=@#3#u0H+2ORI z>I=7g5%hiw**2PQ0Z8xg^d^tcts4`H;+YPd6J1{TZlqpOH5^$*RIU1mJzw2OAMP&8 zL4SP58i;U~%X&)vM2UW|h%JSI85ODApt&+eP;2z3)1wP5D70=nHbx3|NQK1hqF!d2jt^c{hvGSABDk_dRqVo;_~YWokDgM=nfpi5c{! z;jg5Qm(XT<(OP^|^X^6H{ekF8g@lgk3B2WE+t^z`upw_%Q~7nd<^N(gl-W+rvVA)* zLMS8I{rjDv=O3y|Ct}%}OVUpwsN>I?L;16WMu%!tpwk9uVB7Q0{ zp^DRV>#l2+^?_hbmUZ*|B=dgFN48&}#IITI`N5sdX4|FJ^>v9L_t*_PP;aE^7P@y_ z9e)ssV=ZedBKKMm41RZWzx|-pJr{rbHI{2nO1s}j7VE>2Q8VKMjpcV7dT*|DxlKkV z=dU3oYHun2;)`_r^SvR;`$2}dyYi%P-daXKY=1=Y@VG275p-N|4)-9Z%*pX=h1rLpVZ!F()X8M!TDvU5(00i>s33VyGQ+0{!3fNkjr?LWSj!wWrqG=HhdVbpt5fgQE`T9p%!8EzQ>^|g_68W;J zaF~9ZtimmF0+2!}Tw>Dia#xek+Wq;MjdNu*GaKn&w%qh|_82eCMF^-#`(VoY8CsNTz%R~6YErn!_?kw&eN%Fw#jEaHelRKe2*FI_2An4-8`7mBd)jvwy*kYhBVPl%QqWs2ul>W80=2?b{un zMIR8MSjk#e>Id0wpU?Wn%XHz15LE6yrQqZ8mW}JRu^x9x@$|yBGcF2ue5C-KEk?^S zh?gH0%U=qu$g*{z6rJ{hmDpiHcLRH3+DMsEQ1WzW^{OM%j(`Cd=m_a_#p-AM7?JJ} zNITvGyD2(*75#P@+rElliWT7WSZUFAe1;0;Zg-ernk;5ot2h_~ zn8{VGnInHdsk;h;%hj+2?TprOn8mv9;*m1h8e|}GK5(>my`$`Pp4>XH)TCCKwF?56 zw~kC*jmGPVqIys09CrS7S2*6=^6cPbZPJ5jv+a}}IWu7#dfUl!>4dlIa}`+v^T^?8 zRL#iO*ALx(Mv4H8-nDec|L?24casK>9Y_yGmX{ro`0|2JL1&bwm$XfCdEutISmuhF z=y%d$SZ|6PNmS+P=Ph#G@>e5TCHfPjuBoL}YNXErRMr(-n$+F;msBbO^pB&pW znTbSWfU|MR{|FG%y{ihs)X2%AscBc5>{H-u1>~NnK;iydya#}mMzpgvXGLGZdouXz zKDY&n+{HrP#ht!Aq@g!H?#b zh-=^?{`2!zucT+ z8t9(d?|=R+_}Y4_7hH%_w?gnTC$m(i!uH>b{FW05$XfoObAN%rGjDcm+CwDeuh_>OKq0;{;aNe}0@d@;daWIQ6RYea^$K zSPpDW6b6P8{2Ne!M|TS9IM)q ztk`9xACbguU@3L>=Nc9ZQb%pkNVpTgzpbcvjqMY;jch;B`Q(>4AC45-H8_H#@zU4r z&$5Jk49Y=tZnt zw3wUa-1Q-VBMbg}J03^^;`%lYixHWtcM?FDI0u8Mv?$OO40>_`*wnuXhoEyCDenu( zOLSPX{1sn21_xTMqh`yX)9|CV^#OzAEg{?F1Wuh~&}aPnCF*9`!IqVL+4vbmpwa&O zPBFgB)~+8xhtj{z!SS3XQm7_CrKf@9#S}tD?{8-S%C_u{@41}sQi62JKqsan0g$XA z1kMuzUW*w-_X0DyP@ciiMNunfB1fG!GDhTs#; zW?|907{9=uog`?)k1*naG$+zqCxMaAANB>Y$o%^@Papu3|H~B-RZ%k*e2uVwkY1es zLNai^@gq{N*)npbJt(Lj{-2KZczAD~g{spflFp{> zsMGlr$uQRhHPyeKY-9dmGT6)cT^$bxl#=_$OIEh(Ft%7DzJoY=UF8 z8Ft?xM@iz2O>ovKC?E*f?`St((GT^33FZF^jz1RZ9l>L>?lnR4}RPYL8 zQd#0&j+*U(*Vw|xerlEJNNxluPJ@MVhzkVj)H+N>{Trf!ho=zx_x4QkT>9zCfc--C zFMCghFd|C+g7kdQwcUrQ%?Y!&zzRZ{{yP|$3IBgGH@}9x%l}sk`1iZCk^3KC4E{$} zod5GCe}BXOA0*HGZ*4VDjMYIGfibeq&=}^Mz1bSC`Glr%6Lyoo9D< zS8@F$m}P?Scxy95RVhM`+Px^oEW z7`hqiz4$%)yzlq-H*4uyu!foYzV0i|*?XUTLa2?cC=mw6#_fwTWO8rr-@7;NSQ*i_ zcwC$@x3y(`E$-{r8}DCdV9UtL29;@6?6)ix)kOmD7paP}bC_us}&X?ltO3(nA6hqc7yq* z|6yZeKGL@@ldY>bpvSpHwz`1^yu$m$9M{u~(-BOsg&?{=sJjlss7DR?}NZQ=yXk*2Cn zXFrRlEqqL)kg!YbK_?5)X!TC$6ULla#n;VL@WSGLvy_ew=`V-o9L2@&pwI!sDPT+WWywKlW5Z*6T2`F+DKworfAggk?UxyNF@_a8D6 zDQlCyfw8ft&z|Yiv$N--G1-nB zLCq+UuUM#4&E&kfz%QIVU;WR*a>Ctg`-(Knels&OdV2byMM1|iN-?o|R%O1;v87u# z9cx8Vdk)$ueq2=>czAe+rj$P&XdsgLrU*||S6u0no|cOLBF5VWK`-`V-Sy4`vs=a( zX<<*_zU^mt`mD4mxTJ(LPQbR_F)@eM*6)V)fiGp|KZ?mi2~tf0qUemz{5MYl}^ET9jdZMYu;+Svjh5l+<{0 zj3&RZ5Ly1#J|_>eiMe)7Q*?8FUjJosUY_)q)m36fsrTP9@63A@4G;2 zWa@9>;rCq^hex}S=86trg}1l2M}PhGCXUy#s!Z$NF1w41%ME-|YWH71ym-$Xyd`@N zh1zDsb+_k^$XCRu>#ZQd@kSucAk5~W- zvcUA2ii!#o8Jl((n5a@lOP1k8VQfl(5gQNsPMB~;!Cf@=d{I%s!}acuAChy;G9%?N$>yV}~# z^tvuTbahS5EPhOL1&{QOrWAki_EOY%Zz}q9@8~Xh;=XrzAyQhnpw|r>`^B~2{bp8X zk=fb!JH;WdYieoNU2q#l#f3~wBnibXXN`h1u|i4P63N%deU~_#j<+8X_b_{Yh-22Q zQ2U@iFS{t~arQ>N%&bf{nR8evNs}MeQx_C+o^BDvU1(C)X#+{@UyDf|8&y?bbkbrH zE;yBbFg!5u7%Ui$#vpuo*Nge{c765pI`=Qtu}$gK1b=HZd+NfCkwjCj1y zmggGecIYQH>S1ZKKy0Xade#O}Mm?;(M@nO~IR#f}jtn_*yJHgaK-6SpZ_Rw>hw51* z6x%1Dw23hbRX9Hp86ExW`CiL%NwnB~k&z$BAbv zl9vore0B6}1v+e@5gh>pC+K<%L`p#+M(nZ(rk8zka?)Ppbs}>!^lRAVuFgdPTYkiz zN}ucguYQ{4Tek@!RdqZ!>SAmck9YL#4!g!TRUT3CTCf-8mx5Tg{lfE9?xB!ptAp!q z`=XUhz=8ASX#GXh&(@zE@xT`7&o~hIc`tD+&7kwfzGkl1toLy z7NrfM_YMw96=>hcCkZ|SE=5r}Dn&Fl*m8P$X&z;!5e1%`mDm(C2V~TPD+i0KE^N>G z?hd^-msR|bq0BBA9cWqClP#NUb}iob`eElvzyBd*%~3XCzAZF~M#4>N zgwN}?s^Wg>n0^0<0^(oB3uFCs*(7nnD#w#`j)Ot&5s{JWhmI@cJg9QZZ};fts)MA6 zZI3>chR8)ECVrSmH9hF6u${-N&562KwUzAhA?~*0`y9E5z8~x-!$n@t293Me)8wp~ zOQ%t##+5`44j!4Xi)C7A505h(mU-#duRot?4X!adi?0c&_IhkzxZgLb?WsSnt|tSh z!^x_`OgQN2+o06OU(PlponQ&_7bd22kv}QU_HVEa>J!6t7othLCo8<rv^_r3ylhvj-qyWxw6u*{0He$U# z;3buBx=&x~C-<=#XK}72Bp~r;CjE=8l?q6XLQ=^~xNUa)hup!Vu`|~_!@Z>FD-7>Fpzw6M}C~$n87sUT z=YqRS+PZmqoAno+^=dHU`-`8+Xo`59|DEd%qyATOeR-LUinoUT%N?39G+$vHsh+gL z^Dm!2ch0qN8DfIsSYtdfab+ba0?oo$4yMCcQ|L!7_a4nSF_>P=2_0R=I%7gvKsHy> zVH1YT@DvHpHf!bO4e2R2Sml(Gw}rj-Qc=mK$eC|vRE;I>>p_@3FLxY_(fK8`b=Fa{ z1Ps+>l#~#+8Q^fZ9WaQ3{1i0b*z4qcEUL|*5O0wuAoxWqhE+Q0VXLOJPN-I3Wnbl$Y6cP6k;Y)<+V0DrL!~(>F48}c)-+;Ozf!nnNn7E6B01ti0 zqg7+`0@Qlbs}^cT_w^}4)?-a9PYw1kn*AdVpga4w1U{=bUS1zxNlI$yX{0mj)HN~B z#33IFdCh&g>Nh?i*_hp;+8PDPUR!J-rnDGfs}8`mL68) zb5BGUmSf8~Bg&FOmbpNA0r4l1bwh-Y1T4orzqVG3siU*|qRiia^|)$sLTBJvYCngo z!};Zf*jbylD)Ao}YlQ;4TVEb0=yhOBY=TO?l8SOXaU~Mi`1iK~H#nACq|A}vytV(p z%f!@y`>=4Oea{-U?7noODMrIUrQ_D3)VI<;?d?5lwI&o zV<0O8m5$v|e~zk;A5C@8OeiQ|7SO|E!f;(GT%OcB+!PHUxV2bxvBn11Wtgd%dHk5J z8!h0v`)M6jJ<6PM+RU)rL%j!;WDJV7R5@0)!n-4w{BC(IbYS4!iNfWon6$ECmaC4* z=e`hX6x_2`)$0;;=H5WdRaM`CGrP?P&xBvk+W0vXNW~`_4xWIK!-w<}D2kAjj4ZG| zCFOgp{p+L8DyS85eqLmeqc9~E;XL=T+dK8z zh+Q<#biyv!U`8)*QB%E!s5&URSiZ=CuLugcE#y|})EJmrr)UGqeZ$Ras_QHHMZ9rg zU~DkfviT4~iykQB7VNnBl10oD%>v=4Tve3X11<@%Hoz@W=_F~(YZMnE7~Ka9cNbIO zh8GuG7b+L0m#3G~J|u->9>@J(7!qAEamEJotueA=>5UzXBNzR7l+?6~r!$u?Vk}R8 z`yLsBR>7ca+bssoKAShDJUwD(=QDAR1)60Yh?|2pQV_}g%8RYb6EQ2DB79G%);mQ- zT`$s$iwnDYgwGpm&@IBAJY`jnC4*(nVa8AW(Mqz2`vRaScpl~Yu~X)C#fxb0TDTO; z*a#SPk-txSucTyfZ3IM)aSz#fc}MD|Y1JFkLYDW}OU?fPcn!_NdlZgXp|bk=88>MV z@hhPhQ?v;-5~dHgfkWRf5M+1xU#Y&vW7JCw{42{pbMR8qn*<{GA(=L#PF+!Xc}#mA zQ+S$`Zf83wXZ|E}^l`-JP`xb13mCeaPmX`Pg)BwLqAf4h$z=H9zHoSW^LH4Zb+PGIM^T+a`zW5KuM{lXAZ$qol2z3dG^oB7@9`lHjs4kC@a zX~VRXqN`&}pp0M6Jy4ji((AOme%SJ1R{AFLa$qg;x?cXL@$I?5Py-6op;nE{i)l=I zXm{^L<#I~-v=DGaLAB9((urRO~v5i4IwfcdHf5h4_J^#fpfQ7<@u#a5^x& zvs@B!+y8pg)&fBt&E)$*pgZpRA+Pr#>;}Hy2lIf=N#)P2{p)sGeldu=?iC`Cpyani}u@1w| z<`^C2m`PSM03R~T9VTgbJY00k_ny$xS0sXThmJ$V*S!)E@*QU1XSD(JKVzyM?*k4SJv+5I@ z@_gIlCiIwgLo;&P&e0E2%4_k%v;j1urH-_SV^*tp<8{zkz6d)X6ziC|Y!(w$JmvfM zSl4};(L%A!llQ%_7zTggyC>I1D7W5%z71oD%~qVq(2Y)+Pxo%5SwPpZoG zdnbE2rOV&r2wE~4-7QHhr zw`x&U;aDHRJ;Df!z3+iBtnsHOw@7~-@61y-#RUWqJY!`FuamA4O6~wYnp&b>tDE*! z@3n^SK|g=`B(0OgZ#xKhpL4~(^~?&Zyt$MJ10czQua8| z^k$VeH8*!Vk^S>eMN&>df$Y^zN}atbb$NLTyBPNXPWy@O=)kY+Brc`$DI1;Y0cy?lcCp1aGUIK*C zn@;MUqVSsj4r0O|n3pkSwVTr+bb|?o4#~Zu=R-knGq7X2Yh3rbovcvEVGDcXs(RS& zJZ)SNqg*oc)X6C9RJAmD=48{kT9}tfFY?57!s`yw)=#3!H2)9tk!ppS^_}3V9auH<-qz(gEKKZlPmF7r4|+2qKHA8~e{Z=b zuJ4tvAHd$6)aAtqEgg}LXwp4T9aO@&Y&`e4QqzjmQAGuR%$`YEPaNk^M3STC`dZ{(;`5(SRm|&Nk3LV}r!pBI`*oOm@F;C1xLA zQ4@lyXBMfprN!}jR(SB{d?|+|{Ljaa zA32TI$+-^wk$8h0o~{vjBZEvMF=R5twDzc@c~gdxRFM zr($9b4fT*Zw$@ByfHc$%F4kB%K=;q)ly-)U%2ifH`+D*$wKy$cm_g_=) z8GQsc7qhe%+D5%`^G@ptD=XxCHNeg{GD*nkYsx|LdGi)*Cdl_wn~wea4A)DS)BW0) zL=6pnlO9J$V+k|*zu%ghTVCOnJ0+rDTwQHN=-J835ZoGHk}OB+6GTVqQ@E3{X?Q{e zIEGxgd3g3~o$q>Enc@W@6PQ?;qK}VV{7Zd&ru`V9uJe}EeV_dfJnSy@`jE;qApQ8o z4ly{XzuYYnvC6@}IWf)5#3b#OpPBhn$!$LyF9Es5#KaU1zGK12Q&g=T z#3pFHxtGRQ$5JlqB6c&O15PO3q40Q`{7i=Y^)e(F7RyWKn zw}|IOKJ0m_i`yYQ{z!Nzg7RIcnx?X%sZz zFa(GBmXjA8e?SA|Jqp&QWnq3$q6C%H6*!}yRUpNn@#Z8pNzc=B^@AZhxg$rNLuZ{8 zd*Yrydoa=UvUn_mgLodJGvKy;{L-(A1*j=@eCl>Ee1DExEER1365*8$-c=7cCr& zeu7LUf8LITg`vRyw{I%=&2urj)c^DvE5^A00p(cdLEisS!l@}&j~sE!n-$6#A~V=u zgo`5s&?iT861F0}x!KuASTykHXrrAU7kiYvvRJp}myX6TeD5zeaJNmyMf2U<+|>CB zzu@9$jEtz5T3dthU11bojph2?eaY(06*Ay$#ho(!ggh3C`yAE}5tzVj&~4q~=&Ofr zO=I2Geqev?-1w=7%7Jt;y*EU2;6H-Auh+yDzoK8oLvkXo6I_za`v?SrH?TaE4G#78 z>QhwJhYB5Ih{&*f72T@=X5@HAbBcGvTQa|_QaxTH{wE40S>xw=%eyh>dvPOzY5(AW zj0j3{EmTw76K=xQm}b)@!0cLr)x%$XvtpKlXJC^32SS}TS|pyTrBkq-JIGi2_qV;= z@7#<|UkHgvv3wP(N%~xdRN{zbo3HucHe?J>4?U%kBb-}BGd9z{ z$on~0@;}~^f%@{d9W@F5doq2!H~#-Urh9$=eb#=d-k%^G%bS>pi0J%ssz@litUTdT z<7ngB@5a0Ty>*>Cc4vFrVK4TizH&4yn=bcJ0ruwg|K>JY9GRO-PS#00faUq(`QIlh9t&4iH~#$DH9W}?r3ckWc%!WRxzf}oB2rl8>>NiB z-Zn^J0>yj24!u zpSL&M9iHAi_I$U?@9$6j2phXOtNaY-T9p^yN!VXYq%Z;>}%hAdr@M z;Z+D&zACL=(08%mq&X=&ybr7P1>WD)eES|{hl`tA6orRN8ef{07l9!kkt6kHEfUBQ}-yT zDod-oejgehc>|Wc%jxkO8=Kslh6v9%IUAd=^f^Hh34Dd|t55-uTbLZ&CgFa*_1{cv z(C-->EXKTUj_vBAdIx>C&abZpS5k?T(Y8X;2g&ok2$pkk$vl?ZCxcyL#jp%apilwkdeB}q@kEf_reb}f>^&A%Xi*4z3rAFi*G7PnvT}u1 zc3GLS)l3!ZhDsPQ3AK3&&0Y4%#WTv|+Xho*&ZT&~lyb|p`^_K?E4b90X??M}i48VNn9&CK$;-7C}6orl?|ANcxBtMoXiywzUf&hl(f zjjOn2yoN?+ral~1!e51_KJ1l6R|!8Nq!EGsuZstkw^dYBlz&W2%%@MEZv5_<7O7sC zD9dNKtzNoBLGcE77(Fg4$v_ofg3vwhSi%M-D^oKnb5|Saf zMbOntCnzW}H!s-%cma1!Rz@KWf?Kx=QsJ-D^*cv){pP4h)lXpM=CT;uMf71XUwqmElV8<2qO*Ut1c$YKOO6ep;&^GdHTmt=ucwWp;^IDl z)ofpV&)9tgkhLY_h?E%PYoVwScbk&{u_o|(K6>%ug%JicGg~0K+&*3UX$sQtN;6?j z&H=q~1+jC@l9H0HQ7~e#$1Z0kpBo~dy>A)Z+u6vi2OW;=OU`V)f^nw4zh{)?C#C{c z&P@66-~5xZMFqL+u$V%is+gU<$7z1};LDnCgvA0P_zpgA|G@XJI`q z#M0~T#ODHglHe2)vx6v=OMc`jWd*!D(%!tJpetd@kBe7OL1l?WN}gi*MtpoYKkk0!Ka2&@10eVts8V_IxIFkiY@HBNTC5$5aTW4K|D?h>?~t}?ywnoOWMZS+bWeUmA}6sM9K^UHa!f;X*@` zKw|&h!h(WVZutm=8rU7c@v!~l@4>R}1<=P%kfU{t0$Z$To%6MrL*fBI+nRjlqgrVA z=nDeHM_0nz0?o<+;lsH=s)b+Q=$5Vu1UhBdED=Tay~(wQ`9A>-^Qf`0(Wi0#a6<#I z3xv;@m^e359v4KQK=Qe2r(BOTtNM_nC@&)u^YbVD={`{X`UA{fxY(jnv&x~rD<@6M z!lIxnPG}}E)5_E|8o_E|ig2Ps zdNku`c6K(LUGQyqczBnT6BTs^5UK8Qy6v09%#W=cu1{8KofWX#k4HcjyoN@GVgtfZ zBj~*HYuHmM(6@7oi_fZ^w>UQlmb*1{mqa`Ky+ z$}v~|b!e&4C8~ySkxDuG$OM5z0fUEFTYc`KK3;uiJNwM+stH^+aJPIci-K38p_}vX zpRhm8?ZiZ~{P+(4zOfsdoH?r4q|6ggS5!tFXB81rHYcniYptZD6l-g*T!A1j;4Xq_$9h zDvl0}XEjT0+9?Y|t80>PPG)9$jVwkw=H~5%875)3KU-zPW~5^iYAN($CG- z;6k*B`y9I5CusUW(=q4?(dDdIJaI1cMF!)zrK-u+SaEY*2=GU~fggHBlm31MI|K@u zck1eT*Zcxi8dBk@f<(WxjgtC?Y=tFaBi4?tQ6^8KmNl8L^pGl-&aeZhtB0E6Bmr0d7@nm71=m}6Q z;Ns%O*4JX}1-#aC#RJRSxfLr_@$ORzH3gNwd-slBL`s^*{9NS7Nlo?Cd-G&bZR4Ge z4#ZPgM`!s%(!M}*^Ph+bYn|Jn_@omE66}3`ly-F$$nQ3(`#dQ-5=jM`t^dw6WNuZ9x>M{Ae9F zJ7~Vd6{DhmjgoL1X)$e(Cw#@sKY9H4rPnebM&!BC{>v;Hb)3VT%RNa^fG#fS#N443 zHOVudc9~DOZ^e?&m~&uoc?a^aFCYojxJ?m!suH_bxYgaQ<7wIy7sq9sKoD_=B>kS3 z$4&Bq^0|pFH|*l&s(hD=^-dmwP(ANDul)@xLiKyqMl&XA00X2DaGk3-ph4;TL?ut_W2zk8 zoh@d}CVW{mD=IpLDIHeOWBZHCB|~ls!IV55N^cgI7dt@@GuhYj&a=I~eN1eG56c1= z=n>1_O9+x4ZlI?EgvXRhZ=!%_$ES#*xztCNljt_aBHI=3u zgU=>fR~H_WFuyBs?V6uV(+WMr!oHw@a%@&s^{BMg^0uI_*ULX?)NRZD_ka+*)Ygb_ zWTczVYd&JDtC+^+Hak6}W=Iuq-mDS033phhp!UW06?bxyv&5?WS*M_S5hKW`NBgZw*SIp3OM zwS2LZC#S5y2`Aov{rNMe-NIAimt*p+X!C*8{F;I;ZNm>4vw0!S>5U2V7nPPT*$IV9 zIH@)COd*_8j7aIo)A8%P$;sMAx5<-KO&5dlnai!GI3J~5$ZCDIoRHsG7IW|Pfa6r7 z-OXCN)UyLxlu3f{T|sB)Y>OGBG67I4w5bcU}YDXQk!XLo-yKY;0OpU5IQU$K49oN!vJHbD;;Q!&eBhaHsOCM0w|sqtk=-8mTUfOm+p%rB#txj#4HhvNUq$=UbmbCbzg z+1U7IF86b+9VjNR$K`(A@_B%m zkaH-uc>d?`;hK~?JiR~cdH&bQXUJ=BMD*bEunK~Q#1Y|g{As<$s4qbB*;NB&$-wpt zM)D1s-CbS-#D*Q(x%c4a2YC9A&s48lsP%I3pZEC2qmL#II|NcWP$nA+aGN~DODKH1 zZ^oXQ$YeM2yU}yksluL6u!7>w_1&kho|)iMsHI5Ks@lt{t^6rmZlbPPUus&VT1N#6XE=MNIw!pJ>x0FC4yy?s`lWl-95U&LY0$B)4=fd>@{qYRt_j?XiPY24mbXI7}WrRz830tsb80A3bj z$^kthxq-EY>i3GLGj_10h#;#%abUz8vh7yjX41nEPd=x~;}F9F#TKNOyL;)7(icad z+p0d~Fic$KXTjLNLoScnG)KMRYm7%S4SGvJ^tnIvH@s~AOb=1JS*dZ5xzU*YNuK9a zoR-S+vmj9kkp+Sz9)j%4?v{I)DwYvUrNg0v?k#vIHseOP+|~QeHwo0O_lp+!-Jh6{ zMOCa;h(WasZ;9;}10`EWKi!wby|5<$Itnj=J=|SJzYdezY=P z7JD>1`z>5dSar?J+^y_vd-kKsbLxJ>q=t;=fA-1sY=smnA``&u=Ikn5?uXt9H8wE# zRRlYy+AH(pE2`NoX`Tn{DLZzs8?ZH4++Pjhumm|+AC%J0~kU;kmdt1)&M|e&32Xrw=}T1NY6WklvtTQPLPT)&<56RC z`qps8Jvw?`)}Ekek(RZpJVE^`*3w7$8>b`?RRQMwA_dgg@H92!YWRV6im0cbt88;{ zds6G7?b2p#+EyA|gD+uucw08#*iF1`s{g2Q()Cus`SAH^&s6V#@DgfgZ}cdr8W~Rc zaMcTaLwxEw&k;19u+G+4@Oo{AB%=nbnsuKXvBD`>v{&UV`S}k%I97W&k-vM0vX*)K zw)kw0%sPSiJy?r1KYzaJ+?i)wU;}KyI^6z>6x52=xl)ysXeflQ)gYry5PVcM`5WXF_4KRX;ivtYTx^ZsEe$t}?p z2>gbrg~?qp2(BH;%hh(rsUjej1nPP-*v#4(-;yIeL#0+ZJRnzpI>cK7wZ-CY_j!L9 zP*w{Q!?!8S@nZ9np@aE``=0JS6K&aUptg`^d6emq>b|v;x@p|^Yj$@qn%(BNXg5Do zxXoC>Jbu{SF#(z=gR@WmD#tF(7?C39%Ak242VFFM|}v+T`cWZBzHKHjvhtQ25Xh&RLg8W0e&X-h45=s&Qdq}hLfnr#)YjZ#r@vtSBdx2T{#pFHD9ZQMv|$aq}3+% z;DrU^ec#T*(^NJBg55=9u~UB_MMG@}FRFaaO&2U{yj3kU4YufSs6~s=@mB3B9YBb4 z>#5jD2NY=U$%bxVEaV@E8C|Oa!Q_#eNQQ$B0>SMZSGcj@;O3yzTaS}8-bASZDQ%<$ zuGnmnIQgK%k;c{r$9+mlRxg#WS>=k5t|3!mM!AURIg0uE)VSO(4u8N?Z(o1V_c_dH zwh2#*2J8@tXW$TSpE>K+sn)t^A*0SWIAdw11Hztdg(0` z|HEv=Wj#D8|j{+_> z_21*ahSEM`0czDj!JCDut7s`}RZ9fMHzY7auX#hGyi4~0dh#tI$q=gB9m`Rw3i6HG zv&jiZ74nmh9+-AXhEIKm9sm(Fs-f1336Z-$5J+leo}$6HRewY!;IQqjS?|;>_(JR* zR0CCTFc}T731a3IHToWeNaE&bsj-j`vFb)Q<|SmtVKS9X^m1r&p9jdi@J>#ajQOW0 z{BH9-l0uLmP2E|N*nlo{)>+Hf4;K=89Ze=)G9}Mkw zT5&?}H~C!SS_;IMQh;mED^{i}-&bJO(Zh2Ql2glM!F>3jZx|aB^PQjzIW0s<-yO%* zOF*r^=w)(TYCS`{etjUH7E^_(Ve` zHrit1bQL{nV|#XdlhbgG`y>3CMBBuwMv@Oa{D#ZW-$|}9F(7SC?zaExAiu~{+-YM% zFOOs&7cpSw@483!Ykk~)5q;nI^BuSQZd=Jyc95Z*bWW2w2=GzKVpK1Wdd+MX!F7?tWmG_xhISB-J zriwt#(=Xovtl!^rMt-#bo%dLJk&O7QsgRo^==PQDfY;*Wo|+2BLW3%wDf?DjxBxz@ zMFR`-?8_OA34aVu?kbAq*KL9QiZ55qA4G-eLbq4l8`a$~^bqgBaIhHSILsVUAcU{L zGdoou^{fXHqYWMN*Fo@(uDHFKLBQJYl@6={@u)kEdn*Gsx01HnW%_r@QaleqIaq6` z-GkJ|Un5m=;?>E}o~iu!M~N>kw@u8>S)$QC3jFBFaW)4|sSJ zlG89_;nRv#6y(G26QK>>JbxaB<${P$pltb8QdK8!c925AuFD6(v7YYR-bQbYc2JgQ4!L5p}S``k#27k zs@z=(xfrMF<)L_)IO*nDA;5UOurNBM?tt#Sdg)G<>cZQ#B2PtaZ7caYbZP8U!dqg)J z1n>#HzxxQ({ueOD!t#Fc^*_=QD>dam<_ZhzKMu8zkeapub2)X|Gm%w0<l_!5_pWhA5&81&-v#S>;vfy&!lspq`VwQ8R%Sa;>VjTVN4uET_5dRb1YWi`tSr501Sv>m&ISFQssnnV@u(GCQ zj^QKy)SglhvR)z&&rF*FJMeSW*( z=?E?;74qkT{P>se8ums(PXZNgWfdXjmK0_>w@R#DUfo;apT|nxB-j+;jxFu^KH&_e zL)v~W=uit>Wy`x-?7?-Wa{c`%?zZiPm@iD3xp}W?e%5b1i^%iiE$_Y3B>eY|<+bQu zdDV7bGb_s&_;P-=Cn%QkP7C?-(8&1$j{~KBdphCEMHQZe!k2i?s zZf{Q4BLY89{-sSMEcFwFnH`C2wZLyf>Hd6`F7B~#jr_`msDmmFB!o%6L;uGPK-RT4H84v%y1D$J8 zNtTLx>fQm^}vrKh0;r?|``?w;pvz;)@T>WTGUZ7G5fhS^D%wbA|onl;ugd`oPerZ~%#`IgG) zb8G@>^MW$BjEs3TxKF8Ln1t8*1sXVyz&xIlz`(Jg0)f7Qf`CJlX^i`@JeVbdb zd9s&^A0axWnbVnZ0@Bf$nO>qvxrXjmFZpPEqCOqTO@P zH)FYjG=PSvPxW6K06#J(MIB;kX*stlP$9%=o=|c{;iLcx2NWQKs_*z!P_CIR{l+)` zs_Z%awM?d%11|H?(CDZXAlbeb7COXgYbif_{Th!!kuoXvgJpevv)}~Eea7uhXlTfG z3u!AD+~0b-x54tq!oum%B{Gi0XLoz&es$(IQ)DS~gIq?xt_NuFFuwUV40Q7!Vr;TY znIO6St^jVV)*=Ic=6x!TM_4sHG(^9+XlSI{_v6Qp>sIxts<%{>A`^TE!ovD!+$qc< zUqe1h3ETiT=kgDr7Oo1>jdb14yQ0F_q1kdN{TrOnDZ6F)5CcP__|xre8!7Unr&3Z< zcZNxmcmV5XYl(oX>gj#_o_m@&ME*_qMunHh+Ew>0O zJx`-aIEOUQU%$nb8p$Z+<>z;Es*j)x%CBAbOv->;h6Gae8&2y>hQ2XX|IQ5Xy@`;Q zTwbyt%et#Xq@>yhG#tyy?o(6K(Mg7^?ZzUlsd&3Iq-A6>v$9$?mMzZ50eRL)Ad^RL z_49_5v}`yiYAH$yO%ii9UzC-xw-4>)(P+a_S1&g>J9hZu`1bYHjv>r{Exs-G4l7hq zv2Wg^Go~nvL%&Txb`Ww78fY*s_at*X^4~o;h`Nff>aAc_nJ)&7O z9%bCWU)5D~{TwjpQ9!bh;M+Si8*>T6tv6xVeDkf7^+&V`cg2 z`TFwW;u8>KG1#>Ks(2j1Am>y)2}<@Cb{A!q%n22_e^%HnmK>b0Y62hmVb+gDp4e|qa_Dt{@R1sj2kO(F%c@K1v?wR!qR=8oP6PM58dc{y13v!zf^hPH0=g=laZ5&0iHTC)&gI+ zNJtE)RC@UH^9sVG(b;5bj@pd#!B^9l$d7A0l%tlZpR}+dJ&M^aEdP39&wgIZAYe5? zk>$QrHvA(^?$%VP#>)bn+02E1Rs*S3#?l$F_8WvisqXIXF8!e3$~0ot{-l-4Iv!`R z2bAL)6b23DlTsDnV4A<&Q7d9p%9ck{-ZA}}d3_trXF-3Z;8@Ap-L)Gpag7jYuWKT> z-x{2v`_j8);N5t!e*ObdkG@5_woq!Gk6%?%O|b4gcwpfZO3WD24(N}9UT2+OAf_IJ z2=DK$WV4C!&33(l?8ot0f4ogAs%d6!R$#Lj^q@R?yyis4^_>}Vo(Qe(?|$}ytV;_sz)xrh?uQspxX{M56bs#(M^(uw4O+dZM2_*qUR1UXS-9sCuvnj>*cu(Fv@ez7#kbLLzt6rC<)`h z0eot4&=341dJT8OGAo$?Rj+3_A4?TDiN=WiI!* zY|+v8)5W=Y5qccOnl z0B4jwTitQVZ6miX7u`$IN|zm<%2hQbFh@dhm`wa066%D|h*(T;SC~;`Z_w;NcMJ;j zRilPUphCy*thlGY2&DPBHXP7n+0}(9SRREiIeH>-bQKiX>>Ki41PAATe6Nrs{0M|E zB_J)6W3vUHyPxc}G#G8v_~;QU?dZdXIF|Jam)V-mUSELU3*pgxc5ZtW6ciACePX)0 zmyCj9b=OuEm2X#4+IuwIu>g;;q zYCM5_StMcS{3Dk(pe(28kaLp|A%DMS@^dZMgb&;}f@@X18D3D<96e0V@q(XN)w>acz$QM5Yr?C;|RJP)~zBVAE zfatVg{*$-S*Z%xa04|#4scTZJP56Xw7XBPeo}a*fNrZG4>_Z;h7%|i=f*fz|3Eol4 zJ4ZMcB!GgMc!I>5NljPa$huUFMDlXouuxO`e@sFwa*1y!+8q=;FVo0W;;l2B2}XpIxrd>%+R`db~HyJk2l|NQx~9i^&Nac!-~*pchb&phxz ztdoEIIK1p>WYOBldUal2r@Yc#!PxGf&xfzI zNA#>$7gaSzyDPnvl$31UoZnnnj};Ps@ZfblYockz_BtZR$=Knuob)uR;|2wIiGq1m z0`W?Wu)8dreOg|l!s!m7^J%)fGbA zN(PH{uiesfGpz(_dtMoDQ`6j<`pCd_q%5mHX!*Wg=cwFRT$<&a$IiW2keRYN zw5mN+xPY;H^u1o|Kt-j|-zG2diBxY`;_vc%l{-7DjV=+*l=b zlLnbD%breHGSE~HGs}JVvT8`kgcARJCBMRq4`qywE2i4eb#_(g;m_^uAkVJ57keVJ zJN?{=oiI_Z^597Ydn88<^L|DAnyz3&S0>Z&1_;n6y_s7Nl;?V;Sn+kXQWM$%5?x;E z0qT)B*_xu#;249GWt6GwXjKg;@cyNbpF4vtY-w)~g_5HM*pDX1u9$I!BlV8&-&rO) z3XOV}mpZkk0ZhIv-?h7TRIOwK9+7L@jc>fKF#+=?KuCXS`{KxR!C47C^I6k8x-;^?v3yNn)O~n&%&w(*d55c4$ zUOE4&w0hOj_Cnpe|8lk|4BLRZ?8WNH9#BzDQ&)z{)XhdpwR76bK}2RN5^y)SYUf=G z!~KIVEhgbm9$da~Z`SzXQnE*`CYCM%_K`?#04C@@cD*xu1GWdm8gnLk*}mqYuC)}X z#miWjW$y*;?F$>7kM#x>Z*X^|jEpk&h8i0?en&iBEAowq#j19pt@kn4PNI`5G23hA zt8-RR%t0|487=7V10{TVzAI_=;VMk@^;*O8cl17H#~XkJ;H>rVmq$`7L`?g<(tE1I zFP+VXoe-A>-A0+bQ|}%gIGK%C>&aFR!IDAB#A%wyyHM$VjP1BEqeQ{DBAEcU$`T_JnTOCce-c3v6z-3fqJZP4$3R#U)xuX~`f@+eOw+;!PfS`k2J+sR)SKJ-o^!#%MN7S(bt$z_wp@o zwQ-oQ`F-RQu9;AG<2KFBN>3j+Q?O5Vg)m6^M~b@%m-+AR>&y+lBu0E(SgVFJK8iYf zxMw0+t*`}9*R6E`CL(zRIP{1>XLS46uB^J5zGUh7 zgtp*rAttK?=qWlEmG#>rO*J*LUMgn0NOq$;jrM(1HiD>*vm&_kn&qL>@Gv0@Zp{1_8G{iY`;`@7uNS-9<*bGN@T~}*SM|be_)rHouwLLOD`&F<0Ew$ zj+T~rOu`66g`v5AOEZuoo+b2jDOxzcG(G>%hZ5NU<0vM4rmZtuug`iry%bIz-sxRT zoAK@t=A_G>ni7|kewlq$S^JrWM$R^`MQRyIlgjhw1@};u4=*l{)72c#bm;Ydf0lYq z?TN$E2ZJNE>^OhZiPm}>U^Bt&Byw*b7|brgo7F9Qv#l|7Fec!U?xB`0Suqek$|s7a z{SasSMY!jjoDJ2I!7>qpqJ(BqiHU7b)f5)mkCa=eZC_gbMhMZ2e)RRr1WO${A)Br1DyXqqZxi+8)g%C^Tgf3FsyGUuR(>89e;D!hc;=`@M%FO-+Go(*{+zC z)kofS=ZPq{>+Im#i@}eMGoRiml^}a&ft9HNV?mbYUkK-l|ucFXLCC_mA5sGvESH4-G6RE?})LJi6CZSfY<5OSOJ~V4zEM^ z__lo7oD#ru2z~>2-|XwJs}1VVt;{o@;Sl`_I`>xG5dc}X9Bj3~Fo1Ue!%!4W5W20U zyzt7|eEvt0Q)jLcov}$FR$9Jc`!1-)v2t*ay|YjMYNy>NBe`qZrIn;~YA6*zmRi9h zwe&cG?Nr7f0U3ruzYY_pFFb;-fh{vzG&z2k)3;8M_0VTTv0eyycf+ZN@Q{zEN<)1u z$5^cXy8YJI+_5cBb6ru;5s;P4;<|6qnT191*_M|r80ZW)sn~baOneKQ*6#fHy1JXN zFGkZ#5uZ^r|9NJXNozPe0cv52DS5$>_e+GhL_N1s;kVD-Kc`wpS$g}X$Z&)nizH$D z|28vZ$x^u8{!-X^c+s6zefFsd?-d*pufuriyrRWog;u0(76x;Dx7 zwd?%omP6(y&!gR>gzCEAMHP9EnWF^L6SV*-; z!;shI)(b{UEH`|M-~Z!paounul&H{mFF)v``V7^5PMOcIoy zEnrU&KDo!OH@|AQW`?c?(ryD2ZU9Oq2{#M8%YterURkZ{h(D6mdA>IE0#*PlQ3Y`Y zADew2(+cyN10EuF&64?a66@t;1$w9Tk)$g`qt9HER({87mQ*u)M^5pXlBZ+)QLa%4 zT9rzbCK5S1ElF5D`()ICUTZ3G+el*aFDWjLJOE|ZKr6e!s!N2RvtPXc?Py^|anW}_ z7Y}1-4n4dOhpV)d;r&-CSx=k*vRm*7szBGyG|xz-_UCnH;Tv>BEV0dZF{Bn!yc>%i zR-G>-#?;&a&oWL0_Tt~eeB;nl((uxLTd^}Vs@P$N$vM$%CaVD|A!)dLp@n%GO!xJ2 z2Dk#ING@B=Rn+f9^y5K=&APki=*V41EGY3BDX z@829(7hJm3Ol5p|&3e6OHQZ)6_kPyzPER*YVOYn)4~(CH4IOKaAO8@=1Lm>w=g)H! z+2qh4ZzVo(rFi!2*~Ol1TO$UZDjt?E3$I1tv*w;h45QwBTy?UnNTT}wUnWtTHxz|` z7-LO-+`$K7d-dE-t;n$QOP2*A>qjA>)wpLaa4%W+?+%L*Ja8Iv`?o*Tkc)_WXY~kj z=2$NINRpT~3=05D#OHb+t6z|et7{BG-<$m<*=S*DdtX)4hn#=RlOd{R|2b^p?GvSo ztr0y1=4)mWQgMbkb_el*0>_N&Lgb zrmV!5nN&7BX&^Got{SAtO$@o!tCu)d3X2tXBkX(}Iz`SSp#P2d`z1C%6|1(z%!Q_n z2P?)X-?p3fA@5ZyujhPctZId<(C=TT_qKxkrEMi%szvt#{ko03KP5l^8F)Y(*8+-E z{6cRg1@X1o+v^xB_>yo&P9>?2AM9&q9Zbe5_jdMdFFZH(MklnTKf}{U+1U6<$8f2) zM+?#760C+n#V+CQ?d!|lm@0g*;IC(+6ZmUyUuD>_<%|l-5i~&bumF(U`8$-1M>t*| zL&2>f(yoh_cTm5)m`HX1YfxZhe1<&Dt4b;= zMkwurg9ET*le&&cV$3&JtGR8^5gp2^+rTG(w1ta~RN376oH{vY+(6WGO18ur+@K;% z&PorF!S$#Wj}QdnyI4Rjn2~=!GK&0LKeNa?{LO1v{)!+~=hY@;5m3guAmpS|@JFal zOYLEdX!6aBuP%|Oy0{!=$N!kX#op&fPvsf5%!^ZSzVEr(yObCt`CD5BtDNEM7Mxy=*}Ac~2aiL*vSM^-(9XW2y1cOZw#k$@+`4z4C6BfbzLk1l+rPi(Kx(9z2 z0G2`)99WZT)j_~$0_yyR2AmkF!^6X`{rw$%WUYK8VSfbZTb>^99}&Kx;4)(qMHC9? zZDr4ul$KZoSy&$HOij|>y9YLq9O>ZbfJ|`VVSlpBJ_POw3@($?S;l7$0dBUMa(egG zm*g%CLRSlNyofrd=VqEhd|E&ZeiMyGUm>Dk1fFnnIIHf;Cg|~7-kzUBrtJ|NMpj|A zg@uLR{Z>@J4L6F1GHWid94!y_fZrW8(aa3u&5aQ@>b^=U{Z zNr6>qGqd7h7;Ya{@=pr3s_N*7^Pt!2DEOToB7=f2l%R39)_fYkOxzw9r1E+0JG9BI zE+C|}IvP?SoGm?P$c7G>UhKQTkRJXbPEkeWZk+4>r(o4OAHNvFt5<1|8BsSg28VPQxwD{05gO3X;V!#&|sQ&Ur!_xsU@LX7!&L!skkIbN`K zPEJi#odD?Et_$nI8xmImF0OWMb+WPa-a?Lp!X(8X2@|bbr0jatL}v5F{e68+>$>7H z3T+?*)RRfWN?|TGAJ!=rEir=ZI$$~&zvXIE6tQlT?=V#G;RmX3@cZ|Vkx8E<^j{p@ z+))8~jee#Dj+?g~XF~dEdr?#;7v!6mH2C*|qaU7(iqVIyw>Wg_VUBt9kq{Rgp*0I$ zW$Y6^DoI59hDDE2PUU+-yX{q%?sB4aBN=_b75y4o8Smmn1biNZ{)0mWV?J;PEcuFX zrLeKFk-6zQ%xsnIH4T@z(ZTSWp`1^IO}<3<^-nPxVYu3(N@@#@ts4R46WDA;f%Xr` zVSpM*%(g}tpdw=gtx+fM(cwD67xK8#;dn@jPr9F(T3kMCyQ2V-S5mp#JT%EIx(E(c zU69!=#7L{>^J{-Ul0KxpFcW;z!SCyOYGb26$C7<25kJ{16jzau=$M)+*4*5zHfEzi zPSGJodz&_D#Zv!#;E05@bnwKhSL&cLc*3y@+MW~MSM8L?iQ9uLN>z2g{C#0@VRL6ns0DFj}Y}-ky(9U=`K`l+5d39A|8p5j1RUu4LY);Aqtz+nnoY0`r4b2NpLsH~o>Y9|2nHfJHNeG25!xKloy} zZvE_X5=^~H+*j79v{skM$<*4jR(_C;2&B4<2zWWRHj0DKf{aCq>A=a^A!$X{wAugz zJ)G{cTPj*l^W^1&B{a|A;P9h2>rO=`i4%YkW}~J`p4KN)s)pI-kd^||rCFvHpZEUU zA-9KSUv^EV><&fo77_J$7{DYh^`;(pZ%1IISxXgHj_`xDb|KG4vFZJo(W9hQKmF)pW-_`7UB#>9IYh6W|b|r{^Y`S@-;RW4LHtN zUNqRh$;UTzMi`cs0O(mELV!rH!p>~XZf|7ddf34#Ff(R_no%{rHAR|R+hyeJ>B+se z11HsCt;mU%=0~rew5k#KHAk1vrc`&d%>H`)B~uD845oCvG(>5(y=c(dk2ElLs8>E_Yp^cN zK)ig>gGha6at~7Y2Gwv7`KL zJZ#TCJp|mrqh$)QJy*}<`cka5*y|(GTM`Wa2Xo*yi(u7F6%|Rk{Uny2-~J_H?I)d>q)XF<64MM@Wp`CCF&n#j za#`ZsJmHe%zolQfxKceiMc6vP_V%nJTurMi?#jxZc$TkUm-`8BvYd+KU{LPb1`5ej zGqoChGjLfeFz%D<)|as-?i>j1lO#vWOGq!H@RD=a!LL39t;*E`K8r{)2)ipV#5cYc z(9M8%YzQu=(Z*G421Z6CUI6bre$afyR8QgfD2~!(_Rq&9y8p!jk6^QnY>g_3Z#m@S zlGW9HgJ;W8+dXVyA}qMwOV*R=i|i`U%sxd-r38MFp23=@lfg)o{-I5?nA(6rR}p8( z>_ey8pIW5!0)ka)vi&=nWM>Sse=N(+Wj;?rY696l)A)A}0)Lz&N)DSJj=qSCR zEz*J)O@yQES-DvS1rIn3yYqD^-|g=^ZC0;a8>3Tgu1C7>)d+JWw3y`9Xvev2&1>^I zP3L7Rmr25Y9$^GTxLI2hmOgUSc2Yv9wINsV!teAG%Jvc2rAstmb2XbPmhYGUt+Bsj zKWdQy3n%W~K5A+6nfEW;Gv!BW|NNLB{n!{SVjzzY7j3#R7$b@QiBy{k~q zNwS)q@M6y_!G7CaI}=W1H*XToWh&;sxwLeSz(2riA&Fp|JA@tejqL_!n~?f&Foi(r zxF=H%y>s;0GiM%a8k%tZIsNBPPCp$P^}GYe>W~F*kJhYqA*b^tviE9jr8i5=$JuoA zAi0cjouMiS4D1?Lr#>E-zpo>|17XK_L@7PX7VlTHY z$mz#xP+Zv6F1ikDGZdEP0}Ybv^H(qf4cU9;Z%Ctnl*H?H7*1-hUryu((7k*$6X-st z0dl^9OR&tX`$etHMdBSk`R%SQRz#kQn7(9;EVKfPTmGD5PxY0PlmCzfrwywZ_Uke` z&U#OF7`_Gd7TQ=pPbyK`Jmr7ugvNd3flGk@F)}jpYrp*uU&r|2lsJQ57kZ9K-r&q@ z!s>Uy4ZdtKBbIc}?z4M<@4M8g!_(9Iz9!&dPHTPs+&Q+Y5jnXYS^)tyc+p_W-V0wX z#P)vuf_@hs77x$1QGW`HV(8D&3<39Il_o3Sh->8JbQwlQY;K2V);BkaweG}&<*BAx z+nEbya88fB&yi{UOhUf(uK|tcOYJs%hU|>|FJvndvEkt~Mhk?ryu5FBZa8E^YjWgG z&{F#Yy6G+EQ}CBS{M{!;!YBSQ#K{j0y#_I9xzWP*7$KSA*tVDwkp^FK=GrNsqt9!) zDC6L8pCXHQhi7?1g^k}?!!!H!DUjUXNSl~s!D0o*tV%Obj6&9mq3m;iQhvqCY=Vp6 zY!C=4`nzaF2Qa2&I{BdRMe7HcXP;4f%Vs?N{aK*?TNd30zt05K{MMLzd-F*IU=33L zpN90p(=!~W!~Hm|C%*7{Jp}=Tw0>(iE#dPX8lF;<1x;n;QXdL-+4fjLMj-4@uE?Cf z^Y>+N$dGGjxr`lQ$U>#koZKWw!^o))>)*U(8R+DoS71LPKiTx*Z)$5rMc6&Q`M(c? zWn5CSnPh!q@u=1Yh-0%SO9b+?IJe;`UpDs|oh<3dcPNEpU*Av2%ZqO*+}MCB!04}y zD;7&B%uFowQc^aSG>;xYAsWQwuMStE+djr0S%|ApN~Wf0Xg{Dp4%q^tXAqtj>?c%` zB*<|3e+f*Y2gdB**96+fHG|X2fV8`;e@jyge|Dqk?p<|Ce?PxZuxbw$nSi<7*)j_I z)a2xcJ1e7%fGq78{V5V%BG~jYTl6>tcrCQzqWPU0JZYNy`;}(fG^v4e6;|DCVc4Iu zg1}z~g?V`_;41vqNAmGJTg^K**p3mFrgvIe8Whtl-E^U4>NPmZMYcr+mQxIDFGp%`|0yWibh)|i1CrT|%oM`o;sy6r%@e`~T z^MGkHd`__PMaODPLH{{3HE??`g?^~plMUonpTIdis`CZ1s2^Zt7P1hIx*~nRtNOyEuqP~ONb8mrXNbQUwJ&n ze|sbxOj2PSJP7WW#^V0hxq7PC8=@4kru9-g;Er)y-z<4C*S@mRKt6s|Q&@PxS4y!n zIKol&c~3XkclPZplw`-x!2q(T*z!M#OW|1bu9GyIu6By4oGY2qF|*25N$BqX<^Z0& z-wQbMofovogwEjNw*0KEHJj^EG(e3`s(nB>#t=2t@()Ap!u9q$Xde||;K|9zsn3)~ z7jyL#>z^lPD)3@A{`GSLNz3WUS%!7Dn|z4g6ex1Hc~E&;3H7>7O?QEx@KcOI>m>>m znNm>jTt`P|r3YkQDTRf}E#)O(+I9c_D}B|!w+qQVSTg{oj6jb$H%E8l zM#9A&Z|{$-&>CB-GZ7OL8w~mK`eVb$<;52gw3eklxqCzLYOG;r;?#6g)4RR@vZKe*m8{+K?OW9esaLL%2nFoZ&Kgj_cD)s`j5-mF1bNhIeIemE zJpl11iltZdz65U+ut|Us(f9N_pqL7UN(7ll`7iA9`T2ZiGa;p-qGC9_6Nc1Hux&^a zNtv4Zs#QdS!5(%2jKW|e7^(JQywim-UIinV$KX|iXT4Qcku+?o+OS>zdQHef{Dtmc zEWo_1erut}AUxk}2YdzSEs)Z(Yz`CA$dNr%Z2OsL(z6MMfHTjGOie#EymP7(=`s5~ z-m7drN(SDKX^gZ>##!L`*k|VIh9oNyP{b)jMUkOZgRn?khKBi>0!-8U&2CddUJ?1Z z#^~5s%E>vZJ09$?+DT_AXpH%It3TY%MDGoQVi?%_4Qqx@MBQuv+uXJKWgU? z=?+NC%iy=yy+`7|-C;3sI{UHrP?|u$MA&PM9)oMvb}A}0FHZ!l z<)o=EQxNJthM#d^D zt*#z3Y+4|gs{Q22>s3E~Ii)ox*L~F1wb`5V;C=kA%r^Dl$JcdTHv3f%fQg%DZ9@{EPMkW{Nx$~berI9+?TPJ=GBpj^ z+r33i{TKlFm2OMm+oYwPvG_*$^E+I>Dsf8WU!mONqujg<7N4S`F$?JvR4i%&f;kp5>e#5Zo-fY?2=hImWLI5A&Re#{w;GJC6KY~TN%AyTa%g=$p@-9r$Hu8L5o`*S;kYxcr^$q=;=$1k=Ynhu^Wh9!ToBWR{U#c> zrcuOwau;7TIPFJ15gD2Bs%Z$!ZqdzrN-c)-i9Io@euIX?`TP6(8fWS0?+LVyRH$ky z=*^7oIcbc4s>f|}QWPvg2?+9!m8Ybn%nC7awT~P_IG-IO{mk-H%bvBhb=%SRPf6EPy~H0rmbEK3a-FSgKM&s32Y}ct_yz<# zWq;QS0u<>>(<6Q>F3kODQ)~apX_D?4eZ}p1bhzB(;(D~)^LHg8c@HZe4?dTTPsnP6 zXZ~It)zOFg-6^`{<`0C8v{TJ`h$$gyF388jDTM95x{NxON3uC);u&6~9AE};acDRR z2{2oq5^viDS2IiHR5ZHHlN(jXrr)Z3V1u?na2do#pwW-=6J4mFk^6Fc%=I$YrBu@0 z)QTNbKCw111AFoH{Vyin?uQR;JURKeWPtWy^d_~BeX7CtU-&0fEA(*xW~b*pMQo8C zc!3EsOd#`>@{-e@1Rfr$-DO~4$M#0Ys2GqXBRi(h!LlwA2dMX&Xu#(^)m>WJZ&sXB zAA5Uyzau;C5X#&D3N?1<2<~sTl(^px%C1dKNYH>(L9GXoz|D`Kk7_qlx!;2Ht^MQs zJN7d3I$+=}K=^guft&2V(~pYRKhT9nS=x>8=DFwMrE4hH&K> z32Dib0v%a=Pd?1@VjsipXe1Gh$T&I52+*EX+rf_^S*^P;{o+z!^bWgcTjuu+4{xKp zCASH~s2O3=cR3e#kEiC++D~G89*MCPBNguFP4K@_# zcNsBfyFUZq&p1-m7}Ao4)!cUO24)eFS#`K4PM<0U6g|LAt@tM6dW8Jel9FM{SKi=X_9F>2g`z=Vkell zDJQg9d=|oYr3_tMG{(DdVfne28k+PWB1M9*sn0W7ymP{gKMd4-y-+E z*j!L&b#*lueXX%*f-2^^uv=@S2Ho%9*k=7{3DV}!metl$TQB*>ejz2geA&p%|G`}G zzr)8bybz3g*4Quh#s@JZ2SVq&w-Vr-0EP&|X@jStpo0B-pJAP*!fwOjat9!R zIU)7(Wweoj9V9|+y6Qc8J5p{d=i=f*10BJiLyc6P;@+RJU&64nsnkjZ5$VCEiloxP zYIx<+C2DZ83V=E{+)}TwSN9IvH{u1dzBTP~ z{%88hq!g+3Vc#h%Dw5QSUwX4pTPyPKBlL!Vu^lH5fE-OIJ>&lR5Q9nuS`V!R?S$^3 zA$n+w{;ro;lvL16K>;I?YVH8g+~1Gm(TIy2X`tjq2)idN4^+2#a*$#E{nI-0aIM-Q z2$w_-If&$Dru>C2L3IOIrY-+*N%fKXzu(ZwDN`Kpq=s#NXDuo+vK64zKaUG$$ZJP( zc7*@UeuejWGW_}T^Z&*DyO4*x7Gx+XiItW8n@=M6{xy?2ImytcfrZqw9QC&O?Zf|S z6)z&M;E9)Ug^*%uBY$>Q|L$Ezi15mhdTv$l)t}_<-?yS=fz*2h<6DzcG6A0r*3AC>`QDrcJ_R+X@IkKvaaodopYi0%YZTGfPc7U1 z`Sa4>Z?pWo+)jkyX4hQEg*$b3|wrAE~ySw#J(8mA$wnv?phrWl&%a_4b&UP)i z?%Q@@5ah{!GtPbI!_{lo0I!%A1P||}*}EWcWipGMMWiACn2Udaw_sv!9)>V920y2L z>vO!Rsi}#~!CW@hy`T`e0a|N1iaP1WwxnT4#J%{>vG6|!S0CKhv`wv*j8OL>i?^Ml zOM{O}fz1M&k+E?g_(=i7!{SMOXtiSFz!yZ63@_;A%YN~+GSD~6G)pZ${o32Bh&F&D zhd@doV@aKaw%tb0#0V4DviQp~j7dGXyZefxa^bcSR03+n7*!RO!MR2+GK$e`hn z^eMEou+-ce8yhp5%euoHh76HdK&H&I$P{e^!LN&p^hRdJ9J=j*1-`Fw_lVkdP==&7 z&Z;bB-;aLR;O_kZo+Sit{G`$*TC!EFY4lo2HhB}6;e8<~H508c0o4N=6|kVWeR32o z(7?^5{3ZQNncGSxplVIg$`+5Z^b0rQ?&k7esfVPC`;NBlFVL_;7LN+UAVXj^fW5%KTLdSc>D_EHyU>cOJ?`@CmYU~uru8WPbyOz-#V zBj=Qa>M@tx)1&5Nl}#>!x((8J*C_{9reM0(t%SOfO#EuT7$T)UO<>pSjg+nj0(u5S zyZqFd=8>{Z8i7jPn&6O-X5fBGf9nLR3J!mv@unO+!AU@4## ziK0!1i{FP8$+ReC|0%;D10oWe2`u|ST&n_GW`b#HKyG&)+o+YJJk?rxn2fyEfbP1h=-uk*X~g06|bRIs1h`;Ys(9_)M{WKV1B zcXRuF`yR5$Opi2uvSZll?B__4TT-Ype3)hw|4d$)IxM??c4^K)C%Y%@JbL)e(`JYSF0+H)C;*+=mQ>R}}-{&{)Mj7#UvZ?x^(Qk9)E zgeYizRO1x{P6yew`7Qln}dl_t%#W~uct4`4gGd}_E>hpvoWl6(p3k$TM;thr| zafA_Ihy@5A5hBY${K1I8+Ttrk{q8Lz$D0Jl5-zT;ZNE=eU@dAV9^bAm^FqOYCP3@9 zE8ZBkkX1f}O1n$BL4A=zKoLK#-_??tbj$N%F)LW;V5@+{|ve;~g zY`hkR$j8RVkE{1vPGft5SxB;Td-}NF8@_FV^`fnR=z+p;#KHhu@ih~WhvBTD9p?*98cRcDqFz8WXIaU7h_o5VF?MqiW4Tmq8k|Lvz3wf~jl+UfK z+-hr+aaEnY5xdoIAv)}7)cJFjzh-sA;b64R6qc`PZ3IClHUAa@mRy64DqWVV!G7*@ zvLFB*_Gsu+W{RPL1nto7z$;-BPt09`D5>8{t^|3#h0@^xe@aUv+5EIJ2-^_tbKyS` zvpOCl2pSCuqnMQf*nGajQVs8TBIK>sO55o_W+w%tz_H$+xB?>iXu$1pV3; zX0Y8u?OxooGRTm5bK7=r09+od%$-lQy1I&14cqqhSGZ?aED{at`uh5APReBS735iDC zPZ#@mDVF++&D%{owl@74K*=5I^<`?zn!g9C;USEle-m=ec!;;iv1lzwToTm&6dgTj zN4Y`~7Z5-Vv!m{TPHM!TW6n4%KK{}NUy80QJwd^$7t>(qnv+Zz{c^g_IK5&V&^;wJD*uByQzethK4@)HmCUA1;^!opp|!lEiS8JZc{!M+IguwYv@?mr24ryBgifF8--5WQIpVPYt^Up2?i?3M>^YkGl3B%C60!rSWzah=2@_UMvRoAx&6rnfSJtX38k z08^=&5+n?^4IEy~0FF#y9S=bz| zA|SOOZvu83c;ilk2X0VpMF<<06X)V@*n_jP3zKSqXljvxMym@5QZ&lr70G^Gk^!VG z;*xlymgS?<(O!La(r>(B`2sQ!frO%Bs2W(@N%udcW^_#?YQL9P@?)RRFzPen$_ozf zk8_B$5X*(|p(MpY)HR_WuC%yQ{Lcie$=wdE^L^9~|p`(Pv3sODqU ze9m|a@=v2_p;5IOJ!ecw1O*!6cs*FK$3V!VUf!Eu#Wx#Q{VwisTKuFls7;#f>h0}3 zmTB)|AghI=ECU4U7qU)1veE^z`VT+svY6k^mwf>dBDY`!HGA$Ug<<$PvI}RSMa6vR zMJ&PcWTzo+NIVNX!Oon+uBY;H*A-ZO$3f|e%Dff5;JghSs~ne~brrM8$Hoi+mg0@J zP>Hi0`#C#onGREOQFP?AIaQ&$ri@j$whdD{>>=+|pE4y*TxkENtAvb95UA5wd*DY| z1)ZIpV}j>FywU!dLh2TTT9AweADH zbEBh}-*s9foW-_a=m~HJ?S~Mn$L1}je~jGY!PTBAIQG|?pN3~b$*UhfCqxl9ZMp5l zsV)#%efnfM=qYPyX}M$3K!JYRrE0zh45#7#`wY%oI)8AreYo|h<4x~FZtAVKZ_mzR zMtbi-LxwaR^wPAg7};^eONz!eu^e{9%-j}GmErrE)Q0^5f% zz|jG0cT!;3p(dR`tZewLNeetUZkiurxMzO6ItsL=6E_m?;^X-F)p@gNT4&F zIDHm;17dh$kp&Rg^f)>81SB?{CXn;mjBf%KdJLjP?LX=X`rJ!bpqQa=jV6*b_F90QbDJ} z<>3|f?oBii$g`n)cca!Zo5_*%I zJRro#M&G<&{cv${ak=N?n$YS(lRx3Vp4X$!1L;~8JvrnAH$mc$WKl<4vo9GP1d~k| zoTA`1rBR6}(R0v>KZD{v`74jyIIk*($KnQ;2w>IndxwXU4Ia6OX4eWhAsN}3!9M~n zArfufZe;Npc^N9Sp8V(aTwDdp3yn*Jt?Zuzu2-g_31Nn!6tFpQ10#@BSo`$_a?E;C zx1~|6>kcpB5HMP!I`zN&k_Q3Coj=c@iAzB6Bn(!xJ-$=Xe(|X?ETynnM&*Ahs`t(X zTPAv_5T45`-+_#sE5cU6p2~AIt6{OiCNQT!5;zKBGb^*6^ZTWedt=9}gbeE!A7D?X z5)!m8j+^j*hIEoY2!uzjs(C$Wqn?f1lLwJz0A@9XFoXdfstInE-^M#MAzD-Hej6XD(@|)MEtrsoxr<7nLx$0}6j&i%Alw;n z@~6GcwNuSt1RE}dgECGoEiq*E3+QHAZ5hC}K!b2nVes98%s^|7&})y~yPtyZqAZv( z=+%9BbPCI#|H&Wh1#ACtmH{8b-MfJ%O3W1(3?Kx!YNRyw#-q1;qd5jZH$roUu)#f1 zpfe-4V-PKbZD1f<17)F+>Ss{EMEpSJd4-BgPx|^e zXNB0t1bpjHm`}gah$uS|4k&wtADR-1(`)uYN zmKFwbAI6^4HkPRjL+>0`#h)x@hiBN=z&Izl4RtKZ@N-_eJ^;GF$9YAJP&3*&WS5pc zmW}3NLZU!nb9OEF!?*sI{gyKter;AlQj$&KLComCS=Zr;>Ig+(gx|iE&!#eL(0W!9 z33p*5d(jqEA_Cn^h0CZmW-}ua)qh{v98$d^obg|&bu9o=q%UN@38I&#CPF$IW?`jD zFGnez=LN|$X^$Tpj;jX#PhEaT6;O*dw|z+2+e&$S@$m~xc4ZOL8i+P+R2mr>@|wSw z>SX$fsR|QdkzDwfItZ&%9L$Mc*#=fKpW9ed#+DhXD%xg^M<6l;h*N23X^}cSI+Bsf zGf~QIPL>ElA6&pIdi~ncelE8}_7G_=VT)qa)}DyLShuuhbqFKzNOPTpzxTs&1Y?W_ zlBNppP>_pdNke?nOU%JWOYTSWw2xtd-B&*QkuXd{ERvVJqT+XGuTsj(hdeKl-KpFk zBG*?ny?OIyTU$)@vY(|9lFW5P#%&jk=g%?nk$hs{woH9ebo9OTo#F>!Umu3GD5=)@ z`h7}T`3}mUwxzBe6Y+~w!C@M1GB~Y?X0FcUr2#g>*8Cl2J6wUwsR)i3^JkEh~fM z%C77%N1b2#p8|)b=O$F1;ftZ44LTqi$!pr1SqSFdu2oW;&+H2qXZgqXVu?^QEeC5y z4ce!vJpW<=mDQY819Vs{1AnC_KdOx^EZkfARJ0$x-wMIG3d=WwB_d$4s}q#VK>xPh zh|;VX)rj)MsF%OP+>5EJtII5mpx|`| zRF3($FHxKvu!j)_s#itcAXUowF3%8f3d_d-*#OSvm6Z&tYg<%&Rj8Bh9hP)Vf4=T= zOVQ}K)wf5FW`(MHN?EvugznwtO=;PJ%@gnZd3GWWE(8_c5S{Bc4uEjz1Kqc8-vai1 z4?2;H9a*^wjpg}o*<%(+?n!3pM*Cjp&1~TSg~aD7PQ{;zuL2nA-{F7$5NcKnI>d`T{wYlIau4g)!({NfZU={;fMK2rR%K<`H> z28@hbRa*&vLtKH!uZ|X?J_8Q&E$T=cuTH_$!X; ztM{gdL0vJYBENh&W$nKH#nJh3Z^X*_m&6=w8H>kxEvDVBX%inR0;Cumz+~^63;NYF z;71#!q%tAEG}~Nscw(i7G|L! zKulj2*Qq2&xn6g)Uyg1+5Z~Qp9{(Lty1BCE^5oR%(`T{X-Gl;4*7?;U5k6V%yzqOz z?~x_j{w1Mp*Hn%NV3JdJfn|4jXiid$BX`4g=2S_(H+h_S=2uH+yN$W-GCvrUxF){nymtw9j>( zQ`0`X67mKe&8Qm4m}d6mps-`Xd38iJEp4?|zO8p8bI(RdTBc3HHFM4`&wq4uwRpHV zTWdz^(MNfjj8^H7yat!fd{F5)Z}yM&=`(k%&QrS!_hE1_8YU~A->P=@bLSk>W&={M ze$7@b;cAQF=SCkNZjKb2bSE=^`S4~1Rff;JIdE(Fz3ro-mW)fLO*$__OXF&eD~@kL zSPyku&17?Nke#ktbR-y9$TtQT`bB)cz$x=fLeOHVc0FCURor9&rV zgQ{NsEHK{2JsyeW(QHI@^g zyQ=-rhx4=RL9xJ&Oxde>-S`8mRN0uwFn>$Ko1X7KhUJdiSXVQiisNCm8!fjrYLDi1 zydGg_uGqIKAsf!Zs;TMN*XP(8AxBGZ?05Bsyy@kwU~+@olqRl61BU`hGlK)~-U$f$ zH};rG$F4p!DRHRMjgE$_!6x3uhUE{I4$Xtrrm8sti)>X6nhy@>Qw^u=TF@nF%voEq zHvLx^8~!;(V(4?f$N!rO`NWuWO&4u6o@MbD*WJ;$j{Q5(<3u~HKdLHsdTOa26RLFJTrx1oLH){uipL{eOAG;?VJ+Obsb#2pz?#mly=R{fgJ+R() zj}khXo+>C2CwgWhw~*1M`b6hmY+g|mHN&{w%L@_Rl`*#V*Xc8Z9^7r^i+D#|Cx7PU zK{?*35{mO)SU6Y2@%Qrw65a<6T2%=RdsDnKbiDSa6x+fItyY%USjT!$!IQ;=;)ck; zROVaz>Wxm5FDuy9P44tmsHZc(j?O%TW#P1dVs%;FQctH7RDV~_h0^YQrBdLvZ|^VAn!>y7QiN9L(8O|UBy zjMbI*ekk?XFax8sE^t$1u*O`|X}d41qSAjovSEwG8k1eH^xo1~=upeZ%joiAW!Vp3 zwQY9S1|OS(Z%*V5zAZ#zmd7im$~8i0amj$NxvM3I* zc_MC(I4pOGZ*&O%UVrjjy@J{N^f!LY=Bj3l#()Im>o?jhUFW-Dvk@M~y zp3&BPdBM_x_dkZS9W`uKo9(I##KOla7wJ)r!74F;+r_pEAHUvONQ(xRQ2#S;@@GZJN4r+#~$^rqa&WDI);~mXdmZ)(>#qMpf?= zMRk8DpTP`w6Z#8B)-Y$Iir8W}XR_s0`RUzpKQ4yz)S2x2L@Z2txA;?756*1%oM#pY z3uRIdY+U~^bF=j0?g5-*VOk=Ni9jhPnGWGyX{W>d@wtQdyX+dfJo!uy5<(ahX*^y% z6zTDo5p+hOD)eQ>jOJJ4QP<~HdX{z1=Gm&F@XxcAB0gGVf;`mKI`cG)X%!RuOG8ar6+=%XDy%YpyR4Rz-7Gg>RN zw4?7lyj%?#d)fbJv@ggD%3YbN5%~F|q$lyw`JVD3lb(vT>Y%j#-ri)BoH8bL%NYf| zM&E_3rJRZzxR<=IF@5h?`>Zq0{ndeqSdE9yUsT}bK%Pxv;+1(^;lpS9Q&P;+opi55 zFXi5Mz5M$j)-~M~8@dMtcORv1Hn%XRl#FWxhk1K2e8~U>RhVoDi2>bCT@t>UyyQ39 z*M$|U<#a1!RjMMVFYqYH$oTqQ*^*;b9u+>`pxX307Tk5a75AxAqmaXUV~|Hw`!|tN zD!KWg)9W5}x%^vpzkVigWa~dHc|-c8Nj}qoB%Luc)^WdyS>gU?_wm)k5dtcqNJ!kQ zS>h(*=)&A+zjL@RQ)0urxh{Xlm!W5DR))MA@^;JBQ>&|Ql$>jij({mEm7jT6rhDh@XJzrcoSbXS4`4!EQ+N!}hfbSeo#AUU8MQO5N@^)=F>1nb zF$)V#8E7^3tj!cuGR$$rAW?GL!eeBrt@>6VeHPB4`b(?5bLJD0t(lHOe_$B>hWUGa zhDd%-E{@Gc_LL6AM00MI@19!|L9h%-Tm7t1k*doYNm4?adcHrxl)BcQOjb6t=WSr? zE|_{vB=W?B4qVL@opKLf^ny)ECWD0MjI+GA7{IJ-60aO{g`L!4=1SM{ zsL8SoCCFxYF=DTowXOz0{)b7Re;7t4V zBVq^`ro~|Kg)t;?w8RfrR)RXf_Ww&D;jLn$ZFT0L zKGwdjDWm-yjgy=Wqggl?4rMbM6auT0kw!NLU#IB|2h9DuTSJp)=({HaAUnG5*K4fZ z-zLY|ZlV>omwGDoZoU)m1+M1t`d^W&i+Cz zM`5o^qmSwSVmb0zmm8^Q`S;6T$1H9~mY=PSBlDpsbo9ILJ>ZT)MzN^yv4OSopI?3H zy%PWnv~5DNOxA`_+t+vo1|l@@->~u7nINK1u*x%CFxtbN)2@m5Ys^dWfcqD|1IP)w zf0!TrBE^>S=HhX>QPlX&+!d0-)UGn67q)I?snFzQI_Y>(7+BXm!0$AbS1~eFFI21u z8B3ut?`#sT>0q(>BJ0C0$25-6$k>;@6%}gs*JP7^u{yq=gdX{$P1Bje03LJ>^D9jE zqOkknfw5vYxo)BxX?JCuVCJzS9%Sxa8h;?#H8SO*L*>daP}Y~y_&1ohuo0Fp{Y64B(k-J47Ys?Sv0q+MsfmWf#x2vN_SP`UdB_pNsO^dG_D8jp2f2he@nP@lm7<45lG-V*l`!hn0 z(~S4VN|I}QX#=PQ+Z4s@3J%X%)cz8Ywcg+wlS|#kmNDWN2$WEAo=|`HvSUiEW1!C8 zHJLE#IkxiM?tLU1{i294)9Vz? zcE)S#u|%LpE-ZHGFEtg8_IfC5M>&(ZJ!ey-9iF6UW^Rum`3>fL^DFAI7p|3>hC1;c zdBebv{xjq9uubFQ+5BIVr8bU+EZ<(sx{9dsKc7hWYu%lWg(bCgi&D^%)-<|3lF)o} zUNBSW$*Rvv40oaJYw?R%(HiO=rz_2wAF6a>Nh+IaB|M?tsvYuXi)74N`#w4S&0lhD z2Ya@Kv)hXacpuRq@r#-=v8MaWPO?S#Ctmmn=W_RZmgzqY28(%DxPq z*x009ctgf~6iN z+fb41q@=L)Q>&WUwPa0sLSotJueBVPuG(GONWRCQ<6xJNog8w#gJDE<3LRzS8h%a( zI2>a$x1E&N;y)v`ke7}mF=V&sB}Ly(x4!1dt10m$C%3Fs@^tBO@jy9J7g6FqCf}Wh zCv-uxwh7v) zEU3s&d@Nrgq(Y;6l3n#jGiY@ZptM^MF*CT#a@<{MT)E1@ZHOFvl)_R~0((!2GN8sb z%U&a-hYDkb>U_RCED!rq2F>e4kjQJ(!TlEKBFFSn!;+bhkT|F$*9vv^O*icynN<41 zn{(NyQpL8y<+&efYbs?rftdb$%ZB>j!IG2fHx`gBH|om=8XpJD6skANQ7N-anwdLWrsCKDl6vRzoY$CE7vW zZ7%ez6+I{O>>`6Z*atsm5%>13b0u#^p-`b*sI!4hi*ESqZVutm;OnuUTq4B4^1m*R zjV7X%R#H5!qH*!>4%E zsYI3fW_xGa47^-)Y0xif*jtjvZfVW`c8&g*>Jw|4x;6KKzq#+;Y9M-d+j{0KO6Stz z{miOK0@#zVW#KNXjyPD8_gJbZ@uv)%i71!s7;{QiZMc5!Bw3BV5ieRUqbBq{e*I3; zqAaN2CZ6LCq{0oq589VnT`rRleVMSvmnC@W?7;2?+_z_=Fb?uY%D&1GnW5*tAHRXR z6*TRltoCK;`35G#p{k#Dq`zinF8h zlHO>b`}Nl%6!}G7y&nrwah)~!oaZ=+-^xx8wuxt8dcG99HMx!LX*nm2DLt8E(pvt> z9#=J{Z$ojP(K8^3S^0cN!JGA;;(RI!yYas(%!%_mC-Mixlse0KysqlCtk1N%$gnQA ztyGbd%bX)`>#|ZPcnU1X5tE&If;E)Jwl!L#mM0XfP6*E*Hu~H_vdsqrHgCnNJ(eFN zNI6`k`pY>mmzI9%$(SToV=!s0az;kF-Qd1-ino6!7X^le?cRJme^WED^jw{%C#?+I z6`sGW!NNfJR{eUW2B&M|ZG>F}RtY}fF1qzZi%u-fFYkM|pZ&*P50jhtddK54a6{+zY~kcdI$I@~g@7`9N@G3L3}iD{wf}PXCPi z=G?H?Ymgs73~iRN?i`meZ(1@F0{#V`Cmm}xo`8iU)Z9`H!)7N-3c)tierrm2LVd8@ zQ47FdktGhJ3sVI^Axk5t17M?3*ABnkBddBLG*8#3{~*BF4C2SDfgbmP(M}KJ5@qDx zJpV>Vaff`}(z-~^s&9dewel0cul!BdfDpwuS6=F#TCCi1qQqC3?1O&ezg*?NZ3X^n zj)m1x`;-aJrq54BS4EDT%@eU~R}%5tnV_E^vP#y(Q^uI(beUA1ZYH28dgl#|6R1la z)S8A{!wgm+{H{6P3$x)CC;a?NOCc5ECs^D=Ce|h-?>9`%{|LhLNGYk)!B9I5<`#kJ z6+~s8xP$qjtrE5%FEc zkbz7Jha{n0Nx7D?mA=2T0>B7vvxx1GX39DYuI@T(_IagZs-Tx0EoR!!{<4)V$$`^! zU{AW#V{}+yOAAcPkh_1ram-|8xu`*I=GhjrTB+eZWn{Wl?^jYOM_xk6rq0*!ut`u1 z2#+i_X2VouYF8>+?T0Ir%8w-~>@G1auA2dNzmt`gk*1lAz8|$IQl}mo5{MHp`1$~J zPW-SXvtmmPhi7N$cSP(wFVtLq70S^w1M^=iR#;JceI43`%EqQmSqmfA^*y5w^Y-q{ zQkXOF)UAQ}k9f)z5&0a3p!72@8rLmkPgl*xFM@IAE9xmqmqvF=3$qO1-m;W*F9)5_ z3y7t`A_PED5RD--vZ)m_(YTi6Td=~O`zjS1R5Ec^$`Za+IpQ@n5E}S9!DVp0r|tkZ zS)|cH|HdHSEUNi+aI=v^TU7rxDW!X{ur@y0Z_AM7N@7wtm#k4uR-OyPS)xJ7GkLF6 z^EZ}s@@xD4d)uf;tgNR`?m7KP{X(<2m|&YIoMT;a!~Ou?$$YrT6-lk$9nv}|V3+^` z-}vmY;M}haD+RS%RlNq0StZ9|pmKk3u-}RjeD&est|T+ylv_}FFcj$-7|QTuB73k8 z*oF+eSm;G4mc3ro%n8Y)Amv>e5LdT^_hrw}S zx2rMcvJ5Lo=<0yfS8cGlM?yGxXclC1Wape4OKa4#Isok%YW?N5^1&bYH2zXz@FU)z z!7?& z_q-!{)Y~pf@)ipMCQrVkCg+f>}hl^Xm8yg-oLweSX{b;a*&6 zBXuXV-QCCQsk#QznRerDyhhFJ^OPzhT>J^Ey=pHl+<``c$(rFX#?Kb6|FNkzLZjFU zKDdQMc@d|?xCZO^_1I7cm+p}iPaWHvb?Ql*bS)4AXq3(pzn(w-*v|TS<`of4wM5p$ zC7V|LyGQvAwD7VM>Zzo3Sm?`G7;@>O?>BoOr80F$5qldS*|DCe0DC&huW)8d zeZ_w;E;02SWt<0;{e#ZhXmdSDxCzHQIgDc||D$U%xgKs2i+~pm*h-uoh-j?%tLqEu zh4Y7E{;mbP_V_*o9#e~Gi^Y`2)5_@iuR9)ONqhik{vzr@ecYv2rCZ#KP2t=z{rRR* z0vSHGb`3k4i_m;srw|D2gTO{>J+%i6h!CAIo198oVEWCQ<^^#6>tzpCEfGkN%io?N zYb1F%oR@R6&T@YU$-w5412SO=AX)m>KK-#cnp|565Zw~zhPQ58AYd`+o}#(gAy=N2 zAo}dF+~N|V+0Awy?Ss+ZyX3)}%PrvK`-q*){C;s$Q_bDEQ+#o*VDtk3ZoR@UM`gp*tz~g8z z@IMXyAJEjG1?io&%!h z#Itn=W=s!%0*QEc>40g9a4l)wjkjaw4STW%s1B?X&UO%@jUBXfvNRTNph%$Y8p`Sk zfr?|-i8ro28q)ag4?2KMGVwrv$bD(3m|s$gM;%Ox3Lwd`yqB+mi)KfA z;=Sb!s@jr}&SuU0DZYu+o$k;a2RGArC3DM#P(sKzi_HZ+gx#GxEM;vEIi>6#q8#vs3_#1<=zy7dU+*_l4{rdU_rk$?bWou2l6ShkLvmLXkvnkXy0>Gu<4?OX%@ECWltG5&5 z<0oWm=JL65aR zI6F2j0p|FpB}$;%JVNPHGHPXrluysI@U6`%#qSeTz_!=UP41J2CG$cNDIO=R(@lrL zSN18(ll}G~U4Ij0{xkxZFU6_|6lXub_J>wuDy|Mix!||g|4Po{G^Vu{3oJ^&QRhRK!$kGDqsI3+OR9lqL033BE2nSM5+?^-}$Mhqa z8I`+E{wsi@wn>n3?#?IythDf=|LlBLceZxvZqYxA=$jWo^P5f?9IHjTKGnWq)0@qu zdsjyL#*5z{d}}?4$-;|+0MR^eh$|1UT8ml_h@i`Y64rm^L&Z2>|%^hJL zJ>Y3Lu&HOj+%knNL5+dO+;ljm7J|BZGQ;M><%!oEIRBZve42W?lVlFI5UPUx$QnQc z?o*A3)G;?VAFgn|LsfhguP0zIs~S^P1uAOir@%ew{Z|coW*&72+~q+nZO;RoUaK|6 zFB%wxRJFnMWXM~~0@Vel*%UxzMG&yuInt^dePP$?Fx`|AIQ+Hv=B9b*s)Y`&gyH%5 z^G&4`o{N32jumD>c&A3Pf-G%)T-L%MG(N}i4kE`@N>$(E*H`2nv!GDo@f51E={dl| zDm`DbA@U#vg%MsJD-}p`#a40;e|*DWoPH7wLK-O#wVP$qerCBlU1jJ~Bau))CC`kK zj?mV5d{PzEW24Jc=M}4j?T5b07S`$3_9P|Adz1+2_?v!-7$stvdPM4c{dpE=(Y)#* zCleVL2eKUfH(vT0zt-$<|dS`D4 zWxu2rmT<#t6h0)LIvVAC#h38)I#o93oLNGuIHZgas>N*9m-i(6W!90V&LLlR5vn}F z?N4r<(BKfaRIgfGK~@Q(QW>7#eou4(PYj{+Qhy~1k127QcvbS^&m^gucW!rV+kdc( z3fNFw#-@aW#(bG|ofIH}dm|N_hYP~&q{B6l;25=E>_}FumRCQu@R?i}^u2Xs(e1`BT9Li1L4?Pt zGuNBzg5XIE7H|9B{}#Gg&05aLeLg1MS2Qi>&xzx17V>Xff{$tl36;rm{GObCl?v)e6}gNSR1kxKSb z4NlOFI#h0Mm6S8s=;xb!Y)%A;4lg} z=ZLV9O!Vngoe_>3vl^9pILQH%n5Kx74_URV`^AXe^%=xijW=*jwE*;X-+T~YRUMkQ zEPkD9xpXgFlOz%p8W0ig2xD30Zivd4#h)7^;j0K5Gl-vA=>( z0)A4%Sjutf#&)dOCZfeqC$!^-2v*LP@=C`-9kOAb%K}+^1WX?HOg0j;pmK$>{OYp{ zb)WyBpn;g;zxR+QZx#@rg2o!(5$21u$;DW?>IPB~BO_vTxD)~M-u#GbmS=@M=*M=e z(w>|%#21IoSty%Djo@}tO8O~(n)bEkv zra7LDwTj?Y@VX!b-+E|cr|`ss3Kbr$@8bw;DLGTP{H$RP25_~VTATSfvTSU67Y_Co z;pj$UU5u3da4eX)?wLXtGZ>^ZwgBFLly4+BP$rbUE{2&V$-N&SunC?IZDTh;?sAh^ z+DX zyXO910oUmi6R57Op#!fGhSHMF{r*g5CF}g(vYvY+I+~-}gpR5(&H?t6Kr*s+e~)po z+ndln|4qpr3qDus0Sm}~+LEk48b>|xIP-w6NYD*cF$mww1lmF6r!@D+f{PEJWTm4JxBH{L4;(jptasHc&(*mfc0LJu z9%J+}KAPsjOQk_c8$i7Wuy_^QV$?1H1uShecDKPIJbrK~?9W=*r*gtlM02!gHQMk+ z>xT>9X(%5-gEB&g-F?teTJkSD;UDq$jT`i8SxTF*Rz&bIc4-rPV)!LomCb@ zQ`<&2VCt*BLcP}<3WUPJIqff?iu>YpoCYf@By=B`13Us^weI&r`YAw2Fp@T7sL{R( zGPZ9#glnd0A`}n*B2bPrXLiKK0pGxAVAGa#Z=jElX1uNIe7CM=Y`>_(Z48&9&t*xN zgC-EPRV#kH6m6gg75fwe_jG)`{B}BNvk;%?e?Z2Ao>5x%_YoSa4?82of+Lwg$ar4P zE*4x6a6%G=zG^iQr4;=FlaFAhVhk0KNU?93xZ~*$ma!=Z(;{bpp30gL5k9RNk6mu9 zGMpT|@e=|r=7`Xz`_a@?;z=AU!vlYo^@ldS(t$kXV?20#}K;>6E? zyR@)fN&QFTn=J~pu;Ayvf7Rh__&cOntm?qmd+Ms5ULW`ExbX6*+X?;OGJ(1h>dOMC4{jc<4>&ymv=Dv?s7Fi) z-CpQDop|7!8{kj$nrH)vn9q|ka>$`C&`xf4Ds3uWfE{ax$4CMP3clshVtIq#cNxTO zbWP7o``@;)=D=I*_Ip@e2c{$7j{{F58j@{NL)@495t&f}N^0_+4n$GK+wqD>kC|3b z)pWl&yjGkh@3!)i;tm~nI>R6K+A zw{EdgUaN-|oQGErZnDYR8FO@7qPKrxbdv1i{&VVtVgZrVSL8EW|B`~hl?mmPGyQ!F zyQR6|S@0VQHsh^eIHt3(w1jJUl^nZQgjgBz&T&xp8`@o5Sm;Td+}hiF%QN6Ax0r}t z8mkrG>?<%$iuq@rCQ&_*m4;-VuO}kJeO=}rXx|A*()^O3BHvoZCxlB#XF*cDkBy{> zhWnpQo8u&?>Q-xVn|;8=0vZai7I1c}mFjiUIbs8&4=fR|rZAH;L!KBSL%WXEZq3T+(jy%f4B8Sgq;;2la(K z033Ok*+S=Kd>UM<==fa=bvn`fm@m!#2hZc9Ex8*$a};N#J@Z}2=V-PX**U>IkbMSB zhtiB^00R@z`ckgHnCTdn-I;PSlf)J2MVeWs_7mm(EQ1j3?Lmjrto$(`dTZWE5->Z? z%<~Cb_tYV`&~eTq?&Brfo@4B0i8i+PJ!AbVa>Sr}?Bv1-Dh9;0TIrk$Q#8M2=Q5a9-l zJ#vn^V25&(4Tr{^4}bno zMqm&sPdVu|7Z@L&0-B?N0mqNW=H@cI$PG93?Cb9SBy!|1+67S6ZXP}QKu^!T{6`!6 zM#)?0{9El^(6f42z@*&=kMbc71PXxM!a}V;dQ_!y+`ll{Oi&*J6Ed-8Moz#zej?-) zC=~~(*)W>!ZJqxdE$gET@pw?AWw6GI%6qP;*X<6VuDy!*0`Pyac_jYe+0btK-ejKv zTr(7p5(&Ee3|QUG4=)yI#hCecFXVypEQ{UDODf-_DBa$OPN{sv1sN}AZxpk8N!ROt zhrk}F1wEi>ZBMje{E$5Wx0HRK1JD>c_@!z=&WT|V^8dLrl%RmwQycrP9T`ncOfZ}6z6_^vxcYV6FaE_bj&HZDgbS>R_hhz)4afvODN;I|+A zb}`?q^oHWvuP^gjD3Vo9nTKxBE<3>ESY`#aq(|M6StR-f&uWp3T)RdtV?UK2imr_G}YJA+O#^|Bfc^~*)Fe$SsTv1F9(saP0QYroy>kxA1T$!t|f=Fo1gdrt4d;-3Sq|8Ya^Xx9s`Z zKCW-9Ki}AegOyD%DXJ+2(z7juF&L$*T7s(IbU1cq(-b&Fi&?5FG%?ty0#BN1T}sXW z1&`H~PC6RJ;b_@98E zK$a&1WWya({jZ@4$12(XJA?B=kK}+Em^uKv=yh~-h|R;YLtxE8SK1Bh159mBAxO6n z5C^E%_r|W!IKhWfF8ead1uL^%koEP zj^6jRe0wL1UNSx4q%14OwMm&@vcZK@M-otLe*$)|!U&!#T*@l{2^!Rx-n*w;I_`C zSk`k&w`qRekv{Q{UGpPZ=YVoP+M`2VUzDWNK0#3E)|BrZr{Xy00 zPuW@{%iipM=jTjZGM&o`Xq=60M9N;coYYF&%fOid_6b#!g;qMn7*i!>_%N=nHTEqt~YRrxDPEf)U2oJ6_t+%&5%H(5TqbeQ$yp)th%SmtX8Gc9rEzw*lWuUG2p? zZ!-hwnKLl&EQUEv_RSQnpE_;@B`~39XEP<-o@lI1cHF%1M*F+TjUHM(nLb~_v^syP zY*_7H3(WOcBS3eC7cIcE{wO!&8h@_oy|WYQx^*NUzv^wb>H^U+3_&&V^wBZp{}t41 zPeN)}`BJ0i9S>#;H%h!Wgf-yzd}Vy2%*)&`i`rlAvv+tJEQD&8ev!{Fz8`^_;`BRtQVq0~@E-GjTJ|4^EnJcB#=jAGsY6Z8b*hS5G>{O$ZOD-M2052BJ3 ze(h-dF~^$dfsH^I6@gP823rX_1|s=2umfv@<|YZtxN`JM;qa^yW<-;u`h!JfIBs#q z*5)mHq3xY4cbk&Khq4p)?uwR07+FxBk7{ z1*AHC7PV?%!Px-F1CJeh`@;U1|Ni=r19%2)ukQE@R&m+zcxYFOjD1;DrQwm`_D(tSAIZ!c)e8n5QrNs|L)s)99n?3TezBo@AAu zrV7xTme0kZ1D;DmSEXFk#S+*}gL=ZH7kX2PxC0u_0 zjiy3B5DW-X)?*Gn1O^*BR0@T`lrJU;8ySV4rPXk|w9lIn9B@TA4RC4-Pc+`cbp3au zYYwwA&0a(fC_;Y3o z+NkD{^Ig`o1XJdRbjUK7>2b>z{~T3isVc7g^FBmQFO31W*B|ioA+FtZnOQdaKPILhk{VniBtw8-d&K-@q7j z82*0*5x@O7@$^DYt}4w)|+9Qs<=<_GGiFrKN53zIpGNfMM$I>I z)(IybV&_k9I!TZvwp#>50Q!{M(}1V=159*4it)(_Uz$^@-*S9kV~JJ|I>!C$Sg<~#5VNP6tmM8>av0~q z`h%08`quq(H^7;CjNOC5>gV(|oyWieq6DF1i!0uOCTt|DC*E@6e#QYqp5JbbQ3f*} z7NH?ev!v7Yj7khbTcZEJccA~6m>zu-Fe`C(s%<~0ZXe$b7(xB5t<20jIbb(0$aonI zB+w^Mi(a|@L{1<~xww=8<#Xv!1vGO#2~cLH|C0#l?jz9kj*OuFhJeF>9-TU854Y!7 zWOLu)w-N9XYG{o>Sz~g-wM!+&EtaQG0_b?u+}+JvgxSH0j_hJ!Jk-mH-d$+=42RGA z4;PC3jC<^^^^i_%IWHhR-V&NTU^6g@0;?7i44?nM-|E{2L`xo&D$$$KtY8)xoU-Gf!*lejbC{=54M{p}D*B;W** zznI;2`gMCqrS!jOaI$6_G=iyoV+T$ZUXI}sFwOcLb|F4yNuCGw^?fd+cgq~tQ%eem zO?(aHe5M}&`mwtV*V`ML8*&h!LsZ|v8iIw9Z<#ogfzSqA^TupD;s5; z5#Ct-zv&YHB-b|gOFzFmgbM<^)tzL3)qBP&0oMT6SP~FI6Z$PZN1P2HZ5_sb;^#2{ z>)Owgm3JZ)?rGAgIM$V3g+!W??>S?HtC!X%oh36O(+p`k9l3>$lzcgn{r3US&-$}) zAA8Ug-Vc2wAzWYYo>3`F8|7L>%=6%>qE+3uNW3Uqq)Hv$gZ5et{m*&&ISWALwtnJF?BEuv{`v{QX!8exWhyoshG_2D%nfd6u6Q zQXepJH9fEFe>-{WCwQ=CT4S=jH)hdb`z9J1z=ly*?^kl;V#J`)72jWLDVLxxn_pY4 zI)&{9ZI&3geY}r{D^9_bY8Y+^x5wN^9aQsn?g#?=58iee{iHMhp;o!^oxv)7Z^mo5 zzZ|JmzIf7n5n1r-1f)j=C``)_^%5%qA()<2IUd|XKr6cK?hEwbsqJtAVvVcrE8rv` zAQ(WTWedN~fuWs^_07yMPJnOBoe^r2E9VjjKA8v_*RAW1PHdVlZn%3c;);>mMZ4j3 zn8WVNm0;@0{^Q|d$_jvfHa4dpMsBz(Y;g=&lDF*t`OSL*wCxB%qnDKJx;+snd|5a; z0*Qj?cb&ZN0JQV=jkA8!Kh%v@TX(p4jHzE10&-SQiH#Cs* z%r}nV{m*al@nwjHw|ylV|0?Sr+;lykAZzQvgSY5Pmj)PPkle`GXMciV!tKghDN4l+ z_8Y;a)14@<^g^NdY|18d?g}CzuGJS_Q4 zM9PudE71Ke0ir-UtK31$txac68K?1^!{46y0dUdE27v$<%3qaqq<;RglJqvvKP+}= zJstm6_ZNS`W4zjgo45>Z;)_G2C=l8J)16UWu-JvVTu0s>#d5;xLGE-h+NUBx7k0@T z{MP@}LOaCZN)YBg)Jm%!pdG|zY9x4QRxJaBc@FfU8;2G#sE?S*ki2d-1GA`bpcxvw zp4^ZQwC}%3S;~9Gbd;`Um|ra9x=_RY%R}0CXH~+Y#Skiq)GpcDwh9-c4ye%d1mI8g zOEmHd3q_(U6@ghq{?ZMbe zeJ%&%Vl~{2KX8yr{zqWYv^@cmdMKmh$uTHuR!ztGlsG-Te8N3_J+y=kX-?wV{%f~q zMYTZJHFQEo5`rGs;a*Dlrqxm!Npg~-NIYc}i{vF&gA-;=t)y5je7G3cQ{g<-GyO-W z8=T>*)Fh|DupT%cCT2Kd#!YGtb$~xeIVhxa`UGaf6czW#_q!pDcSrKOBwSu$Wf^W4 z4`>OalGXP8wDa;9Mn=Y6JM_+nWEtn@YqW}Gtv4Wa3xcw`0YmI^)pf0LBP5B~v)*Nr|bEVX}5==hd3p?LuF(woHH+}3BJ_N}A1p3axW2f%EHf?9b$^sV3JWNV{*lIi1R|miz3YL;8C!Y^E4TJY%KlrPha`QI|d!j2{MOu2&uV=d5Q&}>B1ImUw`r5G@ARM&IpL9N5A)gnT^jZ*2ryIe23)b{r5#L;U{*ngz@GB5Z+?R4Unk>4ZrpPI z!^hcO=)c)Y+A{vDdbIAneF5dqEp0zm+^|3+ZN5P$#lUL+=O0#~7BlLU+I$0Z%&hpf zBWAas)U75$s%VQD!q+Y=*dAtO3qQ!PLdkm-=$jXc#OY4Gh}t(ZdafMZ^AVUzNAh~S zzH}j2oWAZLQ2F5o0saw}u&JAKhHqN?nd_akXQsm^n4Hhvr4wfPDR>>TRAwNDbK2io zGsU!-0hll+bMWH3q{Zy-^Vm;~im+2=-(NVtqS_5vrOYl4V&zcUiLQbr?~AvFL%9bA z?@gV;EEW=X_-|uCu?6CaD<&s(<?nt3ApJUvXf( zoAD<8Su<8*X{z$rnj!bW@kG>*H@n*aa=kqM*P7wk+BI`d1PuH74>0BtUz`%8FqrvV zGD4YwG2|RbRd=HYP)ui>Tz+C1* z821yX^!rYqe>Pz^x43cDUyA{!snj5Yl>ze&p4Y*C%298t@mJ3kK_R2r2{ZKo_H!`m zI!cYe23L>|J$pZ`Ob7X8Cm{kiximI-R<4@#eWk1tN+ONY(Uotw!CX{=FBX1TO z7TYvmVC|GXtjB@tl-#-WGg8AEcjaT}d$RabJ#MK(|IhRD%9{rZ{9u{M$&Z zc71U0+S3+p!4+)GD1I3W4Pe)CcEshqxoDLfNvS1yEj8ch1geZ3)z3|<8wVx3KFwgOS3Jr@NEehgCS8S?j)TE#u@rBZ z&Fm~)D1xIK4vww?7!g(6l~eswty5)B9IN%VOBfS0h{sqFlN|;)=>yFl z&B){_8^uNaVrqPOl)mcJIs?UUpZh+W>bpQ?vChdkZPU7^(PhCOFSVrDE4$5g?!OTq z-Y*q$eT73HwQsS?Ce|U>5p_FYIvCR&a6Z&>)2&_8CLUZ{YWeK2tr4|<;j{emYSJwv|KkTVk;5sPu$_qZ2{$nmGU z_QF`F5H-JQktFDdvdg!|nA{Ml-5M4^EXPYChGhxU^IiRX*eCCA_QvREf0bXU$g?*V z4Ch1x%>^19NJ8Lmmgq5O!YBgEC1jYI$U$`K|2kB8=1P;03GnhHk#tZG1foUMAX;O{ zg4&*PfGay0Z%sZ!*_L)3{yYXw4Rf^cL%jD6vYF94KnMDwn+P-R%g5y+j{ef-E3epb z*liQnLW7Yog;D?Jq!XH+S?fpya?4zn`|y1C4tRcjca0w#`;I5w`FJCHYhU?j|0rPZ|TsbJAYe94<+{(!*!rOkGL(IiEdO=+-4Wh zDdT-EL^Pk}XQG9NiB#8dMmeFE<%LHA1xl;8``g!_-=coHQ)V+b*fcNk_7JjP$ z*YVa+lybU(zw5??Lc#G)d1p~6yWzp|z;Dj0QcAYwf}G=d&fm8@ue^>U4WK9nIYnzvhj5(CWtuQUvWm#^+#gOW%01D? z1#cQYIh0kh4r#W=NfW>OUePIW*&Pq$+a+)?pPYj;@sPK_fVT38QEjR9vpphe6W*Px zC(t@ZZ6rA0%MxU)*~o>8VScoUKK!<*^5Veetv*{@zf2dO-0AJ^v2U=}n?R0;xv>$h zmv{G%?WyD^F4;w5LPjJ@+#uVshV0^303THVbIzubjp|y@F>iq&A>hcN9MjLUO$|NT zfCCtJsEq1n9Ka9ekyFIXEmw@Iyf-rUX_dYV{*U&~{2$7; z@8jyKD|bEVqJ?DXaV15RRMu#rE;D0|~kjrrlPz7F(7nk-o(NwQ=N znURqgjU{0$+2;Np#(lq@=WlqP^9S3Q)68)?&*MBk-_Pg$ExC5RXMUX;PM$n&hL(;2 z_rHGr{Z6zLrO>1EVbSdwi2x|A`kwtUm{ZWGTZYmwb+)gUg@daNU2%1h&ZCA!3~#mF z$396?$c2;7&yh@4R!Ey3o;38(Hj`MBY=4F6bWl9?X;Jsppp_MWY;IStf;w|$(jrfu zOu4-Iy2+P>S-R`MKk49n)!XjPXUiWB^zH1oPkr@zCV9P=h|2FL{@FY%g$wR|Ys{nN z<}%?GnKM76Q}cwwCh_kXXAqIa95;l50Ktm|$Q$EH z*Cc>ZjXP}pj(0lr=FWL`3G(>8>zeyF{4Bl&x#BDo(YlwPgDp4H**JJl(+(?13^wk* ze&_o3KnL<1n*)f}@jAU-W7W6w9OY^YH7@kN^<{K;)_0`T`tMag&qESMGd>a<-mXln z>+bUBiyL{=S~e*RR+3k?^_2w1FjXENFI|{)yMX7V!R*~qOo~^=;ctf=J8kD zRSU0cy9*ydURb4ky1P`{DI%o)PH)=CWC!Pz%(+DN$ct22wxw!B^B1W$|K1E^-UpR} zrqt{z%OMz-LILjH%@3bEg79OW)yXB2{m-*{dE=9O&Z5+Vq~?wGpqoe?^~8H>Htg5)E?X>-Rw`@d&MLs4>{e{h`l<(A`Ht!e`KHY z6cbB%e|4=0HOZ;rg=AX#fBnAGG!^cu<#MGU|0|fv7lFDz)Hd&@t0W(^-%wlEllPhm=78(?0DNt6$O7zo1>`}kdN6I> zKYr~flj)2VUlj~&C2gm0E$$aTP04sa@184PNSeM@KY&QggR)iqg%eT`R0do7;XIXN zQAqDaA<#sis>jb|tKFbLKr!=`YkObSpDPm{ekt{%!lal)e<^yI7FDMK3G$2G{lCUP zg~?~Fkqh3%?1*+xBHM_st<_Ni_$S3?+*b?(!cF2K$>u+gJqE z#n;L)SEYUH1S)v0m(|&UVA#lD>f4}Nl!=Wzm0Rw=09ZMys23DCOXhXzzUjApPVkIA zHiI)s8TdIx<#}c6jo*D%f-mePSx;+UsAcw zUOj?{I(aOz$f3~OGhQ_7W1ICRP6vMd<*2*r zfMV*F>zLDTQGeQp9b1p$>QTP>>qn%ptxO;CNfUpA?;@XO?%8$hUJ&c{4n;`FTZ`RS zD-8~{)TBT|kPN38OO#3S=I;+R1NLOLDho^?{V};p@j_Z6Ahv5$AELr`{C0 z?I@obRB?tPllSl>mgqN200)_SvnIvn76y6`_?4dS16iC%S^kH)w#%|!oy4LCv!N5TcaPbAxHFUC z#%!Co)cZE#myUHDY0HZGmh|Hm+FmxfFJC_Mj@aU2_CSKUE2UOS8>ly!1U)F86frwG z28OJN^^lL5n9RLOIHow}Pu(;WF(7Y0!auWHB+>SAiuz^T-RzCuKE_x`duBD*%d=U% zs_$r><*t@t>?h;9?T(|wLu)TMjq3cBQ|3qLIil9@WY)!CFa+b2##FMAwJoqP zr5A=B$?-Q|K>9FIg{**sx&vMx<=d`&@U>*NE*6SnFxGX{fCFI%KD~wu(KFGlV3myq z03*8T1d_-)sPo=Z1Dhcz`k$OX|DDJmJ1L)K!8`x$O|Y${rR5>R$U2Ew!=+ltEX#5m zNfHy=9zg$6R=4p@Ba)H=KBgh6RdhBg4*ilK9Ouk)Z~j8DM7*5vh49;6yRr-0+3)TN zo_yezIHopz{is^hO#ze+Rg2vIjm!#A<`@OA}*=;t=1v&*0(cSW{pcH zVCcN(qB~r?@p4O93o7oeIwKSp_fYf#oD>hh_V|i$1A4PT>t+p0H#BvreXW7kQWnHK zn+}%PaG8Q{_?R6lOk=DV@1V62^Ns6<2!tczw+tOj{UB|m_Oi)1paguDDJ?odf7(%{ zg1FnJ$tsm6$8<*ab^{o5DIx>t8{DeZh@dCC@}}q?NJ9@`<#xVgXPrE?F;*=oa$nlS zk;&1@X%DfWSsIXCD(nQmUI$kyeo`KWc?d&gwZR;C;ow1D9@s0Iqv~3^VTIU=BH4V- z;t+XIV$=Ep=kE8|XHaEVUdKS0qv3{s570)JGnQy>$&71=UCayEHH#TjdM z&rB8uJPqj>2Ggc|$jniw#R;?<6Vx@r4vCu^zG{T2oTYp*(6trNhLH8Bwf`KuI3^!T zfpF>rF?s!Dz&ky1i6osQy+;<@Y;&7c+c;%{>wGq6QRnb@DW^}F;*S&0&4msO(Um^n zeC}6wVMYDAsF%<|3{niS(;IL$64t)m8Pw*#G($&*cuY$>eC14Sb88z+DPtEDsv;d| zIXNha-JWj!Oi7&ser}3gAP=s|Popy)*AD3e$z@*3U{80He|dh%)N8u}fZu*csU386 zt&+HKRAycPCCf4UC(`z?h@&EIf7t$!FIU;J&fiX-^0)z#XAh2`w>EI>>SwJfAICal?5oksMnSraSst z$<)=w<%4~*p%K>8u)h(CeUbMakxrS{`9py(1*~0<%qc?n)r(_gsJ@wMiI~(RN)GdYmwm}5{milKzra_ii~{pO!Sws z5dj0P8+}!uvW`8+Vw}9Lz5wP_p9(nzP7d5D_=vV=yEa2^p~_ej3<{@hY?54DTu@5K z76hTC$J46mLO7Ag|8Rl*e-IeP=6|`~mc~kC^OhBjOQ}mZESWO2d>W<{PH?ns7VpH7 zuvliC&?9xk$ncQGsspO2O2UVg6<$1kLm)T@z!ej=GzEpEZ2iCkAu+;-pM}4_Oj|d) zQ}`YFW!g-7cJ}k<#nNz_j5e)UvGuan78bGwujm=^!km=|_4MvX+FM#=LUt}y$3?DS zV)s8DY$xW(3*7)B$>z}Eio7S^=LpP;FP{{*a+gfK000kw9*Hgv^QRVS>4W6IgnuJh zfp|%sFrp-{-&I_asc7==ALDH9h~+)Dg1qB`>dENB`Dx*MtTKksoBB=OsiV+QXbQ3~ z9r>!4X;|UDf}O#ZQ93=`shJ0TBTb#H!`3F+YtGj#Kec{bo*kx zK%?=MmhA*~5pIh6<0xEh{A!cCCpCtPYMGVGqbbu|X%Lsk|6aVpL`sLw6EOEr zjdEw#cDn-W3obA7p0!ND!=-17H0>cD z^mS?!B;rq@N27GX_{iB6I=@{wWXV%B{cyLwhFcl|s=OWA!80v_yy96holb94T-w1k z280xuKY9lZ#J27q7Np>BJlfK73#R_){5;vQ_}ZKE29lNd<^O`;*kJpN6I6I|t_!+a zTK-l_*`ahW&AA{un^(76c7f4bmn0ncs;Y5w3{$WVN&%^v7CkYm4=5VZ4txWs-n1ow zz&T5Ztx3Efe0OPN?Y7p3b}r7^vpDEN1QX{=g_L7dy)<4f>~;{UV0L!4Dcnt_zGvWt zb`l7x8zWQgho!%w&@{{_G#MJ4fi~8(C+?jCwapFSgp(&&T2=!6y5)BE4P`kBxvuNJfA6>dm-qef-`|+M*4lgRa~s>*T{WHe+%L_`$wZ(get z5nVSYA|g5a>pJkCCm)IL5E0!Wl7B6!>7KGZN0OqcMccg>#Fg9BBq@0(M)}u|AGU^i z*4wtfc6ManzPf7>q1xEgqya+_B%0h3=28<==ThmlkG;=BMBmOfI9cs@r#YoXBZ02} z=h}Vt?Ac1i&o^Oo!jw0E=Pk8Xmm0P;$_##{Q@Ztx&OE}1l;3HsUv~t#spwhvbbc^u z=%1EERiEO&PhnP{!rkj?Z``7Lm-f@Ke<+b@J>;4&lO_^16R_o+6!bV8HeWowQvw$@udoa9jwQ@%Ge>vcmo zCwV8IWcB->%|C$Wb4doh8=?~~$zjlt>Qd>7_auGmw-Jw{plxo zl?U9qJ09Qt-U9DkrsqB5M@QPi*|Akr_qNrGp(g?FvkF%eQzo zpH$Fl2O zc#$}cTK)SrbivKf23o2y|7Y~a4d;ZT=`eaEM+c=Xi&oK@s6~tT0C8wniW-70>fcEqT0D_Yq7%M1 zsATmv=__fHk`;o%^YOah9tk-^Y|zThf5v-dA}^nG-azTd&#v8guwq~SUFf=!RM}@n z`N4l~A$lz*94i$VHkeDNn1cvZ8ZI$x+8Pk^z-fVm|BcT(;8kt1`z)F+Kfg>E26-y| zCLU;XDOMRumbh#<*x3iq^C_az<6?8$0V!^s}m}Irb*r^2xIsL@&zqdrZ7j?5v zht|C7k!596nF#oZ>#DU|>x)nSug8AQx}G(w*xMZqG8eE;&=E4*5lemK_U|`(jEiwn z+mR7YSom{?;|j~E>%|#~CGEdse2{9OUN!P(RGid$uCgQ6{a?SZncjLn{AbX^p_RV$ zw!DAi|8ZVSfEriVrQ2i4Xm+6Wp`r$ewL`ai03sMT>GznW4TpYlTOi;e9*4E zwEsMaB7Mc@dxwJfI8Ivb-c(VQm;cq9x^ma*N5{2(t?qwc_71hM)0%lCk|Q(nKYb`W zYWAiAk6rYi;p%^8W{J7&)S6#x5L3i?<$jfBJHe z_5b&o9}m9yPvCSu`ad1yMJM(DX_Hqe{~tWp|1E9g{CQNU{Lrq$?ykkx#1piGtRoCskrNL)MPm1NUF6}wdH zT9aKHd?0!3)+}PbRpSP>NrrHdBJ9+N)h*NaDAsOijO8+TzFl*9?w0R;G0prS)D9(C_OmyR)6C3SqHna%aK}P;s~{Vb^_^SkXlh8}+{kLO1b$Diw(<)F zZLV;rq0h;Pb~(h9Ic2z)hF`pkXQ|!qngDG4uVg{rG-RIFOj?byi1W6I%=ZW6C-YAN zZcKY&y*EcHjm?U6i(RMIgD7Y}IIZ`?)pHe)x@PHCBfALQRU1A=YrHw?wi?mDEj@ryw9`QQ=PKST^Gj$v<~nJ;B%ZjP44{}|0x{PEoUfx9FYz=%feqbApLs}mgc zn?o8U>2kHFPfQ(UkG7|m(@;%r<+-cve&;*2kt_uzh#abjd9=4}4t~8imVKHp=JC5` z_sFJDMv2MBRL7)=65T$jAu}l>@v)?EU}Mvj-Nw!54^7ot#hZR^n+1)EtqrD%JT$C@ z@axr>XAY#i1P>4o9AS_)BR>Lnd=9txIhgp;&ri>-*>y_nagb(rQg-c<1pM(Wy*8f~ zPTi`h){8B2(ajYNDW5N`R`yjL@evUV7hg^<2uIjD`tRF!59K_=?$jhit_z%cT7DkvXM%|2v)SkwL^tbee_g6VH`WjM$rr z6-mGf?J1?=7d78 zq7_BgXK^L^4UX^gdE51T6b4!LrWzCxCZsxtkW)AB%ftKf3MUeCF0Fz_r$_Nhl zM#bI;eYQn^$MPl_$fT2dtj4)#DPnBzo*3EiWqe_fzk<2T_V}-@$TBgXW zc(!B^K)Amh&rHh?A&OD$JW_ogBR@!XeAWjIqCsY_<)gR^lpVv_b$KLip*y+RC#MPe zHq_N02j31M=X^j495$qEhzIO!a(PfYHp1j`Gr0k!C91VWU>AS!-m?f`_k*DK<9$jk zKh=-EuQCBt43f6y|^Pzu>o;tO=Q_ zamZ#@$%DQz?Tw=#G)61$d}K}?ANVG#X34=DQ!)-On}4O?uUVuyefV52F3d)fpfv|O zG^ko}=^7W6YjZE>IrFn$u-AER+gD1Z4qK8y|2qY9&#-0(YD=3^5a3se$ z<$e4kqJXR2_W|$}ZowbEgx_d=gS{Uwo!T}0nvh*`CYYS6jS6T$7% z)n*MCL(}<~go9`o8Z-zj;=ExZ$7nDWy19=>EpxKRa%psJO(<@6&-&EuPc`DBT%O_Lj@3W%MC1&>3CtBC&HwrIq_0BHmd7ngy?82Pq}ig$qkvw zW3}dtud_|<>zuDm?W$U~k?*!G`Q4p7~N zuE~?5STQN7^MRNdpp_3F!}rGT&><>KwYwQ|G1H;Fm8oCKQLy4iPLm zM|dQ|}tyD>U_0h-Ox*0TxuCcdG~Pf$PDDoF2?(wxXje zlpeh!_=XKf)l-of!2e0<_qwB}-#Hv3GL=~~rDxXEY@#PrYdLvD`7BmiT&GR)S~8Dm z)Ib_9QrUXq`LvUQkh%Tok3jOK*U*nCUi+*^(kOARmqPBlj|E*71IegL^-uP>gbNt- z_bP1XAb+rvid~x{Vplaw2A5%DbJ6Tk=B!&&qo2fp=zo5Ot2@6y5;bisDH{CXWsi|h zG6WgaFk0v*8J*5L4T6V&?K;(FzPZQeV)KTb?~ol8yB2(ZwYTZ@{g#ja8+b$!8Nu1T zvBgt#+(hLs*(}H3(8+Z&+T}qeI*FAwM|0gW8VAhuDG~D zjr`Bv%EmalEkG)L9pOxQD)a4&(r^JnW^d`2&2m>LfK6=dIy**Lomj2tw9hg^3jQn} zFKlM+Ckq>YQGCc{(AYT#e1+xSjEPdcA<$eETgQ{?s4lz0=yA`kd>%7};rq`9oM1W#ZkD7teHhm6kF6>4Jzk*^q~8 zz1{r#@RL)uXV3p;y>w}BhC9_(*|ZG&WlaZTGSoZ@CyI3%KH1rShaF}mzVuEiJ)jh3 zvsjB4ET%N|;0-m^;0|3l${R?w>DvP?A6=5JEYN7r?l^j8}K8X?62P@G(MddpUboHw3^E^FnWY8@5)s7 z;F}YG1tTU)k$_&VMZO zzJB#gmKNMv7eQdoRu;;PrFEaLGuix*%;OP7Zc6|MXQ|~{^7ke35^g2u%rny*gR^5a z304Oz$)axXS}RlsD0MtqA(-s2{`WTrm_jVus;yEIU+p;o-vm`)lDp}ITsz(~F4g+x zXjPekfwcS>mo_`AuPjW{QGc^s*Pq5emc%bHKbrkIIBK$2(VgW)Xg3_SJ*rr4zxwNg zg_1fqYiYV_i<$Z;noX-{+m;iOvYX6|nB{opqPep5rM`FJ}C>dW3?j1GFS&!>VS08%W<`xlU|MwCO6FbNV<~_`s zu6L0BAkWGzneC`dlLJm*U^mS4Cm*#6xkHgxW@KODd6kZBOE?qCA8?(*8O*|WJ=A|v z^-=W~+m@j;-ae4k+CVazlG!DT;~I4^?3eX0TobNe_0m>-ROkg@W>wOQy1gr5eOb8o zHD*c(+f2@Bc;WTL5bvFCXS4i;0{(HpvJR7vkY{$O9+J2m_YU8(IC!pjJNA>t5JRCs zzU^-WOHYj_f~$BD)c7NGAScbJw%J9*V(IfMsed-X$Up`@hqZWC4OZ5}$0Kdhv6v!l z{z{#J0ySVgvuRxTt z*r%hPUnnX&d~byuHv(+2u}ycxSdsMJVTzi%I=FZ|n`69GyR`H3cu68JC(}4>p>g-% z&c#AUfHgJ^9H+ZAeemYTiw&6WbQK|P0OQti{G*_O<^lCcV2O8H8QG8CK1>yn$i>ZoPQ(&%7;)46^R^Ig82-l=-Q^_ zg%oJymn9F*w|Mf3QGlW~{ojIHPQCDtc)553E9=#2({ziA zC0&gz|M0@oF320&6RODF^mH4?ro(T1T2nDptkWGxZScXO5DPNlQ~rKE8u9p`QXz)r zrMqLD#x@>x+H{g4VOJK*rZw~J0sC4MKYFtCkkT}H&MI8A%;T+MKyY3ul&P#aKK}E! z*DY3L)Lb6`Ay5g(GYAEDL(E-z5!WM14t8rKyi~14d{spA_H&S?7qFjJX()riTDm`s za{FQ`|LDJ$zM)ljnZ8VS24BAGiOMahsFNs0q;yrNai;(lrh9N&^sVI4z`s}4Xb|zh zlZ^Qn3d1ZB#h>hiCW>t-9n9dL_fS!AoX=Ynvl3Wks>nr@P- z82^tSEtf~%TbrnpXM=^z(BY(zW} z@H)0f&*oOw+Rk;|iv9eV7+58#^xg*}fX#A6dh(%wbpe2uC^pRkb7nX6$Dr>&T`v2% z;I`8ryidK>chY@MA89wfee^SO8C~91l`87`uKMEuCc!wILafzcS(dOproySSqwjiR z8n3tbRA$>A*T*e^Y^=2^wVi`a7P(l7j&7scP~s=YOm1z`-C^1-FpBT7KM(ONqC)C% zn8;S&t3;p10Xo&Qp_Xkuwfla@r&znR#G7y{j-kmFQx$LM({qbX$jAe?QVDfK852ds zQT4?mGb95z0MZkrMC86cn0hoK$2bF^piNKIugNSK#lB^F>Sa?v!tX4>I?hPo?t4!K zC4?PUDjZk)^g_2LN?nrSuKh2&U-Os#`cAEvj%}?4&$|_B*CrV_@BJ!-;wIt^XP#o6 zqih zhzBBNXN^|n2)&#Zg0gl`)Cn>RvFueCQq z_wnbAhg;ozl1}v(45l~adaJ;rcoia|2pT{G>Q=jkif%gNb;{uYqBnhl*2sp^SZF*~ zamC|S`^<j-SS!b8-`Swb#>H{u)^RaxDYV!@L%Tu)7 zS2RyYq@v`G2X3u_!Ne@>5$Z9%?efA3<%{Z`)8THkoG8+D#Th1aGpXe qU*YZsYU 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 literal 240773 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