Skip to content

fix(honcho): pinPeerName opt-in keeps memory unified across platforms (#14984)#15162

Closed
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/honcho-pin-peer-name
Closed

fix(honcho): pinPeerName opt-in keeps memory unified across platforms (#14984)#15162
briandevans wants to merge 2 commits into
NousResearch:mainfrom
briandevans:fix/honcho-pin-peer-name

Conversation

@briandevans

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #14984: when Hermes runs under a gateway (Telegram, Discord, Slack, ...) and Honcho is the active memory provider, the platform-native user ID (Telegram UID, Discord snowflake, ...) always wins over the `peer_name` configured in `honcho.json`. That's correct for multi-user bots — each user needs their own peer scope — but it's wrong for the vast majority of personal Hermes deployments where `peerName` is an unambiguous identity.

The failure mode: one physical user talks to their Hermes over Telegram, Discord, and Slack and ends up as three separate Honcho peers. Memory, peer-card, and dialectic context all fork per-platform.

Fix

New `pinPeerName` boolean on the host config, default `false` (preserves existing multi-user behaviour). When `true` and `peerName` is set, the configured peer_name beats the gateway's runtime identity.

```json
{
"peerName": "Igor",
"hosts": {
"hermes": { "pinPeerName": true }
}
}
```

Resolution order becomes (pinned case):

input chosen user_peer_id
`runtime_user_peer_name` skipped (opt-in flag active)
`config.peer_name` WINS — `"Igor"`
session-key fallback unreached

Config parsing follows the same host-block-overrides-root pattern as every other flag in `HonchoClientConfig.from_global_config` (the existing `_resolve_bool` helper).

Safety rail: `pinPeerName=true` with no `peerName` set is a no-op — otherwise the user peer would silently collapse to the session-key fallback and lose per-user scoping entirely. Explicit regression test for this.

Files changed

  • `plugins/memory/honcho/client.py`: new `pin_peer_name` field on `HonchoClientConfig`, parsed in `from_global_config` with host-block-overrides-root semantics via the existing `_resolve_bool` helper. No other behaviour touched.
  • `plugins/memory/honcho/session.py`: one-liner gate in `get_or_create` — `if self._runtime_user_peer_name and not pin_peer_name:`. Uses `getattr(..., "pin_peer_name", False)` as a defensive fallback so callers building partial config objects (several test fixtures across the codebase do this) don't break.
  • `tests/honcho_plugin/test_pin_peer_name.py`: 13 new tests in 3 classes covering config parsing, peer resolution order, and the cross-platform unification outcome.

Related Issue

Fixes #14984

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✅ Tests (adding or improving test coverage)

Test plan

  • `tests/honcho_plugin/test_pin_peer_name.py` — 13 new tests pass
  • Full honcho_plugin suite — 244 passed, 3 pre-existing skips, 0 regressions
  • `tests/test_honcho_client_config.py` — 7 existing config tests still pass
  • Default behaviour verified: runtime ID still wins when `pinPeerName` unset (regression guard — a silent drift here would merge memory across users of multi-user bots)

Test coverage detail

Group 1 — Config parsing (`TestPinPeerNameConfigParsing`, 5 tests)

  • `test_default_is_false` — `HonchoClientConfig()` defaults to `pin_peer_name=False`
  • `test_root_level_true` — `pinPeerName: true` at root parses correctly
  • `test_host_block_true` — `hosts.hermes.pinPeerName: true` parses correctly
  • `test_host_block_overrides_root` — host `false` overrides root `true` (matches every other flag)
  • `test_explicit_false_parses` — `pinPeerName: false` resolves to `False`

Group 2 — Peer resolution order (`TestPeerResolutionOrder`, 6 tests)

  • `test_runtime_wins_when_pin_is_false` — multi-user regression guard
  • `test_config_wins_when_pin_is_true` — the honcho: peerName in config should win over platform user ID for single-user setups #14984 fix
  • `test_pin_noop_when_peer_name_missing` — no silent collapse
  • `test_runtime_missing_falls_back_to_peer_name` — CLI-mode unchanged
  • `test_everything_missing_falls_back_to_session_key` — deepest fallback intact
  • `test_pin_does_not_affect_assistant_peer` — flag is user-peer-scoped only

Group 3 — Cross-platform unification (`TestCrossPlatformMemoryUnification`, 2 tests)

  • `test_telegram_and_discord_collapse_to_one_peer_when_pinned` — the user-visible outcome
  • `test_multiuser_default_keeps_platforms_separate` — negative control, a regression here would silently merge unrelated users' memory

Not in scope

  • A UX polish where a warning fires if `pinPeerName` is set but `peerName` isn't — deliberately left out since the no-op path is already the safe behaviour; we can add a one-time log if the maintainers want it.
  • Per-host pinning with different peer_names — current design says "if pinned, use the config peer_name for this host block" which is sufficient for the reported use case.

…NousResearch#14984)

When a gateway drives Hermes (Telegram, Discord, Slack, ...), it passes the
platform-native user ID as ``runtime_user_peer_name`` into the Honcho
session manager.  That ID wins over ``peer_name`` in ``honcho.json``, so a
single user who connects over three platforms ends up as three separate
Honcho peers — one per platform — with fragmented memory and no cross-
platform context continuity.

For multi-user bots this is correct (and must not change): each user gets
their own peer scope.  For the vast majority of personal Hermes deployments
the configured ``peer_name`` is an unambiguous identity, though, so the
reporter asked for an opt-in knob that pins the user peer to that value.

Fix: new ``pinPeerName`` boolean on the host config, default ``false``.
When ``true`` AND ``peerName`` is set, the configured peer_name beats the
gateway's runtime identity; every other resolution case is unchanged.

  honcho.json:
  {
    "peerName": "Igor",
    "hosts": {
      "hermes": { "pinPeerName": true }
    }
  }

  session.py (resolution order, pinned case):
    runtime_user_peer_name  →  skipped (opt-in flag active)
    config.peer_name        →  WINS   "Igor"
    session-key fallback    →  unreached

Parsing follows the same host-block-overrides-root pattern as every other
flag in HonchoClientConfig.from_global_config (``_resolve_bool`` helper).

Tests (tests/honcho_plugin/test_pin_peer_name.py — 13 cases, 5 groups):
- Config parsing: default, root true, host-block true, host overrides
  root, explicit false.
- Peer resolution: runtime wins by default (regression guard for multi-
  user bots), config wins when pinned, pin-without-peer_name is a no-op
  (prevents silent peer-id collapse to session-key fallback), CLI path
  where runtime is absent, deepest fallback intact, assistant peer
  untouched by the flag.
- Cross-platform unification: Telegram UID + Discord snowflake collapse
  to one peer when pinned; negative control confirms two distinct
  runtime IDs still produce two peers when unpinned.

244 honcho_plugin tests pass, 3 pre-existing skips, zero regressions.

Defensive detail: session.py uses ``getattr(self._config, "pin_peer_name",
False)`` so callers building partial config objects (several test fixtures
across the codebase do this) don't break if they haven't updated yet.
Runtime cost: one attr lookup per new session.

Closes NousResearch#14984

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 24, 2026 13:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in pinPeerName flag to Honcho config to allow single-user deployments to keep a stable Honcho user peer ID across multiple gateway platforms, preventing memory/context fragmentation (#14984).

Changes:

  • Add pin_peer_name to HonchoClientConfig and parse pinPeerName with host-block-overrides-root semantics.
  • Update Honcho session peer resolution to prefer configured peer_name over gateway runtime identity when pinning is enabled (and peer_name is set).
  • Add a dedicated test suite validating config parsing, resolution order, and cross-platform unification behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
plugins/memory/honcho/client.py Introduces pin_peer_name config field and parses pinPeerName via existing _resolve_bool helper.
plugins/memory/honcho/session.py Gates runtime user identity usage when pin_peer_name is active and peer_name is configured.
tests/honcho_plugin/test_pin_peer_name.py Adds coverage for parsing, peer selection precedence, and cross-platform peer unification/regression guards.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/plugins Plugin system and bundled plugins comp/gateway Gateway runner, session dispatch, delivery labels Apr 24, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briandevans

Copy link
Copy Markdown
Contributor Author

Pushed 37e09419 addressing the CI failure on the first run.

One honcho test elsewhere in the suite (tests/agent/test_memory_user_id.py::TestHonchoUserIdScoping::test_session_manager_prefers_runtime_user_id_over_config_peer_name) regressed because it passes a MagicMock() for config. My getattr(..., "pin_peer_name", False) fallback was supposed to protect against callers who haven't added the new attr — but on a MagicMock the attr EXISTS (returning a fresh MagicMock, which is truthy), so the guard fell through.

Tightened the gate to getattr(..., False) is True. Real configs from HonchoClientConfig.from_global_config always yield proper booleans, so strict equality matches the pinned case cleanly and rejects both unset-attr fallbacks and MagicMock stand-ins. Same trick for the peer_name existence check.

Verified locally:

  • tests/honcho_plugin/test_pin_peer_name.py — 13/13 pass
  • tests/agent/test_memory_user_id.py::TestHonchoUserIdScoping — 3/3 pass (previously failing)
  • Full tests/honcho_plugin/ + tests/test_honcho_client_config.py — 244+7 pass, 0 regressions

The other non-green lane on the initial run was the same test_custom_provider_model_switch / test_no_single_field_categories / test_hindsight_provider / test_registry baseline quartet I've reported on #13411 and #15158 — repro'd on clean origin/main, unrelated to this PR. New CI run should drop the honcho failure; the baseline 3–4 will persist until main is swept.

@briandevans

Copy link
Copy Markdown
Contributor Author

CI update for run 24893147547 on sha 37e09419 (the MagicMock-hardening follow-up):

Honcho test now green — the previously-failing test_session_manager_prefers_runtime_user_id_over_config_peer_name passes (my getattr(..., False) is True tightening handled the MagicMock-default truthy-attr trap).

Remaining 4 test failures are the standing baseline that I've been tracking across every open PR in this window — they reproduce on clean origin/main:

tests/hermes_cli/test_custom_provider_model_switch.py::...::test_saved_model_still_probes_endpoint
tests/hermes_cli/test_web_server.py::...::test_no_single_field_categories
tests/plugins/memory/test_hindsight_provider.py::...::test_local_embedded_setup_preserves_existing_key_when_input_left_blank
tests/tools/test_registry.py::...::test_matches_previous_manual_builtin_tool_set

None touch plugins/memory/honcho/ or this PR's diff. Focused honcho suite (tests/honcho_plugin/ + tests/test_honcho_client_config.py + the TestHonchoUserIdScoping class in test_memory_user_id.py) is 257 passed, 3 pre-existing skips, 0 regressions locally.

erosika pushed a commit to erosika/hermes-agent that referenced this pull request Apr 24, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
erosika pushed a commit to erosika/hermes-agent that referenced this pull request Apr 27, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kshitijk4poor pushed a commit that referenced this pull request Apr 27, 2026
…ck configs (#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briandevans

Copy link
Copy Markdown
Contributor Author

Closing — superseded by @erosika's #15381, which closed #14984 (cherry-pick consolidation that included this fix's intent).

Thanks @erosika.

ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dannyJ848 pushed a commit to dannyJ848/hermes-agent that referenced this pull request May 17, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
…ck configs (NousResearch#15162)

CI caught that ``test_session_manager_prefers_runtime_user_id_over_config_peer_name``
in ``tests/agent/test_memory_user_id.py`` failed after this branch: that
test passes a ``MagicMock`` for ``config``, where
``mock.pin_peer_name`` silently returns another ``MagicMock`` — truthy by
default.  My ``getattr(..., "pin_peer_name", False)`` fallback was
supposed to guard against callers that haven't added the new attr, but
MagicMock *does* have the attr — it just returns a live mock for it.

Tightened the gate to ``getattr(..., False) is True``.  Real configs
built via ``HonchoClientConfig.from_global_config`` always yield a
proper boolean, so strict equality matches the pinned case and rejects
both the unset-attr fallback and MagicMock stand-ins.  Added a comment
explaining why ``is True`` is intentional, not paranoid.

Also tightened the ``peer_name`` existence check to
``getattr(..., None)`` so a MagicMock with ``peer_name`` left at its
default (also truthy) doesn't spuriously enable pinning either.

Verified against both the new ``test_pin_peer_name.py`` suite (13/13
pass) and the previously-failing
``TestHonchoUserIdScoping`` (3/3 pass).  Zero behaviour change for real
``HonchoClientConfig`` values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

honcho: peerName in config should win over platform user ID for single-user setups

3 participants