@semiont/backend 0.4.19 → 0.4.21

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/dist/openapi.json CHANGED
@@ -12,303 +12,6 @@
12
12
  }
13
13
  ],
14
14
  "paths": {
15
- "/resources/{id}": {
16
- "get": {
17
- "summary": "Get Resource by URI (W3C Content Negotiation)",
18
- "description": "W3C-compliant globally resolvable resource URI with content negotiation. Returns JSON-LD metadata (Accept: application/ld+json), raw representation (Accept: text/plain, text/markdown, etc.), or redirects to frontend (?view=semiont). Requires authentication.",
19
- "tags": [
20
- "W3C URIs"
21
- ],
22
- "security": [
23
- {
24
- "bearerAuth": []
25
- }
26
- ],
27
- "parameters": [
28
- {
29
- "name": "id",
30
- "in": "path",
31
- "required": true,
32
- "schema": {
33
- "type": "string"
34
- },
35
- "description": "Resource ID"
36
- },
37
- {
38
- "name": "view",
39
- "in": "query",
40
- "required": false,
41
- "schema": {
42
- "type": "string",
43
- "enum": [
44
- "semiont"
45
- ]
46
- },
47
- "description": "Optional view parameter. If set to 'semiont', redirects to frontend viewer."
48
- }
49
- ],
50
- "responses": {
51
- "200": {
52
- "description": "Resource metadata (JSON-LD) or raw representation",
53
- "content": {
54
- "application/ld+json": {
55
- "schema": {
56
- "$ref": "#/components/schemas/GetResourceResponse"
57
- }
58
- },
59
- "text/plain": {
60
- "schema": {
61
- "type": "string"
62
- }
63
- },
64
- "text/markdown": {
65
- "schema": {
66
- "type": "string"
67
- }
68
- }
69
- }
70
- },
71
- "302": {
72
- "description": "Redirect to frontend viewer (when ?view=semiont)"
73
- },
74
- "404": {
75
- "description": "Resource not found"
76
- }
77
- }
78
- },
79
- "patch": {
80
- "summary": "Update Resource",
81
- "description": "Update resource metadata (append-only operations - name and content are immutable)",
82
- "tags": [
83
- "W3C URIs"
84
- ],
85
- "security": [
86
- {
87
- "bearerAuth": []
88
- }
89
- ],
90
- "parameters": [
91
- {
92
- "name": "id",
93
- "in": "path",
94
- "required": true,
95
- "schema": {
96
- "type": "string"
97
- },
98
- "description": "Resource ID"
99
- }
100
- ],
101
- "requestBody": {
102
- "content": {
103
- "application/json": {
104
- "schema": {
105
- "$ref": "#/components/schemas/UpdateResourceRequest"
106
- }
107
- }
108
- }
109
- },
110
- "responses": {
111
- "202": {
112
- "description": "Update accepted"
113
- },
114
- "404": {
115
- "description": "Resource not found"
116
- }
117
- }
118
- }
119
- },
120
- "/annotations/{id}": {
121
- "get": {
122
- "summary": "Get Annotation by URI (W3C Content Negotiation)",
123
- "description": "W3C-compliant globally resolvable annotation URI with content negotiation. Returns JSON-LD for API clients (Accept: application/ld+json or application/json). Redirects to frontend for browsers (Accept: text/html or browser User-Agent). Requires authentication and resourceId query parameter.",
124
- "tags": [
125
- "W3C URIs"
126
- ],
127
- "security": [
128
- {
129
- "bearerAuth": []
130
- }
131
- ],
132
- "parameters": [
133
- {
134
- "name": "id",
135
- "in": "path",
136
- "required": true,
137
- "schema": {
138
- "type": "string"
139
- },
140
- "description": "Annotation ID"
141
- },
142
- {
143
- "name": "resourceId",
144
- "in": "query",
145
- "required": true,
146
- "schema": {
147
- "type": "string",
148
- "format": "uri"
149
- },
150
- "description": "Resource ID or URI containing the annotation"
151
- }
152
- ],
153
- "responses": {
154
- "200": {
155
- "description": "Annotation representation (JSON-LD)",
156
- "content": {
157
- "application/ld+json": {
158
- "schema": {
159
- "$ref": "#/components/schemas/GetAnnotationResponse"
160
- }
161
- }
162
- }
163
- },
164
- "302": {
165
- "description": "Redirect to frontend (for browsers)"
166
- },
167
- "400": {
168
- "description": "Missing resourceId parameter"
169
- },
170
- "404": {
171
- "description": "Annotation not found"
172
- }
173
- }
174
- }
175
- },
176
- "/api/annotations/{id}/context": {
177
- "get": {
178
- "summary": "Get Annotation Context",
179
- "description": "Get the text context around an annotation with configurable before/after window",
180
- "tags": [
181
- "Annotations",
182
- "Context"
183
- ],
184
- "security": [
185
- {
186
- "bearerAuth": []
187
- }
188
- ],
189
- "parameters": [
190
- {
191
- "name": "id",
192
- "in": "path",
193
- "required": true,
194
- "schema": {
195
- "type": "string"
196
- },
197
- "description": "Annotation ID"
198
- },
199
- {
200
- "name": "resourceId",
201
- "in": "query",
202
- "required": true,
203
- "schema": {
204
- "type": "string"
205
- },
206
- "description": "Resource ID containing the annotation"
207
- },
208
- {
209
- "name": "contextBefore",
210
- "in": "query",
211
- "required": false,
212
- "schema": {
213
- "type": "integer",
214
- "minimum": 0,
215
- "maximum": 5000,
216
- "default": 100
217
- },
218
- "description": "Number of characters before the selection"
219
- },
220
- {
221
- "name": "contextAfter",
222
- "in": "query",
223
- "required": false,
224
- "schema": {
225
- "type": "integer",
226
- "minimum": 0,
227
- "maximum": 5000,
228
- "default": 100
229
- },
230
- "description": "Number of characters after the selection"
231
- }
232
- ],
233
- "responses": {
234
- "200": {
235
- "description": "Annotation context",
236
- "content": {
237
- "application/json": {
238
- "schema": {
239
- "$ref": "#/components/schemas/AnnotationContextResponse"
240
- }
241
- }
242
- }
243
- },
244
- "400": {
245
- "description": "Invalid query parameters"
246
- },
247
- "401": {
248
- "description": "Authentication required"
249
- },
250
- "404": {
251
- "description": "Annotation not found"
252
- }
253
- }
254
- }
255
- },
256
- "/api/annotations/{id}/summary": {
257
- "get": {
258
- "summary": "Get Annotation Summary",
259
- "description": "Get an AI-generated summary of the annotation in context",
260
- "tags": [
261
- "Annotations",
262
- "AI"
263
- ],
264
- "security": [
265
- {
266
- "bearerAuth": []
267
- }
268
- ],
269
- "parameters": [
270
- {
271
- "name": "id",
272
- "in": "path",
273
- "required": true,
274
- "schema": {
275
- "type": "string"
276
- },
277
- "description": "Annotation ID"
278
- },
279
- {
280
- "name": "resourceId",
281
- "in": "query",
282
- "required": true,
283
- "schema": {
284
- "type": "string"
285
- },
286
- "description": "Resource ID containing the annotation"
287
- }
288
- ],
289
- "responses": {
290
- "200": {
291
- "description": "AI-generated annotation summary",
292
- "content": {
293
- "application/json": {
294
- "schema": {
295
- "$ref": "#/components/schemas/ContextualSummaryResponse"
296
- }
297
- }
298
- }
299
- },
300
- "400": {
301
- "description": "Missing resourceId parameter"
302
- },
303
- "401": {
304
- "description": "Authentication required"
305
- },
306
- "404": {
307
- "description": "Annotation not found"
308
- }
309
- }
310
- }
311
- },
312
15
  "/api/health": {
313
16
  "get": {
314
17
  "summary": "Health Check",
@@ -553,18 +256,88 @@
553
256
  }
554
257
  }
555
258
  },
556
- "/api/users/me": {
557
- "get": {
558
- "summary": "Get Current User",
559
- "description": "Get information about the authenticated user",
259
+ "/api/tokens/worker": {
260
+ "post": {
261
+ "summary": "Worker Token Exchange",
262
+ "description": "Exchange a shared secret for a bearer JWT. Used by workers and actors connecting to the EventBus.",
560
263
  "tags": [
561
- "Users"
264
+ "Authentication"
562
265
  ],
563
- "security": [
564
- {
565
- "bearerAuth": []
266
+ "security": [],
267
+ "requestBody": {
268
+ "required": true,
269
+ "content": {
270
+ "application/json": {
271
+ "schema": {
272
+ "type": "object",
273
+ "properties": {
274
+ "secret": {
275
+ "type": "string",
276
+ "description": "The shared worker secret (SEMIONT_WORKER_SECRET)"
277
+ }
278
+ },
279
+ "required": [
280
+ "secret"
281
+ ]
282
+ }
283
+ }
566
284
  }
567
- ],
285
+ },
286
+ "responses": {
287
+ "200": {
288
+ "description": "Token issued",
289
+ "content": {
290
+ "application/json": {
291
+ "schema": {
292
+ "type": "object",
293
+ "properties": {
294
+ "token": {
295
+ "type": "string",
296
+ "description": "Bearer JWT for subsequent authenticated requests"
297
+ }
298
+ },
299
+ "required": [
300
+ "token"
301
+ ]
302
+ }
303
+ }
304
+ }
305
+ },
306
+ "401": {
307
+ "description": "Invalid worker secret",
308
+ "content": {
309
+ "application/json": {
310
+ "schema": {
311
+ "$ref": "#/components/schemas/ErrorResponse"
312
+ }
313
+ }
314
+ }
315
+ },
316
+ "503": {
317
+ "description": "Worker authentication not configured",
318
+ "content": {
319
+ "application/json": {
320
+ "schema": {
321
+ "$ref": "#/components/schemas/ErrorResponse"
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ },
329
+ "/api/users/me": {
330
+ "get": {
331
+ "summary": "Get Current User",
332
+ "description": "Get information about the authenticated user",
333
+ "tags": [
334
+ "Users"
335
+ ],
336
+ "security": [
337
+ {
338
+ "bearerAuth": []
339
+ }
340
+ ],
568
341
  "responses": {
569
342
  "200": {
570
343
  "description": "User information",
@@ -1109,12 +882,12 @@
1109
882
  }
1110
883
  }
1111
884
  },
1112
- "/api/admin/exchange/export": {
885
+ "/api/moderate/exchange/export": {
1113
886
  "post": {
1114
887
  "summary": "Export Knowledge Base as JSON-LD",
1115
888
  "description": "Export the knowledge base as a JSON-LD Linked Data tar.gz archive",
1116
889
  "tags": [
1117
- "Admin"
890
+ "Moderation"
1118
891
  ],
1119
892
  "security": [
1120
893
  {
@@ -1156,7 +929,7 @@
1156
929
  }
1157
930
  },
1158
931
  "403": {
1159
- "description": "Forbidden - Admin access required",
932
+ "description": "Forbidden - moderator or admin role required",
1160
933
  "content": {
1161
934
  "application/json": {
1162
935
  "schema": {
@@ -1168,12 +941,12 @@
1168
941
  }
1169
942
  }
1170
943
  },
1171
- "/api/admin/exchange/import": {
944
+ "/api/moderate/exchange/import": {
1172
945
  "post": {
1173
946
  "summary": "Import Knowledge Base from JSON-LD",
1174
947
  "description": "Import resources from a JSON-LD Linked Data archive. Returns SSE progress events.",
1175
948
  "tags": [
1176
- "Admin"
949
+ "Moderation"
1177
950
  ],
1178
951
  "security": [
1179
952
  {
@@ -1232,7 +1005,7 @@
1232
1005
  }
1233
1006
  },
1234
1007
  "403": {
1235
- "description": "Forbidden - Admin access required",
1008
+ "description": "Forbidden - moderator or admin role required",
1236
1009
  "content": {
1237
1010
  "application/json": {
1238
1011
  "schema": {
@@ -1244,299 +1017,138 @@
1244
1017
  }
1245
1018
  }
1246
1019
  },
1247
- "/resources": {
1248
- "post": {
1249
- "summary": "Create Resource",
1250
- "description": "Create a new resource",
1020
+ "/api/cookies/consent": {
1021
+ "get": {
1022
+ "summary": "Get cookie consent preferences",
1023
+ "description": "Returns the current user's cookie consent preferences.",
1251
1024
  "tags": [
1252
- "Resources"
1025
+ "Cookies"
1253
1026
  ],
1254
1027
  "security": [
1255
1028
  {
1256
1029
  "bearerAuth": []
1257
1030
  }
1258
1031
  ],
1259
- "requestBody": {
1260
- "required": true,
1261
- "content": {
1262
- "multipart/form-data": {
1263
- "schema": {
1264
- "type": "object",
1265
- "required": [
1266
- "name",
1267
- "file",
1268
- "format"
1269
- ],
1270
- "properties": {
1271
- "name": {
1272
- "type": "string",
1273
- "description": "Resource name"
1274
- },
1275
- "file": {
1276
- "type": "string",
1277
- "format": "binary",
1278
- "description": "Binary content of the resource"
1279
- },
1280
- "format": {
1281
- "type": "string",
1282
- "description": "MIME type (e.g., text/markdown, image/png)"
1283
- },
1284
- "entityTypes": {
1285
- "type": "string",
1286
- "description": "JSON-encoded array of entity types"
1287
- },
1288
- "language": {
1289
- "type": "string",
1290
- "description": "ISO 639-1 language code"
1291
- },
1292
- "creationMethod": {
1293
- "type": "string",
1294
- "description": "How the resource was created"
1295
- },
1296
- "sourceAnnotationId": {
1297
- "type": "string",
1298
- "description": "Source annotation ID (for generated resources)"
1299
- },
1300
- "sourceResourceId": {
1301
- "type": "string",
1302
- "description": "Source resource ID (for cloned resources)"
1303
- }
1304
- }
1305
- }
1306
- }
1307
- }
1308
- },
1309
1032
  "responses": {
1310
- "202": {
1311
- "description": "Resource creation accepted",
1033
+ "200": {
1034
+ "description": "Current consent preferences",
1312
1035
  "content": {
1313
1036
  "application/json": {
1314
1037
  "schema": {
1315
- "type": "object",
1316
- "properties": {
1317
- "resourceId": {
1318
- "type": "string"
1319
- }
1320
- },
1321
- "required": [
1322
- "resourceId"
1323
- ]
1038
+ "$ref": "#/components/schemas/CookieConsentResponse"
1324
1039
  }
1325
1040
  }
1326
1041
  }
1327
- }
1328
- }
1329
- },
1330
- "get": {
1331
- "summary": "List Resources",
1332
- "description": "List all resources with optional filters",
1333
- "tags": [
1334
- "Resources"
1335
- ],
1336
- "security": [
1337
- {
1338
- "bearerAuth": []
1339
- }
1340
- ],
1341
- "parameters": [
1342
- {
1343
- "schema": {
1344
- "type": "number",
1345
- "nullable": true,
1346
- "default": 0
1347
- },
1348
- "required": false,
1349
- "name": "offset",
1350
- "in": "query"
1351
- },
1352
- {
1353
- "schema": {
1354
- "type": "number",
1355
- "nullable": true,
1356
- "default": 50
1357
- },
1358
- "required": false,
1359
- "name": "limit",
1360
- "in": "query"
1361
- },
1362
- {
1363
- "schema": {
1364
- "type": "string"
1365
- },
1366
- "required": false,
1367
- "name": "entityType",
1368
- "in": "query"
1369
- },
1370
- {
1371
- "schema": {
1372
- "anyOf": [
1373
- {
1374
- "type": "string",
1375
- "enum": [
1376
- "true"
1377
- ]
1378
- },
1379
- {
1380
- "type": "string",
1381
- "enum": [
1382
- "false"
1383
- ]
1384
- },
1385
- {
1386
- "type": "boolean"
1387
- }
1388
- ]
1389
- },
1390
- "required": false,
1391
- "name": "archived",
1392
- "in": "query"
1393
- },
1394
- {
1395
- "schema": {
1396
- "type": "string"
1397
- },
1398
- "required": false,
1399
- "name": "search",
1400
- "in": "query"
1401
1042
  },
1402
- {
1403
- "schema": {
1404
- "type": "string"
1405
- },
1406
- "required": false,
1407
- "name": "q",
1408
- "in": "query",
1409
- "description": "Search query"
1410
- }
1411
- ],
1412
- "responses": {
1413
- "200": {
1414
- "description": "Resources listed successfully",
1043
+ "401": {
1044
+ "description": "Authentication required",
1415
1045
  "content": {
1416
1046
  "application/json": {
1417
1047
  "schema": {
1418
- "$ref": "#/components/schemas/ListResourcesResponse"
1048
+ "$ref": "#/components/schemas/ErrorResponse"
1419
1049
  }
1420
1050
  }
1421
1051
  }
1422
1052
  }
1423
1053
  }
1424
- }
1425
- },
1426
- "/resources/{id}/annotate-references": {
1054
+ },
1427
1055
  "post": {
1428
- "summary": "Annotate References with Progress (SSE)",
1429
- "description": "Stream real-time reference annotation progress via Server-Sent Events",
1056
+ "summary": "Update cookie consent preferences",
1057
+ "description": "Update the current user's cookie consent preferences. The `necessary` flag must be true — necessary cookies cannot be disabled.",
1430
1058
  "tags": [
1431
- "Resources",
1432
- "Annotations",
1433
- "Real-time"
1059
+ "Cookies"
1434
1060
  ],
1435
1061
  "security": [
1436
1062
  {
1437
1063
  "bearerAuth": []
1438
1064
  }
1439
1065
  ],
1440
- "parameters": [
1441
- {
1442
- "schema": {
1443
- "type": "string"
1444
- },
1445
- "required": true,
1446
- "name": "id",
1447
- "in": "path"
1448
- }
1449
- ],
1450
1066
  "requestBody": {
1067
+ "required": true,
1451
1068
  "content": {
1452
1069
  "application/json": {
1453
1070
  "schema": {
1454
- "$ref": "#/components/schemas/AnnotateReferencesStreamRequest"
1071
+ "$ref": "#/components/schemas/CookieConsentRequest"
1455
1072
  }
1456
1073
  }
1457
1074
  }
1458
1075
  },
1459
1076
  "responses": {
1460
1077
  "200": {
1461
- "description": "SSE stream opened successfully",
1078
+ "description": "Consent updated",
1462
1079
  "content": {
1463
- "text/event-stream": {
1080
+ "application/json": {
1464
1081
  "schema": {
1465
- "$ref": "#/components/schemas/EventStreamResponse"
1082
+ "$ref": "#/components/schemas/CookieConsentResponse"
1466
1083
  }
1467
1084
  }
1468
1085
  }
1469
1086
  },
1470
- "401": {
1471
- "description": "Authentication required"
1087
+ "400": {
1088
+ "description": "Invalid consent data (non-boolean fields, missing fields, or necessary=false)",
1089
+ "content": {
1090
+ "application/json": {
1091
+ "schema": {
1092
+ "$ref": "#/components/schemas/CookieConsentResponse"
1093
+ }
1094
+ }
1095
+ }
1472
1096
  },
1473
- "404": {
1474
- "description": "Resource not found"
1097
+ "401": {
1098
+ "description": "Authentication required",
1099
+ "content": {
1100
+ "application/json": {
1101
+ "schema": {
1102
+ "$ref": "#/components/schemas/ErrorResponse"
1103
+ }
1104
+ }
1105
+ }
1475
1106
  }
1476
1107
  }
1477
1108
  }
1478
1109
  },
1479
- "/resources/{id}/annotate-highlights": {
1480
- "post": {
1481
- "summary": "Annotate Highlights with Progress (SSE)",
1482
- "description": "Stream real-time highlight annotation progress via Server-Sent Events",
1110
+ "/api/cookies/export": {
1111
+ "get": {
1112
+ "summary": "Export cookie data (GDPR)",
1113
+ "description": "Export the current user's cookie-related data as a downloadable JSON file. Response sets `Content-Disposition: attachment; filename=\"cookie-data-export-<timestamp>.json\"`.",
1483
1114
  "tags": [
1484
- "Resources",
1485
- "Annotations",
1486
- "Real-time"
1115
+ "Cookies"
1487
1116
  ],
1488
1117
  "security": [
1489
1118
  {
1490
1119
  "bearerAuth": []
1491
1120
  }
1492
1121
  ],
1493
- "parameters": [
1494
- {
1495
- "schema": {
1496
- "type": "string"
1497
- },
1498
- "required": true,
1499
- "name": "id",
1500
- "in": "path"
1501
- }
1502
- ],
1503
- "requestBody": {
1504
- "content": {
1505
- "application/json": {
1506
- "schema": {
1507
- "$ref": "#/components/schemas/AnnotateHighlightsStreamRequest"
1508
- }
1509
- }
1510
- }
1511
- },
1512
1122
  "responses": {
1513
1123
  "200": {
1514
- "description": "SSE stream opened successfully",
1124
+ "description": "User cookie data as attachment",
1515
1125
  "content": {
1516
- "text/event-stream": {
1126
+ "application/json": {
1517
1127
  "schema": {
1518
- "$ref": "#/components/schemas/EventStreamResponse"
1128
+ "$ref": "#/components/schemas/CookieExportResponse"
1519
1129
  }
1520
1130
  }
1521
1131
  }
1522
1132
  },
1523
1133
  "401": {
1524
- "description": "Authentication required"
1525
- },
1526
- "404": {
1527
- "description": "Resource not found"
1134
+ "description": "Authentication required",
1135
+ "content": {
1136
+ "application/json": {
1137
+ "schema": {
1138
+ "$ref": "#/components/schemas/ErrorResponse"
1139
+ }
1140
+ }
1141
+ }
1528
1142
  }
1529
1143
  }
1530
1144
  }
1531
1145
  },
1532
- "/resources/{id}/annotate-assessments": {
1533
- "post": {
1534
- "summary": "Annotate Assessments with Progress (SSE)",
1535
- "description": "Stream real-time assessment annotation progress via Server-Sent Events",
1146
+ "/api/tokens/mcp-setup": {
1147
+ "get": {
1148
+ "summary": "MCP Setup (browser-driven CLI handoff)",
1149
+ "description": "Browser flow that generates a long-lived (30 day) MCP refresh token for the authenticated user and redirects to a localhost callback URL with the token as a query parameter. Used by CLI tooling (similar to Google's OAuth CLI flow).\n\nThe callback URL must match one of the localhost patterns (`http://localhost:<port>/...`, `http://127.0.0.1:<port>/...`, or `http://[::1]:<port>/...`).",
1536
1150
  "tags": [
1537
- "Resources",
1538
- "Annotations",
1539
- "Real-time"
1151
+ "Authentication"
1540
1152
  ],
1541
1153
  "security": [
1542
1154
  {
@@ -1545,51 +1157,58 @@
1545
1157
  ],
1546
1158
  "parameters": [
1547
1159
  {
1160
+ "name": "callback",
1161
+ "in": "query",
1162
+ "required": true,
1163
+ "description": "Localhost URL to redirect to with `?token=<refresh-token>` on success.",
1548
1164
  "schema": {
1549
1165
  "type": "string"
1550
- },
1551
- "required": true,
1552
- "name": "id",
1553
- "in": "path"
1166
+ }
1554
1167
  }
1555
1168
  ],
1556
- "requestBody": {
1557
- "content": {
1558
- "application/json": {
1559
- "schema": {
1560
- "$ref": "#/components/schemas/AnnotateAssessmentsStreamRequest"
1561
- }
1562
- }
1563
- }
1564
- },
1565
1169
  "responses": {
1566
- "200": {
1567
- "description": "SSE stream opened successfully",
1170
+ "302": {
1171
+ "description": "Redirect to the callback URL with the newly-issued refresh token appended as a `?token=` query parameter."
1172
+ },
1173
+ "400": {
1174
+ "description": "Missing or non-localhost callback URL",
1568
1175
  "content": {
1569
- "text/event-stream": {
1176
+ "application/json": {
1570
1177
  "schema": {
1571
- "$ref": "#/components/schemas/EventStreamResponse"
1178
+ "$ref": "#/components/schemas/ErrorResponse"
1572
1179
  }
1573
1180
  }
1574
1181
  }
1575
1182
  },
1576
1183
  "401": {
1577
- "description": "Authentication required"
1184
+ "description": "Authentication required",
1185
+ "content": {
1186
+ "application/json": {
1187
+ "schema": {
1188
+ "$ref": "#/components/schemas/ErrorResponse"
1189
+ }
1190
+ }
1191
+ }
1578
1192
  },
1579
- "404": {
1580
- "description": "Resource not found"
1193
+ "500": {
1194
+ "description": "Failed to generate refresh token",
1195
+ "content": {
1196
+ "application/json": {
1197
+ "schema": {
1198
+ "$ref": "#/components/schemas/ErrorResponse"
1199
+ }
1200
+ }
1201
+ }
1581
1202
  }
1582
1203
  }
1583
1204
  }
1584
1205
  },
1585
- "/resources/{id}/annotate-comments": {
1586
- "post": {
1587
- "summary": "Annotate Comments with Progress (SSE)",
1588
- "description": "Stream real-time comment annotation progress via Server-Sent Events",
1206
+ "/bus/subscribe": {
1207
+ "get": {
1208
+ "summary": "Subscribe to the Semiont event bus (SSE)",
1209
+ "description": "Opens a long-lived Server-Sent Events stream over which the bus delivers events matching the requested channels and scopes.\n\nEach SSE frame has `event: bus-event`, a JSON-encoded `data` of the form `{ channel, payload, scope? }`, and an `id` (either a persisted event id, `scope:seq`, for domain events; or an ephemeral id for job-lifecycle / result channels).\n\nPass the last-received id as `Last-Event-ID` to resume — the server replays missed persisted events and emits a `bus:resume-gap` synthetic event when the gap exceeds the replay window.",
1589
1210
  "tags": [
1590
- "Resources",
1591
- "Annotations",
1592
- "Real-time"
1211
+ "Bus"
1593
1212
  ],
1594
1213
  "security": [
1595
1214
  {
@@ -1598,79 +1217,51 @@
1598
1217
  ],
1599
1218
  "parameters": [
1600
1219
  {
1220
+ "name": "channel",
1221
+ "in": "query",
1222
+ "required": false,
1223
+ "description": "Unscoped channels to subscribe to. Repeat the parameter for multiple channels. At least one of `channel` or `scoped` is required.",
1601
1224
  "schema": {
1602
- "type": "string"
1603
- },
1604
- "required": true,
1605
- "name": "id",
1606
- "in": "path"
1607
- }
1608
- ],
1609
- "requestBody": {
1610
- "content": {
1611
- "application/json": {
1612
- "schema": {
1613
- "$ref": "#/components/schemas/AnnotateCommentsStreamRequest"
1225
+ "type": "array",
1226
+ "items": {
1227
+ "type": "string"
1614
1228
  }
1615
1229
  }
1616
- }
1617
- },
1618
- "responses": {
1619
- "200": {
1620
- "description": "SSE stream opened successfully",
1621
- "content": {
1622
- "text/event-stream": {
1623
- "schema": {
1624
- "$ref": "#/components/schemas/EventStreamResponse"
1625
- }
1230
+ },
1231
+ {
1232
+ "name": "scoped",
1233
+ "in": "query",
1234
+ "required": false,
1235
+ "description": "Resource-scoped channels to subscribe to (requires `scope`). Repeat for multiple.",
1236
+ "schema": {
1237
+ "type": "array",
1238
+ "items": {
1239
+ "type": "string"
1626
1240
  }
1627
1241
  }
1628
1242
  },
1629
- "401": {
1630
- "description": "Authentication required"
1631
- },
1632
- "404": {
1633
- "description": "Resource not found"
1634
- }
1635
- }
1636
- }
1637
- },
1638
- "/resources/{id}/annotate-tags": {
1639
- "post": {
1640
- "summary": "Annotate Tags with Progress (SSE)",
1641
- "description": "Stream real-time tag annotation progress via Server-Sent Events. Identifies passages serving specific structural roles (IRAC, IMRAD, Toulmin frameworks).",
1642
- "tags": [
1643
- "Resources",
1644
- "Annotations",
1645
- "Real-time"
1646
- ],
1647
- "security": [
1648
1243
  {
1649
- "bearerAuth": []
1650
- }
1651
- ],
1652
- "parameters": [
1244
+ "name": "scope",
1245
+ "in": "query",
1246
+ "required": false,
1247
+ "description": "Resource scope for scoped channels (typically a resourceId).",
1248
+ "schema": {
1249
+ "type": "string"
1250
+ }
1251
+ },
1653
1252
  {
1253
+ "name": "Last-Event-ID",
1254
+ "in": "header",
1255
+ "required": false,
1256
+ "description": "Id of the last event the client received. On reconnect, the server replays persisted events after this id and emits `bus:resume-gap` if the gap exceeds the replay cap.",
1654
1257
  "schema": {
1655
1258
  "type": "string"
1656
- },
1657
- "required": true,
1658
- "name": "id",
1659
- "in": "path"
1660
- }
1661
- ],
1662
- "requestBody": {
1663
- "content": {
1664
- "application/json": {
1665
- "schema": {
1666
- "$ref": "#/components/schemas/AnnotateTagsStreamRequest"
1667
- }
1668
1259
  }
1669
1260
  }
1670
- },
1261
+ ],
1671
1262
  "responses": {
1672
1263
  "200": {
1673
- "description": "SSE stream opened successfully",
1264
+ "description": "SSE stream opened",
1674
1265
  "content": {
1675
1266
  "text/event-stream": {
1676
1267
  "schema": {
@@ -1679,139 +1270,196 @@
1679
1270
  }
1680
1271
  }
1681
1272
  },
1682
- "401": {
1683
- "description": "Authentication required"
1273
+ "400": {
1274
+ "description": "No channels requested (at least one `channel` or `scoped` parameter required)",
1275
+ "content": {
1276
+ "application/json": {
1277
+ "schema": {
1278
+ "$ref": "#/components/schemas/ErrorResponse"
1279
+ }
1280
+ }
1281
+ }
1684
1282
  },
1685
- "404": {
1686
- "description": "Resource not found"
1283
+ "401": {
1284
+ "description": "Authentication required",
1285
+ "content": {
1286
+ "application/json": {
1287
+ "schema": {
1288
+ "$ref": "#/components/schemas/ErrorResponse"
1289
+ }
1290
+ }
1291
+ }
1687
1292
  }
1688
1293
  }
1689
1294
  }
1690
1295
  },
1691
- "/resources/{id}/gather-resource-stream": {
1296
+ "/bus/emit": {
1692
1297
  "post": {
1693
- "summary": "Gather Resource LLM Context (SSE Stream)",
1694
- "description": "Stream real-time resource LLM context gathering progress via Server-Sent Events",
1298
+ "summary": "Emit an event on the Semiont bus",
1299
+ "description": "Publishes an event to the bus. The channel name must be registered in `bus-protocol.ts` (`EventMap`); the payload is validated against the channel's schema in `CHANNEL_SCHEMAS` when one is registered.\n\nWhen `scope` is set, the event publishes on `eventBus.scope(scope)` rather than the global bus, routing it to per-resource SSE subscribers only. The authenticated user's DID is attached to the payload as `_userId` automatically.\n\nReturns 202 Accepted — the event is delivered to in-memory subscribers synchronously, but downstream persistence (Stower) and materialization happen asynchronously.",
1695
1300
  "tags": [
1696
- "Resources",
1697
- "Real-time",
1698
- "AI"
1301
+ "Bus"
1699
1302
  ],
1700
1303
  "security": [
1701
1304
  {
1702
1305
  "bearerAuth": []
1703
1306
  }
1704
1307
  ],
1705
- "parameters": [
1706
- {
1707
- "schema": {
1708
- "type": "string"
1709
- },
1710
- "required": true,
1711
- "name": "id",
1712
- "in": "path"
1713
- }
1714
- ],
1715
1308
  "requestBody": {
1309
+ "required": true,
1716
1310
  "content": {
1717
1311
  "application/json": {
1718
1312
  "schema": {
1719
- "$ref": "#/components/schemas/GatherResourceStreamRequest"
1313
+ "$ref": "#/components/schemas/BusEmitRequest"
1720
1314
  }
1721
1315
  }
1722
1316
  }
1723
1317
  },
1724
1318
  "responses": {
1725
- "200": {
1726
- "description": "SSE stream opened successfully",
1319
+ "202": {
1320
+ "description": "Event accepted and published to subscribers"
1321
+ },
1322
+ "400": {
1323
+ "description": "Missing/invalid channel, payload, or scope; or payload failed schema validation for the channel",
1727
1324
  "content": {
1728
- "text/event-stream": {
1325
+ "application/json": {
1729
1326
  "schema": {
1730
- "$ref": "#/components/schemas/EventStreamResponse"
1327
+ "$ref": "#/components/schemas/ErrorResponse"
1731
1328
  }
1732
1329
  }
1733
1330
  }
1734
1331
  },
1735
1332
  "401": {
1736
- "description": "Authentication required"
1737
- },
1738
- "404": {
1739
- "description": "Resource not found"
1333
+ "description": "Authentication required",
1334
+ "content": {
1335
+ "application/json": {
1336
+ "schema": {
1337
+ "$ref": "#/components/schemas/ErrorResponse"
1338
+ }
1339
+ }
1340
+ }
1740
1341
  }
1741
1342
  }
1742
1343
  }
1743
1344
  },
1744
- "/resources/{id}/match-search": {
1345
+ "/resources": {
1745
1346
  "post": {
1746
- "summary": "Match Search",
1747
- "description": "Submit a match-search command for binding candidates. Returns {correlationId} immediately. Results are delivered asynchronously via the long-lived events-stream as match:search-results or match:search-failed events.",
1347
+ "summary": "Create a resource",
1348
+ "description": "Upload binary content + metadata as multipart/form-data. The backend writes content to disk, then emits yield:create on the bus; Stower persists it and returns a 202 with the new resourceId. Full reconciliation happens via SSE domain events (yield:created).\n\nGeneration workers and the /know/compose page both hit this route — bytes always travel on the HTTP wire, never on the bus.",
1748
1349
  "tags": [
1749
- "Resources",
1750
- "Annotations",
1751
- "AI"
1350
+ "Resources"
1752
1351
  ],
1753
1352
  "security": [
1754
1353
  {
1755
1354
  "bearerAuth": []
1756
1355
  }
1757
1356
  ],
1758
- "parameters": [
1759
- {
1760
- "schema": {
1761
- "type": "string"
1762
- },
1763
- "required": true,
1764
- "name": "id",
1765
- "in": "path",
1766
- "description": "Resource ID"
1767
- }
1768
- ],
1769
1357
  "requestBody": {
1770
1358
  "required": true,
1771
1359
  "content": {
1772
- "application/json": {
1360
+ "multipart/form-data": {
1773
1361
  "schema": {
1774
- "$ref": "#/components/schemas/MatchSearchRequest"
1362
+ "type": "object",
1363
+ "properties": {
1364
+ "name": {
1365
+ "type": "string",
1366
+ "description": "Human-readable resource name"
1367
+ },
1368
+ "file": {
1369
+ "type": "string",
1370
+ "format": "binary",
1371
+ "description": "Binary content"
1372
+ },
1373
+ "format": {
1374
+ "type": "string",
1375
+ "description": "Media type of the content (e.g. text/plain, text/markdown, image/png)"
1376
+ },
1377
+ "storageUri": {
1378
+ "type": "string",
1379
+ "description": "Where the content has been / should be placed (file://... for local). If omitted, derived from name + format."
1380
+ },
1381
+ "language": {
1382
+ "type": "string",
1383
+ "description": "ISO 639-1 language code"
1384
+ },
1385
+ "entityTypes": {
1386
+ "type": "string",
1387
+ "description": "JSON-stringified array of entity type names"
1388
+ },
1389
+ "creationMethod": {
1390
+ "type": "string",
1391
+ "description": "How this resource was created (api, ui, upload, reference, cli, clone, generated)"
1392
+ },
1393
+ "sourceAnnotationId": {
1394
+ "type": "string",
1395
+ "description": "For AI-generated resources: the annotation that triggered generation. Nested into generatedFrom.annotationId on the persisted event."
1396
+ },
1397
+ "sourceResourceId": {
1398
+ "type": "string",
1399
+ "description": "For AI-generated resources: the source resource the generating annotation lives on. Nested into generatedFrom.resourceId on the persisted event."
1400
+ },
1401
+ "generationPrompt": {
1402
+ "type": "string",
1403
+ "description": "For AI-generated resources: the prompt that drove generation"
1404
+ },
1405
+ "generator": {
1406
+ "type": "string",
1407
+ "description": "For AI-generated resources: JSON-stringified Agent (single object or array), capturing which model/worker produced the content"
1408
+ },
1409
+ "isDraft": {
1410
+ "type": "string",
1411
+ "description": "'true' or 'false' — whether the resource is a draft"
1412
+ }
1413
+ },
1414
+ "required": [
1415
+ "name",
1416
+ "file",
1417
+ "format"
1418
+ ]
1775
1419
  }
1776
1420
  }
1777
1421
  }
1778
1422
  },
1779
1423
  "responses": {
1780
1424
  "202": {
1781
- "description": "Search command accepted. Results delivered via events-stream.",
1425
+ "description": "Resource accepted for creation",
1782
1426
  "content": {
1783
1427
  "application/json": {
1784
1428
  "schema": {
1785
- "type": "object",
1786
- "properties": {
1787
- "correlationId": {
1788
- "type": "string"
1789
- }
1790
- },
1791
- "required": [
1792
- "correlationId"
1793
- ]
1429
+ "$ref": "#/components/schemas/CreateResourceResponse"
1794
1430
  }
1795
1431
  }
1796
1432
  }
1797
1433
  },
1798
- "401": {
1799
- "description": "Authentication required"
1434
+ "400": {
1435
+ "description": "Missing required fields (name, file, or format)",
1436
+ "content": {
1437
+ "application/json": {
1438
+ "schema": {
1439
+ "$ref": "#/components/schemas/ErrorResponse"
1440
+ }
1441
+ }
1442
+ }
1800
1443
  },
1801
- "404": {
1802
- "description": "Resource not found"
1444
+ "401": {
1445
+ "description": "Authentication required",
1446
+ "content": {
1447
+ "application/json": {
1448
+ "schema": {
1449
+ "$ref": "#/components/schemas/ErrorResponse"
1450
+ }
1451
+ }
1452
+ }
1803
1453
  }
1804
1454
  }
1805
1455
  }
1806
1456
  },
1807
- "/resources/{resourceId}/annotations/{annotationId}/gather": {
1808
- "post": {
1809
- "summary": "Gather Annotation Context",
1810
- "description": "Submit a gather-context command for an annotation. Returns {correlationId} immediately. The Gatherer assembles passage + graph context (long-running, involves LLM calls) and delivers results via the events-stream as gather:complete, gather:failed, or gather:annotation-progress events.",
1457
+ "/resources/{id}": {
1458
+ "get": {
1459
+ "summary": "Get a resource (content-negotiated)",
1460
+ "description": "Content negotiation via the Accept header:\n- application/ld+json (default) returns JSON-LD metadata including all annotations + inbound entity references\n- text/* or image/* or application/pdf returns the raw representation bytes\n\nBinary payloads flow directly from the content store; metadata payloads go through the bus gateway.",
1811
1461
  "tags": [
1812
- "Resources",
1813
- "Annotations",
1814
- "AI"
1462
+ "Resources"
1815
1463
  ],
1816
1464
  "security": [
1817
1465
  {
@@ -1820,262 +1468,98 @@
1820
1468
  ],
1821
1469
  "parameters": [
1822
1470
  {
1471
+ "name": "id",
1472
+ "in": "path",
1473
+ "required": true,
1823
1474
  "schema": {
1824
1475
  "type": "string"
1825
- },
1826
- "required": true,
1827
- "name": "resourceId",
1828
- "in": "path",
1829
- "description": "Resource ID"
1476
+ }
1830
1477
  },
1831
1478
  {
1479
+ "name": "Accept",
1480
+ "in": "header",
1481
+ "required": false,
1832
1482
  "schema": {
1833
1483
  "type": "string"
1834
1484
  },
1835
- "required": true,
1836
- "name": "annotationId",
1837
- "in": "path",
1838
- "description": "Annotation ID"
1485
+ "description": "application/ld+json for metadata, or a text/image/pdf media type for raw content"
1839
1486
  }
1840
1487
  ],
1841
- "requestBody": {
1842
- "required": true,
1843
- "content": {
1844
- "application/json": {
1845
- "schema": {
1846
- "$ref": "#/components/schemas/GatherAnnotationStreamRequest"
1847
- }
1848
- }
1849
- }
1850
- },
1851
1488
  "responses": {
1852
- "202": {
1853
- "description": "Gather command accepted. Results delivered via events-stream.",
1489
+ "200": {
1490
+ "description": "Resource content or metadata, depending on Accept",
1854
1491
  "content": {
1855
- "application/json": {
1492
+ "application/ld+json": {
1856
1493
  "schema": {
1857
- "type": "object",
1858
- "properties": {
1859
- "correlationId": {
1860
- "type": "string"
1861
- }
1862
- },
1863
- "required": [
1864
- "correlationId"
1865
- ]
1494
+ "$ref": "#/components/schemas/GetResourceResponse"
1866
1495
  }
1867
- }
1868
- }
1869
- },
1870
- "401": {
1871
- "description": "Authentication required"
1872
- }
1873
- }
1874
- }
1875
- },
1876
- "/resources/{id}/referenced-by": {
1877
- "get": {
1878
- "summary": "Get Referenced By",
1879
- "description": "Get resources that reference this resource",
1880
- "tags": [
1881
- "Resources",
1882
- "Graph"
1883
- ],
1884
- "security": [
1885
- {
1886
- "bearerAuth": []
1887
- }
1888
- ],
1889
- "parameters": [
1890
- {
1891
- "schema": {
1892
- "type": "string"
1893
- },
1894
- "required": true,
1895
- "name": "id",
1896
- "in": "path"
1897
- },
1898
- {
1899
- "schema": {
1900
- "$ref": "#/components/schemas/Motivation"
1901
- },
1902
- "required": false,
1903
- "name": "motivation",
1904
- "in": "query",
1905
- "description": "Filter incoming references by W3C motivation type (e.g., 'linking', 'commenting', 'highlighting')"
1906
- }
1907
- ],
1908
- "responses": {
1909
- "200": {
1910
- "description": "Resources that reference this resource",
1911
- "content": {
1912
- "application/json": {
1496
+ },
1497
+ "text/plain": {
1913
1498
  "schema": {
1914
- "$ref": "#/components/schemas/GetReferencedByResponse"
1499
+ "type": "string"
1915
1500
  }
1916
- }
1917
- }
1918
- }
1919
- }
1920
- }
1921
- },
1922
- "/api/clone-tokens/{token}": {
1923
- "get": {
1924
- "summary": "Get Resource by Clone Token",
1925
- "description": "Retrieve a resource using a clone token",
1926
- "tags": [
1927
- "Resources"
1928
- ],
1929
- "security": [
1930
- {
1931
- "bearerAuth": []
1932
- }
1933
- ],
1934
- "parameters": [
1935
- {
1936
- "schema": {
1937
- "type": "string"
1938
- },
1939
- "required": true,
1940
- "name": "token",
1941
- "in": "path"
1942
- }
1943
- ],
1944
- "responses": {
1945
- "200": {
1946
- "description": "Resource retrieved successfully",
1947
- "content": {
1948
- "application/json": {
1501
+ },
1502
+ "text/markdown": {
1949
1503
  "schema": {
1950
- "$ref": "#/components/schemas/GetResourceByTokenResponse"
1504
+ "type": "string"
1505
+ }
1506
+ },
1507
+ "text/html": {
1508
+ "schema": {
1509
+ "type": "string"
1510
+ }
1511
+ },
1512
+ "image/*": {
1513
+ "schema": {
1514
+ "type": "string",
1515
+ "format": "binary"
1516
+ }
1517
+ },
1518
+ "application/pdf": {
1519
+ "schema": {
1520
+ "type": "string",
1521
+ "format": "binary"
1951
1522
  }
1952
1523
  }
1953
1524
  }
1954
- }
1955
- }
1956
- }
1957
- },
1958
- "/api/clone-tokens/create-resource": {
1959
- "post": {
1960
- "summary": "Create Resource from Clone Token",
1961
- "description": "Create a new resource using a clone token",
1962
- "tags": [
1963
- "Resources"
1964
- ],
1965
- "security": [
1966
- {
1967
- "bearerAuth": []
1968
- }
1969
- ],
1970
- "requestBody": {
1971
- "content": {
1972
- "application/json": {
1973
- "schema": {
1974
- "$ref": "#/components/schemas/CreateResourceFromTokenRequest"
1975
- }
1976
- }
1977
- }
1978
- },
1979
- "responses": {
1980
- "202": {
1981
- "description": "Resource creation accepted",
1525
+ },
1526
+ "404": {
1527
+ "description": "Resource not found",
1982
1528
  "content": {
1983
1529
  "application/json": {
1984
1530
  "schema": {
1985
- "type": "object",
1986
- "properties": {
1987
- "resourceId": {
1988
- "type": "string"
1989
- }
1990
- },
1991
- "required": [
1992
- "resourceId"
1993
- ]
1531
+ "$ref": "#/components/schemas/ErrorResponse"
1994
1532
  }
1995
1533
  }
1996
1534
  }
1997
- }
1998
- }
1999
- }
2000
- },
2001
- "/resources/{id}/clone-with-token": {
2002
- "post": {
2003
- "summary": "Clone Resource with Token",
2004
- "description": "Generate a temporary token for cloning a resource",
2005
- "tags": [
2006
- "Resources"
2007
- ],
2008
- "security": [
2009
- {
2010
- "bearerAuth": []
2011
- }
2012
- ],
2013
- "parameters": [
2014
- {
2015
- "schema": {
2016
- "type": "string"
2017
- },
2018
- "required": true,
2019
- "name": "id",
2020
- "in": "path"
2021
- }
2022
- ],
2023
- "responses": {
2024
- "200": {
2025
- "description": "Clone token generated successfully",
1535
+ },
1536
+ "500": {
1537
+ "description": "Failed to retrieve resource",
2026
1538
  "content": {
2027
1539
  "application/json": {
2028
1540
  "schema": {
2029
- "$ref": "#/components/schemas/CloneResourceWithTokenResponse"
1541
+ "$ref": "#/components/schemas/ErrorResponse"
2030
1542
  }
2031
1543
  }
2032
1544
  }
2033
- }
2034
- }
2035
- }
2036
- },
2037
- "/resources/{id}/annotations": {
2038
- "get": {
2039
- "summary": "Get Resource Annotations",
2040
- "description": "Get all annotations (both highlights and references) in a resource",
2041
- "tags": [
2042
- "Resources",
2043
- "Annotations"
2044
- ],
2045
- "security": [
2046
- {
2047
- "bearerAuth": []
2048
- }
2049
- ],
2050
- "parameters": [
2051
- {
2052
- "schema": {
2053
- "type": "string"
2054
- },
2055
- "required": true,
2056
- "name": "id",
2057
- "in": "path"
2058
- }
2059
- ],
2060
- "responses": {
2061
- "200": {
2062
- "description": "Resource annotations",
1545
+ },
1546
+ "504": {
1547
+ "description": "Request timed out (bus gateway)",
2063
1548
  "content": {
2064
1549
  "application/json": {
2065
1550
  "schema": {
2066
- "$ref": "#/components/schemas/CreateResourceResponse"
1551
+ "$ref": "#/components/schemas/ErrorResponse"
2067
1552
  }
2068
1553
  }
2069
1554
  }
2070
1555
  }
2071
1556
  }
2072
1557
  },
2073
- "post": {
2074
- "summary": "Create Annotation",
2075
- "description": "Create a new annotation/reference in a resource",
1558
+ "patch": {
1559
+ "summary": "Update resource metadata",
1560
+ "description": "Archive/unarchive or update entity types. Emits mark:archive / mark:unarchive / mark:update-entity-types on the bus; returns 202 immediately. Frontend reconciles state via SSE domain events.",
2076
1561
  "tags": [
2077
- "Resources",
2078
- "Annotations"
1562
+ "Resources"
2079
1563
  ],
2080
1564
  "security": [
2081
1565
  {
@@ -2084,117 +1568,44 @@
2084
1568
  ],
2085
1569
  "parameters": [
2086
1570
  {
2087
- "schema": {
2088
- "type": "string"
2089
- },
2090
- "required": true,
2091
1571
  "name": "id",
2092
1572
  "in": "path",
2093
- "description": "Resource ID"
1573
+ "required": true,
1574
+ "schema": {
1575
+ "type": "string"
1576
+ }
2094
1577
  }
2095
1578
  ],
2096
1579
  "requestBody": {
1580
+ "required": true,
2097
1581
  "content": {
2098
1582
  "application/json": {
2099
1583
  "schema": {
2100
- "$ref": "#/components/schemas/CreateAnnotationRequest"
1584
+ "$ref": "#/components/schemas/UpdateResourceRequest"
2101
1585
  }
2102
1586
  }
2103
1587
  }
2104
1588
  },
2105
1589
  "responses": {
2106
1590
  "202": {
2107
- "description": "Annotation creation accepted",
1591
+ "description": "Update accepted"
1592
+ },
1593
+ "401": {
1594
+ "description": "Authentication required",
2108
1595
  "content": {
2109
1596
  "application/json": {
2110
1597
  "schema": {
2111
- "type": "object",
2112
- "properties": {
2113
- "annotationId": {
2114
- "type": "string"
2115
- }
2116
- },
2117
- "required": [
2118
- "annotationId"
2119
- ]
1598
+ "$ref": "#/components/schemas/ErrorResponse"
2120
1599
  }
2121
1600
  }
2122
1601
  }
2123
- }
2124
- }
2125
- }
2126
- },
2127
- "/resources/{id}/events": {
2128
- "get": {
2129
- "summary": "Get Resource Event History",
2130
- "description": "Get full event history for a resource with optional filtering",
2131
- "tags": [
2132
- "Resources",
2133
- "Events"
2134
- ],
2135
- "security": [
2136
- {
2137
- "bearerAuth": []
2138
- }
2139
- ],
2140
- "parameters": [
2141
- {
2142
- "schema": {
2143
- "type": "string"
2144
- },
2145
- "required": true,
2146
- "name": "id",
2147
- "in": "path"
2148
- },
2149
- {
2150
- "schema": {
2151
- "type": "string",
2152
- "enum": [
2153
- "resource.created",
2154
- "resource.cloned",
2155
- "resource.updated",
2156
- "resource.moved",
2157
- "resource.archived",
2158
- "resource.unarchived",
2159
- "annotation.added",
2160
- "annotation.removed",
2161
- "annotation.body.updated",
2162
- "entitytag.added",
2163
- "entitytag.removed",
2164
- "entitytype.added"
2165
- ]
2166
- },
2167
- "required": false,
2168
- "name": "type",
2169
- "in": "query"
2170
- },
2171
- {
2172
- "schema": {
2173
- "type": "string"
2174
- },
2175
- "required": false,
2176
- "name": "userId",
2177
- "in": "query"
2178
1602
  },
2179
- {
2180
- "schema": {
2181
- "type": "number",
2182
- "minimum": 1,
2183
- "maximum": 1000,
2184
- "default": 100
2185
- },
2186
- "required": false,
2187
- "name": "limit",
2188
- "in": "query"
2189
- }
2190
- ],
2191
- "responses": {
2192
- "200": {
2193
- "description": "Events retrieved successfully",
1603
+ "404": {
1604
+ "description": "Resource not found",
2194
1605
  "content": {
2195
1606
  "application/json": {
2196
1607
  "schema": {
2197
- "$ref": "#/components/schemas/GetEventsResponse"
1608
+ "$ref": "#/components/schemas/ErrorResponse"
2198
1609
  }
2199
1610
  }
2200
1611
  }
@@ -2202,14 +1613,12 @@
2202
1613
  }
2203
1614
  }
2204
1615
  },
2205
- "/resources/{id}/events/stream": {
1616
+ "/api/resources/{id}": {
2206
1617
  "get": {
2207
- "summary": "Subscribe to Resource Events (SSE)",
2208
- "description": "Open a Server-Sent Events stream to receive real-time resource events",
1618
+ "summary": "Get raw resource content (browser-friendly alias)",
1619
+ "description": "Browser-friendly alternative to GET /resources/{id} that always returns the raw representation, never JSON-LD. Used by `<img>` / PDF.js / `<video>` tags and anywhere an httpOnly cookie is the only feasible auth vector. Behaves like GET /resources/{id} with JSON-LD stripped from the Accept header before content negotiation.\n\nSets long-lived immutable Cache-Control (content is addressed by checksum upstream, so bytes never change for a given resource id).",
2209
1620
  "tags": [
2210
- "Resources",
2211
- "Events",
2212
- "Real-time"
1621
+ "Resources"
2213
1622
  ],
2214
1623
  "security": [
2215
1624
  {
@@ -2218,583 +1627,49 @@
2218
1627
  ],
2219
1628
  "parameters": [
2220
1629
  {
1630
+ "name": "id",
1631
+ "in": "path",
1632
+ "required": true,
2221
1633
  "schema": {
2222
1634
  "type": "string"
2223
- },
2224
- "required": true,
2225
- "name": "id",
2226
- "in": "path"
1635
+ }
2227
1636
  }
2228
1637
  ],
2229
1638
  "responses": {
2230
1639
  "200": {
2231
- "description": "SSE stream opened successfully",
1640
+ "description": "Raw representation bytes with appropriate Content-Type",
2232
1641
  "content": {
2233
- "text/event-stream": {
1642
+ "text/plain": {
2234
1643
  "schema": {
2235
- "$ref": "#/components/schemas/EventStreamResponse"
1644
+ "type": "string"
2236
1645
  }
2237
- }
2238
- }
2239
- }
2240
- }
2241
- }
2242
- },
2243
- "/resources/{resourceId}/annotations/{annotationId}": {
2244
- "get": {
2245
- "summary": "Get Annotation",
2246
- "description": "Get a specific annotation from a resource using nested path",
2247
- "tags": [
2248
- "Resources",
2249
- "Annotations"
2250
- ],
2251
- "security": [
2252
- {
2253
- "bearerAuth": []
2254
- }
2255
- ],
2256
- "parameters": [
2257
- {
2258
- "schema": {
2259
- "type": "string"
2260
- },
2261
- "required": true,
2262
- "name": "resourceId",
2263
- "in": "path",
2264
- "description": "Resource ID"
2265
- },
2266
- {
2267
- "schema": {
2268
- "type": "string"
2269
- },
2270
- "required": true,
2271
- "name": "annotationId",
2272
- "in": "path",
2273
- "description": "Annotation ID"
2274
- }
2275
- ],
2276
- "responses": {
2277
- "200": {
2278
- "description": "Annotation retrieved successfully",
2279
- "content": {
2280
- "application/json": {
2281
- "schema": {
2282
- "$ref": "#/components/schemas/GetAnnotationResponse"
2283
- }
2284
- }
2285
- }
2286
- },
2287
- "404": {
2288
- "description": "Annotation not found"
2289
- }
2290
- }
2291
- },
2292
- "delete": {
2293
- "summary": "Delete Annotation",
2294
- "description": "Delete an annotation from a resource",
2295
- "tags": [
2296
- "Resources",
2297
- "Annotations"
2298
- ],
2299
- "security": [
2300
- {
2301
- "bearerAuth": []
2302
- }
2303
- ],
2304
- "parameters": [
2305
- {
2306
- "schema": {
2307
- "type": "string"
2308
- },
2309
- "required": true,
2310
- "name": "resourceId",
2311
- "in": "path",
2312
- "description": "Resource ID"
2313
- },
2314
- {
2315
- "schema": {
2316
- "type": "string"
2317
- },
2318
- "required": true,
2319
- "name": "annotationId",
2320
- "in": "path",
2321
- "description": "Annotation ID"
2322
- }
2323
- ],
2324
- "responses": {
2325
- "202": {
2326
- "description": "Annotation deletion accepted"
2327
- }
2328
- }
2329
- }
2330
- },
2331
- "/resources/{resourceId}/annotations/{annotationId}/body": {
2332
- "put": {
2333
- "summary": "Update Annotation Body",
2334
- "description": "Apply fine-grained operations to modify annotation body items (add, remove, or replace TextualBody and SpecificResource items)",
2335
- "tags": [
2336
- "Resources",
2337
- "Annotations"
2338
- ],
2339
- "security": [
2340
- {
2341
- "bearerAuth": []
2342
- }
2343
- ],
2344
- "parameters": [
2345
- {
2346
- "schema": {
2347
- "type": "string"
2348
- },
2349
- "required": true,
2350
- "name": "resourceId",
2351
- "in": "path",
2352
- "description": "Resource ID"
2353
- },
2354
- {
2355
- "schema": {
2356
- "type": "string"
2357
- },
2358
- "required": true,
2359
- "name": "annotationId",
2360
- "in": "path",
2361
- "description": "Annotation ID"
2362
- }
2363
- ],
2364
- "requestBody": {
2365
- "content": {
2366
- "application/json": {
2367
- "schema": {
2368
- "$ref": "#/components/schemas/UpdateAnnotationBodyRequest"
2369
- }
2370
- }
2371
- }
2372
- },
2373
- "responses": {
2374
- "202": {
2375
- "description": "Annotation body update accepted"
2376
- }
2377
- }
2378
- }
2379
- },
2380
- "/resources/{resourceId}/annotations/{annotationId}/yield-resource": {
2381
- "post": {
2382
- "summary": "Generate Resource from Annotation",
2383
- "description": "Submit a resource generation command. Returns {correlationId, jobId} immediately. The generation worker processes the job asynchronously and delivers progress (yield:progress) and completion (yield:finished) or failure (yield:failed) via the events-stream to all connected clients.",
2384
- "tags": [
2385
- "Resources",
2386
- "Annotations",
2387
- "AI"
2388
- ],
2389
- "security": [
2390
- {
2391
- "bearerAuth": []
2392
- }
2393
- ],
2394
- "parameters": [
2395
- {
2396
- "schema": {
2397
- "type": "string"
2398
- },
2399
- "required": true,
2400
- "name": "resourceId",
2401
- "in": "path",
2402
- "description": "Source resource ID"
2403
- },
2404
- {
2405
- "schema": {
2406
- "type": "string"
2407
- },
2408
- "required": true,
2409
- "name": "annotationId",
2410
- "in": "path",
2411
- "description": "Reference annotation ID"
2412
- }
2413
- ],
2414
- "requestBody": {
2415
- "required": true,
2416
- "content": {
2417
- "application/json": {
2418
- "schema": {
2419
- "$ref": "#/components/schemas/YieldResourceStreamRequest"
2420
- }
2421
- }
2422
- }
2423
- },
2424
- "responses": {
2425
- "202": {
2426
- "description": "Generation command accepted. Progress and results delivered via events-stream.",
2427
- "content": {
2428
- "application/json": {
2429
- "schema": {
2430
- "type": "object",
2431
- "properties": {
2432
- "correlationId": {
2433
- "type": "string"
2434
- },
2435
- "jobId": {
2436
- "type": "string"
2437
- }
2438
- },
2439
- "required": [
2440
- "correlationId",
2441
- "jobId"
2442
- ]
2443
- }
2444
- }
2445
- }
2446
- },
2447
- "400": {
2448
- "description": "Context is required for generation"
2449
- },
2450
- "401": {
2451
- "description": "Authentication required"
2452
- },
2453
- "404": {
2454
- "description": "Annotation not found"
2455
- }
2456
- }
2457
- }
2458
- },
2459
- "/resources/{resourceId}/annotations/{annotationId}/history": {
2460
- "get": {
2461
- "summary": "Get Annotation History",
2462
- "description": "Get full event history for a specific annotation (highlight or reference)",
2463
- "tags": [
2464
- "Selections",
2465
- "Events"
2466
- ],
2467
- "security": [
2468
- {
2469
- "bearerAuth": []
2470
- }
2471
- ],
2472
- "parameters": [
2473
- {
2474
- "schema": {
2475
- "type": "string"
2476
- },
2477
- "required": true,
2478
- "name": "resourceId",
2479
- "in": "path"
2480
- },
2481
- {
2482
- "schema": {
2483
- "type": "string"
2484
- },
2485
- "required": true,
2486
- "name": "annotationId",
2487
- "in": "path"
2488
- }
2489
- ],
2490
- "responses": {
2491
- "200": {
2492
- "description": "Annotation history retrieved successfully",
2493
- "content": {
2494
- "application/json": {
2495
- "schema": {
2496
- "$ref": "#/components/schemas/GetAnnotationHistoryResponse"
2497
- }
2498
- }
2499
- }
2500
- },
2501
- "404": {
2502
- "description": "Annotation not found"
2503
- }
2504
- }
2505
- }
2506
- },
2507
- "/api/entity-types": {
2508
- "get": {
2509
- "summary": "Get Entity Types",
2510
- "description": "Get list of available entity types for references",
2511
- "tags": [
2512
- "Selections"
2513
- ],
2514
- "security": [
2515
- {
2516
- "bearerAuth": []
2517
- }
2518
- ],
2519
- "responses": {
2520
- "200": {
2521
- "description": "Entity types retrieved successfully",
2522
- "content": {
2523
- "application/json": {
2524
- "schema": {
2525
- "$ref": "#/components/schemas/GetEntityTypesResponse"
2526
- }
2527
- }
2528
- }
2529
- }
2530
- }
2531
- },
2532
- "post": {
2533
- "summary": "Add Entity Type",
2534
- "description": "Add a new entity type to the collection (append-only, requires moderator/admin)",
2535
- "tags": [
2536
- "Selections"
2537
- ],
2538
- "security": [
2539
- {
2540
- "bearerAuth": []
2541
- }
2542
- ],
2543
- "requestBody": {
2544
- "content": {
2545
- "application/json": {
2546
- "schema": {
2547
- "$ref": "#/components/schemas/AddEntityTypeRequest"
2548
- }
2549
- }
2550
- }
2551
- },
2552
- "responses": {
2553
- "202": {
2554
- "description": "Entity type addition accepted"
2555
- },
2556
- "403": {
2557
- "description": "Forbidden - Moderator or Admin access required",
2558
- "content": {
2559
- "application/json": {
2560
- "schema": {
2561
- "$ref": "#/components/schemas/ErrorResponse"
2562
- }
2563
- }
2564
- }
2565
- }
2566
- }
2567
- }
2568
- },
2569
- "/api/entity-types/bulk": {
2570
- "post": {
2571
- "summary": "Bulk Add Entity Types",
2572
- "description": "Add multiple entity types to the collection (append-only, requires moderator/admin)",
2573
- "tags": [
2574
- "Selections"
2575
- ],
2576
- "security": [
2577
- {
2578
- "bearerAuth": []
2579
- }
2580
- ],
2581
- "requestBody": {
2582
- "content": {
2583
- "application/json": {
2584
- "schema": {
2585
- "$ref": "#/components/schemas/BulkAddEntityTypesRequest"
2586
- }
2587
- }
2588
- }
2589
- },
2590
- "responses": {
2591
- "202": {
2592
- "description": "Entity types addition accepted"
2593
- },
2594
- "403": {
2595
- "description": "Forbidden - Moderator or Admin access required",
2596
- "content": {
2597
- "application/json": {
2598
- "schema": {
2599
- "$ref": "#/components/schemas/ErrorResponse"
2600
- }
2601
- }
2602
- }
2603
- }
2604
- }
2605
- }
2606
- },
2607
- "/api/events/stream": {
2608
- "get": {
2609
- "summary": "Subscribe to Global Events (SSE)",
2610
- "description": "Open a Server-Sent Events stream to receive real-time system-level events (e.g., entity type changes). Events not scoped to a specific resource are delivered on this channel.",
2611
- "tags": [
2612
- "Events",
2613
- "Real-time"
2614
- ],
2615
- "security": [
2616
- {
2617
- "bearerAuth": []
2618
- }
2619
- ],
2620
- "responses": {
2621
- "200": {
2622
- "description": "SSE stream opened successfully",
2623
- "content": {
2624
- "text/event-stream": {
2625
- "schema": {
2626
- "$ref": "#/components/schemas/EventStreamResponse"
2627
- }
2628
- }
2629
- }
2630
- }
2631
- }
2632
- }
2633
- },
2634
- "/api/jobs/{id}": {
2635
- "get": {
2636
- "summary": "Get Job Status",
2637
- "description": "Get the current status and progress of an async job",
2638
- "tags": [
2639
- "Jobs"
2640
- ],
2641
- "security": [
2642
- {
2643
- "bearerAuth": []
2644
- }
2645
- ],
2646
- "parameters": [
2647
- {
2648
- "schema": {
2649
- "type": "string"
2650
- },
2651
- "required": true,
2652
- "name": "id",
2653
- "in": "path"
2654
- }
2655
- ],
2656
- "responses": {
2657
- "200": {
2658
- "description": "Job status retrieved successfully",
2659
- "content": {
2660
- "application/json": {
2661
- "schema": {
2662
- "$ref": "#/components/schemas/JobStatusResponse"
2663
- }
2664
- }
2665
- }
2666
- },
2667
- "404": {
2668
- "description": "Job not found"
2669
- }
2670
- }
2671
- }
2672
- },
2673
- "/api/participants/{id}/attention": {
2674
- "post": {
2675
- "summary": "Beckon Participant",
2676
- "description": "Direct a participant's attention to a resource or annotation. Produces no persistent annotations — attention signal only. The participant may be a human username or an agent identifier.",
2677
- "tags": [
2678
- "Participants"
2679
- ],
2680
- "security": [
2681
- {
2682
- "bearerAuth": []
2683
- }
2684
- ],
2685
- "parameters": [
2686
- {
2687
- "schema": {
2688
- "type": "string"
2689
- },
2690
- "required": true,
2691
- "name": "id",
2692
- "in": "path",
2693
- "description": "Participant username or agent identifier"
2694
- }
2695
- ],
2696
- "requestBody": {
2697
- "required": true,
2698
- "content": {
2699
- "application/json": {
2700
- "schema": {
2701
- "$ref": "#/components/schemas/BeckonRequest"
2702
- }
2703
- }
2704
- }
2705
- },
2706
- "responses": {
2707
- "202": {
2708
- "description": "Attention signal accepted",
2709
- "content": {
2710
- "application/json": {
1646
+ },
1647
+ "text/markdown": {
2711
1648
  "schema": {
2712
- "$ref": "#/components/schemas/BeckonResponse"
1649
+ "type": "string"
2713
1650
  }
2714
- }
2715
- }
2716
- }
2717
- }
2718
- }
2719
- },
2720
- "/api/participants/me/attention-stream": {
2721
- "get": {
2722
- "summary": "Participant Attention Stream",
2723
- "description": "Open a persistent SSE connection to receive beckon signals directed at the authenticated participant. Signals are ephemeral — delivered if connected, dropped if not. No queue, no replay.",
2724
- "tags": [
2725
- "Participants"
2726
- ],
2727
- "security": [
2728
- {
2729
- "bearerAuth": []
2730
- }
2731
- ],
2732
- "responses": {
2733
- "200": {
2734
- "description": "SSE stream of beckon:focus events",
2735
- "content": {
2736
- "text/event-stream": {
1651
+ },
1652
+ "text/html": {
2737
1653
  "schema": {
2738
1654
  "type": "string"
2739
1655
  }
2740
- }
2741
- }
2742
- }
2743
- }
2744
- }
2745
- },
2746
- "/api/browse/files": {
2747
- "get": {
2748
- "summary": "Browse project directory",
2749
- "description": "List files and directories in a project directory, merged with Knowledge Base metadata for tracked resources.",
2750
- "tags": [
2751
- "Browse"
2752
- ],
2753
- "security": [
2754
- {
2755
- "bearerAuth": []
2756
- }
2757
- ],
2758
- "parameters": [
2759
- {
2760
- "name": "path",
2761
- "in": "query",
2762
- "required": false,
2763
- "schema": {
2764
- "type": "string",
2765
- "default": ""
2766
- },
2767
- "description": "Directory path relative to project root. Empty string or omit for project root."
2768
- },
2769
- {
2770
- "name": "sort",
2771
- "in": "query",
2772
- "required": false,
2773
- "schema": {
2774
- "type": "string",
2775
- "enum": [
2776
- "name",
2777
- "mtime",
2778
- "annotationCount"
2779
- ],
2780
- "default": "name"
2781
- },
2782
- "description": "Sort order for directory entries."
2783
- }
2784
- ],
2785
- "responses": {
2786
- "200": {
2787
- "description": "Directory listing with KB metadata merged",
2788
- "content": {
2789
- "application/json": {
1656
+ },
1657
+ "image/*": {
1658
+ "schema": {
1659
+ "type": "string",
1660
+ "format": "binary"
1661
+ }
1662
+ },
1663
+ "application/pdf": {
2790
1664
  "schema": {
2791
- "$ref": "#/components/schemas/BrowseFilesResponse"
1665
+ "type": "string",
1666
+ "format": "binary"
2792
1667
  }
2793
1668
  }
2794
1669
  }
2795
1670
  },
2796
- "400": {
2797
- "description": "Invalid path (e.g. path escapes project root)",
1671
+ "404": {
1672
+ "description": "Resource or representation not found",
2798
1673
  "content": {
2799
1674
  "application/json": {
2800
1675
  "schema": {
@@ -2803,8 +1678,8 @@
2803
1678
  }
2804
1679
  }
2805
1680
  },
2806
- "404": {
2807
- "description": "Directory not found",
1681
+ "500": {
1682
+ "description": "Failed to retrieve resource",
2808
1683
  "content": {
2809
1684
  "application/json": {
2810
1685
  "schema": {
@@ -2834,19 +1709,6 @@
2834
1709
  "message"
2835
1710
  ]
2836
1711
  },
2837
- "AddEntityTypeRequest": {
2838
- "type": "object",
2839
- "properties": {
2840
- "tag": {
2841
- "type": "string",
2842
- "minLength": 1,
2843
- "maxLength": 100
2844
- }
2845
- },
2846
- "required": [
2847
- "tag"
2848
- ]
2849
- },
2850
1712
  "AdminUpdateUserResponse": {
2851
1713
  "type": "object",
2852
1714
  "properties": {
@@ -3148,14 +2010,6 @@
3148
2010
  },
3149
2011
  "body": {
3150
2012
  "oneOf": [
3151
- {
3152
- "type": "array",
3153
- "items": {
3154
- "$ref": "#/components/schemas/AnnotationBody"
3155
- },
3156
- "maxItems": 0,
3157
- "description": "Empty array for stub references (Phase 1 pattern)"
3158
- },
3159
2013
  {
3160
2014
  "$ref": "#/components/schemas/AnnotationBody",
3161
2015
  "description": "Single body (TextualBody or SpecificResource)"
@@ -3165,10 +2019,11 @@
3165
2019
  "items": {
3166
2020
  "$ref": "#/components/schemas/AnnotationBody"
3167
2021
  },
3168
- "description": "Array of mixed TextualBody (tagging) and SpecificResource (linking) bodies"
2022
+ "minItems": 1,
2023
+ "description": "Non-empty array of mixed TextualBody (tagging) and SpecificResource (linking) bodies"
3169
2024
  }
3170
2025
  ],
3171
- "description": "W3C Web Annotation body - can be empty array, single body, or array of bodies"
2026
+ "description": "W3C Web Annotation body. Optional per the W3C spec — annotations whose motivation alone is meaningful (highlighting) legitimately omit it. Present values are either a single body or a non-empty array of bodies; the prior empty-array 'stub' branch has been removed (it was a naming lie shared between highlights and never-actually-emitted stub references, and the source of the #651 reference-annotation validator bug)."
3172
2027
  },
3173
2028
  "creator": {
3174
2029
  "$ref": "#/components/schemas/Agent"
@@ -3188,8 +2043,7 @@
3188
2043
  "type",
3189
2044
  "id",
3190
2045
  "motivation",
3191
- "target",
3192
- "body"
2046
+ "target"
3193
2047
  ]
3194
2048
  },
3195
2049
  "AnnotationBody": {
@@ -3369,40 +2223,6 @@
3369
2223
  ],
3370
2224
  "description": "W3C Web Annotation target object - source is required, selector is optional"
3371
2225
  },
3372
- "AsyncJobResponse": {
3373
- "type": "object",
3374
- "properties": {
3375
- "jobId": {
3376
- "type": "string"
3377
- },
3378
- "status": {
3379
- "type": "string",
3380
- "enum": [
3381
- "pending",
3382
- "running",
3383
- "complete",
3384
- "failed",
3385
- "cancelled"
3386
- ]
3387
- },
3388
- "type": {
3389
- "type": "string",
3390
- "enum": [
3391
- "reference-annotation",
3392
- "generation"
3393
- ]
3394
- },
3395
- "created": {
3396
- "type": "string"
3397
- }
3398
- },
3399
- "required": [
3400
- "jobId",
3401
- "status",
3402
- "type",
3403
- "created"
3404
- ]
3405
- },
3406
2226
  "AuthResponse": {
3407
2227
  "type": "object",
3408
2228
  "properties": {
@@ -3482,6 +2302,148 @@
3482
2302
  },
3483
2303
  "additionalProperties": false
3484
2304
  },
2305
+ "BusEmitRequest": {
2306
+ "type": "object",
2307
+ "description": "Emit an event on the Semiont bus. Channel names come from bus-protocol.ts; payload shape is validated against the channel's registered schema (CHANNEL_SCHEMAS). An optional scope routes resource-scoped broadcasts (e.g. mark:added, job:complete) to per-resource subscribers via eventBus.scope(scope); leave it unset for unscoped/global events.",
2308
+ "properties": {
2309
+ "channel": {
2310
+ "type": "string",
2311
+ "description": "Channel name from bus-protocol.ts EventMap"
2312
+ },
2313
+ "payload": {
2314
+ "type": "object",
2315
+ "description": "Channel-specific payload, validated against CHANNEL_SCHEMAS",
2316
+ "additionalProperties": true
2317
+ },
2318
+ "scope": {
2319
+ "type": "string",
2320
+ "description": "Optional resource scope for broadcast channels (e.g. resourceId). Publishers only — frontends must never set this.",
2321
+ "minLength": 1
2322
+ }
2323
+ },
2324
+ "required": [
2325
+ "channel",
2326
+ "payload"
2327
+ ]
2328
+ },
2329
+ "CookieConsent": {
2330
+ "type": "object",
2331
+ "description": "User's cookie consent preferences. `necessary` is always true — necessary cookies cannot be disabled. Timestamps and version are stamped server-side.",
2332
+ "properties": {
2333
+ "necessary": {
2334
+ "type": "boolean",
2335
+ "enum": [
2336
+ true
2337
+ ]
2338
+ },
2339
+ "analytics": {
2340
+ "type": "boolean"
2341
+ },
2342
+ "marketing": {
2343
+ "type": "boolean"
2344
+ },
2345
+ "preferences": {
2346
+ "type": "boolean"
2347
+ },
2348
+ "timestamp": {
2349
+ "type": "string",
2350
+ "format": "date-time"
2351
+ },
2352
+ "version": {
2353
+ "type": "string"
2354
+ }
2355
+ },
2356
+ "required": [
2357
+ "necessary",
2358
+ "analytics",
2359
+ "marketing",
2360
+ "preferences",
2361
+ "timestamp",
2362
+ "version"
2363
+ ]
2364
+ },
2365
+ "CookieConsentRequest": {
2366
+ "type": "object",
2367
+ "description": "Request body for POST /api/cookies/consent. All four preference fields must be booleans; `necessary` must be true.",
2368
+ "properties": {
2369
+ "necessary": {
2370
+ "type": "boolean",
2371
+ "enum": [
2372
+ true
2373
+ ]
2374
+ },
2375
+ "analytics": {
2376
+ "type": "boolean"
2377
+ },
2378
+ "marketing": {
2379
+ "type": "boolean"
2380
+ },
2381
+ "preferences": {
2382
+ "type": "boolean"
2383
+ }
2384
+ },
2385
+ "required": [
2386
+ "necessary",
2387
+ "analytics",
2388
+ "marketing",
2389
+ "preferences"
2390
+ ]
2391
+ },
2392
+ "CookieConsentResponse": {
2393
+ "type": "object",
2394
+ "description": "Standard envelope for cookie consent endpoints. On success `success: true` and `consent` carries the current preferences; on error `success: false` and `error` carries a human-readable message.",
2395
+ "properties": {
2396
+ "success": {
2397
+ "type": "boolean"
2398
+ },
2399
+ "consent": {
2400
+ "$ref": "#/components/schemas/CookieConsent"
2401
+ },
2402
+ "error": {
2403
+ "type": "string"
2404
+ }
2405
+ },
2406
+ "required": [
2407
+ "success"
2408
+ ]
2409
+ },
2410
+ "CookieExportResponse": {
2411
+ "type": "object",
2412
+ "description": "GDPR data export of a user's cookie-related data. The response is returned as a file download (Content-Disposition: attachment).",
2413
+ "properties": {
2414
+ "user": {
2415
+ "type": "object",
2416
+ "properties": {
2417
+ "id": {
2418
+ "type": "string"
2419
+ },
2420
+ "email": {
2421
+ "type": "string"
2422
+ }
2423
+ },
2424
+ "required": [
2425
+ "id",
2426
+ "email"
2427
+ ]
2428
+ },
2429
+ "consent": {
2430
+ "$ref": "#/components/schemas/CookieConsent"
2431
+ },
2432
+ "exportDate": {
2433
+ "type": "string",
2434
+ "format": "date-time"
2435
+ },
2436
+ "dataRetentionPolicy": {
2437
+ "type": "string"
2438
+ }
2439
+ },
2440
+ "required": [
2441
+ "user",
2442
+ "consent",
2443
+ "exportDate",
2444
+ "dataRetentionPolicy"
2445
+ ]
2446
+ },
3485
2447
  "DirectoryEntry": {
3486
2448
  "oneOf": [
3487
2449
  {
@@ -3669,70 +2631,25 @@
3669
2631
  "newItem"
3670
2632
  ]
3671
2633
  },
3672
- "BodyType": {
3673
- "type": "string",
3674
- "enum": [
3675
- "TextualBody",
3676
- "SpecificResource"
3677
- ],
3678
- "description": "Annotation body type - TextualBody for textual content, SpecificResource for resource links"
3679
- },
3680
- "BeckonRequest": {
3681
- "type": "object",
3682
- "properties": {
3683
- "resourceId": {
3684
- "type": "string",
3685
- "description": "Resource to direct attention at"
3686
- },
3687
- "annotationId": {
3688
- "type": "string",
3689
- "description": "Specific annotation within the resource (optional)"
3690
- },
3691
- "message": {
3692
- "type": "string",
3693
- "description": "Human-readable context for the participant (max 500 chars)",
3694
- "maxLength": 500
3695
- }
3696
- },
3697
- "required": [
3698
- "resourceId"
3699
- ]
3700
- },
3701
2634
  "BeckonResponse": {
3702
2635
  "type": "object",
3703
2636
  "properties": {
3704
2637
  "participant": {
3705
2638
  "type": "string",
3706
- "description": "Username or agent identifier that was beckoned"
3707
- },
3708
- "resourceId": {
3709
- "type": "string",
3710
- "description": "Resource the attention was directed at"
3711
- },
3712
- "annotationId": {
3713
- "type": "string",
3714
- "description": "Annotation the attention was directed at (if provided)"
3715
- }
3716
- },
3717
- "required": [
3718
- "participant",
3719
- "resourceId"
3720
- ]
3721
- },
3722
- "BulkAddEntityTypesRequest": {
3723
- "type": "object",
3724
- "properties": {
3725
- "tags": {
3726
- "type": "array",
3727
- "items": {
3728
- "type": "string",
3729
- "minLength": 1,
3730
- "maxLength": 100
3731
- }
2639
+ "description": "Username or agent identifier that was beckoned"
2640
+ },
2641
+ "resourceId": {
2642
+ "type": "string",
2643
+ "description": "Resource the attention was directed at"
2644
+ },
2645
+ "annotationId": {
2646
+ "type": "string",
2647
+ "description": "Annotation the attention was directed at (if provided)"
3732
2648
  }
3733
2649
  },
3734
2650
  "required": [
3735
- "tags"
2651
+ "participant",
2652
+ "resourceId"
3736
2653
  ]
3737
2654
  },
3738
2655
  "CloneResourceWithTokenResponse": {
@@ -3760,6 +2677,10 @@
3760
2677
  "type": "object",
3761
2678
  "description": "Error response for failed bus commands. Replaces native Error objects on the EventBus so payloads are serializable and OpenAPI-typed.",
3762
2679
  "properties": {
2680
+ "correlationId": {
2681
+ "type": "string",
2682
+ "description": "Optional correlation id echoed from the originating command. When present, the failure event can be matched back to the specific command that failed."
2683
+ },
3763
2684
  "message": {
3764
2685
  "type": "string",
3765
2686
  "description": "Human-readable error message"
@@ -3871,310 +2792,72 @@
3871
2792
  "properties": {
3872
2793
  "type": {
3873
2794
  "type": "string",
3874
- "enum": [
3875
- "TextQuoteSelector"
3876
- ]
3877
- },
3878
- "exact": {
3879
- "type": "string"
3880
- },
3881
- "prefix": {
3882
- "type": "string"
3883
- },
3884
- "suffix": {
3885
- "type": "string"
3886
- }
3887
- },
3888
- "required": [
3889
- "type",
3890
- "exact"
3891
- ]
3892
- },
3893
- {
3894
- "$ref": "#/components/schemas/SvgSelector"
3895
- },
3896
- {
3897
- "$ref": "#/components/schemas/FragmentSelector"
3898
- }
3899
- ]
3900
- }
3901
- }
3902
- ]
3903
- }
3904
- },
3905
- "required": [
3906
- "source",
3907
- "selector"
3908
- ]
3909
- },
3910
- "body": {
3911
- "oneOf": [
3912
- {
3913
- "type": "array",
3914
- "maxItems": 0,
3915
- "description": "Empty array (Phase 1 stub pattern - will be migrated to contain entity tag bodies in Phase 2)"
3916
- },
3917
- {
3918
- "$ref": "#/components/schemas/AnnotationBody",
3919
- "description": "Single body (TextualBody or SpecificResource)"
3920
- },
3921
- {
3922
- "type": "array",
3923
- "items": {
3924
- "$ref": "#/components/schemas/AnnotationBody"
3925
- },
3926
- "minItems": 1,
3927
- "description": "Array of mixed TextualBody (tagging) and SpecificResource (linking) bodies"
3928
- }
3929
- ]
3930
- }
3931
- },
3932
- "required": [
3933
- "target",
3934
- "body",
3935
- "motivation"
3936
- ]
3937
- },
3938
- "CreateFromAnnotationRequest": {
3939
- "type": "object",
3940
- "properties": {
3941
- "resourceId": {
3942
- "type": "string",
3943
- "description": "ID of the resource containing the annotation"
3944
- },
3945
- "name": {
3946
- "type": "string"
3947
- },
3948
- "content": {
3949
- "type": "string"
3950
- },
3951
- "format": {
3952
- "$ref": "#/components/schemas/ContentFormat"
3953
- }
3954
- },
3955
- "required": [
3956
- "resourceId",
3957
- "name",
3958
- "content",
3959
- "format"
3960
- ]
3961
- },
3962
- "CreateFromAnnotationResponse": {
3963
- "type": "object",
3964
- "properties": {
3965
- "resource": {
3966
- "$ref": "#/components/schemas/ResourceDescriptor"
3967
- },
3968
- "annotations": {
3969
- "type": "array",
3970
- "items": {
3971
- "$ref": "#/components/schemas/Annotation"
3972
- }
3973
- }
3974
- },
3975
- "required": [
3976
- "resource",
3977
- "annotations"
3978
- ]
3979
- },
3980
- "CreateJobResponse": {
3981
- "type": "object",
3982
- "properties": {
3983
- "jobId": {
3984
- "type": "string"
3985
- },
3986
- "type": {
3987
- "type": "string",
3988
- "enum": [
3989
- "reference-annotation",
3990
- "generation"
3991
- ]
3992
- },
3993
- "status": {
3994
- "type": "string",
3995
- "enum": [
3996
- "pending",
3997
- "running",
3998
- "complete",
3999
- "failed",
4000
- "cancelled"
4001
- ]
4002
- },
4003
- "created": {
4004
- "type": "string"
4005
- },
4006
- "resourceId": {
4007
- "type": "string"
4008
- }
4009
- },
4010
- "required": [
4011
- "jobId",
4012
- "type",
4013
- "status",
4014
- "created"
4015
- ]
4016
- },
4017
- "CreateResourceFromAnnotationResponse": {
4018
- "type": "object",
4019
- "properties": {
4020
- "resource": {
4021
- "$ref": "#/components/schemas/ResourceDescriptor"
4022
- },
4023
- "annotation": {
4024
- "$ref": "#/components/schemas/Annotation"
4025
- }
4026
- },
4027
- "required": [
4028
- "resource",
4029
- "annotation"
4030
- ]
4031
- },
4032
- "CreateResourceFromSelectionRequest": {
4033
- "type": "object",
4034
- "properties": {
4035
- "resourceId": {
4036
- "type": "string",
4037
- "description": "ID of the resource containing the annotation"
4038
- },
4039
- "content": {
4040
- "type": "string"
4041
- },
4042
- "name": {
4043
- "type": "string"
4044
- },
4045
- "format": {
4046
- "$ref": "#/components/schemas/ContentFormat"
4047
- },
4048
- "entityTypes": {
4049
- "type": "array",
4050
- "items": {
4051
- "type": "string"
4052
- }
4053
- },
4054
- "metadata": {
4055
- "type": "object",
4056
- "additionalProperties": true
4057
- },
4058
- "prompt": {
4059
- "type": "string"
4060
- },
4061
- "language": {
4062
- "type": "string"
4063
- }
4064
- },
4065
- "required": [
4066
- "resourceId",
4067
- "content",
4068
- "name",
4069
- "format"
4070
- ]
4071
- },
4072
- "CreateResourceFromSelectionResponse": {
4073
- "type": "object",
4074
- "properties": {
4075
- "resource": {
4076
- "$ref": "#/components/schemas/ResourceDescriptor"
4077
- },
4078
- "annotation": {
4079
- "$ref": "#/components/schemas/Annotation"
4080
- }
4081
- },
4082
- "required": [
4083
- "resource",
4084
- "annotation"
4085
- ]
4086
- },
4087
- "CreateResourceFromTokenRequest": {
4088
- "type": "object",
4089
- "properties": {
4090
- "token": {
4091
- "type": "string",
4092
- "description": "Clone token"
4093
- },
4094
- "name": {
4095
- "type": "string",
4096
- "description": "Name for the new resource"
4097
- },
4098
- "content": {
4099
- "type": "string",
4100
- "description": "Content for the new resource"
4101
- },
4102
- "archiveOriginal": {
4103
- "type": "boolean",
4104
- "description": "Whether to archive the original resource"
4105
- }
4106
- },
4107
- "required": [
4108
- "token",
4109
- "name",
4110
- "content"
4111
- ]
4112
- },
4113
- "CreateResourceRequest": {
4114
- "type": "object",
4115
- "properties": {
4116
- "name": {
4117
- "type": "string",
4118
- "minLength": 1,
4119
- "maxLength": 500
4120
- },
4121
- "content": {
4122
- "type": "string"
4123
- },
4124
- "format": {
4125
- "$ref": "#/components/schemas/ContentFormat"
4126
- },
4127
- "entityTypes": {
4128
- "type": "array",
4129
- "items": {
4130
- "type": "string"
4131
- }
4132
- },
4133
- "language": {
4134
- "type": "string"
4135
- },
4136
- "creationMethod": {
4137
- "type": "string"
4138
- },
4139
- "sourceAnnotationId": {
4140
- "type": "string"
2795
+ "enum": [
2796
+ "TextQuoteSelector"
2797
+ ]
2798
+ },
2799
+ "exact": {
2800
+ "type": "string"
2801
+ },
2802
+ "prefix": {
2803
+ "type": "string"
2804
+ },
2805
+ "suffix": {
2806
+ "type": "string"
2807
+ }
2808
+ },
2809
+ "required": [
2810
+ "type",
2811
+ "exact"
2812
+ ]
2813
+ },
2814
+ {
2815
+ "$ref": "#/components/schemas/SvgSelector"
2816
+ },
2817
+ {
2818
+ "$ref": "#/components/schemas/FragmentSelector"
2819
+ }
2820
+ ]
2821
+ }
2822
+ }
2823
+ ]
2824
+ }
2825
+ },
2826
+ "required": [
2827
+ "source",
2828
+ "selector"
2829
+ ]
4141
2830
  },
4142
- "sourceResourceId": {
4143
- "type": "string"
2831
+ "body": {
2832
+ "oneOf": [
2833
+ {
2834
+ "$ref": "#/components/schemas/AnnotationBody",
2835
+ "description": "Single body (TextualBody or SpecificResource)"
2836
+ },
2837
+ {
2838
+ "type": "array",
2839
+ "items": {
2840
+ "$ref": "#/components/schemas/AnnotationBody"
2841
+ },
2842
+ "minItems": 1,
2843
+ "description": "Non-empty array of mixed TextualBody (tagging) and SpecificResource (linking) bodies"
2844
+ }
2845
+ ],
2846
+ "description": "Optional body. Omit for annotations whose motivation alone is meaningful (highlighting) or whose user-supplied content is empty. Shape matches Annotation.body."
4144
2847
  }
4145
2848
  },
4146
2849
  "required": [
4147
- "name",
4148
- "content",
4149
- "format",
4150
- "entityTypes"
2850
+ "target",
2851
+ "motivation"
4151
2852
  ]
4152
2853
  },
4153
2854
  "CreateResourceResponse": {
4154
2855
  "type": "object",
4155
- "properties": {
4156
- "resource": {
4157
- "$ref": "#/components/schemas/ResourceDescriptor"
4158
- },
4159
- "annotations": {
4160
- "type": "array",
4161
- "items": {
4162
- "$ref": "#/components/schemas/Annotation"
4163
- }
4164
- }
4165
- },
4166
- "required": [
4167
- "resource",
4168
- "annotations"
4169
- ]
4170
- },
4171
- "DeleteAnnotationRequest": {
4172
- "type": "object",
2856
+ "description": "Response body for POST /resources (202 Accepted). Resource creation is asynchronous — the backend writes content to disk, emits yield:create on the bus, and returns the newly-minted resourceId immediately. Consumers watch SSE domain events (yield:created) to observe the fully-persisted state.",
4173
2857
  "properties": {
4174
2858
  "resourceId": {
4175
2859
  "type": "string",
4176
- "format": "uri",
4177
- "description": "Resource URI containing the annotation (required for O(1) Layer 3 lookup)"
2860
+ "description": "The id of the newly-created resource. Assigned by Stower when it persists yield:create."
4178
2861
  }
4179
2862
  },
4180
2863
  "required": [
@@ -4196,100 +2879,6 @@
4196
2879
  "message"
4197
2880
  ]
4198
2881
  },
4199
- "AnnotateReferencesStreamRequest": {
4200
- "type": "object",
4201
- "properties": {
4202
- "entityTypes": {
4203
- "type": "array",
4204
- "items": {
4205
- "type": "string"
4206
- },
4207
- "description": "Entity types to annotate (e.g., 'Person', 'Organization', 'Location')"
4208
- },
4209
- "includeDescriptiveReferences": {
4210
- "type": "boolean",
4211
- "description": "Include anaphoric/cataphoric references (e.g., 'the CEO', 'the tech giant') in addition to direct mentions"
4212
- }
4213
- },
4214
- "required": [
4215
- "entityTypes"
4216
- ]
4217
- },
4218
- "GatherResourceStreamRequest": {
4219
- "type": "object",
4220
- "properties": {
4221
- "correlationId": {
4222
- "type": "string",
4223
- "description": "Client-generated correlation ID to thread the response back to the originating request"
4224
- },
4225
- "depth": {
4226
- "type": "integer",
4227
- "minimum": 1,
4228
- "maximum": 3,
4229
- "description": "Graph traversal depth (default: 2)"
4230
- },
4231
- "maxResources": {
4232
- "type": "integer",
4233
- "minimum": 1,
4234
- "maximum": 20,
4235
- "description": "Maximum related resources to include (default: 10)"
4236
- },
4237
- "includeContent": {
4238
- "type": "boolean",
4239
- "description": "Include full resource content (default: true)"
4240
- },
4241
- "includeSummary": {
4242
- "type": "boolean",
4243
- "description": "Include AI-generated summary (default: false)"
4244
- }
4245
- }
4246
- },
4247
- "GatherAnnotationStreamRequest": {
4248
- "type": "object",
4249
- "properties": {
4250
- "correlationId": {
4251
- "type": "string",
4252
- "description": "Client-generated correlation ID to thread the response back to the originating request"
4253
- },
4254
- "contextWindow": {
4255
- "type": "integer",
4256
- "minimum": 100,
4257
- "maximum": 5000,
4258
- "description": "Characters of surrounding text context (default: 1000)"
4259
- }
4260
- }
4261
- },
4262
- "BindAnnotationStreamRequest": {
4263
- "type": "object",
4264
- "properties": {
4265
- "resourceId": {
4266
- "type": "string",
4267
- "description": "Resource ID containing the annotation (required for O(1) Layer 3 lookup)"
4268
- },
4269
- "operations": {
4270
- "type": "array",
4271
- "items": {
4272
- "oneOf": [
4273
- {
4274
- "$ref": "#/components/schemas/BodyOperationAdd"
4275
- },
4276
- {
4277
- "$ref": "#/components/schemas/BodyOperationRemove"
4278
- },
4279
- {
4280
- "$ref": "#/components/schemas/BodyOperationReplace"
4281
- }
4282
- ]
4283
- },
4284
- "minItems": 1,
4285
- "description": "Array of body modification operations to apply"
4286
- }
4287
- },
4288
- "required": [
4289
- "resourceId",
4290
- "operations"
4291
- ]
4292
- },
4293
2882
  "GatherProgress": {
4294
2883
  "type": "object",
4295
2884
  "description": "Progress payload emitted on gather:annotation-progress and gather:progress SSE channels during LLM context gathering.",
@@ -4298,195 +2887,51 @@
4298
2887
  "type": "string"
4299
2888
  },
4300
2889
  "percentage": {
4301
- "type": "number",
4302
- "minimum": 0,
4303
- "maximum": 100
4304
- }
4305
- }
4306
- },
4307
- "GatherAnnotationFinished": {
4308
- "type": "object",
4309
- "description": "Completion payload emitted on gather:annotation-finished SSE channel.",
4310
- "properties": {
4311
- "correlationId": {
4312
- "type": "string"
4313
- },
4314
- "annotationId": {
4315
- "type": "string"
4316
- },
4317
- "response": {
4318
- "$ref": "#/components/schemas/AnnotationLLMContextResponse"
4319
- }
4320
- },
4321
- "required": [
4322
- "correlationId",
4323
- "annotationId",
4324
- "response"
4325
- ]
4326
- },
4327
- "GatherFinished": {
4328
- "type": "object",
4329
- "description": "Completion payload emitted on gather:finished SSE channel for resource-level context gathering.",
4330
- "properties": {
4331
- "correlationId": {
4332
- "type": "string"
4333
- },
4334
- "resourceId": {
4335
- "type": "string"
4336
- },
4337
- "response": {
4338
- "$ref": "#/components/schemas/ResourceLLMContextResponse"
4339
- }
4340
- },
4341
- "required": [
4342
- "correlationId",
4343
- "resourceId",
4344
- "response"
4345
- ]
4346
- },
4347
- "MarkProgress": {
4348
- "type": "object",
4349
- "description": "Progress state for mark (annotation) workflows. Supports both entity-type-step and percentage-based progress strategies. Emitted on mark:progress SSE channel.",
4350
- "properties": {
4351
- "correlationId": {
4352
- "type": "string",
4353
- "description": "Echoes the correlationId from the originating mark:assist-request command, if any. Lets clients match progress events back to the operation that initiated them."
4354
- },
4355
- "status": {
4356
- "type": "string",
4357
- "description": "Current status of the annotation workflow"
4358
- },
4359
- "message": {
4360
- "type": "string",
4361
- "description": "Human-readable status message"
4362
- },
4363
- "resourceId": {
4364
- "type": "string",
4365
- "description": "Resource being annotated"
4366
- },
4367
- "currentEntityType": {
4368
- "type": "string",
4369
- "description": "Reference annotation: currently scanning entity type"
4370
- },
4371
- "completedEntityTypes": {
4372
- "type": "array",
4373
- "description": "Reference annotation: completed entity types with counts",
4374
- "items": {
4375
- "type": "object",
4376
- "properties": {
4377
- "entityType": {
4378
- "type": "string"
4379
- },
4380
- "foundCount": {
4381
- "type": "integer"
4382
- }
4383
- },
4384
- "required": [
4385
- "entityType",
4386
- "foundCount"
4387
- ]
4388
- }
4389
- },
4390
- "percentage": {
4391
- "type": "number",
4392
- "minimum": 0,
4393
- "maximum": 100,
4394
- "description": "Percentage-based motivations (highlight, assessment, comment, tag)"
4395
- },
4396
- "currentCategory": {
4397
- "type": "string",
4398
- "description": "Category-based motivations (tag): current category"
4399
- },
4400
- "processedCategories": {
4401
- "type": "integer",
4402
- "description": "Category-based motivations (tag): number processed"
4403
- },
4404
- "totalCategories": {
4405
- "type": "integer",
4406
- "description": "Category-based motivations (tag): total categories"
4407
- },
4408
- "requestParams": {
4409
- "type": "array",
4410
- "description": "Request parameters for display in progress UI",
4411
- "items": {
4412
- "type": "object",
4413
- "properties": {
4414
- "label": {
4415
- "type": "string"
4416
- },
4417
- "value": {
4418
- "type": "string"
4419
- }
4420
- },
4421
- "required": [
4422
- "label",
4423
- "value"
4424
- ]
4425
- }
2890
+ "type": "number",
2891
+ "minimum": 0,
2892
+ "maximum": 100
4426
2893
  }
4427
- },
4428
- "required": [
4429
- "status"
4430
- ]
2894
+ }
4431
2895
  },
4432
- "MarkAssistFinished": {
2896
+ "GatherAnnotationFinished": {
4433
2897
  "type": "object",
4434
- "description": "Completion payload emitted on mark:assist-finished SSE channel when AI-assisted annotation completes.",
2898
+ "description": "Completion payload emitted on gather:annotation-finished SSE channel.",
4435
2899
  "properties": {
4436
2900
  "correlationId": {
4437
- "type": "string",
4438
- "description": "Echoes the correlationId from the originating mark:assist-request command, if any."
4439
- },
4440
- "motivation": {
4441
- "$ref": "#/components/schemas/Motivation"
4442
- },
4443
- "resourceId": {
4444
- "type": "string"
4445
- },
4446
- "status": {
4447
2901
  "type": "string"
4448
2902
  },
4449
- "percentage": {
4450
- "type": "number"
4451
- },
4452
- "foundCount": {
4453
- "type": "integer",
4454
- "description": "Number of annotations found/created"
4455
- },
4456
- "createdCount": {
4457
- "type": "integer",
4458
- "description": "Number of annotations actually created"
4459
- },
4460
- "byCategory": {
4461
- "type": "object",
4462
- "description": "Counts by category (for tag annotations)",
4463
- "additionalProperties": {
4464
- "type": "integer"
4465
- }
4466
- },
4467
- "message": {
2903
+ "annotationId": {
4468
2904
  "type": "string"
4469
2905
  },
4470
- "progress": {
4471
- "$ref": "#/components/schemas/MarkProgress"
2906
+ "response": {
2907
+ "$ref": "#/components/schemas/AnnotationLLMContextResponse"
4472
2908
  }
4473
- }
2909
+ },
2910
+ "required": [
2911
+ "correlationId",
2912
+ "annotationId",
2913
+ "response"
2914
+ ]
4474
2915
  },
4475
- "MarkAssistFailed": {
2916
+ "GatherFinished": {
4476
2917
  "type": "object",
4477
- "description": "Error payload emitted on mark:assist-failed SSE channel when AI-assisted annotation fails.",
2918
+ "description": "Completion payload emitted on gather:finished SSE channel for resource-level context gathering.",
4478
2919
  "properties": {
4479
2920
  "correlationId": {
4480
- "type": "string",
4481
- "description": "Echoes the correlationId from the originating mark:assist-request command, if any."
2921
+ "type": "string"
4482
2922
  },
4483
2923
  "resourceId": {
4484
2924
  "type": "string"
4485
2925
  },
4486
- "message": {
4487
- "type": "string"
2926
+ "response": {
2927
+ "$ref": "#/components/schemas/ResourceLLMContextResponse"
4488
2928
  }
4489
- }
2929
+ },
2930
+ "required": [
2931
+ "correlationId",
2932
+ "resourceId",
2933
+ "response"
2934
+ ]
4490
2935
  },
4491
2936
  "MatchSearchResult": {
4492
2937
  "type": "object",
@@ -4548,84 +2993,6 @@
4548
2993
  "error"
4549
2994
  ]
4550
2995
  },
4551
- "YieldProgress": {
4552
- "type": "object",
4553
- "description": "Progress state for resource yield (generation) workflow. Emitted as SSE events on yield:progress and yield:finished channels.",
4554
- "properties": {
4555
- "correlationId": {
4556
- "type": "string",
4557
- "description": "Echoes the correlationId from the originating yield:request command, if any. Lets clients match progress events back to the operation that initiated them."
4558
- },
4559
- "status": {
4560
- "type": "string",
4561
- "enum": [
4562
- "started",
4563
- "fetching",
4564
- "generating",
4565
- "creating",
4566
- "complete",
4567
- "error"
4568
- ]
4569
- },
4570
- "referenceId": {
4571
- "type": "string",
4572
- "description": "ID of the reference annotation that triggered generation"
4573
- },
4574
- "resourceName": {
4575
- "type": "string",
4576
- "description": "Name of the resource being generated"
4577
- },
4578
- "resourceId": {
4579
- "type": "string",
4580
- "description": "ID of the generated resource (available after creation)"
4581
- },
4582
- "sourceResourceId": {
4583
- "type": "string",
4584
- "description": "ID of the source resource containing the reference"
4585
- },
4586
- "percentage": {
4587
- "type": "number",
4588
- "minimum": 0,
4589
- "maximum": 100,
4590
- "description": "Progress percentage (0-100)"
4591
- },
4592
- "message": {
4593
- "type": "string",
4594
- "description": "Human-readable status message"
4595
- }
4596
- },
4597
- "required": [
4598
- "status",
4599
- "referenceId",
4600
- "percentage"
4601
- ]
4602
- },
4603
- "YieldStreamError": {
4604
- "type": "object",
4605
- "description": "Error payload emitted on yield:failed SSE channel when resource generation fails.",
4606
- "properties": {
4607
- "correlationId": {
4608
- "type": "string",
4609
- "description": "Echoes the correlationId from the originating yield:request command, if any."
4610
- },
4611
- "error": {
4612
- "type": "string",
4613
- "description": "Error message"
4614
- },
4615
- "status": {
4616
- "type": "string"
4617
- },
4618
- "referenceId": {
4619
- "type": "string"
4620
- },
4621
- "percentage": {
4622
- "type": "number"
4623
- },
4624
- "message": {
4625
- "type": "string"
4626
- }
4627
- }
4628
- },
4629
2996
  "EventMetadata": {
4630
2997
  "type": "object",
4631
2998
  "description": "Metadata added at persistence time. Part of every StoredEvent. Integrity is provided by git at the commit level (when gitSync is enabled), not by in-event metadata fields.",
@@ -5065,6 +3432,10 @@
5065
3432
  "jobType": {
5066
3433
  "$ref": "#/components/schemas/JobType"
5067
3434
  },
3435
+ "annotationId": {
3436
+ "type": "string",
3437
+ "description": "Annotation this job is attached to, when applicable"
3438
+ },
5068
3439
  "totalSteps": {
5069
3440
  "type": "integer"
5070
3441
  }
@@ -5128,6 +3499,10 @@
5128
3499
  "jobType": {
5129
3500
  "$ref": "#/components/schemas/JobType"
5130
3501
  },
3502
+ "annotationId": {
3503
+ "type": "string",
3504
+ "description": "Annotation this job was attached to, when applicable"
3505
+ },
5131
3506
  "totalSteps": {
5132
3507
  "type": "integer"
5133
3508
  },
@@ -5167,6 +3542,10 @@
5167
3542
  "jobType": {
5168
3543
  "$ref": "#/components/schemas/JobType"
5169
3544
  },
3545
+ "annotationId": {
3546
+ "type": "string",
3547
+ "description": "Annotation this job was attached to, when applicable"
3548
+ },
5170
3549
  "error": {
5171
3550
  "type": "string"
5172
3551
  },
@@ -5180,99 +3559,6 @@
5180
3559
  "error"
5181
3560
  ]
5182
3561
  },
5183
- "AnnotateHighlightsStreamRequest": {
5184
- "type": "object",
5185
- "properties": {
5186
- "instructions": {
5187
- "type": "string",
5188
- "description": "Optional instructions to guide AI highlight annotation"
5189
- },
5190
- "density": {
5191
- "type": "number",
5192
- "minimum": 1,
5193
- "maximum": 15,
5194
- "description": "Optional density: desired number of highlights per 2000 words of text (1-15)"
5195
- }
5196
- }
5197
- },
5198
- "AnnotateAssessmentsStreamRequest": {
5199
- "type": "object",
5200
- "properties": {
5201
- "instructions": {
5202
- "type": "string",
5203
- "description": "Optional instructions to guide AI assessment annotation"
5204
- },
5205
- "tone": {
5206
- "type": "string",
5207
- "enum": [
5208
- "analytical",
5209
- "critical",
5210
- "balanced",
5211
- "constructive"
5212
- ],
5213
- "description": "Optional tone/style for generated assessments"
5214
- },
5215
- "density": {
5216
- "type": "number",
5217
- "minimum": 1,
5218
- "maximum": 10,
5219
- "description": "Optional density: desired number of assessments per 2000 words of text (1-10)"
5220
- },
5221
- "language": {
5222
- "type": "string",
5223
- "description": "BCP 47 language tag for the generated assessment text (e.g. \"en\", \"fr\", \"de\")"
5224
- }
5225
- }
5226
- },
5227
- "AnnotateCommentsStreamRequest": {
5228
- "type": "object",
5229
- "properties": {
5230
- "instructions": {
5231
- "type": "string",
5232
- "description": "Optional instructions to guide AI comment annotation"
5233
- },
5234
- "tone": {
5235
- "type": "string",
5236
- "enum": [
5237
- "scholarly",
5238
- "explanatory",
5239
- "conversational",
5240
- "technical"
5241
- ],
5242
- "description": "Optional tone/style for generated comments"
5243
- },
5244
- "density": {
5245
- "type": "number",
5246
- "minimum": 2,
5247
- "maximum": 12,
5248
- "description": "Optional density: desired number of comments per 2000 words of text (2-12)"
5249
- },
5250
- "language": {
5251
- "type": "string",
5252
- "description": "BCP 47 language tag for the generated comment text (e.g. 'en', 'fr', 'de')"
5253
- }
5254
- }
5255
- },
5256
- "AnnotateTagsStreamRequest": {
5257
- "type": "object",
5258
- "properties": {
5259
- "schemaId": {
5260
- "type": "string",
5261
- "description": "Tag schema ID (e.g., 'legal-irac', 'scientific-imrad', 'argument-toulmin')"
5262
- },
5263
- "categories": {
5264
- "type": "array",
5265
- "items": {
5266
- "type": "string"
5267
- },
5268
- "description": "Categories to annotate from the selected schema (e.g., ['Issue', 'Rule', 'Application', 'Conclusion'])"
5269
- }
5270
- },
5271
- "required": [
5272
- "schemaId",
5273
- "categories"
5274
- ]
5275
- },
5276
3562
  "ErrorResponse": {
5277
3563
  "type": "object",
5278
3564
  "properties": {
@@ -5295,123 +3581,15 @@
5295
3581
  "type": "string"
5296
3582
  },
5297
3583
  "data": {
5298
- "type": "string"
5299
- },
5300
- "id": {
5301
- "type": "string"
5302
- }
5303
- },
5304
- "required": [
5305
- "event",
5306
- "data"
5307
- ]
5308
- },
5309
- "YieldResourceFromAnnotationRequest": {
5310
- "type": "object",
5311
- "properties": {
5312
- "name": {
5313
- "type": "string",
5314
- "description": "Optional name for the generated resource"
5315
- },
5316
- "entityTypes": {
5317
- "type": "array",
5318
- "items": {
5319
- "type": "string"
5320
- },
5321
- "description": "Entity types for the generated resource"
5322
- },
5323
- "prompt": {
5324
- "type": "string",
5325
- "description": "Optional AI prompt for generation"
5326
- },
5327
- "language": {
5328
- "type": "string",
5329
- "description": "Language code (e.g., 'en', 'es')"
5330
- }
5331
- }
5332
- },
5333
- "YieldResourceFromAnnotationResponse": {
5334
- "type": "object",
5335
- "properties": {
5336
- "resource": {
5337
- "$ref": "#/components/schemas/ResourceDescriptor"
5338
- },
5339
- "annotation": {
5340
- "$ref": "#/components/schemas/Annotation"
5341
- },
5342
- "generated": {
5343
- "type": "boolean"
5344
- }
5345
- },
5346
- "required": [
5347
- "resource",
5348
- "annotation",
5349
- "generated"
5350
- ]
5351
- },
5352
- "YieldResourceRequest": {
5353
- "type": "object",
5354
- "properties": {
5355
- "resourceId": {
5356
- "type": "string",
5357
- "description": "Resource ID containing the annotation"
5358
- },
5359
- "title": {
5360
- "type": "string",
5361
- "description": "Custom title for generated resource"
5362
- },
5363
- "prompt": {
5364
- "type": "string",
5365
- "description": "Custom prompt for content generation"
5366
- },
5367
- "language": {
5368
- "type": "string",
5369
- "description": "Language locale (e.g., \"es\", \"fr\", \"ja\")"
5370
- }
5371
- },
5372
- "required": [
5373
- "resourceId"
5374
- ]
5375
- },
5376
- "YieldResourceStreamRequest": {
5377
- "type": "object",
5378
- "properties": {
5379
- "title": {
5380
- "type": "string",
5381
- "description": "Custom title for generated resource"
5382
- },
5383
- "prompt": {
5384
- "type": "string",
5385
- "description": "Custom prompt for content generation"
5386
- },
5387
- "language": {
5388
- "type": "string",
5389
- "description": "Language locale for generated content (e.g., \"es\", \"fr\", \"ja\")"
5390
- },
5391
- "context": {
5392
- "$ref": "#/components/schemas/GatheredContext",
5393
- "description": "Gathered context including source document excerpts, metadata, and graph context"
5394
- },
5395
- "temperature": {
5396
- "type": "number",
5397
- "minimum": 0,
5398
- "maximum": 1,
5399
- "description": "Inference temperature (0.0 = focused, 1.0 = creative)"
5400
- },
5401
- "maxTokens": {
5402
- "type": "number",
5403
- "minimum": 100,
5404
- "maximum": 4000,
5405
- "description": "Maximum tokens to generate"
3584
+ "type": "string"
5406
3585
  },
5407
- "storageUri": {
5408
- "type": "string",
5409
- "description": "file://-relative URI where the generated resource will be saved (e.g. file://generated/overview.md)"
3586
+ "id": {
3587
+ "type": "string"
5410
3588
  }
5411
3589
  },
5412
3590
  "required": [
5413
- "context",
5414
- "storageUri"
3591
+ "event",
3592
+ "data"
5415
3593
  ]
5416
3594
  },
5417
3595
  "GetAnnotationHistoryResponse": {
@@ -5730,32 +3908,6 @@
5730
3908
  "created"
5731
3909
  ]
5732
3910
  },
5733
- "ListAnnotationsResponse": {
5734
- "type": "object",
5735
- "properties": {
5736
- "annotations": {
5737
- "type": "array",
5738
- "items": {
5739
- "$ref": "#/components/schemas/Annotation"
5740
- }
5741
- },
5742
- "total": {
5743
- "type": "number"
5744
- },
5745
- "offset": {
5746
- "type": "number"
5747
- },
5748
- "limit": {
5749
- "type": "number"
5750
- }
5751
- },
5752
- "required": [
5753
- "annotations",
5754
- "total",
5755
- "offset",
5756
- "limit"
5757
- ]
5758
- },
5759
3911
  "ListResourcesResponse": {
5760
3912
  "type": "object",
5761
3913
  "properties": {
@@ -5975,37 +4127,6 @@
5975
4127
  }
5976
4128
  }
5977
4129
  },
5978
- "BindAnnotationRequest": {
5979
- "type": "object",
5980
- "properties": {
5981
- "resourceId": {
5982
- "type": "string",
5983
- "description": "Target resource ID to resolve reference to"
5984
- }
5985
- },
5986
- "required": [
5987
- "resourceId"
5988
- ]
5989
- },
5990
- "BindAnnotationResponse": {
5991
- "type": "object",
5992
- "properties": {
5993
- "annotation": {
5994
- "$ref": "#/components/schemas/Annotation"
5995
- },
5996
- "targetResource": {
5997
- "nullable": true,
5998
- "allOf": [
5999
- {
6000
- "$ref": "#/components/schemas/ResourceDescriptor"
6001
- }
6002
- ]
6003
- }
6004
- },
6005
- "required": [
6006
- "annotation"
6007
- ]
6008
- },
6009
4130
  "ResourceDescriptor": {
6010
4131
  "type": "object",
6011
4132
  "description": "Metadata about a resource (1:1 with its URI). JSON-LD subject is @id. Link to concrete bytes via representations.",
@@ -6827,14 +4948,19 @@
6827
4948
  },
6828
4949
  "BindBodyUpdated": {
6829
4950
  "type": "object",
6830
- "description": "Event payload emitted on the bind:body-updated bus channel after annotation bodies are modified.",
4951
+ "description": "Success result emitted on the bind:body-updated bus channel after bind:update-body has been applied.",
6831
4952
  "properties": {
4953
+ "correlationId": {
4954
+ "type": "string",
4955
+ "description": "Correlation ID echoed from the originating bind:update-body command"
4956
+ },
6832
4957
  "annotationId": {
6833
4958
  "type": "string",
6834
4959
  "description": "Branded AnnotationId of the annotation whose body was updated"
6835
4960
  }
6836
4961
  },
6837
4962
  "required": [
4963
+ "correlationId",
6838
4964
  "annotationId"
6839
4965
  ]
6840
4966
  },
@@ -7021,6 +5147,36 @@
7021
5147
  "response"
7022
5148
  ]
7023
5149
  },
5150
+ "BrowseAnnotationContextRequest": {
5151
+ "type": "object",
5152
+ "description": "Request to get contextual text around an annotation",
5153
+ "properties": {
5154
+ "correlationId": {
5155
+ "type": "string"
5156
+ },
5157
+ "annotationId": {
5158
+ "type": "string"
5159
+ },
5160
+ "resourceId": {
5161
+ "type": "string"
5162
+ },
5163
+ "contextBefore": {
5164
+ "type": "integer",
5165
+ "minimum": 0,
5166
+ "maximum": 5000
5167
+ },
5168
+ "contextAfter": {
5169
+ "type": "integer",
5170
+ "minimum": 0,
5171
+ "maximum": 5000
5172
+ }
5173
+ },
5174
+ "required": [
5175
+ "correlationId",
5176
+ "annotationId",
5177
+ "resourceId"
5178
+ ]
5179
+ },
7024
5180
  "BrowseAnnotationsRequest": {
7025
5181
  "type": "object",
7026
5182
  "description": "Request to browse annotations for a resource",
@@ -7481,7 +5637,7 @@
7481
5637
  },
7482
5638
  "GatherAnnotationRequest": {
7483
5639
  "type": "object",
7484
- "description": "Request payload sent on the gather:annotation-request bus channel to gather context for an annotation.",
5640
+ "description": "Request payload sent on the gather:requested bus channel to gather context for an annotation.",
7485
5641
  "properties": {
7486
5642
  "correlationId": {
7487
5643
  "type": "string",
@@ -7705,7 +5861,7 @@
7705
5861
  },
7706
5862
  "GatherResourceRequest": {
7707
5863
  "type": "object",
7708
- "description": "Request payload sent on the gather:resource-request bus channel to gather context for a resource.",
5864
+ "description": "Request payload sent on the gather:resource-requested bus channel to gather context for a resource.",
7709
5865
  "properties": {
7710
5866
  "correlationId": {
7711
5867
  "type": "string",
@@ -7750,6 +5906,26 @@
7750
5906
  "options"
7751
5907
  ]
7752
5908
  },
5909
+ "GatherSummaryRequest": {
5910
+ "type": "object",
5911
+ "description": "Request to generate an AI summary of an annotation",
5912
+ "properties": {
5913
+ "correlationId": {
5914
+ "type": "string"
5915
+ },
5916
+ "annotationId": {
5917
+ "type": "string"
5918
+ },
5919
+ "resourceId": {
5920
+ "type": "string"
5921
+ }
5922
+ },
5923
+ "required": [
5924
+ "correlationId",
5925
+ "annotationId",
5926
+ "resourceId"
5927
+ ]
5928
+ },
7753
5929
  "JobAssessmentAnnotationResult": {
7754
5930
  "type": "object",
7755
5931
  "description": "Result of a completed assessment-annotation job.",
@@ -7782,6 +5958,79 @@
7782
5958
  "jobType"
7783
5959
  ]
7784
5960
  },
5961
+ "JobClaimCommand": {
5962
+ "type": "object",
5963
+ "description": "Command to claim a pending job (atomic CAS: pending → running)",
5964
+ "properties": {
5965
+ "correlationId": {
5966
+ "type": "string"
5967
+ },
5968
+ "jobId": {
5969
+ "type": "string"
5970
+ }
5971
+ },
5972
+ "required": [
5973
+ "correlationId",
5974
+ "jobId"
5975
+ ]
5976
+ },
5977
+ "JobCreateCommand": {
5978
+ "type": "object",
5979
+ "description": "Command to create a new job via the event bus",
5980
+ "properties": {
5981
+ "correlationId": {
5982
+ "type": "string"
5983
+ },
5984
+ "jobType": {
5985
+ "type": "string",
5986
+ "enum": [
5987
+ "reference-annotation",
5988
+ "highlight-annotation",
5989
+ "assessment-annotation",
5990
+ "comment-annotation",
5991
+ "tag-annotation",
5992
+ "generation"
5993
+ ]
5994
+ },
5995
+ "resourceId": {
5996
+ "type": "string"
5997
+ },
5998
+ "params": {
5999
+ "type": "object",
6000
+ "additionalProperties": true
6001
+ }
6002
+ },
6003
+ "required": [
6004
+ "correlationId",
6005
+ "jobType",
6006
+ "resourceId",
6007
+ "params"
6008
+ ]
6009
+ },
6010
+ "JobCreatedResult": {
6011
+ "type": "object",
6012
+ "description": "Result of a job:create command",
6013
+ "properties": {
6014
+ "correlationId": {
6015
+ "type": "string"
6016
+ },
6017
+ "response": {
6018
+ "type": "object",
6019
+ "properties": {
6020
+ "jobId": {
6021
+ "type": "string"
6022
+ }
6023
+ },
6024
+ "required": [
6025
+ "jobId"
6026
+ ]
6027
+ }
6028
+ },
6029
+ "required": [
6030
+ "correlationId",
6031
+ "response"
6032
+ ]
6033
+ },
7785
6034
  "JobCommentAnnotationResult": {
7786
6035
  "type": "object",
7787
6036
  "description": "Result of a completed comment-annotation job.",
@@ -7814,6 +6063,10 @@
7814
6063
  "jobType": {
7815
6064
  "$ref": "#/components/schemas/JobType"
7816
6065
  },
6066
+ "annotationId": {
6067
+ "type": "string",
6068
+ "description": "Annotation this job is attached to, when applicable. Lets the UI route completion feedback (toast, resolve state) to a specific annotation."
6069
+ },
7817
6070
  "result": {
7818
6071
  "$ref": "#/components/schemas/JobResult"
7819
6072
  }
@@ -7841,6 +6094,10 @@
7841
6094
  "jobType": {
7842
6095
  "$ref": "#/components/schemas/JobType"
7843
6096
  },
6097
+ "annotationId": {
6098
+ "type": "string",
6099
+ "description": "Annotation this job is attached to, when applicable. Lets the UI route failure feedback (error toast, revert state) to a specific annotation."
6100
+ },
7844
6101
  "error": {
7845
6102
  "type": "string"
7846
6103
  }
@@ -7855,11 +6112,11 @@
7855
6112
  },
7856
6113
  "JobGenerationResult": {
7857
6114
  "type": "object",
7858
- "description": "Result of a completed generation job.",
6115
+ "description": "Result of a completed generation job. resourceId is assigned by Stower when yield:create is processed; the worker emits job:complete with only resourceName, and Stower populates resourceId on the persisted payload.",
7859
6116
  "properties": {
7860
6117
  "resourceId": {
7861
6118
  "type": "string",
7862
- "description": "ID of the generated resource"
6119
+ "description": "ID of the generated resource (populated by Stower, not by the worker)"
7863
6120
  },
7864
6121
  "resourceName": {
7865
6122
  "type": "string",
@@ -7867,7 +6124,6 @@
7867
6124
  }
7868
6125
  },
7869
6126
  "required": [
7870
- "resourceId",
7871
6127
  "resourceName"
7872
6128
  ]
7873
6129
  },
@@ -7889,11 +6145,11 @@
7889
6145
  },
7890
6146
  "JobProgress": {
7891
6147
  "type": "object",
7892
- "description": "Progress report from a running job. Common fields are stage/percentage/message; job-type-specific fields may also be present.",
6148
+ "description": "Progress report from a running job. Common fields are stage/percentage/message; job-type-specific fields may also be present. This is the single progress shape for every job type — annotation workers and generation alike.",
7893
6149
  "properties": {
7894
6150
  "stage": {
7895
6151
  "type": "string",
7896
- "description": "Current processing stage"
6152
+ "description": "Current processing stage (e.g. 'analyzing', 'creating', 'complete', 'error')"
7897
6153
  },
7898
6154
  "percentage": {
7899
6155
  "type": "number",
@@ -7903,6 +6159,10 @@
7903
6159
  "type": "string",
7904
6160
  "description": "Human-readable progress message"
7905
6161
  },
6162
+ "annotationId": {
6163
+ "type": "string",
6164
+ "description": "Annotation this job is attached to, when applicable. Echoed inside JobProgress (in addition to the outer command envelope) so consumers that only see the inner progress object (e.g. client.yield.fromAnnotation's Observable) can still route visual feedback to a specific annotation."
6165
+ },
7906
6166
  "totalEntityTypes": {
7907
6167
  "type": "integer",
7908
6168
  "description": "Total entity types to process (reference-annotation)"
@@ -7923,6 +6183,25 @@
7923
6183
  "type": "string",
7924
6184
  "description": "Entity type currently being processed"
7925
6185
  },
6186
+ "completedEntityTypes": {
6187
+ "type": "array",
6188
+ "description": "Reference annotation: completed entity types with per-type counts, for UI progress display",
6189
+ "items": {
6190
+ "type": "object",
6191
+ "properties": {
6192
+ "entityType": {
6193
+ "type": "string"
6194
+ },
6195
+ "foundCount": {
6196
+ "type": "integer"
6197
+ }
6198
+ },
6199
+ "required": [
6200
+ "entityType",
6201
+ "foundCount"
6202
+ ]
6203
+ }
6204
+ },
7926
6205
  "processedCategories": {
7927
6206
  "type": "integer",
7928
6207
  "description": "Categories processed (tag-annotation)"
@@ -7934,6 +6213,25 @@
7934
6213
  "currentCategory": {
7935
6214
  "type": "string",
7936
6215
  "description": "Category currently being processed (tag-annotation)"
6216
+ },
6217
+ "requestParams": {
6218
+ "type": "array",
6219
+ "description": "Echoed job parameters for display in the progress UI (e.g. entity types or categories the user asked to detect)",
6220
+ "items": {
6221
+ "type": "object",
6222
+ "properties": {
6223
+ "label": {
6224
+ "type": "string"
6225
+ },
6226
+ "value": {
6227
+ "type": "string"
6228
+ }
6229
+ },
6230
+ "required": [
6231
+ "label",
6232
+ "value"
6233
+ ]
6234
+ }
7937
6235
  }
7938
6236
  },
7939
6237
  "required": [
@@ -8001,6 +6299,10 @@
8001
6299
  "jobType": {
8002
6300
  "$ref": "#/components/schemas/JobType"
8003
6301
  },
6302
+ "annotationId": {
6303
+ "type": "string",
6304
+ "description": "Annotation this job is attached to, when applicable. Lets the UI attach progress visuals to a specific annotation (e.g. a reference whose generation is running)."
6305
+ },
8004
6306
  "percentage": {
8005
6307
  "type": "number"
8006
6308
  },
@@ -8054,6 +6356,10 @@
8054
6356
  },
8055
6357
  "jobType": {
8056
6358
  "$ref": "#/components/schemas/JobType"
6359
+ },
6360
+ "annotationId": {
6361
+ "type": "string",
6362
+ "description": "Annotation this job is attached to, when applicable. Set for annotation-scoped jobs like generation (from a specific reference). Unset for resource-scoped jobs like bulk reference/tag/highlight detection."
8057
6363
  }
8058
6364
  },
8059
6365
  "required": [
@@ -8237,6 +6543,10 @@
8237
6543
  "type": "object",
8238
6544
  "description": "Bus command to create an annotation on a resource.",
8239
6545
  "properties": {
6546
+ "correlationId": {
6547
+ "type": "string",
6548
+ "description": "Optional correlation id threaded from the originating mark:create-request. Propagated into event metadata by Stower so annotation-assembly can emit mark:create-ok after persistence completes."
6549
+ },
8240
6550
  "annotation": {
8241
6551
  "$ref": "#/components/schemas/Annotation"
8242
6552
  },
@@ -8265,6 +6575,26 @@
8265
6575
  "annotationId"
8266
6576
  ]
8267
6577
  },
6578
+ "MarkCreateRequest": {
6579
+ "type": "object",
6580
+ "description": "Raw annotation creation intent — bus handler assembles the W3C annotation",
6581
+ "properties": {
6582
+ "correlationId": {
6583
+ "type": "string"
6584
+ },
6585
+ "resourceId": {
6586
+ "type": "string"
6587
+ },
6588
+ "request": {
6589
+ "$ref": "#/components/schemas/CreateAnnotationRequest"
6590
+ }
6591
+ },
6592
+ "required": [
6593
+ "correlationId",
6594
+ "resourceId",
6595
+ "request"
6596
+ ]
6597
+ },
8268
6598
  "MarkDeleteCommand": {
8269
6599
  "type": "object",
8270
6600
  "description": "Bus command to delete an annotation.",
@@ -8413,16 +6743,26 @@
8413
6743
  ]
8414
6744
  },
8415
6745
  "body": {
8416
- "type": "array",
8417
- "items": {
8418
- "$ref": "#/components/schemas/AnnotationBody"
8419
- }
6746
+ "oneOf": [
6747
+ {
6748
+ "$ref": "#/components/schemas/AnnotationBody",
6749
+ "description": "Single body (TextualBody or SpecificResource)"
6750
+ },
6751
+ {
6752
+ "type": "array",
6753
+ "items": {
6754
+ "$ref": "#/components/schemas/AnnotationBody"
6755
+ },
6756
+ "minItems": 1,
6757
+ "description": "Non-empty array of mixed TextualBody / SpecificResource bodies"
6758
+ }
6759
+ ],
6760
+ "description": "Optional body. Omit for annotations whose motivation alone is meaningful (e.g. highlighting) or whose user-supplied content is empty (e.g. an assessing annotation saved without comment text). Shape matches Annotation.body."
8420
6761
  }
8421
6762
  },
8422
6763
  "required": [
8423
6764
  "motivation",
8424
- "selector",
8425
- "body"
6765
+ "selector"
8426
6766
  ]
8427
6767
  },
8428
6768
  "MarkUnarchiveCommand": {