# Validation and publishing

> What happens when you submit a GitHub repository to Qsolve: the five stages, the checklist you see, limits and timeouts, how failures look and are fixed, and how a workflow is listed.

Source: https://qsolve.omlabs.co/docs/build/validation-and-publishing
Updated: 2026-11-13

Qsolve fetches one pinned commit, lints it, runs the gates and benchmark cases in a sandbox, publishes an immutable version, then records the cases as the track record. A repository that passes `qsolve validate`, `qsolve lint` and `qsolve test` locally passes the same checks here.

## Submitting

On the [Publish a workflow](/developers) page, choose the repository, and optionally a branch, tag or commit and a folder.

| Field | Accepted | Default |
|---|---|---|
| GitHub repository | `https://github.com/<owner>/<repo>`, up to 200 characters. A trailing `/` or `.git` is removed. Other hosts and `http://` are refused. | required |
| Branch, tag or commit | A branch or tag name, or a full 40-character lowercase commit SHA. Up to 100 characters from letters, digits and `. _ / -`, not starting with `-`. A short SHA is read as a name and will not resolve. | `HEAD`, the default branch |
| Folder | A relative path such as `workflows/max-cut`, up to 200 characters. Each part starts with a letter, digit or `_`, then letters, digits and `. _ -`. No `..`, no leading dot, no absolute path. | empty, the repository root |

Qsolve fetches exactly one commit and records its SHA, so a submission is a snapshot: later pushes do not change it.

## What you see while it is checked

The submission page shows a checklist. Finished steps are ticked, the running one spins, the rest wait, and a failed step shows a cross.

| Step shown | Stage name in the report | What it does |
|---|---|---|
| Fetch the repository | `fetch` | Gets the commit. No code runs. |
| Static checks | `lint` | The same checks as `qsolve lint`. No code runs. |
| Check cases, shots and the version | `publish-checks` | Rejects early, before any code runs: shots above 100,000, unusable benchmark or hardware case inputs, and a version that already exists with different content. Shown only when it fails. |
| Run it in the sandbox | `gates` | Runs the validation gates and every benchmark case, with no network. |
| Publish | `publish` | Stores an immutable snapshot and registers the version. |
| Build the track record | `history` | Runs the benchmark cases as ordinary platform runs and records them. |

A failed stage ends the submission; the later steps stay grey. The `history` stage never fails a submission.

| Status shown | Meaning |
|---|---|
| Waiting | Queued. |
| Checking | A stage is running. |
| Published | Every gate passed and the version is registered. |
| Needs changes | A stage failed because of your repository. The report says which and why. |
| Platform error | A problem on our side, not in your workflow. Retry. |

Open a submission to see its stages, the errors to fix first, gate details and, collapsed, the lint warnings.

## Limits and timeouts

| Limit | Value |
|---|---|
| Submissions being checked at once, per user | 2 |
| Submissions per 24 hours, per user | 10 (a retry of a failed one does not count again) |
| Repository size at fetch | 50 MB |
| Fetching the commit | 150 seconds for the download, 60 for resolving a branch name, 30 for the other git steps |
| Files and size seen by lint | 500 files, 20 MB (see `E011`) |
| Gates stage time | Your manifest `resources.timeout_s`, raised to at least 300 and capped at 7200 seconds, for the whole sandbox job including the second run of the first case |
| Gates stage memory | Your manifest `resources.memory_mb`, capped at 8192 MB |
| History stage, per case | 20 credits and 900 seconds, three cases at a time |
| A validation job that dies | Tried twice. A submission with no live job after one hour is marked as a platform error. |

The two submission limits are settings of the platform and can be changed by its operator; the numbers above are the defaults.

## Fetch

Fetching is hardened: HTTPS only, no hooks, no history, no submodules, no large-file downloads, and a size and time watchdog.

Qsolve rejects a repository that:

- is larger than 50 MB ("repository exceeds 50 MB");
- contains symbolic links ("The repository contains symbolic links, which are not allowed.") or submodules;
- cannot be resolved ("Could not resolve 'x' in this repository": a wrong name, or a private repository that is not connected);
- takes too long to fetch ("Fetching the repository timed out.");
- has no `qsolve.yaml` in the folder you entered ("No qsolve.yaml in the folder 'x' of this repository at that commit.").

## Lint

Lint errors reject the submission: "Static checks failed. Fix the errors below and resubmit." Warnings do not. The report lists each error with its code, message and file, and the stage shows the error count. Every code, its trigger and its fix is in [Lint codes](/docs/build/lint-codes).

## Gates

This is the equivalent of `qsolve test` on the `sim-cpu` target, with no network, inside the sandbox. The eight gates and the rules for each case are in [Benchmarks](/docs/build/benchmarks). A failure lists each failing gate with its detail:

```text
Validation gates failed: cases_pass, estimate_honest
cases_pass: 2/3 passed
estimate_honest: estimated 1 circuits, the run sent 12
```

If the run cannot complete, the report says "the benchmark run timed out" or "the benchmark run ran out of memory", or gives the error your code raised. Hardware cases are not run here.

## Publish

Qsolve snapshots your files, excluding tests and caches, and registers the version under your manifest's `name` and `version`. It also copies your `hardware_cases` into the version with their inputs written out. If that name and version already exist with different content, the submission is rejected right after the static checks, before the sandbox gates: "Version X of <name> already exists with different content; bump the version in qsolve.yaml and resubmit." Resubmitting identical content is accepted and changes nothing: the report says so, the latest version is not moved, and the benchmark history is not run again. A new version of a workflow you own needs only a higher `version`. See [Versioning](/docs/build/versioning).

## History

Each `cases` entry runs again as an ordinary platform run, and accuracy, cost and circuit measurements are recorded as the track record. These runs are paid by the platform, not by you. A case that runs and fails on its own terms is recorded as failed and appears in the track record. A case the platform could not run (for example an unsupported target) is not recorded and is counted in the report. If the history stage as a whole cannot run, it shows as skipped and the version stays published. How results are recorded and shown is described in [Benchmarks](/docs/build/benchmarks).

## When it fails, and sync again

| You want to | Do this | What happens |
|---|---|---|
| Check a failed submission again | **Retry** | The same submission is queued again with its report cleared, the same repository, branch and folder. It needs a free slot of the 2 in progress. |
| Pick up new commits of a published one | **Sync again** | A new submission is created for the same repository, branch and folder, and fetches the newest commit. It counts toward the 10 per day. If the manifest `version` did not change and the content did, publishing is refused until you bump it. |
| Clear an entry from your list | **Remove** | Only the list entry goes. A published workflow stays published. |

Retry and Sync again are refused while the submission is still being checked ("This submission is still being checked.").

If you fix the repository, push and press **Retry** on a failed submission that points at a branch: it fetches the branch tip again, not the old commit. A submission that pinned a commit SHA keeps failing until you submit a new SHA.

## Subfolders, branches and private repositories

- Subfolders: one repository can hold several workflows. Submit each with its folder. Lint, the gates and the snapshot use that folder as the workflow root, and every path in the manifest, schemas and benchmark cases is relative to it. The folder dropdown lists the folders that contain a `qsolve.yaml` (up to 100, at most seven levels deep).
- Branches: choose a branch, or leave the default. The dropdown lists up to 200 branches.
- Private repositories are fetched through the Qsolve GitHub app, with read-only access to the repositories you choose; see [Private repositories](/docs/build/private-repositories). A new version of a private workflow you own is fetched the same way automatically. The workflow page does not show the repository address for a private source.

## Managed accounts

Some GitHub accounts are operated by Qsolve itself and publish Qsolve's own first-party workflows. Submitting a repository of such an account is refused for everyone but Qsolve's administrators ("Repositories of that GitHub account are published by Qsolve."). If you see this message for your own repository, its owner name matches a managed account: use a different account or organisation.

## Publication and visibility

A new workflow is unlisted until it is approved but runnable by its link meanwhile, unless the operator has turned on automatic listing of validated workflows, or the developer is an administrator. Later versions of an existing workflow keep its visibility.

## How a workflow appears in the marketplace

The listing is built from your manifest and Qsolve's measurements:

- The title is your `name` with dashes turned into spaces and words capitalised. Summary, family, category and tags come from the manifest.
- The input form is built from your input schema, with your example inputs as starting points. See [Input and output schemas](/docs/build/input-and-output-schemas).
- Each method appears with the `title`, `what`, `strength` and `limit` you wrote.
- Supported targets and the envelope come from `targets` and `envelope`.
- The track record shows each benchmark case's accuracy against the baseline, its cost and its circuit and fidelity measurements, all measured by Qsolve.

For how researchers find and run it, see [What is Qsolve](/docs/start/what-is-qsolve) and [How it works](/docs/start/how-it-works).
