User guide
Start with a whole isolate assembly in FASTA format. Pterobacter keeps all supplied records, including plasmids and short contigs, and reports the most specific supported call with its reasons.
| Task | Guide |
|---|---|
| Install from the private source | Installation |
| Install and verify managed components | Database management |
| Verify explicit reference paths | Reference setup |
| Analyse one assembly or a batch | Running Pterobacter |
| Find the answer and warnings | Reading results |
| Investigate an uncertain result | Boundary review and worked example |
| Check which taxa are represented | Reference coverage |
| Understand sequence typing | MLST |
| Interpret a genomovar match | Genomovar matches |
| Resolve a failed run | Troubleshooting |
Use one isolate assembly per input. Reads, metagenomes and mixed samples are outside the supported input. Query quality control is your responsibility; the program does not run CheckM2 and a completed report does not certify purity.
The full command-line help lists all options exactly as ptero --help prints them.
The report reference describes every output field and includes a separate illustrative manual-review recipe. The command reference covers advanced ANIm settings, cache verification and exit codes. The published reference database can be installed with ptero database install 2026-10-15.
Install Pterobacter
Build from the private source if you have repository access. Distribution is on hold during repository review; no public binary, crates.io package, Bioconda package or Homebrew formula is currently offered.
Linux source build
Install Rust and GNU C++ with C++17 support, then obtain the source:
git clone git@github.com:mbhall88/pterobacter.git
cd pterobacter
cargo install --path . --locked
ptero --version
pterobacter --version
Both installed names run the same program. Use pterobacter if another installed tool already uses ptero. Cargo’s installation directory must be on your PATH. It is usually ~/.cargo/bin.
To build without installing, use:
cargo build --release --locked
./target/release/ptero --version
For a debug build, use cargo build --locked and ./target/debug/ptero. These local paths apply to cargo build; cargo install makes the commands available through Cargo’s bin directory.
The measured Linux build used Rust 1.95.0 and GCC 11.5.0 on x86_64 Red Hat Enterprise Linux 9.8. The binary links system C/C++ libraries; the inspected build requires glibc symbols through 2.34. These describe the tested build, not a minimum Rust version or compatibility guarantee for every Linux system. The source includes Rust and embedded C/C++.
macOS source build
Install the Xcode command-line tools and Homebrew GNU GCC. Native builds discover installed Homebrew GNU C++ automatically; an explicit Apple clang override is refused by the pinned native build:
xcode-select --install # skip if already installed
brew install gcc
cargo install --path . --locked
Discovery checks the installed gcc prefix and supports Apple Silicon and Intel Homebrew locations. Explicit compiler overrides retain cc-rs precedence; empty or whitespace-only values fail with a variable-specific error. Unset the variable to request discovery. Keep the compiler’s GNU C++ runtime available. macOS CI build/test smoke and the fixed scientific parity panel on an Apple Silicon Mac have passed. Linux ARM and Windows are untested. The native build currently targets Linux and macOS.
Build offline
First provision Rust, GNU C++, the source and its locked Cargo dependencies through a cache or vendor directory. From that provisioned source tree:
CARGO_NET_OFFLINE=true cargo install --path . --locked --offline
An uncached machine still needs to obtain those prerequisites. At runtime the program embeds skani, MUMmer4 and the MLST matcher; no external analysis executable is required.
Next: reference data
Classification needs reference data separately from the executable. Run ptero database install 2026-10-15, then follow database setup and run an assembly. The current source version is 0.0.0; retain the supplied source commit and binary identity with your analysis record.
For test commands and the optional development binary, see Contributing. Release preparation records the checked platforms and publication steps.
Planned release downloads
Release preparation now builds a Cargo package and precompiled Linux x86_64 and Apple Silicon macOS archives. They are not published yet; use the source installation above until the first approved release. The Linux binaries use glibc and the GNU C++ runtime. The macOS binaries require Homebrew GCC and XZ runtime libraries, available with brew install gcc xz. Each archive records its actual runtime-library requirements and includes licences and checksums. Complete corresponding source is supplied separately beside the binaries.
Docker
A minimal Docker image can be built from source. See containers for database and assembly mounts. GHCR publication is prepared for the first approved release.
Containers
The Docker image is prepared for GHCR but has not been published yet. Until the first release, build it from a source checkout:
docker build --platform linux/amd64 -t pterobacter:local .
docker run --rm pterobacter:local --version
The tested platform is Linux x86_64. On an Apple Silicon Mac, Docker can emulate it with --platform linux/amd64; native Linux ARM support has not been validated.
The image contains both ptero and pterobacter, including the alignment and MLST engines. It runs as an unprivileged user and contains no compiler or reference database. Versioned release images will be at ghcr.io/mbhall88/pterobacter:VERSION.
Download the database once
Use a host directory for the database so it survives removal of the container. The commands below use your own user ID so files belong to you:
mkdir -p database
docker run --rm --platform linux/amd64 \
--user "$(id -u):$(id -g)" \
-v "$PWD/database:/database" \
pterobacter:local database install 2026-10-15
This installs the reference sketches, alignment sequences and MLST data. Add --no-mlst to opt out of downloading MLST data. See database management for verification and storage requirements. Use local storage with atomic rename support; a container does not change the capabilities of an underlying network filesystem.
Classify an assembly
Put isolate.fasta in the current directory, then run:
docker run --rm --platform linux/amd64 \
--user "$(id -u):$(id -g)" \
-v "$PWD/database:/database" \
-v "$PWD:/work" \
pterobacter:local --threads 2 \
--output isolate.json --report-dir isolate-report isolate.fasta
The report and alignment evidence stay in the mounted working directory. Choose new output names for another run. ANIm and MLST are enabled by default; use --no-anim or --no-mlst to skip either. See running assemblies and reading results.
Without arguments, the image shows command help. A small init process starts Pterobacter and forwards signals to it. Keep that entrypoint for normal use; it also gives alignment workers the parent process they require. To use the longer command name:
docker run --rm --entrypoint /usr/bin/tini pterobacter:local -- pterobacter --help
Release provenance
The Distribution workflow tests the image with synthetic assemblies, including ANIm and MLST, without network access and with a read-only image filesystem. It retains the tested image and its receipt before publication. The approved release workflow uploads complete corresponding source before pushing that same image to GHCR; it refuses to replace a version tag whose image differs. PR checks never push images.
The combined executable is GPL-3.0-or-later. Notices are in /usr/share/doc/pterobacter/; complete corresponding source is supplied with the matching GitHub release. The image uses Debian runtime libraries, which retain their own licences. The receipt records the source commit, image identity, platform and archive checksum. Use a version tag or registry digest when recording an analysis.
Set up the reference data
Use database management to install a trusted version once, then select it when classifying assemblies. The installer accepts local archives and supports catalogue-pinned HTTPS downloads. This build pins the published 2026-10-15 database; run ptero database install 2026-10-15 to install its sketches, genome FASTAs and MLST scheme.
If you already have unpacked reference directories and their trusted manifest hashes, you can use them directly as shown below.
Keep the directory intact. Before analysis, the program checks the manifest against the supplied digest, then verifies its listed files and metadata. It checks the package again before publishing results. A checksum computed from an untrusted download does not establish the package’s origin.
Use the supplied directory
Set these shell variables to the path and digest in your trusted handoff:
REFERENCE_PACKAGE=/path/to/reference
REFERENCE_SHA256=THE_TRUSTED_PORTABLE_JSON_SHA256
ANIM_REFERENCE_PACKAGE=/path/to/reference-fastas
ANIM_SHA256=THE_TRUSTED_ANIM_JSON_SHA256
Replace these placeholders with the two directories and their supplied digests. These variables are shell conveniences for the explicit-directory workflow; pass them with each invocation:
ptero --no-mlst --reference-package "$REFERENCE_PACKAGE" --expected-sha256 "$REFERENCE_SHA256" \
--anim-reference-package "$ANIM_REFERENCE_PACKAGE" --expected-anim-sha256 "$ANIM_SHA256" \
--anim-output isolate-alignments \
--output isolate.json --report-dir isolate-report isolate.fa
This explicit-path example skips MLST. To include it, omit --no-mlst and supply the MLST package and digest.
Reuse the same package for another assembly or batch. Do not move output files into the reference directory. The coverage guide describes which names and groups it represents.
Alignment references and MLST
The default analysis starts with skani and adds MUMmer4 alignments for eligible borderline queries. Supply the matching whole-assembly reference FASTA directory and its trusted anim.json digest so those comparisons can run. The command reference gives the complete invocation. A query that needs alignments fails with an incomplete report if this component is absent; it never silently switches to skani-only classification. To choose skani only, add --no-anim and omit --anim-reference-package, --expected-anim-sha256 and --anim-output.
Managed database installation includes MLST, and typing runs by default. Use --no-mlst on installation or classification to opt out. An explicit scheme directory and trusted manifest.json digest are also supported. Follow MLST setup. Typing does not change classification.
Once the executable and required components are installed, classification is offline. Use ptero database list to inspect installed versions and ptero database verify VERSION to recheck their contents.
Analyse assemblies
Pass one whole isolate assembly per FASTA input. Keep plasmids, draft contigs and short records: no manual chromosome selection is required. Gzip, bzip2, xz and zstd FASTA are supported. Reads, metagenomes and mixed samples are outside the supported input.
First install the program and install the database.
One assembly
ptero --threads 2 --output isolate.json --report-dir isolate-report isolate.fa
Open isolate-report/report.md for the answer and warnings. The full JSON is in isolate.json and isolate-report/report.json; reading results explains the fields. Without --output, the full JSON goes to standard output. --report-dir adds the report files without changing that destination.
A batch
ptero --jobs 2 --threads 2 --output batch.json --report-dir batch-report \
isolate_1.fa isolate_2.fa
The main JSON is an array in input order. calls.tsv has one row per assembly, and report.md has a section for each. Inspect every input’s execution status; a failure in one input does not erase a completed result from another. --jobs controls concurrent assemblies; --threads controls the embedded search threads within each assembly. Two jobs with two threads each allow up to four search threads. See the complete synthetic batch outputs.
A list of assemblies or named samples
For many files, put the paths in a list instead of on the command line:
ptero -j 2 -t 2 -o batch.json -d batch-report --input-list assemblies.txt
assemblies.txt holds one assembly path per line, as UTF-8 text. Blank lines are skipped and Windows line endings are accepted. Every other character on a line belongs to the path, including spaces, and there is no comment syntax. A relative path is read from the directory that holds the list, not from where you run the command.
To report your own sample names, use a sample sheet instead. It is a tab-separated UTF-8 file with the header sample and path, then one row per assembly:
sample path
EC-001 assemblies/EC-001 contigs.fa.gz
EC-002 /data/run7/EC-002.fasta
ptero -o batch.json -d batch-report --sample-sheet samples.tsv
Each row needs exactly two fields, both filled. Names and paths must each appear once; two spellings of the same file, or a link to it, count as the same path. For a single assembly given on the command line, --sample-name NAME sets its name.
Use one input source per run: assemblies on the command line, --input-list or --sample-sheet. --sample-name works only with one command-line assembly. Reports keep the supplied order. Each input still gets its own execution status, so a missing or unreadable file fails only its own row. A malformed list or sheet, a repeated name or path, or a conflicting option stops the run with exit code 2 before any output is created.
A sample name is a label for the reports. It appears as input.sample_name in the JSON, in the sample_name column of both TSV files and in the section headings of report.md. It never names an output file: the files inside --report-dir keep their fixed names. The analysis uses the file path, exactly as it would for the same path given on the command line, so naming a sample never changes a measurement or a call.
All output files and report directories must be new, distinct, outside reference-package directories and not nested within one another. Outputs can sit beside the input assembly, but must not replace it. The program refuses existing paths. Analysis makes no network request after provisioning.
Common controls
| Option | Use |
|---|---|
-t, --threads N | Search threads per assembly; default 1. |
-j, --jobs N | Assemblies analysed concurrently; default 1. |
-f, --input-list FILE | Read assembly paths from a file, one per line. |
-F, --sample-sheet FILE | Read sample names and assembly paths from a TSV with the header sample and path. |
-N, --sample-name NAME | Name the one assembly given on the command line. |
-o, --output FILE | Save the JSON to a new file. |
-d, --report-dir DIR | Add readable Markdown and TSV reports in a new directory. |
-n, --no-anim | Use skani only, without alignment rescue. Omit the alignment package/evidence options with this flag. |
-h, --help | Show the complete current option list. |
MLST runs by default; use --no-mlst to skip it. The command reference covers boundary ANIm, its reference components, resource limits and verified alignment caching. The default uses skani plus MUMmer4 rescue. For skani only, use:
ptero -n -r "$REFERENCE_PACKAGE" -R "$REFERENCE_SHA256" -t 2 -o isolate.json -d isolate-report isolate.fa
Command-line help lists every short and long option.
Read your results
The default rescue-mode JSON records species_id and subspecies_id at the top level. With --no-anim, the skani-only format records them under assignment. Saved examples retain the mode that produced them; the Markdown and TSV reports provide a common reading format.
Open report.md in the directory you supplied with --report-dir. Start with the final call, reasons and warnings, then examine the supporting comparisons. Use calls.tsv for a batch overview and JSON for a pipeline.
Find the answer
| File | Use |
|---|---|
report.md | Read the result, warnings and comparison tables. |
calls.tsv | One row per assembly with final calls and reasons. |
report.json | Full authoritative report, including versions and provenance. |
evidence.tsv | Supporting reference comparisons and challenges. |
The JSON sent to standard output or --output FILE contains the same report as report.json. TSV and Markdown are derived from it. One input produces an object; a batch produces an array.
The public-genome examples include a species/subspecies assignment with ST286 and a genomovar match, plus an unresolved species call with ST2274. They contain real JSON, TSV and readable reports, with download and reproduction commands.
Separate a call from its nearest reference
calls.tsv reports assigned when the rules support a species, unresolved when a completed run cannot support one, and not_evaluated when no decision was reached. A species can be assigned while subspecies or genomovar remains empty. Withheld assignment fields are null in JSON and empty in the TSV.
A nearest-reference name can still appear beside an unresolved result. Read it as comparison evidence, not as the assigned name. Reasons explain the withholding. Execution errors are separate: check execution_status, execution_stage and execution_error in the TSV, or execution in JSON. Some later-stage failures retain independently supported parent calls; inspect each rank and the failure rather than treating the whole row as a biological negative.
Read the warnings
A genomovar match means compatibility with the supplied definition. It cannot prove that the query’s source group is represented: an unrepresented group can match a neighbour. Overlapping compatible groups are withheld; one-member groups carry a sparse-reference warning. Genomovar matches explains these limits.
ANI and aligned fraction are percentages. An aligned fraction of 0.8 means 0.8%, while 80 means 80%. Missing comparisons are not zero ANI or evidence against an unmeasured rival. A clean report does not certify assembly purity.
For an uncertain call, follow boundary review. The report reference preserves exact field names, method-specific measurements, competitor completeness and version fields. The candidate ANIm workflow retains not_yet_validated in its output; this documentation does not change that status.
Try two real genomes
These examples use public NCBI assemblies and the published database 2026-10-15. They show what the tool actually writes, including MLST alleles, a genomovar match and an unresolved species call.
| Assembly | Strain | Pterobacter result | MLST | Genomovar |
|---|---|---|---|---|
| GCA_013738375.1 | RHBSTW-00333 | E. xiangfangensis subsp. hoffmannii | ST286 | GV10 |
| GCA_043966805.1 | ECC-219 | Species unresolved after ANIm | ST2274 | Withheld |
Walk through the assigned genome · Walk through the unresolved genome
NCBI calls the first assembly E. hormaechei and the second Enterobacter sp. ECC-219. Pterobacter uses its documented taxonomic framework; the xiangfangensis subsp. hoffmannii combination is proposed. These are demonstrations, not an independent accuracy test. The first genome is itself a diversity reference and a member of the database’s GV10 definition.
Run them yourself
After installing Pterobacter, download and run the reproduction script. It requires Bash, curl, gzip and either sha256sum or shasum:
curl --fail --location \
https://mbhall88.github.io/pterobacter/examples/public/reproduce.sh \
--output reproduce.sh
bash reproduce.sh pterobacter-example
The script creates a new directory and refuses to overwrite an existing one. It downloads both whole assemblies, verifies their FASTA checksums, installs database version 2026-10-15 including MLST, and runs one assembly and a two-assembly batch. Allow roughly 1 GB for the database, inputs and results, plus alignment working space. Use local storage that supports the database installer’s atomic operations.
The classification commands inside that directory are:
ptero --database 2026-10-15 --database-dir ./database --threads 2 --sample-name RHBSTW-00333 \
--anim-output single-alignments --output single.json --report-dir single \
GCA_013738375.1.fna
ptero --database 2026-10-15 --database-dir ./database --threads 2 --jobs 1 --sample-sheet samples.tsv \
--anim-output batch-alignments --output batch.json --report-dir batch
Both assemblies are supplied whole. RHBSTW-00333 has eight records, including its plasmids; ECC-219 has one chromosome record. MLST and ANIm are enabled by default. Only ECC-219 needs ANIm in these examples.
Inspect the saved outputs
| Run | Readable report | Calls | Comparisons | Full JSON |
|---|---|---|---|---|
| RHBSTW-00333 alone | Markdown | TSV | TSV | JSON |
| Both assemblies | Markdown | TSV | TSV | JSON |
The files are unedited outputs from source commit 0944f6d13b989f0329a6c266dbc9e20340fde58d, which reports software version 0.0.0 before the first release. Provenance records the source, database, input and output hashes. The checksums cover the saved reports and reproduction script.
For the exact implementation, build the source commit recorded above; later software versions may change results. Your local paths, process identifiers, timings, resource limits and software version will differ. Use the recorded assembly and database hashes when comparing results; byte-identical report files are not expected across machines. The saved reports retain the tool’s not_yet_validated metadata value; these examples do not change that status.
MLST uses PubMLST submissions through 31 December 2024. An ST describes an allele profile, not a species assignment: ECC-219 demonstrates that distinction. See MLST for scheme limits and genomovars for the scope of a GV match.
Assigned genome: RHBSTW-00333, ST286
GCA_013738375.1 is a public whole assembly with a chromosome and seven plasmids. The reproduction script supplies all eight records.
| Result | Value |
|---|---|
| Species | Enterobacter xiangfangensis |
| Subspecies | E. xiangfangensis subsp. hoffmannii — proposed combination |
| MLST scheme | ecloacae |
| Sequence type | ST286 |
| MLST state | exact_profile_match |
| Genomovar | ECTX-GV-2026-10-02-v1-GV10 |
| ANIm | Not triggered: skani already supports the call |
The seven MLST allele IDs are:
| dnaA | fusA | gyrB | leuS | pyrG | rplB | rpoB |
|---|---|---|---|---|---|---|
| 59 | 64 | 81 | 9 | 79 | 37 | 38 |
An excerpt selected from the actual mlst object:
{
"scheme": "ecloacae",
"sequence_type": "286",
"state": "exact_profile_match",
"status": "complete",
"alleles": {
"dnaA": "59", "fusA": "64", "gyrB": "81", "leuS": "9",
"pyrG": "79", "rplB": "37", "rpoB": "38"
}
}
This assembly is included among the database’s diversity references and genomovar members. Its strongest species reference is therefore itself: 100% skani ANI, with 99.99% aligned fraction on each side. That makes it a useful installation and output example, not a test of generalisation to an unseen genome. The GV10 call also checks compatibility with the other members of its definition; it is an operational match, not proof of a population boundary.
The database’s proposed subspecies name differs from NCBI’s E. hormaechei label. Supported taxa explains the naming framework. MLST remains a separate result and does not determine that name.
Full readable report · JSON · Calls TSV · Evidence TSV · Download and run
Unresolved genome: ECC-219, ST2274
GCA_043966805.1 is a public chromosome assembly labelled Enterobacter sp. ECC-219. It is the second row in the batch report.
| Result | Value |
|---|---|
| Species | Unresolved |
| Subspecies / genomovar | Withheld |
| MLST | ST2274, exact_profile_match |
| Closest species reference | E. nematophilus type anchor, GCA_026344075.1 |
| skani ANI | 94.83% |
| skani aligned fraction | 82.65% query; 88.26% reference |
| Reciprocal ANIm | 95.02965% and 95.03431% |
| Lowest ANIm aligned fraction | 84.94% |
| Reason | ANIm_no_strict_witness |
The genome falls in the range where the tool runs ANIm. That comparison finishes successfully, but neither orientation exceeds the required 96% ANI. The species stays unresolved despite adequate aligned fraction. Empty species fields here are intentional, not missing output or an execution failure.
MLST still finds the complete seven-locus profile:
| dnaA | fusA | gyrB | leuS | pyrG | rplB | rpoB |
|---|---|---|---|---|---|---|
| 590 | 263 | 415 | 493 | 302 | 170 | 101 |
The full JSON contains mlst.sequence_type: "2274" alongside species_name: null. An ST is an allele-profile identifier; it does not establish species membership. Do not copy nematophilus from the nearest-reference table into the assigned-species field.
To investigate further, follow boundary review. Keep the original automatic report and record any subsequent expert interpretation separately.
Full batch JSON · Calls TSV · Evidence TSV · Download and run
Check reference coverage
Check this table before interpreting a name. It describes the reference package 2026-10-06.proposal1, not independent prediction accuracy or every possible member of the genus. Names and their formal status follow the package’s dated registry; proposed combinations remain proposals.
Naming-status links lead to the current List of Prokaryotic names with Standing in Nomenclature (LPSN). The table retains the package’s dated status; a current registry update does not revise the package. Proposed combinations have no corresponding validated entry here and remain linked through the package registry.
The main comparison contains 140 whole-assembly references. A separate genomovar component contains 173 historical chromosome record sets across 25 definitions within the proposed hoffmannii subspecies. Together they are 313 scoped records from 305 accession versions, with eight accessions shared between components. Historical chromosome selection does not imply every plasmid label was biologically resolved.
| Name | Supported rank | Primary references | Type-anchor assemblies | Naming status | Practical qualification |
|---|---|---|---|---|---|
| Enterobacter adelaidei | Species | 1 | 0 | Provisional name; not validly published | One development reference; Provisional name; The reported proposed type is not in this package |
| Enterobacter asburiae | Species | 8 | 2 | Validly published name | Historical type has a quality-control exception; it is not automatically used as the sole operational reference |
| Enterobacter bugandensis | Species | 8 | 1 | Validly published name | No additional registry qualification |
| Enterobacter cancerogenus | Species | 3 | 1 | Validly published name | No additional registry qualification |
| Enterobacter chengduensis | Species | 3 | 2 | Validly published name | No additional registry qualification |
| Enterobacter chinensis | Species | 1 | 1 | Validly published name | One reference; Within-taxon diversity is not represented |
| Enterobacter chuandaensis | Species | 4 | 1 | Validly published name | No additional registry qualification |
| Enterobacter cloacae | Species | 13 | 2 | Validly published name | No additional registry qualification |
| Enterobacter hormaechei | Species | 5 | 1 | Validly published name | The existing type anchor is retained; Whole-assembly sensitivity and reassembly caveats apply |
| Enterobacter huaxiensis | Species | 1 | 1 | Validly published name | One reference; Within-taxon diversity is not represented |
| Enterobacter kobei | Species | 8 | 1 | Validly published name | Historical type has a quality-control exception; it is not automatically used as the sole operational reference; DSM 13645 anchor is retained; The JCM 8580 label does not establish isolate identity |
| Enterobacter ludwigii | Species | 8 | 1 | Validly published name | No additional registry qualification |
| Enterobacter mori | Species | 8 | 2 | Validly published name | Historical type has a quality-control exception; it is not automatically used as the sole operational reference |
| Enterobacter nematophilus | Species | 1 | 1 | Validly published name | One reference; Within-taxon diversity is not represented |
| Enterobacter oligotrophicus | Species | 1 | 1 | Validly published name | One reference; Within-taxon diversity is not represented; Uses the corrected whole-assembly source; The older truncated assembly is not a substitute |
| Enterobacter pasteurii | Species | 2 | 1 | Validly published name | No additional registry qualification |
| Enterobacter pseudoroggenkampii | Species | 4 | 1 | Validly published name | No additional registry qualification |
| Enterobacter quasihormaechei | Species | 1 | 1 | Validly published name | One reference; Within-taxon diversity is not represented |
| Enterobacter roggenkampii | Species | 14 | 2 | Validly published name | No additional registry qualification |
| Enterobacter siamensis | Unsupported | 0 | 0 | Validly published name | No verified type genome or reference is present; No supported positive call |
| Enterobacter sichuanensis | Species | 4 | 1 | Validly published name | Historical type culture provenance is conflicting; Explicit supplementary evidence is needed for interpreting that anchor |
| Enterobacter soli | Species | 2 | 1 | Validly published name | No additional registry qualification |
| Enterobacter vonholyi | Species | 7 | 1 | Validly published name | No additional registry qualification |
| Enterobacter wuhouensis | Species | 3 | 1 | Validly published name | No additional registry qualification |
| Enterobacter xiangfangensis | Species | 30 | 6 | Recorded as a validly published synonym | A peripheral member remains species-only; No subspecies is forced for that member |
| Enterobacter chengduensis subsp. chengduensis | Subspecies | 2 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status |
| Enterobacter chengduensis subsp. rongchengensis | Subspecies | 1 | 1 | Proposed subspecies combination; formal status not validated | One reference; Within-taxon diversity is not represented; Subspecies naming is a project proposal with unvalidated formal status |
| Enterobacter cloacae subsp. cloacae | Subspecies | 8 | 1 | Validly published name | No additional registry qualification |
| Enterobacter cloacae subsp. dissolvens | Subspecies | 5 | 1 | Validly published name | No additional registry qualification |
| Enterobacter roggenkampii subsp. quasiroggenkampii | Subspecies | 6 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status |
| Enterobacter roggenkampii subsp. roggenkampii | Subspecies | 8 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status |
| Enterobacter xiangfangensis subsp. hoffmannii | Subspecies | 8 | 3 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status; A peripheral member remains species-only; No subspecies is forced for that member |
| Enterobacter xiangfangensis subsp. oharae | Subspecies | 5 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status; A peripheral member remains species-only; No subspecies is forced for that member |
| Enterobacter xiangfangensis subsp. steigerwaltii | Subspecies | 8 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status; A peripheral member remains species-only; No subspecies is forced for that member |
| Enterobacter xiangfangensis subsp. xiangfangensis | Subspecies | 8 | 1 | Proposed subspecies combination; formal status not validated | Subspecies naming is a project proposal with unvalidated formal status; A peripheral member remains species-only; No subspecies is forced for that member |
Species and subspecies rows overlap: do not add their counts. A type-anchor count is a count of assembly records, not necessarily distinct type strains. A one-reference group does not represent within-taxon diversity. E. siamensis has no verified reference here and cannot receive a supported positive call. Seven other context lineage concepts are retained separately; none has a positive lineage membership caller.
The asburiae, kobei and mori type exceptions retain their original accessions and warnings. Hormaechei retains its type with scope/reassembly qualifications; sichuanensis retains its culture-provenance caveat. Oligotrophicus uses the corrected whole source rather than the older truncated archive. The xiangfangensis naming status is the registry snapshot; this software does not make a nomenclatural act.
For exact concept IDs, raw status values and qualifications, see the registry appendix. Accession-level details remain in the authenticated package’s historical_types.tsv, primary_references.tsv, named_registry.tsv and lineage_registry.tsv. Manifest SHA-256: 5743c25bcd706242ff8a28863fd6af2bf60e76f4c6af8b50d3f77deaf2e01dae.
A unique genomovar match means compatibility with a supplied definition. An unrepresented group may match a neighbouring group; overlap is withheld and one-member groups retain a warning. See genomovar matches.
Genomovar reporting
Look for a genomovar only after an eligible species and subspecies call. In this reference package the definitions cover the proposed Enterobacter xiangfangensis subsp. hoffmannii: 25 informal chromosome ANI groups built from 173 historical chromosome members. They are not formal taxonomic names.
A match requires sufficient ANI and coverage to every member of exactly one definition, with measured evidence excluding the alternatives. The query remains the whole assembly as supplied; the reference definition uses historical chromosome record sets. A missing rival comparison can block the match.
A unique result means compatibility with the supplied definition. An unrepresented group can match a neighbouring group, so the result does not prove that the query’s source group is present in the database. Two compatible groups are withheld, rather than choosing the nearest one. Fifteen of the definitions have only one member; matching one carries a sparse-reference warning and does not establish its population boundary.
Read the genomovar section for the result, reasons, warnings and member comparisons. A withheld genomovar does not by itself erase a supported species or subspecies call. A candidate ANIm species rescue supports neither subspecies nor genomovar; custom thresholds do not support a genomovar either.
Two queries with the same result are not necessarily at least 99.5% ANI to each other. ST does not break a genomovar tie. Exact gates and reason codes follow below. For deeper investigation, use boundary review.
What is a genomovar?
Rosselló and colleagues introduced the term for genomic groups within a named species in their 1991 study, Genotypic and phenotypic diversity of Pseudomonas stutzeri. For the more recent use of 99.5% ANI to describe within-species units, see Rodriguez-R et al. (2024). The definition below is specific to this reference collection.
Definition and reporting contract
A genomovar is an informal chromosome ANI group within Enterobacter xiangfangensis subsp. hoffmannii (ECTX-SS007, Group A), the project’s proposed combination. The definition is frozen as 2026-10-02-v1: 25 groups (GV01 to GV25) of 173 historical chromosome members. Each group was built by complete linkage at chromosome ANI ≥99.50%. A genomovar call matches a query to one frozen group under the accepted P3a contract, p3a-genomovar-contract-r1. It is an operational match, not a population boundary, a purity estimate or a new taxon.
Every whole-assembly report has a genomovar section. assignment.genomovar_id with --no-anim, or the top-level genomovar_id with ANIm enabled, is set only when that section’s status is assigned, and only after the final recheck described below.
When a genomovar is assigned
All of these must hold:
- Parent: The same query is actually assigned species
ECTX-SP025and subspeciesECTX-SS007by an accepted parent call, with no blocking reason and a scope outcome ofnot_assessedorexplained_after_checks. Either call counts only when it was decided against the authenticated package (reference_package.status: verified). With ANIm enabled, the call must still match the initial skani call: default thresholds, a complete evaluation,call_basis: skani, and the same species and subspecies as itslegacy_v1_result. An ANIm species rescue sets subspecies to null and never supports a genomovar. Custom thresholds do not either, even at the default values. - Definition: The package carries exactly the frozen definition: the 25 groups and 173 members under
ECTX-SS007, members equal to thegenomovar_chromosomecomponent, and the pinned membership SHA-2561a2202dde4e0afcf78a89c1e6c084563169bd5cdea0f102da8113b1a87ebf0ab. That digest coversgroup<TAB>member<LF>lines sorted by group, then member. - All members: The reported skani ANI is ≥99.50% to every member of exactly one group. The threshold is inclusive. Values are compared exactly as the two-decimal estimates skani emits, with no rounding or epsilon.
- Rival exclusion: Every other group has at least one measured member below 99.50%. A member that skani did not return is not a negative measurement, so a group with a missing member and no measured failure stays a possible rival and blocks the call. Two or more compatible groups overlap; nothing breaks the tie, not the best ANI, a medoid, reference counts or ST.
- Member coverage: Both the query and the reference aligned fraction are ≥80% to every member of the compatible group. 80.00% passes and 79.99% does not. A low-AF compatible rival still counts as a rival.
If a gate fails, the genomovar is withheld and the parent call stays as it is. The section keeps the compatible and incomplete groups, each group’s state, missing and failing members, and the ANI and AF minima.
The genomovar search
The search compares the whole assembly as supplied (query_scope: whole_assembly_as_supplied) with the 173 historical chromosome members (reference_scope: historical_chromosome_record_set). It uses the embedded skani 0.3.2 with the genomovar settings c125_m1000_learnedANI_s80_minAF0_uncapped: compression 125, marker compression 1000, learned ANI, screen 80%, no AF reporting floor and no result cap. These are not the primary search’s settings. Primary-search thresholds and custom ANI thresholds do not change the genomovar definition or its rule.
The search runs only for an eligible parent on a package with the frozen definition. Otherwise search.status is not_run. The genomovar database is opened on first use, so a batch with no Group A parent never loads it. search.member_evidence lists every returned member comparison, and search.not_returned_reference_ids lists the members skani did not return.
Report fields
| Field | Meaning |
|---|---|
status | assigned, withheld, or failed when the search could not complete. |
genomovar_id | The assigned group’s concept ID, for example ECTX-GV-2026-10-02-v1-GV03, otherwise null. |
reasons | Every gate that failed. One reason never hides another. |
compatible_groups, incomplete_groups | Groups with every member ≥99.50%, and groups with no measured failure but a missing member. |
groups | Per group: state (compatible, incompatible, incomplete or unassessable), required and observed member counts, missing, below_threshold, below_member_af and the minima. |
warnings | Always the operational-match warning. A singleton group adds a sparse-reference warning. A minimum ANI of exactly 99.50% adds a cutoff warning. |
parent | The parent call, calling-rule source digest and parent decision digest before attachment. |
policy_sha256, approval | Digest of the base and accepted addendum identities, with approval source and contract hashes. |
search | Engine, settings, scopes, query and package hashes, counts and member evidence. |
definition, rule | The definition identity and the gate values. |
| Reason | Meaning |
|---|---|
absent_eligible_parent | No actually assigned, verified Group A parent under the standard calling rules. |
unresolved_scope | The parent’s scope outcome is unexplained_after_checks. |
upstream_veto | The parent call carries a blocking reason. |
unsupported_scope | Not a whole assembly, or not the historical chromosome references. |
unsupported_method_or_definition | Not the pinned engine, settings or frozen definition. detail says which. |
incomplete_or_unbound_execution | The search did not complete, or its query or package differs from the parent’s. |
diagnostic_only_no_deployment_call | The contract’s leave-one-out diagnostic mode. The command never runs it. |
overlapping_definitions | Two or more groups are compatible. |
incomplete_alternative_or_member_evidence | A group has a missing member and no measured failure. |
no_compatible_definition | No group is compatible and none is incomplete. This is not a new genomovar. |
insufficient_member_coverage | The one compatible group has a member with an AF below 80%. |
parent_withdrawn_before_publication | The parent changed or was vetoed after assessment. |
The reporting-rule digest hashes the two contract SHA-256 strings in order, each followed by a newline. approval records those identities and Michael’s dated decision source. The parent-rule digest hashes the exact skani decision source; with ANIm enabled it also includes alignment decision, threshold and pair-binding sources, separated by newlines. The parent result digest hashes compact JSON with sorted keys after removing genomovar, mlst, genomovar_id, execution, measurement, evidence, anim_execution, anim_plan, implementation and nested assignment.genomovar_id. MLST is an independent supplementary receipt: attaching a not-requested, successful or failed MLST result does not change the parent taxonomic decision or its digest. The retained decision contains the query/package/evidence identities, parent assignment and vetoes. Paths and timing are not part of either rule digest.
Recheck before publication
Immediately before writing reports, the command rechecks each assigned genomovar against its report’s final parent. The report must still be complete, and its parent call must be unchanged, eligible and bound to the same query and package. A later failure, such as the final package check, clears the genomovar with parent_withdrawn_before_publication and keeps the evidence.
A genomovar search failure is an execution failure, not a negative result. As with any other failed stage, the report sets execution.status: incomplete at stage genomovar while retaining independently supported species and subspecies fields. Final package checks still apply to those retained calls. It keeps the measurement, the evidence and a failed genomovar section that records the parent call, and the command exits 1.
Limits
An unrepresented group can match a neighbouring reference group. A unique match means compatibility with the supplied definition; it does not prove that the query’s source group is represented or that all unsampled groups have been excluded. The frozen omission diagnostics observed this limitation between GV01/GV24 and GV04/GV05. With the full reference set, overlapping compatible groups remain withheld. Singleton matches retain the sparse-reference warning. These observations do not justify changing the frozen threshold after seeing the results.
The 15 singleton groups have no independently demonstrated population boundary. Identical sequence is not evidence of isolate identity. Nothing reclusters the definition, changes a membership, updates the package from a query or uses ST as a tiebreaker. Queries matching the same group are not necessarily ≥99.5% to each other. Skani aligned fraction does not certify exact whole-input base coverage, and records shorter than 500 bases are not sketched. These are implementation checks against the accepted contract; the evaluation of genomovar calls on new genomes is separate.
Multilocus sequence typing (MLST)
MLST reports the sequence type (ST) from the scheme’s allele profile. The ST286 example shows a complete allele profile; the ST2274 example shows why an ST can be reported even when species is unresolved. It is included in database installation and runs by default:
ptero database install 2026-10-15
ptero --report-dir typed-report isolate.fa
To skip typing, pass -x or --no-mlst to classification. The same option on database install omits the scheme download:
ptero database install 2026-10-15 --no-mlst
ptero --no-mlst --report-dir untyped-report isolate.fa
The bundled scheme covers submissions through 31 December 2024, retrieved in 2026. It is not a live copy of PubMLST.
If you already have a verified scheme directory and its trusted manifest digest, you can use explicit paths instead:
ptero --reference-package "$REFERENCE_PACKAGE" --expected-sha256 "$REFERENCE_SHA256" \
--anim-reference-package "$ANIM_REFERENCE_PACKAGE" --expected-anim-sha256 "$ANIM_SHA256" \
--anim-output typed-alignments \
--mlst-package mlst --mlst-expected-sha256 "$MLST_SHA256" \
--output typed-isolate.json --report-dir typed-isolate-report isolate.fa
The command uses the default rescue mode and the alignment variables from reference setup. To run skani only, use --no-anim and omit the three alignment options.
Set MLST_SHA256 to the supplied SHA-256 of mlst/manifest.json, and use your actual scheme path. MLST runs on the same whole input as classification and never changes the species, subspecies or genomovar result. No separate MLST or BLAST executable is required.
Inspect the mlst section of the JSON for the profile, allele states, dates and limitations. The scheme is a 2026 retrieval of PubMLST submissions through 31 December 2024. It is not a byte snapshot of that date, complete historical coverage has not been established, and it does not claim post-2024 currency. An unlisted profile does not establish a new ST; inexact, missing or ambiguous alleles remain explicit.
If requested typing fails after classification completes, the classification result is retained and the command exits 6. Check both results. With --no-mlst, typing is not requested and the scheme package is neither needed nor opened. When using explicit reference paths, supply an MLST package too, or opt out with --no-mlst. The command reference lists exact MLST states; the implementation contract at docs/contracts/MLST-UNGAPPED-r1.md describes the matcher.
Using a newer Enterobacter scheme
The bundled package retains the submission cutoff described above. Do not edit that date to make an incompatible scheme load. A fresh PubMLST export needs packaging and verification before it can be used.
The PubMLST Enterobacter page links to the typing database. The current/custom package contract supports separately versioned local seven-locus schemes with recorded provenance and rights. Automatic provisioning of a current PubMLST scheme is not available; source access and redistribution terms still need review. Updating a scheme does not change species, subspecies or genomovar rules.
Reviewing an uncertain call
Keep the automatic report and record any expert interpretation separately. A nearest reference is evidence; it does not become an assignment when the call is withheld. Pterobacter uses whole isolate assemblies, with all supplied records retained. It runs no query CheckM2 and does not certify purity or explain every unaligned base.
Start with the reported reason. Inspect both aligned fractions, the closest type and diversity references, competing groups, and the sequence scopes. Percent values remain percentages: an AF of 0.8 is 0.8%, not 80%. A missing estimate is not zero ANI. An unresolved species/subspecies field stays null even if the nearest-reference name is present.
The default adds ANIm for eligible samples just below the species boundary. --no-anim skips those alignments and uses skani only. The ANIm guide shows the reference FASTAs and evidence directory needed for alignments.
A successful rescue requires ANIm strictly above 96% in both directions, the AF and competitor safeguards, and a complete required panel. It assigns species only. Preserve method disagreement rather than selecting an estimator because it produces a preferred label. The worked manual review uses the real ECC-219 assembly, whose species remains unresolved after ANIm.
A recorded wider-context example
The public-assembly review case VAL-L3-1B0C8D325620 matched the proposed E. xiangfangensis subsp. hoffmannii group. Its strongest diversity reference, GCA_009834325.1, had ANI 99.97%, query AF 93.65% and reference AF 92.61%. The type anchor GCA_001729745.1 had ANI 99.03%, query AF 84.29% and reference AF 91.66%. The strongest alternative named subspecies was 96.05% ANI, a 3.92 percentage-point gap. All 140 saved comparisons retain the whole-assembly measurements.
The query recovered 117 of 120 unique BAC120 markers. Michael initially accepted hoffmannii with moderate confidence and requested two more ancestral splits of context. The wider displays retained the same trees and rooting: 75 named cohort tips plus four coded queries in BAC120, and 83 named cohort tips plus four coded queries in Verticall. All named cohort tips in those neighbourhoods were hoffmannii. After reviewing them, Michael retained the label and raised his confidence to high.
Original closer views · Wider PDF
Red marks the focal query; shading marks the earlier displayed clade. Collapsed triangles represent labelled tip groups. The methods have different branch-length scales. BAC120 has weak internal branches, and the retained Verticall/FastME tree has no branch-support values. The additional context changed the expert confidence, not the ANI measurements or calling rules. This was a database-label review, not a withheld-call rescue or an additional independent accuracy test. Names follow the reviewed project framework and keep its proposed-combination status.
Tree follow-up
Select an explicit comparison set before running a tree: the focal group’s type and diverse members, types and diverse members of plausible competitors, and a nearby group outside the focal cluster. If genus membership is uncertain, add relevant neighbouring genera; the Enterobacter-focused panel cannot resolve every genus question. Record accessions, sequence hashes, scope, label source and selection rationale. Preserve the original whole-assembly comparison as primary; any justified alternative scope is a labelled sensitivity analysis.
For a quick distance-tree inspection, put exactly those chosen FASTAs in a new dedicated directory and retain their hashes:
sha256sum query.fa selected_refs/*.fa > selected-inputs.sha256
mashtree --numcpus 4 query.fa selected_refs/*.fa > follow-up.dnd
The wildcard is over your explicitly staged comparison set, not an existing archive. Mashtree is a separately installed optional investigation tool, not a Pterobacter runtime requirement or an authoritative rank assignment. Check its version and settings before running. A core-genome or marker tree needs a documented alignment/model/scope choice and suitable neighbouring groups. Display support, missingness, alternatives and a full-tree overview alongside the local view.
Pterobacter has no placement subcommand, public BAC120 placement database or browser feature. A Newick tree alone is not a placement package: the matching alignment, mask, model and reference identities are also required. Keep the report unresolved when follow-up evidence cannot distinguish the alternatives.
Record the original report hash, software, settings and data identities, reason for review, competing references, ANI and both AFs, tree inputs/settings/support, alternative interpretations, reviewer/date and rationale. A manual label stays separate from the automatic result and does not create a validly published name.
Troubleshoot a run
Check the terminal error and the execution status for every input before interpreting a missing call. A completed unresolved result is a biological withholding; a failed run is not.
| Symptom | Check |
|---|---|
| GNU compiler error during installation | Use GNU C++ with C++17 support. On macOS set CXX to Homebrew’s g++; the native build refuses Apple clang. |
| Reference digest or file mismatch | Use the intact directory and trusted digest from the same handoff. Do not bypass a failure by hashing an untrusted replacement and trusting that value. |
| Existing output path or path collision | Choose new output names outside reference-package directories. Report, alignment and cache paths must be distinct and not nested. |
| Assembly rejected | Supply a nonempty nucleotide FASTA with identifiers and nonempty records. FASTQ and reads are unsupported. |
| No assigned name after a completed run | Read the reasons and comparisons. Do not replace an empty assignment with the nearest reference. See uncertain results. |
| Candidate ANIm run needs more data | Supply the matching authenticated reference FASTA component and a new evidence directory. A failed required alignment does not fall back to a skani-only call. |
| MLST failed | Check the scheme digest, allele states and error. Completed classification can remain available even when typing fails. |
Exit 0 means all inputs finished, including unresolved results. A nonzero exit means a failure occurred; a batch may still contain completed inputs. Errors before analysis can leave no report, while later failures retain evidence where possible. The exit-code table gives the precise meanings and precedence.
When reporting a problem, retain the command, software/reference identities, error and relevant report fields. Share only data you are authorised to disclose.
Command-line help
For a first run, follow classify an assembly. This page explains the less familiar options, followed by the exact help printed by the current executable.
ANIm and ANI thresholds
Pterobacter first estimates ANI with skani. For eligible samples just below the species boundary, it also runs ANIm using whole-genome alignments to refine the estimate. ANIm can take longer, especially in large batches with many borderline samples; samples outside that band do not incur alignment work. Use -n or --no-anim to skip ANIm and use skani only.
-s / --species-ani PERCENT sets the minimum species ANI, 96% by default. Enter a percentage such as 96.5, not a fraction such as 0.965. A skani species call requires ANI greater than or equal to that value; an ANIm-supported call requires ANI strictly greater than it in both alignment directions. Coverage and competitor checks must also pass.
-S / --subspecies-ani PERCENT sets the minimum skani ANI for a subspecies call, 98% by default. ANI must be greater than or equal to this value, with the other subspecies checks satisfied. ANIm never assigns subspecies.
Require 80 <= species threshold <= subspecies threshold <= 100. A custom species threshold also moves the ANIm trigger band to the interval from 1.5 percentage points below that threshold, inclusive, up to the threshold, exclusive, with a lower bound of 80%. Supplying either threshold marks the result custom_unvalidated, even when you supply its default number. Leave both out to use the standard settings. Custom thresholds cannot be combined with --no-anim.
The input is always an isolate assembly FASTA. Every public option has a short form, shown below.
Assembly lists and sample names
Assemblies can come from the command line, from -f / --input-list FILE with one path per line, or from -F / --sample-sheet FILE, a TSV with the header sample and path. Use one source per run. -N / --sample-name NAME names a single command-line assembly. Relative paths in a list or sheet are read from the file’s own directory. Names label the reports only; the analysis uses the file path as it would for a command-line argument. Running Pterobacter has the exact file rules and examples.
MLST
MLST runs by default. Use -x/--no-mlst to skip it. For explicit packages, provide --mlst-package and --mlst-expected-sha256 explicitly. Database management includes a working local install example; MLST explains the submission cutoff, and the current/custom contract defines compatible newer local packages. The bundled scheme is downloaded with the managed database; automatic provisioning of newer PubMLST records is not available.
Alignment files and resource limits
The --anim- options apply to the MUMmer4 rescue mode. ANIm means average nucleotide identity measured from genome alignments.
| Option | What it is for |
|---|---|
--anim-reference-package | The matching reference genome FASTAs, needed when the rescue runs alignments. |
--expected-anim-sha256 | The trusted hash of that FASTA package’s anim.json manifest. |
--anim-output | A new directory for alignments and execution records, including input snapshots, errors and hashes. It preserves evidence used in the call. |
--anim-cache | A reusable store of verified query/reference comparisons to avoid repeating matching work. |
--anim-pair-seconds | Opt-in wall limit for one reciprocal pair, including both directions; omitted or zero means unlimited. |
--anim-query-seconds | Opt-in ANIm-stage budget for one assembly; omitted or zero means unlimited. |
--anim-memory-mib | Opt-in worker ceiling in MiB; omitted or zero means unlimited. |
--report-dir holds the classification reports; --anim-output holds the underlying alignment evidence. Use separate new directories. The rescue command shows both the required inputs and evidence output; cache reuse describes the optional cache.
Execution has no tool time or memory ceiling unless you supply a positive limit. Each control is independent; omission or zero disables it. The query control covers the ANIm stage for one assembly, with cooperative checks after synchronous operations. It does not time skani, genomovar, MLST or the whole batch. OS/scheduler restrictions and jobs/thread bounds still apply. A limit failure leaves required evidence incomplete and withholds the call. Ctrl-C requests a stop and retains partial evidence when possible; repeating the signal terminates immediately. Execution details describe Linux/macOS enforcement, inherited limits and historical cache compatibility.
Exact terminal output
Captured from the current ptero --help. The pterobacter alias accepts the same options.
Standalone, self-contained Enterobacter isolate classification
Usage: ptero [OPTIONS] [ASSEMBLY]...
ptero [OPTIONS] [ASSEMBLY]... <COMMAND>
Commands:
database Install, list or verify pinned reference and typing components
help Print this message or the help of the given subcommand(s)
Arguments:
[ASSEMBLY]... Isolate assembly FASTA files, analysed whole and as supplied
Options:
-D, --database <DATABASE>
Exact installed database version; otherwise use the catalogue's published default
-B, --database-dir <DIR>
Managed database store on a filesystem supporting atomic no-replace rename
-C, --catalogue <CATALOGUE>
Explicit trusted catalogue file; requires its independently supplied SHA-256
-H, --catalogue-sha256 <CATALOGUE_SHA256>
Expected SHA-256 of the explicit catalogue
-x, --no-mlst
Skip MLST sequence typing
-s, --species-ani <PERCENT>
Minimum species ANI (%): skani >= this value; ANIm must be strictly greater [default: 96]
-S, --subspecies-ani <PERCENT>
Minimum subspecies ANI (%): skani >= this value [default: 98]
-f, --input-list <FILE>
Read assembly paths from this file, one per line; relative paths are from its directory
-F, --sample-sheet <FILE>
Read sample names and assembly paths from this TSV with the header sample<TAB>path
-N, --sample-name <NAME>
Name to report for the one assembly given; reporting only, never sent to skani
-r, --reference-package <REFERENCE_PACKAGE>
Authenticated reference package directory
-R, --expected-sha256 <EXPECTED_SHA256>
Expected SHA-256 of portable.json, obtained from a trusted source
-n, --no-anim
Skip ANIm near the species boundary; use skani only
-t, --threads <THREADS>
Worker threads for each assembly [default: 1]
-j, --jobs <JOBS>
Assemblies analysed at the same time, each with its own --threads [default: 1]
-o, --output <FILE>
Write the JSON report to this new file instead of standard output; never replaced
-m, --mlst-package <MLST_PACKAGE>
MLST scheme package directory; overrides the managed scheme
-M, --mlst-expected-sha256 <MLST_EXPECTED_SHA256>
Expected SHA-256 of the MLST package manifest.json, obtained from a trusted source
-d, --report-dir <DIR>
Write report.json, calls.tsv, evidence.tsv and report.md into this new directory
-a, --anim-reference-package <ANIM_REFERENCE_PACKAGE>
Reference genome FASTAs for MUMmer4 rescue; needed when alignments are triggered
-A, --expected-anim-sha256 <EXPECTED_ANIM_SHA256>
Trusted SHA-256 of the component's anim.json
-e, --anim-output <ANIM_OUTPUT>
New directory for alignments and execution records; see the assembly guide
-c, --anim-cache <ANIM_CACHE>
Directory of verified reciprocal pairs to reuse and extend; created when absent
-T, --anim-pair-seconds <ANIM_PAIR_SECONDS>
Opt-in reciprocal pair wall limit in seconds; omitted or 0 means unlimited
-Q, --anim-query-seconds <ANIM_QUERY_SECONDS>
Opt-in ANIm-stage budget per assembly in seconds; omitted or 0 means unlimited
-L, --anim-memory-mib <ANIM_MEMORY_MIB>
Opt-in native worker ceiling in MiB; omitted or 0 means unlimited
-h, --help
Print help
-V, --version
Print version
Uses skani first, then ANIm for eligible samples near the species boundary.
ANIm can be slower; use -n/--no-anim to skip it.
MLST runs by default; use -x/--no-mlst to skip sequence typing.
Give assemblies as arguments, or list them with -f/--input-list or -F/--sample-sheet.
Sample names label reports only; analysis uses each file path.
ANI thresholds are percentages, e.g. --species-ani 96.5. Require 80 <= species <= subspecies <= 100.
Custom thresholds cannot be combined with --no-anim and mark results custom_unvalidated.
Guide: https://mbhall88.github.io/pterobacter/assembly.html
Whole-assembly classification
For managed provisioning and automatic FASTA/evidence resolution, see database management. Explicit package paths below remain supported.
ptero and pterobacter accept one or more isolate assembly FASTAs, without a subcommand:
ptero --no-mlst --reference-package reference --expected-sha256 MANIFEST_SHA256 \
--anim-reference-package reference-fastas --expected-anim-sha256 ANIM_MANIFEST_SHA256 \
--anim-output isolate-alignments --no-mlst isolate.fa > isolate.json
pterobacter --no-anim --reference-package reference --expected-sha256 MANIFEST_SHA256 \
--no-mlst --jobs 2 --threads 4 --output batch.json first.fa second.fa
Use the SHA-256 of portable.json supplied through a trusted package handoff. Computing a digest from an untrusted package does not establish its origin. The command verifies every listed asset, package metadata and component membership before opening the embedded skani database, and checks the package again before writing results. Classification from installed or explicit packages makes no network requests and needs no external executable. The HTTPS client is confined to database installation; where unprivileged namespaces are available, tests run skani with MLST and boundary ANIm inside a network namespace with only an unconfigured loopback interface. Archived search labels are provenance labels; no archived FASTA is opened.
ANIm near the species boundary
Pterobacter first estimates ANI with skani. For eligible samples just below the species boundary, it also runs ANIm using whole-genome alignments to refine the estimate. ANIm can take longer, especially in large batches with many borderline samples; samples outside that band do not incur alignment work. Use -n or --no-anim to skip ANIm and use skani only.
The standard thresholds are skani ANI ≥96% for species and ≥98% for subspecies, both aligned fractions ≥80%, and a subspecies margin ≥1 percentage point. ANIm is considered when 94.5% ≤ maximum skani ANI <96%, subject to coverage and other safeguards. An ANIm-supported assignment requires ANI strictly greater than 96% in both directions and completed required competitor comparisons. It assigns species only; subspecies and genomovar stay unset.
A managed database supplies matching reference FASTAs and creates an evidence directory automatically. Alternatively, provide the explicit package paths and evidence directory. MLST runs by default; use --no-mlst to skip it. Genomovar reporting depends on an eligible parent call. No query CheckM2 is run.
--no-anim cannot be combined with custom ANI thresholds or alignment-specific options. It avoids MUMmer4 at runtime; building still requires the embedded aligner’s C++ dependencies. See all options.
Input and sequence scope
Supply isolate assembly FASTAs. FASTQ, empty input, empty records, missing identifiers, malformed FASTA and non-IUPAC nucleotide sequences fail. Needletail’s supported compressed FASTA formats are accepted. Record headers must be UTF-8; duplicate headers remain separate records identified by ordinal.
All supplied records are passed to skani without plasmid filtering or trimming. Its pinned profile ignores records shorter than 500 bases when constructing sketches. input.total_bases and input.records include those records; measurement.sketched_bases shows the engine denominator. Eligibility by length does not guarantee informative sketch anchors. Sequence hashes cover each parser-emitted sequence as supplied, with case preserved and line breaks removed. input.query_sha256 covers the exact file bytes, including compression when present. The engine measures the byte snapshot that was hashed and validated. The resolved query path, recorded in input.file, also reaches skani as a provenance label. Exact orientation-score ties use sketch content, so filenames do not select the measurement orientation. Preserve the original labels when replaying historical evidence from an older engine profile.
MLST
MLST runs by default using the selected managed scheme. Use -x or --no-mlst to skip typing. For explicit setup, pass a scheme package directory and the trusted SHA-256 of its manifest.json together:
ptero --reference-package reference --expected-sha256 MANIFEST_SHA256 \
--anim-reference-package reference-fastas --expected-anim-sha256 ANIM_MANIFEST_SHA256 \
--anim-output typed-alignments \
--mlst-package mlst --mlst-expected-sha256 MLST_MANIFEST_SHA256 isolate.fa > isolate.json
The engine is terobacter-ungapped-mlst, an in-binary ungapped seed-and-extend matcher that reproduces the calls of mlst 2.32.2 with BLAST+ 2.16.0 on the development fixtures. It is not that tool, and the report names the engine that ran. The implementation contract is retained at docs/contracts/MLST-UNGAPPED-r1.md.
The scheme covers PubMLST submissions through 31 December 2024. It is a later retrieval, not a byte snapshot of that date, and it makes no claim to post-2024 currency. Every record carries the cutoff, retrieval time, package and data SHA-256s, data terms URL and limitation text. States are exact_profile_match, unmatched_profile, incomplete_profile, inexact_alleles and ambiguous_alleles. An exact profile the scheme lacks is unmatched; no new ST is claimed. A profile-compatible candidate ST for a repeated identical allele is never the reported ST.
MLST is supplementary. It never changes assignment, species or subspecies, and it types the same validated whole-input bytes as classification. Locations use each record’s first header word, so repeated first words fail MLST for that input. With --no-mlst, reports carry "mlst": {"requested": false, "status": "not_requested"} and no MLST package is needed. A requested MLST that fails reports mlst.status: failed with its stage and error and exits 6. The classification result is kept.
Reports and failures
One input produces a JSON object. Multiple inputs produce an array in argument order, with isolated statuses. Each report records its argument position as input.ordinal beside input.file. A failed input does not erase or change a completed input. The process exits nonzero if any input fails.
--report-dir NEW_DIRECTORY also writes report.json (the same JSON as the main report), calls.tsv (one row per assembly), evidence.tsv (strongest matches, whole-panel parents and challenges) and report.md. The directory must not exist; a collision exits 2 before any analysis, and no file is replaced. The TSV and Markdown are derived from the JSON and take a label only from its final call. See the usage guide.
--jobs N analyses up to N inputs at once (default 1). Each runs its searches with --threads, so a run uses up to N × --threads search threads, and up to N native ANIm workers when needed, each subject to any opted-in --anim-memory-mib ceiling and inherited OS restrictions. Calls, statuses, exit codes and evidence directory names do not depend on N or on the order in which inputs finish; timings and, with a shared cache, which query stored or reused a pair can.
The report goes to stdout unless --output FILE names a new file in an existing directory. An existing file is never replaced: the run is refused before any work, and a file that appears during the run is left alone, in which case the report goes to stdout and the run exits 1. The file is written completely before it appears, so a reader never sees a partial report. An unwritable stdout returns 1.
Output paths are checked before any work, and a collision exits 2 without a report. The report file, --report-dir, --anim-output and --anim-cache must be distinct and not nested in one another. None may be inside the reference package, the ANIm component or the MLST package, and none may be an input assembly. Paths are compared after resolving symbolic links and ...
A completed search may produce an unresolved biological call, including when no estimate is returned. This is execution.status: complete with a null assignment. Execution failure instead reports execution.status: incomplete, the failed stage and an error, with null assignment fields. Partial reports retain validated input metadata where available. A missing or corrupt reference package or database fails each input that reaches it with exit 4, keeping the validated input metadata. A missing or invalid ANIm component fails a query that needs alignments at the anim stage with exit 1, keeping its plan and any pair evidence; one that changes after its pairs complete fails the final component check with exit 4. A package changed during the run fails the final check, which invalidates all decisions in that batch while retaining their measurement evidence.
The first SIGINT or SIGTERM stops the run at the next check with or without ANIm. Inputs not yet started report run interrupted. A running skani search finishes, and a native ANIm worker is stopped. Every call in the batch is then withheld at the publication stage, measurement and ANIm evidence are kept, the report is still written and the exit code is 1. A second signal of the same kind ends the process at once without a report.
Reports include authenticated data identity and version, analysis settings, implementation version, skani revision and compatibility profile, floor 15%/screen 80% settings, every returned row and every unreturned reference. evidence is the package-bound decision input, retaining exact emitted decimal measurements. Scope is reported as not assessed when no scope assessment was performed; AF alone does not establish purity or explain extra sequence.
| Public exit code | Meaning |
|---|---|
| 0 | All inputs completed, whether assigned or biologically withheld. |
| 1 | Measurement, decision, genomovar search or output I/O failure, or the run was interrupted. |
| 2 | Command-line usage error, including missing package/digest, invalid digest, zero threads or jobs, an existing --output file, a missing directory for it or an output collision. No report is available. |
| 3 | Unreadable, empty, malformed or unsupported assembly input or input kind. |
| 4 | Package authentication, database opening or final package recheck failed. |
| 5 | Alignment-specific options were supplied with --no-anim. |
| 6 | MLST was requested and did not complete for an input whose classification completed, or its package changed during the run. Classification results are retained. |
For batches with different failures, the last failed input’s code in argument order is returned. A final package recheck failure takes precedence over it, and an interruption over both. Inspect each report’s execution status. Development commands retain their separate exit-code meanings.
These are implementation and development-parity checks. Independent biological validation and release/platform acceptance remain separate gates.
Boundary ANIm
ptero --no-mlst --reference-package reference --expected-sha256 PRIMARY_MANIFEST_SHA256 \
--anim-reference-package reference-fastas --expected-anim-sha256 ANIM_MANIFEST_SHA256 \
--anim-output new-evidence isolate.fa > isolate.json
Analysis starts with the whole-input skani search. Outside the boundary band it keeps the skani decision and requires no ANIm component. Eligible queries measure witnesses first. A passing witness requires the entire primary competitor panel, including unreturned references. A decisive veto permits an early stop; the report lists every omitted reference. A positive rescue assigns species only, with null subspecies and genomovar. The report retains the initial skani result and evidence, the final plan, exact reciprocal records, artifact directories and hashes. Validation status remains not_yet_validated.
Missing required FASTAs, invalid metadata or bytes, failed native execution and interruption produce an incomplete report with a null call and nonzero exit. Successful zero alignment is measured evidence and counts separately from failures. Redirect stdout to save the unified report. --anim-output must be a new directory; each query and pair receives a separate retained directory, named by the query’s argument position.
Within each query, ANIm runs one worker at a time with one native query thread. There is no tool-imposed time or memory ceiling by default. -T/--anim-pair-seconds, -Q/--anim-query-seconds and -L/--anim-memory-mib opt into independent limits; omission or zero disables that control. Time limits accept finite fractional seconds of at least one nanosecond. Memory is integer MiB. Values must fit deadline arithmetic, byte conversion and the platform’s finite resource-limit representation. The previous 1800/7200-second and 6144-MiB maxima and 64-MiB floor do not apply to fresh execution.
The query budget covers the ANIm stage for one assembly, including preparation, pair work and verification, with cooperative checks after synchronous operations and before successful completion. It excludes skani, genomovar and MLST and is not a whole-classification or batch timeout. A pair uses the smaller of its configured limit and the remaining query budget; QR and RQ share that time. Synchronous I/O or parsing can overshoot before a check returns an incomplete result. Opting into limits does not guarantee a particular performance bound.
Inherited OS and scheduler restrictions still apply. Without a tool limit, workers preserve inherited soft and hard CPU/address-space limits. With one, they use componentwise minima and never raise an inherited limit. A finite wall limit also installs a subordinate ceil-seconds CPU limit. Linux memory control uses address space; macOS samples peak RSS every 10 ms and checks peak RSS at completion. Sampling can follow an overshoot. Core dumps remain disabled. Jobs/thread bounds, process isolation, process-group cleanup and parent-liveness checks remain active with every ceiling disabled.
SIGINT and SIGTERM stop the native worker and retain partial evidence when possible; repeating the same signal terminates the coordinator immediately. A hard kill can prevent a final report. Signals and reliable watchdog markers are retained; a signal without a marker is reported as unknown/external termination, without inferring timeout or OOM. A complete execution stopped by a biological veto can still report competitor_evaluation: incomplete; anim_execution.stop_reason: decisive_veto distinguishes that valid stop from a failed required comparison. A failed required alignment never silently falls back to a skani-only call.
Reusing reciprocal pairs
--anim-cache DIR keeps verified reciprocal pairs for later queries and runs. The directory is created when absent and may be shared by runs. A pair is reused only when every part of its key matches:
- the query’s exact file bytes, its component and its whole-assembly scope;
- the reference ID, exact FASTA bytes, component, concept IDs, scope and the primary package the component is bound to;
- the method profile, amendment, native build and source hashes, compiler, target and Pterobacter version;
- the versioned execution profile, configured optional pair/memory controls and relevant inherited restrictions.
A reused pair also counts the native time recorded in its receipts against the query’s --anim-query-seconds budget, and is measured again instead when that time exceeds what remains for the pair. This is a defined admission accounting rule, not a guarantee that fresh execution would finish in the same time.
The terobacter.anim-cache-key/2 key schema lives under anim-pairs-2. Historical anim-pairs-1 entries are preserved and are not silently reused by current execution. The same bytes under another file name are the same query. Before reuse, the saved key must equal the requested key, and the saved pair is verified again as any saved record is: snapshot bytes, native artifacts, roles, receipts and integer metrics. The method and limits in the record must also agree with the key. A reused pair is copied into the query’s --anim-output directory and verified there. Its record keeps the original producer request and worker receipts. A separate current_admission records the present remaining query budget, effective pair timeout and charged duration. The original effective timeout may differ because the producing query had a different budget.
Each pair reports cache.status and cache.key_sha256. The statuses are reused; stored, for a new verified pair saved for later; already_stored, when a concurrent query saved it first; and rejected, when an entry at that key fails a check or needs more time than remains. A rejected entry is measured again and left unchanged for inspection; delete it to let the cache store that pair again. not_stored means the pair failed and was not saved. store_failed means saving failed; the measurement still counts. Entries appear whole or not at all and are never replaced. The cache is local working storage: its keys and checks bind entries to comparisons, but they do not authenticate the directory against a writer who can forge a consistent entry.
Separate reference FASTA component
The optional component has its own directory and trusted SHA-256 for anim.json. It contains every primary whole-assembly source FASTA and an exact copy of the primary package’s licence manifest. FASTA bytes, lengths, IDs and concept context must match the authenticated primary package. Chromosome-only substitutes, incomplete inventories, extra files, unsafe paths and symbolic links are refused. The component is verified before alignments and again before completing the native run; the primary package is also rechecked before publishing the batch.
Its manifest has this shape; reference entries repeat for the complete primary panel:
{
"schema": "terobacter.anim-reference/1",
"component_id": "primary_whole",
"sequence_scope": "whole_assembly_as_deposited",
"reference_package_sha256": "PRIMARY_MANIFEST_SHA256",
"licence": {"path": "licence.json", "sha256": "LICENCE_SHA256", "bytes": 123},
"references": [{
"reference_id": "primary_whole:ACCESSION",
"path": "sequences/ACCESSION.fa",
"sha256": "SOURCE_SHA256",
"bytes": 456,
"concept_ids": ["SPECIES_ID", "SUBSPECIES_ID"]
}]
}
Concept IDs are ordered species then subspecies, omitting the latter when absent. Paths are relative to the component directory. Each FASTA is capped at 256 MiB and the manifest at 1 MiB. Keep this component separate from the skani package, whose inventory rejects unlisted files. Obtain both trusted digests from the package handoff. Component provisioning and distribution remain release work.
Native pair snapshots retain the exact supplied bytes, including compression, in inputs/query.fa. Each pair’s query.sha256 and the report’s input.query_sha256 identify those original bytes. The adapter uses the same compressed-format decoder as the assembly reader, then validates and normalizes FASTA formatting for inputs/query.native.fa; query.native_sha256 identifies the bytes read by both native orientations. Verification decodes the retained original snapshot again and checks the native bytes, record lengths and hashes. All records, sequence case and ambiguous bases are preserved. The 256 MiB native-input limit also applies to decoded FASTA.
The maintained MUMmer4 profile preserves literal N identity and inclusive whole-input coverage, matching the accepted MUMmer3 comparator semantics. Long runs of N remain a known limitation. The implementation contract is retained at docs/contracts/P1-ANIM-MUMMER4-r1.md. Duplicate FASTA identifiers accepted by skani cannot be passed to the native ANIm adapter; if rescue requires such an input, the report records an explicit failed pair.
Execution and historical evidence
Fresh public and development measurements record terobacter.anim-execution/2 separately from the unchanged numerical ANIm method profile. Optional controls are explicit nulls or full seconds/nanoseconds durations. Records distinguish configured pair limits, original remaining stage budget, derived effective pair/orientation limits, inherited restrictions, effective worker limits and platform enforcement. Missing required new fields or an unknown profile are errors, not unlimited requests.
Historical bounded requests, receipts and decision replay retain their recorded values and identities. Replay of saved decisions does not run a worker or apply current execution defaults. Verification for current reuse still requires the current source/build identity. A complete verified pair may remain reusable evidence when its enclosing query later misses the ANIm-stage budget; that query is incomplete and cannot turn a partial panel into a successful rescue. Cache charging is an accounting rule, not a prediction that fresh execution on another machine would take the same time.
Existing retained results describe their historical bounded execution configuration. Software regression checks do not establish biological accuracy, completion rates, full-panel runtime or memory performance for a new execution profile. The ANIm input limit of 256 MiB, package format/size validation and MLST/index representation bounds remain input safeguards; they are not whole-process memory ceilings.
Report field reference
Use this reference to check exact output fields, evidence completeness and version identities, or follow the illustrative manual-review recipe. For a first run, use running assemblies and reading results.
Outputs
--report-dir writes four files. If the directory exists, or lies inside the reference, MLST or ANIm reference package, the command exits 2 before doing any analysis and leaves it alone. It never replaces a file. If a bundle file cannot be written, the main JSON still goes to its chosen destination and the command exits 1. If writing --output FILE fails, the main JSON falls back to standard output. Output destinations must be distinct and must not sit inside one another; see output-path checks.
| File | What it holds |
|---|---|
report.json | The authoritative report. One object for one input, an array for several. |
calls.tsv | One row per assembly: the final call, reasons, settings, minima, method, counts and versions. |
evidence.tsv | One row per evidence item: the strongest matches, each parent in the reference panel, and each challenge. |
report.md | A readable summary of the same facts, for manual review. |
The TSV and Markdown files are produced from the JSON. They state the same final calls, reasons, settings, minima and method, and they cannot show a label the JSON does not assign. If you find a difference, the JSON is right, and the difference is a bug worth reporting.
Data selection
Native reports add data_provenance: the actual reference trust source, selected
catalogue/release/citation when managed, explicit or catalogue-derived component
pins, typing request status and the retained ANIm evidence directory. Each
rescue-mode run uses a unique directory unless an explicit new output path is
supplied. This path and catalogue metadata are transport provenance, separate
from scientific measurements and package identities. Markdown includes the same
selection metadata. See database management.
Input identity and sample names
input.file is the assembly path that was read. It is also retained as the skani query label for provenance. Exact orientation-score ties use sketch content, so filenames do not select the measurement orientation. input.query_sha256 and the per-record hashes under input.records identify the bytes and sequences, and input.ordinal gives the position in the run.
input.sample_name holds the name given with --sample-name or in a sample sheet, and is null otherwise. It is reporting metadata only and takes no part in the analysis. input.source records where the path came from: {"kind": "positional"} for a command-line argument, or the kind input_list or sample_sheet with the list’s file, the 1-based line and the entry exactly as written there. A relative entry is resolved against the list’s directory to give input.file.
calls.tsv and evidence.tsv carry the name in their second column, sample_name, and leave it empty for unnamed inputs. report.md heads each section with the sample name and shows the input file below it. Markdown and HTML characters in a name are escaped there so it displays exactly as written; the JSON and TSV files keep the name unchanged. Join the two TSV files on assembly, the input’s position, which is always filled.
The final call
call_status is assigned, unresolved or not_evaluated.
assigned: the approved rules support a species.species_idandspecies_nameare filled. Subspecies and genomovar are separate calls and can stay empty while the species is assigned.unresolved: the run finished and the evidence does not support a call. The species, subspecies and genomovar columns are empty.reasonssays why, using the terms inreason-vocabulary.tsv.not_evaluated: the run did not reach a decision. Look atexecution_status,execution_stageandexecution_error. Do not read this as a biological negative.
A label never appears as a call unless the decision assigned it. The nearest parent, the initial skani result and a rescue witness do appear, but each under a name that says it is not the call: “Nearest parent (not an assignment)” and “Initial skani result”.
Evidence you can check
The report shows the five highest skani references and every exact tie at fifth place, so a tie is never cut at an arbitrary row. Rows in one tie_group have the same ANI. They are sorted by reference ID only so the output is stable; the order does not pick a winner. Each reference is a competitor, not a vote.
The top table does not cover the whole panel. The panel summary lists every parent in the reference panel, whether skani returned it or not, with its best ANI and any challenging references. A challenge outside the top table appears there and in the challenges list, marked as outside the strongest matches.
With --no-anim, there is no alignment-based foreign-parent challenge test, so its challenge list is always empty; compare each parent’s best ANI in the panel summary instead.
With ANIm enabled, an empty challenge list is a result only when the check was carried out. challenge_assessment says how far it went:
| Value | Meaning |
|---|---|
completed | Every required competitor pair was measured. An empty list means the retained measurements contain no challenge; this alone does not validate the call. |
partial | Some competitor pairs are missing. Known challenges are retained; an unlisted reference has not been cleared. |
not_assessed | The competitor panel was not assessed. An empty challenge list is not negative evidence. |
not_applicable | The analysis did not require a competitor check; for example, the query was outside the rescue band or lacked a qualifying skani coverage witness. The check is also skipped with --no-anim. |
Assessment coverage is separate from execution_status. A failed execution or integrity check can retain measurements while withholding the call. Check both fields.
ANI methods are not mixed in one ranking. skani orders the table; ANIm values, where measured, sit beside it as separate columns.
Counts and versions
With ANIm enabled, anim_required, anim_attempted, anim_completed, anim_no_alignment, anim_failed and anim_not_run say how many reciprocal ANIm pairs the decision needed and what happened to each. A pair that aligned nothing is a result and counts under anim_no_alignment. A pair that did not run, or failed, leaves the competitor panel incomplete, and an incomplete panel blocks a rescue. competitor_evaluation says which. The skani columns say how many references were in the panel, how many skani returned and how many it did not.
Each report carries its versions separately, in the versions object and in the matching columns. They answer different questions, so do not merge them:
| Field | Identifies |
|---|---|
implementation | The program build. |
report_schema | The shape of the report. |
validation | Evaluation status: unset with ANIm disabled; otherwise not_yet_validated or custom_unvalidated. |
skani_method, anim_method | The measurement method profiles. |
reference_data | The reference package version and manifest SHA-256. |
A worked manual-review example
The ECC-219 example is an actual public assembly that stays unresolved after ANIm. Its saved report and reproduction commands retain the whole input and database identity.
| Field | Observed value |
|---|---|
status | unresolved |
reasons | ANIm_no_strict_witness |
| Nearest species reference | E. nematophilus, GCA_026344075.1 |
| skani ANI | 94.83% |
| Reciprocal ANIm | 95.02965% / 95.03431% |
| ANIm pairs completed / required | 1 / 1 |
| MLST | ST2274 |
Read the reason first. The alignment ran successfully, but neither orientation exceeded the required 96% ANI. This is not a missing comparison or an execution failure. Adequate aligned fraction and an exact ST do not substitute for the species criterion.
Keep the other candidates visible. The strongest-match and whole-panel tables include the nearby E. bugandensis references as well as E. nematophilus. Do not turn the nearest-reference name into an assignment. An empty challenge list is not proof that every alternative has been ruled out: read the competitor-assessment field and the measured pair counts.
Choose a follow-up question. A useful next question is whether broader sampling places ECC-219 within an existing group or supports a separate lineage. Select types and diverse representatives of both nearby groups, adding relevant neighbouring groups for context. The boundary guide explains how to record that selection and compare tree evidence. No follow-up tree or new species conclusion is claimed for this documentation example.
Preserve the automatic result. Record any later expert interpretation separately, with its inputs, evidence and rationale. The saved output stays species-unresolved, with its independently reported ST2274.
Limits
- Pterobacter takes one isolate assembly per input. Metagenomes and mixed samples are out of scope, and a clean report does not prove the assembly is pure.
- Quality control is your responsibility. Pterobacter runs no CheckM2 or other quality check on a query.
- Reads are not supported. Input kind and provenance stay explicit in the reports so that read support can be added later with its own validation.
- MLST covers PubMLST submissions through 31 December 2024. It never sets a taxon.
- A genomovar call is a conditional match to one frozen group, not a population boundary. An unrepresented group can match a neighbouring reference group. Overlapping compatible groups are withheld; singleton matches retain a sparse-reference warning. See genomovar.md.
Reference registry appendix
Use these exact identifiers and recorded statuses when matching a report to the reference package. The coverage guide explains them in ordinary language. This appendix retains the original table values for package 2026-10-06.proposal1. The authenticated package tables carry the accession-level details.
| Concept | Project name | Primary references | Type anchors | Formal-status snapshot | Limits |
|---|---|---|---|---|---|
| ECTX-SP001 | Enterobacter adelaidei | 1 | 0 | provisional_name_not_validly_published | one_development_reference; provisional_name; reported_proposed_type_not_in_package |
| ECTX-SP002 | Enterobacter asburiae | 8 | 2 | validly_published_correct_name | historical_type_QC_exception_not_automatically_sole_operational_reference |
| ECTX-SP003 | Enterobacter bugandensis | 8 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP004 | Enterobacter cancerogenus | 3 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP005 | Enterobacter chengduensis | 3 | 2 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP006 | Enterobacter chinensis | 1 | 1 | validly_published_correct_name | one_reference_only; within_taxon_diversity_not_represented |
| ECTX-SP007 | Enterobacter chuandaensis | 4 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP008 | Enterobacter cloacae | 13 | 2 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP009 | Enterobacter hormaechei | 5 | 1 | validly_published_correct_name | frozen_type_retained; whole_scope_sensitivity_and_reassembly_caveats |
| ECTX-SP010 | Enterobacter huaxiensis | 1 | 1 | validly_published_correct_name | one_reference_only; within_taxon_diversity_not_represented |
| ECTX-SP011 | Enterobacter kobei | 8 | 1 | validly_published_correct_name | historical_type_QC_exception_not_automatically_sole_operational_reference; DSM13645_anchor_retained; JCM8580_label_not_isolate_identity |
| ECTX-SP012 | Enterobacter ludwigii | 8 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP013 | Enterobacter mori | 8 | 2 | validly_published_correct_name | historical_type_QC_exception_not_automatically_sole_operational_reference |
| ECTX-SP014 | Enterobacter nematophilus | 1 | 1 | validly_published_correct_name | one_reference_only; within_taxon_diversity_not_represented |
| ECTX-SP015 | Enterobacter oligotrophicus | 1 | 1 | validly_published_correct_name | one_reference_only; within_taxon_diversity_not_represented; use_frozen_corrected_whole_source; do_not_restore_truncated_archive |
| ECTX-SP016 | Enterobacter pasteurii | 2 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP017 | Enterobacter pseudoroggenkampii | 4 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP018 | Enterobacter quasihormaechei | 1 | 1 | validly_published_correct_name | one_reference_only; within_taxon_diversity_not_represented |
| ECTX-SP019 | Enterobacter roggenkampii | 14 | 2 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP020 | Enterobacter siamensis | 0 | 0 | validly_published_correct_name | no_verified_type_genome_or_reference; abstain |
| ECTX-SP021 | Enterobacter sichuanensis | 4 | 1 | validly_published_correct_name | historical_type_culture_provenance_conflict; use_explicit_supplementary_evidence |
| ECTX-SP022 | Enterobacter soli | 2 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP023 | Enterobacter vonholyi | 7 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP024 | Enterobacter wuhouensis | 3 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SP025 | Enterobacter xiangfangensis | 30 | 6 | validly_published_synonym | species_only_peripheral_member_preserved; no_subspecies_forced |
| ECTX-SS001 | Enterobacter chengduensis subsp. chengduensis | 2 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature |
| ECTX-SS002 | Enterobacter chengduensis subsp. rongchengensis | 1 | 1 | approved_project_subspecies_proposal_not_validated_combination | one_reference_only; within_taxon_diversity_not_represented; project_subspecies_combination_not_validated_nomenclature |
| ECTX-SS003 | Enterobacter cloacae subsp. cloacae | 8 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SS004 | Enterobacter cloacae subsp. dissolvens | 5 | 1 | validly_published_correct_name | No additional registry qualification |
| ECTX-SS005 | Enterobacter roggenkampii subsp. quasiroggenkampii | 6 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature |
| ECTX-SS006 | Enterobacter roggenkampii subsp. roggenkampii | 8 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature |
| ECTX-SS007 | Enterobacter xiangfangensis subsp. hoffmannii | 8 | 3 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature; species_only_peripheral_member_preserved; no_subspecies_forced |
| ECTX-SS008 | Enterobacter xiangfangensis subsp. oharae | 5 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature; species_only_peripheral_member_preserved; no_subspecies_forced |
| ECTX-SS009 | Enterobacter xiangfangensis subsp. steigerwaltii | 8 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature; species_only_peripheral_member_preserved; no_subspecies_forced |
| ECTX-SS010 | Enterobacter xiangfangensis subsp. xiangfangensis | 8 | 1 | approved_project_subspecies_proposal_not_validated_combination | project_subspecies_combination_not_validated_nomenclature; species_only_peripheral_member_preserved; no_subspecies_forced |
Development commands and source layout
Use this guide when working on the implementation or replaying saved evidence. The public ptero command takes assembly paths directly; the operations below belong to the optional development binary. For repository checks, see Contributing.
Evaluation-only operations live in pterobacter-dev. It is built only on request and is never part of a default build or install.
cargo run --features dev --bin pterobacter-dev -- saved-evidence <EVIDENCE>
cargo run --features dev --bin pterobacter-dev -- reference-package <DIR> --expected-sha256 <SHA256> [--named-registry-sha256 <SHA256>] [--lineage-registry-sha256 <SHA256>]
cargo run --features dev --bin pterobacter-dev -- saved-evidence <EVIDENCE> --reference-package <DIR> --expected-sha256 <SHA256> [--named-registry-sha256 <SHA256>] [--lineage-registry-sha256 <SHA256>]
cargo run --features dev --bin pterobacter-dev -- saved-evidence <EVIDENCE> --reference-package <DIR> --expected-sha256 <SHA256> --exclude-references <MASK.txt> [--report-dir <NEW_DIRECTORY>]
cargo run --features dev --bin pterobacter-dev -- rescue-plan <EVIDENCE> --reference-package <DIR> --expected-sha256 <SHA256> [--anim-records <RECORDS> --anim-method-profile <PROFILE>]
cargo run --features dev --bin pterobacter-dev -- skani-search --database <DIR>/databases/primary_whole --query <QUERY.fa> [--genomovar]
cargo run --features dev --bin pterobacter-dev -- genomovar-diagnostic --report <REPORT.json> --expected-report-sha256 <SHA256> --reference-package <DIR> --expected-sha256 <SHA256> [--exclude-evidence-row <REFERENCE_ID>]... [--remove-group <GENOMOVAR_ID>]...
cargo run --features dev --bin pterobacter-dev -- genomovar-diagnostic --report <REPORT.json> --expected-report-sha256 <SHA256> --reference-package <DIR> --expected-sha256 <SHA256> --setting self_alias --exclude-references <PRIMARY_MASK.txt> --exclude-references-sha256 <SHA256> --mask-member <REFERENCE_ID>
saved-evidence reads recorded skani comparisons and prints the species/subspecies decision as JSON, including raw nearest evidence, competitors, scope assessments and all withholding reasons. It runs no new comparisons. Use pterobacter-dev saved-evidence --help for the replay options. For classification from an assembly, see the assembly guide.
reference-package authenticates a reference package directory against --expected-sha256, the SHA-256 that its portable.json must have. A manifest with any other digest is refused before its listing is read. Every file listed in the manifest must be present with the listed length and SHA-256, and no listed path may be a symbolic link. A file in the directory that the manifest does not list is refused. The package must carry a licence manifest with the NCBI submitter-rights disclaimer. --named-registry-sha256 and --lineage-registry-sha256 pin the two registry tables to digests you give. Nothing is pinned by default, so a table is checked against a digest only when you supply one.
The source manifest must be exactly the record the package’s eleven tables, recipe and skani indexes derive, following the research package builder. The record covers concepts with their parents, references, genomovar definitions, the historical type crosswalk, context records, the cohort summary and every count. Each reference is identified by component and accession, so an accession can be both a primary reference and a genomovar definition member. The reporting cohort is a separate record set. Its membership and evidence flags must agree with the package, and its coverage categories are summarised as written. On success the command prints the package identity, licence, counts, cohort summary and components as JSON, including the SHA-256 of each database.
A package converted from the version 1 format carries the version 1 portable.json as an attested conversion record. The verifier checks that the record lists the same package, source manifest, export attestation and assets as the version 2 manifest.
--reference-package authenticates the package in the same way, then requires the evidence to be bound to it. The evidence’s reference package digest must equal the verified manifest digest, or the digest of the attested version 1 manifest it was converted from. The evidence must cover the whole primary component. Each row must give what the package gives for its reference: the species and subspecies with their display names, the name status of the more specific of the two, the role (type_anchor or diversity), and no lineage. Contradictory evidence is refused, never corrected. The two flags must be given together. For rescue planning, saved ANIm decisions and reference masks, the verified package also supplies the primary panel in place of --reference-inventory; give one or the other. Without --reference-package the decision reports reference_package.status as not_verified.
genomovar-diagnostic accepts a completed assembly report with a completed, package-bound genomovar search. It checks the exact report bytes against --expected-report-sha256, verifies the package, and reuses saved evidence without running a new search. Repeat --mask-member to exclude definition members, --remove-group to omit whole groups, or --exclude-evidence-row to drop saved comparisons while retaining their required membership. The source report stays pinned and unchanged. Its genomovar_id remains null; diagnostic_would_assign_genomovar_id records the diagnostic candidate.
Member masks require --setting self_alias or --setting clone_block and a matching primary mask supplied through --exclude-references and --exclude-references-sha256. The parent is recomputed from the report’s original primary evidence under that exact mask, bound to the same query, package and analysis settings. An additional warning envelope can be supplied through --problem-warnings and --problem-warnings-sha256; its artifacts are checked before recomputing the parent. An ANIm-enabled parent can also use --anim-records with --anim-method-profile, bound only to pairs requested by its masked plan. Valid parent withholding produces diagnostic_outcome: gv_withheld_parent and the parent reasons. Invalid evidence bindings produce an input error. The command exists only in the feature-gated development binary.
Development exit codes
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Failure: an unreadable file, invalid saved evidence, an I/O error reading a package, or a listed path that is a symbolic link. |
| 2 | Usage error: an unknown option, a missing argument, a malformed digest, or a flag given without the flag it requires. |
| 3 | Missing: the manifest, or a file it lists, is not in the package. |
| 4 | Altered: a file’s length or SHA-256 differs from the manifest, or it is longer than listed. |
| 5 | Truncated: a file is shorter than its listed length. |
| 6 | Incompatible: the package or licence schema is not one this build reads. |
| 7 | Inconsistent: the manifest, a component, a table, an attestation or the licence manifest disagrees with the others or is incomplete, or a listed path is unsafe or repeated. |
| 8 | Unresolved: the saved evidence was searched against another reference package, covers another number of references than the component holds, names a reference the component does not have, or gives a reference a species, subspecies, display name, name status, role or lineage that differs from the package’s. |
| 9 | Unexpected: portable.json, or a pinned registry table, does not have the SHA-256 given on the command line. |
| 10 | Unlisted: a file in the package directory is not listed in the manifest. |
Every rejection prints error: followed by the kind of rejection and a message that names the file or field at fault. It prints no decision.
The reciprocal ANIm development operation measures one pair with the approved maintained MUMmer4 profile. It writes input snapshots, native artifacts and exact integer evidence to a fresh directory:
cargo run --features dev --bin pterobacter-dev -- anim-pair --query QUERY.fa --reference REFERENCE.fa --output NEW_DIRECTORY
Frozen evaluation contracts, command bindings and scorer mappings are retained under docs/contracts/ for implementation audits.
Layout
| Path | Role |
|---|---|
src/evidence.rs, src/annotations.rs, src/reference/, src/decision.rs, src/report.rs, src/mlst/ | Pure decision and typing logic. Package bytes arrive through a port, so there is no file, terminal or process code. |
src/cli.rs, src/cli/assembly.rs, src/cli/mlst.rs, src/dev.rs | Argument parsing, files and exit codes for the public and development commands. |
src/bin/ | Thin entry points for ptero, pterobacter and pterobacter-dev. |
tests/ | Tests at the decision, command-line and packaging seams, with fixtures. |
docs/adr/ | Decisions and their reasons. |
CONTEXT.md | Vocabulary. |
See AGENTS.md for contribution rules and CONTEXT.md for the terms used here.
Fresh anim-pair measurements impose no tool time/memory ceiling unless --timeout-seconds or --memory-mib is positive. Omitted or zero controls preserve inherited limits. Saved-evidence replay retains historical settings. See execution and historical evidence for profile/cache identities and platform enforcement.
Licensing and source availability
Modified combined package: Pterobacter. This distribution notice was added on 15 October 2026. The native-source notes and retained patches describe changes to upstream components.
The combined Pterobacter executable is distributed under GPL-3.0-or-later. Pterobacter-authored source retains its MIT licence. These describe different scopes: the executable incorporates upstream code with additional conditions. The reference databases and MLST data have separate terms; this software licence does not replace them or apply automatically to your classification results.
You can run the program for any purpose. If you redistribute the combined executable, provide the applicable notices and complete corresponding source under the GPL conditions. Our releases must make that source available alongside the binaries. See GPLv3 sections 1, 5 and 6 for the terms.
Included components
MUMmer4’s maintained source includes Artistic-2.0 code and GPL-3.0-or-later Jellyfish and skip-list headers. Jellyfish templates are compiled through the native bridge. The distribution uses the GPL-compatible option in Artistic-2.0 section 4(c)(ii), preserving the original notices and the documented maintenance patch. The native-source README records the upstream revision and changes. The FSF licence list describes this compatibility route.
Third-party licences lists the Cargo and native notices to retain. MIT, Apache and other upstream grants remain attached to their source; the combined-executable licence does not erase them.
Preparing a corresponding-source archive
This is a maintainer operation. It prepares files locally and does not publish a release.
From a clean committed checkout with the locked dependencies cached:
cargo fetch --locked
python3 scripts/prepare_source_archive.py \
--staging-parent /path/to/temporary-storage \
--output /path/outside/the/checkout/pterobacter-source.tar.gz
The script exports that exact commit, vendors locked registry sources offline into temporary storage, and adds relative Cargo source configuration. It rejects changed tracked files, missing notices, links and existing outputs. The archive contains source, build scripts, the Cargo lockfile, dependency sources, component notices and the MUMmer maintenance patch. SOURCE-ARCHIVE.json records the commit and every other file’s size, mode and SHA-256. Its own digest and the archive digest are printed separately. Temporary vendoring is removed on exit and must not be committed.
Before distribution, extract the archive into a fresh directory, verify its complete inventory and build it with an empty Cargo home:
cd pterobacter-corresponding-source
CARGO_HOME=/path/to/empty-cargo-home \
CARGO_TARGET_DIR=/path/to/fresh-target \
cargo install --path . --locked --offline \
--root /path/to/fresh-install
A supported Rust toolchain and GNU C++ compiler must already be installed; they are not bundled. Run the installed synthetic smoke checks and record the actual target, compiler versions, binary hashes and source-archive hash. System libraries and compilers are separate from this source archive. If a binary package also ships runtime libraries, review those files and their terms explicitly.
Publish equivalent access to this exact corresponding source beside the executable download, with a clear link and matching release identity. GPLv3 section 6(d) allows a separate source download; users need not download it with the executable. Keep access available as required by the licence. The GitHub-generated source tarball alone does not include registry sources supplied by this preparation script.
The source archive is a software deliverable. It must not contain research workspaces, study genomes, validation outcomes, credentials or private material. Database publication and software release approval remain separate steps.
Install and use a database
Install the published database once:
ptero database install 2026-10-15
ptero database verify 2026-10-15
ptero --report-dir isolate-report isolate.fa
The database is published on Figshare.
This build pins version 2026-10-15 as its default, including the archive hashes,
extracted-file inventories and component bindings. Default installation downloads
about 333 MB for reference sketches, whole-genome FASTAs and MLST. Classification works
offline after installation and does not download missing components.
MLST is installed and enabled by default. To omit it:
ptero database install 2026-10-15 --no-mlst
ptero --no-mlst --report-dir isolate-report isolate.fa
Rerun installation without --no-mlst to add the scheme later. Typing uses records submitted on or before 31 December 2024; see MLST for coverage and limitations.
Use ptero database list to inspect versions and component presence. Select an
exact version with ptero -D 2026-10-15 isolate.fa; without -D, this build uses
the single published default pinned above. It never selects the newest directory
or substitutes another version. Downloads use the file URLs pinned for Figshare
record version 1, and every component must match its expected hashes.
On HPC systems, install to supported local storage using --database-dir DIR and
pass that option for classification too. Some shared filesystems, including a
tested GPFS filesystem, cannot support atomic activation and are refused.
A working local example
This source-checkout example generates archives from the existing synthetic native rescue and typing fixtures. It exercises provisioning and classification; its invented organisms and MLST alleles are software test data.
cargo build --locked --bins
# Choose a new directory on local storage. The generator refuses an existing path.
demo="$(mktemp -d)/example"
cargo run --locked --example local_database -- "$demo"
# This locally generated catalogue has a locally generated pin. For real data,
# obtain this pin through the trusted handoff, independently of the download.
pin="$(cat "$demo/catalogue.sha256")"
ptero_cmd=target/debug/ptero
"$ptero_cmd" --catalogue "$demo/catalogue.json" --catalogue-sha256 "$pin" \
--database-dir "$demo/store" database install fixture-1 \
--from-directory "$demo/archives"
"$ptero_cmd" --catalogue "$demo/catalogue.json" --catalogue-sha256 "$pin" \
--database-dir "$demo/store" -D fixture-1 "$demo/fixed-query.fa" > "$demo/report.json"
The catalogue override always requires -C/--catalogue and
-H/--catalogue-sha256 together. Local archive installation uses
-q/--from-directory, or repeated -f/--from-file paths whose filenames match the
catalogue. Neither local mode uses the network. A published catalogue entry may
supply an HTTPS download URL; certificate verification and HTTPS-only redirects
are enforced, with connection, response, body and total time limits. Archive size,
SHA-256 and decoded length remain mandatory. Candidates have no URLs or default.
Withdrawn entries require explicit selection, emit a warning and install only from
local archives. Retrieval alone is never a publication or scientific acceptance.
Components and paths
Default installation includes reference, its bound primary-fasta component, and the MLST scheme. --no-anim skips the FASTAs; --no-mlst skips the scheme. Use both to install only the reference sketches. During classification, --no-mlst skips typing even if the scheme is installed. The old -l/--mlst flags are accepted for compatibility but are no longer needed. Every selected
component is fully verified during reuse and classification. A missing required
component stops classification; missing or invalid requested typing produces a
failed MLST record and exit 6 while preserving a completed taxonomic result.
Linux defaults are $XDG_DATA_HOME/pterobacter/databases and
$XDG_STATE_HOME/pterobacter/evidence, falling back to
$HOME/.local/share and $HOME/.local/state. macOS uses
$HOME/Library/Application Support/pterobacter for both application roots.
-B/--database-dir overrides the database root. -e/--anim-output overrides
evidence placement. Otherwise each rescue-mode run reserves a unique, retained
state directory and reports it in data_provenance.anim_evidence_directory.
Missing directories are created privately; existing ancestor permissions stay as
configured. --version reads neither catalogue nor user directories.
An install holds one exclusive lock per database/version. Components are verified in private staging directories on the destination filesystem and activated with atomic no-replace rename. Installed bytes are immutable: corruption fails without replacement. A later component failure can leave earlier verified components installed; the requested set is reported ready only after all succeed. A failure after activation explicitly says the component was activated. Retry fully verifies it before reconstructing a missing receipt. Receipts live outside scientific directories and never authorize reuse. Interrupted locks/stages remain for owner inspection; cleanup removes only the current attempt’s temporary files.
Linux uses renameat2(RENAME_NOREPLACE) and macOS uses
renamex_np(RENAME_EXCL). Supported local storage is required for installation.
A tested shared GPFS filesystem rejected this operation; the installer refuses
unsupported filesystems safely. Select local storage with --database-dir, or
classify from verified explicit packages on shared storage. General HPC filesystem
installation support is not claimed.
Explicit packages and provenance
--reference-package DIR --expected-sha256 HEX continues to accept development
and public package flavours and conflicts with --database. Explicit ANIm and
MLST path/digest pairs override only their own components and still pass full
verification. When using an explicit reference, also supply an MLST path/digest pair or use --no-mlst. No unrelated managed scheme is chosen implicitly. An explicit reference never gains
an unrelated default FASTA component: any supplied FASTAs must bind to its exact
manifest. No default catalogue is inferred from an installation receipt.
JSON reports identify operator_pin, operator_pinned_catalogue or
embedded_catalogue as the reference trust source. Selected catalogue citation
metadata appears in JSON and database inspection; ordinary --version remains a
tool version. Public flavour metadata is an export profile, not evidence of
publication, redistribution rights or independent scientific validation.
MLST keeps its 31 December 2024 submission cutoff and limitation. A 2026 retrieval date does not establish newer coverage. The separately versioned current/custom contract supports compatible local seven-locus schemes with explicit provenance and rights. Current PubMLST provisioning remains unavailable pending source access and redistribution review; this interface does not fetch a new scheme.
Release preparation
The reference database is public at Figshare, version 2026-10-15. The first software release is still held for author approval. Source builds report version 0.0.0 until the release version is set.
Prepared distribution channels
| Channel | Prepared and checked | Publication status |
|---|---|---|
| crates.io | One Cargo package; embedded engines; installation from the packaged source | First upload pending |
| Linux x86_64 | Precompiled commands, runtime-library manifest, notices and checksums | First release pending |
| Apple Silicon macOS | Precompiled commands; requires Homebrew GCC and XZ runtimes | First release pending |
| GHCR | Non-root Linux amd64 image with embedded ANIm and MLST | First push pending |
| Reference database | Published archives; pinned installer, component verification and MLST | Available |
| User guide | Built with mdBook and published on GitHub Pages | Available |
The Linux/macOS build, test and installed-command checks pass for the prepared candidate. An Apple Silicon Mac also passed the fixed scientific parity panel: 60 inputs, 120 component comparisons, 44 reciprocal ANIm pairs and 60 reports under each calling policy. This is platform parity for the tested panel, not a universal accuracy or compatibility claim. Linux ARM and Windows are untested.
Real public-genome examples demonstrate the current output format and provide reproducible commands. They do not extend the independent validation dataset. The ANIm report retains its compiled not_yet_validated metadata; documentation does not change scientific status fields.
Source and licences
The combined executable is distributed under GPL-3.0-or-later conditions. Pterobacter-authored source retains MIT. Complete corresponding source, locked dependencies and component notices accompany executable distribution. The source archive is checked by an offline rebuild. See licensing.
Reference sketches, FASTAs and MLST have their own manifests and notices. The published export replaces the earlier private preparation package; it does not replace frozen research inputs. MLST is a 2026 retrieval of PubMLST submissions through 31 December 2024. See database management and MLST.
First-release sequence
- Approve public source visibility and the first software release.
- Review the release version, changelog and citation metadata. Update installation wording before tagging so the immutable crates.io README describes the intended channels.
- Create the reviewed version tag and wait for successful main CI at that exact commit.
- Run the Distribution workflow from main with that tag and publication enabled. It verifies the actual versioned crate, binaries, source archive and container before the publication job runs.
- Verify public crate installation, binary downloads, checksums and a public-database example. Confirm GHCR package visibility and test an anonymous pull. Update the guide to describe the channels as available only after those checks pass.
Preparation artifacts named 0.0.0 must not be relabelled as a release. The release workflow builds the tagged version. A registry token is configured, but its publication permissions will only be exercised by the first approved upload.
The GHCR publication job uses GITHUB_TOKEN with packages: write, loads the exact tested image and publishes complete corresponding source first. It refuses to replace a different image under an existing version tag. For a publication-only network failure, rerun failed jobs in the original workflow run to reuse its verified artifacts. A fresh build of the same source is not guaranteed to be byte-identical.
Software publication, manuscript submission and formal taxonomic acts are separate approvals.
Pterobacter report
This summary is derived from the JSON report, which is authoritative. Assemblies: 1.
Assembly 1: RHBSTW-00333
Input file: GCA_013738375.1.fna
Final call
Call status: assigned
- Species: assigned — Enterobacter xiangfangensis (ECTX-SP025)
- Subspecies: assigned — Enterobacter xiangfangensis subsp. hoffmannii (ECTX-SS007)
- Genomovar: ECTX-GV-2026-10-02-v1-GV10
- Reasons: —
- Subspecies reason: diagnostic_candidate_only
- Call basis: skani
- Nearest parent (not an assignment): species ECTX-SP025, skani ANI 100.0 %
Analysis settings and execution
- ANI thresholds: standard
- Validation status: not_yet_validated
- Minimum species ANI: 96
- Minimum subspecies ANI: 98
- Minimum aligned fraction (both directions): 80
- Subspecies margin (percentage points): 1
- Conflict ANI: 96
- Trigger lower ANI: 94.5
- Whole-assembly ANI method: skani
- Boundary ANI method: ANIm using MUMmer4
- Execution: complete at stage genomovar
Initial skani result and ANIm
- Initial skani result: assigned (species ECTX-SP025; reasons —)
- Trigger: false (at_or_above_96_v1_route)
- Rescue state: not_triggered
- Competitor panel: not_required
- Challenge check: not_applicable
- ANIm pairs: 0 required, 0 attempted, 0 completed, 0 no alignment, 0 failed, 0 not run
- skani panel: 140 references, 140 returned, 0 not returned
Strongest matches
The five highest skani references are shown, plus every exact tie at fifth place. Rows in one tie group are ordered by reference ID for display only; the order does not choose a winner. Each reference is evidence, not a vote. ANI methods are not mixed in one ranking: skani orders this table and any ANIm values are shown beside it.
| Tie group | Reference | Parent | skani ANI % | AF query % | AF reference % | ANIm identity QR/RQ % |
|---|---|---|---|---|---|---|
| 0 | primary_whole:GCA_013738375.1 | species ECTX-SP025 | 100.0 | 99.99 | 99.99 | — |
| 1 | primary_whole:GCA_001729745.1 | species ECTX-SP025 | 98.97 | 82.69 | 92.17 | — |
| 1 | primary_whole:GCA_013625435.1 | species ECTX-SP025 | 98.97 | 85.66 | 90.75 | — |
| 1 | primary_whole:GCA_052922205.1 | species ECTX-SP025 | 98.97 | 85.51 | 91.21 | — |
| 2 | primary_whole:GCA_027595125.1 | species ECTX-SP025 | 98.92 | 83.07 | 90.16 | — |
Whole-panel species and lineage summary
| Parent | Panel references | Returned | Best skani ANI % | Among strongest matches | Challenging references |
|---|---|---|---|---|---|
| species ECTX-SP025 | 30 | 30 | 100.0 | yes | — |
| species ECTX-SP009 | 5 | 5 | 94.32 | no | — |
| species ECTX-SP018 | 1 | 1 | 93.76 | no | — |
| species ECTX-SP016 | 2 | 2 | 91.5 | no | — |
| species ECTX-SP003 | 8 | 8 | 89.67 | no | — |
| species ECTX-SP007 | 4 | 4 | 89.48 | no | — |
| species ECTX-SP019 | 14 | 14 | 89.29 | no | — |
| species ECTX-SP014 | 1 | 1 | 89.17 | no | — |
| species ECTX-SP013 | 8 | 8 | 89.14 | no | — |
| species ECTX-SP002 | 8 | 8 | 89.01 | no | — |
| species ECTX-SP017 | 4 | 4 | 88.7 | no | — |
| species ECTX-SP023 | 7 | 7 | 88.63 | no | — |
| species ECTX-SP015 | 1 | 1 | 88.62 | no | — |
| species ECTX-SP011 | 8 | 8 | 88.59 | no | — |
| species ECTX-SP024 | 3 | 3 | 88.56 | no | — |
| species ECTX-SP005 | 3 | 3 | 88.54 | no | — |
| species ECTX-SP010 | 1 | 1 | 88.48 | no | — |
| species ECTX-SP021 | 4 | 4 | 88.34 | no | — |
| species ECTX-SP008 | 13 | 13 | 88.33 | no | — |
| species ECTX-SP006 | 1 | 1 | 87.99 | no | — |
| species ECTX-SP001 | 1 | 1 | 87.77 | no | — |
| species ECTX-SP012 | 8 | 8 | 87.67 | no | — |
| species ECTX-SP004 | 3 | 3 | 87.55 | no | — |
| species ECTX-SP022 | 2 | 2 | 86.9 | no | — |
Challenges
Not applicable: no rescue was attempted, so no challenge test ran.
Supplementary results
- MLST: complete
- state exact_profile_match, sequence type 286 (supplementary; it never sets a taxon)
- Genomovar search: assigned
Provenance
- Query SHA-256:
603ed679732e01cb7d1a06ec73d89a53fc12b6f6b22f071df5dee866cdf982b9 - Bases: 5215023; records: 8
- Evidence SHA-256: fa30effe40ead1906508371b3e110d4a4a982991c675e2122d7703767103b9b7
Data selection, citation and retained evidence:
{
"anim_evidence_directory": "single-alignments",
"anim_manifest_sha256": "02cd57a36119558ae62b93d8d87b1ef5563f3c8009040fa0867da13027ad195d",
"anim_trust": "embedded_catalogue",
"catalogue_sha256": "873353f91dee10efc5f41ec86daceeeb5a6e841e97e885fdd7912853dda25ff9",
"citation": {
"doi": "10.6084/m9.figshare.34640883.v1",
"record_version": 1,
"title": "Enterobacter reference database for Pterobacter, version 2026-10-15",
"url": "https://figshare.com/articles/dataset/Enterobacter_reference_database_for_Pterobacter_version_2026-10-15/34640883"
},
"database": "enterobacter-reference",
"mlst_manifest_sha256": "0f0a4bd051e7a29d97f530a38982026df10ca223805e7b0147b19796763978dd",
"mlst_requested": true,
"mlst_trust": "embedded_catalogue",
"reference_manifest_sha256": "f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28",
"reference_trust": "embedded_catalogue",
"status": "published",
"version": "2026-10-15"
}
- Reference package 2026-10-15, manifest SHA-256 f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28
- Software version: 0.0.0. Exact schema, method and analysis identities are retained in report.json.
What to do next
The assignment is conditional on the approved rules and the supplied sequence. It does not establish that the isolate is pure.
Pterobacter report
This summary is derived from the JSON report, which is authoritative. Assemblies: 2.
Assembly 1: RHBSTW-00333
Input file: GCA_013738375.1.fna
Final call
Call status: assigned
- Species: assigned — Enterobacter xiangfangensis (ECTX-SP025)
- Subspecies: assigned — Enterobacter xiangfangensis subsp. hoffmannii (ECTX-SS007)
- Genomovar: ECTX-GV-2026-10-02-v1-GV10
- Reasons: —
- Subspecies reason: diagnostic_candidate_only
- Call basis: skani
- Nearest parent (not an assignment): species ECTX-SP025, skani ANI 100.0 %
Analysis settings and execution
- ANI thresholds: standard
- Validation status: not_yet_validated
- Minimum species ANI: 96
- Minimum subspecies ANI: 98
- Minimum aligned fraction (both directions): 80
- Subspecies margin (percentage points): 1
- Conflict ANI: 96
- Trigger lower ANI: 94.5
- Whole-assembly ANI method: skani
- Boundary ANI method: ANIm using MUMmer4
- Execution: complete at stage genomovar
Initial skani result and ANIm
- Initial skani result: assigned (species ECTX-SP025; reasons —)
- Trigger: false (at_or_above_96_v1_route)
- Rescue state: not_triggered
- Competitor panel: not_required
- Challenge check: not_applicable
- ANIm pairs: 0 required, 0 attempted, 0 completed, 0 no alignment, 0 failed, 0 not run
- skani panel: 140 references, 140 returned, 0 not returned
Strongest matches
The five highest skani references are shown, plus every exact tie at fifth place. Rows in one tie group are ordered by reference ID for display only; the order does not choose a winner. Each reference is evidence, not a vote. ANI methods are not mixed in one ranking: skani orders this table and any ANIm values are shown beside it.
| Tie group | Reference | Parent | skani ANI % | AF query % | AF reference % | ANIm identity QR/RQ % |
|---|---|---|---|---|---|---|
| 0 | primary_whole:GCA_013738375.1 | species ECTX-SP025 | 100.0 | 99.99 | 99.99 | — |
| 1 | primary_whole:GCA_001729745.1 | species ECTX-SP025 | 98.97 | 82.69 | 92.17 | — |
| 1 | primary_whole:GCA_013625435.1 | species ECTX-SP025 | 98.97 | 85.66 | 90.75 | — |
| 1 | primary_whole:GCA_052922205.1 | species ECTX-SP025 | 98.97 | 85.51 | 91.21 | — |
| 2 | primary_whole:GCA_027595125.1 | species ECTX-SP025 | 98.92 | 83.07 | 90.16 | — |
Whole-panel species and lineage summary
| Parent | Panel references | Returned | Best skani ANI % | Among strongest matches | Challenging references |
|---|---|---|---|---|---|
| species ECTX-SP025 | 30 | 30 | 100.0 | yes | — |
| species ECTX-SP009 | 5 | 5 | 94.32 | no | — |
| species ECTX-SP018 | 1 | 1 | 93.76 | no | — |
| species ECTX-SP016 | 2 | 2 | 91.5 | no | — |
| species ECTX-SP003 | 8 | 8 | 89.67 | no | — |
| species ECTX-SP007 | 4 | 4 | 89.48 | no | — |
| species ECTX-SP019 | 14 | 14 | 89.29 | no | — |
| species ECTX-SP014 | 1 | 1 | 89.17 | no | — |
| species ECTX-SP013 | 8 | 8 | 89.14 | no | — |
| species ECTX-SP002 | 8 | 8 | 89.01 | no | — |
| species ECTX-SP017 | 4 | 4 | 88.7 | no | — |
| species ECTX-SP023 | 7 | 7 | 88.63 | no | — |
| species ECTX-SP015 | 1 | 1 | 88.62 | no | — |
| species ECTX-SP011 | 8 | 8 | 88.59 | no | — |
| species ECTX-SP024 | 3 | 3 | 88.56 | no | — |
| species ECTX-SP005 | 3 | 3 | 88.54 | no | — |
| species ECTX-SP010 | 1 | 1 | 88.48 | no | — |
| species ECTX-SP021 | 4 | 4 | 88.34 | no | — |
| species ECTX-SP008 | 13 | 13 | 88.33 | no | — |
| species ECTX-SP006 | 1 | 1 | 87.99 | no | — |
| species ECTX-SP001 | 1 | 1 | 87.77 | no | — |
| species ECTX-SP012 | 8 | 8 | 87.67 | no | — |
| species ECTX-SP004 | 3 | 3 | 87.55 | no | — |
| species ECTX-SP022 | 2 | 2 | 86.9 | no | — |
Challenges
Not applicable: no rescue was attempted, so no challenge test ran.
Supplementary results
- MLST: complete
- state exact_profile_match, sequence type 286 (supplementary; it never sets a taxon)
- Genomovar search: assigned
Provenance
- Query SHA-256:
603ed679732e01cb7d1a06ec73d89a53fc12b6f6b22f071df5dee866cdf982b9 - Bases: 5215023; records: 8
- Evidence SHA-256: fa30effe40ead1906508371b3e110d4a4a982991c675e2122d7703767103b9b7
Data selection, citation and retained evidence:
{
"anim_evidence_directory": "batch-alignments",
"anim_manifest_sha256": "02cd57a36119558ae62b93d8d87b1ef5563f3c8009040fa0867da13027ad195d",
"anim_trust": "embedded_catalogue",
"catalogue_sha256": "873353f91dee10efc5f41ec86daceeeb5a6e841e97e885fdd7912853dda25ff9",
"citation": {
"doi": "10.6084/m9.figshare.34640883.v1",
"record_version": 1,
"title": "Enterobacter reference database for Pterobacter, version 2026-10-15",
"url": "https://figshare.com/articles/dataset/Enterobacter_reference_database_for_Pterobacter_version_2026-10-15/34640883"
},
"database": "enterobacter-reference",
"mlst_manifest_sha256": "0f0a4bd051e7a29d97f530a38982026df10ca223805e7b0147b19796763978dd",
"mlst_requested": true,
"mlst_trust": "embedded_catalogue",
"reference_manifest_sha256": "f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28",
"reference_trust": "embedded_catalogue",
"status": "published",
"version": "2026-10-15"
}
- Reference package 2026-10-15, manifest SHA-256 f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28
- Software version: 0.0.0. Exact schema, method and analysis identities are retained in report.json.
What to do next
The assignment is conditional on the approved rules and the supplied sequence. It does not establish that the isolate is pure.
Assembly 2: ECC-219
Input file: GCA_043966805.1.fna
Final call
Call status: unresolved
- Species: unresolved (no assignment)
- Subspecies: unresolved (no assignment)
- Genomovar: none reported
- Reasons: ANIm_no_strict_witness
- Subspecies reason: parent_species_unresolved
- Nearest parent (not an assignment): Enterobacter nematophilus (species ECTX-SP014), skani ANI 94.83 %
Analysis settings and execution
- ANI thresholds: standard
- Validation status: not_yet_validated
- Minimum species ANI: 96
- Minimum subspecies ANI: 98
- Minimum aligned fraction (both directions): 80
- Subspecies margin (percentage points): 1
- Conflict ANI: 96
- Trigger lower ANI: 94.5
- Whole-assembly ANI method: skani
- Boundary ANI method: ANIm using MUMmer4
- Execution: complete at stage genomovar
Initial skani result and ANIm
- Initial skani result: unresolved (species —; reasons nearest_below_species_ANI)
- Trigger: true (triggered_with_witness_candidate)
- Rescue state: withheld
- Competitor panel: not_required_no_witness
- Challenge check: not_assessed
- ANIm pairs: 1 required, 1 attempted, 1 completed, 0 no alignment, 0 failed, 0 not run
- skani panel: 140 references, 140 returned, 0 not returned
Strongest matches
The five highest skani references are shown, plus every exact tie at fifth place. Rows in one tie group are ordered by reference ID for display only; the order does not choose a winner. Each reference is evidence, not a vote. ANI methods are not mixed in one ranking: skani orders this table and any ANIm values are shown beside it.
| Tie group | Reference | Parent | skani ANI % | AF query % | AF reference % | ANIm identity QR/RQ % |
|---|---|---|---|---|---|---|
| 0 | primary_whole:GCA_026344075.1 | species ECTX-SP014 | 94.83 | 82.65 | 88.26 | 95.02964941527868 / 95.0343144759382 |
| 1 | primary_whole:GCA_031218175.1 | species ECTX-SP003 | 94.31 | 80.89 | 85.57 | — |
| 2 | primary_whole:GCA_043970685.1 | species ECTX-SP003 | 94.3 | 80.33 | 86.03 | — |
| 3 | primary_whole:GCA_043967505.1 | species ECTX-SP003 | 94.18 | 81.06 | 85.68 | — |
| 4 | primary_whole:GCA_043966825.1 | species ECTX-SP003 | 94.06 | 80.54 | 84.03 | — |
Whole-panel species and lineage summary
| Parent | Panel references | Returned | Best skani ANI % | Among strongest matches | Challenging references |
|---|---|---|---|---|---|
| species ECTX-SP014 | 1 | 1 | 94.83 | yes | — |
| species ECTX-SP003 | 8 | 8 | 94.31 | yes | — |
| species ECTX-SP007 | 4 | 4 | 93.37 | no | — |
| species ECTX-SP002 | 8 | 8 | 92.48 | no | — |
| species ECTX-SP017 | 4 | 4 | 91.98 | no | — |
| species ECTX-SP023 | 7 | 7 | 91.97 | no | — |
| species ECTX-SP019 | 14 | 14 | 91.85 | no | — |
| species ECTX-SP005 | 3 | 3 | 91.63 | no | — |
| species ECTX-SP011 | 8 | 8 | 91.63 | no | — |
| species ECTX-SP006 | 1 | 1 | 91.11 | no | — |
| species ECTX-SP021 | 4 | 4 | 90.82 | no | — |
| species ECTX-SP013 | 8 | 8 | 90.68 | no | — |
| species ECTX-SP001 | 1 | 1 | 90.02 | no | — |
| species ECTX-SP024 | 3 | 3 | 89.63 | no | — |
| species ECTX-SP008 | 13 | 13 | 89.51 | no | — |
| species ECTX-SP025 | 30 | 30 | 89.45 | no | — |
| species ECTX-SP009 | 5 | 5 | 89.4 | no | — |
| species ECTX-SP010 | 1 | 1 | 89.22 | no | — |
| species ECTX-SP016 | 2 | 2 | 89.22 | no | — |
| species ECTX-SP018 | 1 | 1 | 89.21 | no | — |
| species ECTX-SP012 | 8 | 8 | 89.04 | no | — |
| species ECTX-SP015 | 1 | 1 | 88.65 | no | — |
| species ECTX-SP004 | 3 | 3 | 87.98 | no | — |
| species ECTX-SP022 | 2 | 2 | 87.15 | no | — |
Challenges
Not assessed: the run stopped before the competitor panel was measured, or the analysis did not need it. The absence of a listed challenge is not a negative result.
Supplementary results
- MLST: complete
- state exact_profile_match, sequence type 2274 (supplementary; it never sets a taxon)
- Genomovar search: withheld
Provenance
- Query SHA-256:
34f4924c5954e5c424ecdb5476386a3f5ddbfc7d09aa6be2f32c049806b177a0 - Bases: 5027913; records: 1
- Evidence SHA-256: b801c8ca941599167b057f88ffe6a8316a3d32bd0dfdc1362b4aa680e1e8c9c3
Data selection, citation and retained evidence:
{
"anim_evidence_directory": "batch-alignments",
"anim_manifest_sha256": "02cd57a36119558ae62b93d8d87b1ef5563f3c8009040fa0867da13027ad195d",
"anim_trust": "embedded_catalogue",
"catalogue_sha256": "873353f91dee10efc5f41ec86daceeeb5a6e841e97e885fdd7912853dda25ff9",
"citation": {
"doi": "10.6084/m9.figshare.34640883.v1",
"record_version": 1,
"title": "Enterobacter reference database for Pterobacter, version 2026-10-15",
"url": "https://figshare.com/articles/dataset/Enterobacter_reference_database_for_Pterobacter_version_2026-10-15/34640883"
},
"database": "enterobacter-reference",
"mlst_manifest_sha256": "0f0a4bd051e7a29d97f530a38982026df10ca223805e7b0147b19796763978dd",
"mlst_requested": true,
"mlst_trust": "embedded_catalogue",
"reference_manifest_sha256": "f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28",
"reference_trust": "embedded_catalogue",
"status": "published",
"version": "2026-10-15"
}
- Reference package 2026-10-15, manifest SHA-256 f7c82d8e912fdb08aec93b190316f482fd462b3c514c5b374f8c694af1278e28
- Software version: 0.0.0. Exact schema, method and analysis identities are retained in report.json.
What to do next
No assignment was made. Read the reasons, compare the strongest matches and any challenges, then follow the manual-review steps in the usage guide (docs/usage.md): a tree and an ANI check against the named references. The software does not invent a label.
Current and custom MLST package contract, version 2
This additive package format uses the existing seven-locus ungapped typing engine. It makes no new accuracy claim. Historical schema 1 and its frozen cutoff remain unchanged; the historical contract still applies to it.
manifest.json is authenticated by an independently supplied SHA-256 or a trusted
catalogue’s component pin. Version 2 requires these fields:
| Field | Requirement |
|---|---|
schema, schema_version | pterobacter.mlst-scheme/2, integer 2 |
package_id, scheme | Nonempty source-specific identity |
package_scope | custom or current_snapshot |
loci | Exactly dnaA, fusA, gyrB, leuS, pyrG, rplB, rpoB, in that order |
retrieved_utc | Valid UTC YYYY-MM-DDTHH:MM:SSZ timestamp |
sequence_state, currency_statement | Nonempty description and coverage limitation |
source | Nonempty name and nonempty HTTPS urls array |
rights | Nonempty statement, access, HTTPS terms_url; redistribution is permitted, restricted or unknown |
submission_coverage | {"kind":"unknown","through":null} or {"kind":"through_submission_date","through":"YYYY-MM-DD"} |
data_root, profiles_file | Safe relative directory and a single filename |
data_sha256 | Exact mapping of all eight data paths to lowercase SHA-256 |
allele_counts, profile_count | Counts matching the verified data |
Each locus file is data_root/LOCUS.tfa. The profile table is
data_root/profiles_file, with the same columns and allele/ST rules as schema 1.
The package inventory must contain exactly those eight files and manifest.json.
Paths use ASCII letters, digits, dots, underscores and hyphens in nonempty segments;
. and .. segments, absolute paths and links are refused.
Version 2 refuses the historical fields submission_cutoff,
complete_through_cutoff_independently_established and cutoff_evidence.
Reports carry the declared coverage separately from retrieval time, plus source,
rights, currency statement and package hashes. A dated coverage declaration is
reported as source-declared and not independently established. Unknown coverage
has a null report cutoff. No metadata field changes the typing or taxonomy rules.
current_snapshot describes the source’s snapshot claim. It does not prove that
all submissions are present, confer redistribution rights or authorize downloads.
Current PubMLST provisioning is unavailable until source-specific access and
rights are settled. Synthetic tests cover this contract without fetching a new
scheme; users remain responsible for obtaining a permitted, authenticated package.
MLST-UNGAPPED-r1
Issue #12 implements the MLST route chosen after issue #2. This contract names the new engine and describes the record it produces. Its job is to support the versioned amendment and pin mapping that the #24 integration needs before #25 evaluation. It does not amend P4a-r3, relabel the engine as mlst, or authorise evaluation or release.
Engine identity
terobacter-ungapped-mlst version 1 is route D of the feasibility study. It finds exact 32-mer seeds between the allele set and the assembly, in both orientations, and extends each seeded diagonal without gaps. Scoring is +1/−2 with a raw X-drop of 13, and the first maximum is kept. Before the rules run, an HSP is kept only with at least 95% identity and a score that passes an e-value of 1e-20. Ambiguous bases and N are mismatches and never seed. Lower case is upper-cased. The code is Rust, compiled into tero and terobacter, and needs no external executable or alignment library.
The comparator is mlst 2.32.2 with BLAST+ 2.16.0, running blastn -ungapped -word_size 32. Terobacter does not run it. The comparator’s rules were read from its GPL-2.0 source and observed in its output; no code was copied:
- a hit counts once its identical bases cover at least 50% of the allele;
- a full-length identical hit is exact; further exact hits append
,id, and an exact hit replaces an earlier~or?; - the first full-length inexact hit in report order gives
~id, and the first shorter one givesid?; - report order is contig, then the allele’s best HSP score, ties going to the later allele in database order;
- the score is
int((7 − 0.3·tilde − 0.5·partial − missing) · 90/7), plus 10 with an ST, and the STATUS table follows from it.
The X-drop and tie rule were fitted on the development fixtures. They reproduce every comparator HSP and every call there, but that agreement is in-sample. BLAST’s removal of HSPs with common endpoints and its query splitting are not modelled.
The record reports every value above under engine.profile, the comparator under engine.comparator, and the comparator-style ST, STATUS and SCORE under comparator_style. A receipt therefore names the engine that actually ran.
Scheme package
The operator passes a package directory and the SHA-256 of its manifest.json. The loader applies the frozen importer’s package checks. The manifest must be schema 1 for scheme ecloacae, with the seven loci in order, the 2024-12-31 submission cutoff, the exact cutoff limitation text, package ID, retrieval time, sequence state, data terms URL and complete_through_cutoff_independently_established: false. Each of the seven locus FASTAs and the profile table must match the SHA-256 listed in the manifest. Alleles must be locus_N records of A, C, G and T, with a digit ID that fits in u64. Larger IDs fail package validation before typing. STs and profiles must be unique, every profile must name alleles that exist, and the counts must match. The package is checked again before reports are written. Nothing is embedded in the binary, so whether to embed the scheme is still Michael’s decision from #2.
Record
The record keeps the frozen importer’s semantics, with the same derivation:
state:exact_profile_match,unmatched_profile,incomplete_profile,inexact_allelesorambiguous_alleles. Only seven unique exact alleles that form a listed profile givesequence_type. An exact profile the scheme does not list isunmatched_profile, never a new ST.- Per-locus
raw_token,state, reported IDs and sequence-verified exact locations: record ID (the first header word), 1-based inclusive coordinates and strand. Every location is checked against the hashed query sequence. profile_compatible_candidate_ST, given only when every repeated locus has one allele at distinct locations, withcandidate_is_reported_ST: falseand the copy-diagnostic reasons.database: package ID, manifest SHA-256, data SHA-256s, cutoff, retrieval time, sequence state, limitation text, data terms URL,complete_through_cutoff_independently_established: falseandpost_cutoff_currency: not_claimed.taxonomic_assignment_performed: false. MLST never sets or changes an assignment.
Repeated record identifiers, which would make locations ambiguous, fail the record. A failure gives status: failed, the stage (input, package, typing or package_recheck) and the error. It never gives a negative result.
Relation to the importer contract
The importer’s prepared-command contract pins mlst, blastn, any2fasta and a BLAST index, and none of these exist here. This record replaces the importer’s execution block with engine and drops query_path and the prepared command. The issue #2 diagnostic passed route D output to the importer under the comparator’s command, and that receipt is not provenance for this engine. Mapping this engine onto the P4a-r3 executable and profile pins is the amendment that #24 must record before #25.
Development evidence
tests/mlst_dev_baseline.rs matches all 52 valid development fixtures to the frozen comparator calls and importer records: tokens, ST, STATUS, SCORE, state, candidate ST, copy reasons and exact locations. tests/fixtures/mlst-dev/README.md records the derivation. Real-assembly parity is RG-4 in mbhall88/Enterobacter#25.