honcho/tests/routes
Vineeth Voruganti 331f6ff416 fix(scopes): exclude scope memberships from the session observer limit
Scope memberships carry observe_others=true, so every scope counted against
SESSION_OBSERVERS_LIMIT (default 10) — capping scopes-per-session at the limit
minus the session's real observers, and reporting the failure as
`400 Cannot create session <name> with 11 observers. ... Observers are peers
with 'observe_others' set to true.` on a membership call. Wrong on three counts:
the ceiling is undocumented and contradicts RFC §5.1 ("sessions belong to any
number of scopes"), the message describes session creation, and it leaks the
word "observer" through a facade whose entire job is hiding observers (RFC
goal 5). The limit exists to bound per-observer deriver fan-out for real peers;
a scope costs document rows, not LLM calls (RFC §5.2), so it does not belong in
that budget.

Excluded from both halves of the check in `_get_or_add_peers_to_session`: the
incoming names via a flag-based lookup, existing memberships via a correlated
NOT EXISTS on `scope_peer_clause()` — the same pattern the replacement and
removal paths already use, so the exclusion holds regardless of concurrent
scope creation. The early `count_observers_in_config(session.peer_names)` check
in `get_or_create_session` is left alone: `peer_names` cannot contain a scope,
and `scopes` is a separate field.

`reject_scope_peers` is split into a `scope_peer_names()` query helper plus a
two-line raiser so the observer count reuses the authoritative name-AND-flag
predicate instead of growing a third copy of it. Still costs nothing on the
common path — no reserved-prefix name in the input means no query at all.

Also caps `SessionCreate.scopes` at 100, matching `ScopeSessionsAdd.session_ids`.
This belongs in the same commit: the observer limit was the only thing bounding
that list, so removing it turns an unbounded `scopes` array into a peer row and
a membership row per element, committed — the single-request path to the
cardinality anti-pattern RFC §8 warns about. Partly answers OQ6: no per-session
cap, 100 per request.

Tests: a session joins SESSION_OBSERVERS_LIMIT + 2 scopes through both the
facade and session creation; real observers over the limit still 400, so the
carve-out cannot quietly disable the limit; 101 scopes is a 422.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 22:52:31 -04:00
..
__init__.py [0.0.10] Release 2024-07-25 13:45:27 -04:00
test_auth_route_policy.py Fix scoped JWTs (#679) 2026-06-22 17:30:00 -04:00
test_conclusions.py Abigail/conclusions level filter (#851) 2026-07-01 10:48:01 -04:00
test_files.py fix(files): handle empty json uploads safely (#434) 2026-03-18 18:36:34 -04:00
test_keys.py feat: honcho 3.0, sdks 2.0, excise stainless, update v3 docs, changelogs (#331) 2026-01-22 15:16:28 -05:00
test_messages.py feat(llm backend): enable combined tool calling + structured output in the LLM backend transport layer (#907) 2026-07-15 11:47:49 -04:00
test_peers.py feat(dialectic): optional structured outputs with limited schema for Dialectic calls (#896) 2026-07-20 18:46:49 -04:00
test_queue_status.py Refactor clients.py to add modern features and more flexible configuration (#459) 2026-04-20 02:46:37 -04:00
test_scope_route_policy.py fix(scopes): refuse future scopes in observed positions, preserve scope membership 2026-07-29 16:07:52 -04:00
test_scoped_api.py Fix scoped JWTs (#679) 2026-06-22 17:30:00 -04:00
test_scopes.py fix(scopes): exclude scope memberships from the session observer limit 2026-07-29 22:52:31 -04:00
test_sessions.py feat(api): restore reverse pagination (#685) 2026-05-21 13:40:47 -04:00
test_validation_api.py Align API contract with DB contract for IDs (#684) 2026-05-14 16:37:39 -04:00
test_webhooks.py feat: honcho 3.0, sdks 2.0, excise stainless, update v3 docs, changelogs (#331) 2026-01-22 15:16:28 -05:00
test_workspaces.py Session-purity invariant + card_refresh dream type (DEV-2000) (#883) 2026-07-23 14:22:07 -04:00