# 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: &#x2A;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.

<Callout title="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.
</Callout>

## 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: &#x2A;*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.

<Callout title="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.
</Callout>

## When it refuses

The route answers `400` with `bounty_challenge_not_ready` and an issue list:

```json
{
  "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

| Response                                          | What happened                                                                                     | What to do                                                                                                                                                                |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` with `frontmatter.*` issues                 | Gate 1 rejected the page                                                                          | Fix the named field                                                                                                                                                       |
| `400` `bounty_challenge_not_ready`                | Gate 2 refused                                                                                    | Revise per the issues, then publish again                                                                                                                                 |
| `401` `unauthorized`                              | Your signed request was stale, or the signature did not verify                                    | Re-sign against a recent block and retry; the client does this for you                                                                                                    |
| `403` `forbidden`                                 | The signing wallet is not the declared `poster_address`                                           | Sign with the wallet you named                                                                                                                                            |
| `409` `publication_review_unavailable`            | A review for this exact signed request is running, or its previous attempt was rejected or failed | Wait for the running one, or send a **freshly signed** request                                                                                                            |
| `429` `publication_review_limit_reached`          | The rolling 24-hour review quota is exhausted, for you or for the deployment                      | Wait until `error.retry_not_before` (UTC); `Retry-After` gives the remaining wait in seconds                                                                              |
| `502` `orchestrator_provider_error`               | The review provider was unreachable or errored                                                    | Transient — retry                                                                                                                                                         |
| `500` `invalid_orchestrator_output`               | The reviewer returned incomplete or invalid feedback, such as malformed or truncated output       | Retry 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_unconfigured`                 | The deployment has no reviewer configured, or has it switched off                                 | Not yours to fix; report it to the deployment operator                                                                                                                    |
| `503` `bounty_challenge_spec_storage_unavailable` | The approved bytes could not be persisted                                                         | Retry; identical bytes produce the same `spec_commitment`, so a repeat publication is not a duplicate bounty                                                              |

<Callout type="warn" title="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.
</Callout>

## After both gates pass

The response carries what you need before signing:

```json
{
  "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](/docs/poster/publish-and-fund).
