# Synthesis handoff — 64 shipped designs, from "a model liked it" to "a vendor would accept it"

Built 2026-08-14T23:36:48Z by `scripts/export_synthesis.py` from `releases/generated/designs.jsonl`. No model call, no network call, no new score.

> **ORDER-READY MEANS A VENDOR'S INTAKE WOULD ACCEPT IT. IT DOES NOT MEAN VALIDATED.** 600 bp, inside the published composition limits, screened against the design rules the synthesis vendors publish. Nobody has synthesised any of these sequences. Nothing here has been transfected, transduced or measured in any cell. Every number beside a sequence is a prediction of one model on one checkpoint in one genomic scaffold. **The first honest thing that happens after someone presses order is an experiment.**

> **RESEARCH USE ONLY, NON-COMMERCIAL. Not wet-lab validated. Not clinical.**

---

## What is here

| file | what |
|---|---|
| `A1_cardiomyocyte__vs__hepatocyte.fasta` | **the submittable artifact** — 17 sequences, FASTA, 60 bp per line |
| `order_A1_cardiomyocyte__vs__hepatocyte.csv` | the same sequences plus the synthesizability read and the full provenance |
| `order_A1_cardiomyocyte__vs__hepatocyte.json` | the CSV's JSON sidecar — the same rows, the per-rule gate records, the vendor rules with their sources, the counts |
| `A2_skeletal_muscle_myofiber__vs__hepatocyte.fasta` | **the submittable artifact** — 47 sequences, FASTA, 60 bp per line |
| `order_A2_skeletal_muscle_myofiber__vs__hepatocyte.csv` | the same sequences plus the synthesizability read and the full provenance |
| `order_A2_skeletal_muscle_myofiber__vs__hepatocyte.json` | the CSV's JSON sidecar — the same rows, the per-rule gate records, the vendor rules with their sources, the counts |
| `CHECKSUMS.txt` | SHA-256 of every other file |

The sidecars validate against `schemas/synthesis_order.schema.json`, as every artifact in this repo does.

### The FASTA is submittable; the CSV is the informative superset

IDT's bulk entry accepts FASTA, and tab-, comma- or semicolon-delimited `Name`/`Sequence` lines, one construct per line — so the FASTA in this directory can be pasted into an order form today. **The CSV is not a vendor template.** Twist's bulk-upload template is behind a login and we have not seen it, so no vendor's column headers are reproduced here; claiming a verbatim vendor template we have not opened is precisely the small overclaim this project exists not to make.

The CSV is simultaneously an order and a provenance record. The left columns speak to the vendor — name, sequence, length, composition, the synthesizability read. The right columns speak to the collaborator deciding whether to run it — the scaffold the score was measured in, both arm scores, the margin against its own floor, the ratio to the best natural promoter in the **same** scaffold, the distance from any natural promoter, and the model, checkpoint, context digests and run behind every number. Nothing has to be reassembled by hand, and a sequence cannot travel apart from its caveats: the FASTA headers carry them too.

Two verdict columns, and they are about different things. `synthesizability_verdict` is this directory's read of vendor design rules over the sequence, with no model involved. `verdict` is the design's **margin** verdict against its own magnitude-banded noise floor, copied from the release. Neither implies the other.

---

## The result, reported rather than filtered

Gates are columns here as everywhere else in this project (`docs/decisions/GATES_AS_COLUMNS_2026-08-14.md`): a design that trips a rule still ships, marked. **The flag rate is itself the finding.**

**64 of 64 designs carry at least one advisory flag, and 0 trip a hard rule.** Every one is 600 bp, inside the global 25–65% GC band, and free of any homopolymer at or above the 14 nt hard limit. What flags is local composition and repeat structure — the kind of thing that lengthens a quote or a turnaround, occasionally costs a resynthesis, and does not stop an order.

| rule | severity | flagged, all 64 | A1 (17) | A2 (47) |
|---|---|---|---|---|
| `V1_length_in_vendor_range` | hard | 0 | 0 | 0 |
| `V2_global_gc_in_band` | hard | 0 | 0 | 0 |
| `V3_homopolymer` | hard (>= 14 nt) plus an IDT advisory | 0 | 0 | 0 |
| `V4_local_gc_window` | advisory | 0 | 0 | 0 |
| `V4b_local_gc_window_genscript` | advisory | 18 | 17 | 1 |
| `V4c_local_gc_window50_in_band` | advisory | 29 | 17 | 12 |
| `V5_repeats` | advisory | 64 | 17 | 47 |
| `V6_hairpins` | advisory | 31 | 6 | 25 |

### 1. Every design carries a repeat of 20 bp or more, and that is our doing

This is the number to read first. The generator's module-level operators are `swap`, `duplicate` and `revcomp` over 100–200 bp blocks — mechanically, a machine for producing direct and inverted repeats — and Twist publishes *"Avoid repeats of ≥ 20 bp or Tm ≥ 60°C"*, with GenScript at the same 20 bp limit. So **64 of 64 flag**, and not marginally: the longest direct repeat runs to 150 bp and the longest inverted repeat to 143 bp, against a shortest-in-set maximum of 20 bp. The check was built expecting this and it fired.

**31 of 64 designs also carry a hairpin** — a perfect 20 bp stem inside a 200 bp window, scored with dnachisel's own `AvoidHairpins` parameters. A stem is an inverted repeat at close range, so this is the `revcomp` operator's signature seen at the length scale that actually stalls a polymerase.

Neither is fatal and neither is cosmetic. A vendor may well synthesise these; it may also quote them longer, price them higher, or come back once. The honest statement is that the sequences carry a structural feature the design process manufactured, we measured it rather than discovering it at the order desk, and a future generation run that wants a cleaner synthesis profile should constrain the operators rather than filter the output.

### 2. The GC asymmetry between the two pairs is real, and smaller than it looked

An earlier read over the 30 designs shipped at the time found all 15 A1 designs flagging on local 50 bp GC and all 15 A2 designs clean. Re-derived over all 64, the direction holds and the absoluteness does not:

- **Twist's actual published rule is about the *spread*** — *"Minimize the difference in GC content between the highest and lowest 50 bp window so that it does not exceed 50%"*. Under it, **0 of 64 flag**: the largest spread measured anywhere in the set is 48 percentage points.
- **GenScript's local rule is a different rule** — *"Keep the GC% content between 25-65% within 100 bp window"* — and under it the asymmetry is stark: **17 of 17 A1** designs flag against **1 of 47 A2**. A1 is the GC-rich cardiac set, with 100 bp windows reaching 75% GC.
- **Read at 50 bp** — our own adaptation of GenScript's band to Twist's window, stricter than anything either publishes and labelled as ours — A1 stays at 17 of 17 while A2 rises to 12 of 47. That is where the earlier "all clean" reading stops holding: it was true of A2's first 15 designs and is not true of all 47.

**Twist's own pages disagree on the 50 bp figure** — 50% in the design technical note (DOC-001081 REV4.0), 52% in the Express Genes acceptance-criteria FAQ. Both were live on 2026-08-14. Both are recorded per design in the sidecars and neither is silently picked; on this set the choice changes nothing, because the largest spread is well below either.

### 3. The IDT homopolymer advisory splits the same way

IDT calls runs of ≥ 6 G/C or ≥ 10 A/T problematic — far stricter than Twist's 13 nt guidance — and **17 of 64** trip it, all of them in A1, on G/C runs of 6–7. Against Twist's and GenScript's hard limits (≥ 14 nt, > 15 bp) nothing in the set comes close: the longest homopolymer anywhere is 7 nt.

---

## What the checks are, and why they can be trusted to fire

Every check is a sliding window or a set-membership test over one string. There is no model call, no network call and no external data, so the same sequence gives the same answer on any machine. `dnachisel` is not installed here and was not added: these are all simple string computations, and a dependency to run them would be the wrong trade. The hairpin parameters are dnachisel's own defaults so the number stays comparable.

The rules and their sources live in `src/gi_promoters/synthesis.py:VENDOR_RULES` and are copied into every sidecar, each carrying the vendor, the rule as published, the URL and whether we verified it on 2026-08-14. One rule — `V4c` — is **our adaptation and says so**: GenScript's band evaluated at 50 bp rather than the 100 bp GenScript publishes.

We do **not** assign a design to a vendor's own complexity tier. Twist publishes four — Standard, Complex, Error, Not Accepted — and which one a sequence receives is the output of Twist's own intake, which is not public. A flag here means a design trips a rule Twist publishes; it is not a prediction of what Twist would return.

## Length, adapters and the product a 600 bp insert becomes

All 64 designs are 600 bp inserts. That sits inside IDT's gBlocks range (125–3,000 bp) and eBlocks range (300–1,500 bp), and above Twist's advice to keep sequences above 300 bp. **Twist's adapters are 22 nt each and sit outside the insert, so a 600 bp design ships as a 644 bp synthesis product** — the composition rules apply to the insert, the 644 bp is what arrives.

## Biosecurity screening

Synthesis orders of 200 bp or longer are screened by International Gene Synthesis Consortium members against a common Regulated Pathogen Database under the IGSC Harmonized Screening Protocol -- v3.1, 1 June 2026, succeeding the v3.0 of 3 September 2024 -- with members required to transition to a 50 bp threshold by 24 October 2026 to conform to the US OSTP Framework. Every sequence here is 600 bp, so it is screened under either threshold. Each is a non-pathogenic human regulatory sequence -- a promoter, assembled from human promoter modules -- encoding no protein and derived from no pathogen, offered for research use only. It is expected to clear screening; that is a statement about what these sequences are, not a prediction of any vendor's decision.

---

## Per pair

### A1_cardiomyocyte__vs__hepatocyte

**Ventricular cardiomyocyte ON / Hepatocyte (liver parenchymal cell) OFF.** 17 constructs, all 600 bp, scaffold FAM47C.

- Synthesizability: 0 clean, 17 carrying at least one advisory flag, 0 tripping a hard rule.
- Margins 6.3228 → 5.9169, i.e. 1.351× → 1.2643× the best natural promoter measured in the same scaffold, in the same run, under the same two context strings (TNNT2).
- Files: `A1_cardiomyocyte__vs__hepatocyte.fasta`, `order_A1_cardiomyocyte__vs__hepatocyte.csv`, `order_A1_cardiomyocyte__vs__hepatocyte.json`.

### A2_skeletal_muscle_myofiber__vs__hepatocyte

**Skeletal muscle myofiber ON / Hepatocyte (liver parenchymal cell) OFF.** 47 constructs, all 600 bp, scaffold FAM47C.

- Synthesizability: 0 clean, 47 carrying at least one advisory flag, 0 tripping a hard rule.
- Margins 4.5822 → 4.1451, i.e. 2.3083× → 2.0881× the best natural promoter measured in the same scaffold, in the same run, under the same two context strings (TRIM54).
- Files: `A2_skeletal_muscle_myofiber__vs__hepatocyte.fasta`, `order_A2_skeletal_muscle_myofiber__vs__hepatocyte.csv`, `order_A2_skeletal_muscle_myofiber__vs__hepatocyte.json`.

---

## Before you order

1. **These are hypotheses.** The ask is *"we have a design hypothesis, will you validate it with us"* — not *"here is a promoter that works"*.
2. **A margin is scaffold-bound.** Every score here was measured with the design substituted for the proximal promoter of one fixed real gene TSS window (FAM47C). The identical 600 bp ALB promoter scores −0.012 in one admitted scaffold and +4.844 in another. Only the ratio to the best natural promoter in the same window crosses.
3. **A cassette is a different regime.** These designs were evolved and scored in a genomic window, not in an AAV or plasmid cassette, which is out of distribution for this model. Whatever construct you build, the promoter's behaviour in it is unmeasured.
4. **There is no cross-model corroboration** and nothing here is wet-lab validated.
5. **Research use only, non-commercial.** Nothing here is clinical, diagnostic or therapeutic.

Release `gi-promoter-atlas-designs-2026-08-05` v1.0.0. Model `g0-expression`, checkpoint 20260523. Unit: log(TPM+1), natural log of quantile-normalised TPM plus one.

