Skip to content

fix(ctl): openab set/get thread.name always fails — thread registry never populated #1215

Description

@chaodu-agent

Description

openab set thread.name "..." --thread <id> always fails with:

✗ unknown thread (use --thread or register via message dispatch)

…for every thread, with or without --thread. The thread.name control command can never succeed in the current code.

Root cause: RuntimeHandler::handle_set resolves the target thread through an in-memory thread_id → platform registry, but that registry is never populated.

resolve() requires a registry hit even when --thread is supplied:

openab/src/ctl.rs

Lines 176 to 182 in 00ec0e0

async fn resolve(&self, thread_id: Option<&str>) -> Option<(Arc<dyn ChatAdapter>, String)> {
let tid = thread_id?;
let platform = self.registry.read().await.get(tid).cloned()?;
let adapter = self.adapters.get(&platform)?.clone();
Some((adapter, tid.to_string()))
}
}

The only function that writes to the registry, register_thread, is dead code — marked #[allow(dead_code)] with zero call sites anywhere in src/ or crates/:

openab/src/ctl.rs

Lines 145 to 148 in 00ec0e0

#[allow(dead_code)]
pub async fn register_thread(registry: &ThreadRegistry, thread_id: &str, platform: &str) {
registry.write().await.insert(thread_id.to_string(), platform.to_string());
}

In main.rs the registry is created and handed only to the reader side (RuntimeHandler::new), never to the dispatch/adapter side that would record thread_id → platform. The comment even claims it is "Populated on message dispatch", but that wiring was never implemented:

openab/src/main.rs

Lines 314 to 315 in 00ec0e0

// Thread registry: thread_id → platform. Populated on message dispatch.
let ctl_registry = ctl::new_registry();

So self.registry is always empty → resolve() returns Noneunknown thread.

Not a regression. The feature was incomplete from the start: ctl.rs was added in #1147 ("openab set/get — Unix socket IPC (Phase 1: thread.name)") and register_thread shipped as dead code then. There is no prior working state.

Architectural note: the registry lives in the openab bin (src/ctl.rs), but message dispatch lives in openab-core, so populating it requires threading the registry (or a register callback) from the bin into the core dispatcher — which is why "Phase 2" was deferred and never landed.

Steps to Reproduce

  1. Run any bot (openab run) with at least one adapter (e.g. Discord).
  2. From inside the container, run:
    openab set thread.name "test thread name" --thread <any-thread-id>
    
  3. Observe: ✗ unknown thread (use --thread or register via message dispatch) — even though --thread was provided and the bot is actively handling that thread.

(get thread.name is likewise unusable.)

Expected Behavior

openab set thread.name --thread <id> should rename the thread for any thread the bot is handling.

Proposed fix:

  1. Wire register_thread into the dispatch path — when the bot dispatches a message in a thread, record thread_id → platform in the ctl registry. This requires passing the registry (or a registration hook) from main.rs into the openab-core dispatcher. Then --thread <id> resolves for any thread seen during the current process lifetime.
  2. Single-adapter fallback (quick win): if exactly one adapter is configured, resolve() should fall back to it even without a registry hit — making set/get work immediately for single-platform bots (e.g. Discord-only) without depending on prior dispatch.
  3. Fix the misleading error message / the register via message dispatch wording once registration actually works.

Note the registry is in-memory and per-process, so even after the fix it is expected to be empty immediately after a restart until the bot handles a message in the thread (the single-adapter fallback avoids this for single-platform bots).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingp2Medium — planned worksession

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions