CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
Semantic versions with the date in the heading: `v0.2.0 — 20.08.2026`. The number
is the unique key of an entry, the date is informative: a working day may produce
several versions or none. Rules for choosing a number — `docs/VERSIONING.md`.
**The numbering starts here.** This journal opens at the first public release. The
development that produced it ran under its own numbering, up to `2.24.0`, and that
numbering was retired at publication: it measured how much had been built, and a
version number is meant to promise something else — that a person holding the
previous version knows what moving to this one does to their data and their
commands. Nobody outside had run any of those versions, so there was nothing to
promise. They are kept privately, in `CHANGELOG.pre-0.1.0.md`, and their tags live
in a namespace of their own (`pre-0.1.0/v2.24.0`), so that if the published
numbering ever reaches `2.24.0` it is a different tag on a different commit and
cannot be mistaken for one of them.
**How to read it.** The main sections of an entry are not the file list but three
curated ones: **what this changes in the conclusions**, **what is retracted**,
**what needs recomputing**. The file list at the bottom is generated from git
(`python3 src/tools/release_notes.py`). A **series break** is marked separately —
a change to `src/scholion/knowledge/` that alters the result on unchanged input.
Values from before and after such a change cannot go on the same chart without a
note.
**Who it is for.** Somebody who has never seen this repository and wants to know
what this version does. That decides what an entry contains: **new capabilities,
fixed defects, and what either of those means for data already stored.** It also
decides what an entry does NOT contain — the path a change took, which attempt
came first, what was learned along the way, whose machine anything ran on, and
who wrote it. Those are worth recording and belong elsewhere; in a release entry
they crowd out the two questions a reader actually has: what can I do now that I
could not, and what was wrong that is now right.
**What is not here.** Personal data and one person's findings: no genotypes, no
lab values, no dates of anyone's tests. This journal records what changed in the
**system**, not what was found in somebody.
---
<!-- NEW ENTRIES GO HERE -->
## v0.7.7 — 04.11.2026
The new Mitochondria body system links saved mtDNA readings to dated laboratory
observations, annual changes, related current prescriptions and recorded responses.
It shares the same answer across the web, CLI and assistant interfaces. No overall
mitochondrial health score or biological-age estimate is inferred. Opening the
system reuses the saved BAM analysis; no genome recalculation is required.
- Gene cards open with the role of the gene and then explain what the available reading can support. Reading depth and repeat information stay together. Genome lookup also returns the same structured result to compatible MCP clients. Existing saved readings are used directly.
- Where the evidence supports a genotype comparison, cards explain the possible personal meaning, the comparison group and the proposed mechanism before the limitations. Relevant laboratory observations remain distinct from a measured genetic effect. Weak or conflicting readings keep the study explanation without assigning its effect to the person. These explanations update from saved readings without a new BAM or PGS calculation.
- A failed coordinate lookup now distinguishes an unavailable reference, an empty result and an ambiguous placement. A local-only query stays local when it opens a gene's details.
### What this changes in the conclusions
All 71 included polygenic models show the populations reported for variant
discovery, training and evaluation, with links to the PGS Catalog records. The
summary distinguishes group-specific results, pooled evaluations, modified
weights and the reported independence of the evaluation sample. Missing
evidence remains explicit. The population comparison is separate from the reference panel used
to calculate a percentile and cannot establish personal applicability.
Open Genome → PGS in `scholion serve` or run `scholion prs`.
Genome → Mitochondria can analyze an indexed BAM locally. It reports the
estimated maternal haplogroup, mitochondrial variants with observed read
fractions and strand support, and coverage across the mitochondrial genome.
When an indexed ClinVar snapshot is available locally, it shows the annotation
for the exact allele alongside the reading. The analysis is opt-in and is
also available through the command line, MCP and plugins. Progress shows the
current stage, and cancellation preserves the previous report. If only the
ClinVar snapshot changes, annotations can be refreshed from saved variants.
Genome locus search shows progress and places results or errors beneath the
search field. Gene names and rsIDs work in either case. Search and gene
panels group positions by gene and retain the reading, evidence level and
sources for each position. Thematic panels show curated calls first and keep
other VCF records in region details. New sourced positions cover circadian,
neurological, metabolic and other thematic genes. The APOE
card shows each available position reading and identifies unresolved phase.
Thematic gene panels now separate 178 exact-allele ClinVar reference records
from four additional research associations. Disease classifications retain
their source condition or condition group, review status and versioned record.
Existing region readings remain available. A different alternative allele at
the same rsID is not treated as the selected allele; unsupported deletion
readings remain unresolved rather than inferred.
Gene descriptions show their sources and the recorded review date. Reference
functions and literature associations remain distinct from an established
personal variant effect. Source-review reminders do not trigger a network
request or genome recalculation automatically.
### What is retracted
None.
### What needs recomputing
**Run `scholion genotype-sites` — when newly added catalogue positions are missing and an indexed BAM with its reference genome is available.**
Previously stored PGS scores do not need recalculation for these catalogue and
presentation changes. Existing exact VCF calls are used directly. To fill newly
added supported positions that are absent from a variant-only VCF, run the
catalogue-position update from an indexed BAM with its reference genome. The
update now includes supported thematic-panel positions and preserves the prior
file if calling fails or is cancelled. It does not recompute PGS. Once the saved
site catalogue matches, explanation-only updates do not request another BAM run.
Unsupported complex variants remain explicitly unresolved.
The mitochondrial analysis requires a separate, explicitly requested first BAM
run. Opening its results reuses the saved report.
## v0.7.6 — 03.11.2026
### What this changes in the conclusions
Gene and prescription views use the same underlying reading and keep its
source and quality visible. Matching allele letters at different known
positions no longer confirm a reading. ClinVar and ACMG findings retain the
source record and show the limits that apply to the reading.
System summaries and the visit sheet show which measurements and dates
support a conclusion. Comparisons keep distinct units and draws separate.
A saved review can be compared with the current assessment to see whether
the result changed after an update to the data, rules or evaluation date.
The original review remains available. The assistant also reports where
profile data came from.
Run `scholion serve` to open the local application.
### What is retracted
Automatic interpretations based on incompatible genetic readings are
withheld. The recorded readings remain visible.
### What needs recomputing
Nothing. Existing measurements, genome files and PGS results remain compatible.
You can open a current review without regenerating genome data or scores.
## v0.7.5 — 02.11.2026
### What this changes in the conclusions
Measurement cards and annual summaries retain their existing values, dates,
source labels, trend qualifications and appearance across the application.
Gene cards, system insights, visit reports and prescription views retain their
existing content, navigation and expandable details.
Closing a browser tab or cancelling a request no longer stops the local server.
Screen changes release chart and polling resources, and delayed replies cannot
restore stale screen caches. A form from a previous profile is refused before
it can write to the newly selected profile.
Genotype views now retain conflicting saved and current readings consistently.
A confirmed reference call no longer loses to an older summary, and missing VCF
rows do not erase stored findings. Conflicting readings remain visible but no
longer support an automatic allele interpretation. Known alternative alleles at
two curated positions can be shown without assigning them another allele's effect.
Coverage messages distinguish single-copy and diploid intervals and no longer
print missing percentages or duplicate lists. Low interval coverage is explained
as a data limitation, not an automatic recommendation for more sequencing.
System pages place the genetic panel summary after the main results. Gene cards
combine read depth and any low-depth warning in one line, with the full note in
the reading details. Within each ClinVar category, better-reviewed records lead
and supported homozygous alternate calls come first among records of comparable
review confidence. Selected previously unnamed entries now show a sourced gene
or locus label and the studied trait. Where a gene cannot be established, the
card says so and explains what the cited study assessed.
Continue using `scholion serve` for the local application.
### What is retracted
Automatic allele interpretations based on conflicting source readings are withheld
until the discrepancy is resolved; the original observations are retained.
### What needs recomputing
Nothing. Existing profiles, genome results and measurement histories remain
compatible; no genome preparation or PGS recalculation is required.
## v0.7.4 — 27.10.2026
### What this changes in the conclusions
Gene cards retain the same information, reading states, scientific qualifications
and appearance across Genome, Radar, screening, gene panels and visit reports.
Their presentation is maintained together so future improvements can remain
consistent across these views. Navigation, expandable annotations, inheritance
details, laboratory comparisons and printing keep their existing behavior.
MCP tools also work when Ouroboros is installed alongside Scholion, including
clients using older MCP protocols. ClinVar annotation selects the reference for
the genome's assembly and preserves previous results if a refresh fails.
Unsupported or ambiguous HTTP request framing is rejected before changing data.
### What is retracted
A negative ACMG screen cannot be established from a multi-allelic reference whose
classification cannot be assigned to a particular allele. Explicit per-allele
classifications are matched to the allele actually carried. Saved ClinVar tables
with conflicting assemblies or altered recorded contents are preserved but no
longer used as current findings. Small ACMG source files receive a content check
even when their filesystem timestamps coincide.
### What needs recomputing
Nothing is required for unchanged valid data. No general genome reimport or
PGS recalculation is required. Unchanged valid
reports and normal workflows retain their behavior. If a saved ClinVar result
was produced against a different assembly, refresh that annotation using the
matching reference. An ACMG screen refused for ambiguous reference alleles needs
an allele-specific reference; the previous result stays on disk. Verification
of a large genome's full contents remains an explicit operation, separate from
the quick file-identity check used when opening a saved report. Use
`scholion acmg-scan --verify-only` when that full verification is needed.
## v0.7.3 — 27.10.2026
### What this changes in the conclusions
Gene and variant cards now use the same layout across genome findings,
disease screening, gene panels, body-system views, laboratory and medication
context, and visit sheets. Each card separates interpretation confidence,
gene/position, personal reading with zygosity, and biological function and
personal meaning. Open the local interface with `scholion serve`. Personal inheritance status remains distinct from a database
classification. Database annotations and inheritance details open separately.
Personal gene topics now read existing records from each gene interval when an
indexed genome and compatible gene coordinates are available, including genes without a
selected catalogue SNP. They retain each recorded allele and distinguish a
failed query from an empty result. Opening a topic does not call new variants
or remeasure BAM coverage. Cached results are bound to the selected profile,
input files, index, annotation and sample.
Packaged public GRCh38 intervals provide an offline coordinate fallback. They
do not invent coding exons or protein effects when transcript annotation is absent.
Scientific context separates gene function, gene–disease validity, a variant
association and individual applicability. References with verified missing
bibliography have been repaired. Incomplete project curation, conflicting
studies, an unverified individual estimate and absence of a source are separate
states; an unfilled field is not described as absence of scientific research.
Versioned database and guideline sources can support their own assertion types
without a publication identifier; they do not inherit permission for personal
clinical conclusions.
### What is retracted
Several positive or individual-effect descriptions overstated the cited evidence:
null pooled results, population-specific findings and genotype models were
previously presented too broadly. These descriptions and unsupported numerical
predictions have been corrected. Interpretation confidence is lower where the
sources conflict or only establish a gene–disease relationship. Database
classifications and actual recorded genotypes remain separate and unchanged.
Adding a reference never automatically enables a clinical recommendation.
### What needs recomputing
Nothing needs new genome calling, BAM preparation or polygenic scoring.
Existing readings remain valid. Reopen the affected panels to use the corrected
reference interpretations and gene-interval display. No personal data need to
be uploaded or reimported.
## v0.7.2 — 26.10.2026
**Carrier status is distinguished from disease.** Genome findings now show
zygosity, sourced inheritance and what the recorded call can establish. A single
heterozygous finding under a supported recessive model is presented as carrier
context, separately from the variant's ClinVar classification. Multiple variants
without established phase, mixed inheritance and incomplete readings remain
explicitly unresolved. The same context reaches the web, command line and
assistant tools. Existing saved findings need no genome recalculation; their
classification and secondary-finding reporting rules remain unchanged.
**Visit handouts connect genetics to the actual discussion.** Current deviations
are grouped by System with their measurements and available annual history.
A genetic factor is included for an explicit link to a discussed measurement
or a recorded prescription, with its inclusion reason and evidence limits.
System membership or alphabetical order alone no longer selects a factor.
Counts cover the complete relevant set before preview limits and distinguish
unique factors from their appearances in several Systems. Existing genomic
readings need no recalculation for this presentation change.
**The Today radar is visible immediately.** The system chart appears alongside
the existing overview without an extra disclosure click.
**Attention cards load faster.** A page shares repeated reference lookups and
reads indexed catalogue positions in bounded batches. Startup PDF integrity
checks run separately from the web interpreter. Measurements, genetic reading
checks and card contents are retained; this change requires no recalculation.
**Clinical estimates recognise available inputs more accurately.** Laboratory
values with an import-source witness and registered unit spellings are accepted
by the same conversion rules as other measurements. FIB-4 and PhenoAge use
measurements from one draw; missing inputs are named without borrowing values
from another draw.
**Verified reference readings remain visible.** Some newly added SNPs could be
shown as unread even when the aligned-read evidence confirmed the reference
alleles. The reading now retains the evidence file's assembly and coordinate.
An existing valid sites file needs no recalculation solely for this correction.
**Prescriptions have broader, qualified System links.** Named nutrients and
substances can relate to several Systems, with physiological context, research,
possible influence and monitoring distinguished. A link is not a demonstrated
treatment response. Food, gastrointestinal context outside the System map and
formulation-dependent records receive an explanation instead of an arbitrary
System assignment. The same relationships are available in the web, CLI and
assistant tools; saved prescriptions and doses are not rewritten.
**Compound laboratory documents retain separate collection dates.** Dated sections
inside a discharge summary can be imported without assigning every result to the
first date. Import, completeness checks and reverse provenance use the same
section boundaries. Invalid section dates are reported; different draws remain
separate. Reviewed archive previews retain their source and specimen checks.
**FHIR measurements retain their identity.** Additional verified LOINC mappings
preserve specimen, reported assay and source identifiers. Blood-specific
concentrations stay separate from serum/plasma; a reported MDRD estimate does not
become CKD-EPI. Vital signs and blood-pressure components enter the metrics layer.
An issue date without a collection date remains approximate, and conflicting
codes or invalid quantities receive a named refusal. FHIR bundles can also be
imported through the shared folder-import path used by the web and assistant.
Serum calcium imported from FHIR could previously be assigned to the separate
elemental whole-blood series. It now enters the serum total-calcium series; a
method-unspecified blood result stays separate from both.
**Reference gene panels keep biological context separate from personal findings.**
Pathway panels cover 525 genes and one separately labelled gene region within the
existing body Systems. Methylation is shared across the relevant Systems;
research associations in neurotransmission and stress are separate from clinical
neurogenetics. Gene functions, actual readings, variant context and available
measurements use one core across the application, CLI and assistant tools.
Scholion confidence, GenCC gene–disease validity and ClinVar classifications
remain separate. The supplementary GenCC snapshot retains all submitters and
validity classes, including disagreement; the absence of a submission is not a
negative genetic result. The main GenCC catalogue also retains all 1469 genes, with refreshed identity and function-source witnesses, bilingual descriptions, and current validity assertions for the existing disease concepts. Gene-level biology does not establish the effect of a personal variant. Gene names with mixed letter case retain their functions, translated disease labels and source identity when searched in upper case. Text reports also retain known functions and GenCC assertions when personal genotype reading is unavailable.
Every thematic gene card also opens the existing gene-region reader, including
genes without selected catalogue positions. It shows observed variants, the
reference transcript and measured coverage where available. Coding changes are
kept separate from other regional variants and from clinical classifications.
Opening a panel does not start a region scan or genome preparation; the CLI and
assistant expose the same explicitly requested reading.
**Gene-region coverage could incorrectly appear low or absent.** Some larger
alignment regions were read only in part, while other indexed intervals could
include extra reads. Coverage now respects the complete indexed block boundaries,
and a truncated alignment record produces an explicit failure instead of an
ordinary coverage result. Reference transcripts, observed sequence changes and
the limits of an absence claim remain visible together.
**Reference coordinates are not an effect allele.** Newly verified SNP positions
can be read in either supported genome build without borrowing a risk allele or
inferring reference homozygosity from a missing VCF row. Verified insertion,
deletion and repeat identities remain reference entries where specialized allele
reading is required. Known readings and source documents are retained.
**Gene descriptions lead finding cards.** Known gene biology and the recorded
reason for including a variant appear before inheritance and personal-meaning
qualifications. Additional reference descriptions distinguish protein genes,
noncoding transcripts and regulatory DNA regions. Stored readings and variant
classifications are retained; these descriptive changes do not require a genome
recalculation.
**Clinical estimates share one panel.** The existing FIB-4 index and PhenoAge
appear in a compact Today block and a detailed panel. Each retains its own
outcome, scale, dated inputs, source and applicability. Completed estimates also
appear in the visit sheet; missing inputs are not borrowed from another draw.
**Lumiflex application PDFs can be previewed and imported.** Printed summary and
daily statistics, recorded meal/activity events and approximate readings of
visible curves stay distinct. Post-meal comparisons require a complete visible
window and retain overlapping events. Sleep alignment uses explicit report timezones and sourced Garmin, WHOOP or
recorded sleep intervals. Approximate sleep-period means, ranges and variation
remain separate from device sleep summaries; the last recorded meal is not
assumed to be the last actual meal. Within-device night comparisons retain their
included and excluded records and exploratory sensitivity. Food and activity
events have separate visible comparison windows. Sensor data never become a fasting
laboratory glucose or HbA1c series. Source revisions remain available after an
update; failed or stopped imports preserve saved reports. The CLI, local web
application, MCP and Ouroboros tools use the same import and reading paths.
**Visit handouts follow the appointment focus.** Select body systems, thematic gene panels and a question for the visit. The short sheet combines dated measurements, existing system insights, relevant recorded prescriptions and qualified genetic context; important recorded alerts stay visible outside a narrow selection. GenCC gene–disease validity remains separate from variant confidence. The full handout and original structured fields remain available through the web, CLI, MCP and Ouroboros tools. Preparing a handout does not start genome or polygenic-score recalculation.
**Insight sources and changes are easier to inspect.** A system conclusion keeps
its used measurements, source identifiers, knowledge records and rule versions.
Comparisons with a saved review distinguish changed observations from changed
knowledge; missing original files remain explicit. Opening a report does not
start genome preparation or polygenic-score recalculation.
**Corrected reference statements.** NAT2 descriptions no longer claim that no
guideline exists: the hydralazine guideline and isoniazid studies have different
scopes, and an isolated position does not establish a complete acetylator
phenotype or dose. Longevity references correct mismatched citations, preserve
conflicting study results and do not count linked positions as independent
benefits. A low-quality or unverified genotype does not receive a personalized
longevity conclusion.
### What needs recomputing
**Run `scholion ingest-labs` — if a previous compound-form or FHIR import omitted measurements or used the wrong calcium series.**
Re-import the affected source folder. Earlier stored values are unchanged; inspect the import preview before replacing results.
**Run `scholion genotype-sites` — if newly added catalogue positions are unread and a local alignment with its matching reference is available.**
Review the targeted site-genotyping preview before confirming the operation. Existing results remain visible. This release does not require whole-genome preparation or polygenic-score recalculation merely because the version changed.
Reopen a previously exported gene-region report if its coverage informed a
decision: these reports calculate coverage again when requested. The coverage
reader correction does not change saved polygenic scores or require their
recalculation. The catalogue update is offered when its saved position set is
outdated; an already current set is not queued again.
For sleep alignment, re-import a wearable export if its saved night summaries
do not yet contain start and end timestamps. Missing timestamps are not inferred
from sleep duration. This does not require re-importing laboratory data.
Saved sensor reports are unchanged by a preview. Reference descriptions and clinical estimates update on read; use `scholion system clinical_estimates` and `scholion lifestyle` to inspect them.
## v0.7.1 — 23.10.2026
### New capabilities
- The updated Ouroboros integration opens Scholion's web interface inside its Widgets panel. A guided start creates a profile or connects an existing one after confirmation; the interface and assistant tools use the same profile. Laboratory imports and saved changes remain available after a restart. Existing medical files stay in place; this integration does not require recalculating genetic results or connecting a language model.
### Corrected conclusions
- Source-checked allele definitions follow the selected genome assembly, including positions whose reference base differs between GRCh37 and GRCh38. Site-reference evidence retains its actual read base; partial or unselected-sample calls cannot confirm a reference genotype.
- A different substitution at a curated position retains its observed genotype without inheriting the selected variant's effect. Conflicting calls at one position remain unresolved. Corrected multi-allelic definitions distinguish the read alleles, variant identity and effect allele; an unconfirmed effect direction stays explicit without hiding known gene function.
- A moved ACMG source can be verified by content instead of requiring a clinical rescan. Saved findings whose source or knowledge cannot be verified remain visible as historical rows, separately from current findings. The recorded ClinVar date, ACMG catalogue and interpretation rules remain distinct from a claim to have checked the latest online source.
- Body-composition estimates retain their units, original values and measurement pairing. Fat mass and fat-free mass are derived only from weight and fat percentage in the same exported record. Water, fat, muscle and bone estimates overlap and are never added as independent compartments. The manufacturer's bone-mass estimate is displayed separately from bone density.
- Body-composition changes are descriptive unless a sourced, applicable personal goal and comparable measurements support a goal comparison. Monthly means stay distinct from dated readings; invalid values and unknown units remain visible without becoming numeric health conclusions.
- Folder selection provides a system dialog on Windows and macOS and manual path entry on every platform. Selecting a source folder is separate from confirming its path or importing its contents. Cancellation and failed validation preserve the previous setting. Selecting a genome folder does not start an analysis; preparing a selected genome remains an explicit operation.
### Development checks
- Selecting a test module, class, method or file now runs only the requested tests in both test runners. Duplicate checks and repeated command launches have been consolidated while retaining the distinct regression cases. This does not change stored medical data or require recalculation.
### What is retracted
- Allele-specific interpretations with an unconfirmed correspondence to the genomic strand no longer establish a personal effect. Corrected reference explanations remain available with their limitations.
- A universal body-fat target and automatic improvement labels for unsupported body-composition comparisons are withdrawn. Device estimates do not count as several independent confirmations of a health change.
### What needs recomputing
Nothing needs a mandatory genomic recalculation solely because of this update.
Curated locus readings and panel explanations use the corrected definitions on the next request. Existing genotypes are preserved; this update alone does not require BAM preparation or PGS recalculation. If a position remains unread, inspect `scholion genome-updates` before requesting site genotyping.
Use `scholion recompute` to inspect the data-driven ACMG action. A moved source with a saved content witness can use `scholion acmg-scan --verify-only`. A changed genome, changed knowledge, or an older report without the required content witness needs an explicit clinical scan with the named inputs. Failed or cancelled verification preserves the saved report. No clinical scan starts merely by opening a page.
Re-import an available Garmin export with `scholion ingest-wearable FOLDER --device garmin` to retain per-record body-composition pairing and the bone estimate. Saved monthly history and local corrections are preserved; missing source pairing is not reconstructed from monthly averages. No genomic recalculation is needed for these changes.
## v0.7.0 — 19.10.2026
- Detailed genetic-panel effect and provenance explanations now follow the selected interface language; study values and original references are preserved.
- Radar units, saved lifestyle metric captions and compound ClinVar classification labels follow the selected language. Original measurements and personal notes are retained.
- Long-term laboratory trends can show a forming direction despite overlapping readings; isolated spikes remain separate observations. Dated patient reports of symptoms, everyday function and tolerability appear alongside system trends and in the visit brief, without being treated as measured treatment effects. Existing journal entries are preserved.
### What you can do now
- Today summarises the last year by body system, alongside the person map. Comparable period medians are assessed against recorded targets or stable laboratory ranges; changing ranges and unknown targets remain explicit. Treatment comparisons require recorded starts and monitored markers, and retain uncertainty about cause.
- Today brings the person and system map together with one attention list. Repeated laboratory deviations, changes distinguishable from recorded variation, movement toward an explicit target, and qualified wearable changes share their facts and sources. Related reasons appear together under highlighted, initially collapsed system headings; individual laboratory results remain in Labs.
- Today shows one annual phenotype overview. The CLI and MCP retain 30, 90 and 365-day analysis, for example `scholion overview --period 90`. Recorded monthly means remain labelled as means, and incomplete or incompatible observations do not establish a confident change.
- Save a local review explicitly and compare it with the next review. The comparison distinguishes changed observations from changed rules, brings withdrawn interpretations first, and does not mistake missing data for recovery.
- A visit brief brings together system changes over the year, current prescriptions and specific discussion questions, with completed courses and detailed measurements kept separately.
- Choose attention items for the visit agenda. The sheet reuses their evidence and keeps historical measurements and the optional genetic appendix separate. The same results and review operations are available through the CLI and MCP.
- A specific, calibrated LDL polygenic score can be presented alongside elevated measured LDL with its study population and treatment limitations. This is an association, not an individual disease probability or a causal explanation.
- Curated FOXO3 context includes positive and negative human studies, variant mechanism and applicability limits. The immune panel adds four distinct ORAI1 variants, separating recessive loss of function, dominant activation, benign classification and conflicting classifications.
- System insights now include the person's read genetic variants and dated lifestyle context. Supported matches between a variant association and a current laboratory abnormality are visible even without a trend, with evidence level and source. Normal readings remain normal despite a predisposition. The same context accompanies the clinician brief and agent responses; no genomic recalculation is required.
- System panels now compare source-checked variant associations with the same dated laboratory observations used in insights. Evidence level, call quality and applicability stay separate: historical or uncertain results remain visible without confirming a current association. The clinician view includes direct sources, knowledge-check dates, limitations and contrary observations; hypotheses remain labelled.
- A position can be compared with several relevant measurements. Composite contexts include phase-aware APOE, iron markers with HFE, thyroid-hormone ratios and possible HbA1c bias; collection identity and specimen requirements are checked before combining results. Broader gene mechanisms remain sourced hypotheses with the actual variant and GenCC assertion, rather than gene names being treated as diagnoses. Additional panels use the same comparison logic.
- Gene descriptions share one reading order across panels and genome views: known function, available variant interpretation, then confidence and expandable evidence. Low-confidence explanations remain readable, and GenCC validity stays distinct from Scholion's variant evidence level.
- Gene-function references now cover previously undescribed longevity catalogue genes, with NCBI Gene and Gene Ontology sources in both languages. Predicted functions, non-coding loci, pseudogenes and withdrawn models are distinguished. Study gene sets are kept separate from variant-to-gene assignments. Longevity catalogue disclosures use visible buttons, and gene lookup states retain the same description format.
- Current prescriptions can relate to several body systems through recognised classes, explicitly recorded ingredients and laboratory monitoring. Possible effects and monitoring remain distinct; unrecognised products are identified rather than assigned an unsupported action.
- Labs open as collapsed system groups with measured and abnormal counts. System cards can expand their current measurements and open the matching Labs group.
### What is retracted
**The individual favourable FOXO3 verdict is retired.** Positive human associations and studies that did not reproduce them are now shown together at Scholion level C. Existing genotype readings and the reference explanation remain available; no individual lifespan effect is assigned.
### Corrected display and consistency
- Empty genetic catalogues no longer appear as fully read negative results. Longevity counts distinguish individual gene symbols from study gene sets. Gene searches retain reference biology when a region cannot be read without an index. Undated assistant text is no longer labelled fresh.
- System trend insights follow the same selected measurement source as current values and period comparisons. Secondary device histories remain inspectable without silently replacing the main trend.
- Review history tracks changes to the effective laboratory range and its origin. Switching the display language does not change measurement identity or invalidate an otherwise unchanged review confirmation.
- An ambiguous device choice no longer produces a difference between unrelated device histories. Approximate laboratory dates remain visible but do not establish an exact before/during-treatment comparison. A visit agenda whose selected topics changed offers retry and explicit reselection instead of an unfinished loading screen.
- Recorded weight and wearable weight now share one source-labelled history across Today, Lifestyle, goals, charts and assistant responses. Weight and derived BMI use one plotted line; each point retains its source. Attention cards link to the system genetic panel and Lifestyle instead of repeating those details. BMI uses the same weights and recorded height. A newer recorded weight no longer disappears from a chart or leaves BMI pointing in an older direction. Month-only recorded values remain distinct from device monthly means; differing devices are never silently treated as one measurement method.
- The same current-value rule applies to mapped sleep, steps, resting heart rate and activity readings. Imported measurements no longer appear missing merely because they were not entered by hand.
- Personal and Visit views now open different working screens. The clinician introduction follows the selected language, and the complete technical reference remains available.
- The first screen renders the person map and phenotype before the heavier contextual review. Chart switches and visit actions are explicit, duplicate overview blocks are removed, and completed prescriptions remain in history instead of the current regimen.
### Existing data
- Expired courses no longer remain current solely because an old status says active. Absolute albumin in a protein-fraction panel is recognised separately from biochemical albumin; existing records are retained for source review.
- Existing laboratory, wearable and genetic records are retained. Reviews are saved only on request. This update does not automatically rerun PGS or whole-genome preparation.
- Garmin and WHOOP exports can be imported from the installed wheel without a separate source checkout.
- Older wearable summaries without sufficient coverage or uncertainty keep their values but cannot establish a qualified change. Newly imported daily Garmin records include the uncertainty needed for median comparisons.
- New curated positions use available verified readings; an unread position remains unread. Reference explanations do not imply that the variant is present.
### What needs recomputing
**Run `scholion genotype-sites` — if the new ORAI1 or FOXO3 positions are unread and your local alignment is available.**
Inspect unread positions with `scholion genome-updates` before requesting this
explicit catalogue-site genotyping operation. Existing verified calls need no repeat. Without the source alignment, retain the
saved readings and reference explanations; an unread position remains unknown.
PGS scores do not need recalculation for these additions.
## v0.6.9 — 15.10.2026
### What you can do now
**Preserve qualitative and interval laboratory results.** Urinalysis absence statements, microscopy counts and intervals, and respiratory PCR targets now retain their printed result, specimen, method, date, unit, reference text and source. They appear beside numeric series in CLI, web and agent lab reports and participate in archive completeness checks. Absence is never converted to zero and an interval is never reduced to a midpoint. Conflicting same-draw forms are reported without silently replacing another source. Reviewed archive previews include these rows and apply them atomically after confirmation. Wrapped quantitative SARS-CoV-2 S RBD total antibody rows are recognised separately from their interpretation thresholds.
Existing imported forms need a forced re-import to add these newly supported rows (`scholion ingest-labs FOLDER --force`). New recognition rules remain proposed and do not supply clinical reference intervals or verdicts. No genome recalculation is required.
### Corrected conclusions
**Keep reporting limits distinct from exact measurements.** Review summaries retain
less-than and greater-than signs and use the laboratory flag at the boundary.
A bounded observation no longer becomes an exact percentage change, personal
baseline shift or estimate of measurement scatter.
**Count confirmed deviations consistently.** A value recognised through an
unconfirmed rule remains visible, but does not increase the out-of-range count.
Invalid or future dates no longer establish that monitoring was completed recently.
**Keep historical results out of the current visit agenda.** Results older than
one year remain available in a separate history section. Values whose dates
cannot establish recency are retained for review rather than presented as current.
**Preserve laboratory row identity across wrapped lines.** Non-HDL cholesterol and
separately named renal formulae are retained instead of omitted or mistaken for
HDL or creatinine. Standard and high-sensitivity CRP remain separate assays;
a neighbouring analyte’s reference scale no longer supplies a false grade.
Unrecognised qualitative urinalysis rows are disclosed as labels for review,
without turning absent findings or intervals into invented scalar values.
New marker rules remain provisional until reviewed.
### Existing stored data
Inspect the updated summaries with `scholion labs`, `scholion overview` or
`scholion brief-review`. They update when reopened; no laboratory values or dates
are rewritten.
No genome or polygenic-score recalculation is needed for these corrections.
Previously saved polygenic results and the existing recalculation workflow remain
available.
### What needs recomputing
**Run `scholion ingest-labs FOLDER --force` — if laboratory forms were imported before this update.**
Re-import the original forms to recover omitted numeric rows, qualitative urinalysis results and PCR targets. This also separates newly recognised assay identities. Re-import does not automatically remove legacy points filed under a different assay: review those against the originals. Reopen the affected summaries or regenerate a saved visit sheet. No genome preparation or PGS recalculation is required.
---
## v0.6.8 — 11.10.2026
### What you can do now
**Recalculate saved PGS through the installed application.** Preview with
`scholion prs --recalculate` and confirm with
`scholion prs --recalculate --yes`. The web update panel and `sch_recompute`
use the same operation, with progress and cancellation. A source checkout is
no longer required. The operation reuses available scoring calls, including
reference homozygotes, and reads a matching BAM only for missing model positions.
VCF-only inputs retain their actual coverage; absent positions are not imputed.
A report moved to another computer names missing local inputs. Failed or stopped
work preserves the previous report, and a successful replacement keeps a backup.
**Read a gene with the scope of its examination.** Gene lookup combines catalogue
positions with available region findings, including noncoding differences.
The answer identifies the reference build, interval and transcript, links the
reference sequence, and shows measured depth and the fractions covered or lacking
reads. Unmeasured coverage is distinguished from zero coverage. A zero variant
count does not mean the gene is absent or every base matches the reference.
Treatment lists and timelines use the recorded prescription date as the intake
start when no separate intake start is recorded. Existing intake dates take
precedence. The result retains the source of the default; an ambiguous or invalid
prescription date does not supply a start. The treatment view distinguishes the
scheme date from the intake start and remembers the selected interface language.
### What changes in the conclusions
Saved PGS scores are rebuilt with checked called-allele scoring and pinned models. Previously recorded numbers remain visible as unverified saved values in PGS, system panels, lipid views, CLI and agent results until a new report is saved successfully. They carry a recalculation recommendation and do not enter confirmed high-score summaries.
Only verified calibration can establish a population percentile; an unavailable
reference remains an explicit limitation. Coverage alone does not establish
calibration or a disease probability. Gene conclusions remain bounded by the
positions called and the coverage measured.
A missing intake start no longer makes a dated prescription appear undated.
This default does not establish the actual first dose or a treatment response.
### What is retracted
Previously saved percentiles lacking verified scoring or calibration remain
diagnostic history; this release does not restore them as confirmed results.
### What needs recomputing
**Run `scholion prs --recalculate --yes` — if saved PGS scoring is unverified or the genome inputs, pinned model or reference population changed.**
Preview with `scholion prs --recalculate` before confirming. An application update alone does not require
repeating an already verified calculation. Review the plan and confirm before
starting; genome preparation can take time. Repeating BAM calls cannot supply a
missing reference distribution. Models without a pinned identity remain outside
the recalculation rather than being silently changed.
Gene lookups and existing prescription records are resolved when read, without
rewriting their stored history or automatically preparing the whole genome.
## v0.6.7 — 11.10.2026
### What you can do now
**Read genetic interpretations with their confidence and limitations.** Available catalogue interpretations remain accessible at every Scholion evidence level A–E. Inspect them with `scholion system <key> --json` and `scholion panel <key>`. Missing support is identified beside the interpretation rather than hiding the recorded wording. Gene function, variant evidence and GenCC gene–disease validity remain distinct. Clinical decisions belong to the clinician; automatic findings and decision routes retain their eligibility checks.
**Scan genetic panels in a consistent compact layout.** System summaries lead with the evidence letter, linked gene, reading and a short preview. Open a row's details for the full wording, sources, hypothesis passport and analytical checks. The complete catalogue starts folded in both patient and clinician views, including panels outside the radar. Evidence letters open the guide and gene names open the detailed reference.
**Keep the visit agenda focused.** Catalogue gaps such as a missing genetic mechanism, an undefined risk allele or unwritten genotype wording stay in variant details instead of becoming repetitive questions to the clinician. Questions about measured values, carriership and applicable polygenic scores remain. Prescriptions use a structured table with readable class names; uncertain system assignments and correction-route support start folded.
**Open the radar sooner.** The diagram appears before detailed cards finish loading. System cards are read together and reused when opened from the radar. Repeated input-file searches and coverage-reference calculations are avoided within the reading; the next reading still checks current inputs. Only supported test proposals appear in the main interface, and an empty genotype-to-laboratory comparison is omitted.
**Clearer explanations in English and Russian.** Screens present results, evidence and limitations without development history. The evidence guide consistently distinguishes an available interpretation from eligibility for an automatic clinical finding.
**Combine wearable and recorded weight.** Fitness presents one weight card with the current reading and separately labelled monthly device averages and dated measurements. Daily intensity minutes also populate the activity row of the current phenotype table. Factual measurement cards do not show clinical-support warnings intended for interpretations.
**Read additional laboratory rows.** Recognition-only analytes now retain units printed after a reference interval, including wrapped result rows. Unknown or conflicting units still stop ingestion. Existing omitted rows require a targeted re-import of their source forms; proposed markers do not receive an inferred normal range.
**See one current phenotype table.** The first tab combines current measurements, saved personal targets and dated changes within the past year. Personal focus notes and goal reasons start folded. Device history remains labelled separately from a newer recorded measurement. Imported data invalidates browser answers when the view is reopened or the application regains focus.
**Review current laboratory results.** The main laboratory list and counters cover the past 12 months. Older measurements remain in expandable history and charts; they no longer appear as current deviations or current clinician-target questions. Use `scholion labs --history` for older readings. Units use the selected language without changing stored values. Unstructured legacy notes are retained in the data rather than presented as current product conclusions. Verified PGS readings with unavailable reference calibration now say which part remains unconfirmed.
**Read genome references consistently.** Longevity, ClinVar, class screening, lipids and gene lookup use compact A–E descriptions with expandable sources. Scholion confidence remains separate from an external variant classification or GenCC gene–disease validity. Legacy ClinVar tables can recover gene names from an indexed local annotation using exact coordinate and allele matches.
**Understand APOE results and the longevity catalogue.** Confirmed common APOE combinations have plain-language, sourced explanations with Scholion confidence and population limitations. Catalogue position counts are labelled explicitly. Literature associations without a curated variant effect remain available in a separate folded list, with publication links. All four PCSK9 positions retain their reading; an unresolved effect direction is distinct from absence of the allele.
**Inspect PGS calculation separately from model accuracy.** Each trait can show called-position and weight coverage, recorded AUROC and reference provenance. A verified percentile establishes a checked population position; it does not establish clinical accuracy or an individual disease probability. An independently checked EUR reference is available for the exact supported PGS000646 model files. Its percentile is approximate and identifies the reference cohort.
### What is fixed
The lipid panel retains the verification status of its Lp(a) polygenic estimate and never presents an unverified percentile as an ordinary reading. Extreme percentile labels remain below P100. Recovery of missing ClinVar gene names requires matching recorded coordinate provenance. ClinVar annotation also retains valid source metadata when reading long VCF headers.
Today tables wrap long reference descriptions to fit the screen. Known source-language unit labels are rendered in the selected language without changing values or stored units. Saved goal and focus text can carry separate English and Russian versions. Class screening now explains stale or unverifiable scan provenance instead of exposing a message identifier.
Polygenic scoring now counts the actual effect alleles at multi-allelic sites and accepts the case of soft-masked reference bases. Partial calls, conflicting records and unresolved allele representations reduce measured coverage instead of becoming reference genotypes or zero-dose matches. The score retains both position and weight coverage and an input/model witness before reference calibration. Recalculation uses the pinned model directly; a different candidate cannot replace it merely because the previous result was unusable. Exact trait-name fallback can resolve a missing catalogue search result without substituting a different endpoint.
Lifestyle views could omit a newer recorded weight and show only the device's monthly average. The current value now follows the same source-selection rule as personal measurements; device averages are kept separately. A focus metric could show no current value even when a measurement was available. An unverified stored PGS percentile no longer appears as if its selected model were absent: the model identifier remains visible and calibration details start folded. Missing reference ancestry is distinguished from a confirmed population mismatch.
A called variant could appear outside the found-variant table because its clinical interpretation lacked complete support. Readings are now grouped by what was actually read, independently of clinical eligibility. Simultaneous panel requests could leave a test proposal unassessed. Laboratory flags are now isolated per reading; an unassessed proposal has a readable status rather than a debug message. Repeated reference descriptions and automatically expanded catalogues no longer overwhelm the initial system view.
### What this changes in the conclusions
An interpretation's A–E confidence describes the evidence available for assessing it. Displaying an interpretation does not promote it to a supported automatic clinical finding. Scoring models and clinical thresholds remain the same. The PGS summary includes all admitted percentiles at or above P80; incomplete position or weight coverage is explained separately and does not become a high flag. Corrected allele dosage can change a polygenic score and its calibrated percentile on unchanged genomic input; no genotype is altered.
### What is retracted
The presentation rule that an existing catalogue interpretation must disappear solely because its confidence is below B or its support record is incomplete. The unrelated obesity publication previously cited for APOE is replaced with publications on APOE; this does not change the genotype reading.
### What needs recomputing
PGS000646 can use its separately verified EUR reference when the corrected score, exact model identity and effective coordinate build match. Its reference differs from earlier external calibrations: keep that change with the result and do not splice percentile series across references. Existing calls can be reused; a calibration change alone does not require BAM genotyping. Unsupported calibrations for other models remain unavailable.
**By hand — if polygenic scores were computed before this release.**
Check saved polygenic scores with the corrected matcher using existing scoring-site calls. Only missing required calls need targeted BAM genotyping. The application proposes this check when corrected scoring evidence is missing, and stops proposing it once the report has been checked. Updating the application does not start a genome operation. Earlier results may contain incorrect multi-allelic or soft-masked allele dosage, or overstate coverage. Do not grant old results a new scoring witness merely by copying metadata. Models without a validated reference distribution still have no supported population percentile; additional genotyping cannot establish that distribution. Reload the application for presentation changes. Existing measurements and saved personal goals are retained.
## v0.6.6 — 10.10.2026
### What you can do now
**Population assignment is part of connecting a genome.** Connecting genomic inputs prepares a coarse reference-panel assignment automatically when depth-checked genotypes or a usable BAM and indexed reference are available. Missing or ambiguous input leaves the population unresolved, and PGS scoring stops instead of silently assuming EUR. The determination is bound to its input files and active profile. See the reference population determined automatically from the genome beside saved polygenic results, including whether the calculation used the same panel. Inspect these facts with `scholion prs --json`. New PGS calculations use the available genome-derived population automatically unless explicitly overridden, and retain the source of that choice.
**Read lower-level context directly on genetic panels.** Both patient and clinician views show sourced C/D descriptions immediately, labelled as hypotheses. Genetic summaries have a dedicated A–E evidence column; its letter opens the reference guide. Click a gene name in a system card to open its detailed panel reference.
### What is fixed
A missing selection-source field in older results could produce a warning that no population had been determined, even when genome analysis had established the same population used for scoring. The application, command line and assistant reports now distinguish the current determination from the historical selection source. Different or unrecorded calculation populations remain explicit warnings.
### What this changes in the conclusions
Matching panel labels establish agreement with the current population assignment, not valid PGS calibration. Calibration, coordinate and coverage checks continue to apply independently.
### What is retracted
The statement that population analysis had not been performed solely because an older result lacked its panel-selection source.
### What needs recomputing
**By hand — if saved PGS results lack calibration provenance or use a different reference panel.**
Verify or rebuild the scoring report. No recalculation is required solely to correct this warning when the recorded calculation panel matches the current determination. Saved personal results are not rewritten automatically.
## v0.6.5 — 09.10.2026
### What you can do now
**Read polygenic results with their calibration and coordinate provenance.**
Use `scholion prs --json` to inspect the result and its provenance.
Raw scores, calculation methods, reference populations, reference parameters and
coordinate builds travel with each result. Variant coverage, weight coverage,
calibration and model informativeness are separate facts. Displayed percentiles
retain fractional values; rounded endpoints are shown as bounds rather than an
exact P100 or P0. A percentile remains a population position, not a probability
of developing a disease.
### What is fixed
A fully covered genome could receive a seemingly reliable P100 when the score
had no suitable reference distribution. Such approximations are now withheld
from ordinary percentile results, high findings and clinical questions. A missing
or rejected reference, an unsupported calibration method, inconsistent reference
parameters, and unknown or mismatched coordinate builds cannot be repaired by a
coverage flag. Model selection and the reported spread use the same validation.
Models originally published on one genome build can still be used through their
matching harmonized coordinates. The scoring request carries the verified input
build. Preparing scoring sites from BAM refuses inconsistent position lists,
BAM headers or reference sequences before genotyping starts.
### What this changes in the conclusions
A stored reliability flag alone no longer establishes a valid percentile. A
verified high percentile can remain high; no disease-specific exclusion or cap
is applied. The application, command line, assistant tools, body-system panels
and visit sheets use the same validation and explain why a value was withheld.
### What is retracted
Percentiles without verifiable calibration or coordinate provenance, including
AUROC-only approximations, are withdrawn as population positions. Previous
values and explanations remain available as diagnostic history rather than
ordinary findings. They are not replaced with percentiles from rejected
reference data. These checks apply to low values as well as high ones.
### What needs recomputing
**By hand — if polygenic results were saved before this release.**
Rebuild saved polygenic results from a report with verified calibration and
coordinate provenance. Retain the original report and backup. A result without
that provenance stays withheld until a verified scoring report is available;
re-genotyping BAM is required only if the scoring-site input itself is missing
or inconsistent. Existing laboratory and curated-gene results do not require
recomputation for this correction.
## v0.6.4 — 09.10.2026
### What you can do now
**Review several laboratory forms inside one PDF before importing them.** Each
self-contained form keeps its collection date and time, specimen and source
pages. The application, command line and assistant tools show a preview; an
explicit approval imports it only while the source files and destination still
match. Numbered continuation pages require the same order identifier and
consecutive pagination. Ambiguous boundaries and contradictory observations
prevent the archive from being written. Start with
`scholion ingest-labs "<folder>" --archive-preview`; the preview supplies the
matching approval command.
**Prepare a visit sheet with traceable facts.** The sheet names the data
container, software version and preparation date, retains measurement dates and
sources, and separates unassessed measurements from assessed findings. A separate
optional appendix keeps reference genetics and hypothesis passports with their
evidence levels. The same sheet is available through the application, command
line and assistant tools, in English and Russian.
**Read the liver fibrosis index (FIB-4) in the liver panel.** A compact row opens
to show its meaning and calculation details. It uses
AST, ALT and platelets from one recorded draw and age at that draw. Inputs,
units, missing data, population, purpose and primary sources accompany the
number. Invalid inputs and insufficiently established dates withhold calculation;
no diagnostic category is assigned automatically. The body-system radar is
explicitly labelled a Scholion heuristic rather than a validated risk score.
**Use a consistent interface throughout.** Remaining application screens now use
the same controls and visual system as the main views. The visit sheet adapts
its measurement rows for narrow screens and has a dedicated print layout.
### What this changes in the conclusions
Laboratory forms from different draws remain separate observations. An English
ISO collection header also retains its time, so two draws on the same day do
not silently become one measurement.
### What is retracted
No existing stored observation is reclassified automatically.
### What needs recomputing
Nothing needs automatic recomputing. No profile migration is required.
Preview an archive explicitly to import forms that the single-form importer
previously refused. Previously saved observations remain unchanged until the
user imports or edits them.
---
## v0.6.3 — 07.10.2026
### What you can do now
**Read more precise reference explanations across genetic panels.** Molecular
mechanisms and bounded implications for 38 existing positions now identify
primary studies, experimental models, negative findings and variant nomenclature.
Gene function remains visible when a variant's influence is uncurated. Open a
genetic panel in the application or use `scholion system` to read the same context.
**Read gene biology throughout the GenCC system panels.** All 1,469 existing
GenCC genes now carry source-bound reference descriptions. Russian views also
translate the disease names, inheritance and validity labels. Each gene–disease
assertion retains its organisation, date and original classification; conflicting
assessments remain visible side by side. GenCC validity and Scholion A–E variant
confidence are labelled separately, and a whole gene receives no variant grade.
When a gene's reading status is unknown, its row shows an unread state instead
of appearing to be a negative finding.
**Keep concurrent profile changes on Windows.** A temporarily inaccessible write
lock is retried; if it remains unavailable, the write is refused explicitly.
Separate processes no longer proceed without the lock and silently lose a change.
**Distinguish variants and the tests they represent.** CYP2C19*17 has its own
increased-transcription explanation, separate from the splice defect associated
with *2. ADRB1 context includes the current beta-blocker guideline and its lack
of an ADRB1-based recommendation. HLA tags remain distinct from direct typing;
historical protein names and reference-strand changes are explained explicitly.
### What this changes in the conclusions
Reference wording is more specific about the studied tissue, population and
endpoint. Clinical grades, personal interpretation checks, allele readings and
calculated results are unchanged. A molecular experiment or biomarker association
does not establish an individual diagnosis, supplement response or treatment.
### What is retracted
The generic reduced-function explanation beside CYP2C19*17 and the assertion
that ADRB1 has no CPIC guideline are replaced. Vitamin D, selenium, iron,
fatty-acid and thyroid explanations distinguish associations from unproven
universal treatment effects. Reference and alternate alleles do not mean
beneficial and adverse, respectively.
### What needs recomputing
Nothing. Reopen or regenerate panel reports to obtain the new reference wording.
Stored genotypes, locus coordinates, measurements and clinical conclusions are
unchanged; no alignment rescan or genome re-indexing is required. Earlier exported
reports retain their previous wording.
## v0.6.2 — 06.10.2026
### What you can do now
**Read allele presence separately from clinical interpretation.** A positively
read named allele stays present even if its interpretation is withheld. An
unread, presumed or unconfirmed position is unknown, rather than a negative
result. Clinical carrier counts and findings retain their independent checks.
**Understand why a sentence is missing.** System cards, reports and clinician
questions distinguish incomplete clinical support from a phrase that has never
been written. Reference panels show the number of withheld A/B interpretations;
gene biology and reading quality remain visible at every A–E level. Use
`scholion panel cardio` for the reference panel, `scholion system cardio` for
readings and `scholion longevity` for the literature catalogue.
**Use restored, sourced explanations for key clinical positions.** F2, F5, HFE,
G6PD, TPMT, NUDT15, UGT1A1, SERPINA1, APOB and two PRSS1 variants have their own
identifiable references and mechanisms. Single positions do not establish a
complete pharmacogenetic phenotype, a diagnosis or a drug dose. Source curation
remains incomplete for 119 of 151 A/B system-panel rows (117 of 140 distinct
positions) and all nine A/B on-demand rows. Their personal interpretations stay
withheld; this is a knowledge gap, not loss of genome data.
**Read concise longevity support notices.** Each variant lists its unsupported
fields together once, while structured output retains support for every field.
A supported field is still shown with its own provenance.
### What this changes in the conclusions
Supported explanations return only within the scope of their own sources.
Presence of an allele grants neither a finding nor a treatment decision.
Reference gene lookups and panel explanations use consistent neutral context
for the revised positions. Other unsupported clinical claims remain withheld.
### What is retracted
A withheld interpretation no longer reports a read heterozygote as lacking the
named allele or promises an unwritten phrase. Unsourced personal risk multipliers,
hormone-route and haematocrit advice, single-SNP dose instructions and diagnoses
are removed from the revised explanations and lookup notes. The catalogued PRSS1
A>C change is identified as N29T, distinct from the A>T variant sharing its rsID.
### What needs recomputing
Nothing. Reopen or regenerate panel and longevity reports. Stored genotypes, coordinates,
alignment data and laboratory measurements are unchanged; no genome re-indexing
or alignment rescan is required. Previously exported wording is not rewritten.
## v0.6.1 — 06.10.2026
### What you can do now
**Gene panels explain the biology beside the reading at every evidence level.**
Both personal and clinician views show gene function, known variant mechanisms
or literature associations, the Scholion A–E confidence level and separate
sources. Use `scholion panel cardio` for the reference catalogue or
`scholion system cardio` for readings beside it. Reference panels also work
without a connected genome. Unknown variant
influence is named explicitly, even when the gene's function is known.
**Missing clinical support no longer hides useful reference knowledge.**
The coagulation panel again explains prothrombin and Factor V Leiden, with
primary sources. Research contexts below A/B remain visible as reference
knowledge. Reading quality and an unread or unconfirmed position remain visible;
a gene description does not imply that a variant was found.
### What this changes in the conclusions
Reference biology is separate from personalised analysis. It grants no finding,
carrier status, individual risk estimate, treatment rule or laboratory proposal.
Personal conclusions still require their own evidence, applicability and reading
checks; an unsupported conclusion remains withheld.
### What is retracted
The display policy that reduced lower-confidence positions to counts or hid
gene explanations together with unsupported clinical sentences is replaced by
visible reference context. Previously withheld clinical claims are not restored
by this change.
### What needs recomputing
Nothing. Stored measurements, genotypes and analytical results are unchanged.
Reopen or regenerate panels to see their reference explanations. No genome
re-indexing or alignment rescan is required.
## v0.6.0 — 05.10.2026
### What you can do now
**Printing stays readable when the screen uses the dark theme.** Printed
Crossread cards and legacy views share a light paper palette without changing
the selected screen theme. Regenerate previously saved dark-theme PDFs; stored
measurements and interpretations are unchanged.
**Windows file checks no longer mistake unchanged genomes for changed inputs.**
ACMG screening still refuses a replaced or modified source. If an older table
is refused, rerun the screen; stored findings are not silently revalidated.
Edits to local notes are also reread even when successive saves share the same
rounded modification time, instead of retaining the previous note.
**Amino-acid reference contexts are shared, not diagnoses.** Low measured
values can link to one source-backed explanation of protein intake,
malabsorption and catabolism, with the limits of each single study. These
contexts do not affect scores or establish a cause. Value-only markers and
censored observations do not trigger them. Urinary urea nitrogen is described
as part of nutrition assessment, not a direct measurement of absorbed protein;
an amino-acid panel alone cannot establish an order or a repeat interval.
**A 16-position folate, histamine, redox and choline panel.** Available through
`scholion panel folate_histamine_redox_choline` and
`scholion system folate_histamine_redox_choline`, it preserves existing
interpretations. Thirteen new positions carry literature context, not approved
genotype-specific clinical conclusions. Coordinates support GRCh38 and GRCh37;
genotypes must be considered alongside measured phenotype.
**Personal and Visit are explicit display modes.** Visit defaults to the
professional register and offers a patient selector only when there are several
local containers. Changing the display mode does not change the patient. The
technical container ID and engine version remain visible, including in print.
**Recorded goals have a shared view and explicit origins.** Personal targets,
clinician targets and recorded focus tracks appear together. A person can state
whether a goal comes from a complaint, a lab result, the genome, history, a
clinician or prevention, with a reason. Changing that metadata does not change
the target or its observations. Older records without a stated origin remain
unspecified rather than acquiring invented provenance.
**Genome positions name their data workflow.** Each position distinguishes
an available linked measurement, a missing measurement, or no independently
supported marker link in this build. Unread or unconfirmed genotypes and missing
claim support keep the route blocked. These routes are not test orders or
treatment decisions; an undeclared link does not mean that no marker exists.
**Dose and longevity sentences cannot borrow nearby citations.** Effects,
formulations, alternatives, actions and population statements each need their
own source and mechanism. Unsupported sentences are explicitly withheld;
genotypes, recorded doses, laboratory values and their dates remain visible.
A withheld dose-context assessment cannot produce a reassuring prescribing
verdict. Lipoprotein(a) uses the dated laboratory comparison, and an inexact or
unassessed value cannot acquire a green grade.
**Calculations are distinguished from clinical conclusions.** BMI retains its
calculated value without an unsupported clinical grade. Radar and wearable
indices state their display-comparison method, not a clinical prediction.
PhenoAge carries its population-model source and method, not an individual
prognosis. Recorded focus expectations are labelled as notes, not measured
treatment effects. Stored observations and previously entered goals are not
rewritten; regenerate saved reports to see the withdrawn interpretations.
**Clinical thresholds and actions need independent support.** A catalogue
boundary without held interpretation is shown as unresolved, not safe or below
an action threshold. The qualified marked-CK warning uses the applicable upper
reference bound rather than a fixed number; treatment decisions stay with the
clinician. Measurements and prescribed schedules are not changed.
**Suggested tests need their own grounds.** Test selection, reason, trigger
applicability, priority, referral and repeat interval no longer borrow one
another's support. Unsupported candidates stay visible without an order or a
reassuring low priority. There is no implicit three-month repeat interval;
one recent result cannot establish completion of a whole monitoring panel.
Existing measurements and prescribed schedules are unchanged.
**An observed number is not automatically a treatment goal.** Historical
extrema and reference bounds remain visible as observations. An assumed risk
category or unconfirmed diagnosis cannot select a clinical target, and a
guideline citation alone does not support the target or an adjacent quotation.
Previously entered or accepted goals are kept; review previously generated
targets with your clinician and regenerate saved proposals to replace the
unsupported advice. Stored values are not recalculated or erased.
**Laboratory scales are no longer mistaken for normal intervals.** Printed
grades and conditional rows stay with the measurement; a graded scale is not
replaced by a dictionary interval. Time-dependent rows use the recorded draw
time, while an unknown posture leaves the comparison unresolved. Unrecognised
result labels are named even when other rows in the file were imported.
An inexact result expressed as a bound is not assigned a unique printed grade.
**Import refuses ambiguous combined forms instead of corrupting results.**
Documents with several draw dates or mixed blood/stool forms must be split
before importing. A numeric stool count cannot be truncated onto the worded
score scale. Decimal results beside thousands-separated ranges, unbracketed
age bands, a paediatric first reference row, wrapped vitamin B6 and the
Cyrillic OH spelling are read without the reported losses. Published ClinVar
and other sites-only resources are not counted as a person's genome.
Existing stored measurements and dates are not repaired automatically:
review affected histories against the originals and re-import individual
forms with forced re-reading, rather than relying on a previous import's
success message. Printed grading labels are reported as the form's words,
not as Scholion diagnoses.
**Recorded tests are separate from monitoring advice.** Monitoring reasons and
the proposed use of each marker require their own support; unsupported reasons
and timing are withheld and named, rather than printing a validated plan or a
reassuring prescribing verdict. The selected observations keep their values,
dates, units and laboratory comparisons. A missing profile row now says "not
recorded in this profile", not that the test was never done, and uses the marker's
display name. Recorded tests and prescriber schedules are unchanged; regenerate
saved prescription checks to replace the unsupported advice.
**An interaction match is not automatically a clinical judgement.** Unsupported
effects and management statements are withheld independently, with their
missing basis named beside the matched medicines. Such a gap cannot produce
"no interactions" or a low prescribing verdict. The supported warfarin/NSAID
bleeding caution remains prominent without a personal risk estimate or an
automatic gastroprotection plan; it is not lent to every vitamin K antagonist.
Mixed partners remain separate. Stored medicines are unchanged; regenerate
saved prescription checks to replace the withdrawn wording.
**A prescribing statement cannot borrow another statement's support.** Clinical
notes, gene-role explanations and guideline quotations now require their own
source and mechanism. A changed quotation loses its recorded support rather
than inheriting that of the previous text. Missing support is named; the
phenotype and its observations remain visible without a reassuring assessment.
Indication-specific tables are withheld when the indication is not established,
and an omeprazole or citalopram quotation is not lent to another drug.
The supported DPYD poor-metaboliser toxicity warning remains prominent,
without supplying an individual dose. Recheck saved drug and prescription
reports; recorded readings and treatments are not changed.
**Prescribing tables must match the drug and joint phenotype.** A simvastatin
table is no longer quoted for another statin, or a codeine table for tramadol.
Two intermediate TPMT/NUDT15 readings no longer receive the held single-IM
dose recommendation. Both readings remain visible; the missing applicable
table is named instead of yielding a reassuring verdict. A normal phenotype
found online also cannot stand in for a prescribing table that is not held.
Stored readings and prescriptions are unchanged. Regenerate saved drug checks
to replace these earlier recommendations; treatment decisions remain with the
prescriber.
**Connection instructions fit long installation paths.** Commands and path
details wrap on narrow screens without being shortened or changing the text
to copy.
**A missing route dependency is not a negative genotype.** When a triggered
rule needs a reading unavailable in the current panel, the gap is named
instead of being silently omitted or described as no genetic influence.
The patient's view counts lower-level rules; the clinician's view retains
their missing dependency. No genotype is inferred from the gap.
**Genotype-linked prescribing cautions carry their own basis.** A caution
without a primary reference and mechanism, or below evidence level B, no
longer supplies a prescribing interpretation. The recorded genotype remains
available. The factor V Leiden warning retains its priority and now cites
contraceptive eligibility guidance rather than an unqualified risk multiplier;
that multiplier is withdrawn, not converted into a personal probability.
Treatment decisions remain the prescriber's. Stored prescriptions and
genotypes are unchanged; regenerate saved reports to replace the old wording.
**Separate support for separate claims.** A position's source no longer
automatically supports its marker expectation, intake route, response to a
load or proposed next step. Each unsupported claim is withheld with a reason,
including in reference panels and marker links; readings and evidence levels
remain available. Existing reports should be regenerated.
**Supported next steps retain their explanation.** Laboratory, genome and
discussion lists carry the step's own mechanism and reference. A genome step
or low-coverage warning no longer disappears when every listed gene was read,
or gets attached to the last gene instead of the gene it concerns.
**PCSK9 interpretations no longer exclude other causes of low LDL-C.** R46L
and C679X descriptions distinguish population associations from personal
predictions and experimental mechanisms. Cohort estimates are not doubled for
two copies; the pooled nonsense-variant estimate is not presented as specific
to C679X. The previous reassuring wording and per-allele estimate are withdrawn.
Genotypes, laboratory values and prescriptions are unchanged.
**Correction routes distinguish missing support from no effect.** A route and
its recheck timing and change criterion each need their own reference and
mechanism. Unsupported advice is withheld with a reason, not presented as a
negative genetic conclusion. Lower-level evidence no longer transmits the same
treatment claim under a different heading. Measurements and prescriptions are
unchanged; regenerate saved reports to replace the withdrawn advice.
**Explicit gaps in curated interpretations.** A curated A/B position or group
without an identifiable primary reference and a recorded mechanism no longer
prints a clinical interpretation. Its evidence level and reading status remain
visible, with the missing basis named. Unsupported positions do not count as
findings or support a reassuring panel summary; their marker links no longer
assert a direction. This withdraws earlier unsupported positive and negative
panel wording. Genotypes, measurements and prescriptions are not rewritten;
regenerate saved panel reports to see the corrected interpretation status.
**Consistent CYP2C19 labels.** A newer locally cached reference can no longer
restore the withdrawn compensation claim in the computed IM label. The local
reference file, its date and the computed phenotype code remain unchanged.
**Clearer limits on genetic predictions.** ABCG2 urate explanations no longer
promise a response to allopurinol or turn a population odds ratio into a personal
risk prediction. CYP2C19 panel rows no longer infer a complete metaboliser
phenotype or select treatment from a single position, and no longer combine
stroke and coronary-treatment advice. The unsupported claim that `*17` partly
compensates for a no-function allele is withdrawn; the computed IM code is
unchanged. Revised explanations carry primary references and mechanisms;
their human review is open. Stored readings and prescriptions are unchanged.
**Corrected pharmacogenetic-panel explanations.** The lipid panel no longer treats the
SLCO1B1 c.521 position as a complete `*5` haplotype or places poor-function dose
advice beside a one-copy ABCG2 result. Those earlier formulations are withdrawn.
The revised explanations distinguish the reading from prescribing decisions,
carry a mechanism and primary reference, and explicitly await human review.
An unrelated urate claim was removed from the statin explanation. Stored
genotypes and prescriptions are unchanged. Cardiac, inflammatory and renal
panel explanations also no longer turn a single CYP2C9 position into general
NSAID dose instructions. Warfarin-related rows explicitly require the complete
genetic and clinical context and INR, rather than proposing a dose from one position.
**Read chart gaps and goals without implied health judgements.** Missing values
break observation lines instead of being bridged. Goals and reference windows
use neutral, labelled marks; calendar years no longer make an observation look
favourable. Paired series have labels, distinct line patterns and point shapes.
Chart colours follow the active theme. Stored observations and targets are unchanged.
**Read the complete panel list.** `scholion panel author_list` includes positions
awaiting inclusion and positions that were refused, with the reason for each.
Available panel-author explanations retain their Russian original and a labelled
English translation. They are shown as opinions at the position's evidence
level, not as additional findings or individual treatment recommendations.
Existing genotypes, findings and patient-specific clinician notes are unchanged.
The clinician's view (`scholion system author_list --register clinician`) adds
local genotype readings and separately labelled values recorded in the profile,
including positions
not accepted into a panel. Missing calls and unsupported insertions/deletions
remain explicit refusals; no remote variant lookup is made by opening the list.
The web reading list groups compact, keyboard-expandable rows by gene. Each row
distinguishes a current local-file call, a recorded profile value and an
unconfirmed value, with evidence level and provenance kept beside the reading.
Printing includes the folded details without changing which rows stay open afterward.
**Keep hypotheses separate from patient conclusions.** Patient-facing system
cards and text reports now count C–D hypotheses and E-level values without
listing their individual positions. Previously, those positions could still
appear in summaries even when their explanatory text was withheld. Clinician
views retain the details; JSON and assistant tools still carry all positions,
their levels and hypothesis passports. No stored genotype is removed or changed.
**Separate local patient containers.** A workstation can hold several people
without mixing their files. CLI, web and assistant replies name the technical
container ID; an assistant session refuses a switch until a new session starts.
Local labels are not sent through the model tools.
**Whole-container export and deliberate erasure.** Local CLI and web controls
export the owned files and a manifest, or erase an inactive container only after
an inventory and exact-ID confirmation. Uncertain or shared external ownership
refuses. Erasure includes raw originals and cannot be undone; it is not forensic
secure deletion and does not remove separately retained backups.
**Local access journals.** Registered workstations record the technical ID,
time, action and entry point in the container and a surviving clinic journal,
without labels or medical content. These are access records, not tamper-proof
evidence. Export and erasure are not assistant tools.
**Privacy boundaries are available offline.** The installed documentation and
plugin distinguish the local engine from an assistant host: tool answers can
reach a remote model provider, and a technical ID is not anonymisation.
The policy explains network queries, journals, export and erasure limits;
offline mode blocks the engine's requests, not the host's model requests.
### What is fixed
**Position panels name rows, not genes.** A completed sixteen-position panel
covering eight genes no longer claims sixteen genes were read. X-linked calls
retain their single-copy checks even without an assigned risk allele; an
apparent heterozygous male call is withheld rather than treated as diploid.
**A gene-region report is visible in the genome view.** Missing annotation,
unselected samples, unreadable inputs and unavailable protein calculations
remain named gaps, not zero variants. Variant counts use the selected sample
and exclude reference homozygotes.
**PhenoAge does not assemble a blood draw from a month.** Different collection
dates and times are kept separate. Legacy records with only a month no longer
produce a composite result until their draw dates have been recovered.
**An interrupted form import can resume.** Completed files are checkpointed,
rejected table rows and storage errors are named, and bounded numeric results
keep their qualifiers. Time-limited tool hosts return a terminal command for
an unfinished import or an uncached whole-genome pass, not a partial report.
Resuming preserves the preferred measurement method and reports disagreements
with later forms instead of silently replacing the selected value. A valid
English collection date in a table is no longer also reported as rejected.
The first tool-based import into an unnamed local container no longer invalidates
the assistant's session after saving the results. Previously overwritten values
are not repaired automatically: compare the source forms and force a re-import
of the affected folder.
**Genetic conclusions require confirmed inputs.** APOE epsilon assignment
requires two confirmed calls. Stale indexes are not used for seeking reads,
coverage refuses an unknown or mismatched assembly, padded equivalent alleles
can match secondary-findings records, and unanchored report genotypes are not
counted as reference-oriented calls. Moderate gene–disease relationships are
not findings; X-linked recessive findings distinguish sex and single-copy calls.
**A curated repeat is read as repeat alleles, not individual letters.**
SERPINE1 4G/5G uses rs1799762 and verified reference windows on both genome
assemblies. rs1799768 remains a distinct insertion, not an alias. A missing
variant row, unsupported representation or duplicate call cannot establish
4G/4G. The repeat count does not establish an individual clinical risk.
AGXT Gly170Arg, Phe152Ile and Ile244Thr are available for coordinate-based
lookup; their literature context does not establish a treatment response in
an unaffected carrier.
**Correction routes can observe existing cross-panel dependencies.** Read
state is preserved without importing another panel's clinical sentence.
Unobserved inputs remain explicit gaps; an observed genotype cannot bypass
the independent clinical-support gate. Local clinician notes are labelled
as opinions, not evidence upgrades.
**Reference comparisons retain their context.** Form age bands use age on the
collection date, unknown demographics do not select a labelled range, and
boundary flags use the measurement's own interval. Same-day records with
incomplete clock precision no longer bypass the recorded method priority.
Radar rows retain reference origin, and form defaults use the local date.
**Local diagnostics retain their security checks.** TLS verification is not
silently bypassed, a foreign server's text does not identify it as Scholion,
and PRS constraints use private unique temporary files. The Hub data view
honours the configured external profile. Medicine replacement and import
conflicts/errors are visible in the web interface; CLI exit codes are documented.
**Previously missing laboratory analytes are no longer silently omitted.**
Recognition includes 31 additional analytes, with English and Russian names.
These new rules are explicitly proposed: values and dates are retained, while
norm judgements await the person's confirmation. Units come from the form or
the table, not an assumed assay; missing or changed units produce a named
refusal rather than mixing unlike numbers. No reference intervals, standard
identifiers or conversion factors are invented. Earlier imports are unchanged;
re-import source forms to recover previously omitted readings.
**Unassessed laboratory readings no longer look reassuring.** A proposed rule
or a missing corridor produces a neutral label rather than a green in-range
badge. An unconfirmed rule does not print its corridor as a normal range.
**Existing print views keep the radar together.** Large system cards can flow
across pages instead of leaving a blank opening page; the on-screen layout is
unchanged. This does not add a new consultation sheet.
**An interrupted laboratory import could leave only part of a panel.** CSV
imports now validate dates and prepare the complete panel before saving it.
A rejected row leaves the previous laboratory file unchanged. Importing into
a demonstration profile is refused without clearing that profile.
**A bounded laboratory result could become an exact number.** FHIR observations
such as “less than 5” are now explicitly skipped, rather than stored as exactly
5. Observations with multiple or conditional reference ranges are also skipped
until their context can be represented without guessing.
**A failed coverage measurement could look like no reads.** A failing alignment
reader now stops the measurement without replacing the completed coverage table.
Interrupted measurements are reused only when their local input identities and
parameters match; obsolete progress is retained separately, not mixed into the
new measurement.
**Unresolved threshold comparisons could dilute the reported rate of flags.**
Unresolved markers are counted separately, not as negative comparisons. A
text-only result no longer crashes the next-draw checklist.
**A slower tab could replace the screen selected afterwards.** Late tab replies
and their errors no longer overwrite the current screen. A read started before
cache invalidation cannot repopulate that cache with its old answer.
**The note beside an assumed reference named two script files instead of a
command.** When a position has no row in the variant file, `scholion genome`
answers that this is either the reference or a lack of coverage, and says what
tells the two apart. It pointed at two scripts inside the source tree, which a
person who installed the package does not have. It names `scholion recompute`
now, which reads the catalogue positions from the alignment where one is at
hand. The answer itself is unchanged.
### What is checked now that was not
- The linter of the public checks runs in the test runner before a publication,
with the version and the command the public job names. Until now it answered
only after a version was out.
### What is retracted
**A saved secondary-findings table is not necessarily a result for the current
genome.** A table whose input identity or selected sample cannot be confirmed
is no longer presented as findings or as a clean negative result. Missing,
unreadable or replaced input files and altered tables now require a fresh scan.
### What needs recomputing
**Run `scholion genotype-sites` — when the alignment and matching reference are available.**
The added panel expands the locus catalogue. An older scoring-site file cannot
establish reference genotypes at its new positions. No laboratory values are
changed by the catalogue update.
**By hand — previously saved composite and genetic reports.**
Recover collection
dates for month-only PhenoAge inputs and regenerate reports assembled across
draws. Recheck APOE assignments based on assumed references, selected-sample
region reports, X-linked interpretations and previously accepted Moderate
gene–disease findings. No stored result is silently corrected.
**By hand — existing ACMG secondary-findings tables.**
Run `scholion acmg-scan` after confirming the selected VCF and sample. Earlier
tables do not contain the input-identity witness required to reuse them safely.
The original VCF and stored table are not removed by a read-only check.
**By hand — if an earlier CSV import failed partway through.**
Check the original file and
re-import the corrected complete panel.
**By hand — if an earlier FHIR import contained bounded results or conditional ranges.**
Imports that contained
bounded results or conditional reference ranges must be checked against the
original observations: a qualifier lost during import cannot be recovered from
the stored number alone.
**Run `scholion coverage` — if an earlier attempt failed or was resumed after changing its inputs.**
The old table cannot establish whether either happened.
## v0.5.11 — 27.09.2026
### What you can do now
Nothing new: the program answers exactly as 0.5.10 does. This release repairs
the public checks that stand behind it.
### What is fixed
**The public check of types could not run.** Every push to the public
repository starts a job that counts type errors per module and refuses a push
that adds one. The job called a tool the published tree did not contain, so it
failed before it measured anything, on every push since it was introduced. The
tool and its recorded counts now travel with the package, and the job measures
what it says it measures. Nothing a person runs was affected: `scholion` and
every command of it behaved the same with the job red.
### What is checked now that was not
- A workflow that ships names only tools that ship with it. The package's own
suite reads the workflows and the test runner, and a tool one of them runs
and the package lacks stops the publication before anything goes out.
- A tool that compares against recorded numbers travels with those numbers.
- Type errors are counted before a publication and not only after it. The test
runner fetches the checker in the version the public job pins, without
installing anything into the interpreter, and stops when a module has gained
an error; where it cannot fetch the checker it says the count was not
measured. The first count found three modules above their recorded number,
and they are corrected: the recorded total falls from 258 to 173.
### What is retracted
Nothing.
### What needs recomputing
Nothing has to be recomputed and nothing has to be re-imported. A person who
runs `scholion version` sees the new number and no step to take.
## v0.5.10 — 27.09.2026
### What you can do now
**Read the current regimen through an assistant.** An assistant connected through
the tool server could check a new prescription against «the current
prescriptions» and could not read that list: the overview it was given carries
how many prescriptions there are, not which. The tool `sch_medications` prints
the regimen as `scholion medications` does, so the assistant can say what the
new drug was compared against — and no longer has to ask the person to recite
it, which is an answer from memory and not from the record.
**Ask about the genome file and the laboratory archive before a negative
answer.** The safety rules tell an assistant to consult `scholion genome-status`
before a statement that depends on the file, and to run `scholion selfcheck`
before saying a test was never taken. Both are tools now: `sch_genome_status`
and `sch_selfcheck`. The rules handed over by `sch_rules` end with a table that
names, for every command they mention, the call that runs it.
**Start the ACMG screen from an assistant when it has never been run.**
`scholion recompute` and `sch_recompute` offer the screen as a step whenever a
genome is connected and no result of the screen exists; it starts, as every
step does, only after the person's yes. Before, the step was offered only when a
release asked for a re-run, so a profile that had never been screened was told
«not run» and given nothing that could run it.
**Reach five more readings through the tools that already cover their
subject.** `sch_selfcheck` with `full=true` prints the whole audit of forms
against the profile (`scholion reconcile`); `sch_genome_status` with
`updates=true` prints what the last check against a fresh ClinVar changed
(`scholion genome-updates`); `sch_analyze_labs` with `catalogue=true` prints
the marker keys its own `markers` parameter takes (`scholion markers`);
`sch_rules` with `levels=true` prints what each evidence level A–E means
(`scholion evidence-levels`); `sch_overview` with `snapshot=true` prints the
bare snapshot (`scholion profile`).
**Ask a build what it can do, and through which door.** `sch_capabilities` is
`scholion capabilities` as a tool. The manifest now prints the call that answers
for each command and, where no tool does, why not and which tools reach the
same thing — so an assistant can answer «this exists, on the command line»
where it used to have nothing to say.
### What is fixed
**Coverage of a gene was never measured on an alignment that names its contigs
`chr7`.** The depth reader looked a chromosome up by the exact name `7`, which
is how the coordinate layer spells it. An alignment against a UCSC or GATK
reference spells it `chr7`, so for every gene on such a file `scholion genome
--gene` printed «coverage not measured — the alignment carries no contig 7» —
about a file that holds the contig and was never asked for it under its own
name. The name is now matched against the file's header in either spelling; the
mitochondrion is found as `MT`, `M`, `chrM` or `chrMT`. A contig the file really
does not hold is still refused, and `1` never finds `chr11`.
**A measured coverage was replaced by «not measured» in the answer about a
gene.** For a gene outside the curated catalogue the depth read from the
alignment was written into the answer and then overwritten by the entry of the
coverage table, which for most genes is empty. The report then said that
coverage «was not computed for this answer» beside an alignment that had just
been read. The measurement now stays, and the table's answer travels beside it.
**Three commands that write were listed as «reads only — safe to call to answer
a question».** `scholion capabilities` called `choose-genome`, `brief-reviewed`
and `acmg-scan` reads. The first records which file is the person's genome, the
second records the person's statement that a brief still holds, the third
writes the table the ACMG screen reads. All three are listed as changes now.
**The instruction counted thirty-two tools where the build registers more.**
The paragraph an assistant reads about the tool server listed thirty-two tools
and left out `sch_version`, `sch_update` and `sch_recompute`. It lists what the
build registers.
**An evidence level was a bare letter to an assistant that holds only tools.**
The laboratory report prints «(B)» beside a genetic note, and the legend — which
levels permit a conclusion at all — had no tool. See `sch_rules` with
`levels=true` above.
**A request to prepare for a visit to a physician did not lead to the page
written for it.** A host that reads tool descriptions and no skill entry saw
nothing in the description of `sch_second_opinion` that said when to use it. It
says so now, in both languages.
### What is checked now that was not
- What the build says about its tool door is held to what it does: every
command without a tool states a reason of a kind a program can check; a
command excused for writing must be listed as a write; a reading said to be
reached through another tool is run through both and compared; and a command
the safety rules name must be one the tool door answers.
- A tool and the command it stands for print the same text and the same
structure, compared on every run.
- The alignment reader is tested on files written in both spellings of a contig
name.
- An import nobody reads, and a type named in an annotation and never imported,
are found by the suite itself — until now only the public linter looked.
- A test of a shell script starts the shell a probe found to run, never a bare
name: on Windows the two are different programs.
### What is retracted
Nothing.
### What needs recomputing
Nothing has to be recomputed and nothing has to be re-imported. The coverage of
a gene outside the catalogue is measured when it is asked for and is not stored,
so the next `scholion genome --gene` on an alignment with `chr` names gives the
measured answer. A profile whose ACMG screen was never run will see that step in
`scholion recompute`; whether to run it is the person's decision.
## v0.5.9 — 27.09.2026
### What was wrong and is now right
**A failed read of the genome no longer answers «reference».** When the program
that seeks into an indexed VCF failed at a position — it timed out on a large
file, it could not load the index, it was missing, or the built-in index reader
hit a damaged block — the position came back as having no row, and a position
with no row is read as «the person carries the reference». The answer was
labelled as assumed, but it was a sentence about the person made from an error.
Such a position is now reported as not read, with what the reader said, and the
advice to check that the index sits beside the file and matches it. A clean read
that finds no row is still the reference, as before.
**`scholion update` from an unpacked archive no longer offers `pip`.** A copy run
from where a release archive or an sdist was unpacked — a source tree without
`.git` — was treated as an installation, and the command offered
`pip install --upgrade`. That updates the copy in site-packages and leaves the one
that is running as it was. Such a copy now says what it is and how it is updated:
a newer release unpacked in its place, or a clone updated with `git pull`.
**A drug name typed in Russian goes to a translator only when nothing else found
it.** The transliteration and the original spelling are looked up in RxNorm first;
the translator is asked only if both found nothing — before, it was asked first,
for every Cyrillic name, including the ones transliteration reaches on its own
(metformin written in Cyrillic, for one). The second, undocumented translation endpoint
(`translate.googleapis.com`) is gone: the only translator is MyMemory, as listed in
`THREAT_MODEL.md`.
**`scholion.format_system` imports on its own.** It worked only when
`scholion.format` had been imported first; imported first itself, it failed with
a circular import. Nothing in the package imported it that way, so no answer was
affected; code built on the package could have been.
**A failure is no longer printed as a fact about the person.** Every place where
the program caught an error and went on in silence was read once, by hand; where
the silence could reach an answer, the answer now says what could not be read.
What somebody could have been told before, and is not told now:
- *«Variants in the gene: 0»* — about a gene whose region the reader failed on,
a file called against another genome build, or a chromosome the file does not
hold. Each is now said by name, and nothing is counted.
- *The reference at a position* — when the built-in reader of the index failed
(index missing or damaged, file cut short), when the file's composition could
not be measured, or when the kind of file could not be measured at all (it was
then treated as a whole genome, opening ClinVar, ACMG and polygenic scores).
- *«No coding exons»* for a gene, stored after a failed request to Ensembl. Such
stored entries are asked again.
- *«A published reference sample»* about a genome when the file that says whose
genome it is could not be read.
- *«A scan without OCR»* about a laboratory form or a study every PDF reader
failed on; it was also recorded as read and never tried again. It is now
reported as unreadable, with the readers' errors, and read again next time.
- *No clinical threshold at all* for a value that could not be compared with one.
It is now «could not be compared», and the prescription check lists it as
unresolved instead of letting the verdict fall to «low».
- *«Done recently»* for a monitoring test whose last date could not be read.
- *No red flag on this drug*, when the prescriptions file could not be read; *no
such drug*, when the drug database did not answer. Both now say so.
- *The default folders and a different genome file* when the settings file that
names the chosen folders and files was damaged. The program now stops with the
reason (the command line exits with status 5).
- *A reference range for the other sex*, when the file with sex and age sat in a
chosen folder or could not be read.
- *Points the person had removed from a wearable series* came back when the file
of corrections could not be read; the rebuild now stops instead. Export files
that could not be read are listed, instead of months averaged without them.
- *A radar without its fitness domain*, and an overview without its wearable
line, when the wearable data could not be read: both now say it.
- *A request with a body that is not JSON* was read as an empty one by the local
server — for the goal screen that meant adopting every proposal. It is refused.
**The positions and rules added in 0.5.8 now carry the review that covers
them.** The five positions, the carrier classes and the five «adds nothing»
correction rules added in 0.5.8 were shown as reviewed on a date before some of
their levels were assigned. The panel author has since approved them as a whole —
sentences, levels, the corrected genes and the wording for a woman with an OTC
variant — and the card shows that review, dated 27.09.2026.
**The list of sources gives the locus catalogue the date it last grew** —
25.09.2026, not 18.09.2026. A positions file made by 0.5.8 stays current: nothing
needs to be genotyped again.
### What is checked now that was not
- Every module of the package is imported first, into an interpreter where
nothing of the package is loaded yet.
- The suite also runs in the tree a release archive unpacks into, without
`.git`, on every push.
- Two rules of the rendering are held by tests rather than comments: a value
with no reference range never gets a verdict colour, and what the interaction
comparison left out is printed whether or not anything was found.
- Lint (pyflakes rules) runs on every push with zero findings; type errors are
counted per module and may not grow.
- A handler that catches every error and stays silent must say, in the code,
why its silence cannot become an answer; the suite and the test runner refuse
one that does not.
- The package's own suite runs before publication in a copy without `.git` —
the shape a release archive unpacks into — not in the repository's working
tree.
### What needs recomputing
Nothing is recomputed automatically. A genotype stored as «assumed reference»
from an indexed VCF read before this version is correct when the reader worked;
if the index was missing or damaged at the time, ask for the position again.
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if a form was reported as a scan without OCR by an earlier version.**
It may have been a PDF the readers failed on; it is read again, and if it still
fails the reason is printed.
**Run `scholion ingest-garmin` — if a Garmin export was imported by an earlier version.**
A file that could not be read was skipped without a word; the rebuild now lists
such files, and the months are averaged over what was actually read.
## v0.5.8 — 25.09.2026
### What you can do now
**Five positions from the panel author's list are read.** Each carries its level
of evidence, and only A and B print a conclusion.
- **Gonads.** rs5934505 near FAM9B is read on the X chromosome and carries its
association with testosterone in men (level B). rs1691053 in SRD5A1 is shown
as a value only. Its author declined to grade its genotypes, so no ladder of
genotypes is drawn for it and no verdict is printed.
- **Glucose.** rs182052 in ADIPOQ is read (level C): a genotype and its source,
without a conclusion.
- **Behaviour.** The on-demand panel reads rs6356 in TH, Val81Met (level C), and
rs34424986 in PRKN, p.Arg275Trp. The PRKN variant is recessive, and one copy is
printed as carriership.
**A position outside the pseudoautosomal regions of X is read by sex.** A man has
one copy there, and his genotype is shown as one allele (hemizygous), not as two.
A two-letter heterozygous call for a man is left unread, since it cannot be a real
genotype. Without a sex in the profile, such a position is not read at all.
**A carrier of a recessive amino acid gene is told what that carriership means.**
- PAH, CBS and GLDC: carriership is silent.
- SLC7A9: carriership may have an effect.
- OTC sits on X. A likely pathogenic or pathogenic variant in a man is shown as
clinically significant, with the variant named, not as carriership. In a woman
it is not reduced to carriership either: following GeneReviews, the picture
ranges from no symptoms to episodes of hyperammonaemia.
**Two variants in one recessive gene are a result, not carriership.** With more
than one heterozygous variant in a gene that needs both copies changed, the row
no longer says «carrier». It says the result is clinically significant if the two
lie on different copies, which short reads cannot tell; phasing, or testing the
parents, settles it.
**Three tests are offered under their author's condition.** They were withheld
before.
- **Fecal elastase:** when albumin or total protein is low, or when vitamin D is
low together with essential amino acids, and it has never been measured.
- **Methionine load:** when homocysteine is high while folate and B12 are not
low.
- **ADMA/SDMA:** when Lp(a), apoB or LDL is high, or arginine or citrulline is
low, and they have never been measured.
**Tryptophan to the large neutral amino acids (Trp:LNAA) is computed** from a
draw that holds all six components. It is a value; no range is carried for it.
**«If a decision to correct has been made» says outright, in five more
situations, that carriership changes nothing.** Each statement has its source,
and in each one heterozygous carriership is no reason for a different route:
- high phenylalanine in a PAH carrier: restricting phenylalanine and aspartame
is for confirmed PAH deficiency;
- citrulline on the medication list of an ASS1 or ASL carrier: the allele does
not predict the response, the measured concentrations do;
- low tryptophan in an SLC6A19 carrier: nicotinamide is not a preventive measure
for a carrier. This one is level C, so it is printed as «adds nothing» with
the reason;
- creatine on the medication list of a GATM carrier: there is no evidence of a
higher need;
- collagen or gelatin on the medication list of a carrier of a primary
hyperoxaluria gene: there is no evidence they must be excluded.
### What is fixed
**Two genes on the panel author's list were wrong.**
- rs6356 was listed under the wrong gene; it is in TH.
- rs3816873 was listed as an MC4R variant. It is in MTTP, so it is not taken
into the panel it was proposed for.
A SERPINE1 entry is an insertion, which this build cannot yet read from a genome
file, so it stays waiting rather than being read as a single letter.
### A series break
On unchanged input:
- a man's genotype at an X position outside the pseudoautosomal regions is shown
as one allele;
- a recessive gene with two heterozygous variants is no longer shown as
carriership;
- the three tests above may now be offered.
### What is retracted
Nothing.
### What needs recomputing
**Run `scholion genotype-sites` — if a sites file was made by an earlier version and an alignment is at hand.**
The five positions added in this version are not in a sites file made before it.
Until they are read from the alignment, they are shown as not read. They are never
shown as the reference.
## v0.5.7 — 22.09.2026
### What you can do now
Nothing new to learn: this release corrects answers. Every item below is a
wrong answer somebody could have received from 0.5.6, and what they receive now.
### What is fixed
**Laboratory forms**
**A flag or a unit printed against the result cut its decimals off.** «6,5H» and
«6,5ммоль/л» were stored as 6.0. The whole number is read now.
**A result with a space as the thousands mark was cut at the space.** A ferritin
of «1 250,0» was stored as 1. The two readings are told apart by the corridor
printed on the same row (or the marker's physiological range); with neither, the
row is left unread rather than guessed.
**A digit of the analyte's name was taken for its result.** «ИФР-1» and
«пиридоксаль-5-фосфат» gave 1 and 5. A number joined by a hyphen to a word is
part of the name.
**A longer analyte was stored as the shorter one it contains.** Prealbumin and
microalbumin were read as albumin, macroprolactin as prolactin, non-HDL
cholesterol as HDL, latent iron-binding capacity as total, folate in red cells
as serum folate — each a different number filed under a marker it is not.
**The unit printed on the row was ignored for most markers.** «Glucose 95
mg/dL» became 95 mmol/L, a catastrophic reading; an HbA1c of 48 mmol/mol became
48 %. The row's unit is now converted, value and corridor together — by the
formula where the unit needs one — and a unit the marker cannot take (Lp(a) in
mg/dL) leaves the row unread.
**A one-sided corridor on the result row was not read.** «< 5,2», «до 5,2»,
«> 1,0» and «более 1,0» — the commonest layout for lipids and liver enzymes —
arrived with no corridor at all, so a total cholesterol of 6.1 against a printed
ceiling of 5.2 was not flagged.
**A corridor the form did not print was stored as if it had.** It was filled in
from the dictionary and then judged as the form's own, skipping the checks made
before a reference range is lent — whose sex and which age band it belongs to. A
woman's point could be judged by a man's ceiling with nothing on screen saying
so. Such a point now carries no corridor of its own, and the reference is lent,
labelled, or withheld with its reason.
**The reconciliation reported every point as missing, and the provenance audit
called every point hand-entered,** once points began to carry the day and the
clock time of the draw. Both now match a draw at the resolution each side has.
**Lab points written at the same moment could be lost.** Two writes from the
page could each read the history, add their own point and write back the other's
loss. Writes of a lab point are now serialised.
**A local marker file that could not be read was overwritten.** The next
proposal replaced it with an empty file holding one entry, and every marker, unit
and rule the person had confirmed was gone. A write over such a file is now
refused and the file is kept.
**Pharmacogenetics and prescriptions**
**An unread second gene disappeared from a two-gene drug.** With TPMT normal and
NUDT15 never read, azathioprine was answered as a normal-dose drug. The unread
gene is now named, and the answer does not read as reassuring until it is read.
**A called phenotype the engine had no code for was answered as normal.** A
caller's «Indeterminate», and SLCO1B1's «Poor Function», fell through to «nothing
notable in the markers». «Indeterminate» is now unknown; SLCO1B1's function
phenotypes reach the statin table; any other phrase is quoted and not taken for
normal.
**A genotype that was not a reading of the counted allele was counted as zero
copies.** A strand-ambiguous chip call, a genotype written on the other strand,
and a person carrying the other alternative allele of a multi-allelic site all
produced «normal». Each is now unread.
**A drug name was matched inside other words.** Nystatin was given the statin
guideline, «Антигриппин» the proton pump inhibitor one, and heparin the omega-3
dose evidence. Names are now matched as whole words; a dose, a brand word or a
Russian case ending still matches.
**A non-normal phenotype with no guideline row read as low.** A CYP2C19 poor
metaboliser asking about pantoprazole, and a CYP2C9 poor metaboliser asking about
celecoxib, were told «low». Every gene the guideline database links to a drug
now reaches the prescription verdict: a non-normal phenotype without a row, and
an actionable gene that could not be read (HLA among them), are named and keep
the verdict off green.
**Genome files**
**A half call («./0») was read as a call**, and a reference block with one
allele unread as a confirmed reference. Both are now «no call».
**A missing row on an exome was presumed to be the reference.** Outside an
exome's targets nobody sequenced the position. The presumption is now made only
on a file whose breadth shows it is a whole genome.
**A chromosome the file does not hold was read as the reference at every locus
on it** — a file without chrY, or one that names the mitochondrion `chrM` where
the catalogue says `MT`. Both names are tried, and a contig the file does not
declare is said to be absent.
**A multi-sample file read in container form took the first sample as the
person.** It now needs the sample named, as a multi-sample VCF already did.
**A gene region was asked of a file in another build.** GRCh38 coordinates on a
GRCh37 file returned the variants of some other stretch — usually none, printed
as «0 variants in the gene». The region is now refused with the reason.
**The page and the local server**
**Another server on the same machine could write to the profile.** The origin
check compared the host name and not the port, so a page served on
`localhost:3000` could add a medication. The whole origin is compared now, and a
browser's cross-site fetch is refused by its own fetch metadata as well. The
drug, prescription and genome questions — which reach outside services on the
caller's behalf — are gated the same way.
**The prescription card never showed its verdict or the genetic context of the
decision** — both were computed and left out. They are shown now.
**The ACMG class chips did nothing when clicked, a ClinVar finding opened an
empty gene card, and choosing a genome file also opened a folder dialog.** Each
now does the one thing it says.
**An error answer was drawn as if it were data**, and the state of a recompute
was cached by the page. Neither happens now.
**Other doors**
**Under the Ouroboros Hub, `recompute` started work that could never finish.**
The Hub runs every call in a fresh process, and a rebuild started on a thread
died with the call. There it now shows the plan and names the command to run in
a terminal.
**A package registry that did not answer was asked again on every call**, each
call paying the timeout. The failure is remembered for an hour.
**A long-running process that started offline never mentioned a newer build.**
The note was closed for the process before anything was said.
**Two recomputes could run at once**, one from the page and one from a terminal,
and a run that did not start left the job marked as running until the server
restarted. The job is claimed atomically now, and always ends in a final state.
**The MCP server stopped on one deeply nested message**, ending the session for
every later call. It answers with a parse error and carries on.
**A refused value exited with success.** `add-lab`, `add-med`, `remove-med`,
`add-metric`, `target` and `lab-draw` printed the refusal and returned 0, so a
script could not tell which values never arrived. They return 1 now.
**The public package could carry files git ignores** — a spreadsheet, a log or an
`.env` left beside the code. What git will not track is no longer copied.
### A series break
Laboratory forms read with this version give different values on unchanged
input wherever one of the defects above applied: decimals and thousands are read
whole, a row's unit is converted, a one-sided corridor is kept, a prefixed
analyte no longer lands on its stem, and a point no longer carries a corridor its
form did not print. A value stored by an earlier version and the same form read
again can differ; they should not be charted together without re-reading.
### What is retracted
Nothing.
### What needs recomputing
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if forms were ingested by an earlier version.**
Values, units and corridors are read again under the corrected rules; points of the same draw are replaced, not doubled.
## v0.5.6 — 22.09.2026
### What you can do now
Nothing new: this build is 0.5.5 with one test corrected.
### What is fixed
**The test suite went red on Windows for a reason that had nothing to do with
the product.** One test runs a shell script of the genome pipeline with its
external programs stubbed by small shell scripts. Windows carries `bash` on its
PATH and still cannot run such a stub, so on that system the four branches of
the test failed before the script under test was reached — while every other
test passed there. The test now skips where a stub is not a program. Nothing
that runs for a person changed: `scholion version` reports 0.5.6, and every
answer is the one 0.5.5 gave.
### What is retracted
Nothing.
### What needs recomputing
Nothing.
## v0.5.5 — 21.09.2026
### What you can do now
**The genes a «nothing found» cannot rest on can be handed to a laboratory in one
step.** `scholion limits --bed` prints them as a BED — worst gene first, each
interval carrying its percentage — `--out` writes the file, and `--panel` narrows
it to one panel (ACMG, pharmacogenetics, HLA). The genome tab offers the same file
under the screen, and an assistant can ask for it. The list existed before; no
command, page or tool reached it.
**The amino acid panel reads by pathway.** Branched-chain amino acids, the urea
cycle, methionine metabolism, phenylalanine → tyrosine and the sulphur amino
acids each show as a group, with how many of its markers were measured. A marker
stands in every group it belongs to — methionine in both its own cycle and the
sulphur chain. A group counts nothing: the panel's term in the score is what it
was.
**Five markers are shown as values only.** β-alanine, β-aminoisobutyric acid,
aspartate, asparagine and pipecolic acid are printed with their values, say so
on the line, and no longer enter the panel's share outside its corridor.
**A marker names the ones to read beside it.** Under histidine when it is low,
under cystathionine when it is high, under phenylalanine always, and so on for
ten markers: the companions are listed with their values, or as not measured.
Nothing more is said about what they mean together.
**Hydroxyproline/proline is shown**, computed from a draw that holds both. No
range is carried for it, so it is a value, not a deviation.
### What is fixed
**Forms from one laboratory lost their dates.** Laboratory forms that print the
draw as «Дата/время забора» had their markers found and then dropped, because no
date was recognised. Studies that print their date and kind as one header line —
a two-digit year, the clock time and the kind in capitals — were stored without a
date and mostly without a kind. Both are read now. Where a study also prints when
the examination was done, that is its date rather than the time it was written
up; a birth date, the print time in a footer and a date inside a recommendation
are never taken for it, and a two-digit year later than this one is refused
rather than read as last century.
**Three answers sent a person to a script the package does not carry.** When
coverage had never been measured, or had been measured before the intervals were
recorded, the answer said to run a shell script of the source tree — which a
`pip install` does not have. It names `scholion coverage` now, which has done the
same measurement from the package for some time.
**A proposed marker name belongs to the profile it was proposed for.** It was
written beside the data root — in a source checkout, the checkout itself — and
shared by every profile the same installation was pointed at. It now lives in
the profile. A proposal an earlier version wrote is read until the next one, and
moves with it.
**The journal's yes/no factors are the ones the person declared.**
`scholion focus-log --factor NAME` records any yes/no field `profile/focus.json`
declares for the journal, the page draws those fields, and the assistant's tool
takes `factors`. The earlier flag named after one drug still works and is no
longer listed. The journal analysis names the factor it separates instead of a
drug.
**Three tests are no longer offered to everyone with an amino acid panel.**
Faecal elastase, the methionine load and the dimethylarginines were suggested
whenever the panel was measured and they were not. They are held until the
conditions that select the people they are for are written; urine urea nitrogen
stays.
**Under the Ouroboros Hub, `update` no longer installs into the host's Python.**
The Hub runs a skill in a child of the host's interpreter, so the route «pip in
the running interpreter» would have changed the host's environment rather than
the skill's own. Under the Hub the answer now names the host, whose catalogue
brings the newer build. Through the classic tools module, the MCP server, the
page and `scholion update` on the command line, updating works as before.
**The note about a newer build no longer ends every answer on a host that starts
a process per call.** «Once» was kept in the memory of a process. It is now
remembered beside the registry's answer, so it is said once a day for a given
release, on every door.
**The Hub manifest says what the package does.** It declares `subprocess` — the
package starts `bcftools`, `pdftotext`, `pdftoppm` and `tesseract` when they are
installed — and counts the once-a-day question to PyPI among what goes out. Both
corrections came from the Hub's maintainer; a test now holds the first, so a
later manifest cannot drop it.
**No position of an authored list leaves it without a word.** Every position a
curated list names is now either in the catalogue and on a panel, or waiting,
with the reason and the work that closes it. The first check of the list of
29 June 2026 found twelve positions absent with no reason recorded anywhere, and
thirteen covered only by a note about their whole class; each now carries its
own. It also found one reason that had outlived its position — the position had
arrived later — and removed it.
**The ClinVar annotation script is run by the tests in every branch.** The
branch for a genome with `chr`-named chromosomes stopped once on a variable that
was never set; each branch is now executed end to end, with the external
programs replaced by stand-ins.
**A reviewed sentence names a role, never a person or a clinic.** This was
already how a review was recorded; it is now a rule over everything that
ships, with a test that fails the build when a clinician or a clinic is named.
### What needs recomputing
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if the folder holds forms that print the draw as «Дата/время забора».**
Their markers were found and dropped for want of a date; they are stored with it now.
**Run `scholion ingest-studies <folder of studies>` — if the folder holds studies whose header is one line of date, time and kind.**
They were stored without a date and mostly without a kind.
## v0.5.4 — 17.09.2026
### What you can do now
**An assistant can run the recompute, not only describe it.** A new tool shows
the plan by default and starts the ready steps when asked to with a
confirmation, the same way the page does; the progress is a file, so nothing is
lost if the call ends first. A system's answer also carries, as a field rather
than prose, why rows were not read and what closes each reason.
**The reports say how a command is typed on this machine.** Where the word
`scholion` is not on the PATH, `version` and `recompute` add one line with the
spelling that works here.
**A release records the size of the catalogue it ships.** A catalogue that grew
without the release notes naming the step that re-reads the new positions now
stops the publication, instead of being noticed on somebody's profile.
**The panel of authored positions grew from 120 to 214, in three kinds of row.**
Thirty-four positions rest on a named study whose reference was checked
against Europe PMC — every one of them carries the product's own sentence in
both languages, a level from B to D by how well the source replicates, and the
source itself. Twenty-two rare variants of immunity, the pancreas and the
kidney are read through the gene–disease base: the classification and the
inheritance come from GenCC, the sentence says what one copy and two copies
mean, and a carrier is never printed as a finding. Twenty-nine positions the
list named without any source are shipped at level E: the genotype is shown,
and the row says that nothing stands behind it. One source on an older row
pointed at a paper about another subject and was replaced by the paper about
the variant.
**Fifteen groups of positions print as one row each.** Linked variants of one
locus — the FTO block, TCF7L2, the deiodinases, the estrogen and progesterone
receptors, SHBG, the rare variants of SECISBP2 and TSHR — say one thing, and
the card said it three or five times. A group prints its name, its count, one
sentence, one level and one source, and opens into its members.
**Two panels without a radar domain.** Behaviour and the stress response —
seventeen candidate positions of neurotransmission, most at level C or D — open
as a card of their own, with the reason at the top: there is no laboratory
marker a behaviour is read by, and an empty half on the radar would teach a
reader that an empty half means a clean one. The dental panel is declared and
waits for its positions.
**«The genetics of this marker».** A laboratory marker with positions behind it
says so under its own row — gene, rsID, level, the direction the panel
expects — and the row is a door to the system card, where the person's own
state is.
**A clinician's local note.** A note kept in the profile prints on the row it is
about, in its own voice, and never reaches the package.
**A system can now answer the question that comes after a deviation: if a
decision to correct has been made, what does the genotype say about the
route.** The amino acid system carries it first. Routes are grouped by what the
genotype says — this one goes around your narrow place, this one probably works
worse for you, this one makes the genotype beside the point, this one needs a
different dose, this one the genotype says nothing about — and never ranked,
because a ranking would mean an optimum, which needs cost, availability, the
clinical picture and your own preference. A route is printed only at evidence
level A or B, only with a named source, only in the conditional, and only with
the other half of the answer: which marker to recheck, after how long, and what
counts as a change rather than the scatter of the method. Where nothing
reaches that bar, the product says the genotype adds nothing here, with the
reason, instead of saying nothing at all.
**Every position of the amino acid system says which link of the chain it sits
on** — digestion and absorption, carriage into tissues, use inside the cell,
renal losses — **and how it reads on the three routes protein can arrive by.**
A drip removes the gut and the first pass through the liver; free amino acids
remove the digestion of protein and the peptide path. So the same variant
matters on one route and is beside the point on another, and the card says
which, marking what is a mechanistic reading rather than a measured comparison.
**Where a fasting corridor cannot answer, the position names the load that
would.** Carriership of the transsulfuration is invisible at rest; the
methionine load is what shows it. The same for the urea cycle under a protein
load and for urate under a purine load. The product names the test and what it
would reveal, and never says to do it.
**The second half of the amino acid picture is now asked for.** Urine amino
acids, cystine in a 24-hour collection, plasma ammonia, kynurenine with its
ratio, vitamin B6 and fecal elastase appear in «what else to take» while they
are missing, and disappear the day they are taken.
**The genetic half of a system is read as a table.** One line per position or
gene — level, state, chain link, what it means — grouped by link where the
system has links. A line opens into the card it used to be, so the density is
the reader's choice and not the page's.
**Every statement about a genetic position now says what stands behind it.**
A position on a system's card carries a level from A to E: A is a clinical
guideline or a gene–disease link GenCC rates Definitive or Strong, B a
replicated association with a measured effect size, C single or conflicting
studies, D a candidate gene whose association was never replicated, E no
source at all. A conclusion is printed at A and B only. Below them the card
shows your genotype and says why nothing follows. The same letter appears on
the page, in the command line and in what an assistant is told to relay.
`scholion evidence-levels` prints the legend, and so does the Guide page.
A position with no level assigned yet says so and draws no conclusion.
**Three new body systems: immunity, the musculoskeletal system, and amino
acids and protein.** The radar now has fifteen laboratory systems. Immunity is
read through white cells, lymphocytes, IgA, ESR, C-reactive protein and two
autoantibody screens. The musculoskeletal system is read through calcium,
phosphorus, alkaline phosphatase, parathyroid hormone, osteocalcin and vitamin D.
Amino acids and protein are scored on seven markers: total protein, albumin,
urea, creatinine, uric acid, homocysteine and citrulline. Beside them the card
shows the amino acid panel and its ratios. The share of the panel outside its
corridor counts in the score as one term, so a drifting panel shows at the top
level. A marker can now count in two systems, for example C-reactive protein in
inflammation and in immunity. Each new system has a genetic half composed from
the gene–disease base: 75, 366 and 97 genes. In front of that base stand 28
authored positions: seven for immunity, six for bone, twelve for amino acids
(glycine, branched-chain amino acids, asparagine, uric acid, homocysteine and
classic homocystinuria among them), and three more for the gonads. The panel
now holds 120 positions across fourteen systems.
**The gene–disease base is refreshed to the export of 13 September 2026.** The
kidneys gain one gene. The systems now hold 1,469 different genes.
**A common variant shows its three genotypes, with yours marked.** The card
lists them from the base genotype to the one with two copies of the named
allele.
**An amino acid panel is read as a picture.** Nine ratios have their own
values: phenylalanine/tyrosine, glycine/serine, the Fischer ratio,
glutamine/glutamate (and glutamate/glutamine, as some laboratories print
it), methionine/homocysteine, α-aminobutyrate/leucine,
kynurenine/tryptophan and urea/creatinine. A ratio a laboratory prints is
read and checked against the value its components give. No reference range
was invented for them: until a source gives one, a ratio is shown as a value.
### What is fixed
**A position written on the other strand could read as «the allele is
absent».** When the named letter was not one of the two at the position, the
genotype was searched for it, it was never there, and the card said the
allele was not found. Such a position is now refused before any genotype is
read.
**The recompute panel took over the screen after the recompute was done.**
It reappeared at full height on every reload, showing the report of a run the
person had just watched. A finished run is no longer a reason to open it: what
is ready to recompute is one line with the panel one click away, and a line
dismissed stays dismissed until something new is ready.
**A ratio refused to compute when one of its components had been measured
again later.** Urea/creatinine — the only ratio of the amino acid panel with a
published corridor — and methionine/homocysteine were both dropped although
their components were drawn together: the engine compared each marker's newest
point instead of looking for the last draw that held them all. Two values drawn
months apart still do not make a ratio; a draw that exists is now found.
**Two lines of one card contradicted each other**: the panel said it does not
enter the score while the line above it said the share outside the corridor
enters as one term. The panel is not scored marker by marker — that is what it
says now.
**A gene whose coverage was never measured was called «not read», which is
false about the file.** The file did read the gene; what nobody measured is how
deeply. That is now a state of its own — read, with the depth unmeasured — and
the row says what the file holds in the gene, with the alignment named as what
measures the rest. A coverage table that WAS made and found the gene thin is a
different answer and still counts as not read.
**A position a whole-genome file has no row for is answered, not left blank.**
Such a file omits a position BECAUSE it matched the reference, so the answer is
almost certainly there. With an alignment on the machine the position says it
is not read yet and names the step that reads it. With none, it is taken by the
reference — and the caveat stands inside the sentence, not beside it: «the risk
allele is absent — taken by the reference: the file has no row here, and no
alignment was checked». That is never allowed on a chip, a genotype table or a
panel, where a missing row means the position is not on the chip; never where a
coverage table calls the gene low; never for a position outside the catalogue.
It is not a finding, it is counted apart from what was read, and it never lets
a list be called read end to end.
The other side of the same question: a position whose row IS in the file is
read — and where the row states no depth and no alignment is on the machine to
measure one, it says so: read from the file, the depth of reading not verified.
**«Not read end to end» did not say what was in the way.** A reader who had just
run every recompute the product offered was told that 28 rows of 373 were
unread and left to guess the next step. The count now comes with the reason and
with what closes it: read too thinly — deeper sequencing; no row in the genome
file — genotyping those positions from the alignment; the depth never measured
— a coverage table. The sentence no longer lists a dozen gene names or explains
what «nothing found» means over an unread gene: the names are on the rows.
**A system card could take three quarters of a minute to open, and could show
a position as unread on a machine with no network.** A position whose
coordinate the build did not carry was looked up online at every opening, once
per position. Every position a panel ships now carries its coordinate in the
build, confirmed against two independent sources, and a card opens without
reaching the network at all.
**A rare variant read off a genotyping chip could be printed as a finding.**
Chips often report rare variants that are not there. Such a variant is now
shown as a signal to confirm by sequencing, not as a finding.
**A disease class could read as «every gene read, nothing found» with no
coverage measured.** Without a coverage table, no gene now counts as read,
and the answer says so gene by gene.
**A ratio printed with full names was read as one of its components.**
«Phenylalanine (Phe)/Tyrosine (Tyr) 1.13» was stored as tyrosine 1.13, a value
far below its range, and ratios printed as «Phe:Tyr», «AABA:Leu» or
«Glu:Gln» were not read at all.
**A printed albumin/globulin ratio was never checked against its
components**, and could be flagged as having nothing behind it.
**The warning about calcium on high-dose vitamin D showed calcium as not
taken** even when it had been measured.
### What needs recomputing
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if the profile holds a urine or an amino acid panel this version added markers for.**
Ammonia, fecal elastase, the dimethylarginines, 3-methylhistidine, urea
nitrogen in urine and six urine amino acids are new keys: a form that holds
them was stored without them.
**Run `scholion genotype-sites` — if a sites file was made by an earlier version and an alignment is at hand.**
The positions added in this version are not in a sites file made before it, so
a position the raw genome file has no row for is shown as not read rather than
as the reference. Reading those positions from the alignment settles what is
there. Without an alignment the step says so and is not offered as ready: a
position stays honestly not read, which is what it is.
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if an amino acid panel whose form prints ratios was ingested by an earlier version.**
A ratio line could have been stored as one of its components: tyrosine,
glutamine and the other single values are read again from their own lines, and
the printed ratios get values of their own.
**Run `scholion coverage` — if a coverage table was computed by an earlier version.**
The three new systems add 372 genes that a coverage table made before this
version does not hold. Until the table is computed again, they are shown as not
measured, never as read.
**Run `scholion provenance` — if the profile holds an albumin/globulin ratio or an amino acid panel.**
The printed ratios, and the albumin/globulin ratio that was never recomputed
before, are checked against the values their components give.
## v0.5.3 — 16.09.2026
### What you can do now
**The tools and the instruction that governs them now travel as one package.**
Scholion is packaged in the portable plugin format agreed in August 2026 — a
manifest, the skill folder, and the description of the local tool server — which
a client reads in a single import instead of three separate steps: install the
package, register the server by hand, copy the skill folder beside it. The
convenience is the smaller half. A model that reaches these tools through a bare
server is handed a list of functions and no instruction with them, which is why
the safety canon has to be a tool of its own; in this package the instruction
sits in the same folder as the functions and cannot be installed without them.
The launcher installs nothing: where the engine is absent it refuses and names
the one command that installs it, because software that quietly put itself on a
machine in order to read somebody's genome would be the wrong kind of quiet. It
starts on the machine that holds the data and nowhere else — a client that cannot
run a local process does not get this door, and that is the correct answer rather
than a limitation. The launcher also looks where a per-user installation puts the
`scholion` command. A desktop application started from the Dock does not get a
terminal's search path, and without that look it would have refused on a
machine where the engine was installed.
**The tool server speaks the 2026 revision of the protocol and hands back
structures.** `scholion mcp` now answers clients of the July 2026 revision,
which has no handshake: a client can ask the server which revisions it speaks,
and a revision the server does not know gets an error listing the ones it does.
Clients that open with the older handshake are served as before, under the
revision they ask for. From the June 2025 revision on, thirteen tools also
return their answer as a structure, the same one their command prints with
`--json`: overview, labs, suggested tests, second opinion, radar, metrics, goal,
ClinVar, ACMG, polygenic scores, longevity, drug check and prescription check.
An assistant no longer has to parse the report back into numbers. The rendered
report stays in the answer, and a copy of it sits inside the structure, because
it carries the qualifications an assistant has to pass on, and some clients
show a model only the structure. `scholion capabilities --json` lists the
revisions under `access.doors.mcp.protocols`.
### What is fixed
**The catalogue entry in the plugin hub advertised an older build.** The row a
person reads before installing said version 0.4.7 and thirty tools, while the
package on the index had moved seven releases past it and registered thirty-four.
That row is a shipped page like any other, and nothing compared its numbers with
the build. The copy kept beside the source had also lost the field that declares
which plugin contract the skill speaks, so publishing it would have dropped that
field from the row as well. The numbers and the required fields of the entry are
now read from the build and refused when they disagree, and the version the row
offers is checked against the releases that are actually on the index — a row may
name an older release, never one nobody can install.
### What needs recomputing
Nothing has to be recomputed and nothing has to be re-imported. What changed is
what the catalogue says about this skill, not anything the skill computes: a host
installing it already received the tools of the published package, because the
entry installs that package from the index instead of carrying its own copy.
`scholion version` names the build you are on.
## v0.5.2 — 14.09.2026
### What you can do now
**An assistant tells a person that a newer version is out, and installs it on
their word.** Somebody who uses Scholion through Claude or another assistant never
sees the local page, so a newer version went unnoticed. `scholion update` says
whether a newer build is out and how it installs in this environment — pip, pipx
or uv as it was installed, or `git pull` for a source checkout — asking the package
registry at most once a day, sending only the package's name, and never with
`SCHOLION_OFFLINE=1`; `scholion update --yes` installs it. Through the tool
interface the same is `sch_version` and `sch_update`: the first tool answer of a
session mentions a newer build once, and `sch_update` installs nothing without
`confirm=true`, which is reserved for the person's own yes. The skill's instruction
starts every session with `scholion update`.
**The menu checks for an update and opens the recompute.** The ☰ menu beside
the language switch now carries «Check for an update», which asks the package
registry on request and, when a newer version is out, prints the command that
installs it, and «Recompute after an update», which opens the list of steps
the releases since your data's version ask for. Both used to live only inside
the note shown right after an upgrade, so once that note was dismissed there
was no way back to either. The same answers come from `scholion version` and
`scholion recompute`, and an update itself is `pip install --upgrade scholion`
followed by a restart.
### What is fixed
The engine's answers are the same; what changed is how they are shown.
**The body figure and the radar no longer wait for the genetic rings.** On the
Overview the figure appeared seconds after the rest of the page — about seven
seconds on a server that had just started — because it waited for the listing
of the systems' genetic halves, the slowest answer of the page, and asked for it
only after the person's block was drawn. The figure and the radar are drawn at
once now, a bar beside them shows the rings loading, and the rings are drawn in
when they arrive.
**A pharmacogenetic phenotype read from a diplotype in the profile is shown in
the reader's language.** A star-allele call carried by the profile — from PyPGx,
PharmCAT or a laboratory report — printed its phenotype as the English CPIC
phrase («Intermediate Metabolizer», «Normal Function») on a Russian page. It is
worded from the phenotype now, and a «likely» or «possible» qualifier is kept.
**A ClinVar drug-response record says what kind of response it is.** A record
named like «warfarin response - Dosage» reads «warfarin: response to the drug —
dosage» in the reader's language; the drug keeps ClinVar's spelling, and disease
names are still printed as ClinVar gives them rather than translated without a
source.
**A month without a day no longer reads wrongly after a preposition.** Dates
that carry only a month are abbreviated like full dates, and a system's
movement reads «was 80 (Nov 2025)».
### What needs recomputing
Nothing.
## v0.5.1 — 13.09.2026
### What you can do now
**An update can now run what it asks, and shows how far it is.** `scholion
recompute` lists every step the releases since your data's version ask for,
together with the genome steps your data lacks, and says for each one whether it
will run, what it still needs — a folder of forms not named, an alignment not
found — or that it is yours to do by hand. `scholion recompute --yes` runs the
ready steps one after another and prints the step, the item being read, the time
spent and an estimate of the time left; `--status` shows the same from another
terminal, and `--stop` stops after the item being read. Files a step rewrites are
copied into the archive first, and the version is recorded as done only when
nothing is left for you. The local web page offers the same from the update note,
keeps the progress through a reload, and on the radar a panel with positions not
read for this reason offers the step where the gap is seen.
**The catalogue positions can be genotyped from the alignment without the source
tree.** `scholion genotype-sites` reads every catalogue position from your BAM
with `bcftools`, one chromosome at a time with progress, in the build of the
alignment, and writes the file that lets a position missing from the VCF read as
the reference. It records beside the file which catalogue it answers for, so a
later release that grows the catalogue can tell that the file is behind. Until now
this step needed two scripts that only the source tree carries.
**Every file in a profile now records the build that wrote it.** `scholion
version` names the files a later release asks to rebuild — laboratory results
written by an older build before a release asked to re-read the forms — with the
command to run. Files written before this release carry no such record; they are
counted as such, and `scholion version --since` lists what to rebuild from a
version you name.
**A skill copied into a skills folder can say which build it came from.**
`scholion skill --install` copies the entry into `~/.agents/skills/scholion/`, or a
folder you name, records the build beside it and says what it replaced; `scholion
selfcheck` reports a copy that differs from the installed build as an error and
exits with a non-zero status until the copy is replaced.
**An update now says what it asks of the data you already have.**
`scholion version` names this build and its age, the version your data was last
used with, and — for every release in between — what that release asks: a command
to run and when it applies, or a step to take by hand. The same note stands under
the header of the local web page until you press «Understood»
(`scholion version --seen` on the command line). A profile that never recorded its
version says so, and `scholion version --since 0.4.8` lists everything after a
version you name. `scholion version --check`, or the button beside the note, asks
PyPI whether a newer version exists — one request, only when you ask, refused when
the network is switched off. The README has a new section, «Updating», with the
command for each way of installing.
**The panel of a radar segment is one picture of the system's genotype, and it
says it was checked whole.** Each panel opens with the genotype of the system,
assembled from the panel's own sentences and nothing else: in which positions
the named allele was found and what the panel says of each, which alleles are
not carried, which positions were not read. Every position is then a card by
gene — found ones bright, the rest muted with the sentence that says what «not
found» means for that one — until now the patient's view showed two rows of a
seven-position panel and nothing about the other five. The polygenic scores
mapped to the system fold into one line and open by a click. «Genotype against
the measurements» puts, for every found position that names a marker, the
expected direction beside the measured value with its place in the corridor and
the number of the question it raises; whether they agree stays that question.
Where no found position predicts a measured marker, the block says so: the
panel's genotype does not account for those measurements and their cause lies
outside it — and the expectations the panel holds for alleles not carried are
listed as what did not apply, so the check is seen to have happened.
Positions a guideline weighs when a drug is chosen are named last, as what they
are: not a prescription, and no statement that a drug is taken. The same view is
on the system's own card, both for the patient and for the clinician, and the command line prints the
same conclusion.
**The panel itself, with its studies, on a page of its own for the clinician.**
Every radar block with a panel, and the system's card, link to a description of
that panel as the catalogue holds it: each position with its locus and named
allele, the sentence it prints for one copy and for two, the kind of link, the
guideline or study it rests on with the effect size, what it expects of a marker,
the gene–disease classification where there is one, and who signed the sentence
and when. It reads no genome and no laboratory result, so it is the same page
for anybody; the reading against a person's genome stays on the radar. `scholion
panel <system>` prints the same, and `scholion panel` lists the panels.
**One design across the application.** Every page is built the same way now:
a title, the question the page answers, a strip of the few numbers worth
seeing first, the sections, the details folded, and the sources in one line
at the bottom. There are six tabs — Overview, Radar, Labs, Genome, Medicines,
Lifestyle — with the Guide and the Assistant in a menu beside the language
switch. Medicines joins the list of prescriptions and the check of a new
drug, which used to be two tabs under two names. The body figure and the radar
open both the Overview and the Radar; the Radar adds an index of the systems, and each
system's block leads with a one-sentence verdict, the measurements as a table,
the genotype as findings with whether it agrees with the measurements, and the
questions for the doctor; every position of the panel, the scores and the notes
are under «More». Labs shows what is out of range first and folds the values
in range. Dates read «3 Sep 2026» instead of «2026-09-03T08:22», ClinVar
significance is shown in the reader's language, long notes are cut at three
lines until clicked, and a finding without a usable rsID is named by its
position. The Russian interface addresses the reader formally throughout. On a
phone the header takes one line, the tabs scroll sideways, the disclaimer sits
in the footer instead of covering the tabs, and the page no longer scrolls
sideways. A prescription that could not be removed now says so instead of
doing nothing, a test's priority is shown in words instead of an English code,
and the count of unread target genes agrees with its number.
**The radar shows its head at once and fills the systems in as they arrive.**
The tab used to wait for everything before showing anything. The head of the
tab now appears as soon as the quick answers are back, well under a
second; the blocks by system, which are the slow part, fill in under
their own loader. The server also reads every system's card once right after
it starts, on a thread of its own, so the first page of a session finds the
genome folder, the catalogue positions and the coverage table already read.
The two ways out of a block — the system's card, and the panel with its
studies for the clinician — are labelled buttons with a hint each, no longer
two blue links run together.
**Switching tabs no longer fetches every answer again.** What a tab has fetched
is kept for the session: coming back to the radar takes a tenth of a second
instead of seconds. Every write made from the page, a finished recompute or
ClinVar refresh, and a change of language forget what was kept; the answers that
describe a running job are never kept.
**A block of the lifestyle brief due for a review opens what changed.** The
flag «needs a review» is a button: for every block due it shows, per watched
marker, the value at the review date, every measurement since, where each stands
against its range and whether that position moved — beside «the wording still
holds» and a request for the assistant built from the same facts, carrying the
block's live tokens. The flag on the Assistant page, in the menu, goes there. `scholion
brief-review [block]` prints the same.
**The coverage of the genes the panels read can be measured from the package.**
`scholion coverage` reads, with `samtools`, how well the alignment covered every
gene of the ACMG list, the CPIC genes and the composed genetic half of each body
system, and writes the table the cards judge coverage by. Until now that step was
a shell script of the source tree, and its table held 93 genes while the systems
read 1203 — so most genes were honestly reported as not read, with nothing a pip
install could do about it. `scholion recompute` plans this step when the table
is missing or covers fewer genes than the panels read.
**A loading view shows the project's helix and how much has arrived.** Every
view that loads shows the DNA mark turning above a bar that fills as the view's
requests come back, with a count of what has arrived; the motion stops under the
system's reduced-motion setting.
**Every segment of the radar has a panel of its own: the positions a
clinician acts on, read on the genome and set beside the segment's laboratory
markers.** Ninety-two authored positions across twelve systems, each of one of
three kinds and saying which: a position that changes a prescription by a
guideline (the statin, thiopurine, NSAID, warfarin, clopidogrel and
allopurinol genes), a position that explains a laboratory marker with a
measured effect from a named study (PCSK9 and LDL-C, the LPA positions and
lipoprotein(a), PNPLA3 and liver fat, GC and vitamin D, FUT2 and B12, TMPRSS6
and ferritin, ABCG2 and urate, SHBG and testosterone, DIO1 and the T3/T4
ratio), and a position people ask about that decides nothing, printed with
that note. Each row prints the person's genotype with its depth, the sentence
written for that state, and — where the position bears on a marker of the
segment — a question comparing the expected direction with the last value; when the marker was
never taken, the positions waiting on it are named inside one question
rather than asking for the same test once per position. The
panel follows the verdict on the segment's card and in each block of the radar page; the broad
disease list from the base stands after it as the background. The clinician's
blank for the thyroid is in, sorted by kind rather than copied as a list. The
locus catalogue grew from 61 to 113 positions, every new one verified against
two independent sources; two whose second-build position the sources disagree
on are held without it and say so.
**A gene short reads cannot read is named as such, never as clear.** The
21-hydroxylase gene beside its pseudogene, the androgen-receptor repeat and
the Gilbert promoter repeat are printed as «requires a separate method», with
the method named, and are never counted as read; a «nothing found» over them
would have been a statement about the method.
**The radar page shows panels, not scores.** Polygenic scores stay on the
genome tab; on the radar each system's block opens with its verdict and panel,
and the scores mapped to it are folded under «More».
**The radar has a thirteenth segment, «Heart and vessels».** Until now the
body was laid out as eleven laboratory panels and one wearables segment, and
the heart had no panel of its own — so the pharmacogenetics that matter most in
a cardiology prescription (warfarin with VKORC1, CYP2C9 and CYP4F2; clopidogrel
with CYP2C19; the beta-blockers; the anticoagulants and antiplatelets) and the
cardiovascular polygenic scores had no card to stand on. The new segment is
built from the five markers a laboratory issues beside the lipid panel rather
than inside it — lipoprotein(a), apolipoprotein B, apolipoprotein A1,
fibrinogen and D-dimer — and answers like every other system: `scholion system
cardio` prints the laboratory now and its movement, a genetic half of 258
genes composed from the Gene Curation Coalition export (cardiomyopathies,
channelopathies and inherited arrhythmias, aortic aneurysm and dissection,
monogenic thrombophilia and hypertension, the monogenic forms of coronary
disease and of cerebral small-vessel stroke; pulmonary arterial and portal
hypertension are excluded by name because they belong to the lungs and the
liver), the ten cardiovascular scores, the prescriptions acting on it, and the
questions for a clinician. On the figure it is drawn at the heart. Lipids stay
a separate segment and keep the lipid measurements; the pulse and heart-rate
variability a wearable records stay in fitness, because a segment has one
source. Nothing stored is rewritten: the five markers were already recorded
under their own keys, and the segment reads them where they are.
### What is fixed
**A click on a radar label opened nothing, and the dot beside it was hard to
hit.** The dot's hit area was eighteen pixels across, and the label beside it —
«Lipids 56» — was not a door at all, so a click on it did nothing and looked like
a hang. The label opens the system like the dot does, and the dot answers within
a wider circle around it. A click from the radar now opens the system's card at
once and asks the server for nothing: the answer the radar already drew is the
one the card shows.
**The radar tab took about a minute to open on a real profile.** The list of
systems and every card asked the same questions hundreds of times: the genome
folder was searched and each file in it opened by content on every genome read,
the genotyping program was started once per position for the list and again for
every card, the laboratory results were analysed again for each card, and the
coverage table was parsed again for every gene. What a file's content says is
now remembered while the file is unchanged, the rows read at a position are
remembered while the file and its index are unchanged, and inside one reading
each of those questions is asked once. The list of systems opens in about four
seconds after a start and under a second after that; the cards in about two.
**The Ouroboros installation never loaded.** The instructions copied the tools
module into Ouroboros's own tools package, where it could not import its
neighbours, so the plugin failed on its first line and registered nothing. They
now place one line that imports the installed package, which also means an
upgrade of the package is the whole update of the plugin.
**A reference file refreshed on this machine outranked a newer one the package
carries.** An import kept answering for as long as the file existed, so after an
upgrade a months-old local copy silently beat the newer copy the build brought. The
newer of the two now answers, by the date each carries; `scholion sources` says
which copy answers each file and why, and a local copy with no date keeps
answering and says that it cannot be compared.
**The button labelled «Check for updates» refreshed ClinVar, and after a pip
install it answered with a file path.** It never updated the program: it ran a step
of genome preparation that a pip install does not carry, and the reason it printed
was a path inside the Python installation. It is now called «Refresh ClinVar»,
where it cannot run it is replaced by a sentence saying where that step is done,
and updating the program itself is `scholion version`.
**A cardiology prescription was printed as acting on nothing, and six
polygenic scores appeared on no card.** An ACE inhibitor, a sartan, a
beta-blocker, a calcium-channel blocker, a thiazide or loop diuretic, warfarin,
a direct oral anticoagulant, clopidogrel or an antiarrhythmic was listed as
«unmapped» on every system card, so `scholion prescription` could not
reach its genes through a system; the scores for atrial fibrillation, heart
failure, hypertension, systolic blood pressure, ischemic stroke and venous
thromboembolism were computed and shown on the genome tab but placed on no
system. All of them now stand on «Heart and vessels», and coronary artery
disease, myocardial infarction, peripheral arterial disease and abdominal
aortic aneurysm move there from the lipid card, where they had been the only
outcomes among measurements.
**Three lines of every form from one laboratory were read by nobody.** Total
calcium, magnesium, zinc and serum copper — the biochemical rows, printed in
mmol/L and µmol/L — were excluded from any form whose text or file name
contained «исп», the three letters that stand for the elemental method. Those
letters also stand inside «Исполнитель», the word that names the performing
laboratory in the header of every form one Russian laboratory prints, so on
those forms the four rows matched nothing at all: the elemental series does not
answer to the plain printed names, and the biochemical series had excluded
itself. Nothing failed — the other rows of the same form were read as usual, and
the missing ones were simply absent. The rule now names the form it meant
(«ИСП-МС», «Ответ ИСП»), and a check refuses any form rule short enough to hide
inside an ordinary word.
**A form could be counted as already read without ever having been read.** The
list of files a loader has taken remembered each one by the name it was given on
the command line. Named by a path relative to the directory the command ran in —
`ingest-labs ../forms` — that name meant a different folder from a different
directory. Two folders reached by the same relative name, a file of the same name
and the same modification time in each, and the second was passed over in
silence: present, never refused, its rows simply absent from the history.
Copying is what makes modification times equal, since `cp -p`, rsync and every
cloud sync carry them over with the bytes. A file is now remembered by its full
resolved path, so two files can no longer be one entry, and one file reached
through two paths — a folder of forms opened through a symbolic link, say — is no
longer read twice. Lists written by earlier versions go on working and are
renamed as each file is met again, so nothing is re-read because of this change.
### What needs recomputing
**Run `scholion genotype-sites` — if the catalogue positions were genotyped from an alignment before this version.**
The locus catalogue grew from 61 to 113 positions. A position the genome file
does not list counts as the reference only when a sites file genotyped from the
alignment confirms it, and a sites file made before this version holds none of
the new positions: in a segment panel they print as not read, never as the
reference. `scholion recompute` finds this step by itself and runs it with the
alignment and the reference it names. Everything else in the panels, the
heart-and-vessels segment included, is read from the reference base at every run
and needs nothing.
**Run `scholion ingest-labs --force` over your folder of laboratory forms — if a form names its performing laboratory in its header.**
Total
calcium, magnesium, zinc and serum copper from those forms are in no series at
all; re-reading adds them. Two cautions. A value converted by an earlier version
out of the biochemical row into the elemental series — a calcium of 2.31 mmol/L
stored as 92.58 mg/L, and the same shape for magnesium, zinc and copper — is NOT
removed by re-reading: it stays beside the true elemental readings, where a
change of method reads as a trend. Such a point carries no date beyond its month
and no source, which is how to recognise it. Delete it by hand — but only AFTER
the re-read has put the printed row where it belongs, or the value leaves the
profile altogether.
**Run `scholion ingest-labs --force` — if the folder of forms has ever been named by a path relative to the directory the command ran in.**
A form passed over for that reason left nothing behind to find it by: it counted
as unchanged, not as refused, so no report names it. One full pass over the
folder is what rules it out, and it is the same pass the note above asks for.
## v0.5.0 — 13.09.2026
### What you can do now
**Every body system now has its genetic half, composed from a base with a
version, without waiting for anyone's signature.** Eleven systems of the radar
carry a gene list taken from the Gene Curation Coalition's export: which genes
have an asserted link to the diseases of that system, who asserted it, how
strongly, under which mode of inheritance, and on what date — 945 genes in
all, from 31 for the growth axis to 218 for the kidneys, every submitter's row
kept side by side. The disease groups behind each list are named per system
and tuned title by title against the export; a term that matched the wrong
things — a bare «gout» that reached a neurological syndrome, «short stature»
that reached sixty syndromic genes — was vetoed by name, and the tool now
carries such vetoes so a refresh keeps them. The primary analysis runs on
every system at once: what was read, what was not, what ClinVar holds, and the
questions that follow. A clinician's signature is still what the curated
layer waits for — the positions, the phrases per genotype state, the signed
exclusions — but a list composed from the base no longer waits for it.
**COMT rs4680 stands on the radar, under the adrenal axis, and says what it
does not decide.** The catalogue held the locus since the previous release;
the adrenal system now carries it as an authored position: one or two copies
of Met are printed with the sentence that CPIC names the gene in its opioid
guideline and issues no recommendation by it, that the behavioural and
cognitive associations of the 2000s do not reproduce, and that nothing is
decided by the genotype — it is shown because it is asked about. It is printed, and it is not a finding: a
position never read prints as unread, and the named allele not found prints as
read and absent, with the depth.
**Polygenic scores stand beside every body system, as scores.** Of the seventy
pinned polygenic models, thirty-eight are placed with the system they measure —
LDL and coronary disease with the lipids, type 2 diabetes and glycated
haemoglobin with carbohydrate metabolism, Crohn's and lupus with inflammation,
gout and kidney disease with the kidneys — and each system's card prints its
scores under their own heading, never interleaved with the gene rows and never
inside the 0–100 index or the verdict: a genotype cannot be refuted by the next
blood draw. A reliable score at or above the eightieth percentile becomes one
question for the clinician — whether a screening is worth discussing — with the
caveats in the sentence: a percentile is not a probability, and the panels are
mostly European. The thirty-two models that fit no system of the radar are
named, with the reason, in the file that maps them. A profile with no scores
says so, and says that scores are computed from a full genome.
**The card says what a full genome would add.** For a person whose genome file
is an array, an exome or a panel — or who has none yet — the «to read in the
genome» basket names, per system, the genes of the list a full genome would
read and the polygenic scores it would make possible. A full genome prints
nothing there, because nothing is missing.
**The «Second opinion» tab is now «Radar», and it carries the whole picture.**
The figure and the radar with two rings per system, and one block per system
below them: what is outside the corridor, the genetic half composed from a base
with a version and how much of it was read, the polygenic scores, the
prescriptions acting on it, what to test and the questions for the clinician —
with the system's full card one click away. An explanation of what the rings
and the genetic half mean stands on the page itself, and the page still prints
as the sheet to take to an appointment.
**A body system answers as one card on every face.** Click a segment of the
radar or an organ on the figure, run `scholion system thyroid`, ask the local
API or the assistant's tool, and the same card comes back: the laboratory now
and its movement since the previous draw, the genetic half and how much of it
was actually read, the prescriptions acting on the system, the target a
clinician set, what to test, and the questions to bring to the appointment. The
next step comes in three baskets — laboratory, genome, ask — and a basket that
is empty says why it is empty. The card has two densities, one for the patient
and one for the clinician; they differ in how much is said, never in the
verdict, and no line in either is an instruction.
**The second look is laid out by body system.** What is outside the corridor,
what is prescribed for that system, what to test and what to ask now stand
together under one heading per system, where before the thyroid appeared three
times in three layers without being called one subject. Each block prints
whole, and a system with nothing to say is named as silent rather than left
out.
**Every system carries two rings, never merged.** How much of its laboratory
panel has been measured, and how much of its genetic half has been read, drawn
as two rings on the figure and on the radar. A system whose genetic list is not
composed shows that ring dotted — an absence, not a zero.
**Markers, genes and prescriptions point to their system.** A marker card says
which system it belongs to and opens that system's card; a gene says in which
systems it is named; a prescription says which system it acts on. A
prescription's genes now come from the system it acts on, and a clinician's own
rows about that drug stand as exceptions on top — a sentence, a class of link,
or a signed exclusion; an unsigned exclusion is refused and counted. Thirteen
drug classes are mapped to a system; the classes whose target is a use rather
than an organ — blood pressure, anticoagulation, pain — are left unmapped, and
the file says why.
**Three entries refuse in one voice.** A prescription, a class of disease and a
body system all judge their gene list through one form: the same gate (printed
only with a sentence and a source, the rest counted), the same pending row, the
same four-state verdict with the number of unread genes inside it, and the same
sentence. A list that was not read end to end is never called clear, whichever
door was used.
**The genetic half of a body system is composed from a base with a version, and
a clinician signs exceptions.** For the thyroid the monogenic composition comes
from GenCC — 38 genes, every submitter's assertion side by side with its
classification, mode of inheritance and date, and the export the list came
from printed with it. A clinician's own positions, phrases and exclusions are
read from a curated file that ships empty and says why. Ten systems say plainly
that their genetic half is not composed; the twelfth, built from wearables,
says it has none by design — three different answers where an empty block used
to be the only one.
**What the engine says about genetics is bounded.** Every row carries its
evidence mode and the three modes never print alike; an assertion classified
Limited, Disputed or Refuted is never a finding; one copy of an allele in a
recessive gene is printed as carriership and raised as a question, never as a
risk line; a single common variant prints only with an effect size from a named
study; and genetics does not enter the 0–100 score — a genotype cannot be
refuted by the next blood draw, so it stands beside the score, not inside it.
**A target your treating clinician set has a place of its own.** «TSH between
1 and 2», «free T3 5.0» — beside the reference interval printed on the form and
separate from your personal goals. You enter it with who set it and when; a
target without either is refused, and the product never proposes a figure of
its own. The figures convert to the marker's standard unit the way a laboratory
value does. The labs report, the marker cards and the marker charts show the
target beside the corridor, drawn in a different stroke so the laboratory's
range and the treatment's aim are never confused. When a value sits inside the
corridor but outside the target, the product asks whether it is worth
discussing at the next visit — a question, not an instruction. Standing outside
a target is never counted as an abnormality: the flag and the out-of-range
count are exactly what they were before. Targets live in their own file, so
re-importing a folder of forms rewrites the series and leaves them in place;
`scholion target` and a matching block on the labs page list, record and
withdraw them, and name in one place the values that are in the corridor yet
outside a target.
**The monogenic half of a system's gene list can come from a curated base
instead of from one person's memory.** A single command pulls the Gene
Curation Coalition's weekly export, keeps only the genes whose diseases belong
to a system, and writes them down with everything a reader needs to weigh each
line: who asserted the link, how strongly, on what date, under which mode of
inheritance, and which version of the base it came from. Every submitter's row
is kept, so two groups disagreeing about one gene are shown side by side rather
than averaged, and a weak or refuted assertion travels marked as such rather
than being silently dropped or silently promoted. The thyroid system ships
composed this way — thirty-eight genes with the recessive ones named recessive,
which is the difference between «carrier» and «at risk» for a heterozygote. A
freshness check says how far behind the base the shipped copy is, and the tool
refuses to touch the network when told to work offline. The other ten systems
remain unfilled on purpose: their terms are entered from a named panel or
report, and none has been named yet, so each says so instead of looking like a
system nobody asked about.
**A gene answers with what has been decided about it, not only with genotypes.**
Asked about a gene, the build now prints the curated verdict written about that
gene before the findings and again under them — including the case where the
verdict is that no clinical decision follows from it. Where such a sentence
exists it is quoted with the file it came from: a statement about what does not
follow from a gene is as much a claim as one about what does, and neither is
printed unattributed.
**How well a gene was read travels with the answer about a prescription.** The
measure arrived with the gene question and was wired only there. It is now beside
every gene on the prescription path as well, where «no pharmacogenetic finding»
is read as permission to proceed and is worth exactly as much of the gene as was
read. One state stays silent — a gene read like the rest of the file — and that
is not a claim that the reading was sufficient: sufficiency depends on the
question, which the product does not know. Without an alignment file the answer
is «not measured», which is a fact about the input.
**A second way in: a class of disease instead of a prescription.** `scholion
screen` answers the question a person has when nothing has been prescribed and
the examination says they are well — what to look at for the conditions where
inheritance carries most of the weight. The gene list there is fixed in advance,
which is what a panel is, and this build still invents none: the classes come
from the published secondary-findings panel it already carries, with the
panel named as the source, and every class that panel does not cover is printed
as absent rather than left out. A curated file takes classes a clinician
supplies, under the same rule as the prescription side — a list without a named
source is dropped and counted.
The answer for a class is gene by gene, and it will not call a class clear it
did not read: something reportable was found; nothing was found and every gene
of the class was read; nothing was found and part of the class was not read,
with how many and which; or the screen has not been run. On a screening result
«nothing found» is taken for health, and over a gene nobody read it is a
statement about the file. A finding does not cancel the gap either — both travel
in the same sentence.
The entry is on every face at once: the command line, the page (a pane of the
genome tab), the plugin, the model-facing tool list and the instruction the
model reads.
**Everybody has the gene; what can be missing is a variant, or knowledge of
one.** The class of link that used to read as «this gene is not here» was making
a claim about a person. It now reports what this build can say about variants in
that gene, measured against the reader's own file and never defaulted: positions
read and matching the reference, with how many of how many and at what depth —
which is a measured absence of a finding; positions held and not read in this
file — which is an absence of measurement; or no position held for the gene at
all — which is a statement about the build. Positions with no row are counted
beside the ones that were read, so two confirmed out of eight held no longer
reads as «nothing here».
**A gene somebody named, whose meaning nobody has written yet, is kept and
printed as unwritten.** It used to be dropped with the unattributed entries. It
is the most informative row on such a screen: it says a clinician put the gene
on the list and that what follows from it is still to be written — and the build
says plainly that it will not fill that in. The class of link is authored too: a
gene arriving without one is printed as named and unclassified rather than filed
under a class this program chose.
**A prescription is answered with a judgement about the choice, not only with
genotypes.** Asked to check a drug, the answer now opens with one of three
statements, and each is about what this build holds rather than about what to
do: a rule for this pair exists and the reading selects a row that is not the
neutral one; a rule exists and the reading selects the neutral row, which is a
statement about the rule and not clearance; or no rule could be reached, with
the reason named.
**The link between a prescription and a gene has a class, and the class decides
what may be said.** Two classes are computed from this build's own tables — a
pair with a guideline, and a pair recognised with no table, which travels with
the date of the copy. Three cannot be computed: a gene that handles the
substance with no dosing rule following, a gene asked about from which nothing
follows, and a gene named in a list and unknown here. Which genes belong to a
prescription is a medical statement and so is «nothing follows from this one»,
so those three are read from a curated file and never derived. An entry without
a named source is not printed, and the number of entries dropped that way is
printed instead — an entry that vanishes quietly is indistinguishable from one
nobody wrote.
The curated file ships empty, deliberately. Until a clinician writes a row, the
honest answer to «what else bears on this prescription» is that this build holds
no list for it — and that sentence is printed, because a silence there is
completed by whoever is answering the reader, out of knowledge that never passed
through this build.
**Every locus stands on one of five named things, and two of them license
nothing.** What permits saying anything about a position — a guideline rule, a
curated note, a verdict about the gene, or the bare fact that the gene is a
recognised pharmacogene this build holds no table for — is now decided from the
files and printed. The fifth state is a position with none of those, and it no
longer prints a genotype and stops: it says this build holds no reading for the
position, the genotype is named and not interpreted. A check walks the whole
catalogue and fails on a locus that stands on nothing silently.
### What is fixed
**A gene the ACMG scan had put through ClinVar was still called «not put
through ClinVar».** The system card counted a gene as read only when the
wide ClinVar annotation — a separate pipeline step — had been run; on a full
genome with only the product's own ACMG scan, APOB and LDLR on the lipid list
said the annotation had not been run, although the scan had done exactly that
for its 84 genes. For those genes the scan now counts; every other gene still
says, in words, that its variants were not put through ClinVar, and what
closes it.
**Why a gene was not read printed as a code.** «not read (clinvar_not_run)»
stood on every such row and once per gene in the genome basket — two hundred
and eighteen lines for the kidneys, none of them saying what to do. A reason
is now a sentence in the reader's language, the basket groups the genes by
reason on one line each, and each line names the step that closes it: the
ClinVar annotation of the file, or the coverage table computed from the reads.
**A position whose author says nothing follows counted as a finding.** An
authored position of the «asked about» kind — COMT Val/Met — was counted into
the system's verdict as something reportable, while its own sentence said
nothing is decided by it. Such rows are printed with their sentence and are
not findings; the patient's register shows them, since the sentence was
written to be read, and shows the genotype state on them instead of «not
determined».
**The demo-genome recipe ended in a refusal.** The fetcher printed «lay out a
profile, then point the product at both», and the product then refused to
read the reference genome beside a profile it took for the person's own. A profile
can now be laid out for a reference sample — `scholion init --subject
reference` — every file of it says so, the reference genome is read beside
it, and the refusal that used to print a raw key names this way out.
**The demo-genome fetcher crashed on its first request.** `fetch_demo_genome.py`,
the one tool that downloads a public Genome in a Bottle sample so the product
can be shown with a real genome, had `encoding=` pasted onto its HTTP calls to
satisfy a text-file check, and every run since 0.4.9 stopped with a type
error before listing anything. The three calls are HTTP openers again, and the
check now knows them by line.
**Three tools could not be called through the tool server.** A model asking to
note an episode in the focus journal, to record why a day holds two draws, or
to propose a marker name received a type error instead of an answer — on every
call since those tools appeared, because the three read their arguments in a
way no host passes them, and the test that covered them filled the arguments in
by hand. All thirty-two tools now answer over the wire with the arguments their
schemas declare, and a test calls every one of them that way. Nothing stored
changes.
**Five tools were served without a description.** The register of sources, the
array report, the flag rate, the draw context and the marker proposal showed a
raw key where a description belongs, in both languages. They are described now,
and a raw key in a tool list fails the build.
**Asked to transcribe laboratory forms with no folder named, the tool read the
current directory.** An empty folder name resolves to wherever the process is
standing, so a call that named nothing could transcribe every PDF under the
working directory into the profile. A folder must now be named; an empty name
is refused before anything is read, a refused call no longer copies the
transcription manifest into the profile, and on success the tool prints the
same report as the command line — it used to fail on a spreadsheet export
after having written the profile. If such a call ever ran against your
profile, the points it added carry the file names they came from and can be
removed by re-importing the folder you meant.
**An unknown register was served as the patient's.** Asked for a system card in
a register that does not exist, the local API and the tool answered the
patient's card labelled with the word given. The request is now refused by
name, with the two registers listed; the command line always refused it.
**Two writing commands were listed as reads.** Recording the context of a
double draw and proposing a marker both write to the profile, and the
capability manifest called them reads. They are listed as writes of the
dictated kind — what the person said, never a value — and the skill text and
the tool descriptions no longer claim that only one tool writes: four do, and
each records what the person handed over.
**The web's source badges had no command-line twin.** The route the page reads
its «where this data comes from» badges from was mapped to the provenance
audit, a different function. `scholion sources --json` now carries the same
block under `data_sources`.
**A Russian card explained an empty genetic list in English.** The sentence a
system prints when its genetic list is not composed shipped in one language.
Both now.
**A wearables file in the oldest layout listed the years as kinds of workout.**
A file that kept workouts as «kind, then year» was carried over to the current
layout without being turned, so the summary printed «2024» as a type of
training and «Walking» as the last active year. The file is now turned on
read, once; nothing stored changes, and a file already in the current layout
is read exactly as before.
**A gene link typed into a person's own lab file no longer reads like a curated
statement.** Such a line is free text without a source; on the second look it
was printed in the same voice as a sentence that had passed the gate. It now
travels marked as the person's note, so every page shows it as one. Nothing in
the stored profile changes.
**A deletion or duplication in a position list could be read as the reference —
with an empty genotype.** Asked about a position whose event is not a
single-base substitution — a frameshift deletion, a duplication, an insertion —
the locus reader fetched the coordinate, found no row there, and answered
«assumed reference» with an empty string where the genotype belongs. A variant
of that kind is written one base upstream in a VCF as a pair of alleles of
different length, so the reader was looking at the wrong base with the wrong
instrument and calling the silence calm. Such a position is now refused by name
before any file is opened: the coordinate is given, the event is named, no
genotype is written and no reference is assumed, and the answer says what would
read it. A position list that contained such an event now shows a refusal where
it showed an empty reference.
**A position with three alternative alleles can now be held, without anyone
choosing one.** The catalogue holds one alternative nucleotide per position,
which is right for comparing genotypes and left some studied positions unable to
be entered at all. Such a position is now kept with its coordinate and the
alleles observed there and no alternative chosen — which of them a study meant is
not in the source, and this build does not pick. Every reader refuses on it by
name, before reading anything: the coordinate is given, the observed set is
named, no verdict is offered. An entry may hold a comparable pair or an observed
set, never both — one carrying both would be compared against the chosen allele
while looking as though it had declined to choose.
**A catalogue refresh could rewrite the alleles it was only meant to check.** The
documented update command refreshes the coordinates of every locus it already
holds, and it was writing into the alternative-allele field whatever the public
source returns — the full observed set, `A/T`, `C/G`. The catalogue holds one
nucleotide on each side and the genotype comparison reads one character from
each, so a run left thirty-five of fifty-five loci compound, among them the ones
dose answers are drawn from. A refresh may move a coordinate and may not decide
what the alleles are: a disagreement about alleles is now reported and never
applied, since which is right is a curation decision with a source behind it. A
position the source reports with more than one alternative allele is named and
left out rather than guessed at, and the whole file is checked against its own
invariant before anything is written — a run that would break it writes nothing
and exits non-zero, instead of printing «Written to:» over a broken catalogue.
Adding a locus no longer leaves an empty record behind when the source does not
answer.
**«Coverage not measured — » printed with nothing after the dash.** The value of
that line is the reason: no alignment file, no index, or a gene outside the
coverage table need opposite actions, and an empty one reads as text that broke
off. A reason is always printed now, including the one that says nothing said
why.
**An annotation beside the data was not looked for there.** The gene-coordinate
search consulted two declared folders, and on a machine where neither was the
one holding the file — while the live source was unreachable in the same moment
— three genes came back unresolvable with the file one directory away. The
folder holding the alignment the profile already knows about, and its
neighbours, are now part of the declared list. An explicit setting still
switches the search off entirely.
**A caveat vanished when a gene was listed rather than a position.** Each line of
a gene listing is cut to its first line, and everything a position had to add
about itself was on the lines after it. On one locus that discarded sentence was
the one that decided the answer: the catalogue's own note saying the variant read
there is the minor one for most readers, and that the main one is not a single
substitution and cannot be read from a variant file at all. The curated note, the
note about that particular read, and any refusal are now printed under their
locus in a listing as well.
**A verdict written about a gene reached nobody.** One gene carried a sentence,
written and checked, saying that no guideline exists for it and that testing it
is not recommended. The field was translated into both languages and covered by a
check — a check that the field was in the file, which is a different claim from a
reader seeing it. On the screen that gene printed two bare genotypes. Nine more
curated sentences were in the same position, across four files: how an analyte is
measured and why its published limit may be the wrong one for the reader, what a
laboratory code means for that analyte, why a missing guideline row is missing,
and which tools were examined, not taken, and what taking one would close. All of
them now reach the reader, each where its own answer is. A check enumerates every
curated field of this kind and fails on one that nothing renders, so that the
next such sentence cannot be written for nobody.
**«No meaningful pharmacogenetics for this drug» carried no date.** «Nothing is
known about this pair» and «our copy of the guidelines is a release behind» are
different facts, and the date of the copy is what tells them apart. The
drug-by-name path said it; the prescription check — the path taken before a
tablet — did not. It does now, in the command line and on the page alike.
**A mineral measured by two methods stayed one series.** An elemental analysis
(ICP) reports calcium, magnesium, zinc, copper and iron as mass per litre; a
clinical-chemistry panel reports the same elements in molar units, and the two
disagree by more than rounding — over ten per cent on the same sample. The
dictionary converted the molar result by the atomic weight and appended it to
the elemental series, so a change of method read as a change in the person; for
iron the elemental row had no unit gate at all, and a molar value carrying the
symbol was stored as micrograms unchanged. Every such element now has two
markers, each declaring its method; the elemental one accepts no molar unit, and
each is kept off the other method's forms. Serum copper by the biochemical method
is a new marker with a standard adult interval by sex. A check refuses the next
element that mixes.
**Re-importing laboratory forms could add a second point for a draw the series
already held.** When the earlier point was dated to the month — the shape older
imports wrote — and the form carried the day and clock time, nothing was
refused: the marker count stayed the same while the number of points grew, and a
trend read the same draw twice. A point of the same period now stands in for the
earlier one at every resolution: a draw replaces its day or month, a day replaces
its month, and the finer date is kept whichever order the two arrived in, with
what the earlier entry recorded about the draw carried over. A month or day that
arrives against two distinct draws inside it still replaces neither and is
reported, because choosing one would be a guess.
### What is retracted
Nothing.
### What needs recomputing
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if forms were ingested by an earlier version.**
A month point beside a dated point of the same draw is collapsed into one (the
next write to that marker, of any shape, does the same), and biochemistry copper
points move from the elemental series to their own marker.
**By hand — if an elemental-iron point sits in the low tens.**
It is a molar value stored as micrograms; remove it from the series.
## v0.4.11 — 12.09.2026
### What you can do now
**A variant file with no index is read.** Every reader of a genome file used to
need an index beside it, and the tools that build one are not on a physician's
machine. Such a file is now read once from beginning to end — the catalogue's
positions in both builds, the counts that tell what kind of file it is, and the
header — and no index is written, because one written subtly wrong would be
trusted by every other tool. What that reading cannot answer is refused by
name: a question about a whole region says it needs an index and names the two
commands that make one, rather than answering with an empty list that reads as
«this gene carries no variants».
**The screen for what is worth acting on runs from an installed package.** The
secondary-findings screen over the 84 ACMG genes does not compute when asked: it
reads a table, and the pass that writes that table lived in the data-preparation
directory, which does not travel with `pip install`. `scholion acmg-scan` runs it
now, with no external tools and no index, from the person's variant file and the
published ClinVar file; when that file is missing the command prints the one
download it needs, for the build the person's file is in. Each file's build is
established from the file itself, and a crossed pair — a GRCh37 genome against a
GRCh38 ClinVar — is refused before a single position is compared, because a
crossed pair does not fail: it finds nothing, or matches a position that belongs
to a different base, and both look like an answer.
**An exome is told apart from a panel.** Breadth used to be probed in windows
that are gene-poor by construction, where an exome is empty, so an exome was
classed as a sparse panel — and that class shuts the ClinVar and ACMG paths, on
the one input where a screen for known pathogenic variants is most obviously
worth running. A second set of probes in gene-dense windows tells the two apart
by contrast. The two paths open on an exome and say what an exome can and cannot
answer; polygenic scores stay shut, because a score summed over the coding two
per cent of the genome has no distribution behind it.
**The status says which questions this input can carry, before any finding.**
Six paths — catalogue loci, pharmacogenetics, a whole region, ClinVar, the ACMG
panel, polygenic scores — each marked open or shut for this file, with the
reason; «this input cannot carry the answer» is told apart from «the annotation
this path reads has not been produced», which used to be invisible because the
narrower gate fired first and blamed the file for a missing table.
**A gene is asked of every shelf that holds anything about one.** What this build
knows about a gene sits in four places, each keyed differently — the curated
catalogue by rsID, the ClinVar scan by coordinate, the shipped ACMG secondary
findings panel by symbol, coverage by gene — and nothing joined them. Asking about
a gene read the catalogue alone and answered «not in the coordinate reference»,
which is a statement about one shelf and reads as a statement about the genome. A
clinician asked about the bile-acid transporters and was told there was nothing to
say «even in general terms from your genome», while the ClinVar table on that
machine held 386 findings.
`scholion genome --gene X` now prints a frame before the findings: what each layer holds,
that it holds nothing, or that it could not be asked and what would let it be. A
gene in the ACMG panel is recognised with no network and no annotation file,
because those 84 symbols travel inside the build — so a question about BRCA1 on a
machine that cannot reach Ensembl gets an answer rather than a shrug.
**ClinVar can be asked by gene.** `scholion clinvar --gene X` matches findings to a gene by
COORDINATE — the scan table carries no gene column, and this needs no re-scan of
the genome. A gene whose coordinates cannot be obtained is reported as unresolved,
with what would resolve it, rather than as a gene with no findings.
### What is fixed
**A row at the position was taken for the locus.** The reader took the first
variant row at a catalogue position and built the genotype from that row's own
alleles. A coordinate is not an identity: an insertion, a neighbouring
substitution or a multi-allelic row can stand on the same base, and the genotype
printed then belonged to somebody else's variant while carrying the locus's name
and the label «called». On three clinical files the alleles at the Factor V
Leiden position disagreed with the catalogue in every one. The row is now
chosen, not taken — its alleles must be the catalogue's — and the two ways of
failing to find one are named: another variant on this base, and a reference
base that is not ours at all, which is a statement about the file's build, never
about the person.
**A genome file with no index that had been cut short was read up to the cut
and answered «reference» at every position past it.** A copy or a download that
did not finish leaves such a file; a heterozygous APOE ε4 carrier could be
printed as a non-carrier under a status line saying the genome was connected.
Such a file is now refused by name — the status says the file ends before its
end — and a reading that dies part-way is answered as a failure rather than as
an empty result.
**Two shapes of a gVCF row printed the strongest label the layer has over
stretches that were never read.** A reference block whose genotype is a no-call
(`./.`, depth 0 — what a caller writes over an unread region) answered
«confirmed reference»; and a row whose only alternative is a spanning deletion
(`*`), left behind when a multi-allelic row is split and one half filtered,
answered «confirmed reference» at a base that lies inside a deletion on one
chromosome. The first is now a no-call; the second a refusal naming the allele
found.
**A deletion or multi-base change standing on a catalogue base was reported as
«the file is in another build»** — a claim about the file made from a row that
merely carried a different variant; it is now «another variant at this
position». A multi-allelic row written with a shared trailing base rendered a
heterozygote as a four-letter string labelled «called»; it now prints the
locus's own allele pair, and a genotype naming an allele of another length
beside ours is refused by name instead of concatenated.
**An owner of a genotyping chip saw a status that said the array was connected
and, six lines later, «no genome is connected» on every question** — closing
the locus catalogue and the pharmacogenetics a chip answers as designed. The
frame now belongs to the input that answered: the catalogue and
pharmacogenetics are open, a gene region is closed because a chip reads chosen
positions and a gene is a stretch nobody chose, and the screens are closed as
too narrow; a gene query on a chip refuses with the same reason instead of
proceeding without a file.
**The secondary-findings screen could report a variant a person does not carry,
and miss one they do.** A row whose genotype was not called at all — the
ordinary shape of a family file or a gVCF — was written as a finding, because
«not a reference» was the only test. A row with two alternate alleles was
matched on the pathogenic one and judged from the other, so a person homozygous
for a benign second allele was reported homozygous for the pathogenic first. And
in a file holding several samples the first column was read as the person's: a
mother's BRCA1 heterozygote, screened as her child's. Each is now a named step —
the column is chosen, the allele index is required in the genotype, a no-call is
counted and said with the result — and a call the caller itself flagged as not
PASS is written as filtered rather than decided.
**The refusal against matching two builds could be switched off by the one
variable meant to arm it.** Declaring the build of a headerless personal file
also declared it for the ClinVar file, so a declared GRCh37 against the
downloaded GRCh38 ClinVar read as «GRCh37 against GRCh37» and ran. The ClinVar
build is now read from the ClinVar file alone. And a personal file whose build
could not be told at all went into the scan with a clean «ok»; it now refuses
and names what closes it, the same way the ClinVar side already did.
**The table was written beside the variant file while the screen read it from
the genome folder**, so with the file anywhere else the command said «written»
and the screen said «not run». It now lands where the screen looks, and carries
a sidecar saying which builds it was matched in, which ClinVar release, when,
and how many positions were unread — so a stale or crossed table can be told
from a current one.
**The advice about external tools described a product that needed them.** The
first command a new person types offered four binaries and explained that
without them «the genome layer does not work at all». True when written, false
since a file without an index became readable and the ACMG screen became
runnable. It now says what the four buy — seeking a region or a whole gene, and
the wide ClinVar annotation — and what answers without them.
**The gene frame said the wrong thing about a scan that had not run.** Asking
about a gene prints, above its findings, which shelves of the build hold
anything about it. When the ClinVar scan had simply never been run, that frame
said the gene's coordinates could not be obtained — sending a person to fetch an
annotation file they did not need — and `clinvar --gene` blamed a missing or
broken index. Worse, the ACMG line printed «in it, 0 findings» for a panel
nobody had scanned: a false «clean» on a hereditary-cancer gene. Each layer now
says which of three things is true — what it holds, that the scan has not been
run, or that it could not be asked and why — and a warning that only part of the
findings table was read now reaches the frame instead of dying on the way.
**The web page still showed a genotype for a position with no row.** A position
absent from the variant file means either «reference» or «never read», and the
command line had already stopped rendering that state as an answer. The page
had not: the card printed the reference bases in large type with the caveat in
small type beside it, and a gene listing did the same for every such locus. The
page now prints a dash there, on both views.
**A prescription's status could not be set, was erased on re-entry, and stopped
drugs looked current.** No writer — command, page or API — could record whether
a drug was current, so for anyone not editing the file by hand every entry was
«no status recorded» while the wording claimed those entries predated the field.
Re-adding a name to change its dose replaced the whole entry, so a stopped drug
came back current with its start date and monitoring gone, silently. And every
listing of the regimen drew a stopped drug like one taken this morning, while the
interaction check had already excluded it. A status can now be written
(`add-med --status`, a field on the page, `status` in the API); re-adding merges
and says what it kept; and every listing — command, page, and the context handed
to a model — marks entries that are not current. A pulse course counts as
current everywhere, by one rule.
**A gene filter over a truncated scan said the gene was clear.** The ClinVar
scan is read a page at a time, and the gene filter took the page: on a profile
with more findings than one read, «0 in this gene» would have been printed
where the finding sat past the cut. The filter now compares what it read with
what exists and says when it could not see everything. In the same pass: a gene
frame that failed to build vanished without a trace and now reports itself
unavailable with the reason; a single letter of a supplement's name matched a
drug and earned it a pharmacogenetic tag, and a match now needs a whole name; a
folded provenance note could still run to three hundred characters and now has
a ceiling.
**What the person is taking NOW is asked instead of assumed.** Every comparison —
interactions, drug classes, the laboratory monitoring rules, the limitations —
ran against every name in the prescriptions file, so a drug the physician stopped
carried exactly as much weight as one taken this morning. A statin that left the
scheme on the day an azole course was replaced still produced «↑ statin
concentration, risk of myopathy», and beside it a warning about a probiotic
paused six weeks earlier.
A status decides now, and it decides by a WHITE list, so a value nobody taught the
code about is not silently treated as current. An entry with no status at all
stays current: those predate the field, and reading them as stopped would delete
real prescriptions from every check at once — silence where a warning belongs is
the worse mistake. And what was left out is named in the answer, because a red
line that is absent for a reason and a red line nobody computed look identical on
the page.
**How well a gene was read comes with the answer about it.** Coverage was a
footnote at the bottom of a report, and the question it qualifies is asked one
gene at a time. It now travels beside the answer — and only when it is worth
saying: a gene read in line with the rest of the file is left in silence, a gene
far below it says so and says by how much.
The ruler is the file's own middle, and it was measured before it was chosen. At
20× on a 30× whole genome the callable fraction runs to a median of 79.8 %, with
the best gene of ninety-three at 92 % and none at 95 %: any clinical-looking
threshold therefore fires on 89 of 93 and is measuring the shape of a depth curve
rather than anything about a gene. Against the file's own median, eight fire —
and they are the genes that are hard to sequence for known reasons, X-linked or
carrying a pseudogene. The rule travels with the sequencing depth, so it says
something useful at 30× and at 100×.
Four states, one of them silent. «In line with the rest of this file» is never
reported as «adequate»: what is adequate depends on the question, which the
product does not know. A gene the coverage table does not cover, and a profile
where coverage was never computed, both say so — a silence that means «nobody
measured» is read as reassurance, which is the same mistake as a missing row
printing as «reference».
**A position with no row in the file was printed as a confirmed reference.** A VCF
of variants has no line where the genome matches the reference, and none where
nothing was read either; the layer calls that state «assumed», and every decision
in the engine already excluded it. The last mile did not. It rendered the state in
the shape of an ANSWER — «genotype TT (reference)» — with the honest note beneath.
On a single locus a reader got both, a reassuring label and a warning contradicting
it on the next line. In a GENE LISTING they got only the first, because a listing
keeps one line per locus and the note is the second.
A physician running this over DPYD — fluoropyrimidines, where the genotype is
required before the first dose — met eight positions labelled reference, six of
which have no row in the file at all. The state is now rendered as the refusal it
is, in one line, so it survives being cut to one line.
**A genotype with no curated reading behind it says so.** A variant outside the
curated set reached the reader as a bare genotype, and the silence where a reading
should be was filled by whoever was talking: asked about COMT, the product
correctly said the variant is outside its set, and the conversation supplied «the
low-activity variant» from general knowledge with no source inside the product.
The sentence is a statement about this build's catalogue, not about medicine.
**A refusal about a drug names which silence it is.** «We could not look», «we
looked and there is no such drug» and «we looked, found it, and no guideline for it
is in our copy» wore one sentence. The third now carries the date of the guideline
copy it is a statement about — which is what tells «the literature has nothing»
from «this build is behind».
**The regimen says which entries the model can speak about at all.** A list of
supplements produced «no interactions found», which is true and uninformative:
most of them are outside pharmacogenetics and always were. Entries with a
gene-drug pair are marked; the rest are named as outside the model rather than
left to look unexamined. Long provenance notes fold to their first sentence — a
list of forty-five entries carrying a paragraph each is not a list anybody reads.
**The build says when it is old.** It reported a stale reference database and said
nothing about its own age. It now reads its own release date out of the journal it
ships and says so on the first screen once that date is old enough to matter.
Nobody is contacted to find this out: a product whose claim is that the profile
never leaves the disk does not acquire an outbound host to deliver a convenience.
### What is retracted
Answers that labelled a position «reference» where the file has no row at it. No
stored value changes — the engine never counted those positions — but a printed
page or an exported summary made before this version may carry the old label, and
for DPYD and CYP2D6 that label reads as permission to prescribe.
A genotype printed at a catalogue locus whose row carried other alleles than the
catalogue's. It was somebody else's variant under our locus's name; it is now
withheld with the reason, so a report made before this version may carry a call
that will not be repeated — the Factor V Leiden conclusion among them.
An exome classed as a sparse panel, with ClinVar and the ACMG screen reported
shut. The same file now opens both paths; the earlier statement about what that
input could answer no longer stands.
### What needs recomputing
**Run `scholion acmg-scan` — if an ACMG table was written by an earlier version.**
That table was matched without checking that the personal file and the ClinVar
file share a build; if the two were crossed, it is a silent zero or a match on a
different base. The scan rebuilds it from the files and refuses a crossed pair; a
table whose files were of one build comes out unchanged.
## v0.4.10 — 09.09.2026
### What you can do now
**The Genome tab is one page at a time, and it opens with findings.** Seven
headings on one scroll — all open, the maintenance block above every conclusion,
and the same gene appearing in four of them without any of them saying so — are
now panes of one tab. The first is neither ClinVar nor polygenic nor longevity: it
is one list, ordered by how much a line can change and marked with the source each
came from. Clicking a gene anywhere on the tab gathers what every source holds
about it into a single card: the loci and their genotypes with coverage, what
ClinVar says at those positions, what the longevity layer and the lipid card say
about that gene. Nothing was removed — the sections are still there, one at a
time, and the service text each of them opened with is folded rather than first.
**The documents inside the package open as pages, and the second opinion offers
the one written for a clinician.** The product's own output names files — «see
PREPARING-THE-GENOME.md» — and after `pip install` the only way to read one was
`scholion doc <name>` at a terminal, which the person reading the interface may
not have open. The local server now serves the same nine documents at
`/doc/<name>`, each as a self-contained page that prints on paper and pulls
nothing from the network. «Second opinion» carries a button to the one-page
description for clinicians and researchers: what the program is, what it
computes, and where it refuses to answer — meant to be handed over at the
appointment.
**The first screen is the person.** It opened with the one experiment being run
this month and reached the reader before anything about the reader. The order is
now the order the questions come in: who the data belong to — sex, age, height,
body-mass index, the reference panel — then their own indicators, then the
targets they are aiming at, then the body systems and the figure, then what is
out of range right now, then what is worth measuring, and last the focus of
attention. Every block still names the tab that owns it and goes there on a
click.
**The Profile tab is retired into that first block.** It held four cards and two
forms, and the four cards were the ones a watch measures every day; as a tab of
its own it had become the emptiest page in the product. Nothing it could do was
lost — the profile form, the manual measurement form and the list of what the
profile is still missing all open at the top of the first screen.
**The state of the genome is said in one place, including when it is not being
read.** The tab used to show a grey badge and leave the reason unprinted; a
person whose folder held more than one candidate file met «not read» in six
places and the cause in none. The state now carries the file, the assembly, the
sample, what was set aside and why — and, where a choice is open, the names with
a button beside each. The choice is kept, so it is asked once
(`scholion choose-genome` at the command line).
**«What to test» is part of the second opinion.** Every row of it is a line for
the same conversation, and it was a tab that handed half of its own list back to
the tab beside it. The routine controls travel with it, folded.
**The lifestyle brief's «needs review» can be answered.** The flag is raised when
a marker a block watches is measured after the block's wording was last read, and
until now nothing in the product could lower it: it went up once and stayed up, at
the top of the tab, above the content. There is now one button — the wording still
holds — which records the date that has always been what the flag compares against
(`scholion brief-reviewed <block>`). It also moves down the page to sit beside the
wording it is about.
### What is fixed
**Accepting the reach baseline moved the whole file to whichever machine ran
it.** A number in `test_reach_baseline.json` is not a property of the code
alone: it is what the suite reached on one interpreter, with one backend — the
two do not count a line identically — and, for at least one module, only where a
file the repository does not carry happens to sit. `--strict` had printed a
warning whenever the run and the recorded stamp disagreed; `--accept` rewrote
every number regardless, restamped the file, and reported it in one line.
There are three writing modes now, and only one of them moves the file.
`--accept` records the whole measurement and refuses when the baseline was taken
elsewhere — before measuring, since the answer never depended on the ninety
seconds. `--accept-new` records only modules that have no accepted number yet,
which is what the suite's own guard asks for when a module is added; it changes
no other number, not the overall, and not the stamp, and it does not run the
suite at all when there is nothing to add. `--rebaseline` is the deliberate
whole-file move and prints every number it lowers, old → new, before writing.
**A document name was tolerant about spelling, which was free until a route
handed it one.** `DATA_LAYOUT`, `data-layout.md` and `data-layout` are one
request, and refusing two of them teaches nothing but the exact spelling. While
the only caller was a person typing at their own prompt, that was the whole
story; a URL is composed by whoever holds it, and `../../../etc/passwd` builds a
path outside the package as readily as a name builds one inside it. The
tolerance stays and the shape does not: a document name is one file name, or it
is nothing. Anything else opens the list of documents instead.
**Seven of the thirteen rows of the goal table said «—» while the numbers sat in
the file.** Weight, body-mass index, body fat, muscle mass, VO₂max, resting heart
rate and steps come from a wearable device, and five of the goal charts drew
nothing at all. The lifestyle layer stores a measurement together with the device
that made it — two watches do not measure resting heart rate the same way, and
one series built out of both shows a step on the month the second export was
loaded — and the goal reader had been written before that was true. It looked for
the metrics where they used to sit, found nothing, and returned an empty series.
Nothing failed and nothing was logged: «—» is what that table prints when there
is no data, and there was a decade of it.
Two things follow, and both are new behaviour rather than a repair. The reader
goes through the accessor that knows the file's shape, so a file written by an
older version answers exactly as a current one does. And a row with no number now
says which of three things is the matter — nothing carries this series, the
series is empty, or more than one device measures it and the goal has to say
whose. The last of those is refused rather than averaged, and a goal may name the
device (`wear:garmin:RestingHeartRate`) to answer it.
**A number the watch already had was reported as missing, or as three weeks
old.** Some indicators are kept twice: what a person types in, and what a device
records every day. Only the first was read. Steps stood at a single figure
entered in July and were called «below target», while the device series had the
month just gone above it; sleep showed nothing at all beside seventy-five months
of nightly data; a resting heart rate from December stood as the current one in
September. The two are joined now: the newest measurement is the one shown, each
card says which store it came from and on what date, and the other store is
printed beside it rather than instead of it. A tie goes to the hand-entered
reading — a monthly mean and a measurement taken on a day are not the same
statement. Neither file is written to.
The pairing is declared once, in the shipped wearable reference, and only where
the two are the same quantity. Where they are merely similar it is left out and
the row goes on saying it has nothing behind it: intensity minutes are not
«minutes of activity», and a pairing that is nearly true prints a number nobody
can act on.
**The goal board was dated by one of the files behind it.** The heading read
«data as of» the timestamp of the wearables file, while half the rows come from
the laboratory — so a table carrying a draw from the 3rd was headed with the 23rd
of the month before. Every row carries its own date now, and the heading carries
the newest of them.
**A stored result was deciding what language the product speaks.** Polygenic
risks and longevity markers printed in Russian while the interface was English.
Neither catalogue is missing a translation — both carry every name in both
languages. The names were coming from `prs_results.json` and
`longevity_findings.json`, which are stored RESULTS: each label is a copy of the
catalogue made on the day of the run, in whatever language that run was speaking.
The catalogue now decides what a thing is called and the file decides what the
number is; a trait or a marker the catalogue does not carry keeps the name it was
stored with, because a percentile with no name is worse than a name in one
language.
**The longevity layer showed genotypes and explained none of them.** Each row
printed a gene, an rsID, a genotype — and an explanation line that was always
empty, because the page asked for a field these rows do not carry. Everything
that says what a marker MEANS was in the catalogue, in both languages, unread: what
the allele is, what a second copy does, what it argues for, what population the
direction holds in, and the papers behind it. Rows now carry all of it, sorted so
that what was found comes first and what was checked-and-quiet folds away. The
verdict and the strength of the sources are written out as sentences rather than
as the internal words they are — and a word the catalogue does not recognise is
never turned into a message key, which is how «⟦longevity.verdict.…⟧» used to
reach a reader.
**APOE says what APOE is.** The card led with «APOE — status» over two rsID
numbers, which tells a reader nothing about the gene or about their own
combination. It now opens with what the gene is and what this particular pair
means, says plainly that it is a factor and not a diagnosis, and folds the two
positions it was computed from underneath.
**A file carved out of a genome was counted as a second genome, and the whole
genomic layer went dark behind it.** Files called from the same reads at a chosen
list of positions — the loci of the catalogue, the scoring sites of the polygenic
models — sit beside the main file by design. They were recognised by NAME, from a
list of four; an output written under a fifth name became a second candidate, the
choice became ambiguous, and a refusal to guess between two files means no locus is
read at all. Nothing failed and nothing was logged. Every genomic answer said «not
read» — including a card that named two positions and said they had not been read
while the reads sat in the file beside it.
What a file is called no longer decides anything. bcftools records its command in
the header, and a pileup restricted to a list of sites, or an annotation pass over
another file's rows, is an extraction rather than the genome it came from; files
this project writes stamp themselves besides. The rule may narrow the set of
candidates and may never empty it — a folder holding nothing but extractions still
holds the person's reads — and whatever it sets aside is named with its reason
rather than dropped in silence.
**A card no longer blames the positions when the genome is not being read.** «The
PCSK9 positions have not been read» is a statement about two rows of a file that is
open. With no genome connected there is no such file, and the sentence sent a
reader to look at their sequencing when the answer was in the folder beside it.
### What is retracted
No stored value changes. Answers that said «not read» for the reason above will
now say what the reads say — which is not a retraction of a claim but the end of
a refusal.
One claim is retracted, and it was a claim about a person rather than a silence:
an indicator whose hand-entered point was older than the device series was judged
against its target on the old point. Where that judgement was «below target» and
the device disagrees, the flag changes with this version. Nothing was stored, so
nothing has to be undone — but a printed page or an exported summary made before
this version may carry the old flag.
### What needs recomputing
Nothing has to be recomputed and nothing has to be re-imported. A profile whose
genome folder holds one file behaves exactly as before; one that holds several is
asked, once, which file is the genome, and everything that was silent answers
from it. The wearable series were on disk the whole time — they are read now, not
rebuilt — so the goal charts fill in on the first run with no export and no
ingest.
## v0.4.9 — 08.09.2026
### What you can do now
**The Overview draws the body beside the radar.** The same systems, twice:
the radar as before, and a figure on which every system with a place on a body is
lit by its score. Around each mark a ring shows how much of that system was
actually measured, which is the number the radar has never been able to show. A liver scoring 100 out of 100 on one marker of three is a full
point at the edge of the radar and a ring closed a third of the way on the body.
Picking a system on either picture marks it on the other.
**The endocrine system is four systems, and each is scored on the panel a
laboratory actually issues.** One domain called «Hormones», averaged from
testosterone, IGF-1 and TSH, is gone. In its place the radar carries the thyroid
axis (TSH, free T4, free T3, anti-TPO), the adrenals (cortisol, DHEA-S), the
gonads (testosterone, DHT, estradiol) and the growth axis (IGF-1, growth
hormone). The ring beside each now says how much of that panel exists, instead of
how much of a mixture of three markers nobody orders together; a system with
nothing measured is not drawn at all rather than averaged into the picture.
**A hormone is marked at the gland that makes it**, not at the organ it is read
for: TSH and growth hormone at the pituitary that secretes them, free T4, free T3
and anti-TPO at the thyroid, cortisol and DHEA-S at the adrenals, IGF-1 at the
liver that writes it, testosterone at the gonads. Each mark carries the score of
what is made there — the average of a whole axis would print the same number in
two places and mean it in neither. Two hormones answer instead that there is no
one place to mark: DHT is converted in the tissues that respond to it, and
estradiol comes from the ovary in one person and from adipose tissue in another.
An antibody is the one named exception to the rule — anti-TPO is made by
lymphocytes, which are everywhere and mean nothing as a place, so it is marked at
the gland it is raised against. A reason is recorded beside every placement, and
beside every refusal to place.
**The pancreas is on the map.** It is a system of its own now — amylase, its
pancreatic fraction, lipase and C-peptide, the acinar cell and the beta cell
together — and insulin, which stays in the carbohydrate panel because HOMA-IR is
computed from it, is marked at the gland that secretes it. Nothing else about
carbohydrate metabolism moves: glucose, HbA1c and the index itself say plainly
that they are made nowhere in particular.
**A reference interval that belongs to one sex is no longer lent to the other.**
Six markers carry both corridors and were already handled. Every other marker
carries one, transcribed from the forms of one person — and it was borrowed by
anybody whose own laboratory printed no range. HDL's floor of 1.0 mmol/L is a
man's; so are AST's ceiling of 40 U/L, GGT's of 60, and the intervals for DHEA-S,
DHT and estradiol. Borrowed for a woman, none of them failed: each produced a
verdict, and the wrong one. Every marker a body system is scored on now declares
whether its corridor depends on sex — silence was what made the class invisible,
so silence now fails the build — and a corridor is withheld, with the reason
printed, rather than lent across that boundary. A person's own form is unaffected:
it is always preferred, and this only ever governed what fills a hole.
**A number with no reference interval beside it no longer costs its system
points.** Such a marker scored 55 out of 100 — the score for «a deviation whose
size cannot be assessed» — when there is no deviation, because there is nothing to
deviate from; and it was counted among the system's deviations, while the marker
list on the same screen said, correctly, that it was not one. It is now left out
of the score and out of that count, and still counted as measured: a system whose
only measured markers carry no corridor reports no score rather than a mediocre
one.
The five systems with no place on a body say so rather than being drawn on an
organ they do not belong to; which is which is recorded with a reason beside each
entry, and a system added to the radar without one now fails the build. The figure
is drawn male or female from the profile; where the profile does not say, it is
not drawn at all and the radar answers alone.
**Windows is a supported platform.** The package, the command line, the local
web application and the assistant skill run there, and a cell of the test matrix
now says so on every commit rather than leaving it to hope. The promise and the
check are tied together: a platform named in the package metadata with no runner
behind it, or a runner with no promise in front of it, now fails the suite.
Two things stay Unix-only and both are optional. The `crossread` wrapper is a
shell script — on Windows the installed `scholion` command is the same core, so
nothing is lost but the second name. Building a genome from raw reads drives
external alignment and coverage tools through shell scripts; every such tool is
looked for before it is used, so where one is missing the answer names it
instead of failing. The data directory on Windows is `%USERPROFILE%\.scholion`,
and `SCHOLION_REPO_DIR` overrides it as everywhere else.
**The suite can be started without a shell.** Until now the only way to run it
was a bash script, including the run the release procedure requires INSIDE the
unpacked package. There is now a second entry point written in Python that does
the same run, so a person who received the package can check it on a machine
that has no shell at all. The build carries it, and a check makes sure of that:
every way of starting the suite that the project's own automation uses must be
present in the package a recipient receives, or the build fails.
**Any gene can be asked about, not only one in the curated catalogue.** `scholion
genome --gene CASR` used to answer "Gene CASR is not in the coordinate reference"
— true about `loci.json`, which is a book of pharmacogenetic loci, and easily read
as a statement about the genome, whose reads were there the whole time. The gene
name is now resolved to coordinates from a local Ensembl annotation (or from
Ensembl live, cached afterwards), the interval is cut out of the personal VCF,
coding variants are separated from the rest by the coding exons of the canonical
transcript, and what each one does to the protein is computed against the same
reference the genome was called against — no web service is asked, and no
coordinate leaves the machine.
**A gene report prints coverage before it prints findings.** Every reassuring
thing such a report can say has the form "no such variant", and that sentence is
empty until the region is known to have been read. Read depth is computed
directly from the alignment, without samtools or pysam, and it reproduces the
project's own native callability run exactly — mean and every threshold, to the
last base, on four genes across three chromosomes. Where a piece is missing the
report names it and what would supply it: coverage without an alignment prints as
"not measured — because", and "changing the protein: 0" is replaced by "not
computed" wherever the reference was absent, because a zero and an uncomputed
number look identical on the page and mean opposite things. The two blind spots
of short reads — large exon-level deletions, and deep intronic or regulatory
variants — are printed on every answer, not only on the reassuring ones.
**Three analytes the dictionary did not know are now recognised.** A urine
albumin-to-creatinine ratio, a urine microalbumin and a **total** T3 went through
`ingest-labs` without a word: an unrecognised line is skipped, and a skipped line is
indistinguishable from a line that was never on the form. All three sit on real forms
of an ordinary laboratory, and the ratio is one of the two axes of KDIGO staging — a
value whose absence changes what may be said about the kidneys. Total T3 gets its own
table rather than joining free T3: the two are reported in different units (ng/dL
against pg/mL) and the same number under the wrong one is out by an order of
magnitude. The unit table learned `mg/g`, so the ratio prints with a unit rather than
a code.
**A polygenic percentile is printed with two quantities beside it: how stable
the number is, and how informative the model is.** A bare percentile looked
equally convincing for coronary artery disease and for intelligence, and it is
not: for the second, the choice of reference population moves the number by
some fifty points while the model's whole range separates the outcome by a
few. The two are different properties and are shown as such, under every
percentile in the `prs` report and in its JSON. Stability belongs to the
measurement — the spread of the percentile across the five reference
populations, its spread across the models scored for the trait, and the share
of the model your file actually covers. Informativeness belongs to the model —
its discrimination (AUROC), and what the score's range from the 10th to the
90th percentile does to the outcome, read per standard deviation as the
catalogue reports it. A figure that is not on the machine is named as «not
recorded» rather than left out, because a line with one number and a line
with three look alike only when the missing two are silent. The two are not
folded into one «signal to method» ratio: the effect size cancels out of such
a ratio, and what remains is the population spread written in other letters.
### What is fixed
**A corridor transcribed at one age was lent at every age, and most corridors
did not say whose they were.** The rule that keeps one sex's interval from the
other covered only the markers the body systems score; the other three hundred
and forty held a corridor and were silent about it, so a man's prolactin or
LH interval could still be borrowed for a woman whose form printed no range.
And age was not modelled at all: IGF-1 and DHEA-S depend on it more than on
sex, every laboratory bands them, and the dictionary held one corridor each.
Every corridor now declares both — whose it is, and whether age governs it —
with three states for age: independent, banded with the band on record
unknown (lent to nobody), or a band in years (lent inside it; an unrecorded
age is not lent a band). A corridor that could not be checked against a form
or a standard interval says so in a word — `unreviewed` — and is lent to
nobody until it is; nine are marked so, the estrogen-metabolite panel among
them, and that number may only shrink. PSA is a different case again: not a
man's interval but a test that exists for the male sex only, and for a woman's
profile the value is shown with that sentence rather than with a borrowed or
withheld corridor. The reason is printed beside the value in each case, and it
names what would supply the corridor: the range on the person's own form, or
the birth year in the profile.
**A value was judged by a range its own form did not print.** The rule that
the range on the person's own form wins held only at the level of the marker,
which keeps the first range it met and is not rewritten by later forms; no
stored value carried the range printed beside it. A September draw was then
judged by a corridor recorded in December, or by one entered by hand. An ionised
calcium the form called a hair under its 1.10–1.35 read as deeply low against
a 1.16–1.32 recorded months before; a DHT five per cent under one corridor was
twenty-three per cent under the other. The range printed on the form now
travels with the value and the verdict stands on it; where a value has none,
the marker's recorded range answers and the report says so; and a series whose
corridor changed between draws says that its values compare and its flags do
not.
**A bound printed instead of a number lost its sign.** A laboratory that
cannot quantify a value prints the limit — «< 0.09 nmol/L» — and the ordinary
form reader stored the number without the sign, as if 0.09 had been measured.
The engine has carried a censoring mark for such values all along, and two
special readers (flora, titres) supplied it; the common path did not, and a
series of «below the limit» results read as a level that later rose. The sign
is now read from the text immediately before the value — `<`, `>`, `≤`, `≥`
and their spelled-out forms — so a bound in a reference column further along
the row cannot be mistaken for it.
**Calcium measured by two methods was filed as one series.** Elemental
analysis (ICP) prints calcium in mg/L; a biochemistry panel prints total
calcium in mmol/L; one marker caught both and converted the second into the
first by molar mass. The two methods disagree beyond rounding — thirteen per
cent on the same person two months apart — and a series that holds both
presents a change of method as a trend. Total calcium is now a marker of its
own, the elemental one no longer reads a biochemistry form, and the rule is
written where the next mineral will meet it: a series belongs to a method, not
to a substance — a unit conversion is legitimate within a method and not
across methods. Magnesium and the other minerals have not been checked yet.
**A form that printed «HOMA-IR» in the Cyrillic alphabet was not read.** The
dictionary knew the index by its Latin spelling only; the file was refused
with an honest reason and the value had to be entered by hand. Both alphabets
are recognised now, and «insulin resistance index» as well.
**A report could not be redirected to a file.** `scholion labs > labs.txt`, and
every other command whose output was piped or saved rather than read on screen,
ended in a crash partway through — thirteen of sixteen commands measured. The
reports are written with arrows, dashes and guillemets, and the encoding a
redirected stream inherits from the system cannot always carry them. Output is
now written as UTF-8 whatever the system would have chosen, so a saved report is
the report. A character that still cannot be written appears as its own escape
rather than as a question mark, so what was lost is visible.
**Files were read in whatever encoding the machine assumed.** A genotype table,
a cached answer or an export written as UTF-8 and read back through a national
code page does not fail — it decodes, wrongly, and where the read also asked for
replacement characters the wrongness was silent by construction. Every text read
and write in the package now states its encoding, and a check over the source
refuses a new one that does not. Twenty-nine places were corrected; six of them
were never reached by any test, which is why the check reads the source rather
than watching a run.
**Two programs writing the profile at once could lose a change.** Where the
system offers no lock between processes — Windows has none — the local web
application and a command line each read a file, changed one field and wrote it
back; whoever finished last erased the other, with no error anywhere. A lock the
program takes itself now covers that case, and where it is already held the
second writer says who holds it and stops rather than writing over them. A lock
left behind by a run that died is taken over after a minute.
**The update button reached for a shell that need not exist.** On a machine
without one it now says so in a sentence, instead of showing the failure of a
program it tried to start. The search path it builds is also joined the way the
platform joins it, rather than always with a colon.
**The monthly reanalysis stopped at its first step.** The ClinVar annotation
(`annotate_clinvar.sh`) died with «GEN: unbound variable» on the first scheduled
run: the branch that looks for a reference FASTA named a variable that belongs
to the orchestrator calling it, not to the script itself, and `set -u` stopped
it at the first of three such places. All three now use the script's own
`GENOME_DIR`. The annotation has not yet been re-run against the fresh ClinVar
release; until it is, findings stand on the release recorded in the profile.
**A profile that spelled its sex «f» or «m» could be measured against the wrong
reference row.** Several spellings of sex are accepted when a profile is
written — «f», «female», «woman» and their male counterparts — but the reader
that picks the applicable row of a multi-row reference interval compared the
raw spelling with «male»/«female», so for any other spelling the sex half of
that choice was silently off: a men-only row could fit a woman, a women-only
row a man. The reader now recognises sex the way everything else does. A
profile created by `scholion init` was never affected — it can only write the
two spellings; the demonstration profile and imported or hand-edited profiles
were.
**The version shown could be another installation's.** With any `scholion`
distribution installed on the machine — an older one from the registry, kept
for comparison — a copy run from its source tree reported the installed
number rather than its own, in the server's header and in `--version`. The tree
now answers for itself; an installed copy still answers from its metadata.
**The polygenic-score layer could stop starting on a machine that had run it
the week before.** The scoring sidecar is fetched into an isolated environment
on first use, and its own dependency declaration left one library unbounded; a
newer major version of that library reached the index in August, and any fresh
cache took it — the sidecar then died at start-up, before the first request,
and `prs`, its page in the web application and the monthly reanalysis all
reported a server that «exited without an answer». The resolution is now pinned
below that major version wherever the sidecar is launched, from the application
and from the setup script alike; a constraint already set in the environment
by whoever runs it is respected rather than overruled. The message for a server that
exits without answering now carries its exit code and names this cause and the
pin, so a recurrence reads as «the pin was not applied» rather than as silence.
**Every polygenic-score computation went to the server twice.** Two optional
settings of the report — a wider pool of candidate models, and the models of
child traits — are not accepted by the pinned sidecar; they were sent with every
trait, refused with every trait, and each trait was computed again without them,
so a full panel cost double for a setting that was never in force. A refusal is
now remembered for the rest of the run and the panel pays it once. The two
settings are honoured only by a newer sidecar than the pinned one, and the help
says so.
**Three models were computed for a trait and one was shown.** The client asked
the server to score several models per trait and then to return only its
favourite, so the spread between them — for a trait whose score explains five
per cent of the variance, half of the answer to «how much of a number is
this» — never reached the page. Every scored model now comes back, the spread
is stored with the panel and printed as part of the percentile's stability.
And the count of candidate models left unscored — eighty-five of eighty-eight
for coronary artery disease — travelled without its rule; the rule is the
report's own `--models` limit, and the count now says so wherever it appears.
**A panel entered by hand and then re-imported from its form stood twice in
every series.** The form prints the draw hour, so the re-import arrived with a
finer date than the day entered by hand; the two did not match as strings, and
the second point joined the series beside the first — identical values, one
draw, nothing reported. Trends were then computed against a «previous point»
that was the same blood. A point now stands in for every point of the same day
whatever precision either carries, the more precise date is the one kept
whichever order the two arrived in, and what the earlier entry recorded about
the draw — its context, its source — travels to the replacement instead of
being erased on every re-import. The importer names each replacement. The one
case that cannot be decided — a bare day arriving against two timed draws of
that day — is still reported and left to the person.
**One file the reader could not handle stopped `ingest-labs` for the whole
folder.** A traceback, every form after it unread, and no indication of which
file was at fault. Each file is now read on its own: a file that raises is
listed among the files nothing was taken from, with the exception's type and
text, the rest of the folder is processed, and the command exits with a
non-zero status so that a partial run is not mistaken for a clean one. The
failed file is tried again on the next run rather than remembered as done.
**The list of files already read was shared by every profile on the
machine.** `ingest-labs` and `ingest-studies` remembered what they had read in
the application-wide cache rather than beside the profile, so anyone working
with more than one profile — a family member's, a temporary one — shared a
single list, and a form already read for one profile could be silently skipped
for another. The list now lives in the profile directory, one per profile
(`ingest_labs_manifest.json`, `ingest_studies_manifest.json`); on the first run
after upgrading the old list is carried over from the cache and the run says so
once, so no form is read as new because of the move. Both loaders report the
carry-over as a `manifest_moved` field in `--json`.
**The reach baseline could not be accepted for a commit that added a module.**
The suite fails when a module of the package has no accepted reach, and its
message says to run `--accept`; `--accept` in turn refused to record a suite
that had failed. Adding any module therefore closed a circle the tool could not
be talked out of, and the only exit was to seed the new module in
`test_reach_baseline.json` by hand. `--accept` now enters missing modules at
0.0 before the suite is measured, drops entries whose file is gone, says which
it did, and records the measured numbers over the seeds. When the suite fails
anyway the file is put back exactly as it was. `--strict` is unchanged and
still fails on a module nobody has reviewed.
### A series break
`knowledge/lab_markers.json` now records whose reference interval each scored
marker holds, and a corridor that belongs to one sex is no longer lent to
another. On unchanged input that changes the verdict in one place: a profile
whose sex differs from the corridor's, for a marker whose own laboratory form
printed no range, used to receive a flag and now receives the value together with
the reason no corridor is shown. Thirty-six markers can be affected — the six the
body systems score (HDL, AST, GGT, DHEA-S, DHT, estradiol) and thirty more
whose adult interval is sex-specific: the red cell count and ESR, iron and
transferrin saturation, the gonadal and pituitary hormones, calcitonin,
osteocalcin, leptin, PSA, urine creatinine and the estrogen metabolites — and
only where the range was borrowed: a person's own form has always been
preferred, and this governs nothing but the hole it filled. The remedy is the
form itself, or a range recorded by hand.
Age is the same line, one axis over. Four markers whose interval every
laboratory bands by age — IGF-1, DHEA-S, inhibin B and total PSA — held one corridor
each, transcribed at one age, and lent it to everybody. The band on record is
not known, so the corridor is now lent to nobody and the reason is printed; a
value that used to receive a verdict against it receives the value alone. The
same remedy applies. Every corridor in the dictionary now states both — whose
it is, and whether age governs it — and a marker that does not fails the suite,
because absence was how the question used to be spelled.
A verdict now stands on the range printed beside the value rather than on the
range first recorded for the marker. For a value whose own form printed a
different range from the one on record, the flag can change either way; the
value does not. Which ruler each flag stands on is printed, so the two can be
told apart on the page.
The score of a body system also moves where a measured marker had no corridor:
such a marker used to take 45 points off its system and no longer takes any. The
overall health index is a mean over systems, so it moves with them. Values from
either side of this line belong on one chart only with a note.
### What is retracted
No stored value changes and no conclusion is revisited. One correction above —
the spelling of sex — is to how a reference row is chosen for a profile spelled
other than «male»/«female»; what that asks of such a profile is under the next
heading. The rest are to how reports are written and how files are read.
### What needs recomputing
**Run `scholion ingest-labs --force <folder of laboratory forms>` — if forms were ingested by an earlier version.**
The folder is read again, and for each of these what an earlier version stored
is corrected: reference intervals picked without the sex filter, for a profile
whose sex is spelled other than «male»/«female»; urine albumin-to-creatinine
ratio, urine microalbumin and total T3 lines that were left out; a hand-entered
day beside the same draw's timed re-import, collapsed into one point that keeps
the timed date, with every collapse named; the range each form printed, which
replaces the marker's recorded range a value was judged by until then; and the
sign of a bound («< 0.09»). Points entered by hand before the form was read keep
whatever was typed.
**By hand — if a biochemistry total calcium was ingested by an earlier version.**
It sits in the elemental series converted to mg/L. Reading the folder again files
it under total calcium, but the converted point is not removed from the elemental
series; remove it, or the report shows a method change as a trend.
**Run `python3 -m scholion.prs report` — if a polygenic panel was computed by an earlier version.**
Such a panel carries no spread across models and no AUROC, and the report prints
«not recorded» in their place. Recompute it, then rebuild the panel with the
panel-build step of the genome guide; the spread across reference populations
comes from the ancestry-sensitivity step of the same guide, run once per panel.
**By hand — if a report saved from an earlier version stops short.**
It may be truncated at its first unwritable character; running the same command
again produces the whole report.
## v0.4.8 — 31.08.2026
### What you can do now
**`ingest-studies` names every file it took nothing from.** The report used to be
four counts, and the number of files seen was never reconciled against them: a
file that was read and then dropped moved no counter at all. Each such file is
now listed with the reason it produced nothing — the PDF gave up no text, it is a
laboratory form that the other loader owns, it reads like a study but no
conclusion could be lifted out of it, or this loader cannot place it at all. The
counts and the named files add up to the files that were looked at.
**A PDF holding several studies is reported with what is inside it.** A discharge
summary — several examinations, and often a laboratory panel, in one file — is
listed section by section with each section's own date, together with the plain
statement that this loader cannot split such a file yet and that nothing from it
reached the profile. Until now such a file was declared a laboratory form and
handed to the laboratory loader, which dropped it for a reason of its own, and
neither report held a line about it.
**A decision you made about a wearable series survives the next import.** A
rebuild is written from the export every time, so an edit made inside
`wearable_trends.json` was lost at the next run — a weight point removed by hand
as physically impossible came back as soon as a fresh export was read. Put the
decision in `profile/wearable_corrections.local.json` instead: `remove` or
`replace` a month of one metric of one device, with a reason. The import applies
them over the rebuilt series and says which it applied, which it refused and why,
and which no longer match anything — a reason is required, and a correction
without one is refused rather than applied. `LOADING-DATA.md` describes the file.
**A monthly point from a wearable now says what it stands on, and a movement too
small to see is no longer given a direction.** Each month carries the number of
days that held a reading, the days the month had, the median beside the mean and
the spread. From those the lifestyle answer works out the smallest difference the
data can tell from its own sampling, and when a shift is smaller than that it says
so instead of naming a direction — for a monthly sleep series measured on a
typical month that threshold is on the order of several minutes, and movements
under it were previously reported as improvement or decline. A month measured on
part of itself — nineteen nights of thirty-one — says that too. A series written
by an earlier version carries no sample description and behaves exactly as before:
nothing is invented for it.
**A laboratory arrow says whether the change can be told from the marker's own
scatter.** «↑ 44 % since the previous measurement» is arithmetic on two numbers
and it stays; what follows it now is whether this marker's own history has ever
shown itself able to tell a change that size from its own wobble. The threshold
is measured from that history — no outside table is required and no coefficient
is assumed — and it is reported with it, so it can be argued with. A rule that
suggests a test because a marker is trending no longer fires on a movement the
series cannot distinguish: a suggested test costs a real draw of blood. Where
the history is too short to support the statement, none is made.
**A genotype read from a VCF says how well the reads actually supported it.**
Depth said how many reads there were; nothing said how they were divided. A
heterozygote whose reads split 15/85 — a mosaic, a duplicated region, an
artefact — was presented in the same words as one that split evenly. The allele
fraction and the caller's own quality score are now read, and everything worth
confirming about a call arrives as one list with the measurement that raised each
entry, instead of three separate flags a reader had to know to look for. These
are quality-control heuristics and they say «have this confirmed by another
method», never «this is wrong».
**A gene a variant file cannot answer now says so, instead of showing a tag
SNP.** CYP2D6 decides codeine, tramadol, tamoxifen and the tricyclics, and it is
settled by the full diplotype — copy number and phase — not by any single
position. Asked about codeine, the answer used to print the gene, the word
«important», a bare genotype and the promise that a full genome would bring the
rest, which for this gene is not true. It now states that a diplotype is what
decides it, shows the tag SNPs under a name that says what they are, and names
the two things that actually close the gap: a star-allele call over your reads,
or a laboratory report that states the diplotype — the only route open to
somebody who has no alignment file. A diplotype already on file is used as
before, and the sentence beside it now follows where it came from instead of
asserting the caller's name over both cases.
**The genes a «nothing found» cannot rest on can be handed to a laboratory.**
The coverage table knew which genes were under-read and could give the list to
nobody: a percentage names a gene, and re-reading something needs coordinates.
The intervals the measurement was made over are now recorded and the weak list
exports as a BED, worst gene first, each interval carrying its own percentage.
The track line states that these are gene loci with a margin rather than coding
sequence — a small dropout inside an exon barely moves a locus-wide percentage,
so the file is a worklist of genes to look at again, not a map of the bases that
were missed. A coverage table written before the coordinates existed is refused
with the run that would fill them in: a gene name is not an interval and none is
invented from it.
### What is fixed
**A conclusion written in mixed case produced an empty record, and an empty
record was dropped without a word.** The recogniser accepts the heading whatever
its case; the extractor beneath it demanded the word in capital letters and
required the text to begin on the following line. A document that writes the
heading in ordinary case, with the text after a colon on the same line, was
therefore accepted as a study and then yielded nothing at all. Both shapes are
read now, and the printed disclaimer that contains the same word is not mistaken
for the finding.
**A laboratory point is dated in one of three shapes, and anything else is
refused.** A month, a day, or a day with the clock time of the draw — the last
one because two draws can fall on one day and a key no finer than the day loses
the second. Nothing checked the string before: a value that was not a date at all
would have become a key of the series and been sorted and charted beside real
dates. And when the same period is already present at another resolution — a
month point and a dated point of that month, one measurement standing twice — the
import now says so rather than quietly holding both.
**A doubled measurement was found and then not mentioned, for anyone whose
results arrive as a table.** The importer notices when one measurement ends up in
a series twice at two resolutions — a month point and a dated point of that
month. It said so for results read out of a PDF and stayed silent for results
read out of a CSV or TSV export, because the two kinds of file reach the profile
by different routes and only one of them carried the report. The doubling was
detected in both cases and shown in one. Both now say it.
### What needs recomputing
**Run `scholion ingest-studies --force <folder of documents>` — once, if studies were ingested by an earlier version.**
Studies that were dropped in silence may now be read, and whatever is still not
taken is named in the report.
**By hand — if you want the BED of under-read genes.**
Measure coverage once more: the measurement now records the intervals its
percentages were taken over, and a table produced before it did does not carry
them.
**Run `scholion ingest-garmin` — once, if Garmin months were imported by an earlier version.**
Existing months gain the description of their sample; the values themselves do
not change, so charts and comparisons are unaffected. Until an import has run, a
series simply has no sample description and no statement about what is
distinguishable is made for it.
## v0.4.7 — 27.08.2026
### What you can do now
**The Ouroboros Hub skill now says where your files go, on a page of its own.**
Installed there, Scholion arrives by a click into a machine whose paths you have
never seen and cannot list. Until now it registered thirty tools and nothing
else: no data directory was created, and the first thing the skill said was a
tidy report — `markers: 0`, `genome: not connected` — about a person it had
never been given anything about. A statement of absence, phrased as a finding.
Enabling the skill now adds a **Scholion** tab to the Widgets page, and that tab
is the first thing to read:
- it names the data directory this installation actually uses, and the exact
folders for laboratory forms and for the genome;
- a button lays that directory out — empty templates, plus a README in every
folder saying what belongs in it. Pressing it a second time writes nothing,
and it never touches a file that already exists;
- if your files already live in a folder of their own, a field points at that
folder instead of copying them.
The directory the skill creates is one the host keeps, so it survives restarts
and is not scattered inside a container. To put it somewhere else, set
`SCHOLION_REPO_DIR` (the whole layout) or `SCHOLION_PROFILE_DIR` (the profile
alone) in the host environment before enabling — either is respected, and
nothing is moved.
Nothing changed for the command line or the local web application: the same
layout is what `scholion init` has always written, and the tab creates it
through the same command.
### What is fixed
**A freshly created, empty directory was described as a connected genome.** The
introduction the skill prints was reading the genome section of the report as
«present» rather than reading its ready flag, so a person who had just pressed
the button — with no VCF anywhere — was told the genome was connected and then
handed a list of loci «still unread». Both halves were wrong and the second made
the first look substantiated. It now says `not connected` until a VCF is
actually there, which is what `scholion genome-status` said all along.
**A profile that cannot be read is no longer reported as an empty one.** If a
file in the profile is malformed, the tab now says so, with the reason, instead
of showing zeroes that look like a person with no history.
### What is retracted
Nothing. No stored value changes, and no conclusion drawn from a previous
version needs revisiting: the corrections above are to what the skill said about
its own state, never to a reading of anybody's data.
### What needs recomputing
Nothing.
## v0.4.6 — 25.08.2026
### What you can do now
**A tool that installs skills from a repository can now find this one.**
`npx skills add` and its kind read a repository rather than a package: the root
if it holds an entry, then `skills/`, then the agent folders — the documented
shape being `skills/<name>/SKILL.md`. None of those existed here, so the entry
was reachable only by such a tool's fallback recursive search, at a path whose
folder is called `skill` while the file inside calls itself `scholion` — and the
format requires those two to agree.
The published repository now carries `skills/scholion/`, and it holds the entry
and nothing else. That is the licensing decision rather than economy: what is
published as a skill is the entry; the long instruction and the canon of rules
stay with the package they are printed from, under their own licence, and a
folder carrying both would put one licence over two bodies of text.
Unlike the standalone skill folder in the downloadable archive, this one is not
excluded from the repository — a tool fetches it from there, and a folder kept
out of version control does not exist for the purpose it was made for.
**An assistant that reads skills from a folder can now be given this one, in one
line.** Several hosts read the same path, with no registry, no account and
nobody's moderation in between — and until now nothing in this project mentioned
it:
```bash
mkdir -p ~/.agents/skills/scholion
cp "$(scholion skill --path)" ~/.agents/skills/scholion/SKILL.md
```
That single file is the whole installation, which is what makes it worth doing
and also what it had to be repaired for. **The entry did not name the tool
server.** A host with a plugin mechanism finds `scholion mcp` through its own
means; a host that reads only this file had no way to learn the door existed —
so the door built for exactly those runtimes was invisible to them. It names the
tool server and the in-process module now, and says that neither writes to a
profile.
**And it pointed at reference texts that a one-file install does not have.** The
full instruction and the canon of safety rules sit beside the entry in the
downloadable bundle and nowhere else; the entry named them by path regardless, so
a model following the pointer would report a missing file rather than ask for
what it needed. Each is now named twice — the path, for the bundle, and the
command that prints it out of the installed package, for every other way in.
`scholion capabilities --json` lists this door beside the others, derived from
the build: the size of the entry and whether it names the tool server are read
off the file rather than asserted about it. `scholion doc connecting-an-agent`
describes it in words, and the heading there has stopped counting the doors —
it said «four» through the arrival of a fifth and a sixth.
**The checks now run on the oldest Python the package promises, before a release
rather than after one.** `pyproject.toml` says this runs on Python 3.10 and
later. That sentence is a promise to everybody who installs it, and until now
nothing checked it before a release: the matrix that runs every promised version
lives with the published repository, so it answers about a version that is
already out.
It answered twice in two days, both times too late — once with a release build
that failed and never reached the registry, once with a red matrix on a version
that had. Both were the same shape: a repair verified on one interpreter and
promised about four.
`./run_tests.sh` now runs the whole suite a second time under the oldest promised
version, taking that version from the promise itself rather than from a number
written into the script — `scholion doc contributing` describes how to run the
checks that come with the package. Where `uv` is available it fetches the interpreter and
caches it; where it is not, the run says the check could not be made instead of
passing over it in silence. `SCHOLION_SKIP_OLDEST=1` skips it while editing.
Three places name that floor — the promise, the versions the matrix runs, and
this step — and a test now compares them, so a version can no longer be promised
and never run, or run and never promised.
## v0.4.5 — 24.08.2026
<!-- This entry is open. While 0.4.5 is unpublished, further work is added here
rather than under a new number. Refresh the date in the heading before
publishing, and delete this note. -->
### What was wrong
**The README told you the plugin adds fourteen tools. It adds twenty-nine, and
there are not four doors but six.** Neither sentence was wrong when it was
written; both stopped being true and nothing was obliged to notice. They are
corrected, and the numbers are gone rather than updated: a count kept by hand
beside a count the build derives will go stale again, so the README no longer
writes one and a check refuses a new one.
The installation table for a skill folder was rewritten against each product's
own documentation rather than from memory. `~/.agents/skills/` is the shared
path and two runtimes read it as they are; the others keep their own folder and
take the same single file. The table carries the date it was checked, because
paths move and that is the kind of claim that goes stale quietly.
The published format's own limits are now a test: the name a valid slug matching
its directory, the description within its ceiling, the body within the
recommended length, and no frontmatter field the format does not define. They are
somebody else's rules, which is exactly why they are worth checking — a file that
breaks one is refused with a message about YAML, and the person meets that
instead of this product.
**What the data cannot answer reached every way in except the one most people
use.** `scholion limits` says what cannot be said from a profile and what would
close it — and the page had never asked for it. Not a broken renderer: no screen
called that route at all, so the whole layer existed for the command line and for
an assistant and for nobody sitting in front of the interface.
The Profile tab now opens with what the profile is still missing and what each
absence costs — a reference interval withheld rather than guessed, the age-banded
rows of a form that cannot be read — with the fields to fill them in directly
below. And the caveat about which reference panel a percentile is a position
inside is printed beside the percentiles, where the number is met.
A check now holds the general rule: every route the server answers is asked for
by the page, or is named with the reason it is not. Two writes are named — one
superseded, and one an acknowledged gap: conclusions from a doctor can still only
be loaded from the command line.
**A percentile said which population it was a position in, and the answer could
be wrong.** The reference panel a polygenic score is computed against decides
what the percentile means: against another population it is not your position.
The report carried a panel and, beside it, a claim that the panel had been
settled — and those two came from different places. The claim asked the profile
whether a panel was known; the number had been computed against whatever the
scoring run was given, which fell back to Europe in a function signature.
While a panel could only be typed in by hand the two rarely disagreed. Once it
began to be determined from the genome, they came apart for everybody who had
one: the screen said the panel was settled and showed percentiles computed
against a different one. No error and no gap — an ordinary number with a wrong
sentence attached.
Three facts are reported now where one was: the panel the stored numbers used,
whether it was chosen or fallen back on, and which panel applies today. Where
they disagree the report says so beside the number and names both, rather than
leaving it in a field. A result computed before any of this was recorded cannot
say which panel was chosen, and that reads as «cannot say» rather than as «yes».
`scholion prs` takes the panel from the genome unless told otherwise, and a run
that had nothing to go on says it used a default.
**Determining that panel is a step of preparing a genome now, and it can be
asked what it does before it does it.** The tool that answers it existed and was
reachable from nowhere — no command, no mention in the guide. Worse, it took no
arguments and checked its inputs while being imported, so any invocation at all
ran the whole job: about three hundred requests to a public database over
somebody's real genome, from what was meant to be a question. It has an entry
point now — `--help` explains, `--dry-run` names what it would read and write and
fetches nothing, and a missing input is refused by name with where it comes
from. The guide carries it in the sequence, at the point where the data it needs
exists.
**A check that travels with the package disagreed with itself between Python
versions.** The tool that measures how much of the code the test suite actually
runs asked the compiler whether a file has anything to execute. For a file with
no statements in it at all — the vendored package carries an empty `__init__.py`
— what compiles is an implicit return, and the line it is numbered at is 1 on
Python 3.10 and 0 on 3.11 and later. The tool ignores line 0.
So one empty file was measured on one interpreter and skipped on another, and
the recorded baseline, taken on a newer Python, failed the suite on 3.10 over a
module with no code in it. Anybody running the checks on the oldest Python this
package supports would have met it — the checks travel beside the package and
`scholion doc contributing` describes how to run them. The question is answered
from the source now: no statements, nothing to reach, the same answer
everywhere.
## v0.4.4 — 23.08.2026
This release is mostly about a medical record read from a file: what such a record
holds that is not a laboratory number, and how the product names the codes it could
not place. The rest is about statements being true — a number and the word after it,
the version the local server gives out about itself, what a connectivity check is
allowed to fetch, whether a download checked who answered it, and whether an index
still describes the genome it was built from.
### What you can do now
**The facts the application cannot derive can be given from the page at last.**
Sex, year of birth, height and which wearable answers are preconditions: without
them a dozen reference intervals are withheld rather than guessed, the age-banded
rows of a laboratory form cannot be read, and there is no body-mass index. There
is now a **Profile** tab, and it offers all four. The main wearable had no field
anywhere but the command line.
**The reference panel for percentiles is no longer a question.** It used to be
one: `--ancestry EUR|AFR|EAS|SAS|AMR`, a superpopulation code nobody knows about
themselves in those terms. What such a box collects is a guess, and a guess
stored where a measurement goes is indistinguishable from one afterwards — while
every polygenic percentile depends on it.
Your own genome answers it. Comparing a few hundred of your genotypes against
the five 1000 Genomes panels is a step of preparing a genome, and the result is
used from where that step writes it; the Profile tab shows which panel applies
and says whether it was measured from your DNA or set by hand. Until it has been
determined, percentiles go on naming the default panel they used. The
command-line flag remains as a deliberate override.
Saying there is no wearable is an answer of its own. Until now «I do not own one»
and «nobody asked» were one blank field, so anything listing what the profile
still needs asked a person with no watch about their watch for ever. Choose «No
wearable device» once, or `scholion profile --wearable none`, and it stops.
**What the profile is still missing is now part of what the data cannot answer.**
`scholion limits` already answered one question — what cannot be said here, and
what would close it — and a missing precondition is exactly that. Each one now
appears in that list with the sentence it prevents and the command that records
it, and disappears from it once answered. An assistant reading the list at the
start of a conversation therefore asks for what is actually absent, rather than
from a list somebody typed into an instruction and then had to keep in step.
**A body measurement in a bundle is now kept, not dropped.** This product has
always taken a weight — from the command line and from the page — and an import
that met one inside a medical record threw it away because it is not a
laboratory analyte. It goes to the metrics layer where it belongs, with the same
mark of whose measurement it is as everything else written today. Only where one
of this product's own metrics holds the same quantity IN THE SAME UNIT: nothing
here converts, so a weight in pounds is refused rather than joined to a series in
kilograms. `scholion import-fhir <file>` reports the two layers separately,
because one number for both would say nothing about either.
**Height can be set from the command line at last.** The page has always had the
field; the command had not, and the body-mass index needs it —
`scholion profile --height-cm 178`. A bundle that states a height still does not
apply it: a file may hold a relative or two people, and a height is one field of
the profile rather than a series, so it is reported for you to set yourself.
**A marker may now carry more than one LOINC code**, because a LOINC code is not
one per analyte: the same substance has a different code by material and by
method, and four of that bundle's unplaced observations were analytes this
dictionary knows under a code it does not — glucose in whole blood beside
glucose in plasma, LDL measured directly beside LDL calculated. Every additional
code has to state why the two are the same measurement, and none ships: whole
blood and plasma differ by about a tenth, so pairing them because the names
match would put a systematic error into a series. The mechanism is here; the
pairings wait for a source, and the refusal now prints the code, so each one can
be looked up.
**The suite now says how much of the code it runs, and will not quietly run
less.** A thousand green tests is not a measurement, and this project had been
reading it as one. The number, once taken, was 69.9% — with the module that
implements provenance for every answer at 12.8%, and the VCF reader used whenever
`pysam` is absent, which is most installations, at 35.4%. Nothing could have said
so, because nothing was counting.
`check_test_reach.py`, which travels with the package beside the other checking
tools, counts — on the standard library alone and
including the tests that run the command line in a real subprocess. It reports
per module, `--strict` fails when a module falls below the reach recorded for it,
and `--accept` records a new number deliberately. It is the last step of
`./run_tests.sh`; `SCHOLION_SKIP_REACH=1` skips it while editing.
No module is now under half. Seven that were — polygenic scoring, the provenance
audit, the study loader, the watch import, every route of the local web
interface, the online drug lookup and the VCF reader — carry tests for what they
actually decide: which polygenic model is allowed to speak for a trait, that a
score is not computed for an organ the person does not have, that a stored number
which no report holds is told apart from one that a second method explains, that
a rebuilt watch export cannot erase months it no longer mentions, that a
judgement written about a study survives the file being read again, and that an
empty answer from a database that was never reached is never printed as «nothing
was found».
Nothing about anyone's data changes, and no command behaves differently.
### What was wrong
**A form the interface never showed.** The page holding sex, year of birth and
height existed, worked, and was in no tab: it had never been reachable, in the
whole history of the file, so in practice those facts could only be set from the
command line — while the command's own help said the opposite. Every view the
page defines is now checked for a way in, because a view nobody can open fails no
test that calls its functions directly.
**A recorded age and a recorded sex could both show as «—».** The age was
computed from a year of birth alone, so a profile carrying a full birth date —
which is what the demonstration writes, and what an imported medical record
writes — reported no age at all while the file held one. And the page compared
the stored sex against `male`, while the file is allowed to say `m`; a sex
already given then showed as blank and was asked for again. Both are read
through the one function that knows the spellings.
**A value that cannot mean anything was stored rather than refused.** `--ancestry
EURO` went in, and every polygenic percentile afterwards was computed against a
reference population that does not exist — printed as an ordinary number, and
without the caveat about a default one, because a value was set. Nothing
downstream could tell. Populations, devices and spellings of a sex are now
checked on the way in, by the same lists in every face; an unrecognised value is
refused with what is accepted. A profile field a person did not touch is also no
longer rewritten by a save of a different one.
**«1 markers are printed without a reference range».** A number and the word
after it did not agree — on the screen that says what the data cannot support,
which is the screen this project argues from. The machinery for it existed and
was in use; twenty-three messages simply did not go through it, and in Russian,
where a noun after a number takes three different forms, the same lines read as
carelessness about everything else on them. All twenty-three are repaired, and
the rule that replaces them is mechanical: a message may not put a number
immediately in front of a word unless it carries all the forms of that word. The
page and the package now also agree on which form to choose, checked against
each other rather than each against its author.
**A body weight was reported as a laboratory code nobody knows.** Importing a
FHIR bundle, ten of the twenty-three observations it could not place were not
analytes at all — height, weight, body mass index, temperature, heart rate,
respiratory rate, oxygen saturation. Calling them «a code this build does not
know» sends the reader looking for a dictionary entry that should never exist.
They are named for what they are now, each with the code and, where one of this
product's own metrics holds the same quantity, with that named too — and where
it does not, the reason is written down rather than left as silence: a heart
rate at a visit is not the resting home pulse, and a body-mass-index percentile
against an age-and-sex reference is not the index this product keeps. Nothing is
written from them yet; what changed is that the list of what a bundle held is no
longer misleading. On the same bundle the count of «not in the dictionary» falls
from 23 to 13.
**An observation the dictionary could not place named only its label.** Importing
a FHIR bundle lists what it did not take and why; for a code the dictionary does
not know it printed «Calcium» — while the code, which is the thing an entry is
keyed by and the only way to look the analyte up, sat in the record one line
short of the screen. It is printed now: «Calcium (49765-1)».
`scholion import-fhir <file> --dry-run` shows the list without writing anything.
**A profile with no birth year stopped a whole batch of laboratory forms.**
Reference ranges on a form are often given by age band — one row for 40 to 49,
another for 50 and over — and choosing the row that applies needs the reader's age.
A profile without a birth year is an ordinary state, one the setup warns about and
proceeds from; the comparison was made anyway. `scholion ingest-labs` then failed
on the first form carrying such a row, and the run stopped there rather than
setting that one file aside and going on.
An age that is unknown is not the same claim as an age that fits. An age-banded row
is now neither confirmed nor excluded — the standing a row with no group label has
always had — and where a block offers several of them, the rule this product
already followed takes over: more than one row could apply, so none is taken and
the marker arrives with no reference corridor at all. That is the safe direction
rather than a gap: nothing without a corridor is ever called a deviation here.
Sex is a separate question and still filters rows when the age is unknown.
**The connectivity check accepted an address to fetch, and it should never have
accepted one.** The local server answers a page in your own browser, and any
other page open in that browser can ask it for something. The check that says
«is there internet from here» took the address to try as a parameter. The first
repair made it verify that address — https only, and only the handful of hosts
this product itself talks to — which closed the hole it was written for and left
the shape: a host that is allowed still accepts any path and any query, so an
address could still carry something outward, and a check over a string somebody
else composed is a race with whoever composes the string.
It no longer takes an address. It takes the NAME of a probe, and the address
behind that name is a constant in the source; a name that is not in the table is
refused and nothing is opened. `scholion serve` shows the result in the same
place as before, and the page asks for it the same way — only `?url=` is gone,
replaced by `?target=`, and no caller can name an address again.
**A reference download could stop checking who was answering, and said nothing
about it.** Two of the catalogues this project builds are fetched from public
reference databases: the collection of longevity variants, and the list of genome
positions those variants are read at. When the certificate check failed, both
downloads simply repeated the request without it. Whether a certificate was the
problem at all was decided by reading the wording of the error — so a message
that merely mentions SSL, such as a protocol mismatch or a proxy refusing the
connection, was enough — and nobody was asked for permission. The note written
beside it argued that the archive's own integrity check made this safe; it does
not. That check catches a damaged transfer, not a substituted one.
What could have come of it: a catalogue of variants, or a set of coordinates a
genome is then read at, supplied by somebody other than the database named on it,
and afterwards reported with exactly the confidence the real thing would carry.
Nothing on screen would have looked unusual, which is the whole difficulty with
this class of fault.
Both now refuse. Verification is skipped only when the person allows it out loud
(`SCHOLION_TLS_INSECURE=1`), only when the failure really was a certificate —
decided by the kind of failure, not by its wording — and every request made that
way prints a warning as it is made. This was already how the application's own
lookups behaved; it is now how everything behaves, and a check that reads the
whole source tree refuses any new place that goes back to deciding for itself.
**A genome rebuilt while the application was running could report a variant as
absent.** The reader that answers questions about a variant file without external
tools keeps that file's index in memory. It kept it under the file NAME alone, and
nothing ever discarded it — so a genome re-called and re-indexed while `scholion
serve` was left open went on being read through the previous index. The offsets in
it no longer describe the file, the read lands nowhere useful, and it comes back
with no rows.
No rows is the answer that matters. For a variant file produced the usual way, the
absence of a row at a position means «the same as the reference» — so a stale index
did not produce an error, and did not leave a gap. It produced an ordinary genotype,
stated with the ordinary confidence, at a position that may carry a finding.
The index is now remembered together with the modification time and size of the
index file, so a rebuilt genome is read afresh. Anyone who never rebuilds a genome
under a running interface was never affected, and a command-line run never was: it
starts a new process each time and had nothing to remember.
### What needs recomputing
Nothing, unless a warning about unverified certificates was seen while the
reference catalogues were being built. They are rebuilt by rerunning the build; the
data already in a profile is not affected, because those files are a shared public
reference and hold nobody's measurements.
## v0.4.3 — 22.08.2026
This release is about files that arrive wrapped, laboratory forms printed for an
American reader, and — the larger half — a report that stops claiming more than
the file it was given can support.
### What you can bring it now
**A consumer DNA test still inside whatever the provider wrapped it in.** A VCF
compressed with bzip2, a VCF inside the provider's zip, a VCF whose file name
carries URL-encoded brackets — all of them ordinary VCFs, and all of them now
read. A file is identified by its bytes before its name, so an export that
arrived zipped is no longer «an archive, not opened blind here»: looking inside
is the opposite of blind. None of these can be seeked into, but the catalogue is
fifty-four loci, so one cached pass over the file answers all of them — and the
same pass measures the call set exactly rather than by probe.
`scholion genome-status` names what it found.
**A genotype table from a chip, with the ceiling of the chip attached.** It is
read the same way, and a position nobody typed is reported as not read — never
as the reference.
**Three formats stay named and unread, each with its reason**, because a gap
left unexplained is indistinguishable from an oversight: a VCF that went through
a spreadsheet (its structure is gone rather than hidden — the honest answer is
the original export), a Complete Genomics `var` table (the vendor ships a
converter that is correct by construction, and a second implementation here
would be a worse one), and an archive of the FTDNA era keyed by internal SNP
numbers with no rsID anywhere in it.
**Laboratory forms printed for an American reader.** A LabCorp report prints its
dates as a table — the column headings on one line, the values on the next — and
a reader expecting the label and the date side by side finds neither. The
heading and the line under it are now read, and only while «collected» is the
leftmost date column; where that cannot be established, nothing is read rather
than the wrong column filed. A two-digit year is read. And a page carrying
`12/15/2008` has already said which order it prints in, because there is no
fifteenth month, so `12/10/2008` beside it is the tenth of December and not a
coin toss — the evidence is on the same page, in the same table, from the same
instrument. A page whose dates contradict each other is still refused, and so is
a lone ambiguous date with nothing on the page to settle it. Two weaker
witnesses are used only after the page and are named as what they are:
«Ordered Date», which some lipid panels print instead of a draw date, and the
file name, where a month spelled out is read and a numeric one is not.
`scholion ingest-labs` reports what each file gave.
**An exome or a panel whose header does not say which build it is in.** The
build decides whether the genomic layer may answer at all, and it was
established from the lengths of the chromosomes in the header, or — failing
that — from a variant lying past the end of chromosome 1, which only a GRCh37
file can have. A capture panel has neither: no contig lengths, and no rows out
at the telomere to probe with. Three providers stamp their own pipeline into the
header and build against one reference only, so that signature is now read as
well. Where a pipeline serves both builds, the provider's name alone settles
nothing and is not used on its own: DRAGEN counts only together with the
reference path in the same header. `scholion genome-status` prints which of the
four witnesses answered — a build inferred from who made the file is a weaker
claim than one measured off the file, and it no longer looks the same.
**A WHOOP export.** The zip that arrives by email — or the folder it was
unpacked into — is now read: recovery, day strain, resting heart rate, heart
rate variability, respiration, blood oxygen, skin temperature, sleep with its
stages, sleep debt, consistency and efficiency, and workouts.
`scholion ingest-wearable <folder-or-zip>` takes either device and says which
one it recognised; the Garmin command still does exactly what it did.
WHOOP does not publish the layout of that export, and a layout nobody published
is one that can change without telling anybody, so the column names are read
rather than assumed. Each header is looked up in a table that ships as data, and
a column that is not in the table is **listed by name** with nothing read from
it — an export carrying a column this has never seen says so instead of quietly
dropping a measurement.
**The reader can be named.