fix(bruno): convert drifted body keys to body.data — CLI scenario runs now carry bodies

Follow-up to the sweep route audit, correcting its diagnosis: the CLI
DOES read .yml bodies — via OpenCollection's `body.data` string form
(the NewDevDBSetup script always worked because it used it). The
failing scenario POSTs used `body.json` (structured) / `body.jsonBody`
(string) — keys the CLI silently ignores, sending Content-Length: 0
with form-urlencoded content-type, so every server bind failed.

- 81 bodies converted to data-form (json maps serialized; jsonBody
  strings kept verbatim, {{vars}} intact).
- 6 pre-existing TRUNCATED payloads repaired: the original generator
  cut bodies at the first {{var}} (every SHA-256-identified scenario
  plus Sync Progress/Sync Bookmarks shipped mid-JSON and 400'd from
  day one). Rewritten whole, faithful to each file's documented
  purpose; book_sha256/book_uuid added to the environment.
- environments: opds_base_url correction from the sweep retained.

Verified live against the rebuilt dev container: the full koreader
scenario tree runs green through `bru run` — 14/14 (202s across
immediate/checkpoint/SHA-256 progress, 200s bookmarks, highlights,
notes; SHA-256 book identification exercised against a real
file_sha256).
This commit is contained in:
John O'Keefe committed 2026-10-17 12:22:35 -04:00
1 parent 63a20dcc95
commit 09b6693505
83 files changed
+386 -2769

No files matched your search

@@ -2,90 +2,17 @@ info:
name: Sync Multiple Books Progress
type: http
seq: 3
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: inherit
headers:
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
- key: Content-Type
value: application/json
- key: x-kobo-device
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
body:
type: json
json:
ReadingSync:
- ContentId: book-1-uuid
PercentRead: 25.0
EntitlementId: entitlement-1
RemainingTimeMinutes: 240
FirstReadTime: '2026-01-25T10:00:00Z'
LastModified: '2026-01-30T18:00:00Z'
- ContentId: book-2-uuid
PercentRead: 78.5
EntitlementId: entitlement-2
RemainingTimeMinutes: 45
FirstReadTime: '2026-01-25T14:00:00Z'
LastModified: '2026-01-30T20:00:00Z'
BookmarkSync: []
docs: |-
## Sync Multiple Books Progress
Synchronizes reading progress for multiple books in a single request.
**Method:** POST
**Endpoint:** /api/sync/kobo/markup
**Authentication:** Bearer token
**Headers:**
- `Authorization`: Bearer {{kobo_device_token}}
- `x-kobo-device`: Device information (Model: "Kobo Aura")
**Request Body:**
- `ReadingSync` (array): Multiple progress items
- Each item contains: ContentId, PercentRead, EntitlementId, etc.
- `BookmarkSync` (array): Empty for progress-only batch
**Response:**
- `total` (integer): Total items in request
- `synced` (integer): Successfully synced
- `failed` (integer): Failed items
- `results` (array): Per-item results
- `ContentId` (string): Book UUID
- `status` (string): `synced`, `failed`, `skipped`
- `error` (string, optional): Error message if failed
**Status Codes:**
- 200: Batch sync completed
- 207: Multi-status (some succeeded, some failed)
- 401: Unauthorized
- 413: Payload too large (>1MB)
**Batch Sync Advantages:**
- Efficient sync of entire library
- Reduces HTTP overhead
- Faster for devices with many books
- Atomic operation (all or nothing by default)
**Kobo Batch Sync Behavior:**
- Triggered when device connects after being offline
- Occurs during manual "Sync now" operation
- Limited to 100 books per request
- Progress updates shown on device
- Failed items retried individually
**Performance:**
- Typical batch: 10-50 books in 1-3 seconds
- Large batch: 50-100 books in 3-8 seconds
- Timeout: 30 seconds
- Rate limit: 10 batches per minute per device
**Use Cases:**
- Initial device sync after registration
- Catch-up sync after extended offline period
- Library-wide progress update
- Pre-sync before device firmware update
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-1-uuid\",\n \"PercentRead\": 25.0,\n \"EntitlementId\": \"entitlement-1\",\n \"RemainingTimeMinutes\": 240,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T18:00:00Z\"\n },\n {\n \"ContentId\": \"book-2-uuid\",\n \"PercentRead\": 78.5,\n \"EntitlementId\": \"entitlement-2\",\n \"RemainingTimeMinutes\": 45,\n \"FirstReadTime\": \"2026-01-25T14:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": []\n}"
docs: "## Sync Multiple Books Progress\n\nSynchronizes reading progress for multiple books in a single request.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information (Model: \"Kobo Aura\")\n\n**Request Body:**\n- `ReadingSync` (array): Multiple progress items\n - Each item contains: ContentId, PercentRead, EntitlementId, etc.\n- `BookmarkSync` (array): Empty for progress-only batch\n\n**Response:**\n- `total` (integer): Total items in request\n- `synced` (integer): Successfully synced\n- `failed` (integer): Failed items\n- `results` (array): Per-item results\n - `ContentId` (string): Book UUID\n - `status` (string): `synced`, `failed`, `skipped`\n - `error` (string, optional): Error message if failed\n\n**Status Codes:**\n- 200: Batch sync completed\n- 207: Multi-status (some succeeded, some failed)\n- 401: Unauthorized\n- 413: Payload too large\
\ (>1MB)\n\n**Batch Sync Advantages:**\n- Efficient sync of entire library\n- Reduces HTTP overhead\n- Faster for devices with many books\n- Atomic operation (all or nothing by default)\n\n**Kobo Batch Sync Behavior:**\n- Triggered when device connects after being offline\n- Occurs during manual \"Sync now\" operation\n- Limited to 100 books per request\n- Progress updates shown on device\n- Failed items retried individually\n\n**Performance:**\n- Typical batch: 10-50 books in 1-3 seconds\n- Large batch: 50-100 books in 3-8 seconds\n- Timeout: 30 seconds\n- Rate limit: 10 batches per minute per device\n\n**Use Cases:**\n- Initial device sync after registration\n- Catch-up sync after extended offline period\n- Library-wide progress update\n- Pre-sync before device firmware update"