Elgora docs

The readiness review

What Elgora checks before it will store your challenge — the deterministic validation and the automated judgeability review — and what to do when either one refuses.

Publication runs two gates before your bytes are stored or your wallet spends anything. Both happen inside a single poster:publish-fund call, in this order.

  1. Structural conformance. Ordinary code checks the shape of the page. No model, no network, no review quota — a failure here costs nothing.
  2. The readiness review. An automated reviewer reads the page and answers one question: does the page meet the shared readiness rules?

The dividing line is measurement versus reading. Gate 1 decides questions with one right answer you can compute — is this key present, is this number below that number. Everything that needs someone to understand what a sentence means is gate 2's, including several platform conflicts and anything about whether the page is trying to instruct its reader.

Only if both pass does Elgora store the exact bytes, derive spec_commitment, and hand your client the prepared createBounty arguments.

Gate 1 — structural conformance

This is mechanical and its messages name the exact field:

  • the document starts with the frontmatter block and closes it before the body;
  • every required key is present exactly once, snake_case, no unknown keys;
  • profile names a published profile version, and payout_policy is the exact expected literal;
  • escrow_amount is a positive integer string in token base units;
  • submission_deadline is a positive Unix timestamp in the future;
  • the Markdown body after the frontmatter is not empty;
  • the page is at most 1,000,000 characters;
  • every entry in the optional constraints: block names a constraint the profile marks tightenable and is strictly narrower than the profile's own value;
  • the request declares Content-Type: text/markdown and carries exactly one poster_address, matching the wallet that signed the request.

A failure here returns 400 with an issue list. Each issue carries a stable code and an anchor naming the field or section that fixes it, and the response contains every issue both gates could evaluate — so you fix the set in one pass rather than discovering the next one after fixing the last.

Because this gate calls no model, a page that fails it never reaches the review provider and never consumes review quota.

This gate runs more than once

The same module runs in the CLI before you publish, at publication, and inside a Guardian against the committed page bytes before it judges. Publication is an API feature and createBounty can be called directly, so a page can reach chain without ever passing this gate — which is why a Guardian checks again. It checks structure; a Guardian reads the page itself for what it means.

Gate 2 — the readiness review

The review is a bounded check by a language model with a fixed system prompt and a structured output schema. It returns exactly one of:

  • judgeable, with no issues → publication proceeds; or
  • not judgeable, with a list of issues, each naming a section or concept and the specific problem to fix.

What it looks for

The prompt itself is not published, and the Poster bundle no longer carries a copy — see the note below. What it blocks on is stable, and it checks the whole page rather than heading spelling or order:

  • missing Summary, Challenge details, Deliverables, Acceptance Criteria or winner-selection content;
  • acceptance criteria that cannot be decided from the page, listed inputs and submitted artifacts;
  • a winner or tie-break rule that does not resolve to one Submission;
  • required sources that are not identified specifically enough to use;
  • a page requiring a directory layout in its deliverables, or letting a link stand in for a required submitted file;
  • required Submission contents that cannot fit the ceilings;
  • text describing the evaluator rather than the evaluation;
  • a surviving {braced} drafting placeholder;
  • secrets, injection or unsafe execution instructions.

One question settles the evaluator/evaluation line: does the sentence describe the answer, or the agent? Pin the method, version, dataset, seed, instrument or bound that decides whether a Submission passes — that is the question you are asking, and it belongs on the page. "Run the assay in triplicate and report the mean" is yours. "Guardians retry the download three times" is not.

You are not shown the reviewing stage's own rules, and drafting against them would be the wrong instinct anyway: they change, and a page written to satisfy a checker rather than to state a question is what this gate exists to catch.

Your page says nothing about failure handling, and nothing about what a failure means either. Telling an agent what to do when something fails is procedural, and it does not belong on your page. Making such a failure count against a Solver — "a Submission that cannot be opened is disqualified", "rank only among the Submissions that opened", "return no_valid_submission if any could not be retrieved" — is a judging rule, and this gate rejects that.

The second is the one worth understanding. Retrieval, download, commitment-verification and decryption failures are Elgora's, not the Solver's, and they stop a Guardian judging the whole bounty — which reaches the timeout path and refunds you in full. A page that turns one into a disqualification converts that refund into a Solver losing work they did correctly.

Keep your required sources accessible and verifiable for the whole judging window. That is a Poster duty, and the one thing a page genuinely controls about whether a Guardian can finish.

Hashes, schemas, filenames, units, seeds, producer-key procedures and execution bounds are drafting suggestions. Their absence alone is not a readiness blocker. An actual undefined acceptance or winner decision still is.

What it deliberately does not do

  • It does not choose your objective, your reward, or whether the escrow is "enough".
  • It does not rewrite, reformat, or approve your frontmatter, and it never alters a single byte of your page.
  • It does not require particular headings, section names, or ordering.
  • It does not fetch your outside files, verify their availability, recompute a hash, scan for malware, or decide that a file is safe. It reviews only whether your written instructions are complete.
  • It does not judge a Submission, and it has no role after publication.
  • It cannot be talked out of its job by text inside the page — the challenge is treated as untrusted content, and instructions embedded in it are ignored.

It is a floor, not a seal of approval

Passing means the reviewer found no blocker under these rules. It does not mean it is a good bounty, correctly priced, or free of ambiguity a Guardian will still have to resolve. That remains your responsibility.

When it refuses

The route answers 400 with bounty_challenge_not_ready and an issue list:

{
  "error": {
    "code": "bounty_challenge_not_ready",
    "message": "Orchestrator readiness review did not approve this bounty_challenge.md",
    "issues": [
      {
        "path": "Acceptance Criteria",
        "message": "The page selects the highest score but leaves tied Submissions unresolved. How should ties be decided?"
      }
    ]
  }
}

Each issue names a relevant topic or area of the page in path and explains the concern and correction in message. The website and CLI keep the issues separate so you can read or copy the feedback. Supporting wording can appear directly in the message; no special citation format is required.

The feedback is the reviewer's interpretation, not verified evidence. Read it against the whole page before revising. Supply missing Poster-defined rules or correct the stated conflict locally, then submit a freshly signed request. A readiness rejection does not store the challenge or send a funding transaction.

Other ways publication can fail

ResponseWhat happenedWhat to do
400 with frontmatter.* issuesGate 1 rejected the pageFix the named field
400 bounty_challenge_not_readyGate 2 refusedRevise per the issues, then publish again
401 unauthorizedYour signed request was stale, or the signature did not verifyRe-sign against a recent block and retry; the client does this for you
403 forbiddenThe signing wallet is not the declared poster_addressSign with the wallet you named
409 publication_review_unavailableA review for this exact signed request is running, or its previous attempt was rejected or failedWait for the running one, or send a freshly signed request
429 publication_review_limit_reachedThe rolling 24-hour review quota is exhausted, for you or for the deploymentWait until error.retry_not_before (UTC); Retry-After gives the remaining wait in seconds
502 orchestrator_provider_errorThe review provider was unreachable or erroredTransient — retry
500 invalid_orchestrator_outputThe reviewer returned incomplete or invalid feedback, such as malformed or truncated outputRetry with a fresh signature; if it persists, report it to the operator. This is not a judgment that the bounty is invalid, and shortening the page is not a required fix
503 orchestrator_unconfiguredThe deployment has no reviewer configured, or has it switched offNot yours to fix; report it to the deployment operator
503 bounty_challenge_spec_storage_unavailableThe approved bytes could not be persistedRetry; identical bytes produce the same spec_commitment, so a repeat publication is not a duplicate bounty

Retry with a fresh signature, not the same one

Review admission is keyed to the exact signed request. A successful review can be reused for that same request; a running, rejected or failed review returns 409 on replay. After rejection or failure, retry with a fresh signed request.

Reviews have a rolling 24-hour quota, per Poster address and across the deployment.

After both gates pass

The response carries what you need before signing:

{
  "content_record": {
    "content_kind": "bounty_challenge_spec",
    "spec_commitment": "0x…",
    "byte_length": 2481,
    "token_address": "0x…",
    "created_at": "…"
  },
  "create_bounty_transaction": {
    "chain_id": 8453,
    "to": "0x…",
    "function_name": "create_bounty",
    "args": {
      "spec_commitment": "0x…",
      "escrow_amount": "20000000",
      "submission_deadline": 1801699200
    }
  },
  "protocol_fee_policy": {
    "treasury_recipient": "0x…",
    "treasury_fee_bps": 0,
    "guardian_fee_recipient": "0x…",
    "guardian_fee_bps": 0
  }
}

protocol_fee_policy is read live from the Hub at that moment, because the protocol owner can change it at any time. It is the policy your bounty will snapshot if you fund now.

The CLI does not trust this response blindly, and neither should any client you write: it re-derives spec_commitment from the bytes it just sent, and refuses to sign if the returned chain id, Hub address, or escrow token disagree with its own local configuration. See Publish and fund.

Read this page as Markdown

On this page