Skip to content

Codex bridge does not pass the owner ID to watch-once, causing the inbox subscription to be skipped #605

Description

@joelmitz

Environment

  • agmsg: v1.1.13
  • Host: Codex
  • Delivery mode: monitor
  • OS: Linux
  • Codex bridge: app-server based

Symptom

The Codex bridge does not trigger an inbox notification even when unread messages exist.
The bridge log repeatedly contains errors like these:

codex-bridge: watch-once failed with exit 1: agmsg watch: skipping pairs held by other sessions: <team>/<agent>(<owner-id>)
watch-once: no available subscription for project=<project> type=codex name=* team=*
codex-bridge: stopping after 3 consecutive watch-once failure(s)

Investigation

armWatch() in the Codex bridge starts watch-once.sh with the following information:

<project> codex --timeout <seconds> --interval <seconds> --pair <team><TAB><agent>

The command does not include the owner ID used to identify the actas lock owner.

At the same time, watch-once.sh calls agmsg_subscription_pairs() as follows:

agmsg_subscription_pairs "$PROJECT_PATH" "$AGENT_TYPE" "" "$ACTIVE_NAME"

The third argument is the owner ID, but it is always an empty string.

agmsg_subscription_pairs() uses this value to check actas locks.
When the value does not match the lock owner, the identity is excluded as other:<owner>.

Therefore, when a lock exists for the bridge's own identity, notification delivery stops through this sequence:

Start watch-once without an owner ID
        ↓
The value does not match the existing lock owner
        ↓
Exclude the identity from the subscription set
        ↓
No available subscription
        ↓
watch-once exits with status 1
        ↓
The bridge stops after three consecutive failures

Difference between 1.1.12 and 1.1.13

armWatch() in v1.1.12 and v1.1.13 both omit the owner ID when starting watch-once.sh.

Therefore, the missing owner ID cannot be attributed solely to the 1.1.13 release commit.

However, 1.1.13 also includes changes related to seating roles from app-server loaded threads, recording the armed thread in the role session, and resolving the app-server endpoint.
When the bridge reconnects after these changes while old actas locks or role-session records remain, the missing owner ID can surface as a notification failure.

Proposed fix

The following changes appear to be needed:

  1. Add --owner-id <instance_id> to watch-once.sh.
  2. Pass that value as the third argument to agmsg_subscription_pairs().
  3. Resolve the instance ID associated with the Codex bridge and include it in the armWatch() spawn command.
  4. If the owner ID cannot be resolved, fail closed and log the reason instead of treating an existing lock as owned by the bridge.
  5. Add self-tests for the three cases: owner ID missing, owner ID matching, and owner ID not matching.

The Codex thread ID and the actas lock owner ID are different identifiers.
Passing the thread ID as a substitute is not sufficient to perform the lock ownership check correctly.

Additional information

No direct edits were made to the database or team data during this investigation.
When delivery succeeds, the bridge log records wakeup and started turn, and the unread message is passed to the current Codex thread.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions