# Version 1 protocol and bounded behavior

## Requests

```json
{"version":1,"sequence":"GTAC","topology":"circular","enzymes":[{"name":"synthetic","motif":"ACGT","top":1,"bottom":3}],"policy":"certain"}
```

Only these keys are accepted. `policy` is optional; the others are required. Topology is `linear` or `circular`; policy is `certain`, `possible`, or `reject`. Numeric fields must be integral signed 32-bit values, then satisfy domain-specific bounds. Unknown keys, wrong types, invalid DNA and duplicate model names fail. JSON duplicate object keys follow the upstream parser's last-value behavior; this is not a duplicate-key-detecting or cryptographically canonical JSON format. Do not use it as an authorization/signature encoding.

Request DNA/model construction always validates private models. Lowercase DNA normalizes to uppercase; whitespace, RNA U, gaps, empty sequences and non-ASCII bases fail. No automatic whitespace removal from JSON DNA.

## Reports

Wrapper: `{"version":1,"kind":"moonrestrict.digest","digest":...}`.
The typed body contains `topology`, `source_length`, `sites`, `cuts`, `fragments`, `policy`.
Enum spellings in reports are the generated MoonBit forms (`Linear`, `Circular`, `Forward`, `Reverse`, `Certain`, `Possible`, `CertainOnly`, `IncludePossible`, `RejectPossible`), not the lowercase request vocabulary.
Sites contain `enzyme,start,orientation,top,bottom,stagger,certainty,cuttable`.
Fragments contain `start,length,sequence,circular`.

`read_report` enforces decoded-shape roundtrip equality to reject fractional integers, missing/defaulted fields and extra body fields. Parsing alone never proves correctness: call `Request::verify` with the original request, or `verify_digest` with the original DNA/models. Public report arrays are mutable and must be reverified after edits. The request-specific verifier additionally enforces the original ambiguity policy.

`write_report` is a low-level serializer without a size limit; a huge library report may exceed the decoder limit. `run_json` rejects oversized serialized output rather than emitting a report its decoder cannot read. JSON sizes are measured in MoonBit string code units, not transport bytes; valid DNA is ASCII, while wrappers may contain Unicode. Consumers must also bound raw transport byte sizes.

## Formats

FASTA uses upstream `genetic_code` parsing; any recoverable issue becomes an atomic failure. There must be 1–64 records with valid, unique identifiers, IDs up to 128 units and total DNA up to 100,000 bases. Descriptions are dropped by serialization. Writing uses printable ASCII identifiers, 60-base lines, and reparses output. All records use the supplied topology; mixed topology is not encoded in FASTA.

TSV begins with exact `name\tmotif\ttop\tbottom`, followed by four tab-separated columns. Blank lines and `#` comments are ignored; signed offsets use a strict decimal grammar. Model names are case-sensitive and must be unique. These are synthetic model definitions, not an enzyme catalogue.

## Resource ceilings

| Input/work | Ceiling |
|---|---|
| DNA | 100,000 bases, nonempty |
| Model name / motif | name 1–64 ASCII identifier characters; motif 1–64 IUPAC bases |
| Offsets | −64 through 128 relative to motif start |
| Batch | 32 distinct model names |
| Recognition work | `n * motif_length <= 10,000,000` per scan; summed product <= 20,000,000 per batch (both orientations are a constant factor) |
| Sites | 10,000 per scan and aggregate batch |
| JSON | 2,000,000 string units, nesting depth <= 32 |
| FASTA | 1,000,000 string units, 10,000 lines, 64 records, total DNA 100,000 |
| TSV | 16,384 string units; 32 models |
| Partial subsets | <= 12 unique cuts; requested outputs 1–64; outputs × source length <= 2,000,000 |
| Annotation | <= 128 unique IDs; annotation count × source length <= 4,000,000 |
| Ends | non-blunt 1–192 IUPAC bases; blunt sequence empty |
| Panel | 2–32 rows, 1–32 equal-width columns, total signature text <= 1,000,000 |

Oversized data is refused, not silently truncated. Partial-digest enumeration is the exception explicitly requested by the caller: ascending bitmasks return a bounded prefix with `total_subsets` and `truncated`. It starts with the uncut case, is based on certain-only complete cuts, rejects an invalid full-cut geometry before subset enumeration, and makes no probability/kinetic claims.

## Diagnostics

Errors are `InvalidInput(code)`, `LimitExceeded(code)`, or `CutConflict(code)`.
Representative stable codes: `JSON_VERSION`, `JSON_INTEGER`, `JSON_UNKNOWN_FIELD`, `REPORT_SCHEMA`, `REPORT_NONCANONICAL_SCHEMA`, `VERIFY_POLICY`, `VERIFY_EVIDENCE`, `VERIFY_INTERVAL`, `VERIFY_BASE`, `SAME_TOP_DIFFERENT_BOTTOM`, `CROSSING_STRANDS`, `SITE_MAX_10000`, `BATCH_SCAN_WORK`, `JSON_DEPTH_32`, `REPORT_BYTES`.
Do not rely on human-readable panic formatting. CLI stdout's first record carries a JSON error; nonzero process status is the portable failure signal. User sequence contents are not copied into diagnostic codes.
