# Build the package

> What the client packs from your folder or file, the rules it enforces before encrypting, the size ceilings, and what must never be in a Submission.

Your Submission is whatever you point the client at: a **folder**, whose
contents become the Submission with every subfolder kept, or a **single file**,
which becomes a Submission of that one file. The client packs it, so the
folder *is* the deliverable, and it has to be exactly right before you run the
command.

You never package anything yourself. The client builds one `.tar.gz` from your
files, encrypts it, and prints `content_sha256`, a private digest of every
file's path, size and SHA-256 that the opener of the winner reports again.

## The package rules

Every rule below is checked by the client from the files themselves, before
anything is read into memory or encrypted, so a mistake fails fast and costs
nothing.

| Rule                                                                                                                                | Failure                                                                   |
| ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Regular files only: no symlinks — including the folder or file you point it at — devices, sockets or FIFOs                          | `"source/link.py" is a symbolic link…`, naming the path                   |
| No empty folders, anywhere                                                                                                          | `Folder "source/empty" is empty…`                                         |
| Not empty                                                                                                                           | `No files found in folder`                                                |
| At most **10,000 files**                                                                                                            | `The Submission holds more than 10000 files…`                             |
| Each name in a path starts with a letter or digit, then uses only letters, digits, `.`, `_`, `-`, and is at most **255 characters** | `"my file.txt" is not a valid Submission path…`                           |
| A whole path, `/` separators included, is at most **768 characters**                                                                | `"…" is 800 characters; a Submission path is at most 768.`                |
| No two paths differ only in case, and no file sits where another path needs a folder                                                | `"Result.csv" and "result.csv" differ only in case…`                      |
| Files total at most **250 MB**                                                                                                      | `The Submission holds … bytes of files and exceeds…`                      |
| The archive encrypts to at most **50 MiB**                                                                                          | `This Submission packs to … bytes encrypted and exceeds Elgora's 50 MiB…` |

`solver:submit`, `solver:check` and a Guardian's `guardian:open` then run the
same code on the packed Submission. It checks:

* the challenge's `constraints:`: `max_files`, `max_extracted_bytes`,
  `required_files`, `allowed_extensions`;
* the total size of the Submission's files against the extracted budget. An
  archive the Solver included counts at its own size here; Guardians count what
  it unpacks to once they unpack it.

`solver:submit` refuses a Submission with any issue; `solver:check` lists them
without submitting.

Folders may nest as deep as the path length allows.

```text
./solution/
  RUN.md
  results.csv
  source/
    main.py
    model/
      weights.bin
```

`elgora-cli solver:submit <bounty_id> ./solution` submits exactly that tree:
`RUN.md`, `results.csv`, `source/main.py` and `source/model/weights.bin`.

<Callout title="An archive of your own is just a file">
  If you include a `.tar.gz` or `.zip` — because the challenge asks for one, or
  because it is the natural form of your result — the client stores it as one
  file and never opens it. Pointing the client at `results.tar.gz` alone and at a
  folder holding only `results.tar.gz` submit the same thing, with the same
  `content_sha256`. Guardians unpack it when judging needs its contents, and a
  Submission whose archives unpack past the extracted budget is disqualified, so
  size them by what they unpack to.
</Callout>

## Match the challenge exactly

A published challenge cannot be changed, so match it as written.

* Use the **exact paths** the challenge names, relative to your folder. If the
  page asks for `source/main.py`, the file is `main.py` inside a `source`
  folder.
* Meet the stated formats. "UTF-8 Markdown" means UTF-8 Markdown.
* Respect the challenge's own size caps, which may be far below Elgora's.
* Include everything listed as required, and nothing the page puts out of
  scope.

Reproduce every check the challenge lets you run locally before you submit.
Most losing Submissions lose on something the Solver could have caught: a
missing file, a wrong column order, an unstated unit.

## Everything the solution needs is inside

Guardians install ordinary tooling themselves — compilers, interpreters,
general-purpose libraries and domain tools — so name what you need, with
versions. They never load any part of your **solution** from outside the
package: code, parameters, trained weights, sequences, structures, data or
results. Your Submission's bytes are fixed on chain; a link's target can change
after the Verdict is recorded.

* Your code runs with the network off. If it downloads a piece of itself, it
  fails.
* A dependency you published yourself, one named after the bounty, or one first
  released after the bounty was published counts as part of your solution and is
  not installed.
* A Guardian resolves each name you list itself, from a source it chose: an
  official registry, or the project's own canonical release when a well-known
  tool has no registry presence. What sinks a dependency is not registry
  absence but being findable only through a URL, mirror, install script or
  lockfile entry you supplied — those say what to resolve, never where.
* Vendor anything a Guardian could not identify on its own. Code, models and
  data inside the package are judged like the rest of it, so vendoring is
  always safe and never counts against you.

Anything reachable only through a link counts as missing, and fails the criteria
that needed it.

## What must never be in a Submission

* **A link standing in for a required file.** A URL, a DOI, an IPFS CID, a
  bucket path or a repository reference is not a deliverable. Guardians judge
  the bytes inside your sealed package and nothing else: they do not fetch your
  links, and content behind one can change or disappear after the deadline, so
  nothing about it is provable. A required artifact supplied as a link counts as
  missing, and the Submission is disqualified on that alone. Cite sources by all
  means — as provenance next to the bytes, never in place of them.
* Plaintext secrets, private keys, seed phrases, API keys, or credentials.
* Files unrelated to the challenge.
* Instructions addressed to the Guardian. Guardians are required to treat text
  inside submitted files as data, and a Submission that tries to steer the
  judgement is a standard disqualification condition.
* Private, licensed, or human-subject data you do not have the right to share.

<Callout type="warn" title="Your artifacts are private, not anonymous">
  The pinned Guardians can open your Submission after the deadline, and if you
  win, the funding Poster receives it. Your Solver address is public from the
  moment you submit. Nothing else about your Submission is.
</Callout>

## The ceiling, in practice

A Submission has two sizes, and they are capped separately.

**Packed: 50 MiB.** This is the encrypted object that reaches storage, and it is
the hard one — the storage bucket will not take more. Your files are encrypted
as raw bytes, so the encrypted object is the compressed archive plus 16 bytes;
nothing is re-encoded on the way. Text, CSV and code compress well, so a folder
of them can be considerably larger than 50 MiB on disk. The client builds the
archive first and checks its size before any encryption work.

**Extracted: 250 MB.** This is everything the Submission amounts to once opened
and once every archive you included in it is unpacked. A challenge may set a
lower extracted budget, and then that number applies.

These are protocol invariants, fixed by the profile a bounty declares and published
at `/api/protocol/profile/<version>`. That endpoint is the authority; the
numbers here are a restatement, held to it in CI. Where a challenge narrows one,
it declares the narrower value in its `constraints:` frontmatter, checked
against the profile before the bounty was published — so the narrower number is
already known to be a real tightening, not a claim you have to evaluate.

Keep evidence proportionate. A 30 MB model plus a 40 KB `results.md` is normal;
a 40 MB screenshot dump is not, and no criterion asks for it.
