Skip to content

pyrefly: fix real bugs surfaced by 0.61 bump#4804

Open
rjpower wants to merge 6 commits intopyrefly/bump-0.61from
pyrefly/pr0-real-bugs
Open

pyrefly: fix real bugs surfaced by 0.61 bump#4804
rjpower wants to merge 6 commits intopyrefly/bump-0.61from
pyrefly/pr0-real-bugs

Conversation

@rjpower
Copy link
Copy Markdown
Collaborator

@rjpower rjpower commented Apr 15, 2026

Summary

Stacked on #4801 (PR-base, pyrefly 0.42→0.61 bump). Fixes the set of real
bugs (not pure typing cleanup) surfaced in the Stage-3 cluster triage
memos. Grouped into one commit per subproject plus a final baseline
refresh.

Baseline delta: 169 → 129 diagnostics (−40); .pyrefly-baseline.json
shrank from 2031 → 1551 lines.

Removed deprecated = false from [tool.pyrefly.errors] — the category
now has zero unbaselined diagnostics under 0.61.

Bugs fixed

fray

  • v1/cluster/__init__.py:126__all__ lists "TPUConfig", only
    TpuConfig is imported. Downstream from fray.v1.cluster import TPUConfig would silently AttributeError.
  • v1/cluster/ray/tpu/__init__.py:30,36,45__all__ lists
    TPU_CONFIGS, TPUConfig, get_tpu_config — none defined or
    imported. Drop from __all__.
  • v1/cluster/base.py:{435,443,482}, v2/types.py:{508,516}Self
    used as return type on @staticmethod; meaningless. Replace with the
    explicit class name.
  • v1/queue/base.py:32,56Queue protocol used T_co (covariant) in
    contravariant input positions. Switch to invariant T.

haliax

  • jax_utils.py:360ensure_tuple imported from haliax.core; it
    lives in haliax.util.

iris

  • cluster/config.py:1218db: "ControllerDB | None" marked
    # noqa: F821 for a circular import that doesn't actually exist.
    Import ControllerDB at module scope, drop the noqa.
  • cluster/controller/db.py:334 — the EndpointRegistry forward-ref is
    a real cycle; use TYPE_CHECKING import instead of # noqa: F821.
  • cluster/controller/controller.py:312,315,690,691 — helpers
    _building_counts and _inject_reservation_taints typed against
    list[WorkerRow] but the caller passes list[WorkerSnapshot]. Widen
    helpers to list[WorkerSnapshot] (WorkerRow satisfies the Protocol).
  • cluster/controller/controller.py:1546_capture_one_profile asserts
    _provider is not a K8sTaskProvider before calling the
    TaskProvider-Protocol signature. The profile loop is only spawned on
    the non-K8s branch (see start() at line 1202), so no behavior change.

zephyr

  • plan.py:779MapShardOp.fn takes ShardInfo, not stale
    shard_idx=/total_shards= kwargs (see reference at line 237).

levanter

  • inference/openai.py:363 — the Exception handler in
    _batch_processing_loop referenced batch, which was unbound if
    queue.get() raised anything other than queue.Empty. Guaranteed
    UnboundLocalError on the error path. Restructure so the queue
    wait and the work block are in separate try blocks.
  • optim/model_averaging.py:42,73EmaModelAveraging.update and
    EmaDecaySqrtModelAveraging.update renamed their model parameter
    to new_model, breaking keyword-argument overrides of the abstract
    base ModelAveraging.update. Rename back.
  • utils/py_utils.py:129FailSafeJSONEncoder.default(obj=) vs
    stdlib JSONEncoder.default(o=); rename with local alias.
  • data/dataset.py:325, data/sharded_datasource.py:531,
    store/cache.py:220 — three classes used a TypeVar outside the class
    generic scope. Widen to Any or add Generic[T].

marin

  • Delete dead lib/marin/src/marin/infra/ package: __init__.py
    imports TpuMonitor/start_tpu_monitor_on_head from a deleted
    tpu_monitor submodule; nothing imports marin.infra.
  • rl/weight_transfer/arrow_flight.py:267 — stray debug return 123
    from a function declared -> None; widen fetch_server return to
    ServerInfo | None (caller already handles None).
  • rl/weight_transfer/arrow_flight.py:307 — guard self._latest_weight_id is None before using it as a dict key.
  • rl/rollout_storage.py:200while time.time() - start_time < timeout crashes on timeout is None (signature allows it); compute
    a deadline.
  • datakit/download/wikipedia.py:61tarfile.extractfile() returns
    None for non-regular entries; skip rather than with None.
  • transform/wikipedia/transform_wikipedia.py:180postprocess_content
    declared -> str, returns None on filter failure. Annotate str | None (caller already None-checks).
  • transform/conversation/adapters.py:52-55,91,110 — StrEnum member
    annotations dropped (invalid); transform_conversation_to_openai_format
    annotated list | None; guard against best_completion is None
    before subscripting.
  • transform/conversation/transform_conversation.py:123 — caller
    annotation updated to match.
  • transform/fasttext/transform.py — add missing return True to
    convert_fasttext_to_dolma_format (declared -> bool, fell through).
  • rl/environments/inference_ctx/inflight/worker.py:215generate
    returns list[str], not str.
  • execution/executor.py:155,634,973,1137,1138,1209 — replace 6 sites
    where dataclass (the decorator) was used as a type annotation with
    Any.
  • cluster/config.py:317 — add _GenerationConfig TypedDict annotation
    to GENERATION_CONFIGS.
  • utilities/json_encoder.py:18CustomJsonEncoder.default param
    rename.

Deferred

  • lib/marin/src/marin/rl/scripts/replay_completions.py — the whole
    script is stale against the renamed InferenceServer.create(config, model, tokenizer) API and the slimmed-down InferenceServerConfig.
    Fixing requires loading a concrete model/tokenizer at script entry,
    which is a rewrite beyond PR-0 scope. The script was already
    non-functional.
  • lib/iris/src/iris/cluster/controller/controller.py:2176
    self._provider.sync(batches) dispatches across
    TaskProvider.sync(list[DispatchBatch]) vs
    K8sTaskProvider.sync(DirectProviderBatch). K8s path already uses
    _sync_direct_provider at line 1455; reconciling the Protocol needs
    iris-owner judgement.

Test plan

  • ./infra/pre-commit.py --all-files — green
  • uvx pyrefly@0.61.0 check --baseline .pyrefly-baseline.json
    0 errors
  • .pyrefly-baseline.json strictly smaller than parent branch
    (2031 → 1551 lines; 169 → 129 diagnostics)
  • Full tests not run locally (large repo); rely on CI.

rjpower added 5 commits April 15, 2026 23:28
- v1/cluster/__init__.py: drop "TPUConfig" from __all__ (only TpuConfig
  is imported; the wrong-case name never existed).
- v1/cluster/ray/tpu/__init__.py: drop "TPU_CONFIGS", "TPUConfig",
  "get_tpu_config" from __all__ (none are defined or imported).
- v1/cluster/base.py, v2/types.py: replace Self with class name in
  five @staticmethod return annotations (Self is invalid on
  staticmethods); drop the now-unused Self import.
- v1/queue/base.py: Queue stores and returns T on both sides, so T_co
  (covariant) is wrong when used as an input position. Switch to
  invariant T across Queue and MemoryQueue.
haliax/jax_utils.py: ensure_tuple lives in haliax.util, not haliax.core.

iris/cluster/config.py: ControllerDB can be imported at module scope —
no circular import — so drop the stale "# noqa: F821" string forward
reference.

iris/cluster/controller/db.py: the EndpointRegistry forward-ref is a
real cycle; guard with TYPE_CHECKING instead of "# noqa: F821".

iris/cluster/controller/controller.py:
- Widen _building_counts and _inject_reservation_taints to accept
  list[WorkerSnapshot] (matches Scheduler.create_scheduling_context;
  WorkerRow already satisfies the Protocol).
- _capture_one_profile asserts the provider is not a K8sTaskProvider
  before calling the TaskProvider Protocol signature with (address,
  request, timeout_ms). The profile loop is only spawned on the
  non-K8s branch (see start()), so this narrows for the type checker
  without behavior change.

zephyr/plan.py: MapShardOp.fn takes a ShardInfo, not the old
shard_idx/total_shards kwargs (see the reference site at line 237).
inference/openai.py: in _batch_processing_loop, the Exception handler
accessed `batch` which is only assigned by queue_get. If the
Exception came from the queue.get itself (other than queue.Empty),
`batch` was unbound and the handler would crash with
UnboundLocalError. Restructure so the queue.Empty / "other" split
happens before the work block, mirroring the intent.

optim/model_averaging.py: EmaModelAveraging.update and
EmaDecaySqrtModelAveraging.update renamed their `model` parameter to
`new_model`, which breaks keyword-argument overrides of the abstract
base (ModelAveraging.update). Rename back to `model`.

utils/py_utils.py: FailSafeJSONEncoder.default had `obj` as the param
name but stdlib JSONEncoder.default names it `o`. Rename and alias
locally to keep the body unchanged.

data/dataset.py, data/sharded_datasource.py, store/cache.py: three
classes used a TypeVar that wasn't in scope (class wasn't declared
Generic). Widen the input typevars to Any where unused (dataset,
sharded_datasource) and add Generic[T] to SerialCacheWriter so its
`exemplar: T` attribute resolves.
Dead code:
- Delete lib/marin/src/marin/infra/ package: the __init__.py imports
  and re-exports `TpuMonitor` / `start_tpu_monitor_on_head` from a
  deleted `tpu_monitor` module, and nothing imports `marin.infra`.

Guaranteed / possible runtime crashes:
- rl/weight_transfer/arrow_flight.py:267: drop a stray debug
  `return 123` from a function declared `-> None`; widen
  `fetch_server` return to `ServerInfo | None` (caller already
  handles None).
- rl/weight_transfer/arrow_flight.py:307: guard against
  `self._latest_weight_id is None` before using it as a dict key.
- rl/rollout_storage.py:200: `while time.time() - start_time <
  timeout` crashes when `timeout is None` (signature allows it).
  Compute an explicit deadline instead.
- datakit/download/wikipedia.py:61: tarfile.extractfile can return
  None for non-regular entries; skip those rather than entering `with
  None`.
- transform/wikipedia/transform_wikipedia.py:180: fix return
  annotation to `str | None` (function already returns None on
  filter failure).
- transform/conversation/adapters.py:
  - StrEnum members no longer annotated `: str = "..."`.
  - `transform_conversation_to_openai_format` returns `list | None`;
    guard against best_completion being None before indexing.
- transform/conversation/transform_conversation.py:123: update
  annotation to match the callee (already None-checked).
- transform/fasttext/transform.py: add `return True` to
  `convert_fasttext_to_dolma_format` (declared `-> bool` but fell
  through).
- rl/environments/inference_ctx/inflight/worker.py:215: `generate`
  returns list[str], not str.

API / type drift:
- execution/executor.py: replace 6 sites that used `dataclass` (the
  decorator) as a type annotation with `Any`.
- cluster/config.py: add _GenerationConfig TypedDict so
  `GENERATION_CONFIGS[x]["base_worker"]` is typed consistently.
- utilities/json_encoder.py: `CustomJsonEncoder.default(obj=)` →
  `default(o=)` matching stdlib JSONEncoder.default.
Baseline: 169 → 129 diagnostics, file shrank 2031 → 1551 lines.

Removed `deprecated = false` from [tool.pyrefly.errors]: the category
now has zero unbaselined diagnostics, so the blanket disable is no
longer needed.
@rjpower rjpower added the agent-generated Created by automation/agent label Apr 15, 2026
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 15, 2026

Claude finished @rjpower's task in 3m 28s —— View job


PR Review

Reviewed all 30 changed files against origin/pyrefly/bump-0.61. Verified each claim in the PR description by reading the touched code and (where relevant) the surrounding callers. Overall this is a tightly scoped PR that fixes real bugs — most changes are clean. A handful of nits below.

  • Read changed files in detail
  • Verify each fix matches its stated intent
  • Check for regressions/missed call sites
  • Post review

Verified-correct fixes

  • fray __all__ typos (v1/cluster/__init__.py, v1/cluster/ray/tpu/__init__.py) — confirmed TPUConfig/TPU_CONFIGS/get_tpu_config were not defined or imported. Removing from __all__ is the right call (a downstream from fray.v1.cluster import TPUConfig would silently break, since the actual symbol is TpuConfig).
  • fray Self on @staticmethodSelf is meaningless without an instance/class binding; replacing with the explicit class name (Entrypoint, JobStatus) is correct.
  • fray Queue variance — switching T_co (covariant) to invariant T is correct: push(item: T_co) had T_co in a contravariant input position, which would fail strict variance checks. The Protocol already had no covariant guarantee since pop() returns leases that are written/read both ways.
  • haliax ensure_tuple import — confirmed ensure_tuple lives in lib/haliax/src/haliax/util.py:25, not haliax.core. The original import would ImportError if to_jax_shape were ever called.
  • iris ControllerDB import — verified no cycle: iris.cluster.controller.db does not transitively import iris.cluster.config. The string-form annotation + # noqa was leftover from a no-longer-existing cycle.
  • iris EndpointRegistry cycle — confirmed real cycle (db.pyendpoint_registry.py); TYPE_CHECKING guard is correct.
  • iris _capture_one_profile assert — verified _run_profile_loop is only spawned in the non-K8s branch at controller.py:1208 (inside the else of isinstance(self._provider, K8sTaskProvider) at L1202). Asserting not isinstance(...) is sound.
  • iris _building_counts / _inject_reservation_taints — widening to WorkerSnapshot matches the actual call sites; WorkerRow satisfies the WorkerSnapshot Protocol.
  • zephyr MapShardOp.fn callplan.py:237 (the reference call site) and the new plan.py:779 now both pass ShardInfo(...). ShardInfo is already imported (line 44). Consistent and correct.
  • levanter _batch_processing_loop — splitting into two try blocks is the right structural fix. The original except Exception referenced batch, which would be unbound if queue.get() raised anything other than queue.Empty. (Rare in practice, but pyrefly is right to flag it.)
  • levanter model_averaging.update — confirmed no internal call site passes new_model= as kwarg, so the rename back to model is purely a cleanup that restores LSP-conformance with the abstract base.
  • marin infra/__init__.py deletion — confirmed nothing imports marin.infra anywhere in the repo. Safe to delete.
  • marin arrow_flight.py:267 stray return 123 — clear bug fix; widening fetch_server to ServerInfo | None matches the __init__ initializer (self._server_info = None style).
  • marin rollout_storage.py:200 deadline — handles timeout=None (which the signature allows) instead of crashing on time.time() - start < None.
  • marin wikipedia.py tarfile Noneextractfile() does return None for non-regular entries; with None as file would AttributeError. Skip is the conventional fix.
  • marin fasttext/transform.py missing return True — function declared -> bool but fell through to implicit None; if any caller tested truthiness, this masked failures.
  • marin worker.py:215 generate return type_generate_batch_async clearly returns list[str], and the only call site (vllm.py:385) iterates outputs. The old -> str was wrong.
  • marin transform/conversation/adapters.py — StrEnum value annotations (SINGLE_COLUMN_MULTI_TURN: str = "messages") are invalid on StrEnum (annotates a class member as str, not as the enum). Stripping them is correct. The best_completion is None guard is also correct — the previous code would crash with TypeError: 'NoneType' object is not subscriptable if response was empty.

Nits / suggestions

  1. arrow_flight.py:307-308flight.FlightUnavailableError("No weights available yet") is raised inside the broader try ... except Exception as e: raise flight.FlightInternalError(...) from e block at L294/L315. The typed Unavailable error is silently rewrapped as Internal, defeating the intent. Either re-raise the typed exception in a nested try/except (FlightUnavailableError,): reraise, or move the FlightUnavailableError outside the catch-all. Fix this →

  2. rollout_storage.py:199start_time = time.time() is now used only to compute deadline. Inline it: deadline = time.time() + timeout if timeout is not None else float("inf").

  3. worker.py:215 docstring — return-type changed from strlist[str], but the docstring still says Returns: Generated text. Should be Generated texts (or list of generated text).

  4. utils/py_utils.py:129 and utilities/json_encoder.py:18 — the def default(self, o): + obj = o aliasing pattern works but reads as a code smell. A short # stdlib JSONEncoder.default uses parameter name 'o'; alias for readability comment, or simply renaming objo throughout the body, would explain the intent. Not blocking.

  5. executor.py:155ConfigT = TypeVar("ConfigT", covariant=True, bound=dataclass) → no bound. The dataclass bound never worked (it's a decorator), but consider bound="DataclassInstance" if you want any compile-time signal. Probably fine to leave as-is for this PR.

  6. pyproject.toml — dropping deprecated = false is good. Worth a quick comment in commit c96df0b mentioning what dependency-side change finally made deprecated diagnostics empty (e.g. jax/equinox API updates), so future drift is easier to attribute.

Test plan gap

The PR notes "Full tests not run locally; rely on CI." For the levanter _batch_processing_loop and marin arrow_flight.do_get changes specifically, it would be worth confirming CI has coverage that exercises the error paths — both are touchy concurrent code where a regression is easy to miss.

Bottom line

LGTM with the nits above. The changes are small, well-scoped, and each is justified by the diagnostics. The 169→129 baseline reduction is real progress without smuggling in functional drift.
· base: pyrefly/bump-0.61

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c96df0be1c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread lib/zephyr/src/zephyr/plan.py Outdated
if isinstance(op, Map):
if op.needs_shard_context:
stream = op.fn(stream, shard_idx=ctx.shard_idx, total_shards=ctx.total_shards)
stream = op.fn(stream, ShardInfo(shard_idx=ctx.shard_idx, total_shards=ctx.total_shards))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass shard context as keyword args in run_stage

When op.needs_shard_context is true, this now passes a positional ShardInfo object into op.fn, but Map functions created by compose_map expect keyword-only shard_idx/total_shards parameters. Any stage containing MapShardOp will hit TypeError (pipeline() takes 1 positional argument but 2 were given) at runtime, breaking shard-context transforms; keep keyword arguments here or update both call sites/signatures consistently.

Useful? React with 👍 / 👎.

Comment on lines +20 to +21
if TYPE_CHECKING:
from iris.cluster.controller.endpoint_registry import EndpointRegistry
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid TYPE_CHECKING import guard in controller DB

This introduces a TYPE_CHECKING-guarded import, which violates the explicit Iris convention in lib/iris/AGENTS.md (“Avoid TYPE_CHECKING. Use real imports. If you hit a cycle, prefer refactoring or use a Protocol at the boundary.”). The same rule is also present in /AGENTS.md; please replace this guard with a structural cycle break rather than adding a forbidden import pattern.

Useful? React with 👍 / 👎.

@rjpower
Copy link
Copy Markdown
Collaborator Author

rjpower commented Apr 15, 2026

@claude the tests are failing due to the issues noted in the PR comments, pls address.

address nits (1) and (2) as well

TypeError: compose_map..pipeline() takes 1 positional argument but 2 were given
FAILED lib/zephyr/tests/test_groupby.py::test_deduplicate_with_num_output_shards - zephyr.execution.ZephyrWorkerError: Shard 0 failed 3 times (max 3).
Last error:
Traceback (most recent call last):
File "/home/runner/work/marin/marin/lib/zephyr/src/zephyr/execution.py", line 1169, in _poll_loop
result, task_counters = self._execute_shard(task, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/marin/marin/lib/zephyr/src/zephyr/execution.py", line 1273, in _execute_shard
raise result_or_error
TypeError: compose_map..pipeline() takes 1 positional argument but 2 were given
--- subprocess traceback ---
Traceback (most recent call last):
File "/home/runner/work/marin/marin/lib/zephyr/src/zephyr/subprocess_worker.py", line 165, in execute_shard
result_or_error = _write_stage_output(
^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/marin/marin/lib/zephyr/src/zephyr/execution.py", line 236, in _write_stage_output
first_item = next(stage_gen, None)
^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/marin/marin/lib/zephyr/src/zephyr/plan.py", line 779, in run_stage
stream = op.fn(stream, ShardInfo(shard_idx=ctx.shard_idx, total_shards=ctx.total_shards))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: compose_map..pipeline() takes 1 positional argument but 2 were given
============ 12 failed, 252 passed, 1 skipped in 340.42s (0:05:40) =============

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 15, 2026

Claude finished @rjpower's task in 14m 11s —— View job


Done — pushed commit 51dea7300

  • Fix zephyr plan.py:779 test failure. run_stage's op.fn here is a compose_map pipeline with signature (stream, *, shard_idx, total_shards), not a user-supplied MapShardOp.fn that takes positional ShardInfo. PR-0's line-779 change conflated the two call sites (physical Map.fn ≠ logical MapShardOp.fn at line 237). Reverted to kwargs and added a comment calling out the distinction.
  • Fix iris db.py TYPE_CHECKING violation. Per lib/iris/AGENTS.md ("Avoid TYPE_CHECKING. Use real imports. If you hit a cycle, prefer refactoring or use a Protocol at the boundary"), replaced the TYPE_CHECKING-guarded import with a local EndpointRegistryProtocol in db.py. Eight-method structural type covering all external callers (service.py, transitions.py, actor_proxy.py). The concrete EndpointRegistry — still imported locally inside __init__ as before — satisfies the Protocol.
  • Nit 1 (arrow_flight.py). Added an except flight.FlightUnavailableError: raise before the generic except Exception so the typed "retry me" signal isn't rewrapped as FlightInternalError.
  • Nit 2 (rollout_storage.py). Inlined start_time into deadline = time.time() + timeout if ... else float("inf").

Tests

  • ./infra/pre-commit.py --all-files --fixpass (ruff, black, pyrefly, license headers, etc.)
  • uv run pytest lib/zephyr/tests/264 passed, 1 skipped (the originally-failing test_deduplicate_with_num_output_shards now passes; full suite green)
  • uv run pytest lib/iris/tests/cluster/controller/test_endpoint_registry.py test_scheduler.py test_transitions.py217 passed (validates the Protocol change doesn't break db/endpoint usage)
  • uv run pytest tests/rl/test_rollout_storage.py tests/rl/test_weight_transfer.py4 passed, 1 skipped

Full test suite not run locally (large repo); rely on CI for broader coverage.
· Branch

zephyr plan.py: the run_stage call to op.fn invokes a compose_map
pipeline (which takes shard_idx/total_shards as kwargs), not a
user-supplied MapShardOp.fn (which takes a positional ShardInfo).
The PR-0 change at line 779 conflated the two and broke
test_deduplicate_with_num_output_shards with
"compose_map.<locals>.pipeline() takes 1 positional argument but
2 were given". Revert to kwargs; add a comment distinguishing the
physical Map.fn call site from the logical MapShardOp.fn call at
line 237.

iris db.py: replace TYPE_CHECKING-guarded forward-ref import of
EndpointRegistry with a local EndpointRegistryProtocol. lib/iris
AGENTS.md explicitly forbids TYPE_CHECKING ("prefer refactoring
or use a Protocol at the boundary"); the real module-level cycle
(db -> endpoint_registry -> db) means a plain import would cycle,
so Protocol at the boundary is the documented fix. The concrete
EndpointRegistry (imported locally inside __init__) continues to
satisfy the Protocol structurally.

arrow_flight.py nit 1: the broad `except Exception` was rewrapping
the typed FlightUnavailableError raised at line 308 as
FlightInternalError, defeating the typed-retry signal. Catch
FlightUnavailableError before the generic handler and re-raise
unchanged.

rollout_storage.py nit 2: inline `start_time` into the `deadline`
computation (the local was only referenced once).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-generated Created by automation/agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant