Skip to content

relayburn-cli: opencode HarnessAdapter via pending-stamp factory (#248 D7)#320

Merged
willwashburn merged 3 commits intomainfrom
rust-port/cli-opencode-adapter
May 7, 2026
Merged

relayburn-cli: opencode HarnessAdapter via pending-stamp factory (#248 D7)#320
willwashburn merged 3 commits intomainfrom
rust-port/cli-opencode-adapter

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Scope

Wave 2 D7 of the burn → Rust port (epic #240): the OpenCode harness adapter, registered via the pending_stamp::adapter_static factory the codex adapter (#317 D6) already uses.

Files

  • crates/relayburn-cli/src/harnesses/opencode.rs (new) — mirror of harnesses/codex.rs. name = "opencode", session_root resolves to $HOME/.local/share/opencode/storage/session (matches the TS sibling exactly), ingest_sessions opens a fresh Ledger handle and runs relayburn_sdk::ingest_opencode_sessions (already re-exported by D6).
  • crates/relayburn-cli/src/harnesses/mod.rs — add pub mod opencode;.
  • crates/relayburn-cli/src/harnesses/registry.rs:
    • RUNTIME_ADAPTERS gains ("opencode", opencode::adapter())
    • RUNTIME_ADAPTER_NAMES gains "opencode" (alphabetical after codex)
    • EXPECTED_HARNESS_NAMES test fixture updated to ["codex", "opencode"]
  • CHANGELOG.md — one impact-first bullet under [Unreleased].

How it plugs in

harnesses::lookup("opencode") resolves through the RUNTIME_ADAPTERS LazyLock (factory-built adapters can't be const-expressions for phf_map!). list_harness_names() returns ["codex", "opencode"] from RUNTIME_ADAPTER_NAMES without forcing the LazyLock, preserving the cold-start contract. The deterministic-order test pins both lists in lockstep.

Test pattern

Both opencode tests use the same ENV_LOCK: Mutex<()> + with_test_home helper introduced in the codex fixup (commit 5144ab6) so $HOME mutation is serialized across cargo's parallel test runner. The closure-around-catch_unwind shape preserves prior $HOME (or removes it if it was unset) even when the inner test panics.

Test plan

  • cargo build --workspace clean
  • cargo test --workspace green (610 SDK + 15 CLI harness tests + 9 sdk-node + integration)
  • harnesses::lookup("opencode") returns Some(adapter) (new adapter_round_trip test)
  • list_harness_names() returns ["codex", "opencode"] (list_harness_names_is_deterministic updated)
  • runtime_adapter_names_match_runtime_adapters passes — both lists in lockstep
  • Two new opencode tests (config_has_opencode_name, adapter_round_trip) pass under parallel runner without flake (env-lock pattern)

Out of scope

…D7)

Wires the OpenCode harness adapter through the same
`pending_stamp::adapter_static` factory codex uses (#248 D6). The new
`harnesses/opencode.rs` mirrors `harnesses/codex.rs` exactly:

* `name = "opencode"`, dispatch key + log label
* `session_root` resolves to `$HOME/.local/share/opencode/storage/session`,
  matching the TS sibling at `packages/cli/src/harnesses/opencode.ts`
* `ingest_sessions` opens a fresh `Ledger` handle per tick and runs
  `relayburn_sdk::ingest_opencode_sessions` (already re-exported)

Registry plumbing:
* `RUNTIME_ADAPTERS` gains `("opencode", opencode::adapter())`
* `RUNTIME_ADAPTER_NAMES` gains `"opencode"` (alphabetical after codex)
* `EXPECTED_HARNESS_NAMES` test fixture updated to `["codex", "opencode"]`

Tests reuse the `ENV_LOCK` + `with_test_home` pattern introduced in the
codex fixup (commit 5144ab6) so $HOME mutation is serialized across the
parallel cargo test runner. Two new tests:
* `config_has_opencode_name` — name + session_root resolution
* `adapter_round_trip` — full trait-object round trip
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d11be64-bc09-4887-a75d-b01f8e21a39b

📥 Commits

Reviewing files that changed from the base of the PR and between 6dc83a9 and 56cfc2a.

📒 Files selected for processing (4)
  • crates/relayburn-cli/src/harnesses/codex.rs
  • crates/relayburn-cli/src/harnesses/mod.rs
  • crates/relayburn-cli/src/harnesses/opencode.rs
  • crates/relayburn-cli/src/harnesses/test_env.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/relayburn-cli/src/harnesses/opencode.rs

📝 Walkthrough

Walkthrough

Adds a new OpenCode harness adapter to relayburn-cli: new opencode module (with config() and adapter()), exported from harnesses::mod, registered in the runtime registry and deterministic name list, plus shared test helpers for safely overriding $HOME and unit tests. CHANGELOG updated with the new Unreleased bullet.

Changes

OpenCode Harness Adapter

Layer / File(s) Summary
Changelog
CHANGELOG.md
Adds an Unreleased bullet for relayburn-cli noting wiring of the HarnessAdapter via pending_stamp::adapter_static and registration in RUNTIME_ADAPTERS ((#248 D7)) while retaining the prior (#248 D6) entry.
Module Export
crates/relayburn-cli/src/harnesses/mod.rs
Exports new pub mod opencode;.
Core Implementation
crates/relayburn-cli/src/harnesses/opencode.rs
New module: opencode_sessions_dir() computes session root from $HOME; config() constructs a PendingStampAdapter named "opencode" with a lazily-resolved session_root and an ingest closure that opens a fresh Ledger per tick and calls relayburn_sdk::ingest_opencode_sessions with default RawIngestOptions; adapter() returns a &'static dyn HarnessAdapter. Includes unit tests validating name, session_root resolution under a test $HOME, and adapter trait round-trip.
Shared Test Env
crates/relayburn-cli/src/harnesses/test_env.rs
Adds ENV_LOCK: Mutex<()> and with_test_home(home: &str, f: impl FnOnce()) to serialize and safely run tests that mutate process-global HOME, restoring prior state and resuming panics.
Tests — reuse
crates/relayburn-cli/src/harnesses/codex.rs
Tests now import with_test_home from test_env instead of defining per-file HOME mutation utilities.
Registry Integration
crates/relayburn-cli/src/harnesses/registry.rs
Imports opencode, inserts an opencode entry into RUNTIME_ADAPTERS, adds "opencode" into RUNTIME_ADAPTER_NAMES for deterministic ordering, and updates the deterministic-names test snapshot accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant CLI
    participant Registry
    participant Adapter as OpenCodeAdapter
    participant Ledger
    participant SDK
    participant FS as Filesystem

    CLI->>Registry: lookup("opencode") / list_harness_names
    Registry->>Adapter: return &'static HarnessAdapter
    CLI->>Adapter: invoke ingest tick
    Adapter->>Ledger: open fresh Ledger handle
    Adapter->>SDK: relayburn_sdk::ingest_opencode_sessions(Ledger, options)
    SDK->>FS: read session files under session_root ($HOME/.local/share/opencode/...)
    SDK-->>Adapter: ingest results
    Adapter-->>CLI: report status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A tiny adapter hops to play,
Sessions under HOME it maps the way,
Ledger opens fresh each tick,
Tests lock HOME so things stay slick,
Opencode joins the harness fray!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding the OpenCode harness adapter via pending-stamp factory, which is the primary objective of this PR.
Description check ✅ Passed The description is comprehensive and clearly related to the changeset, detailing the scope, files modified, integration points, test patterns, and test results.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rust-port/cli-opencode-adapter

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/relayburn-cli/src/harnesses/opencode.rs`:
- Around line 92-109: The ENV_LOCK mutex and with_test_home function currently
only serialize within this module but HOME is process-global; extract the
Mutex<()> into a shared test utility (e.g., a pub static ENV_LOCK in a
test_utils or common tests module/crate using the same static initialization
method) and have with_test_home acquire that shared ENV_LOCK instead of the
local one so all tests that mutate HOME reuse the same lock; update
callers/imports to reference the shared ENV_LOCK and keep the rest of
with_test_home (prev capture, set_var, restore/remove_var, resume_unwind)
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3d849d0a-5267-4498-937a-17b889bfb48c

📥 Commits

Reviewing files that changed from the base of the PR and between 8c7e198 and 0082b4d.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • crates/relayburn-cli/src/harnesses/mod.rs
  • crates/relayburn-cli/src/harnesses/opencode.rs
  • crates/relayburn-cli/src/harnesses/registry.rs

Comment thread crates/relayburn-cli/src/harnesses/opencode.rs Outdated
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: 0082b4d6be

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// `relayburn_sdk::query_verbs::state_status` tests and the codex
/// sibling. Poisoned-mutex recovery is intentional — a panicking
/// test shouldn't break every subsequent run.
static ENV_LOCK: Mutex<()> = Mutex::new(());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Share HOME mutation lock across harness test modules

This ENV_LOCK only serializes tests inside opencode.rs; codex.rs defines a separate lock, so cargo test (which runs tests in parallel by default) can still run both modules’ with_test_home helpers concurrently and race on process-global HOME. In that case session_root() assertions can intermittently read the other module’s value, and on Unix set_var/remove_var during concurrent env access is explicitly unsafe. Please use a single shared lock (or serial test attribute) for all tests mutating HOME in this crate.

Useful? React with 👍 / 👎.

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 56cfc2a. The two per-module locks are gone; both codex::tests and opencode::tests now share a single crates/relayburn-cli/src/harnesses/test_env::ENV_LOCK. with_test_home lives in the same module (gated by #[cfg(test)]) and preserves the existing catch_unwind + resume_unwind shape so a panicking assertion still restores HOME before propagating.

Concretely: cargo test of the relayburn-cli binary now serializes every harness HOME mutation through one mutex — concurrent session_root() assertions across the two adapter modules can no longer race. Verified with cargo test --workspace (610 SDK + 23 CLI lib + 58 binary + 10 smoke + 5 golden tests; all green).

Resolve registry.rs conflicts by unioning all three Wave 2 adapters:
- EAGER_ADAPTERS keeps claude (from #318 D5)
- RUNTIME_ADAPTERS keeps codex (#317 D6) + opencode (this branch, D7)
- RUNTIME_ADAPTER_NAMES = ["codex", "opencode"] (alphabetical)
- EXPECTED_HARNESS_NAMES = ["claude", "codex", "opencode"]

CHANGELOG.md additive: keep opencode bullet alongside D5/D6/D8 bullets.
mod.rs auto-merged with all three pub mod statements.
Cargo.lock taken from origin/main and confirmed unchanged after build.
CodeRabbit + Codex flagged: codex.rs and opencode.rs each defined a
private `static ENV_LOCK: Mutex<()>` for serializing `HOME` mutation
in tests, but `HOME` is process-global. `cargo test` runs modules in
parallel by default, so the two modules' `with_test_home` helpers
could acquire their own locks simultaneously and race on the global
env, intermittently leaking each other's sentinel values into
`session_root()` assertions.

Extract the lock + helper into a shared `harnesses::test_env` module
gated by `#[cfg(test)]`. Both adapter test modules now `use
crate::harnesses::test_env::with_test_home;` and funnel through one
crate-wide `ENV_LOCK`. The save-set-restore-`resume_unwind`
machinery (including `catch_unwind` so a panicking assertion still
restores `HOME` before propagating) lives in one place — adapters
that join later (e.g. a future `aider` harness) reuse the helper
without re-deriving the unwind-safety details.

Scope kept tight: SDK-side `RELAYBURN_*` env tests in
`relayburn_sdk::query_verbs` carry their own lock and don't share
this one. Lifting both into a workspace-wide test-utility crate is a
deliberate follow-up if HOME and RELAYBURN_HOME mutations ever need
to interlock; today the two scopes are independent.
@willwashburn willwashburn merged commit ad48f65 into main May 7, 2026
3 checks passed
@willwashburn willwashburn deleted the rust-port/cli-opencode-adapter branch May 7, 2026 01:09
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