spec: 007 platform features bundle — StalemateWorker, A2A, mobile, IdP, K8s handlers
8 features specified: StalemateWorker message enforcement, channel reply_to, A2A Agent Cards + inbound gateway, mobile-responsive UI, K8s reactive agents, enterprise IdP (GitHub/Google/Azure AD), CLAUDE.md acknowledgment protocol. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
bd166843d6
commit
a00394bd2b
@@ -0,0 +1,39 @@
|
||||
# Specification Quality Checklist: SynapBus v0.6.0 Platform Features Bundle
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-03-16
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- All 8 features specified with P1/P2/P3 priority levels
|
||||
- 20 functional requirements defined
|
||||
- 9 success criteria established
|
||||
- 6 edge cases documented
|
||||
- 12 assumptions recorded
|
||||
- Spec is ready for /speckit.plan
|
||||
@@ -0,0 +1,217 @@
|
||||
# Feature Specification: SynapBus v0.6.0 — Platform Features Bundle
|
||||
|
||||
**Feature Branch**: `007-platform-features-bundle`
|
||||
**Created**: 2026-03-16
|
||||
**Status**: Draft
|
||||
**Input**: 8 features covering message lifecycle enforcement, A2A protocol support, mobile UI, enterprise identity, reactive agents, and agent communication conventions.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 — Stale Message Enforcement (Priority: P1)
|
||||
|
||||
An agent receives a DM but its session ends without marking the message as done. The StalemateWorker detects the orphaned message and takes corrective action: auto-failing processing messages after 24h, sending reminders for pending DMs after 4h, and escalating to the human owner after 48h.
|
||||
|
||||
**Why this priority**: Without enforcement, messages silently drop. This is the #1 reliability issue for agent communication — agents must be accountable for messages they receive.
|
||||
|
||||
**Independent Test**: Send a DM to an agent, wait for the configured timeout, verify the worker auto-fails the message and sends a system notification.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a DM in "processing" status claimed 25 hours ago, **When** the StalemateWorker runs, **Then** the message status changes to "failed" with reason "claim timeout exceeded" and a system DM is sent to the claiming agent.
|
||||
2. **Given** a DM in "pending" status created 5 hours ago, **When** the StalemateWorker runs, **Then** a reminder DM from "system" agent is sent to the target agent with priority 7.
|
||||
3. **Given** a DM in "pending" status created 49 hours ago that already received a 4h reminder, **When** the StalemateWorker runs, **Then** a message is posted to #approvals channel with priority 9 including the original message details.
|
||||
4. **Given** a DM from the "system" agent, **When** the StalemateWorker runs, **Then** the message is skipped (no infinite reminder loops).
|
||||
5. **Given** configurable thresholds via environment variables, **When** the admin sets SYNAPBUS_STALEMATE_PROCESSING_TIMEOUT=12h, **Then** processing messages are auto-failed after 12 hours instead of the default 24.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 — Channel Reply Threading (Priority: P1)
|
||||
|
||||
An agent reads a bug report in #bugs-synapbus and wants to reply with "DONE: Fixed in commit abc123" as a threaded reply to the original message. The reply_to parameter on send_channel_message enables this.
|
||||
|
||||
**Why this priority**: Without reply_to on channel messages, agents cannot create threaded conversations in channels. This blocks the ACK/DONE acknowledgment convention.
|
||||
|
||||
**Independent Test**: Send a channel message, then send a reply_to that message, verify the reply is linked in the thread.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a channel message with ID 42, **When** an agent calls send_channel_message with reply_to=42, **Then** the new message is created with reply_to pointing to message 42.
|
||||
2. **Given** a reply_to value pointing to a non-existent message, **When** an agent calls send_channel_message, **Then** the message is created without reply_to (graceful fallback).
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 — A2A Agent Discovery (Priority: P2)
|
||||
|
||||
An external developer wants to discover what agents are available on a SynapBus instance. They fetch `/.well-known/agent-card.json` and get a structured Agent Card listing all agents as skills with their capabilities, supported authentication methods, and contact endpoint.
|
||||
|
||||
**Why this priority**: Agent discovery is the foundation for A2A interoperability. Without it, external systems cannot find or interact with SynapBus agents.
|
||||
|
||||
**Independent Test**: Fetch `/.well-known/agent-card.json` via curl, verify it returns valid A2A Agent Card JSON with skills matching registered agents.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** 5 registered agents with capabilities, **When** fetching /.well-known/agent-card.json, **Then** the response is a valid A2A Agent Card with 5 skills.
|
||||
2. **Given** an agent with no capabilities set, **When** generating the Agent Card, **Then** the agent appears as a skill with name and description but empty tags.
|
||||
3. **Given** the admin updates an agent's capabilities, **When** the Agent Card is fetched again, **Then** the updated capabilities are reflected.
|
||||
4. **Given** SynapBus supports API key and OAuth auth, **When** generating the Agent Card, **Then** security_schemes includes both apiKey and oauth2 entries.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 — Mobile Web UI (Priority: P2)
|
||||
|
||||
A user opens SynapBus Web UI on their phone via hub.synapbus.dev. The sidebar is hidden behind a hamburger menu, messages are readable, and they can compose and send messages. The approve/reject workflow for #approvals is usable on mobile.
|
||||
|
||||
**Why this priority**: Mobile access enables human oversight of agents anywhere — approving actions, reading digests, monitoring channels from phone.
|
||||
|
||||
**Independent Test**: Open the Web UI at 375px viewport width, verify sidebar is a drawer, messages render correctly, compose area works.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a viewport width < 768px, **When** the page loads, **Then** the sidebar is hidden and a hamburger button appears in the header.
|
||||
2. **Given** the hamburger button is tapped, **When** the sidebar drawer opens, **Then** it slides in from the left with an overlay backdrop.
|
||||
3. **Given** the sidebar drawer is open, **When** the user taps a channel link, **Then** the drawer closes and the channel page loads.
|
||||
4. **Given** a channel page on mobile, **When** the user types a message, **Then** the compose area is visible above the mobile keyboard.
|
||||
5. **Given** the header search box on mobile, **When** the user taps it, **Then** it expands to fill available width.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 — A2A Inbound Gateway (Priority: P3)
|
||||
|
||||
An external A2A agent (built with Google ADK) discovers SynapBus via the Agent Card, then sends a task to "research-mcpproxy" agent. SynapBus creates a DM to that agent and returns a Task object. When research-mcpproxy replies via MCP, the A2A task updates to COMPLETED and the external agent retrieves the result.
|
||||
|
||||
**Why this priority**: This enables SynapBus to participate in the broader agent ecosystem. External agents from any framework can delegate tasks to SynapBus agents.
|
||||
|
||||
**Independent Test**: Send a JSON-RPC message.send to /a2a targeting an agent, verify a Task is returned. Have the agent reply via MCP, verify the task transitions to COMPLETED.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a valid A2A message.send request targeting agent "research-mcpproxy", **When** POST /a2a is called, **Then** a Task with state SUBMITTED is returned and a DM is created for the target agent.
|
||||
2. **Given** an A2A task in SUBMITTED state, **When** the target agent replies via MCP send_message, **Then** the task state updates to COMPLETED with the reply as an artifact.
|
||||
3. **Given** an A2A tasks.get request with a valid task ID, **When** POST /a2a is called, **Then** the current task state and history are returned.
|
||||
4. **Given** an A2A tasks.cancel request, **When** POST /a2a is called, **Then** the task state updates to CANCELED.
|
||||
5. **Given** an unauthenticated request to /a2a, **When** the request lacks auth headers, **Then** a 401 response is returned.
|
||||
|
||||
---
|
||||
|
||||
### User Story 6 — Reactive Agent Activation via K8s (Priority: P3)
|
||||
|
||||
A user sends a DM or @mentions "research-mcpproxy" in a channel. SynapBus detects that research-mcpproxy has a registered K8s handler and spawns a K8s Job that runs the agent with the message context. The agent processes the message and responds via SynapBus MCP.
|
||||
|
||||
**Why this priority**: Transforms agents from periodic batch workers to responsive, event-driven workers. Sub-10-second response to DMs and @mentions.
|
||||
|
||||
**Independent Test**: Register a K8s handler for an agent, send a DM, verify a K8s Job is created with correct env vars.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** agent "research-mcpproxy" has a registered K8s handler for "message.received" events, **When** a DM is sent to research-mcpproxy, **Then** a K8s Job is created with SYNAPBUS_MESSAGE_ID, SYNAPBUS_MESSAGE_BODY, SYNAPBUS_FROM_AGENT env vars.
|
||||
2. **Given** agent "research-mcpproxy" has a registered K8s handler for "message.mentioned" events, **When** a channel message contains @research-mcpproxy, **Then** a K8s Job is created.
|
||||
3. **Given** the admin registers a handler via CLI, **Then** the handler is stored and active.
|
||||
4. **Given** a K8s handler with a 30-minute timeout, **When** the spawned Job exceeds the timeout, **Then** the Job is terminated.
|
||||
|
||||
---
|
||||
|
||||
### User Story 7 — Enterprise SSO Login (Priority: P3)
|
||||
|
||||
A Gcore employee navigates to the SynapBus login page and sees "Sign in with Microsoft" alongside the existing username/password form. They click it, authenticate with their Azure AD credentials, and are automatically provisioned as a SynapBus user with the "user" role (mapped from their Azure AD group). On subsequent visits, they log in with one click.
|
||||
|
||||
**Why this priority**: Enterprise identity integration is required for organizational deployment. Manual user provisioning doesn't scale.
|
||||
|
||||
**Independent Test**: Configure Azure AD IdP, navigate to login page, verify "Sign in with Microsoft" button appears, complete OAuth flow, verify user is created.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** GitHub IdP is configured, **When** the login page loads, **Then** a "Sign in with GitHub" button appears.
|
||||
2. **Given** Google IdP is configured with allowed_domains=["gcore.com"], **When** a user with @gmail.com tries to log in, **Then** access is denied. When a user with @gcore.com logs in, **Then** access is granted.
|
||||
3. **Given** Azure AD IdP is configured with group_mapping, **When** a user in the "SynapBus-Admins" group logs in, **Then** they are provisioned with the "admin" role.
|
||||
4. **Given** a user first logs in via GitHub, **When** they later log in via Google with the same verified email, **Then** both identities are linked to the same SynapBus user.
|
||||
5. **Given** no IdPs are configured, **When** the login page loads, **Then** only the username/password form appears (backward compatible).
|
||||
|
||||
---
|
||||
|
||||
### User Story 8 — Agent Communication Protocol (Priority: P1)
|
||||
|
||||
All Claude Code and Gemini CLI agents have standardized CLAUDE.md/GEMINI.md instructions for SynapBus communication: checking inbox on session start, claiming and processing DMs, acknowledging channel tasks with ACK/DONE replies, following message format conventions, and being aware of StalemateWorker timeouts.
|
||||
|
||||
**Why this priority**: Without consistent instructions, agents behave unpredictably — some check inbox, some don't, messages go unacknowledged. This is the glue that makes all other features useful.
|
||||
|
||||
**Independent Test**: Start a Claude Code session with the updated CLAUDE.md, verify it calls my_status first and processes pending DMs.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the updated CLAUDE.md is present, **When** a Claude Code session starts, **Then** the agent checks SynapBus inbox before starting planned work.
|
||||
2. **Given** pending DMs with priority >= 7, **When** the agent reads inbox, **Then** it claims and processes high-priority DMs first.
|
||||
3. **Given** a channel message tagged [TASK] directed at the agent, **When** the agent reads the channel, **Then** it replies with "ACK: <summary>" and later "DONE: <result>".
|
||||
4. **Given** the StalemateWorker timeout of 24h, **When** an agent session is ending with claimed messages, **Then** the CLAUDE.md instructions remind it to mark all claimed messages as done or failed.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when the StalemateWorker runs but the "system" agent doesn't exist? Worker skips reminder/escalation and logs a warning.
|
||||
- What happens when an A2A message targets a non-existent agent? Return A2A error response with "agent not found".
|
||||
- What happens when a K8s handler Job fails to create (API unavailable)? Log error, don't crash SynapBus, message remains in pending state.
|
||||
- What happens when multiple IdPs return the same email for different users? Link to the existing user with that email (auto-link by verified email).
|
||||
- What happens when the agent-card.json is requested and no agents have capabilities set? Return valid card with skills containing only name/description from agent records.
|
||||
- What happens when mobile viewport is exactly 768px? Treated as desktop (breakpoint is < 768px).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST run a background StalemateWorker that auto-fails processing DMs older than a configurable timeout (default 24h).
|
||||
- **FR-002**: System MUST send reminder DMs for pending messages older than a configurable threshold (default 4h).
|
||||
- **FR-003**: System MUST escalate pending messages to #approvals after a configurable threshold (default 48h).
|
||||
- **FR-004**: System MUST skip messages from/to the "system" agent in StalemateWorker to avoid loops.
|
||||
- **FR-005**: The send_channel_message action MUST accept an optional reply_to parameter (message ID).
|
||||
- **FR-006**: System MUST serve a valid A2A Agent Card at GET /.well-known/agent-card.json.
|
||||
- **FR-007**: The Agent Card MUST list all active agents as A2A skills with their capabilities.
|
||||
- **FR-008**: System MUST support agent capability declaration via admin CLI and API.
|
||||
- **FR-009**: Web UI MUST be usable on viewports as narrow as 375px with a slide-out sidebar drawer.
|
||||
- **FR-010**: System MUST provide an A2A JSON-RPC endpoint at POST /a2a supporting message.send, tasks.get, and tasks.cancel.
|
||||
- **FR-011**: A2A message.send MUST create a DM to the target agent and return a Task object.
|
||||
- **FR-012**: System MUST track A2A task lifecycle (SUBMITTED, WORKING, COMPLETED, FAILED, CANCELED).
|
||||
- **FR-013**: System MUST support K8s Job handler registration per agent for reactive activation.
|
||||
- **FR-014**: K8s handlers MUST spawn Jobs with message context as environment variables.
|
||||
- **FR-015**: System MUST support external identity providers (GitHub, Google, Azure AD) via OIDC/OAuth.
|
||||
- **FR-016**: External IdP login MUST auto-provision new users on first authentication.
|
||||
- **FR-017**: System MUST support account linking by verified email across multiple IdPs.
|
||||
- **FR-018**: Login page MUST display IdP buttons alongside existing username/password form.
|
||||
- **FR-019**: CLAUDE.md MUST include SynapBus communication protocol with inbox check, claim-done loop, ACK/DONE convention, and StalemateWorker awareness.
|
||||
- **FR-020**: All StalemateWorker thresholds MUST be configurable via environment variables.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **StalemateConfig**: Processing timeout, reminder threshold, escalation threshold, check interval.
|
||||
- **A2A AgentCard**: Hub-level metadata listing agents as skills with auth schemes.
|
||||
- **A2A Task**: External task with ID, state, context_id, target agent, conversation mapping.
|
||||
- **K8s Handler**: Agent name, container image, events, namespace, resources, timeout, env vars.
|
||||
- **UserIdentity**: Links external IdP identity (provider + external_id) to local user.
|
||||
- **IdentityProvider**: IdP configuration (type, client_id, client_secret, issuer_url, domain restrictions).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: No DM remains in "processing" status for more than 24 hours (default) without being auto-failed.
|
||||
- **SC-002**: All pending DMs older than 4 hours (default) receive a system reminder notification.
|
||||
- **SC-003**: The Agent Card endpoint returns a valid response in under 100ms.
|
||||
- **SC-004**: Web UI is fully functional (navigation, messaging, search) on a 375px-wide viewport.
|
||||
- **SC-005**: An external A2A agent can send a task and receive a completed result within the target agent's response time.
|
||||
- **SC-006**: K8s Job handlers activate within 10 seconds of a triggering message.
|
||||
- **SC-007**: Users can log in via GitHub, Google, or Azure AD with zero manual account provisioning.
|
||||
- **SC-008**: All existing tests continue to pass (zero regression).
|
||||
- **SC-009**: Agent communication protocol documentation covers all common scenarios (bugs, completions, discoveries, approvals).
|
||||
|
||||
## Assumptions
|
||||
|
||||
- A2A protocol v1.0 specification is stable (released March 12, 2026).
|
||||
- The a2a-go SDK (github.com/a2aproject/a2a-go) requires Go 1.24+ and is pure Go (zero CGO).
|
||||
- Zero CGO constraint applies to all new dependencies.
|
||||
- Mobile-responsive changes are CSS/Svelte only, no new npm dependencies added.
|
||||
- Enterprise IdP follows one SynapBus instance per organization (no multi-tenancy).
|
||||
- K8s handlers build on the existing internal/k8s package (JobRunner, K8sDispatcher).
|
||||
- StalemateWorker follows the same patterns as ExpiryWorker and RetentionWorker.
|
||||
- The "system" agent exists (created at startup) for sending system notifications.
|
||||
- Existing agent API keys and OAuth tokens remain fully functional (backward compatible).
|
||||
- coreos/go-oidc/v3 is used for OIDC discovery and token verification (pure Go).
|
||||
- golang.org/x/oauth2 is already an indirect dependency (v0.30.0) and will be promoted to direct.
|
||||
Reference in New Issue
Block a user