From a65e12b9165ecbbbd9fe656f322653a2ad2e56e7 Mon Sep 17 00:00:00 2001 From: jedarden Date: Sat, 23 May 2026 00:01:12 -0400 Subject: [PATCH] docs(pdftract-5xq16): add verification note Add verification note documenting JSON-RPC 2.0 framing implementation with all acceptance criteria PASS. Co-Authored-By: Claude Opus 4.7 --- notes/pdftract-5xq16.md | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 notes/pdftract-5xq16.md diff --git a/notes/pdftract-5xq16.md b/notes/pdftract-5xq16.md new file mode 100644 index 0000000..09807f5 --- /dev/null +++ b/notes/pdftract-5xq16.md @@ -0,0 +1,70 @@ +# pdftract-5xq16: JSON-RPC 2.0 framing layer + +## Summary + +Implemented hand-rolled JSON-RPC 2.0 framing layer at `crates/pdftract-cli/src/mcp/framing/mod.rs`. + +## Files Changed + +- `crates/pdftract-cli/src/mcp/framing/mod.rs` - New module (658 lines) +- `crates/pdftract-cli/src/mcp/mod.rs` - Added `pub mod framing;` and re-exports + +## Implementation Details + +### Types Defined + +1. **`Id` enum** - Request identifier preserving JSON type: + - `Id::Number(i64)` - Numeric IDs + - `Id::String(String)` - String IDs + - `Id::Null` - Null IDs (for parse errors) + +2. **`Request`** - JSON-RPC request with: + - `jsonrpc` field (validated to be "2.0") + - `method: String` + - `params: Option` + - `id: Option` (None = notification) + +3. **`Notification`** - Request without id field (no response) + +4. **`Response`** - Response with mutually exclusive `result` or `error` + +5. **`ErrorObject`** - Error with code, message, and optional data + +6. **`BatchMessage`** - Single or batch request wrapper + +### Error Codes Implemented + +| Code | Name | Constructor | +|------|------|-------------| +| -32700 | Parse error | `ErrorObject::parse_error()` | +| -32600 | Invalid Request | `ErrorObject::invalid_request()` | +| -32601 | Method not found | `ErrorObject::method_not_found(method)` | +| -32602 | Invalid params | `ErrorObject::invalid_params()` | +| -32603 | Internal error | `ErrorObject::internal_error()` | +| -32099..-32000 | Server errors | `ErrorObject::server_error(code, msg)` | + +## Acceptance Criteria + +All PASS: + +- ✅ **Round-trip test**: `test_request_round_trip` - Request serializes and deserializes correctly +- ✅ **ID preservation**: `test_id_number_preservation`, `test_id_string_preservation`, `test_id_null_preservation` - All 3 ID types preserve JSON type through round-trip +- ✅ **Parse-error path**: `test_parse_error_response` - Parse error response has `id: null` +- ✅ **Method-not-found**: `test_method_not_found` - Returns code -32601 with method name in data field +- ✅ **Notification path**: `test_notification_no_id`, `test_notification_deserialize` - Notifications have no id field; deserialize correctly +- ✅ **Batch round-trip**: `test_batch_round_trip` - Batch of 3 requests serializes/deserializes correctly +- ✅ **Error codes**: `test_all_error_codes` - All 6 spec-defined error codes return correct values +- ✅ **jsonrpc validation**: `test_reject_invalid_jsonrpc_version`, `test_reject_missing_jsonrpc_field` - Invalid versions rejected with clear error +- ✅ **Empty batch**: `test_empty_batch_rejected` - Empty array returns Invalid Request error + +## Test Results + +``` +running 16 tests +........................ +test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured +``` + +## Commit + +`3c10dfd` - feat(pdftract-5xq16): implement JSON-RPC 2.0 framing layer