diff --git a/tests/test_task_batch.py b/tests/test_task_batch.py index db23910..69eb585 100644 --- a/tests/test_task_batch.py +++ b/tests/test_task_batch.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""t-260930101325-010ba3: батч-обработка задач в часовом тике (hermetic, без LLM/БД). +"""t-261001090908-18a4f5: тест синхронизирован с контекст-схемой 11a8ccc (min 256k / hour 512k / day 1M), hermetic. Запуск: ./venv/bin/python tests/test_task_batch.py @@ -81,16 +81,24 @@ check("4: env SIMBIOT_BATCH_MAX_HOUR=2 переопределяет", os.environ.pop("SIMBIOT_BATCH_MAX_HOUR", None) # ── 5. Бюджет контекста: секция задач не съедает ctx тика ── -# hour: ctx 32K токенов · 3 симв/токен · 0.5 = 48_000 симв на батч. -# Задача ~9261 симв → в 48К влезает 5 (46305), 6-я (55566) — нет. -big_details = "х" * 9000 +# Бюджет выводится из контекст-схемы уровня (11a8ccc: min 256k → hour 512k → +# day 1M ctx_tokens): budget = ctx_tokens · CHARS_PER_TOKEN · TASK_BUDGET_SHARE, +# для hour = 512_000 · 3 · 0.5 = 768_000 симв на батч. Размеры деталей тоже +# выведены из бюджета — схема не должна рассыпаться при следующей смене уровней. +budget = int(LEVELS["hour"].ctx_tokens * scheduler.CHARS_PER_TOKEN * scheduler.TASK_BUDGET_SHARE) +check("5: контекст-схема 11a8ccc (min 256k / hour 512k / day 1M)", + LEVELS["min"].ctx_tokens == 256_000 and LEVELS["hour"].ctx_tokens == 512_000 + and LEVELS["day"].ctx_tokens == 1_000_000, + f"min={LEVELS['min'].ctx_tokens} hour={LEVELS['hour'].ctx_tokens} day={LEVELS['day'].ctx_tokens}") +# Задача с деталями budget//5 - 300 симв стоит ≈ budget/5 (263+details); +# 5 шт влезают (сумма < 1.0·budget), 6-я пробивает (кап 6 не достигнут). +big_details = "х" * (budget // 5 - 300) huge = {f"t-{i}": _task(f"t-{i}", details=big_details, created=f"2026-09-30T0{i}:00:00") for i in range(8)} batch = scheduler.select_task_batch(LEVELS["hour"], _model(huge)) cost = scheduler.task_batch_cost([huge[t] for t in batch]) -budget = int(32_000 * scheduler.CHARS_PER_TOKEN * scheduler.TASK_BUDGET_SHARE) check("5: бюджетная отсечка (5 из 8, кап 6 не достигнут)", len(batch) == 5, f"n={len(batch)}") -check("5: суммарная стоимость ≤ 48К симв", cost <= budget, str(cost)) +check("5: суммарная стоимость ≤ бюджету hour (768К симв)", cost <= budget, str(cost)) check("5: 6-я задача пробила бы бюджет (отсечка не случайна)", cost + scheduler._task_cost(huge["t-5"]) > budget, f"cost6={cost + scheduler._task_cost(huge['t-5'])}") @@ -101,7 +109,9 @@ check("5: узкие — все 6 влезли", len(scheduler.select_task_batch(LEVELS["hour"], _model(wide))) == 6) # ── 6. Первая (старейшая) берётся ВСЕГДА, даже если бюджет пробит ── -fattail = {"t-huge": _task("t-huge", details="y" * 200_000, created="2026-09-30T07:00:00"), +# Размер t-huge — от бюджета (details = 2·budget симв): влезть следом для +# t-s (~263 симв) места нет, но первую задача берётся безусловно. +fattail = {"t-huge": _task("t-huge", details="y" * (budget * 2), created="2026-09-30T07:00:00"), "t-s": _task("t-s", created="2026-09-30T08:00:00")} batch = scheduler.select_task_batch(LEVELS["hour"], _model(fattail)) check("6: сверхтяжёлая старейшая берётся одна (не блокирует очередь)",