agentic-orchestrator 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CLAUDE.md +2 -2
- package/README.md +47 -14
- package/agentic/orchestrator/agents.yaml +13 -0
- package/agentic/orchestrator/policy.yaml +3 -0
- package/agentic/orchestrator/schemas/agents.schema.json +76 -0
- package/agentic/orchestrator/schemas/policy.schema.json +16 -0
- package/agentic/orchestrator/schemas/policy.user.schema.json +16 -0
- package/agentic/orchestrator/schemas/state.schema.json +53 -0
- package/apps/control-plane/src/application/configuration-service.ts +181 -0
- package/apps/control-plane/src/application/kernel-tool-wiring.ts +292 -0
- package/apps/control-plane/src/application/services/checkpoint-service.ts +523 -0
- package/apps/control-plane/src/application/services/feature-send-message-service.ts +132 -0
- package/apps/control-plane/src/application/services/patch-service.ts +29 -5
- package/apps/control-plane/src/application/services/repo-operations-service.ts +276 -0
- package/apps/control-plane/src/application/services/worktree-watchdog-service.ts +156 -0
- package/apps/control-plane/src/cli/cli-argument-parser.ts +12 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +17 -0
- package/apps/control-plane/src/cli/init-command-handler.ts +31 -0
- package/apps/control-plane/src/cli/resume-command-handler.ts +31 -4
- package/apps/control-plane/src/cli/rollback-command-handler.ts +217 -0
- package/apps/control-plane/src/cli/run-command-handler.ts +8 -0
- package/apps/control-plane/src/cli/types.ts +3 -0
- package/apps/control-plane/src/core/kernel-types.ts +55 -0
- package/apps/control-plane/src/core/kernel.ts +61 -878
- package/apps/control-plane/src/core/tool-caller.ts +10 -0
- package/apps/control-plane/src/core/utils/field-readers.ts +38 -0
- package/apps/control-plane/src/core/utils/index-normalizer.ts +119 -0
- package/apps/control-plane/src/core/utils/path-normalizers.ts +22 -0
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +15 -0
- package/apps/control-plane/src/providers/api-worker-provider.ts +14 -12
- package/apps/control-plane/src/providers/cli-worker-provider.ts +82 -12
- package/apps/control-plane/src/providers/providers.ts +45 -24
- package/apps/control-plane/src/providers/worker-provider-factory.ts +36 -1
- package/apps/control-plane/src/supervisor/run-coordinator.ts +91 -36
- package/apps/control-plane/src/supervisor/runtime.ts +107 -1
- package/apps/control-plane/src/supervisor/types.ts +9 -0
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +253 -14
- package/apps/control-plane/test/checkpoint-service.spec.ts +537 -0
- package/apps/control-plane/test/cli-helpers.spec.ts +28 -0
- package/apps/control-plane/test/cli.unit.spec.ts +52 -0
- package/apps/control-plane/test/configuration-service.spec.ts +466 -0
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +537 -0
- package/apps/control-plane/test/dashboard-client.spec.ts +233 -0
- package/apps/control-plane/test/feature-send-message-service.spec.ts +314 -0
- package/apps/control-plane/test/init-wizard.spec.ts +35 -0
- package/apps/control-plane/test/path-normalizers.spec.ts +41 -0
- package/apps/control-plane/test/repo-operations-service.spec.ts +339 -0
- package/apps/control-plane/test/resume-command.spec.ts +33 -0
- package/apps/control-plane/test/review-workspace-logic.spec.ts +130 -0
- package/apps/control-plane/test/rollback-command.spec.ts +208 -0
- package/apps/control-plane/test/run-coordinator.spec.ts +119 -0
- package/apps/control-plane/test/worker-decision-loop.spec.ts +209 -0
- package/apps/control-plane/test/worker-provider-adapters.spec.ts +102 -0
- package/apps/control-plane/test/worker-provider-factory.spec.ts +14 -0
- package/apps/control-plane/test/worktree-watchdog-service.spec.ts +147 -0
- package/config/agentic/orchestrator/agents.yaml +13 -0
- package/dist/apps/control-plane/application/configuration-service.d.ts +19 -0
- package/dist/apps/control-plane/application/configuration-service.js +123 -0
- package/dist/apps/control-plane/application/configuration-service.js.map +1 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.d.ts +39 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.js +38 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.js.map +1 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.d.ts +84 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js +367 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.d.ts +25 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.js +105 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/patch-service.d.ts +6 -0
- package/dist/apps/control-plane/application/services/patch-service.js +11 -2
- package/dist/apps/control-plane/application/services/patch-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/repo-operations-service.d.ts +70 -0
- package/dist/apps/control-plane/application/services/repo-operations-service.js +213 -0
- package/dist/apps/control-plane/application/services/repo-operations-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.d.ts +23 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js +119 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js.map +1 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js +12 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/help-command-handler.js +17 -0
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +23 -0
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/resume-command-handler.js +25 -5
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/rollback-command-handler.d.ts +6 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js +177 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/run-command-handler.js +7 -1
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +3 -0
- package/dist/apps/control-plane/cli/types.js +1 -0
- package/dist/apps/control-plane/cli/types.js.map +1 -1
- package/dist/apps/control-plane/core/configuration-service.d.ts +25 -0
- package/dist/apps/control-plane/core/configuration-service.js +130 -0
- package/dist/apps/control-plane/core/configuration-service.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.d.ts +50 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.js +44 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-types.d.ts +48 -0
- package/dist/apps/control-plane/core/kernel-types.js +2 -0
- package/dist/apps/control-plane/core/kernel-types.js.map +1 -0
- package/dist/apps/control-plane/core/kernel.d.ts +17 -48
- package/dist/apps/control-plane/core/kernel.js +44 -539
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/tool-caller.d.ts +10 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.d.ts +2 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.js +51 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.js.map +1 -0
- package/dist/apps/control-plane/core/utils/field-readers.d.ts +9 -0
- package/dist/apps/control-plane/core/utils/field-readers.js +30 -0
- package/dist/apps/control-plane/core/utils/field-readers.js.map +1 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.d.ts +7 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.js +92 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.js.map +1 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.d.ts +2 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.js +17 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.js.map +1 -0
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +13 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/providers/api-worker-provider.d.ts +4 -13
- package/dist/apps/control-plane/providers/api-worker-provider.js +10 -0
- package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +11 -13
- package/dist/apps/control-plane/providers/cli-worker-provider.js +64 -0
- package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/providers.d.ts +31 -24
- package/dist/apps/control-plane/providers/providers.js +10 -0
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +11 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js +20 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +3 -0
- package/dist/apps/control-plane/supervisor/run-coordinator.js +81 -33
- package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.d.ts +8 -1
- package/dist/apps/control-plane/supervisor/runtime.js +90 -0
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/types.d.ts +11 -0
- package/dist/apps/control-plane/supervisor/types.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +21 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +207 -13
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/package.json +1 -1
- package/packages/web-dashboard/package.json +2 -0
- package/packages/web-dashboard/src/app/analytics/page.tsx +83 -2
- package/packages/web-dashboard/src/app/api/actions/route.ts +92 -1
- package/packages/web-dashboard/src/app/api/analytics/route.ts +5 -2
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/[checkpointId]/diff/route.ts +43 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/compare/route.ts +45 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/stream/route.ts +170 -0
- package/packages/web-dashboard/src/app/api/features/[id]/file-diff/route.ts +144 -0
- package/packages/web-dashboard/src/app/api/features/[id]/log-stream/route.ts +167 -0
- package/packages/web-dashboard/src/app/api/features/[id]/raw-logs/[filename]/route.ts +65 -0
- package/packages/web-dashboard/src/app/api/features/[id]/raw-logs/route.ts +63 -0
- package/packages/web-dashboard/src/app/api/features/[id]/timeline/route.ts +60 -0
- package/packages/web-dashboard/src/app/feature/[id]/page.tsx +32 -11
- package/packages/web-dashboard/src/app/globals.css +2 -0
- package/packages/web-dashboard/src/components/detail-panel.tsx +483 -0
- package/packages/web-dashboard/src/components/review-workspace.tsx +1162 -0
- package/packages/web-dashboard/src/lib/aop-client.ts +725 -0
- package/packages/web-dashboard/src/lib/review-contracts.ts +182 -0
- package/packages/web-dashboard/src/lib/review-workspace-logic.ts +64 -0
- package/packages/web-dashboard/src/lib/types.ts +131 -0
- package/packages/web-dashboard/src/styles/dashboard.module.css +333 -0
- package/spec-files/completed/agentic_orchestrator_execution_mode_spec.md +1905 -0
- package/spec-files/outstanding/agentic_orchestrator_runtime_inspection_spec.md +940 -0
- package/spec-files/outstanding/execution_mode_critical_review.md +355 -0
- package/spec-files/outstanding/shadow_workspace_implementation_spec.md +1271 -0
- package/spec-files/outstanding/shadow_workspace_spec_summary.md +222 -0
- package/spec-files/progress.md +269 -1
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
# Feature Spec: Runtime File Inspection (AOP Dashboard)
|
|
2
|
+
|
|
3
|
+
> Purpose: Enable direct inspection of `.aop/runtime` artifacts (Operation Ledger and Worker Events) through the dashboard with time-sorted, formatted views per feature.
|
|
4
|
+
|
|
5
|
+
**Version:** 1.0
|
|
6
|
+
**Date:** 2026-03-05
|
|
7
|
+
**Status:** Outstanding
|
|
8
|
+
**Roadmap Mapping:** M46
|
|
9
|
+
**Depends On:** M45 (Dashboard Advanced UX)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. Scope and Standards
|
|
14
|
+
|
|
15
|
+
### 0.1 Primary User Job
|
|
16
|
+
|
|
17
|
+
**Operator/Debugger Job:** Understand what happened during a feature run by inspecting:
|
|
18
|
+
|
|
19
|
+
- Operation Ledger: idempotent tool invocations with request/response payloads
|
|
20
|
+
- Worker Events: agent lifecycle events (started, completed, failed, timeout)
|
|
21
|
+
|
|
22
|
+
**Key Questions This Feature Answers:**
|
|
23
|
+
|
|
24
|
+
1. What tools were called for this feature and what were the results?
|
|
25
|
+
2. When did the agent start/stop/fail/timeout?
|
|
26
|
+
3. What was the sequence of events leading to a failure?
|
|
27
|
+
4. Were there any retries or duplicate operations?
|
|
28
|
+
|
|
29
|
+
### 0.2 UX Principles
|
|
30
|
+
|
|
31
|
+
1. **Time-first ordering:** All events sorted by timestamp (newest first by default)
|
|
32
|
+
2. **Progressive disclosure:** Raw JSON collapsed by default, formatted summary visible
|
|
33
|
+
3. **Feature-scoped:** Filter to single feature ID, not global view
|
|
34
|
+
4. **Read-only:** No mutation of runtime files through UI
|
|
35
|
+
5. **Performance-bounded:** Limit display to last N events, paginate if needed
|
|
36
|
+
|
|
37
|
+
### 0.3 Quality Standards
|
|
38
|
+
|
|
39
|
+
- TypeScript strict mode passes
|
|
40
|
+
- ESLint zero warnings
|
|
41
|
+
- Coverage >= 90% for new code
|
|
42
|
+
- API response time < 200ms for typical feature (< 100 events)
|
|
43
|
+
- Graceful degradation when files are large (> 1000 events)
|
|
44
|
+
- Must pass `npm run verify` checks
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 1. Runtime File Structure
|
|
49
|
+
|
|
50
|
+
### 1.1 Run ID Tracking in Feature State
|
|
51
|
+
|
|
52
|
+
**Schema Change Required:** Add `run_history` field to `state.schema.json`
|
|
53
|
+
|
|
54
|
+
**Location:** `.aop/features/<feature_id>/state.md` (YAML frontmatter)
|
|
55
|
+
|
|
56
|
+
**New Field:**
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
run_history:
|
|
60
|
+
- run_id: 'run:8efe99b2-bba0-473a-ad2e-22c54153fdd8'
|
|
61
|
+
started_at: '2026-03-05T22:24:39.635Z'
|
|
62
|
+
ended_at: '2026-03-05T23:00:09.599Z'
|
|
63
|
+
status: 'failed'
|
|
64
|
+
- run_id: 'run:69c36d92-3255-435a-806a-6425461e5aa8'
|
|
65
|
+
started_at: '2026-03-05T06:05:12.123Z'
|
|
66
|
+
ended_at: '2026-03-05T06:07:17.975Z'
|
|
67
|
+
status: 'completed'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Schema Definition:**
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"run_history": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"description": "Time-sorted list of run IDs associated with this feature (newest first). Updated by supervisor on run start/end.",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["run_id", "started_at"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"run_id": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"description": "Run ID from runtime_sessions"
|
|
84
|
+
},
|
|
85
|
+
"started_at": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"format": "date-time",
|
|
88
|
+
"description": "When this run started working on this feature"
|
|
89
|
+
},
|
|
90
|
+
"ended_at": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"format": "date-time",
|
|
93
|
+
"description": "When this run stopped working on this feature (null if still active)"
|
|
94
|
+
},
|
|
95
|
+
"status": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"enum": ["active", "completed", "failed", "timeout"],
|
|
98
|
+
"description": "Final status of this run for this feature"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Update Behavior:**
|
|
107
|
+
|
|
108
|
+
- **On feature.init:** Create `run_history` with current run_id, status `active`
|
|
109
|
+
- **On supervisor start:** Append current run_id to `run_history` if not already present
|
|
110
|
+
- **On supervisor stop/complete:** Update latest run_history entry with `ended_at` and final `status`
|
|
111
|
+
- **On feature.delete:** Archive run_history before deletion (optional)
|
|
112
|
+
|
|
113
|
+
### 1.2 Operation Ledger Files
|
|
114
|
+
|
|
115
|
+
**Location:** `.aop/runtime/operation-ledger/run:<run_id>.json`
|
|
116
|
+
|
|
117
|
+
**Structure:**
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"run_id": "run:69c36d92-3255-435a-806a-6425461e5aa8",
|
|
122
|
+
"updated_at": "2026-03-05T06:07:17.975Z",
|
|
123
|
+
"operations": {
|
|
124
|
+
"<operation_id>": {
|
|
125
|
+
"operation_id": "feature_delete__my_feature__uuid",
|
|
126
|
+
"tool_name": "feature.delete",
|
|
127
|
+
"request_hash": "sha256...",
|
|
128
|
+
"response": {
|
|
129
|
+
"ok": true,
|
|
130
|
+
"data": { ... }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Key Fields:**
|
|
138
|
+
|
|
139
|
+
- `operation_id`: Unique ID for idempotency tracking
|
|
140
|
+
- `tool_name`: MCP tool invoked (e.g., `feature.init`, `plan.submit`, `gates.run`)
|
|
141
|
+
- `request_hash`: SHA256 of request payload
|
|
142
|
+
- `response`: Full tool response with `ok` and `data`/`error`
|
|
143
|
+
|
|
144
|
+
### 1.3 Worker Events Files
|
|
145
|
+
|
|
146
|
+
**Location:** `.aop/runtime/worker-events/run:<run_id>.jsonl`
|
|
147
|
+
|
|
148
|
+
**Structure:** JSONL (one JSON object per line)
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{"ts":"2026-03-05T22:24:39.635Z","run_id":"run:8efe99b2...","feature_id":"my_feature","role":"planner","phase":"execution","event_type":"worker_started","output_types":[],"patch_count":0,"plan_submission_count":0,"request_count":0,"note_count":0,"valid":true,"error_code":null,"provider":"claude","model":"local-default","watchdog_reason":null,"signal":null}
|
|
152
|
+
{"ts":"2026-03-05T22:25:17.441Z","run_id":"run:8efe99b2...","feature_id":"my_feature","role":"planner","phase":"execution","event_type":"worker_completed","output_types":["PLAN_SUBMISSION"],"patch_count":0,"plan_submission_count":1,"request_count":0,"note_count":0,"valid":true,"error_code":null,"provider":"claude","model":"local-default","watchdog_reason":null,"signal":null}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Key Fields:**
|
|
156
|
+
|
|
157
|
+
- `ts`: ISO 8601 timestamp
|
|
158
|
+
- `feature_id`: Feature this event belongs to
|
|
159
|
+
- `role`: Agent role (`planner`, `builder`, `qa`)
|
|
160
|
+
- `event_type`: `worker_started`, `worker_completed`, `worker_failed`, `worker_timeout`
|
|
161
|
+
- `valid`: Boolean indicating success/failure
|
|
162
|
+
- `error_code`: Error code if `valid=false`
|
|
163
|
+
- `watchdog_reason`: Timeout/failure reason
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 2. API Contract
|
|
168
|
+
|
|
169
|
+
### 2.1 Operation Ledger Endpoint
|
|
170
|
+
|
|
171
|
+
**Route:** `GET /api/runtime/operations`
|
|
172
|
+
|
|
173
|
+
**Query Parameters:**
|
|
174
|
+
|
|
175
|
+
- `feature_id` (required): Feature ID to filter operations
|
|
176
|
+
- `run_id` (optional): Specific run ID (defaults to latest from `run_history`)
|
|
177
|
+
- `project` (optional): Project name for multi-project setups
|
|
178
|
+
- `limit` (optional, default 100): Max operations to return
|
|
179
|
+
- `offset` (optional, default 0): Pagination offset
|
|
180
|
+
|
|
181
|
+
**Run ID Resolution:**
|
|
182
|
+
|
|
183
|
+
1. If `run_id` provided, use it directly
|
|
184
|
+
2. Else read `.aop/features/<feature_id>/state.md`
|
|
185
|
+
3. Extract `run_history[0].run_id` (latest run)
|
|
186
|
+
4. If `run_history` is empty or missing, return `run_not_found`
|
|
187
|
+
|
|
188
|
+
**Response Envelope:**
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
{
|
|
192
|
+
ok: true,
|
|
193
|
+
data: {
|
|
194
|
+
run_id: string;
|
|
195
|
+
feature_id: string;
|
|
196
|
+
updated_at: string;
|
|
197
|
+
run_info: {
|
|
198
|
+
started_at: string;
|
|
199
|
+
ended_at: string | null;
|
|
200
|
+
status: 'active' | 'completed' | 'failed' | 'timeout';
|
|
201
|
+
};
|
|
202
|
+
operations: Array<{
|
|
203
|
+
operation_id: string;
|
|
204
|
+
tool_name: string;
|
|
205
|
+
request_hash: string;
|
|
206
|
+
timestamp: string; // extracted from operation_id or response
|
|
207
|
+
response: {
|
|
208
|
+
ok: boolean;
|
|
209
|
+
data?: unknown;
|
|
210
|
+
error?: {
|
|
211
|
+
code: string;
|
|
212
|
+
message: string;
|
|
213
|
+
details?: unknown;
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
}>;
|
|
217
|
+
total_count: number;
|
|
218
|
+
has_more: boolean;
|
|
219
|
+
},
|
|
220
|
+
metadata: {
|
|
221
|
+
source: 'runtime_ledger';
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Error Codes:**
|
|
227
|
+
|
|
228
|
+
- `feature_not_found`: Feature ID not found in index
|
|
229
|
+
- `run_not_found`: No run_history found for feature
|
|
230
|
+
- `ledger_not_found`: Operation ledger file missing for run_id
|
|
231
|
+
- `ledger_parse_error`: JSON parse failure
|
|
232
|
+
|
|
233
|
+
### 2.2 Worker Events Endpoint
|
|
234
|
+
|
|
235
|
+
**Route:** `GET /api/runtime/events`
|
|
236
|
+
|
|
237
|
+
**Query Parameters:**
|
|
238
|
+
|
|
239
|
+
- `feature_id` (required): Feature ID to filter events
|
|
240
|
+
- `run_id` (optional): Specific run ID (defaults to latest from `run_history`)
|
|
241
|
+
- `project` (optional): Project name for multi-project setups
|
|
242
|
+
- `limit` (optional, default 100): Max events to return
|
|
243
|
+
- `offset` (optional, default 0): Pagination offset
|
|
244
|
+
- `event_type` (optional): Filter by event type (comma-separated)
|
|
245
|
+
- `role` (optional): Filter by role (comma-separated)
|
|
246
|
+
|
|
247
|
+
**Run ID Resolution:**
|
|
248
|
+
|
|
249
|
+
1. If `run_id` provided, use it directly
|
|
250
|
+
2. Else read `.aop/features/<feature_id>/state.md`
|
|
251
|
+
3. Extract `run_history[0].run_id` (latest run)
|
|
252
|
+
4. If `run_history` is empty or missing, return `run_not_found`
|
|
253
|
+
|
|
254
|
+
**Response Envelope:**
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
{
|
|
258
|
+
ok: true,
|
|
259
|
+
data: {
|
|
260
|
+
run_id: string;
|
|
261
|
+
feature_id: string;
|
|
262
|
+
run_info: {
|
|
263
|
+
started_at: string;
|
|
264
|
+
ended_at: string | null;
|
|
265
|
+
status: 'active' | 'completed' | 'failed' | 'timeout';
|
|
266
|
+
};
|
|
267
|
+
events: Array<{
|
|
268
|
+
ts: string;
|
|
269
|
+
run_id: string;
|
|
270
|
+
feature_id: string;
|
|
271
|
+
role: string;
|
|
272
|
+
phase: string;
|
|
273
|
+
event_type: string;
|
|
274
|
+
output_types: string[];
|
|
275
|
+
patch_count: number;
|
|
276
|
+
plan_submission_count: number;
|
|
277
|
+
request_count: number;
|
|
278
|
+
note_count: number;
|
|
279
|
+
valid: boolean;
|
|
280
|
+
error_code: string | null;
|
|
281
|
+
provider: string;
|
|
282
|
+
model: string;
|
|
283
|
+
watchdog_reason: string | null;
|
|
284
|
+
signal: string | null;
|
|
285
|
+
exit_code?: number;
|
|
286
|
+
timeout_ms?: number;
|
|
287
|
+
elapsed_ms?: number;
|
|
288
|
+
}>;
|
|
289
|
+
total_count: number;
|
|
290
|
+
has_more: boolean;
|
|
291
|
+
},
|
|
292
|
+
metadata: {
|
|
293
|
+
source: 'runtime_events';
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Error Codes:**
|
|
299
|
+
|
|
300
|
+
- `feature_not_found`: Feature ID not found in index
|
|
301
|
+
- `run_not_found`: No run_history found for feature
|
|
302
|
+
- `events_not_found`: Worker events file missing for run_id
|
|
303
|
+
- `events_parse_error`: JSONL parse failure
|
|
304
|
+
|
|
305
|
+
### 2.3 Run History Endpoint (New)
|
|
306
|
+
|
|
307
|
+
**Route:** `GET /api/runtime/runs`
|
|
308
|
+
|
|
309
|
+
**Query Parameters:**
|
|
310
|
+
|
|
311
|
+
- `feature_id` (required): Feature ID to get run history
|
|
312
|
+
- `project` (optional): Project name for multi-project setups
|
|
313
|
+
|
|
314
|
+
**Response Envelope:**
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
{
|
|
318
|
+
ok: true,
|
|
319
|
+
data: {
|
|
320
|
+
feature_id: string;
|
|
321
|
+
runs: Array<{
|
|
322
|
+
run_id: string;
|
|
323
|
+
started_at: string;
|
|
324
|
+
ended_at: string | null;
|
|
325
|
+
status: 'active' | 'completed' | 'failed' | 'timeout';
|
|
326
|
+
has_operations: boolean;
|
|
327
|
+
has_events: boolean;
|
|
328
|
+
}>;
|
|
329
|
+
},
|
|
330
|
+
metadata: {
|
|
331
|
+
source: 'feature_state';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Purpose:** Allow UI to show run selector dropdown with all historical runs for a feature
|
|
337
|
+
|
|
338
|
+
**Error Codes:**
|
|
339
|
+
|
|
340
|
+
- `feature_not_found`: Feature ID not found in index
|
|
341
|
+
- `state_not_found`: Feature state file missing
|
|
342
|
+
- `state_parse_error`: YAML parse failure
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 3. UI Components
|
|
347
|
+
|
|
348
|
+
### 3.1 Runtime Inspector Panel (New Component)
|
|
349
|
+
|
|
350
|
+
**File:** `packages/web-dashboard/src/components/runtime-inspector.tsx`
|
|
351
|
+
|
|
352
|
+
**Location:** Appears in Feature Detail Panel (right side) as a new tab
|
|
353
|
+
|
|
354
|
+
**Tabs:**
|
|
355
|
+
|
|
356
|
+
1. **Operations** - Operation Ledger view
|
|
357
|
+
2. **Events** - Worker Events view
|
|
358
|
+
|
|
359
|
+
**Run Selector:**
|
|
360
|
+
|
|
361
|
+
- Dropdown at top of panel showing all runs from `run_history`
|
|
362
|
+
- Format: `Run <short_id> - <started_at> - <status>`
|
|
363
|
+
- Default: Latest run (index 0)
|
|
364
|
+
- Fetches from `GET /api/runtime/runs?feature_id=<id>`
|
|
365
|
+
|
|
366
|
+
**Default State:**
|
|
367
|
+
|
|
368
|
+
- Operations tab selected
|
|
369
|
+
- Latest run selected
|
|
370
|
+
- Last 50 operations shown
|
|
371
|
+
- Newest first (reverse chronological)
|
|
372
|
+
- Raw JSON collapsed
|
|
373
|
+
|
|
374
|
+
**Interaction:**
|
|
375
|
+
|
|
376
|
+
- Select run from dropdown → refetch operations/events for that run
|
|
377
|
+
- Click operation row to expand/collapse JSON
|
|
378
|
+
- Copy button for operation_id and request_hash
|
|
379
|
+
- Filter by tool_name (dropdown)
|
|
380
|
+
- Filter by success/failure (toggle)
|
|
381
|
+
- Pagination controls at bottom
|
|
382
|
+
|
|
383
|
+
### 3.2 Operations List View
|
|
384
|
+
|
|
385
|
+
**Requirements:**
|
|
386
|
+
|
|
387
|
+
**Summary Row (Always Visible):**
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
[Icon] tool_name | timestamp | status_badge | expand_icon
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Status Badge:**
|
|
394
|
+
|
|
395
|
+
- ✅ Success (green) - `response.ok === true`
|
|
396
|
+
- ❌ Failed (red) - `response.ok === false`
|
|
397
|
+
- ⚠️ Partial (yellow) - `response.ok === true` but `response.data` contains warnings
|
|
398
|
+
|
|
399
|
+
**Expanded View:**
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
Operation ID: <operation_id> [Copy]
|
|
403
|
+
Request Hash: <request_hash> [Copy]
|
|
404
|
+
Tool: <tool_name>
|
|
405
|
+
Timestamp: <formatted_timestamp>
|
|
406
|
+
|
|
407
|
+
Response:
|
|
408
|
+
<formatted_json_with_syntax_highlighting>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Formatting:**
|
|
412
|
+
|
|
413
|
+
- Use `JSON.stringify(response, null, 2)` for readability
|
|
414
|
+
- Syntax highlighting for JSON (optional, use `<pre>` with CSS if no library)
|
|
415
|
+
- Max height 400px with scroll for large responses
|
|
416
|
+
|
|
417
|
+
### 3.3 Events Timeline View
|
|
418
|
+
|
|
419
|
+
**Requirements:**
|
|
420
|
+
|
|
421
|
+
**Timeline Row (Always Visible):**
|
|
422
|
+
|
|
423
|
+
```
|
|
424
|
+
[timestamp] [role_badge] [event_type_icon] event_type | duration | status
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Role Badge:**
|
|
428
|
+
|
|
429
|
+
- 🎯 Planner (blue)
|
|
430
|
+
- 🔨 Builder (orange)
|
|
431
|
+
- ✅ QA (green)
|
|
432
|
+
|
|
433
|
+
**Event Type Icons:**
|
|
434
|
+
|
|
435
|
+
- ▶️ `worker_started`
|
|
436
|
+
- ✅ `worker_completed`
|
|
437
|
+
- ❌ `worker_failed`
|
|
438
|
+
- ⏱️ `worker_timeout`
|
|
439
|
+
|
|
440
|
+
**Duration Calculation:**
|
|
441
|
+
|
|
442
|
+
- For `worker_completed`/`worker_failed`/`worker_timeout`: show `elapsed_ms` if present
|
|
443
|
+
- For `worker_started`: calculate duration to next event for same role
|
|
444
|
+
|
|
445
|
+
**Expanded View:**
|
|
446
|
+
|
|
447
|
+
```
|
|
448
|
+
Timestamp: <formatted_timestamp>
|
|
449
|
+
Run ID: <run_id>
|
|
450
|
+
Feature: <feature_id>
|
|
451
|
+
Role: <role>
|
|
452
|
+
Phase: <phase>
|
|
453
|
+
Event Type: <event_type>
|
|
454
|
+
Valid: <valid>
|
|
455
|
+
Error Code: <error_code>
|
|
456
|
+
Provider: <provider>
|
|
457
|
+
Model: <model>
|
|
458
|
+
Watchdog Reason: <watchdog_reason>
|
|
459
|
+
Signal: <signal>
|
|
460
|
+
Exit Code: <exit_code>
|
|
461
|
+
Timeout: <timeout_ms>ms
|
|
462
|
+
Elapsed: <elapsed_ms>ms
|
|
463
|
+
|
|
464
|
+
Output Types: <output_types.join(', ')>
|
|
465
|
+
Patch Count: <patch_count>
|
|
466
|
+
Plan Submissions: <plan_submission_count>
|
|
467
|
+
Requests: <request_count>
|
|
468
|
+
Notes: <note_count>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### 3.4 Filter Controls
|
|
472
|
+
|
|
473
|
+
**Operations Filters:**
|
|
474
|
+
|
|
475
|
+
- Tool Name (dropdown, multi-select)
|
|
476
|
+
- Status (Success/Failed/All)
|
|
477
|
+
- Time Range (Last Hour/Last Day/All)
|
|
478
|
+
|
|
479
|
+
**Events Filters:**
|
|
480
|
+
|
|
481
|
+
- Role (Planner/Builder/QA/All)
|
|
482
|
+
- Event Type (Started/Completed/Failed/Timeout/All)
|
|
483
|
+
- Valid Only (toggle)
|
|
484
|
+
- Time Range (Last Hour/Last Day/All)
|
|
485
|
+
|
|
486
|
+
**Filter Persistence:**
|
|
487
|
+
|
|
488
|
+
- Store in URL query params
|
|
489
|
+
- Restore on page load
|
|
490
|
+
- Clear filters button
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## 4. Implementation Details
|
|
495
|
+
|
|
496
|
+
### 4.0 Schema and State Management Changes
|
|
497
|
+
|
|
498
|
+
**File:** `agentic/orchestrator/schemas/state.schema.json`
|
|
499
|
+
|
|
500
|
+
**Add to properties:**
|
|
501
|
+
|
|
502
|
+
```json
|
|
503
|
+
{
|
|
504
|
+
"run_history": {
|
|
505
|
+
"type": "array",
|
|
506
|
+
"description": "Time-sorted list of run IDs associated with this feature (newest first). Updated by supervisor on run start/end.",
|
|
507
|
+
"default": [],
|
|
508
|
+
"items": {
|
|
509
|
+
"type": "object",
|
|
510
|
+
"required": ["run_id", "started_at"],
|
|
511
|
+
"additionalProperties": false,
|
|
512
|
+
"properties": {
|
|
513
|
+
"run_id": {
|
|
514
|
+
"type": "string",
|
|
515
|
+
"pattern": "^run:[a-f0-9-]+$",
|
|
516
|
+
"description": "Run ID from runtime_sessions"
|
|
517
|
+
},
|
|
518
|
+
"started_at": {
|
|
519
|
+
"type": "string",
|
|
520
|
+
"format": "date-time",
|
|
521
|
+
"description": "When this run started working on this feature"
|
|
522
|
+
},
|
|
523
|
+
"ended_at": {
|
|
524
|
+
"type": ["string", "null"],
|
|
525
|
+
"format": "date-time",
|
|
526
|
+
"description": "When this run stopped working on this feature (null if still active)"
|
|
527
|
+
},
|
|
528
|
+
"status": {
|
|
529
|
+
"type": "string",
|
|
530
|
+
"enum": ["active", "completed", "failed", "timeout"],
|
|
531
|
+
"description": "Final status of this run for this feature"
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**File:** `apps/control-plane/src/application/services/feature-state-service.ts`
|
|
540
|
+
|
|
541
|
+
**Changes:**
|
|
542
|
+
|
|
543
|
+
- Add `appendRunHistory(featureId, runId, startedAt)` method
|
|
544
|
+
- Add `updateRunHistory(featureId, runId, endedAt, status)` method
|
|
545
|
+
- Ensure run_history is sorted newest-first on write
|
|
546
|
+
|
|
547
|
+
**File:** `apps/control-plane/src/supervisor/runtime.ts`
|
|
548
|
+
|
|
549
|
+
**Changes:**
|
|
550
|
+
|
|
551
|
+
- On feature start: Call `featureStateService.appendRunHistory(featureId, this.runId, new Date().toISOString())`
|
|
552
|
+
- On feature complete/fail: Call `featureStateService.updateRunHistory(featureId, this.runId, new Date().toISOString(), status)`
|
|
553
|
+
- On recovery: Check if current run_id exists in run_history, append if missing
|
|
554
|
+
|
|
555
|
+
**Migration Strategy:**
|
|
556
|
+
|
|
557
|
+
- Existing features without run_history: Initialize as empty array `[]`
|
|
558
|
+
- No data loss: run_history is additive only
|
|
559
|
+
- Backward compatible: Old state files without run_history still validate (default: `[]`)
|
|
560
|
+
|
|
561
|
+
### 4.1 Backend Implementation
|
|
562
|
+
|
|
563
|
+
**File:** `packages/web-dashboard/src/app/api/runtime/runs/route.ts` (New)
|
|
564
|
+
|
|
565
|
+
**Logic:**
|
|
566
|
+
|
|
567
|
+
1. Resolve `feature_id` and `project` from query params
|
|
568
|
+
2. Read `.aop/features/<feature_id>/state.md`
|
|
569
|
+
3. Parse YAML frontmatter to extract `run_history`
|
|
570
|
+
4. For each run, check if ledger/events files exist
|
|
571
|
+
5. Return formatted response with run list
|
|
572
|
+
|
|
573
|
+
**File:** `packages/web-dashboard/src/app/api/runtime/operations/route.ts`
|
|
574
|
+
|
|
575
|
+
**Logic:**
|
|
576
|
+
|
|
577
|
+
1. Resolve `feature_id` and `project` from query params
|
|
578
|
+
2. If `run_id` provided, use it; else read state.md and extract `run_history[0].run_id`
|
|
579
|
+
3. If no run_history, return `run_not_found`
|
|
580
|
+
4. Read `.aop/runtime/operation-ledger/run:<run_id>.json`
|
|
581
|
+
5. Parse JSON and extract operations
|
|
582
|
+
6. Filter operations by `feature_id` (check operation_id contains feature_id)
|
|
583
|
+
7. Sort by timestamp (extract from operation_id or use file `updated_at`)
|
|
584
|
+
8. Apply pagination (limit/offset)
|
|
585
|
+
9. Return formatted response with run_info from run_history
|
|
586
|
+
|
|
587
|
+
**File:** `packages/web-dashboard/src/app/api/runtime/events/route.ts`
|
|
588
|
+
|
|
589
|
+
**Logic:**
|
|
590
|
+
|
|
591
|
+
1. Resolve `feature_id` and `project` from query params
|
|
592
|
+
2. If `run_id` provided, use it; else read state.md and extract `run_history[0].run_id`
|
|
593
|
+
3. If no run_history, return `run_not_found`
|
|
594
|
+
4. Read `.aop/runtime/worker-events/run:<run_id>.jsonl`
|
|
595
|
+
5. Parse JSONL (split by newline, parse each line as JSON)
|
|
596
|
+
6. Filter events by `feature_id`
|
|
597
|
+
7. Apply filters (event_type, role, valid)
|
|
598
|
+
8. Sort by `ts` (descending for newest first)
|
|
599
|
+
9. Apply pagination (limit/offset)
|
|
600
|
+
10. Return formatted response with run_info from run_history
|
|
601
|
+
|
|
602
|
+
**Error Handling:**
|
|
603
|
+
|
|
604
|
+
- Catch file read errors → return `ledger_not_found` or `events_not_found`
|
|
605
|
+
- Catch JSON parse errors → return `ledger_parse_error` or `events_parse_error`
|
|
606
|
+
- Handle missing run_history → return `run_not_found`
|
|
607
|
+
- Handle large files (> 10MB) → return `file_too_large` with suggestion to use CLI
|
|
608
|
+
|
|
609
|
+
### 4.2 Frontend Implementation
|
|
610
|
+
|
|
611
|
+
**File:** `packages/web-dashboard/src/components/runtime-inspector.tsx`
|
|
612
|
+
|
|
613
|
+
**State Management:**
|
|
614
|
+
|
|
615
|
+
```typescript
|
|
616
|
+
interface RuntimeInspectorState {
|
|
617
|
+
activeTab: 'operations' | 'events';
|
|
618
|
+
selectedRunId: string | null;
|
|
619
|
+
runs: RunHistoryEntry[];
|
|
620
|
+
operations: Operation[];
|
|
621
|
+
events: WorkerEvent[];
|
|
622
|
+
loading: boolean;
|
|
623
|
+
error: string | null;
|
|
624
|
+
filters: {
|
|
625
|
+
toolName?: string[];
|
|
626
|
+
status?: 'success' | 'failed' | 'all';
|
|
627
|
+
eventType?: string[];
|
|
628
|
+
role?: string[];
|
|
629
|
+
validOnly?: boolean;
|
|
630
|
+
timeRange?: 'hour' | 'day' | 'all';
|
|
631
|
+
};
|
|
632
|
+
pagination: {
|
|
633
|
+
limit: number;
|
|
634
|
+
offset: number;
|
|
635
|
+
totalCount: number;
|
|
636
|
+
hasMore: boolean;
|
|
637
|
+
};
|
|
638
|
+
expandedIds: Set<string>;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
interface RunHistoryEntry {
|
|
642
|
+
run_id: string;
|
|
643
|
+
started_at: string;
|
|
644
|
+
ended_at: string | null;
|
|
645
|
+
status: 'active' | 'completed' | 'failed' | 'timeout';
|
|
646
|
+
has_operations: boolean;
|
|
647
|
+
has_events: boolean;
|
|
648
|
+
}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**Hooks:**
|
|
652
|
+
|
|
653
|
+
- `useRunHistory(featureId)` - Fetch run history list
|
|
654
|
+
- `useRuntimeOperations(featureId, runId, filters, pagination)` - Fetch operations
|
|
655
|
+
- `useRuntimeEvents(featureId, runId, filters, pagination)` - Fetch events
|
|
656
|
+
- `useExpandedState()` - Manage expanded/collapsed rows
|
|
657
|
+
|
|
658
|
+
**Component Lifecycle:**
|
|
659
|
+
|
|
660
|
+
1. Mount → fetch run history
|
|
661
|
+
2. Run history loaded → select latest run (index 0)
|
|
662
|
+
3. Run selected → fetch operations/events for that run
|
|
663
|
+
4. Run selector change → refetch operations/events
|
|
664
|
+
|
|
665
|
+
**Performance:**
|
|
666
|
+
|
|
667
|
+
- Virtualize lists if > 100 items (use `react-window` or similar)
|
|
668
|
+
- Debounce filter changes (300ms)
|
|
669
|
+
- Cancel in-flight requests on run/filter change
|
|
670
|
+
- Cache responses per (feature_id, run_id) pair (60s TTL)
|
|
671
|
+
|
|
672
|
+
### 4.3 Integration with Detail Panel
|
|
673
|
+
|
|
674
|
+
**File:** `packages/web-dashboard/src/components/detail-panel.tsx`
|
|
675
|
+
|
|
676
|
+
**Changes:**
|
|
677
|
+
|
|
678
|
+
1. Add new tab: "Runtime" (after "Evidence" tab)
|
|
679
|
+
2. Render `<RuntimeInspector featureId={selectedFeature.feature_id} />` when tab is active
|
|
680
|
+
3. Badge on tab shows total operation count (if available)
|
|
681
|
+
|
|
682
|
+
**Tab Order:**
|
|
683
|
+
|
|
684
|
+
1. Overview
|
|
685
|
+
2. Plan
|
|
686
|
+
3. Gates
|
|
687
|
+
4. Evidence
|
|
688
|
+
5. **Runtime** (new)
|
|
689
|
+
6. Logs
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## 5. Testing Strategy
|
|
694
|
+
|
|
695
|
+
### 5.1 Unit Tests
|
|
696
|
+
|
|
697
|
+
**Schema Tests:**
|
|
698
|
+
|
|
699
|
+
- `schemas/state.schema.spec.ts`
|
|
700
|
+
- Validates run_history field structure
|
|
701
|
+
- Rejects invalid run_history entries
|
|
702
|
+
- Allows empty run_history array
|
|
703
|
+
- Validates date-time formats
|
|
704
|
+
|
|
705
|
+
**Backend Tests:**
|
|
706
|
+
|
|
707
|
+
- `api/runtime/runs/route.spec.ts`
|
|
708
|
+
- Returns run history for valid feature_id
|
|
709
|
+
- Returns 404 for missing feature
|
|
710
|
+
- Returns 404 for missing state file
|
|
711
|
+
- Handles YAML parse errors
|
|
712
|
+
- Checks file existence for operations/events
|
|
713
|
+
|
|
714
|
+
- `api/runtime/operations/route.spec.ts`
|
|
715
|
+
- Returns operations for valid feature_id
|
|
716
|
+
- Uses latest run_id when not specified
|
|
717
|
+
- Uses specified run_id when provided
|
|
718
|
+
- Returns 404 for missing feature
|
|
719
|
+
- Returns 404 for missing run_history
|
|
720
|
+
- Returns 404 for missing ledger file
|
|
721
|
+
- Handles JSON parse errors
|
|
722
|
+
- Applies pagination correctly
|
|
723
|
+
- Filters by tool_name
|
|
724
|
+
- Sorts by timestamp descending
|
|
725
|
+
|
|
726
|
+
- `api/runtime/events/route.spec.ts`
|
|
727
|
+
- Returns events for valid feature_id
|
|
728
|
+
- Uses latest run_id when not specified
|
|
729
|
+
- Uses specified run_id when provided
|
|
730
|
+
- Returns 404 for missing feature
|
|
731
|
+
- Returns 404 for missing run_history
|
|
732
|
+
- Returns 404 for missing events file
|
|
733
|
+
- Handles JSONL parse errors
|
|
734
|
+
- Applies pagination correctly
|
|
735
|
+
- Filters by event_type and role
|
|
736
|
+
- Sorts by timestamp descending
|
|
737
|
+
|
|
738
|
+
**Frontend Tests:**
|
|
739
|
+
|
|
740
|
+
- `components/runtime-inspector.spec.tsx`
|
|
741
|
+
- Renders operations tab by default
|
|
742
|
+
- Fetches run history on mount
|
|
743
|
+
- Selects latest run by default
|
|
744
|
+
- Switches between tabs
|
|
745
|
+
- Changes selected run
|
|
746
|
+
- Refetches data on run change
|
|
747
|
+
- Expands/collapses operation rows
|
|
748
|
+
- Applies filters
|
|
749
|
+
- Handles pagination
|
|
750
|
+
- Shows loading state
|
|
751
|
+
- Shows error state
|
|
752
|
+
- Copies operation_id to clipboard
|
|
753
|
+
|
|
754
|
+
### 5.2 Integration Tests
|
|
755
|
+
|
|
756
|
+
**End-to-End:**
|
|
757
|
+
|
|
758
|
+
1. Create feature with multiple runs
|
|
759
|
+
2. Open feature detail panel
|
|
760
|
+
3. Click "Runtime" tab
|
|
761
|
+
4. Verify run selector appears with all runs
|
|
762
|
+
5. Verify latest run is selected
|
|
763
|
+
6. Verify operations list appears
|
|
764
|
+
7. Select older run from dropdown
|
|
765
|
+
8. Verify operations list updates
|
|
766
|
+
9. Expand operation row
|
|
767
|
+
10. Verify JSON response is visible
|
|
768
|
+
11. Switch to Events tab
|
|
769
|
+
12. Verify events timeline appears
|
|
770
|
+
13. Apply filter (e.g., "Failed only")
|
|
771
|
+
14. Verify filtered results
|
|
772
|
+
|
|
773
|
+
### 5.3 Performance Tests
|
|
774
|
+
|
|
775
|
+
**Benchmarks:**
|
|
776
|
+
|
|
777
|
+
- Load run history (10 runs) in < 50ms
|
|
778
|
+
- Load 100 operations in < 200ms
|
|
779
|
+
- Load 100 events in < 200ms
|
|
780
|
+
- Render 100 operations in < 100ms
|
|
781
|
+
- Filter 100 operations in < 50ms
|
|
782
|
+
- Pagination in < 50ms
|
|
783
|
+
- Run selector change in < 100ms
|
|
784
|
+
|
|
785
|
+
**Stress Tests:**
|
|
786
|
+
|
|
787
|
+
- Handle 50 runs in history gracefully
|
|
788
|
+
- Handle 1000 operations gracefully (virtualization)
|
|
789
|
+
- Handle 1000 events gracefully (virtualization)
|
|
790
|
+
- Handle 10MB ledger file (return error with suggestion)
|
|
791
|
+
|
|
792
|
+
---
|
|
793
|
+
|
|
794
|
+
## 6. Acceptance Criteria
|
|
795
|
+
|
|
796
|
+
### 6.1 Must Have
|
|
797
|
+
|
|
798
|
+
- [ ] Schema change: Add `run_history` field to `state.schema.json`
|
|
799
|
+
- [ ] Supervisor: Update run_history on feature start/stop
|
|
800
|
+
- [ ] FeatureStateService: Support run_history read/write
|
|
801
|
+
- [ ] `GET /api/runtime/runs` endpoint implemented
|
|
802
|
+
- [ ] `GET /api/runtime/operations` endpoint implemented
|
|
803
|
+
- [ ] `GET /api/runtime/events` endpoint implemented
|
|
804
|
+
- [ ] Run ID resolution from run_history (latest by default)
|
|
805
|
+
- [ ] RuntimeInspector component renders in detail panel
|
|
806
|
+
- [ ] Run selector dropdown with all historical runs
|
|
807
|
+
- [ ] Operations tab shows last 50 operations by default
|
|
808
|
+
- [ ] Events tab shows last 50 events by default
|
|
809
|
+
- [ ] Operations sorted by timestamp (newest first)
|
|
810
|
+
- [ ] Events sorted by timestamp (newest first)
|
|
811
|
+
- [ ] Expand/collapse operation rows
|
|
812
|
+
- [ ] Expand/collapse event rows
|
|
813
|
+
- [ ] Copy operation_id and request_hash
|
|
814
|
+
- [ ] Filter operations by tool_name
|
|
815
|
+
- [ ] Filter operations by success/failure
|
|
816
|
+
- [ ] Filter events by role
|
|
817
|
+
- [ ] Filter events by event_type
|
|
818
|
+
- [ ] Pagination controls (Next/Previous)
|
|
819
|
+
- [ ] Loading state
|
|
820
|
+
- [ ] Error state with retry button
|
|
821
|
+
- [ ] Empty state ("No operations recorded")
|
|
822
|
+
- [ ] All tests pass (>= 90% coverage)
|
|
823
|
+
- [ ] TypeScript strict mode passes
|
|
824
|
+
- [ ] ESLint zero warnings
|
|
825
|
+
|
|
826
|
+
### 6.2 Should Have
|
|
827
|
+
|
|
828
|
+
- [ ] Syntax highlighting for JSON responses
|
|
829
|
+
- [ ] Duration calculation for events
|
|
830
|
+
- [ ] Time range filters (Last Hour/Last Day/All)
|
|
831
|
+
- [ ] Export operations to JSON file
|
|
832
|
+
- [ ] Export events to JSON file
|
|
833
|
+
- [ ] Search within operation responses
|
|
834
|
+
- [ ] Keyboard navigation (arrow keys to expand/collapse)
|
|
835
|
+
|
|
836
|
+
### 6.3 Nice to Have
|
|
837
|
+
|
|
838
|
+
- [ ] Real-time updates via SSE (append new operations/events)
|
|
839
|
+
- [ ] Diff view for plan.update operations
|
|
840
|
+
- [ ] Link from operation to related feature state change
|
|
841
|
+
- [ ] Flame graph for operation timing
|
|
842
|
+
- [ ] Event correlation (link worker_started to worker_completed)
|
|
843
|
+
|
|
844
|
+
---
|
|
845
|
+
|
|
846
|
+
## 7. Non-Goals
|
|
847
|
+
|
|
848
|
+
- **Mutation of runtime files:** This feature is read-only inspection
|
|
849
|
+
- **Global runtime view:** Always scoped to single feature
|
|
850
|
+
- **Historical run comparison:** Only shows latest run (or specified run_id)
|
|
851
|
+
- **Real-time streaming:** Initial version uses polling/manual refresh
|
|
852
|
+
- **Advanced analytics:** No aggregation, charts, or trend analysis (use Analytics page)
|
|
853
|
+
|
|
854
|
+
---
|
|
855
|
+
|
|
856
|
+
## 8. Rollout Plan
|
|
857
|
+
|
|
858
|
+
### 8.1 Phase 0: Schema and State Management (Week 1)
|
|
859
|
+
|
|
860
|
+
- Add `run_history` field to `state.schema.json`
|
|
861
|
+
- Update FeatureStateService to read/write run_history
|
|
862
|
+
- Update SupervisorRuntime to append run_id on feature start
|
|
863
|
+
- Update SupervisorRuntime to update run status on feature end
|
|
864
|
+
- Add migration for existing features (backfill empty run_history)
|
|
865
|
+
- Add unit tests for schema validation
|
|
866
|
+
- Add unit tests for state service
|
|
867
|
+
|
|
868
|
+
### 8.2 Phase 1: Backend API (Week 2)
|
|
869
|
+
|
|
870
|
+
- Implement `/api/runtime/runs` endpoint
|
|
871
|
+
- Implement `/api/runtime/operations` endpoint with run_history resolution
|
|
872
|
+
- Implement `/api/runtime/events` endpoint with run_history resolution
|
|
873
|
+
- Add unit tests
|
|
874
|
+
- Add integration tests
|
|
875
|
+
- Document API in README
|
|
876
|
+
|
|
877
|
+
### 8.3 Phase 2: Frontend UI (Week 3)
|
|
878
|
+
|
|
879
|
+
- Implement RuntimeInspector component
|
|
880
|
+
- Add run selector dropdown
|
|
881
|
+
- Add Operations tab
|
|
882
|
+
- Add Events tab
|
|
883
|
+
- Add filter controls
|
|
884
|
+
- Add pagination
|
|
885
|
+
- Integrate with detail panel
|
|
886
|
+
|
|
887
|
+
### 8.4 Phase 3: Polish (Week 4)
|
|
888
|
+
|
|
889
|
+
- Add syntax highlighting
|
|
890
|
+
- Add duration calculations
|
|
891
|
+
- Add export functionality
|
|
892
|
+
- Add keyboard navigation
|
|
893
|
+
- Performance optimization
|
|
894
|
+
- Accessibility audit
|
|
895
|
+
|
|
896
|
+
### 8.5 Phase 4: Documentation (Week 4)
|
|
897
|
+
|
|
898
|
+
- Update state.schema.json documentation
|
|
899
|
+
- Update dashboard README
|
|
900
|
+
- Add screenshots to docs
|
|
901
|
+
- Create user guide
|
|
902
|
+
- Update CLAUDE.md and AGENTS.md
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 9. Success Metrics
|
|
907
|
+
|
|
908
|
+
### 9.1 Functional Metrics
|
|
909
|
+
|
|
910
|
+
- API response time < 200ms (p95)
|
|
911
|
+
- UI render time < 100ms (p95)
|
|
912
|
+
- Zero crashes on large files (< 10MB)
|
|
913
|
+
- 100% test coverage for new code
|
|
914
|
+
|
|
915
|
+
### 9.2 User Metrics
|
|
916
|
+
|
|
917
|
+
- Time to find failure cause reduced by 50%
|
|
918
|
+
- Number of "What happened?" questions reduced
|
|
919
|
+
- Operator satisfaction score > 4/5
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
923
|
+
## 10. References
|
|
924
|
+
|
|
925
|
+
### 10.1 Related Documents
|
|
926
|
+
|
|
927
|
+
- `spec-files/completed/agentic_orchestrator_dashboard_advanced_ux_spec.md` - Dashboard UX standards
|
|
928
|
+
- `README.md` - CLI and tool contracts
|
|
929
|
+
- `CLAUDE.md` - Architecture patterns
|
|
930
|
+
|
|
931
|
+
### 10.2 Related Code
|
|
932
|
+
|
|
933
|
+
- `packages/web-dashboard/src/components/detail-panel.tsx` - Feature detail panel
|
|
934
|
+
- `packages/web-dashboard/src/lib/aop-client.ts` - API client utilities
|
|
935
|
+
- `apps/control-plane/src/mcp/tool-runtime.ts` - Operation ledger writer
|
|
936
|
+
- `apps/control-plane/src/supervisor/runtime.ts` - Worker events writer
|
|
937
|
+
|
|
938
|
+
---
|
|
939
|
+
|
|
940
|
+
**End of Specification**
|