Repository navigation
qvf v0.2.0 - 2026-10-14
The format and toolkit changes since 0.1.0, all within QVF v1
(qvf_version = 1). The last group of format decisions makes QVF the document
format of vibe-sketch, the structure and reaction sketcher: chemical identity
on structure sections, the reaction.scheme and preview kinds, the member
field media_type, job sets, one media type and one macOS UTI for .qvf,
and the withdrawn qvf_version 2 read as a warning
(Decisions).
None of the changes bumps qvf_version.
Deprecated
provenance.hostname(spec § 3.2): producers SHOULD NOT emit it; consumers
MUST ignore it except for display. The schema property is annotated
"deprecated": true; existing archives remain valid. Noqvf_version
bump (D11, WP-07).- The unit spellings
Eh,eVandHartreein a{value, units}object
(provenance.scf_energy,provenance.fermi_energy): still valid there as
$defs/LegacyUnitName, read ashartreeandev; producers SHOULD write
the unit name (D12, WP-13).
Added
- Chemical identity on
structuresections (spec § 5.1): optional section
fieldscharge,multiplicity,name,smiles,inchiandinchikey;
the genericlabelis the species' compound label. Validators report a
charge and multiplicity impossible for the atoms as the new error
E_CHARGE_MULTIPLICITY, and, in an archive with one structure, a
disagreement withprovenance.charge/provenance.multiplicityas
E_ROOT_INCONSISTENT. Pythonadd_structuretakes the six fields. reaction.scheme, a canonical kind (spec § 5.14): steps in reading order
relatingstructuresections as reactants, reagents and products, each
with an optional stoichiometric coefficient, under aforward,
equilibrium,retrosyntheticorresonancearrow, with the conditions
and the yield (yield_percent,yield_text). Roles are chemical whatever
the arrow; the step keyenergiesis reserved for reaction energies.
Validators resolve every participant (E_REF_UNRESOLVED) and reject
duplicate step ids and repeated participants (E_MEMBER_MALFORMED).
Pythonadd_reaction_scheme.preview, a canonical kind (spec § 5.15): a rasterthumbnail
(image/pngorimage/jpeg) and an optionalimage(also
image/svg+xml), both opaque members with a requiredmedia_type; the
archive's picture is the thumbnail of the firstpreviewsection, and SVG
is self-contained and inert. Validators check the bytes against the media
type (E_MEMBER_MALFORMED,E_UTF8). Pythonadd_previewsniffs and
checks the image type and stores the members uncompressed.media_type, an optional field of every member spec (spec § 4.2): the IANA
media type of the member's bytes. Vendor sections may carry opaque members
(binary without dtype and shape); Pythonadd_vendor_sectiontakes
opaque_members=.- Job sets (spec § 5.9): an archive may carry several
job.specsections,
each naming its structure;run.recordgainsjob_ref(the job it ran,
resolved by validators) andrun_status(its outcome), and
provenance.run_statussummarises the set. Pythonadd_run_recordtakes
job_ref=andrun_status=, andadd_job_specwritesstructure_refon
the section object as well as in the payload. - File identification (spec § 2.4): the extension
.qvf, the media type
application/vnd.vibe-qc.qvf+zipand the macOS Uniform Type Identifier
com.vibe-qc.qvf(conforming topublic.zip-archiveand
public.content), inregistry.json(file_type) and as declarations to
copy inspec/file-type/(qvf-uti.plist,qvf-mime.xml). registry.jsonregisters the vendor namespacex_vibesketch.- Finding codes
W_VERSION_WITHDRAWNandE_CHARGE_MULTIPLICITY
(Appendix B). - C++ reference writer:
add_reaction_scheme,add_preview,
set_structure_identity,remove_section,add_opaque_memberand an
add_vendor_sectionoverload withOpaqueMembers,RunRecord::job_ref
andrun_status;qvf::MemberSpec::media_typein the typed model; a member
of an update whose path the archive already holds gets a fresh path
(<stem>.<n><suffix>) instead of an exception,begin_binaryincluded;
open_for_updateacceptsqvf_version: 2and writes 1.
write_all_kindscovers all 56 canonical kinds. The C++ and JavaScript
validators implement every new rule with the codes and locations of the
Python one (@qvf/corealso typesmedia_typeand regenerates its kind
list). - Python reference writer:
label=on everyadd_*method;
remove_section(id), which with anadd_*under the same id replaces a
section;open_for_updatetakes an archive's bytes as well as its path;
to_bytes(repack=True)andwrite(..., repack=True)drop superseded
entries; a member of an update whose default path the archive already
holds gets a fresh path instead of an error. - Conformance corpus:
reaction_scheme.qvf(eight species with their
identity, a three-step scheme, a preview, an opaque vendor member) and
job_set.qvf(a job set halfway through); ten negative archives for the
new rules. - Spec § 5.8 "Sharing and sanitisation": run.record inputs, logs,
attachments,command, andfilesfilenames may carry paths, user names,
and host names; producers SHOULD offer suppression or redaction; a toolkit
scruboperation is the intended mechanism (WP-07). - C++
qvf::Json::erase(key)(WP-07). - Payload schemas for the spectra and analysis members (spec § 5.4, § 5.7,
§ 6):$defs/SpectrumPayloadfor the six 1-D spectra, with new optional
x_units,y_units,x,peaks,broadening,temperature_k,raman
anduvvis(frequencieskeeps the x axis in the kind's § 4.3 unit);
typedNmrSpectrumPayloadandEprSpectrumPayload; strictBondsPayload
(also thestructuresection'sbondsmember),BondOrdersPayloadand
ScfHistoryPayload;QtaimPayloadwith an optionalunitsobject
(positions in Å unless declared, a provisional default);SymmetryPayload.
Validators check each withE_PAYLOAD_SCHEMA, including the equal-length
rule of a 1-D spectrum, so malformed payloads that used to pass now fail.
Corpusspectra_all.qvf,nmr.qvf,qtaim.qvf,symmetry.qvf; three
negative payload archives. Pythonadd_spectrumchecks array lengths and
takesx_units,y_units,peaks,broadening;add_topology_qtaim
takesunits. Noqvf_versionbump (P01, P13, D05, D18, WP-11). - Payload definitions for the geometry and wavefunction JSON members: volume
gridandreaction.pathvolume_grid($defs/VolumeGridPayload),
wavefunction.gtobasisandmo_metadata(BasisPayload,
MoMetadataPayload), and themetadata/waypointspayloads of
trajectory,reaction.path,reaction.waypoints,scan.surfaceand
vibrations. Spec § 5.2, § 5.3 and § 5.5 gain payload tables, and § 6
checks every JSON member that has a payload definition (E_PAYLOAD_SCHEMA).
Additive, noqvf_versionbump; a previously unconstrained malformed
payload now fails validation. Corpus gainstrajectory.qvf,
vibrations.qvf,scan_surface.qvfandreaction_path.qvf; the negative
corpus gains threepayload_*archives (P01, D07, WP-10). - Schema and spec § 5.6: optional members
phonon_bands.eigenvectors
(float64[n_q, n_modes, n_atoms, 3], or[n_q, n_modes, n_atoms, 3, 2]
with the last axis[re, im]) andphonon_dos.projected(float64
[n_channels, n_points], rows labelled bymeta.channels); thedos.total
/dos.projectedsection fieldsn_spin,smearing,smearing_type,
fermi_energy_ev,n_electronsandchannelsnamed as optional typed
properties. Theatom_propertiesroles (mulliken_charge,
loewdin_charge,hirshfeld_charge,iao_charge,spin_population) are
one list in the schema and spec § 5 / § 5.7. Corpus archivesphonons.qvf
andatom_properties_all.qvf. Noqvf_versionbump (D02, D03, D08, WP-04). - Payload definitions for the periodic kinds and the run-record
filesindex
(spec § 5.6, § 5.8): strict$defs/KpathPayload(withKpathSegment),
FermiMeshPayload,QpathPayload,EosFitPayloadand
RunRecordFilesPayload; typed-openDosMetaPayload(dos.coop/
dos.cohpmeta),PhononMetaPayloadand the sharedDosChannel. The
Python validator checks each member against its definition
(E_PAYLOAD_SCHEMA) through a(kind, role)table. Noqvf_versionbump
(P01, P14, D07, WP-12). - Spin axis on projections:
bands.projections[n_spin, n_k, n_bands, n_channels]anddos.projected.projections[n_spin, n_channels, n_points]; the lower-rank shapes stay legal and meann_spin = 1. New
optionalbands.occupations[n_spin, n_k, n_bands]. Both validators report
shapes that disagree witheigenvaluesasE_MEMBER_MALFORMED; Python and
C++add_bandstakeoccupations(C++: a new overload), and the writers
refuse disagreeing shapes (D04, WP-12). - Conformance corpus:
bands_spin.qvf,dos.qvf,fermi_surface.qvf,
eos.qvf; negative corpus:bands_spin_mismatch.qvf,
eos_model_unknown.qvf(WP-12). - Unit vocabulary (spec § 4.3, "Unit names" and "Declared units";
$defs/UnitName, 25 names fromangstromtodimensionless). Every payload
unitsobject (now also on the volume grid), the 1-D spectrum'sx_units,
y_unitsandbroadening.units, andValueWithUnits.unitsare typed as
unit names, and declarations of units § 4.3 fixes areconstin the payload
definitions. New warningW_UNIT_UNKNOWNin the Python, C++ and JavaScript
validators. Python moduleqvf_units(UNITS,LEGACY_UNITS,is_unit,
canonical,convert,fixed_units) and C++ headerqvf/units.hpp
(qvf::Unit,unit_name,parse_unit,canonical_unit,convert), with
CODATA 2018 length and energy conversions; JavaScriptUNIT_NAMES,
isUnitName,canonicalUnit. Pythonadd_volume,add_trajectoryand
add_scan_surfacetakeunits=; C++Grid::units,Spectrum::x_units/
y_units. Corpusunits_declared.qvf; negativeunit_unknown.qvf,
unit_contradicts_fixed.qvf. Noqvf_versionbump (P02, D12, WP-13). - Root
energiesblock (spec § 3.6,$defs/Energies):total,method,
components(nuclear_repulsion,electronic,one_electron,
two_electron,exchange_correlation,exchange,correlation,
dispersion,solvation,zpve,thermal,embedding,x_keys),
by_methodandunits_note. An energy stated for the method
provenance.methodnames must agree withprovenance.scf_energy, and
components.zpvewiththermochemistry.zpve_eh, within 1e-8 hartree; new
finding codeE_ROOT_INCONSISTENTin Appendix B and all three validators.
Noqvf_versionbump (P05, WP-21). - Canonical kinds
forces(spec § 5.10:gradientfloat64[n_atoms, 3]
in hartree/bohr, the energy gradient, so forces are its negative; optional
stress[3, 3]in hartree/bohr³ and strictmeta) andhessian(spec
§ 5.11:matrixfloat64[3N, 3N]in hartree/bohr², optional strict
metawithmass_weighted,projected,atom_masses_amu), registered as
promotions by maintainer decision; optionalvibrations.hessian_ref.
Validators check the shapes against the section's structure
(E_MEMBER_MALFORMED) and resolvemeta.structure_refandhessian_ref
(E_REF_UNRESOLVED). Writers: Pythonset_energies,add_forces,
add_hessian,add_vibrations(hessian_ref=); C++set_energies,
add_forces,add_hessian,add_vibrations(..., hessian_ref); C ABI
qvf_set_energies_json,qvf_add_forces,qvf_add_hessian. The
JavaScript reader exports theEnergiestypes. Corpusforces_hessian.qvf;
negative corpusforces_atom_count.qvf,hessian_not_square.qvf,
energies_inconsistent.qvf. Noqvf_versionbump (P06, P07, WP-21). - Periodic grid semantics (spec § 5.2,
$defs/VolumeGridPayload): optional
grid fieldsperiodic(three booleans),includes_endpoint(default
true, cube style: the last plane repeats the first;false, CHGCAR style:
shape[a]planes per period) andstructure_ref. § 5.2 is rewritten around
the point positions, a cube-vs-CHGCAR worked example and the rule that a
consumer tiling a cube-style grid MUST drop the duplicated plane. All three
validators check that a periodic axis is periodic in the grid's structure
and thatvoxel_vectors[a] × (shape[a] − 1)(or× shape[a]) equals the
lattice row in bohr within 1e-6 relative (E_MEMBER_MALFORMED), and
resolve a gridstructure_ref(E_REF_UNRESOLVED). This resolves a silent
cube/CHGCAR interoperability bug. Noqvf_versionbump (P11, WP-25). - Canonical kinds
volume.vector([nx, ny, nz, 3],
$defs/Volume4DVectorBinary),volume.complex([nx, ny, nz, 2], last
axis[re, im],$defs/Volume4DComplexBinary),volume.series
([n, nx, ny, nz]with a required strictaxismember,
$defs/VolumeSeriesAxisPayload:kindtime / frame / state / custom,
values,units,labels,trajectory_ref) andvolume.laplacian
(∇²ρ in e/bohr⁵, a new § 4.3 row), registered as promotions by maintainer
decision. Validators check the rank and trailing axis of each, a series
axis against its slabs (E_MEMBER_MALFORMED) and itstrajectory_ref
(E_REF_UNRESOLVED); an unknown series axis unit isW_UNIT_UNKNOWN.
reaction.pathframe_volumes+volume_gridare documented as the older
form of a framevolume.series, which producers SHOULD prefer; both stay
valid. Writers: Pythonadd_volume(..., periodic=, includes_endpoint=, structure_ref=, axis=)with 4-D data for the new kinds; C++
Grid::periodic/includes_endpoint/structure_ref,add_volumefor
the new kinds andadd_volume_series; C ABIqvf_add_volumeand
qvf_add_volume_series(the first generic volume entry points). The
JavaScript reader exportsBOHR_PER_ANGSTROM. Corpusvolume_periodic.qvf,
volume_vector.qvf,volume_complex.qvf,volume_series.qvf,
volume_laplacian.qvf; negative corpusvolume_periodic_span.qvf,
volume_endpoint_count.qvf,volume_series_axis_length.qvf,
volume_vector_trailing_axis.qvf. Noqvf_versionbump (P11, WP-25). - Canonical kind
wavefunction.bloch, provisional (spec § 5.3.1): the
k-resolved Bloch orbitals of a periodic system over thewavefunction.gto
basispayload, with a strictkpointspayload
($defs/BlochKpointsPayload: fractional k-points,weightssumming to 1,
labels,mesh,shift,time_reversal), a strictmo_metadata
($defs/BlochMoMetadataPayload:spin,n_spin,n_mo,n_ao,
complex,k_point_convention,orbital_kind,n_mo_per_k,
fermi_energy), complexmo_coefficientsfloat64[n_k, n_spin, n_mo, n_ao, 2], andenergies(hartree) andoccupations[n_k, n_spin, n_mo]. The spec states the Bloch sum φ_μk(r) = N^(−1/2) Σ_T e^{+ik·T}
χ_μ(r − T). Promoted fromx_vibeqc.bloch_wavefunctionahead of the
two-producer threshold by maintainer decision; the registrypromotions
entry carries"status": "provisional"until a second producer ships it.
The Python, C++ and JavaScript validators check the member shapes, the
weights and a periodic structure (E_MEMBER_MALFORMED,
E_REF_UNRESOLVED). Writers: Pythonadd_wavefunction_bloch, C++
WavefunctionBloch+add_wavefunction_bloch, C ABI
qvf_add_wavefunction_bloch. Corpusbloch.qvf(with abandssection at
the same k-points); negative corpusbloch_weights_sum.qvf,
bloch_coefficients_trailing_axis.qvf,bloch_occupations_shape.qvf,
bloch_structure_molecular.qvf. Spec § 7.5 records provisional
promotions and § 9 item 2 what is still open. Noqvf_versionbump (P15,
WP-30). atom_propertiesroles (spec § 5 table, § 5.7, schema
$defs/SectionAtomProperties): 17 new scalar roles, float64[n_atoms]
(cm5_charge,chelpg_charge,resp_charge,esp_charge,nbo_charge,
mbis_charge,bader_charge,ddec_charge,valence,bonded_valence,
fukui_plus,fukui_minus,fukui_zero,dual_descriptor,
atomic_energy_eh,atomic_volume_bohr3,nmr_shielding_iso_ppm), two
vector roles, float64[n_atoms, 3]($defs/AtomVectorBinary:
magnetic_momentin μB andforce_eh_bohr, the energy gradient in
hartree/bohr), andcustom.<name>roles described by a strictmeta
member ($defs/AtomPropertiesMetaPayload:units,description,
kind). Spec § 5.7 gains a role table with unit and sign conventions.
Validators report acustom.*member without ametaentry as
E_MEMBER_MALFORMED(Python, C++, JavaScript). Corpus
atom_properties_extended.qvfand four negative archives
(atom_properties_custom_no_meta.qvf,
atom_properties_custom_meta_entry_missing.qvf,
atom_properties_vector_shape.qvf,atom_properties_role_unknown.qvf).
Noqvf_versionbump (P10, WP-24).- Root
metadatablock (spec § 3.5,$defs/Metadata):title,
description,created_utc,modified_utc,uuid,authors
($defs/MetadataAuthor),license,doi,keywords,derived_from,
tags; strict, with the time stamps (ISO 8601 UTC,Z) and the RFC 4122
uuidpattern-checked by the schema. Authors'emailandaffiliation
are personal data that producers SHOULD NOT emit by default. No
qvf_versionbump (P03, WP-20). - Section fields
structure_ref,run_refandgroupon any section (spec
§ 4.1). All three validators (Python, C++, JS) report astructure_ref
that does not name astructuresection, or arun_refthat does not name
arun.record, asE_REF_UNRESOLVED. A section'sstructure_reftakes
precedence over the one in awavefunction.gtobasispayload. No
qvf_versionbump (P04, WP-20). - Writers: Python
set_metadata(**fields)andannotate_section(section_id, structure_ref=, run_ref=, group=, label=); C++set_metadata(Json),
set_section_field(id, key, value)andannotate_section(id, structure_ref, run_ref, group); C ABIqvf_set_metadata_jsonand
qvf_annotate_section. The JS model types gainMetadata,
MetadataAuthorand the three section fields (WP-20). - Conformance corpus:
multi_structure.qvf; negative corpus:
structure_ref_wrong_kind.qvf,run_ref_unresolved.qvf,
trajectory_ref_wrong_kind.qvf,metadata_uuid_invalid.qvf(WP-20). - Conformance corpus v2 and a C++ runner. Every canonical kind of
registry.jsonnow has a positive archive, and
python/tests/test_corpus_coverage.pykeeps it so (new:bonds.qvf,
volume_orbital.qvf,volume_spin.qvf,volume_elf.qvf,
volume_potential.qvf,volume_rdg.qvf,volume_generic.qvf,
volume_difference.qvf,basis_ao.qvf,dos_coop.qvf,citations.qvf).
Edge cases:wavefunction_uhf.qvf;wavefunction_cartesian.qvf, a
pure: falsed shell whose Appendix A.1 self-overlaps (1 axial, 1/3 for
d_xy) are stored in anx_conformance.overlap_diagonalvendor section;
structure_wire_1d.qvf;reaction_path_variable_cell.qvf;zip64.qvf
(ZIP64 structures forced on small members) anddata_descriptor.qvf
(streamed members). A newconformance/legacy/holds an archive stamped
qvf_version: 2, which the validators reject withE_VERSIONpending a
maintainer decision; the Python and JavaScript runners treat it like
negative/.cpp/examples/run_conformance.cppimplements the whole check
format for the C++ reader (CTestqvf_conformance, and a step in both CI
pipelines); it listszip64.qvfas a known gap, because the C++ ZIP layer
has no ZIP64 yet. No spec or schema change, noqvf_versionbump (WP-14). - Typed
provenancefields (spec § 3.2, now a table of every recognised
field):software($defs/ProvenanceSoftware:name,version,url),
git_commit(7 to 64 hexadecimal characters),n_threads,n_mpi_ranks,
n_gpus,started_utcandfinished_utc(ISO 8601 UTC); the block stays
open andwall_secondskeeps its name.provenance.n_electronsmust agree
withbasis.n_electrons. Pythonset_provenanceand C++set_provenance
check them. Noqvf_versionbump (P18, WP-27). - Typed
job.specfields (spec § 5.9):structure_ref,solvation
(model,solvent,epsilon),dispersion,relativistic,scf
(convergence,max_iterations,guess,damping),geometry
(convergence,max_steps,coordinates) andresources(n_cores,
memory_mb,walltime_s; hints, not requirements); the blocks are strict
withx_keys allowed, the root stays open and engine keywords stay under
options. All three validators resolve a payload'sstructure_refwith
E_REF_UNRESOLVED. Pythonadd_job_spectakes the new fields as
arguments, C++add_job_spec(Json)checks them, and the C ABI gains
qvf_add_job_spec_json. Corpusjob_spec_full.qvfand
provenance_full.qvf; negativejob_spec_structure_ref_wrong_kind.qvf,
provenance_git_commit_not_hex.qvf,provenance_started_utc_not_utc.qvf.
The JS model types gain the provenance fields. Noqvf_versionbump (P18,
WP-27). - Optional member
sizeon every member spec ($defs/MemberSize, spec
§ 4.2): the uncompressed byte count of the stored member, equal to the size
its ZIP entry records. The Python and C++ writers write it for every
member; the Python, C++ and JavaScript validators check it against the
central directory before reading the member (E_BINARY_SIZE, wording
widened; a malformedsizeisE_MEMBER_MALFORMED), and the readers refuse
such a member. Noqvf_versionbump (P19, WP-28). - Spec § 2.3 "Updating an archive in place": an update appends entries,
writes a newmanifest.jsonlast and never reuses another entry's name;
the previous manifest and replaced members are orphans (W_ORPHAN_MEMBER)
that consumers ignore; consumers read the lastmanifest.json;repack
removes orphans;metadata.modified_utc,run.record.sequenceand
provenance.run_statusrecord the update. Validators report a duplicated
manifest.jsonasW_ORPHAN_MEMBERfor each superseded copy instead of
E_ZIP_DUPLICATE_ENTRY, a clarification of the 2026-10-07 duplicate rule;
the Python, C++ and JavaScript readers open such archives. Noqvf_version
bump (P19, WP-28). - Optional root
byte_order,const: "little"(spec § 2.2, § 3.1): states
the byte order every v1 archive already has; any other value fails the
schema (E_SCHEMA) and the readers refuse it. Both writers emit it; v2
moves the byte order into the dtype names (V2-01). Noqvf_versionbump
(P20, WP-28). - Conformance corpus
updated_in_place.qvf(twomanifest.jsonentries, an
orphaned member, validates with warnings) andsize_declared.qvf; negative
corpusmember_size_mismatch.qvfandbyte_order_big.qvf(WP-28). - Trajectory extensions (spec § 4.3, § 5.5): optional
trajectorymembers
lattice(float64[3, 3]or[n_frames, 3, 3]in the structure
convention, rows in Å, unlikereaction.path.lattice),velocities
([n_frames, n_atoms, 3], Å/fs),gradient([n_frames, n_atoms, 3], the
energy gradient in hartree/bohr; forces are its negative),times(fs),
binaryenergies(hartree),cell_volumes(ų) andtemperatures
(kelvin), each[n_frames];reaction.pathgainsvelocities,
gradient,timesandenergies.coordsmay be float32 with
metadata.precision: "float32"($defs/TrajectoryCoordswidened). Metadata
gainsensembleandtimestep_fs;pbcis required with a trajectory
lattice. Schema$defs/TrajectoryLattice,TrajectoryFrameVectors,
TrajectoryFrameScalarsand the sharedTrajectoryMetadataCommon; § 4.3
"Lattice conventions" states all three cell carriers. The Python, C++ and
JavaScript validators check the per-frame extents againstcoords, the
float32 /precisionrule, binaryenergiesagainstmetadata.energies
(1e-10 hartree) andlattice/pbc(E_MEMBER_MALFORMED). Writers:
Pythonadd_trajectory(..., lattice=, velocities=, gradient=, times=, energies=, cell_volumes=, temperatures=, precision=)and
add_reaction_path(..., velocities=, gradient=, times=, energies=); C++
TrajectoryExtras,add_trajectory(metadata, coords, extras)with
Latticeandstd::vector<Lattice>overloads,add_reaction_path(..., lattice, extras); C ABIqvf_add_trajectory. Corpusmd_periodic.qvf;
negative corpustrajectory_lattice_without_pbc.qvf,
trajectory_float32_without_precision.qvf,
trajectory_velocities_frame_count.qvf,
trajectory_energies_disagree.qvf. Noqvf_versionbump (P12, D06, WP-26). - C++ container layer
qvf/container.hpp(qvf::container):ZipWriter
over aFileSink,MemorySinkorCallbackSink, with whole or streamed
entries (begin->EntrySink: CRC-32, SHA-256 and DEFLATE on the fly;
local headers patched on seekable sinks, data descriptors on others),
ZIP64 extra fields, end record and locator when a size, offset or entry
count needs them or when forced,append(path)(existing records kept as
they are) andallow_repeated_name()for the supersededmanifest.jsonof
spec § 2.3;ZipReaderwith ZIP64 and data-descriptor support, CRC-32 and
local-header checks, a repeated name resolved to its last record, and
read_into()streaming an entry underLimits, which moved here
(qvf::Limitsis an alias). The DEFLATE and INFLATE codecs stream. The C++
reader now openszip64.qvf: the known gap and the sanitizer jobs' skip are
gone (D13, WP-40). - C++
QvfWriterstreaming and update:QvfWriter(source, path)writes
members to the file as they are added;begin_binary(section_id, role, dtype, shape)returns aMemberSinkthat computes sha256 and size on the
fly;open_for_update(path)updates an archive in place as spec § 2.3
prescribes (members appended, a newmanifest.jsonlast, the superseded
one kept as an orphan,metadata.modified_utcstamped, no other entry
name reused);write()finishes a bound writer;force_zip64; free
functionrepack(in, out)drops orphans and superseded manifests
(D19, P19, WP-40). - Python
QvfWriter.open_for_update(path)(spec § 2.3 throughzipfile
mode"a": members appended, a newmanifest.jsonlast, the superseded
one kept,metadata.modified_utcstamped, no other entry name reused),
module functionrepack(src, dst), andforce_zip64=onto_bytes()/
write()(D19, P19, WP-40). cpp/fuzz/zip_reader_fuzzer.cpp, a libFuzzer target over the ZIP reader
and the validator, built with-DQVF_FUZZ=ON(clang; a mutation driver
stands in where clang has no libFuzzer runtime); not run in CI yet (WP-40).- Canonical kinds
excited_states(spec § 5.12: one strict JSON member
states,$defs/ExcitedStatesPayload, with per-stateindex,
excitation_energy(SHOULD beev),total_energy,multiplicity,
symmetry,oscillator_strength,rotatory_strength_cgs(10⁻⁴⁰ esu²·cm²),
transition_dipoleandtransition_magnetic_dipole(atomic units),
contributions,nto_ref,density_ref, a strictmeta, and the section
fieldwavefunction_ref) andvolume.transition_density(spec § 5.2, e/bohr³,
optional section fieldsexcited_states_refandstate_index), registered as
promotions by maintainer decision. Natural transition orbitals are two
wavefunction.gtosections per state;mo_metadatagainsstate_indexand
nto_role(hole/particle), andstate_refnames theexcited_states
section (spec § 5.3). A one-dimensional spectrum payload gainsstates_ref,
which makespeaks[].assignment.state_indexa stateindex(spec § 5.4).
All three validators report repeated or descending state indices, a wrong
n_statesand a contribution beyond the reference wavefunction's orbital
rows (E_MEMBER_MALFORMED), and an unresolvedwavefunction_ref,
nto_ref,density_ref,states_ref,excited_states_refor
state_index(E_REF_UNRESOLVED);meta.unitsjoins the unit-name rule.
Noqvf_versionbump (P08, WP-22). - Writers: Python
add_excited_states(states, *, meta=, wavefunction_ref=, section_id=),add_volume("volume.transition_density", ..., excited_states_ref=, state_index=)andadd_wavefunction_gto(..., state_ref=, state_index=, nto_role=); C++add_excited_states,
add_volume_transition_densityand theWavefunctionGTOfields
state_ref,state_index,nto_role; C ABI
qvf_add_excited_states_json.js/src/kinds.tsis regenerated. Corpus
tddft.qvf(water: ground-state wavefunction, three states, an NTO pair, a
transition density and the UV-Vis stick spectrum of the table); negative
corpusexcited_states_index_duplicate.qvf,
excited_states_nto_ref_wrong_kind.qvf,
excited_states_to_mo_out_of_range.qvf(WP-22). wavefunction.gtoextensions (spec § 5.3, Appendix A.1): effective core
potentials specified (basis.ecp: radial functions
Σ c r^(n−2) exp(−α r²)withpowers= n, a new optionallocalflag for
the local part, which has the centre's highestl);basis.n_electrons
(Σ Z − Σ n_core_electrons − charge) must equal the summed occupations and
provenance.n_electrons;restricted_openandgeneralizedlayouts
(generalized: AO axis doubled as[α AOs…, β AOs…], requires
complex: true);complex: truemeans a trailing[re, im]axis on every
coefficient member; optional float64[n_ao, n_ao]membersoverlap,
density_matrix,density_matrix_alpha+density_matrix_beta
($defs/WavefunctionAoMatrix). Validators check coefficient ranks,
symmetry_labelslengths, matrix shapes and pairing and the electron count
(E_MEMBER_MALFORMED,E_ROOT_INCONSISTENTagainst provenance), and, when
overlapis present, its diagonal against the Appendix A.1 self-overlaps:
new finding codeE_NORMALIZATIONin Appendix B and all three validators
(Python, C++, JavaScript). Producers SHOULD writeoverlap. No
qvf_versionbump (P09, WP-23).- Writers: Python
add_wavefunction_gto(..., spin=, ecp=, n_electrons=, symmetry_labels=, overlap=, density_matrix=, density_matrix_alpha=, density_matrix_beta=, complex_coefficients=); C++WavefunctionGTO
fieldsspin,complex_coefficients,ecp,n_electrons,
symmetry_labels(and_alpha/_beta),overlap,density_matrix,
density_matrix_alpha,density_matrix_beta, and
QvfWriter::set_wavefunction_overlap/set_wavefunction_ecp; C ABI
qvf_add_wavefunction_gto_unrestricted,qvf_set_wavefunction_overlap,
qvf_set_wavefunction_ecp_json(WP-23). - Conformance corpus:
wavefunction_ecp.qvf,wavefunction_overlap.qvf
(itsexpected.jsonrecords the overlap diagonal); negative corpus:
wavefunction_normalization.qvf(E_NORMALIZATION),
wavefunction_n_electrons.qvf,wavefunction_complex_rank2.qvf(WP-23). - Canonical kinds
properties.electric,properties.elasticand
properties.dielectric(spec § 5.13, "Property kinds"), each with one
strict JSON memberproperties($defs/ElectricPropertiesPayload,
ElasticPropertiesPayload,DielectricPropertiesPayload), registered as
promotions by maintainer decision. Electric:dipole(debye),quadrupole
(debye·Å, Buckingham or Cartesian, with atracelessflag),octupole,
polarizabilityandhyperpolarizability(atomic units) andorigin.
Elastic: the symmetric 6 × 6 Voigtstiffnessin GPa,compliance, moduli
and theiraveragescheme. Dielectric:electronic,ionicandstatic
tensors, one Born tensor per atom in e, and the piezoelectric tensor in
C/m². Fixed units, with a typedunitsobject that restates them where the
vocabulary has a name (spec § 4.3 gains the rows). Validators in Python, C++
and JavaScript check symmetric elastic matrices,static=electronic+
ionicand the Born tensor count (E_MEMBER_MALFORMED), and an electric
dipole against the rootdipole_momentwithin 1e-6 debye
(E_ROOT_INCONSISTENT). Writers: Pythonadd_electric_properties,
add_elastic_properties,add_dielectric_properties; C++ the same names
taking the payload as JSON; C ABIqvf_add_electric_properties_json,
qvf_add_elastic_properties_json,qvf_add_dielectric_properties_json.
Corpusproperties_molecular.qvfandproperties_periodic.qvf; negative
corpuselastic_not_symmetric.qvf,dielectric_static_mismatch.qvf,
dielectric_born_atom_count.qvf,electric_dipole_inconsistent.qvf. No
qvf_versionbump (P14, P17, WP-29). - Schema-driven generated tables (design § 4–5):
scripts/gen_kinds.py
(standard library only) readsspec/qvf_manifest.schema.json,
registry.jsonand spec Appendix B and writes, deterministically,
cpp/include/qvf/kinds_generated.hpp(namespace qvf::gen:KindInfo/
RoleInfoper canonical kind with formats, dtypes, rank bounds and payload
definitions,kind_info(),kCanonicalKinds,payload_def(), theUnit
enum withunit_name()/parse_unit(), the finding codes, the schema
$id),python/qvf_kinds.py(the same tables,PAYLOAD_DEFS,
FIXED_UNITS), and the compiled schemacpp/src/qvf_schema_table.hpp/
js/src/schemaTable.ts.--checkfails on drift; a test, both CI pipelines
andscripts/make_archive.shrun it. The generator refuses JSON Schema
keywords outside the supported subset, unsupported regular expressions, an
unmapped*Payloaddefinition and a registry that disagrees with the
schema (WP-41). - A table-driven JSON Schema checker for the C++ and JavaScript validators
(cpp/src/qvf_schema_check.hpp,js/src/schemaCheck.ts): an interpreter
of the generated instruction table, with patterns on a Pike VM over code
points and no schema engine or<regex>. Both validators now report
E_SCHEMAformanifest.jsonandE_PAYLOAD_SCHEMAfor every JSON member
with a payload definition, at the same locations as the Python validator
(jsonschema), and the equal-length rule of a 1-D spectrum.
qvf::ValidationOptions::schema_check(C++) andschemaCheck(JS) disable
the check (thenW_SCHEMA_SKIPPED); the C++ and JS conformance runners take
--no-schema-check.python/tests/test_schema_checker_parity.pyholds both
checkers tojsonschemaon the positive, negative and legacy corpora and on
mutated corpus documents (WP-41). - Typed, lossless manifest model (design § 4): C++
qvf/model.hpp
(Manifest,Section,MemberSpecwithfrom_json/to_json, unknown
and wrongly typed fields kept inextra) exposed as
QvfReader::typed_manifest(), and Pythonqvf_model(dataclasses,
QvfReader.typed_manifest); round-trip tests over every conformance
manifest (CTestqvf_model_roundtrip,python/tests/test_model.py). The
writers do not use it yet (WP-41).
Changed
-
Validators read an archive stamped with the withdrawn
qvf_version: 2as
version 1, the JSON Schema check included, and report the warning
W_VERSION_WITHDRAWNinstead of the errorE_VERSION, as spec § 3.1 and
registry.json(readable_versions) asked of consumers; the legacy corpus
expects the warning. PythonQvfWriter.open_for_updateaccepts such an
archive and writesqvf_version: 1and the v1schema_uri. -
A pending archive carries at least one
job.specsection, no longer
exactly one (spec § 5.9). -
The conformance runner reports the legacy corpus as "judged as expected".
-
Reference writers drop a
hostnameprovenance key by default; opt in with
Pythonset_provenance(..., allow_hostname=True)or C++
set_provenance(prov, /*allow_hostname=*/true). The C ABI
qvf_set_provenance_jsonalways drops it and now reports malformed JSON as
an error instead of writing it verbatim (WP-07). -
Schema descriptions no longer cite internal documents or implementation
details, and every spec citation uses the current section number and
title; descriptions only, no contract change (D01, WP-02). -
The
Extensionsschema description now says keys carry theirx_
prefix, matching the pattern, spec § 7.4, and the vendor corpus archive. -
Writer APIs follow the schema: Python
add_atom_propertiesgains
hirshfeld_charge=andiao_charge=; C++ gains
add_atom_properties(std::map<std::string, std::vector<double>>)and
add_atom_property(role, values), plus anstd::initializer_listoverload
that keepsadd_atom_properties({q0, q1})unambiguous; the C ABI gains
qvf_add_atom_property. Both writers now rejectatom_propertiesroles of
different lengths, and phonon eigenvectors or a projected phonon DOS of the
wrong rank, trailing axes, dtype or extent, before writing anything; the
Python writer splits complex eigenvectors into the[re, im]form (D02,
D03, WP-04). -
Spec § 5.6 is rewritten around per-member payload tables with a Spin
axis rule; § 5.8 documents thefilesindex in a table. The schema
requiresbands.projectionsto be float64 (WP-12). -
The negative-corpus runners hold an expectation of a schema-only code
(E_SCHEMA,E_PAYLOAD_SCHEMA) only against a validator that runs the
JSON Schema check (WP-12). -
The writers write the unit names
hartreeandevfor
set_provenance(scf_energy_eh=, fermi_energy_ev=)and refuse a declared
unit that is not a unit name or that contradicts a fixed unit; a payload
unitsvalue outside the vocabulary, previously accepted by the schema, now
fails withE_PAYLOAD_SCHEMA.qvf::kBohrPerAngstrommoved to
qvf/units.hpp, whichqvf/qvf.hppincludes (WP-13). -
Writer APIs follow the enlarged
atom_propertieslist: Python
add_atom_propertiestakes every role by keyword pluscustom={name: (array, entry)}andmeta=and writes themetamember; C++ gains
add_atom_vector_propertyandset_atom_properties_meta, its map overload
andadd_atom_propertyaccept the enlarged scalar list and scalar custom
roles; the C ABI gainsqvf_add_atom_vector_propertyand
qvf_set_atom_properties_meta_json, andqvf_add_atom_propertyaccepts the
enlarged scalar list. Roles namedcm5_chargeorbader_chargewere
rejected as unknown before and are valid now (P10, WP-24). -
The reference writers (Python, C++, and through it the C ABI) add
metadata.created_utcand a random version-4metadata.uuidto every
archive by default, made once per writer; opt out with
QvfWriter(..., auto_metadata=False)or C++w.auto_metadata = false. A
consumer that validates against an older vendored schema rejects the new
root key until it updates. The positive conformance generator opts out, so
the frozen archives keep their manifests (WP-20). -
Validators now check that a
reaction.waypointstrajectory_refnames a
trajectorysection, as spec § 6 already required, not merely an existing
one (E_REF_UNRESOLVED, WP-20). -
set_provenance(Python and C++, so alsoqvf_set_provenance_json) and
add_job_speccheck the typed fields they write and refuse a wrong value
(ValueError,std::runtime_error, a non-zero C return) before anything
changes; the C++set_provenancenow also refuses a provenance that is not
a JSON object. Both Python writer checks match whole strings, so a time
stamp or hash with a trailing newline is refused (WP-27). -
Trajectory writers check every member before writing: Python
add_trajectorywrites float32coordswhen the metadata already names
precision: "float32", and refuses a lattice withoutpbcor a periodic
pbcwithout a lattice; Python and C++add_reaction_pathkeep float64
coordinates and refuse a metadataprecisionof"float32"; C++
add_trajectoryaddsprecision: "float32"for float32 coordinates and
refuses raw metadata that does not parse. Validators now enforce that
metadata.precisionagrees with the dtype ofcoords, as spec § 5.5
already required (WP-26). -
Both reference writers write
manifest.jsonlast (still STOREd), after the
members, as spec § 2.1 recommends; it used to be the first entry. The C++
write(path)streams the archive to the file instead of building it in
memory, and a 32-bit archive's ZIP encoding is unchanged byte for byte.
The C++ ZIP writer sets the UTF-8 flag (bit 11) for non-ASCII entry names
(WP-40). -
The C++ reader verifies each entry's CRC-32 and that its local header names
the same entry as the central directory (as the Python and JavaScript
readers do), reports both asE_ZIP_UNREADABLE, and applies every
Limitscap (member and total size, ratio) to member reads. Its inflater
rejects DEFLATE streams zlib rejects too (a stored block whose length check
fails, more than 286/30 codes, a code-length repeat past the end, no
end-of-block code).
QvfReader::openandvalidate_fileread from the file on demand instead
of loading it whole (WP-40). -
Spec § 5.3 now says what
mo_metadata.state_refrefers to for natural
transition orbitals (it was "not yet specified"), and the writers'
add_spectrumrefuses a one-dimensional payload whosestates_refnames no
excited_statessection already added (WP-22). -
Spec § 9 item 5 (Cartesian shells) now points producers at the
overlap
check. The Python and C++add_wavefunction_gtorefuse coefficient
matrices whose AO extent is not the basis'sn_ao(2n_aofor
generalized), and check everything before writing anything; a
generalizedmo_metadatawithoutcomplex: truenow fails the schema
(E_PAYLOAD_SCHEMA), a layout no archive could use before (WP-23). -
The finding code
E_ROOT_INCONSISTENTnow also covers a section that
restates a root block: aproperties.electricdipole that differs from the
rootdipole_moment. The code is not renamed (spec § 3.3, § 5.13,
Appendix B; WP-29). -
The C++ and JavaScript validators run the JSON Schema by default, so an
archive that only the schema rejects (for examplebyte_order"big"or a
payload outside its definition) is now invalid to them, as it already was
to the Python validator withjsonschema; their negative-corpus runners
hold the schema-only expectations and compare the other codes exactly.
The C++ reader's refusal of abyte_orderother than"little"now starts
withE_SCHEMA:(WP-41). -
qvf::Unit,unit_name(),parse_unit()and the canonical kinds come from
the generatedqvf/kinds_generated.hpp(qvf/units.hppre-exports the unit
names; enumerator names are unchanged),qvf::Sourcemoved to
qvf/model.hpp(still included byqvf/qvf.hpp), andqvf_reader's
canonical kinds, payload definitions and finding codes andqvf_units's
vocabulary come fromqvf_kindsinstead of hand-kept copies and a schema
read at import. A new payload definition is wired to its(kind, role)in
PAYLOAD_DEFSofscripts/gen_kinds.py. The C++ JSON parser now joins an
escaped surrogate pair into one code point (WP-41).
Download Source code (zip) or Source code (tar.gz) under Assets. These are source archives, not prebuilt installers; follow the included installation instructions. Managed Git-based installers need a clone checked out at this tag.
Documentation: https://vibe-qc.com/ · Desktop downloads: https://vibe-qc.com/download/