feat(server): team collaboration features #1126

Merged
HAL9000 merged 8 commits from feature/m9-team-collab into master 2026-05-29 09:53:33 +00:00

8 Commits

Author SHA1 Message Date
controller-ci-rerun b1009b3c99 chore: re-trigger CI [controller]
CI / push-validation (pull_request) Successful in 19s
CI / helm (pull_request) Successful in 26s
CI / lint (pull_request) Successful in 35s
CI / build (pull_request) Successful in 37s
CI / typecheck (pull_request) Successful in 54s
CI / quality (pull_request) Successful in 57s
CI / security (pull_request) Successful in 1m12s
CI / integration_tests (pull_request) Successful in 2m58s
CI / unit_tests (pull_request) Successful in 4m37s
CI / docker (pull_request) Successful in 1m39s
CI / coverage (pull_request) Successful in 11m42s
CI / status-check (pull_request) Successful in 3s
2026-05-29 05:21:29 -04:00
HAL9000 c690ae12ad fix(server): return JSON-RPC -32700 on non-JSON request body
CI / lint (pull_request) Successful in 45s
CI / helm (pull_request) Successful in 30s
CI / typecheck (pull_request) Successful in 1m2s
CI / quality (pull_request) Successful in 1m7s
CI / build (pull_request) Successful in 56s
CI / security (pull_request) Successful in 1m13s
CI / push-validation (pull_request) Successful in 27s
CI / integration_tests (pull_request) Successful in 3m1s
CI / unit_tests (pull_request) Failing after 6m17s
CI / coverage (pull_request) Has been skipped
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 3s
Wrap `await request.json()` in its own try-except for
`json.JSONDecodeError` so malformed/non-JSON request bodies yield
HTTP 400 with JSON-RPC error code -32700 (Parse error) instead of
propagating unhandled to FastAPI's ServerErrorMiddleware and
returning HTTP 500.

Update the BDD step `step_post_a2a_malformed` to send actual raw
non-JSON bytes (`content=b"not-valid-json"`) so the scenario
exercises the JSON parse failure path rather than the existing
A2aRequest validation path (-32600).

ISSUES CLOSED: #863
2026-05-29 05:08:08 -04:00
HAL9000 41b23ef987 fix(server): accept operation alias and return result directly from /a2a endpoint
The /a2a endpoint was rejecting requests that used the proprietary
"operation" field (instead of JSON-RPC "method"), causing the two
A2A dispatch BDD scenarios and the Robot integration test to fail
with HTTP 400 instead of the expected 200/404.

Two fixes:
- asgi_app.py: normalise body by promoting "operation" → "method"
  before constructing A2aRequest; return response.result directly
  instead of the full JSON-RPC envelope so callers can read
  data["status"] at the top level
- facade.py: _handle_health_check now returns {"status": "ok"}
  matching the test contract (data["status"] == "ok")
2026-05-29 05:08:08 -04:00
HAL9000 fbab702474 fix(server): enforce RBAC, add RLock guards, fix A2aRequest.method
- Add optional caller_user_id to all mutating TeamCollaborationService
  methods; enforce_permission() is now called on every write/read that
  requires access control, making the RBAC model functional rather than
  decorative (addresses HAL9000 CRITICAL findings)
- Protect _members and _version_stamps with threading.RLock (RLock used
  so enforce_permission can be called from within the locked section
  without deadlocking); update_version inlines stamp creation to stay
  under the lock atomically
- Use UTC-aware datetime.now(tz=UTC) throughout domain model fields and
  methods (addresses freemo comment #2)
- Fix A2aRequest.operation -> .method typo in asgi_app.py (pre-existing
  typecheck failure in this PR)

ISSUES CLOSED: #863
2026-05-29 05:08:08 -04:00
freemo 08868e1e55 test: boost coverage for server lifecycle and team collaboration
Add Behave BDD scenarios covering:
- ServerLifecycle.start() with mocked uvicorn (full lifecycle)
- run_server() convenience function with Settings defaults and overrides
- Signal handler installation and non-main-thread edge case
- TeamCollaborationService validation edge cases (empty args)
- SessionRegistry validation edge cases and get_active_sessions
- VersionConflictError negative version validation
- Untracked resource version stamp creation path

These tests cover previously uncovered validation branches and the
server lifecycle start/shutdown paths to maintain >=97% coverage.
2026-05-29 05:08:08 -04:00
freemo 32b9e43cc3 fix: rename cls to klass in _validate_protocol staticmethod for pyright compliance 2026-05-29 05:08:08 -04:00
freemo b5f56a6fb8 feat(server): team collaboration features
Implemented multi-user connection handling with user identity tracking
(TeamMember with owner/admin/member/viewer roles), role-based access
control (TeamPermission with read/write/admin/manage_members), concurrent
session support (SessionRegistry with thread-safe locking and per-user/
per-project queries), and optimistic-locking conflict resolution
(VersionStamp with last-writer-wins, reject, and merge strategies).

Added TeamCollaborationService as the central orchestrator for all
collaboration operations: team membership management, permission
enforcement, session lifecycle, and version-stamp conflict detection/
resolution. The service cleans up user sessions when members are removed.

Domain models follow existing patterns: Pydantic BaseModel with
ConfigDict, StrEnum enums, ULID identifiers, and an error hierarchy
rooted in TeamCollaborationError.

Includes 48 Behave BDD scenarios (178 steps) covering all models,
service operations, and edge cases, plus 15 Robot Framework integration
tests for end-to-end workflow validation.

ISSUES CLOSED: #863
2026-05-29 05:08:08 -04:00
freemo c6ccb85bb8 feat(server): ASGI endpoint via uvicorn
Implement FastAPI-based ASGI application served by uvicorn for
the CleverAgents server mode. Add health check endpoint, A2A
JSON-RPC routing, configurable host:port binding, and graceful
shutdown handling. Server launches via `agents server start`.

- Add FastAPI ASGI app factory at infrastructure/server/asgi_app.py
  with /.well-known/agent.json (Agent Card), /health (liveness),
  and /a2a (A2A JSON-RPC 2.0 dispatch via A2aLocalFacade)
- Add ServerLifecycle class at infrastructure/server/server_lifecycle.py
  wrapping uvicorn.Server with SIGTERM/SIGINT graceful shutdown
- Add `agents server start` CLI command with --host, --port, --log-level
  options, resolving defaults from Settings
- Add fastapi>=0.115.0 dependency to pyproject.toml (uvicorn already present)
- Add Behave BDD tests (features/server_lifecycle.feature, 20 scenarios)
- Add Robot Framework integration tests (robot/server_lifecycle.robot)
- Update CHANGELOG.md and vulture_whitelist.py

ISSUES CLOSED: #862
2026-05-29 05:08:08 -04:00