Conversation
Update the application version to 1.0.1 across the workspace crates (pathotypr-core, pathotypr-gui), the Tauri config, Cargo.lock and CITATION.cff. Zenodo marker/model data assets remain at v1.0.0 as they are versioned independently of the application.
analyze_genome loaded each --input-list sample with get_ref, which errors on any FASTA containing more than one record. Ordinary multi-contig draft assemblies (the norm for bacterial WGS) therefore aborted the entire classify run with a misleading 'Reference FASTA ... contains multiple records' message, even though the same files succeed via --input and --input-files. Read every record with get_genomes_from_fasta and run find_markers on each contig, aggregating matches under the sample name. get_ref stays reserved for the single-record reference genome.
detect_paired_end_files stored a single Option per read direction, so multiple R1 (or R2) files sharing a base name (chunked/lane-split Illumina output such as _R1_001, _R1_002) silently overwrote each other and roughly half the reads were dropped, skewing depth-based marker and resistance calls. Accumulate every R1 and R2 path per base name and concatenate them for the sample. Also replace the ineffective file_stem collision fallback (which usually equalled the derived name) with insert_unique_sample, so an unrelated single-end file can no longer merge its reads into an existing sample's counts.
The match and SplitFastq subcommands passed -k straight to needletail without calling validate_kmer_size (unlike classify/train/predict). k=0 underflows in needletail's update_position (debug panic; release yields zero k-mers and a silent 'no match'/'Unclassified' result), and k>32 overflows the u64 2-bit packing so distinct k-mers collide, producing a wrong best match. Validate k to 1..=31 up front in both subcommands.
- excel: derive the .xlsx path by stripping the trailing .tsv extension instead of str::replace, which mangled any earlier '.tsv' in the path. - gff: use saturating_sub(1) for the 1-based->0-based start conversion so a malformed CDS start of 0 no longer underflows (matching markers/masking). - split_kmer: truncate the logged marker header by characters, not raw byte index 80, which panicked when byte 80 fell inside a UTF-8 char. - train: flush the buffered writer before reporting success so a failed final write surfaces instead of silently corrupting the saved model. - predict: skip sequences shorter than k (not just empty ones), which otherwise received a bogus high-confidence lineage call.
run_classify and run_split_fastq derived the per-marker output prefix from the marker file's basename only, so two marker files with the same basename (selected from different folders) produced the same prefix and the second run silently overwrote the first's output while still reporting success. Include the marker index in the prefix to guarantee uniqueness.
is_disallowed_ipv6 did not normalize IPv4-mapped addresses, so an internal IPv4 target could be reached via the ::ffff:a.b.c.d form (e.g. ::ffff:169.254.169.254 for cloud metadata, or ::ffff:127.0.0.1), bypassing the IPv4 rules on dual-stack hosts. Fold mapped (and deprecated IPv4-compatible) addresses back through is_disallowed_ipv4; ::1 and :: are unaffected as to_ipv4_mapped returns None for them.
escapeHtml relied on textContent/innerHTML, which escapes & < > but not quotes, so data-derived values interpolated into quoted HTML attributes (e.g. option value="...", title="...", data-filter-id="...") could break out of the attribute and inject markup/handlers into the Tauri webview. Escape " and ' as well so the shared helper is safe in attribute contexts.
…ogress and tracks - forms/loadDemoData: guard writes to the optional match-coarse-top-n / match-coarse-stride controls, which are absent from the DOM and threw a TypeError that aborted the whole one-click demo/onboarding loader. - forms/detectInputListHasHeader: treat a second column that looks like a path (separator or file extension) as data, so a real first sample is no longer misread as a header and dropped from the classify track context. - progress: stop the progress-complete listener from force-marking every step 'completed'; the backend emits it on error paths too, which made a failed run show all steps green. stopProgress finalizes by real outcome. - visualization/match track: map overview-strip clicks through the full domain instead of the zoom window, so clicking the overview navigates correctly once zoomed in. - visualization: test gene start/end finiteness on the raw value; Number(null) is 0, which read missing gene coordinates as position 0 and hid the inferred-gene fallback when a sample has no GFF.
…resolver validate_download_url resolved the host and checked its IPs, but reqwest re-resolved the host when connecting, so an attacker controlling the URL and a low-TTL DNS record could return a public IP at validation time and a private/loopback IP at connect time (TOCTOU), reaching internal services. Install a custom reqwest DNS resolver (SsrfGuardResolver) that rejects any resolution containing a local/reserved address. reqwest uses it for the actual connection and for every redirect, so validation and connection share the same resolution. Public addresses are returned unchanged, preserving CDN failover.
Set up a Material for MkDocs site that renders the existing guides as a navigable, searchable documentation site with light and dark themes. - mkdocs.yml: Material theme, deep-purple palette with light/dark toggle, tabbed navigation, search and pymdownx extensions. - docs/index.md: landing page (overview, five commands, highlights, quick start, citation). - docs/installation.md: desktop, Bioconda and from-source instructions plus the MTBC marker/model downloads. - docs/benchmarks.md: convert the <picture> blocks to Material light/dark images and vendor the figures under docs/assets so the site is self-contained. - .github/workflows/docs.yml: build (strict) and deploy to GitHub Pages. - Remove docs/README.md (superseded by index.md to avoid a URL clash).
The home hero showed the light scheme SVG in both themes. Add the dark variant and switch between them with Material's #only-light/#only-dark, matching the benchmark figures.
Rewrite the five command pages (train, predict, classify, split-fastq, match) to a consistent template: synopsis, an options table verified against the clap definitions, tabbed examples, and an exact output-columns reference. Improve the input-format, marker-format and GUI guides. Add three new pages and wire them into the navigation: a Getting started tutorial (MTBC), an Output files reference, and an FAQ/troubleshooting page. Fixes several inaccuracies found while cross-checking against the source: -i/--input vs --input-list contig handling, GFF-derived vs marker-derived detail columns, the split-fastq k-mer range, the match containment wording, and the top-level-only -V/--version flag.
Bring the seven algorithm pages plus the section index to the same Material standard as the command guides: a bold one-line summary, sentence-case headings, admonitions for the key rationale/caveats, a language on every code block, and a 'See also' section cross-linking the relevant commands. Correct several inaccuracies (mostly pre-existing) found by cross-checking against the source: - predict: confidence/margin divide by the model's tree count, not a fixed 100; sequences shorter than k (not only empty ones) are skipped. - match: the --early-stop-confidence, --early-stop-min-kmers and --strict-percentages options are defined but never read — documented as reserved/no-effect in both the command and algorithm pages. - marker genotyping: the Bloom hash is multiplicative (multiply-mod), not multiply-shift. - assembly classification: the text index is also used for non-ACGT marker k-mers (not only k > 32); marker keys use a hand-rolled 2-bit encoder.
Replace the deep-purple palette with a red-and-black scheme drawn from the logo: a white header in light mode (so the black+red logo reads cleanly) and a charcoal header in dark mode, with links and accents in the logo's brick red (#b01000 on light, a brighter #ff5a4d on dark) via a small custom stylesheet.
Grouping accumulated R1/R2 paths by filename only, so two distinct isolates whose files share a name (e.g. /runA/S1_R1.fastq.gz and /runB/S1_R1.fastq.gz) were merged into one sample. Their k-mer counts were summed into a single marker vector, producing a chimeric lineage/resistance call while the second isolate vanished from the run. The GUI made this easy to hit because the dropzone accumulates selections across folders. Key the grouping by directory as well as base name, so only same-folder chunks merge. Also sort the groups before assigning names: collision suffixes were handed out in HashMap iteration order, so identical inputs could relabel samples between runs. Warn when a name has to be disambiguated instead of renaming silently. Add the module's first unit tests, covering chunk accumulation, the cross-directory case, unmatched-file isolation and naming determinism.
classify generated marker k-mers from the reference forward strand and scanned query genomes forward only (bit_kmers with canonical=false, and a plain substring lookup for the text index). Contig orientation in a draft assembly is arbitrary, so every marker sitting on a reverse-oriented contig was silently missed, under-calling lineages and resistance mutations. The FASTQ path already indexes all four orientations, so the two workflows disagreed on the same sample. Scan the reverse complement of each contig as well, and deduplicate matches by marker k-mer across contigs and strands: previously find_markers deduplicated per contig only, so a marker present on several contigs inflated the lineage tally. Both genome entry points now share one helper, and two tests cover the reverse-oriented contig and the repeated-marker cases.
…tput and flanks - A genome with no marker hits emits a detail row whose lineage column is empty; the summary builder returned before registering the genome, so it vanished from *_summary.tsv. The summary silently had fewer rows than there were input genomes. Register the genome first — it now appears as Unclassified. - Masked FASTA files were named from the input file stem alone, so two samples laid out as <sample>/assembly.fasta overwrote each other's output. Disambiguate colliding names, and register each path before writing so a partial file is cleaned up on failure or cancellation (the previous code returned via ? without cleanup and registered only after success). - Reject --min-flank-bases values that leave no room for the allele inside the k-mer, and fail when no usable marker k-mer could be built at all. Both previously produced an empty marker index, reporting every genome as Unclassified with no error.
… file - The three cleanup routines derived the .xlsx path with Path::with_extension while the Excel writers derive it by stripping a trailing .tsv. For any output not ending in .tsv (e.g. -o results.out) cleanup deleted 'results.xlsx' — potentially an unrelated user file — and left the real partial 'results.out.xlsx' in place. Share the writer's derivation instead. - predict: several failures between creating the output TSV and the final flush returned via ? without cleanup, leaving a header-only or truncated predictions file that looks like a finished result. - train: the feature-importance and coordinates writers were dropped without an explicit flush, so a failed final write was swallowed and a truncated report was announced as written.
…stale file lists
- visualization: the lineage:count cell was split on [\s,;], but ';' is the
delimiter *inside* a nested lineage path ("L2;L2.2:5") while both backends
join entries with a space. Nested entries were shredded, dropping the
leading component and mislabelling the lineage. Split on whitespace only.
- tauri bridge: read_fasta_range passed record_name, but Tauri v2 maps
camelCase JS keys onto snake_case parameters. The argument never arrived,
the Option deserialised to None and the wrong FASTA record was read.
- dropzone: setDropzoneFile updated input.value but left a previous
multi-file selection in input.dataset.files, which the form builders
prefer — so a freshly picked file was silently ignored in favour of the
earlier list. Clear it.
- k-mer controls: split-fastq and match shipped a GUI default of 21 while
the core (and the docs) default to 31, so the same input gave different
results in the GUI than on the CLI. The match field also allowed up to 51,
which the core rejects outright. Align both with the core.
…rupt files The summary .xlsx built its lineage:count cell by iterating a HashMap and joining with ", ", while the TSV sorts by count then name and joins with a space. The two files therefore disagreed for the same genome and the Excel ordering varied between identical runs. Use the TSV's ordering and separator. Also delete the partially written workbook when Workbook::save fails: every caller only warns, so a failed save left a corrupt .xlsx next to a run reported as successful.
parseMutationTrackData added a +1 offset when the position came from the SNPgenome or k-merPOS column, but classify already writes both as 1-based (format_marker_match emits genome_position + 1 and variant_start + 1). Every plotted sample coordinate was therefore one base too high. Drop the extra offset and the variables that only fed it.
Mask positions come from the marker TSV, which is defined against the reference, but they were applied to every record of every input FASTA. For a de-novo assembly the contigs bear no relation to those coordinates, so the run silently replaced arbitrary positions with N and produced a corrupt '_masked' file that is typically fed straight into a phylogeny. Mask only sequences that live in the reference coordinate system — records whose length matches the reference, which covers consensus genomes and reference-length alignments. Anything else is skipped with the reason logged, rather than emitting a misleading file. Tests cover both cases, and the documentation states the constraint.
…tabs - Smart drop routing assigned each file to the first dropzone whose extension matched, even one the user had already filled, so a second FASTA dropped into the Classify panel landed on the reference instead of the empty sample input. Prefer still-empty dropzones, fall back to any match, and never put a second file into a single-file dropzone. - The multi-marker-set tab bars were only rebuilt on multi-marker runs, so after such a run a later single-marker run still showed the previous run's tabs, pointing at stale output sets. Tear them down in the per-run reset.
The sidebar version is replaced at startup by the value the backend reports, but the literal baked into index.html still read v0.2.0. If that call ever fails the window would claim a version four releases old.
…ction view The genotyping output uses one shape for every panel: the marker TSV columns after REF/ALT are joined into lineage_path. For the WHO resistance catalogue that path is drug;resistance;marker;grade;gene;mutation, so a resistance run was being rendered as if those were lineage levels — drug names, WHO grades and gene symbols all shown as a lineage, with a meaningless major lineage. Add a dedicated insights module that recognises the resistance shape and renders three panels beneath the Split FASTQ evidence: - Drug resistance profile: one card per drug in clinical reading order (first line, Group A, companions, injectables), with the verdict taken from the strongest WHO grade found — grades 1/2 resistant, 3 uncertain, 4/5 not associated. Each card expands to gene, change, grade, depth and allele fraction. - Lineage levels: genuine lineage paths are rebuilt into the hierarchy they describe (L2 > L2.2 > L2.2.1) instead of a flat list of prefixes. - Allele fraction distribution: a histogram highlighting the 20-80% band, where a mixed infection shows up. Because the core only writes variants at or above --min-alt-percent, the panel says so when the data was truncated above that band rather than letting an empty middle read as clonal. Panel detection is majority-based on the WHO grade column, so a genuine lineage panel is never mistaken for a resistance one.
…neages Intermediate allele fractions cannot reveal a mixture at the default settings, because the core only writes variants at or above --min-alt-percent (95%). The signal that does survive is which lineages the *fixed* markers belong to: a single clone can only fix markers along one root-to-tip path, so fixed markers on divergent branches mean more than one strain. Resolve the observed lineage paths into their branch tips and count, for each, the markers no other branch can explain. That separation matters for sibling branches: markers on the shared ancestor (L2 for L2.1 vs L2.2) are reported as compatible but never counted as evidence for either, so shared ancestry cannot manufacture a mixture. A minimum of two branch-specific markers keeps a single stray marker from calling one. The panel leads the genotyping insights with the verdict and each branch's share of the branch-specific evidence.
classify runs the very same marker panels as split-fastq, including the WHO resistance catalogue, so an assembly genotyped against it was still being rendered as if drug names and WHO grades were lineage levels. Reuse the genotyping insight sections there; the allele-fraction panel simply does not appear because assemblies carry no read depth. Verified against real output: classify against the WHO catalogue on a sample carrying rpoB S450L, katG S315T, embB M306I and gyrA D94G now reports 'Resistance markers found for 4 drugs: RIF, INH, EMB, FQ'.
… path Every KPI flows from one tally of the label column. On a WHO resistance panel that column holds the whole marker path, so the header announced 'Primary call: FQ;FQ-R;gyrA_D94G;1) Assoc w R;gyrA;D94G' and the panel was still titled 'Lineage Distribution'. Re-tally resistance runs per sample by drug, so the cards, the chart and the single-sample outcome all describe drugs; summarise the sample as 'Resistant: RIF, INH, EMB, FQ'; and retitle the panel 'Resistance profile'. Assigned counts samples rather than summing the per-drug tally, which would otherwise report 600% assigned for one sample carrying six drugs' markers. showToolVisualization replaced the whole activeVisualizations entry, dropping the stored default title so the panel stayed renamed after switching back to a lineage run; preserve it. Also cap the mixed-infection branch list at six, account for the remainder, and warn when more than three branches appear: that is usually marker noise rather than that many co-infecting strains.
… runs A run with many samples was rendered as a list of per-sample cards, which stops being readable past a handful and silently merged every sample's mutations into one profile. Add two batch charts, and keep the cards for the single-sample case where they are the better form. - Resistance matrix: samples x drugs, drugs in clinical order. Each cell is a state, so it uses the fixed status palette; because a status colour must never carry meaning alone, every cell also has a glyph, and the chart ships a legend and a table view. - Lineage composition: one stacked bar per sample of branch-specific marker share. Colour follows the lineage, not its rank, so a branch keeps its hue across every bar; slots go to the branches that lead a sample and the whole tail folds into a single Other segment. Palettes are the validated data-viz defaults, run through the validator against this app's own surfaces (#ffffff / #192734): categorical slots 1-3 pass in both modes, and the status roles are used as documented with the glyph + label mitigation. Marks follow the spec: 2px surface gaps rather than borders, rounded data-ends, hairline chrome, labels only where they fit, and hit targets well above pinpoint size. Also stop pooling the mixed-infection verdict across a batch, where every sample's lineage would have counted as a co-infecting strain.
One point per called marker: read depth on a log x-axis against alternate allele fraction. Well-supported clean calls sit top right; points hugging the left edge rest on very few reads; weight in the shaded 20-80% band means more than one strain, with the depth behind each point visible — which the histogram alone cannot show. Single series, so it takes categorical slot 1 and needs no legend. Colour is deliberately not mapped to depth or fraction: both are already positional, and re-encoding them as hue would spend the only free channel on information the chart already carries. The 20-80% band is drawn as context, not as a series. Marks follow the spec: 8px dots with a 2px surface ring so overlapping points stay countable, solid hairline grid and axes, 1-2-5 ticks per decade so a tight cluster still has references nearby, and a binned table view as the scatter's tabular twin. Only read-based runs carry depth, so the chart is absent for assemblies. Verified against real output: a simulated 70/30 two-strain FASTQ, genotyped end to end, resolves into the two clusters the mixture predicts.
The earlier fix registered the genome inside update_summary_from_detail_line, but the caller trimmed the detail line with trim_end() before handing it over. For a genome with no marker hits — a name followed by empty columns — that stripped every tab, leaving a bare name the parser rejects as malformed, so the sample still vanished from *_summary.tsv. Trim only the line ending. Verified end to end: a FASTA whose record matches no marker now reports 'Unclassified' in the summary instead of being absent. Covered by a test on the exact row analyze_genome emits.
…l files --input-files is documented as one of the three input sources, but -l's requirement listed only --input as an alternative, so passing --input-files alone failed with 'the following required arguments were not provided: --input-list'. Only the GUI, which builds the args struct directly, ever reached that path. Both list-valued flags also took a single value per occurrence, so the documented '--input-files a.fasta b.fasta' was rejected with 'unexpected argument'. Accept multiple values per occurrence for --input-files and --gff-files.
An audit of all 22 pages against the source turned up 68 issues; the substantive ones are corrected here. - getting-started told readers to fetch H37Rv from NCBI, but the panels are built against MTB_ancestor_reference.fasta (the file the app itself downloads, defaults.rs). The two share coordinates but not alleles, so the tutorial silently built different diagnostic k-mers from the GUI. - SNPgenome and SNPreference were described as alleles; both are positions. - match's Best_Match_Reference is the full FASTA header line, not its first token, and a run with no shared k-mers still reports the first reference with a fraction of 0.0000 rather than emitting a header-only file. - classify: scanning is now on both strands with per-genome deduplication; multi-record FASTA is one genome per record with -i/--input-files but aggregated per sample with -l; the summary example used bare lineage names where the key is the full ';'-joined path. - -V/--version is a top-level flag only, not per-subcommand. - gui: bundles land in the workspace-root target/, Excel export is always on, the published installers are unsigned too, and the file map was out of date. - benchmarks: real MTB models are tens of KB, not 5-50 MB, and the 500-genome extrapolations did not match the measured per-genome rates. - algorithms: lineage counting tallies every ancestor prefix (so the winner is normally the shallowest level), and the Excel export has no conditional formatting. The download links still point at the 1.0.0 assets on purpose: 1.0.1 is not released, so bumping them would break every link.
The last 25 findings from the documentation audit, all small but each one wrong against the code: - predict: Header is the record's full FASTA header line, not just an identifier; no 'Unknown' label is ever emitted — an unresolved record gets a label with near-zero confidence; and the worked example's margin did not match its own numbers (0.96 winner - 0.03 runner-up is 0.93, not 0.92). - train: per-fold accuracies already print at the default verbosity, so -v is not needed to see them. - classify: --min-flank-bases must stay below half of --kmer-size or the run errors; --input-files names each genome '[filename] record_id'. - input formats: the Query FASTA row linked to the Reference FASTA section and credited predict with --input-files, which it does not have; a single --gff-files entry is applied to every FASTA; only split-fastq warns about a short marker row, classify skips it silently. - marker format / output files: -V/--version is top-level only; masked FASTA name collisions get a numeric suffix rather than overwriting. - faq: no checksums are published for the Zenodo assets. - getting-started: a Confidence_Margin of 0.40 is 40 points of the whole ensemble, not 40% more votes than the runner-up. - gui: cargo tauri dev has no front-end hot reload (the frontend is static files); commands.rs is what emits progress events. - benchmarks: the speedup column compares predict against train, not the reverse. - algorithms: the text marker index is reached via non-ACGT bases, since validate_kmer_size caps k at 31 and makes the k > 32 branch unreachable; lineage:count tallies every hierarchical level; Other_Votes is label:fraction to two decimals; the model version example was still 0.2.0.
The config declared devUrl http://localhost:1420 while beforeDevCommand was empty, so nothing ever served that port and cargo tauri dev looped forever printing 'Waiting for your frontend dev server to start'. The documented development command could never launch the app. The frontend is plain static files, so dropping devUrl lets Tauri serve frontendDist directly in development, which is what the docs already describe.
The admonition sat between the intro and the diagram and ran to nine lines, pushing the figure down and dominating the landing page. It now follows the figure and states the same limitation in three lines.
…ates The landing page shipped 4.2 MB of gzipped artwork. scheme-dark.png was 6563x2500 for a 900 px slot, and both the light and dark variants are fetched on every visit because #only-light/#only-dark hides one in CSS rather than skipping the request. Re-encoding the dark diagram as an 1800 px WebP takes it from 3.28 MB to 163 KB, and rounding the light SVG's path data from six decimal places to one takes it from 711 KB to 436 KB without touching how it renders: six decimals on a 1575-unit viewBox is far below one screen pixel. The logo was a 5658 px wordmark used both for the 65 px header slot and for the favicon, where a 2.7:1 image is unreadable. It is now 600 px, with the DNA mark from its centre as a square favicon. edit_uri was configured but content.action.edit was not, so the theme never rendered the button and the setting did nothing. Both actions are on now. Adds a Citation page carrying BibTeX, RIS and APA entries alongside the two DOIs, since that is what readers of the preprint come looking for, and shows a last-updated date per page so nobody has to guess how current a page is. Social cards give shared links a preview instead of a bare URL. Generating them needs cairo and pango, so they are built only in CI, where the workflow now installs those libraries. Total: 4.2 MB down to 657 KB.
The accent was only defined for the light scheme's tabs bar, so it vanished in dark mode. It also disappeared below Material's tabs breakpoint, where the tabs bar is hidden and took the rule with it, leaving phones with no accent at all. Dark mode now uses the brighter red that already carries links there, and below the breakpoint the header itself draws the rule.
frontend/ is the frontendDist Tauri embeds, so everything in it is paid for by every installer download. It held four copies of the workflow diagram totalling 9.3 MB: two PNGs the app displays, an SVG only the README linked, and a PDF nothing referenced at all. The SVG and the dark PNG were byte-for-byte identical to the copies already in docs/assets. The two the app uses are now 2400 px WebP, which keeps the max-width:92vw lightbox sharp while going from 5.66 MB to 0.51 MB. The README points at docs/assets instead of carrying its own copies, and the SVG and PDF are gone from the bundle; git history keeps them if the print master is needed. logo.png was the same 5658 px wordmark as the docs copy, displayed at 300 px at most, so it drops to 900 px. frontend/ goes from 9.82 MB to 1.4 MB.
The file carried a note calling itself legacy and kept for reference, but it was still inside frontendDist, so its 2324 lines were embedded in every installer. index.html loads exactly two scripts, Chart.js and js/main.js as a module, and defines no inline handlers, so nothing could reach the globals it declared. Removing it cannot change runtime behaviour. The GUI architecture listing in the docs no longer mentions it.
The install instructions already point at the bioconda channel, but nothing in the badge row showed the package is published there or how widely it is used. Both badges read live from anaconda.org, so they track new releases on their own. Uses shields.io with flat-square to match the badges already in the row, rather than the anaconda.org native badge, whose style would not fit.
…site Four things were wrong. The Contributors heading linked to the AMAP repository rather than this one, and doubled its closing parenthesis so GitHub rendered it as plain text instead of a link. A bare --- sat directly under the licence link, which makes it a setext heading, so the licence name rendered as a second H2 under the License section. A stray </div> closed a block that was never opened. And the drug-resistance panel was credited to the 2021 WHO catalogue in five places: it is built by convert_who_markers.py from WHO-UCN-TB-2023.6 and 2023.7, and the file published on Zenodo is byte-identical to that output. Every install link combined /releases/latest/download/ with a filename pinned to 1.0.0. Those resolve today because 1.0.0 is the latest release, but each one 404s the moment 1.0.1 ships, since the asset carries the new version in its name. The tables now name the files without linking them, above a single button to the releases page, which cannot go stale. The README also never once linked to the documentation site, sending readers to sixteen raw .md files that render without search or navigation. Those now point at the published pages, each checked against the live site. The header image uses logo/pathotypr.svg, a 34 KB vector, rather than the identical 5658 px PNG beside it.
edit_uri tracked the release branch, so every edit and view-source button would have 404'd once this branch merged and the branch was deleted. Pointing it at main makes them correct for the site's published lifetime. Until this merges the buttons lead to files that do not exist on main yet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release branch for 1.0.1: bug fixes across the CLI and the desktop app, new
genotyping visualisations, and a documentation site.
Correctness
Fixes found by auditing the codebase, each with a regression test where the
behaviour was testable:
classifyskipped genomes with no markers. They vanished from the summaryentirely instead of being reported as unclassified.
classifyscanned only the forward strand, so a marker on areverse-oriented contig was missed. It now scans both strands and counts each
marker once per genome.
--input-filescould not be used on its own and rejected more than onefile, despite being documented as accepting several.
--input-list.single chimeric sample.
silently produced wrong output.
file behind.
file.
download_filewas open to DNS rebinding. It now resolves through avalidating resolver.
cargo test --workspace: 74 passing.Desktop app
raw marker path.
fraction scatter for quality control.
branches, which is the signal that survives the
--min-alt-percentfilter.cargo tauri devstarts again. The config declared adevUrlwith nocommand to serve it, so the documented development command hung forever.
Documentation
A full MkDocs Material site at
https://pathogenomics-lab.github.io/pathotypr/, with 22 pages covering every
command, the input formats, the algorithms, benchmarks, an FAQ and a citation
page.
Every page was audited against the code; 68 factual errors were corrected,
including flags that do not exist, an arithmetic example that did not add up,
and the drug-resistance panel being credited to the 2021 WHO catalogue when it
is built from the 2023 one.
Size
The site's landing page carried 4.2 MB of gzipped artwork, and
frontend/(thedirectory Tauri embeds in every installer) held four copies of the same diagram.
frontend/After merging
edit_uriinmkdocs.ymlalready points atmain, so the documentation's editbuttons start resolving once this lands. The docs workflow still triggers on
pushes to
1.0.1; that entry can be dropped when the branch is deleted.