Skip to content

Commit 6fa5883

Browse files
docs: redesign 013 spec with Health as single source of truth
- Health becomes the single source of truth for per-server issues - Add new Health actions: set_secret, configure - Doctor() aggregates from Health instead of independent detection - UI navigates to fix locations (secrets page, config tab) - Remove OAuthState/ConnectionState structured objects from scope 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4da33cd commit 6fa5883

6 files changed

Lines changed: 583 additions & 545 deletions

File tree

specs/013-structured-server-state/contracts/api-changes.md

Lines changed: 72 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -5,169 +5,106 @@
55

66
## Overview
77

8-
This document describes API changes for adding structured state objects. All changes are **additive** - existing fields remain unchanged for backwards compatibility.
8+
This document describes API changes for making Health the single source of truth. Changes are minimal - only extending the `action` enum in HealthStatus.
99

1010
## Affected Endpoints
1111

1212
| Endpoint | Change Type | Description |
1313
|----------|-------------|-------------|
14-
| `GET /api/v1/servers` | Additive | Add `oauth_state`, `connection_state` to each server |
15-
| `GET /api/v1/diagnostics` | Modified | Aggregate from `server.Health` instead of raw fields |
14+
| `GET /api/v1/servers` | Extended | Health.action has new values |
15+
| `GET /api/v1/diagnostics` | Internal | Now aggregates from Health (no schema change) |
1616

1717
## Schema Changes
1818

19-
### Server Object (Additive)
19+
### HealthStatus.action (Extended)
2020

21-
**New Fields**:
21+
**Current values**: `login`, `restart`, `enable`, `approve`, `view_logs`, `""`
2222

23-
```yaml
24-
Server:
25-
type: object
26-
properties:
27-
# ... existing properties unchanged ...
28-
29-
oauth_state:
30-
$ref: '#/components/schemas/OAuthState'
31-
description: OAuth authentication state (only present if OAuth configured)
32-
nullable: true
33-
34-
connection_state:
35-
$ref: '#/components/schemas/ConnectionState'
36-
description: Connection state (always present)
37-
```
38-
39-
### New Schema: OAuthState
23+
**New values**: `set_secret`, `configure`
4024

4125
```yaml
42-
OAuthState:
26+
HealthStatus:
4327
type: object
44-
required:
45-
- status
46-
- retry_count
47-
- user_logged_out
48-
- has_refresh_token
4928
properties:
50-
status:
51-
type: string
52-
enum: [authenticated, expired, error, none]
53-
description: Current OAuth authentication status
54-
token_expires_at:
29+
action:
5530
type: string
56-
format: date-time
57-
description: When the access token expires (ISO 8601)
58-
last_attempt:
59-
type: string
60-
format: date-time
61-
description: When the last OAuth flow was attempted
62-
retry_count:
63-
type: integer
64-
minimum: 0
65-
description: Number of OAuth retry attempts
66-
user_logged_out:
67-
type: boolean
68-
description: True if the user explicitly logged out
69-
has_refresh_token:
70-
type: boolean
71-
description: True if auto-refresh is possible
72-
error:
73-
type: string
74-
description: Last OAuth error message (if any)
31+
enum: [login, restart, enable, approve, view_logs, set_secret, configure, ""]
32+
description: |
33+
Suggested action to fix the issue:
34+
- login: Trigger OAuth authentication
35+
- restart: Restart the server
36+
- enable: Enable the disabled server
37+
- approve: Approve the quarantined server
38+
- view_logs: View server logs for details
39+
- set_secret: Navigate to secrets page to set missing secret
40+
- configure: Navigate to server config to fix configuration
41+
- "": No action needed (healthy)
7542
```
7643
77-
### New Schema: ConnectionState
44+
## New Action Examples
7845
79-
```yaml
80-
ConnectionState:
81-
type: object
82-
required:
83-
- status
84-
- retry_count
85-
- should_retry
86-
properties:
87-
status:
88-
type: string
89-
enum: [disconnected, connecting, ready, error]
90-
description: Current connection status
91-
connected_at:
92-
type: string
93-
format: date-time
94-
description: When the connection was established
95-
last_error:
96-
type: string
97-
description: Last connection error message
98-
retry_count:
99-
type: integer
100-
minimum: 0
101-
description: Number of connection retry attempts
102-
last_retry_at:
103-
type: string
104-
format: date-time
105-
description: When the last retry was attempted
106-
should_retry:
107-
type: boolean
108-
description: True if a retry is pending based on backoff
109-
```
46+
### Missing Secret
11047
111-
## Example Response
48+
```json
49+
{
50+
"health": {
51+
"level": "unhealthy",
52+
"admin_state": "enabled",
53+
"summary": "Missing secret",
54+
"detail": "GITHUB_TOKEN",
55+
"action": "set_secret"
56+
}
57+
}
58+
```
11259

113-
### GET /api/v1/servers
60+
### OAuth Config Issue
11461

11562
```json
11663
{
117-
"success": true,
118-
"data": {
119-
"servers": [
120-
{
121-
"name": "github-server",
122-
"enabled": true,
123-
124-
"oauth_state": {
125-
"status": "authenticated",
126-
"token_expires_at": "2025-12-14T12:00:00Z",
127-
"last_attempt": "2025-12-13T10:00:00Z",
128-
"retry_count": 0,
129-
"user_logged_out": false,
130-
"has_refresh_token": true
131-
},
132-
133-
"connection_state": {
134-
"status": "ready",
135-
"connected_at": "2025-12-13T10:01:00Z",
136-
"retry_count": 0,
137-
"should_retry": false
138-
},
139-
140-
"health": {
141-
"level": "healthy",
142-
"admin_state": "enabled",
143-
"summary": "Connected (5 tools)"
144-
},
145-
146-
"authenticated": true,
147-
"connected": true,
148-
"tool_count": 5
149-
}
150-
]
64+
"health": {
65+
"level": "unhealthy",
66+
"admin_state": "enabled",
67+
"summary": "OAuth configuration error",
68+
"detail": "requires 'resource' parameter",
69+
"action": "configure"
15170
}
15271
}
15372
```
15473

155-
## Backwards Compatibility
74+
## Diagnostics Changes
75+
76+
### Before (Independent Detection)
77+
78+
Doctor() independently detected issues by checking raw server fields.
15679

157-
All existing flat fields remain unchanged:
80+
### After (Aggregated from Health)
15881

159-
| Field | Consistent With |
160-
|-------|-----------------|
161-
| `authenticated` | `oauth_state.status == "authenticated"` |
162-
| `oauth_status` | `oauth_state.status` |
163-
| `connected` | `connection_state.status == "ready"` |
164-
| `connecting` | `connection_state.status == "connecting"` |
165-
| `last_error` | `connection_state.last_error` |
166-
| `reconnect_count` | `connection_state.retry_count` |
167-
| `should_retry` | `connection_state.should_retry` |
82+
Doctor() iterates servers and groups by `Health.Action`:
16883

169-
## Migration Path
84+
| Health.Action | Diagnostics Field |
85+
|---------------|-------------------|
86+
| `restart` | `upstream_errors` |
87+
| `login` | `oauth_required` |
88+
| `configure` | `oauth_issues` |
89+
| `set_secret` | `missing_secrets` (grouped by secret name) |
90+
91+
**No schema change** - Diagnostics response structure remains the same. Only the internal implementation changes.
92+
93+
## Backwards Compatibility
17094

171-
1. **Phase 1** (this feature): Add new fields alongside existing
172-
2. **Phase 2** (future): Deprecation warnings in API docs
173-
3. **Phase 3** (future): Remove flat fields in major version bump
95+
- All existing `action` values unchanged
96+
- New `action` values are additive
97+
- Clients that don't handle `set_secret` or `configure` will see them as unknown actions (graceful degradation)
98+
- Diagnostics response schema unchanged
99+
100+
## Frontend Action Mapping
101+
102+
| Action | Button Text | Behavior |
103+
|--------|-------------|----------|
104+
| `login` | Login | Trigger OAuth flow |
105+
| `restart` | Restart | Restart server |
106+
| `enable` | Enable | Enable server |
107+
| `approve` | Approve | Unquarantine server |
108+
| `view_logs` | View Logs | Navigate to `/servers/{name}?tab=logs` |
109+
| `set_secret` | Set Secret | Navigate to `/secrets` |
110+
| `configure` | Configure | Navigate to `/servers/{name}?tab=config` |

0 commit comments

Comments
 (0)