5.5.2.2 Files
The Files domain of farm. Raw files as received, what was skipped when parsing them and the parse jobs that processed them. Organization users see what their sources sent and what failed, upload files of their own feeds and remove them; staff see everything, retry failed jobs and ask for re-parses. It is one API, with its own contract and its own version.
5.5.2.2.1 Versions¶
| Version | Status | Prod URL | Contract |
|---|---|---|---|
v1 |
Proposed | https://farm.moonitoring.com/files/v1 |
files/v1/openapi.yaml |
The resources follow the data model. Adds the upload handshake (UploadRequest, UploadTarget) for files an Organization sends by hand, which become a SyncRun of kind full_snapshot with one raw file, and the ReparseRequest of req 51.9. The capability farm.parse_jobs.manage is proposed: req 51.9 names a Moonitoring user but the catalog has no capability for it.
Removing an uploaded file is a logical withdrawal: its active evidence is cancelled under a file_removal WriteCommit, while the original object remains under the raw-retention policy until erasure. RawFileView adds withdrawn_at to the API response without changing the meaning of RawMetadata.deleted_at, which records physical deletion. Repeating a withdrawal does not append another cancellation revision, and a pending parse must not republish withdrawn evidence. Uploading the same bytes of a withdrawn file returns 409; this contract does not introduce a restore operation.
An upload is known only when the server has verified the stored object's uncompressed hash and size and the object remains available. An erased or missing object cannot satisfy this condition: if its metadata already exists, announcing it returns 409 without automatically restoring it. The response always supplies either the known raw file or upload instructions. Reusing bytes does not certify that the current delivery was processed, and a full-snapshot label alone does not establish completeness or authorize inferred deletions. Downloading an erased raw returns 410; an unexpectedly unavailable object returns 409. Neither response includes a signed URL.
5.5.2.2.2 Operations¶
Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.
| Operation | Request | Who | Capability |
|---|---|---|---|
| List a farm's raw files | GET /organizations/{organization_id}/raw-files |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Read a raw file's metadata | GET /raw-files/{raw_file_id} |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Get a download link | POST /raw-files/{raw_file_id}/download-url |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Remove an uploaded file | POST /raw-files/{raw_file_id}/remove |
Organization users | farm.animal_records.edit_own |
| List a raw file's skips | GET /raw-files/{raw_file_id}/skips |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| List a raw file's parse jobs | GET /raw-files/{raw_file_id}/parse-jobs |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Announce an upload | POST /organizations/{organization_id}/uploads |
Organization users | farm.animal_records.edit_own |
| Commit an upload | POST /uploads/{upload_id}/commit |
Organization users | farm.animal_records.edit_own |
| Summarize a farm's skips | GET /organizations/{organization_id}/skips |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Get the row-level detail of a skip | POST /skips/{skip_id}/detail-url |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| List parse jobs | GET /parse-jobs |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Ask for a re-parse | POST /parse-jobs |
Staff | farm.parse_jobs.manage |
| Read a parse job | GET /parse-jobs/{job_id} |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Retry a failed job | POST /parse-jobs/{job_id}/retry |
Staff | farm.parse_jobs.manage |
5.5.2.2.3 Contract v1¶
Proposed version
v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.
5.5.2.2.4 Rules Confirmed with the Implementation¶
Decided on 2026-11-05, from the choices made while building farm:
- Raw objects are zstd frames, addressed by content:
raw/<farm>/<feed>/<hash_type>/<data_hash>.zst, hashes in lower-case hex (xxh3is the 64-bit variant). At commit the server reads the object, decompresses it and checks its hash and size before it records the RawMetadata, so only verified objects are ever reused. - Run logs are
raw/<farm>/<feed>/runs/<run>.jsonl; the run records the path, and a commit that names another path is a 422. - Skip logs are JSONL at
raw/<farm>/<feed>/skips/<job>/<n>.jsonl, one object per skipped row, as the parser gives it.