Partial failures, the four decisions, and the one that cannot be taken casually.
When a compile stops and waits
A compile that cannot read every source stops and waits. Nothing is skipped automatically: a World quietly missing documents you believe are in it is worse than a compile that asks.
The four decisions
Decision
Effect
continue
Compile the readable sources. Refused while any blocker is a security blocker.
remove_blocked
Drop the blocked sources from the set, recorded against the person who chose it.
retry_eligible
Retry the ordinary blockers, keeping the security ones blocked.
Answers a partial failure. A job with blocked documents stops and waits; nothing skips them by itself. `continue` is refused while any blocker is a security blocker -- those leave the set through `remove_blocked`, which records who removed them.
The recorded resolution and the job it applies to.
400
RESOLUTION_REQUIRED — A blocker resolution was requested with no resolution field. INVALID_JSON — The body was not parseable JSON. COMPILE_JOB_SCOPE_INVALID — The job exists and belongs to another workspace.
401
AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404
COMPILE_JOB_NOT_FOUND — No such job in this workspace. Job ids are workspace-scoped, so this is also the answer for another tenant's id.
409
SECURITY_BLOCKER_REQUIRES_EXPLICIT_REMOVAL — continue was sent while a source was held by a safety check. RESOLUTION_NOT_APPLIED — The resolution was understood and the job's state refused it. COMPILE_JOB_ALREADY_SETTLED — The job had already finished. Nothing was discarded — a cancel arriving a second after a compile finished does not destroy the result.
415
METADATA_ONLY_ENDPOINT — Document bytes were POSTed to a route that accepts only metadata. Bytes go direct to storage, never through the application server.
Marks the job cancelled. A job that had already settled is left alone -- a cancel arriving a second after a compile finished does not destroy the result.
curl -sS -X POST https://tavonel.com/api/compile-jobs/{jobId}/cancel \
-H "Authorization: Bearer $TAVONEL_API_KEY"
AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404
COMPILE_JOB_NOT_FOUND — No such job in this workspace. Job ids are workspace-scoped, so this is also the answer for another tenant's id.
409
COMPILE_JOB_ALREADY_SETTLED — The job had already finished. Nothing was discarded — a cancel arriving a second after a compile finished does not destroy the result.
Recording a decision over evidence
Blockers are one half of review. The other is the append-only record of what a person decided about a piece of evidence: Accept, Edit or Reject, each with a reason of at least eight characters, because a decision with no reason is a decision nobody can audit.
The request carries the manifest digest you read the evidence at, and the server revalidates the evidence against the persisted World before it writes. If the World moved in between, the answer is 409 REVIEW_WORLD_CHANGED and nothing is recorded — a decision written against a version it does not describe is worse than no decision. Re-read at the current digest and decide again. This route takes a signed-in browser session; no API key records a review.
POST/reviews
Records an append-only Accept, Edit, or Reject decision after revalidating the evidence against the persisted World. The digest is part of the request because a decision recorded against a version it does not describe is worse than no decision: if the World moved under you, this answers REVIEW_WORLD_CHANGED rather than writing it.
# Browser session only. A developer API key is refused on this route.
curl -sS -X POST https://tavonel.com/api/v1/reviews \
-H "Authorization: Bearer $TAVONEL_SESSION_JWT" \
-H "content-type: application/json" \
-d '{ "collectionId": "<collectionId>", "manifestDigest": "<manifestDigest>", "evidenceId": "<evidenceId>", "action": "<action>", "reason": "<reason>" }'
# Browser session only. A developer API key is refused on this route.
import os
import requests
body = {
"collectionId": "<collectionId>",
"manifestDigest": "<manifestDigest>",
"evidenceId": "<evidenceId>",
"action": "<action>",
"reason": "<reason>"
}
response = requests.request(
"POST",
"https://tavonel.com/api/v1/reviews",
headers={"Authorization": "Bearer " + os.environ["TAVONEL_SESSION_JWT"]},
json=body,
timeout=30,
)
response.raise_for_status()
print(response.json())
// Browser session only. A developer API key is refused on this route.
const response = await fetch("https://tavonel.com/api/v1/reviews", {
method: "POST",
headers: { authorization: `Bearer ${process.env.TAVONEL_SESSION_JWT}`, "content-type": "application/json" },
body: JSON.stringify({ "collectionId": "<collectionId>", "manifestDigest": "<manifestDigest>", "evidenceId": "<evidenceId>", "action": "<action>", "reason": "<reason>" }),
});
if (!response.ok) throw new Error(`${response.status} ${(await response.json()).code}`);
console.log(await response.json());
An evidence-bound human decision receipt. Append-only: a second decision does not overwrite the first.
400
REVIEW_REQUEST_INVALID — The review body did not validate. REVIEW_PATCH_INVALID — An Edit decision carried a patch that did not validate. PATCH_NO_CHANGE — The patch would change nothing. INVALID_JSON — The body was not parseable JSON.
401
AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404
REVIEW_EVIDENCE_NOT_FOUND — The evidence id is not in the World version named by the digest. PATCH_TARGET_NOT_FOUND — The patch names a target the World does not contain.
409
REVIEW_WORLD_CHANGED — The World changed between reading the evidence and recording the decision, so the decision was not written against a version it may not describe. PATCH_BEFORE_MISMATCH — The patch's before value does not match what is stored now. PATCH_TARGET_NOT_EDITABLE — The target is not one a review decision may edit.
413
REVIEW_REQUEST_TOO_LARGE — The review body exceeded its bound.
503
REVIEW_STORE_WRITE_FAILED — The review store could not be written. REVIEW_STORE_NOT_CONFIGURED — The review store is not configured.
What continue will not do
NoteA file stopped by a safety check leaves the set only through an explicit removal. continue will not step over it, because a pipeline that learns to skip security stops has stopped being one.
API version 2026-09-02.1 · reviewed 11 September 2026