Files
SciMesh/docs/api-contract.md

4.0 KiB

SciMesh Coordinator API Contract

Status: draft, version 1. This document is the compatibility boundary between the Go coordinator and the Python Worker. Change it only in the same pull request as both implementation and contract tests.

General rules

  • All worker endpoints require Authorization: Bearer <token>.
  • Times use UTC RFC 3339, for example 2026-07-23T12:05:00Z.
  • JSON requests and responses use application/json.
  • worker_id and attempt identify a lease. The coordinator validates them transactionally on every task mutation.
  • A task becomes completed only after a coordinator-owned artifact is durable.
  • Identical repeated completion is successful; a different result for the same attempt is a conflict.

Worker registration

POST /workers/register

{"name":"lab-worker-01","capabilities":["similarity-search"],"cpu_count":8,"memory_mb":16384}

Returns 200 OK:

{"worker_id":"uuid","heartbeat_interval_seconds":15}

Task lifecycle

Claim

POST /tasks/claim

{"worker_id":"uuid","capabilities":["similarity-search"],"max_concurrency":1}

Returns 204 No Content when no compatible task exists. A successful atomic claim returns 200 OK:

{
  "task_id":"uuid",
  "attempt":1,
  "lease_expires_at":"2026-07-23T12:05:00Z",
  "workload":"similarity-search",
  "input":{"uri":"https://coordinator.example/tasks/uuid/input","sha256":"hex-sha256"},
  "parameters":{"query_id":"CHEMBL939","top_k":20}
}

The claim is one PostgreSQL transaction using FOR UPDATE SKIP LOCKED.

Heartbeat

POST /tasks/{task_id}/heartbeat

{"worker_id":"uuid","attempt":1}

Returns 200 OK and the renewed deadline:

{"lease_expires_at":"2026-07-23T12:10:00Z"}

The Worker schedules its next heartbeat before half of the returned TTL.

Input download

GET /tasks/{task_id}/input returns the claimed task input. The Worker verifies its SHA-256 before execution. On a redirect to another origin, it removes the coordinator bearer token.

Artifact upload

PUT /tasks/{task_id}/artifacts/{filename}
Content-Type: text/csv
X-Worker-ID: uuid
X-Task-Attempt: 1

<streamed bytes>

The coordinator streams the body to storage, checks lease ownership, records the checksum and returns 201 Created:

{
  "artifact_id":"uuid",
  "uri":"https://coordinator.example/artifacts/uuid/download",
  "sha256":"hex-sha256",
  "size_bytes":1234
}

The returned URI is the only URI the Worker may send in task completion. worker:// and file:// are invalid.

Completion and failure

POST /tasks/{task_id}/result

{
  "worker_id":"uuid",
  "attempt":1,
  "result":{
    "artifact_id":"uuid",
    "uri":"https://coordinator.example/artifacts/uuid/download",
    "sha256":"hex-sha256",
    "content_type":"text/csv"
  },
  "metrics":{"elapsed_seconds":12.4,"processed_rows":10000}
}

The coordinator returns 200, 201, or 202 for a valid completion. It must verify that the artifact belongs to that task and attempt before completing it.

Use POST /tasks/{task_id}/failure only for a failed attempt:

{"worker_id":"uuid","attempt":1,"error_code":"ValueError","error_message":"input checksum mismatch"}

Messages are sanitised: no token, traceback, absolute local path, or raw input.

Error responses

Situation Response
Invalid JSON, field, or parameter 400 Bad Request
Missing or invalid authentication 401 Unauthorized / 403 Forbidden
Worker/attempt does not own an active lease 409 Conflict
Artifact does not belong to the task/attempt 409 Conflict
Same attempt, different completion manifest 409 Conflict
Unexpected coordinator failure 500 without internal details

Compatibility tests

Contract tests must cover: registration, 204 claim, successful claim, heartbeat renewal, foreign worker and stale attempt conflicts, streamed upload, checksum mismatch, success after upload, failure through /failure, and idempotent completion.