Skip to content

Tick: drive the codex author across the climb-authoring lanes - #123

Closed
renmengye wants to merge 4 commits into
mainfrom
feat/tick-codex-author
Closed

renmengye wants to merge 4 commits into
mainfrom
feat/tick-codex-author

Conversation

@renmengye

Copy link
Copy Markdown
Member

What

Let the tick drive the codex/terra author for its climb-authoring lanes, so
the live loop can author on codex instead of Claude. Three env knobs, threaded
through a shared helper into the self-initiated, intake, and wake (revise) lanes:

  • AUTORESEARCH_AUTHOR_BACKEND — ""/claude (default) or codex
  • AUTORESEARCH_AUTHOR_MODEL — required non-Claude id for codex (e.g. gpt-5.6-terra)
  • AUTORESEARCH_CODEX_BIN — optional; falls back to the climb CLI default

Design

  • The author backend is a fleet-wide choice. All three authoring lanes share
    key_file, so they must all use the same backend — otherwise a Claude author
    would be handed the codex/OpenAI key. AUTORESEARCH_HARNESS_KEY_FILE therefore
    holds the author's key (Anthropic for claude, OpenAI for codex); the verify/
    review panel keeps its own AUTORESEARCH_PANEL_KEY_FILE regardless. The steward
    is a separate role with its own key and is unaffected.
  • Preflight before side effects. A codex author missing a (non-Claude) model
    is caught up front: the self-initiated lane skips, and intake skips before
    claiming
    an issue — no job submitted that would die at startup, no stranded
    claim.
  • Wake carries the backend. A parked codex run resumes with the right harness;
    codex has no headless resume (supports_resume=False), so the climb's existing
    gate drafts the blocking finding instead of resuming — rather than a Claude
    harness receiving an OpenAI key.

Default behavior is unchanged (the Claude author). This is the code stage; the
live flip (setting the env on the tick host) is a separate, deliberate step.

Test plan

  • New: _climb_author_argv / _author_preflight_error units; self-initiated,
    intake, and wake integration tests (codex flags reach the argv; codex-without-
    model skips before submit, and intake skips before claiming).
  • uv run pytest — 695 passed. Full gate (ruff check + format, mypy) — green.

Context

Builds on #121 (codex author validated end-to-end on Slurm). Author network-egress
hardening is tracked separately in #122.

No secrets / no large files

Confirmed.

🤖 Generated with Claude Code

Wire AUTORESEARCH_AUTHOR_BACKEND/_MODEL and AUTORESEARCH_CODEX_BIN through the
tick into the self-initiated, intake, and wake (revise) climb lanes via a shared
_climb_author_argv helper, so the fleet can author on codex/terra instead of
Claude. The author backend is fleet-wide: key_file (AUTORESEARCH_HARNESS_KEY_FILE)
holds that backend's key, while the verify/review panel keeps its own key. All
three authoring lanes consume the backend uniformly — a mixed fleet would feed a
Claude author an OpenAI key (they share key_file) — while the steward keeps its
own role/key.

A codex author missing a (non-Claude) model is preflighted: the self-initiated
lane skips and intake skips BEFORE claiming an issue, rather than submitting a
job that dies at startup. The wake carries the backend too, so a parked codex
run resumes with the right harness (codex's no-resume then drafts via the climb's
supports_resume gate) instead of a Claude harness getting an OpenAI key.

Default is unchanged (the Claude author). Validated end-to-end on Slurm in #121.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 1 — reviewed head 99d04338 — reviewer hermes/gpt-5.6-terra.

second opinion — terra
Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: nothing blocking — 1 advisory note.

1 finding attached to the lines below.

Comment thread src/autoresearch/tick.py Outdated
# the author backend must match the parked run's: a no-resume backend
# (codex) drafts the blocking finding instead of resuming (the climb's
# supports_resume gate), and key_file below is that backend's key.
*_climb_author_argv(self.spec),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Misconfigured Codex wakes submit jobs that fail before resuming. The wake forwards --author-backend codex without calling _author_preflight_error, so a missing model leaves climb's default Claude model and makes the wake exit at its Codex validation before its lease-release finally runs.

(high confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — fixed in 904b9c8. JobWakeDispatcher.dispatch now calls _author_preflight_error and raises on a bad author config before building the argv. _wake already treats a raising dispatch as a failed delivery (it releases the lease and the bumped wake_attempts still counts toward the stuck threshold), so a persistently-misconfigured author converges to stuck without submitting a doomed resume job each tick — matching how the self-initiated and intake lanes fail safe. Reachability is low (self-initiated/intake preflight before a run can park, so the config was valid at park time; this covers a mid-flight config break), but the fix makes the three authoring lanes consistent. Test added.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 1 — reviewed head 99d04338 — reviewer claude/claude-opus-5.

Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: 1 blocking, 2 advisory.

2 findings attached to the lines below.

The in-review follow-up lane still runs a Claude harness with the now-OpenAI key file. service_in_review passes spec.key_file as --key-file to autoresearch.followup, whose main() always builds a Claude editor harness (build_editor_harness(..., binary=args.claude_bin, model=args.model) with default claude-opus-5), so once AUTORESEARCH_AUTHOR_BACKEND=codex makes AUTORESEARCH_HARNESS_KEY_FILE an OpenAI key, every PR follow-up session gets handed the wrong provider's key and fails to authenticate — the exact failure the PR says it prevents, in a fourth authoring lane the design note does not mention. (src/autoresearch/tick.py:541; high confidence)

I verified the climb CLI flags (--author-backend, --model, --codex-bin), the codex supports_resume=False gate, and that panel lens models come from parse_lenses rather than --model, so the codex model does not leak into the judges. The CHANGELOG's claim of end-to-end Slurm validation (codex 0.130.0, gpt-5.6-terra) is not verifiable from the repository contents.

Comment thread src/autoresearch/tick.py
*_climb_panel_argv(self.spec),
# the author backend must match the parked run's: a no-resume backend
# (codex) drafts the blocking finding instead of resuming (the climb's
# supports_resume gate), and key_file below is that backend's key.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The wake lane threads the author flags but never runs the author preflight. JobWakeDispatcher.dispatch calls _climb_author_argv without _author_preflight_error, so a spec with author_backend=codex and no model (or an unknown backend, which climb's choices=("claude","codex") rejects) submits a wake job that dies in argparse while wake_attempts is incremented each sweep, burning the run's retry budget up to MAX_WAKE_ATTEMPTS.

(medium confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in 904b9c8 (wake now preflights and raises) and hardened in db4ca9a (wake uses the parked run's persisted backend). _wake treats the raise as a failed delivery — releases the lease, counts the attempt — so no doomed job is submitted.

Comment thread src/autoresearch/tick.py Outdated
if not backend or backend == "claude":
return []
argv = ["--author-backend", backend]
if spec.author_model:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion. Preflight strips the model but the argv builder does not. _author_preflight_error validates spec.author_model.strip() while _climb_author_argv emits the raw spec.author_model, so an env value with surrounding whitespace passes preflight and reaches codex as a quoted model id with spaces, which 404s at session start instead of being caught on the tick host.

(low confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in db4ca9a — _author_argv now emits spec.author_model.strip() (and skips the flag entirely when the stripped value is empty), matching the preflight's .strip(), so a stray-whitespace env value is caught on the tick host rather than reaching codex as a bad id.

The wake forwarded --author-backend to the resume job without preflighting, so a
misconfigured codex author (missing/Claude model) would submit a resume that dies
at the climb's startup validation; the lease then TTL-reaps and re-attempts,
burning a Slurm job each tick until the stuck threshold. JobWakeDispatcher.dispatch
now raises on a bad author config — _wake already treats a raising dispatch as a
failed delivery (releases the lease, counts the attempt), so no doomed job is
submitted. Brings the wake in line with the self-initiated and intake lanes, which
already preflight the author.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 2 — reviewed head 904b9c84 — reviewer hermes/gpt-5.6-terra.

second opinion — terra
Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: 1 blocking, 0 advisory.

1 finding attached to the lines below.

Comment thread src/autoresearch/tick.py Outdated
# the author backend must match the parked run's: a no-resume backend
# (codex) drafts the blocking finding instead of resuming (the climb's
# supports_resume gate), and key_file below is that backend's key.
*_climb_author_argv(self.spec),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking. Wake jobs use the current backend instead of the parked run's backend. dispatch builds the wake from self.spec, while RunRecord stores no author backend, so switching the fleet to codex makes a parked Claude run wake as codex and draft rather than resume its Claude session.

(high confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in db4ca9a. RunRecord now persists author_backend (stamped by live_climb, default ""=legacy/claude, carried through the park via the __dict__ spread), and JobWakeDispatcher.dispatch builds the author from record.author_backend (falling back to the spec for legacy records), not the current fleet spec. So a parked Claude run under a now-codex fleet wakes as Claude and resumes its session; a parked codex run wakes as codex. The codex model/binary still come from the stable fleet spec. Test added covering record-backend-wins + legacy fallback. (Note: the fleet key repoint during a flip still can't serve both backends at once, but dispatch is dark on the pilot so no runs are in flight to strand; the backend-mismatch this finding names is resolved.)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 2 — reviewed head 904b9c84 — reviewer claude/claude-opus-5.

Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: nothing blocking — 3 advisory notes.

1 finding attached to the lines below.

Advisory (non-blocking):

  • The in-review follow-up lane still assumes a Claude author but shares the now-repurposed harness key (src/autoresearch/tick.py:541; high)
  • The wake uses the current env backend, not the backend the parked run was authored with (src/autoresearch/tick.py:1830; low)

I verified the climb CLI flag names (--author-backend/--model/--codex-bin), its codex model validation (climb.py:2008-2018), the supports_resume draft gate (climb.py:706-714), and that _wake catches a raising dispatch and releases the lease (tick.py:668-672); all match the PR's claims. The new tests' negative cases are ordered so the author preflight, not the panel preflight, is what blocks. I could not run the test suite (no execute tool), so the '695 passed' claim is unverified.

Comment thread src/autoresearch/tick.py Outdated
return argv


def _author_preflight_error(spec: FollowupSpec) -> str:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Preflight does not check that the codex binary path is absolute. _author_preflight_error validates only the backend name and model, while CodexHarness.run returns config-error when self.binary is not absolute (harness.py:753-758) and _flight_command requires absolute paths, so a relative AUTORESEARCH_CODEX_BIN passes preflight and the intake lane claims the issue before the job dies — the exact strand the panel preflight's absolute-path checks exist to prevent.

(medium confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 49a8d10. _author_config_error now rejects a relative AUTORESEARCH_CODEX_BIN (empty still falls back to the climb CLI's default codex path), so the self-initiated lane skips and intake skips before claiming — matching the panel preflight's absolute-path checks. Test added (empty ok, absolute ok, ~ ok, relative rejected).

The wake built its author flags from the current fleet spec, but the RunRecord
stored no backend — so a mid-flight fleet flip (claude->codex) would wake a parked
Claude run AS codex, which drafts instead of resuming its Claude session. Persist
author_backend on the record (live_climb stamps it; default '' = legacy/claude,
survives the park via the __dict__ spread) and build the wake's author from the
RECORD (falling back to the spec for legacy records); the codex model/binary still
come from the stable fleet spec. Factor the argv/preflight helpers to value-based
cores (_author_argv/_author_config_error) shared by the spec lanes and the wake,
and strip the model in the argv builder so a stray-whitespace env value is caught
on the tick host rather than 404'ing at codex session start (terra R2 nit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 3 — reviewed head db4ca9af — reviewer hermes/gpt-5.6-terra.

second opinion — terra
Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: 1 blocking, 0 advisory.

1 finding attached to the lines below.

Comment thread src/autoresearch/tick.py Outdated
# release the lease and count the attempt toward the stuck threshold
# (same as any dispatch failure), instead of burning a Slurm job each
# tick. Fresh climbs preflight this before submit; the wake does too.
author_error = _author_config_error(backend, self.spec.author_model)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking. A parked Codex run cannot wake after the fleet changes back to Claude. The record stores only its backend, but the wake validates and passes the current spec's model, binary, and key, so a parked codex record with a now-Claude spec has an empty or Claude model and fails preflight before it can draft its result.

(high confidence)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct that it cannot wake — and that is the intended safe outcome, not a fixable bug at this layer. The author backend is not hot-swappable with runs in flight: the fleet has ONE author key, repointed at a flip, so a parked codex run genuinely cannot wake once the fleet is on claude (its key is gone) — persisting the model/binary too wouldn't help (the key is the blocker) and would only move the failure from a fast preflight-raise to a burned Slurm job that auth-fails. The current path fails SAFE: the preflight raises before any sbatch (49a8d10 keeps this), so no job is burned; _wake counts the attempt and the run converges to the stuck terminal. Mitigation is operational — drain in-flight parked runs before flipping AUTORESEARCH_AUTHOR_BACKEND — now documented at the wake. This is also unreachable on the pilot (dispatch/park is dark). Code owner's call: not blocking; documented constraint + fast-fail. A graceful dedicated 'backend-changed' terminal could be a follow-up if we later run dispatch across a live flip.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 3 — reviewed head db4ca9af — reviewer claude/claude-opus-5.

Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: 1 blocking, 3 advisory.

3 findings attached to the lines below.

Advisory (non-blocking):

  • Runs parked before this change still wake with the new fleet backend (src/autoresearch/tick.py:1819; medium)

I could not run anything; findings come from reading tick.py, climb.py, followup.py, harness.py and runstate.py in the checkout. Whether AUTORESEARCH_HARNESS_KEY_FILE will actually be swapped to an OpenAI key on the tick host is an operational fact I cannot verify — finding 1 assumes the pairing this diff documents at tick.py:193-197.

Comment thread src/autoresearch/tick.py
# in which case author_model must be a non-Claude id and key_file holds that
# backend's key (e.g. an OpenAI key for terra). The verify/review panel keeps
# its own key (panel_key_file) regardless of the author backend.
author_backend: str = ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking. The in-review follow-up lane is not covered by the fleet-wide author backend. service_in_review submits autoresearch.followup with --key-file spec.key_file (tick.py:541) and followup.main builds a Claude editor harness with no backend flag (followup.py:733), so once AUTORESEARCH_AUTHOR_BACKEND=codex makes key_file the OpenAI key — the invariant this diff states at tick.py:193-197 — every follow-up session hands the Claude CLI an OpenAI key and fails to authenticate.

(high confidence)

Comment thread src/autoresearch/tick.py
# (same as any dispatch failure), instead of burning a Slurm job each
# tick. Fresh climbs preflight this before submit; the wake does too.
author_error = _author_config_error(backend, self.spec.author_model)
if author_error:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A parked codex run can never be woken after the fleet rolls back to Claude. The record persists only the backend, not the model, so _author_config_error(record.author_backend, self.spec.author_model) raises on every wake once AUTORESEARCH_AUTHOR_MODEL is unset, and _wake bumps wake_attempts before each failed dispatch (tick.py:661-676), so those runs burn attempts until the stuck cap instead of publishing their measured results.

(medium confidence)

Comment thread src/autoresearch/tick.py
argv = ["--author-backend", backend]
if model.strip():
argv += ["--model", model.strip()]
if codex_bin:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion. codex_bin is passed through unstripped and unvalidated. model is stripped and preflighted but codex_bin is forwarded verbatim, so whitespace or a relative AUTORESEARCH_CODEX_BIN reaches the harness, which only fails at session time with config-error (harness.py:755-760) after the job has already been submitted.

(low confidence)

…nt (#123 R3)

- _author_config_error now rejects a relative AUTORESEARCH_CODEX_BIN (empty still
  falls back to the CLI default), matching the panel preflight's absolute-path
  checks — so intake skips before claiming rather than stranding on a job that
  trips CodexHarness's own absolute guard from the flight dir.
- Document that the author backend is not hot-swappable with runs in flight: the
  fleet has one author key (repointed at a flip), so a parked codex run cannot
  wake once the fleet is claude (key gone), and vice versa. That fails SAFE — the
  wake preflight raises before any sbatch, so no job is burned and the run
  converges to stuck; operationally, drain parked runs before flipping. Dark on
  the pilot (no run is in flight to strand).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 4 — reviewed head 49a8d10f — reviewer hermes/gpt-5.6-terra.

second opinion — terra
Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: 1 blocking, 0 advisory.

1 finding attached to the lines below.

Comment thread src/autoresearch/tick.py
# the stuck terminal. Operationally: DRAIN in-flight parked runs before
# flipping AUTORESEARCH_AUTHOR_BACKEND. (Dispatch/park is dark on the pilot,
# so no run is in flight to strand today.)
backend = record.author_backend or self.spec.author_backend

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking. Wake dispatch does not fail safely after an author backend flip. A parked Claude record uses its stored backend but the current Codex key because _author_config_error accepts Claude, while a legacy empty record falls back to Codex, so either case can submit a wake with the wrong backend or key and consume wake attempts instead of stopping before sbatch.

(high confidence)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Round 4 — reviewed head 49a8d10f — reviewer claude/claude-opus-5.

Advisory findings from autoresearch — the code owner decides. Reply to disagree; the autoresearch:no-review label opts this PR out.

Verdict: nothing blocking — 4 advisory notes.

3 findings attached to the lines below.

Advisory (non-blocking):

  • The in-review follow-up lane still runs Claude with the (now codex) author key (src/autoresearch/tick.py:541; high)

I verified the wake failure path: _wake catches dispatch exceptions, releases the lease, and keeps the bumped attempt counter, so the raise-before-sbatch claim holds. Record persistence also holds: every later RunRecord(**{**record.__dict__, ...}) rebuild keeps author_backend, and load_record drops unknown keys so old records still load. Claims about the codex 0.130.0 Slurm validation in the CHANGELOG are not verifiable from this checkout.

Comment thread src/autoresearch/tick.py
"author backend 'codex' needs a non-Claude "
f"AUTORESEARCH_AUTHOR_MODEL (got {model.strip()!r})"
)
if codex_bin and not os.path.isabs(os.path.expanduser(codex_bin)):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Preflight accepts a ~ codex path but the tilde is never expanded downstream. _author_config_error expands the path before os.path.isabs, so AUTORESEARCH_CODEX_BIN=~/.local/bin/codex passes (tests/test_tick.py asserts this), yet _author_argv puts the raw string into the argv, quote_command shell-quotes it so no shell expansion happens, and climb.main passes args.codex_bin to build_editor_harness unexpanded, where CodexHarness.run's os.path.isabs guard returns config-error — the startup death the preflight is supposed to prevent.

(high confidence)

Comment thread src/autoresearch/tick.py
# the stuck terminal. Operationally: DRAIN in-flight parked runs before
# flipping AUTORESEARCH_AUTHOR_BACKEND. (Dispatch/park is dark on the pilot,
# so no run is in flight to strand today.)
backend = record.author_backend or self.spec.author_backend

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Legacy records with an empty backend wake as codex after a fleet flip. record.author_backend or self.spec.author_backend falls back to the fleet default for records written before this field existed, but those runs are all Claude runs, so under a codex fleet they wake with --author-backend codex and the OpenAI key — the exact case the CHANGELOG says can never happen (record.author_backend or "claude" would be exact); the new wake test asserts the fallback, so it passes with this gap present.

(medium confidence)

Comment thread src/autoresearch/tick.py
# release the lease and count the attempt toward the stuck threshold
# (same as any dispatch failure), instead of burning a Slurm job each
# tick. Fresh climbs preflight this before submit; the wake does too.
author_error = _author_config_error(backend, self.spec.author_model, self.spec.codex_bin)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The wake preflight only fails safe in one flip direction, not both. The comment says a parked run whose backend no longer matches the fleet key "fails safe HERE ... and vice versa", but _author_config_error returns "" for any Claude backend, so a parked Claude run under a codex fleet is submitted with a Claude harness plus spec.key_file (the OpenAI key) instead of raising; only the codex-record-under-Claude-fleet direction raises.

(medium confidence)

@renmengye

Copy link
Copy Markdown
Member Author

Superseded. Review of this per-lane approach surfaced that (a) codex was wrongly marked no-resume and (b) threading the backend into each lane's argv is the wrong abstraction. Replacing with: #resume-fix (codex resume validated + supports_resume=True) then a config-driven backend selection so a new backend needs ~zero per-lane change. Branch kept for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant