docs/reference/operation-correlation.md now states two facts from the code: replay matching compares the exact request text, so a change in whitespace or key order is a different request, and an operation ID that isn't a UUID gets HTTP 400 before the route does anything else. A different request reusing an ID gets 409 only once it passes the route's own validation. Cost: +1/-1, one paragraph. Text only.
2.1 KiB
HTTP operation correlation
GET /api/operations/capabilities advertises operation-correlation.v1 and the supported kinds: rig.create, rig.import, and member.add. A client should check this marker before relying on correlation; an older daemon may ignore an unfamiliar request header.
For POST /api/rigs, POST /api/rigs/import, and POST /api/rigs/:rigId/pods/:podNamespace/members, send a UUID in X-OpenRig-Operation-Id. Keep the same daemon, route targets, original request text, and behavior-changing headers for a retry. IDs are case-normalized. An ID that isn't an RFC UUID receives HTTP 400 Invalid X-OpenRig-Operation-Id before the route does anything else. Once a request passes the route's own validation, a different request using the same ID receives HTTP 409 operation_id_conflict. Matching compares the exact request text, so a change in whitespace or key order is a different request, not an equivalent one; an exact replay receives HTTP 200 with replayed: true and current database state. A first request retains its usual status and response fields and adds operation.
The operation contains the rig and node IDs committed by that request. Its current field reads the database at response time, including whether recorded resources still exist and the latest recorded session for each node. It does not inspect tmux or prove a launch finished. A reservation with no IDs can mean that execution is still underway or that it failed before creating resources. Replaying an exact request that failed before creating resources returns HTTP 200 with operation.rigId: null and operation.nodeIds: []; inspect those fields to distinguish it from a replay that recorded resources. Replays never execute the mutation again, retry a launch, or recreate deleted resources. Use a new UUID only when deliberately starting a new execution.
This contract stores neither the original response nor a recovery verdict. An HTTP response can be lost after a database commit. External launch effects are outside the database transaction, so the contract is correlation rather than exactly-once execution of external effects.