Auditable log of TM-Spec design decisions. Each decision references an authoritative source (or explicitly marks original semantics).
Format:
D-NN | <date> | Decision | Source | Breaking?
Marzari-Vanderbilt → marzari-vanderbilt. Also gaussian, fermi, methfessel-paxton, tetrahedra — all lowercase.Run.method.smearing.kind convention [CLAIM, runschema plugin].plane_waves primary, PW aliasbasis.kind: plane_waves (NOMAD primary); aliases allowed: PW, pw.Run.method.basis_set enum.xc: PBE+D3(BJ) (human-readable primary); add optional machine fields:
xc_libxc: [GGA_X_PBE, GGA_C_PBE]vdw: D3-BJpbc: [bool,bool,bool]. Add optional computed fields:
lattice_vectors_A: [[ax,ay,az],...] (Cartesian Å)dimension_types: [0|1, 0|1, 0|1]chemical_formula_descriptive, _reduced, _anonymouswyckoff: {Fe@2a: [...]} (human, science-readable). On export, expand to species_at_sites + cartesian_site_positions.defects.reactions[]: "Fe_Fe^× → V_Fe'' + ..." as primary (human). Add machine layer:
defects:
objects:
- { name: v_Fe, kind: vacancy, site: ..., charge: -2, multiplicity: 1 }
- { name: H_i, kind: interstitial, site: ..., charge: +1, multiplicity: 2 }
v_Fe, H_i, Cu_Zn [FACT].magnetic.state: AFM-G | AFM-A | AFM-C | FM | ferri | NM | PM-itinerant. Add optional magnetic.bns_group: "P_b 4'/n m m'" for magCIF export.T: 363.15 K. Optional computed temp_C: 90 for PHREEQC export.temp keyword = °C [FACT, USGS docs verified].redox.Eh: -0.40 V_SHE. Optional redox.pe_derived: -6.8 (computed via Nernst).pe, but Eh is more natural for electrochemistry.composition_molal: { Fe(2): 1.0e-3, S(-2): 5.0e-4 } — exact match of PHREEQC element-valence notation. Default unit = mol/kgw (PHREEQC default), explicitly encoded via _molal suffix.reactions[].rule (human). Export tooling spec tm-spec → antimony:
→ → ->, ⇌ → <->H_aq^+ → H_aq, (H–Fe)_Fe^× → H_Fe_x[X] → X, θ → theta_tm.mack.vfe.hint.smoke@2026-05-03). On export → AiiDA UUID + LinkType enum (INPUT_CALC, INPUT_WORK, CALL_WORK, …).status: PASS | PRELIMINARY | FAIL | RETRACTED. emmet state: successful/unsuccessful/error — partial mapping on export.paper_quotable: bool + quote_constraint extensionpaper_quotable: bool as a first-class field. Refinement (D-19 follow-up): for partial cases (lower bound, upper bound) add a separate optional field quote_constraint: lower_bound_only | upper_bound_only | point_estimate | range_only. This keeps paper_quotable a clean boolean and adds an orthogonal dimension “how exactly to cite”.sanity[].pass: true | false | "warn" | "skip".
true/false — gate passed successfully / failed."warn" — gate flagged an anomaly that is not blocking (US T_drift, WHAM convergence)."skip" — gate not applicable to this kind (US does not check AFM because MLIP does not enforce magmom).provenance.compute.cost_usd: { value: 47.30, approx: false } or simply 47.30 for exact values; ~4 (string) — deprecated. Schema requires a number.cost_usd: ~4; fix to cost_usd: 4.0.calculation.method: MLIP, use backends[] array (not level):
```yaml
backends:
NEBCalculation — endpoints + path + EaUSCalculation — windows + WHAM + PMFMetaDynCalculation — hills + FES + bias_factor (implemented in D-19)MDCalculation — plain MD without bias (v0.2)MLIPBenchmark — multi-method comparison (v0.2)kind: MetaDynCalculation with three required sections:
cv_definition — reused from USCalculation (same CV semantics).metadyn_protocol (NEW) — variant (well_tempered/standard/tigersaw/frequency_adaptive), hill (height + width + freq), bias_factor (γ + effective_dT), wall (type/position/k), monitoring (3-phase).fes_analysis (NEW) — FES reconstruction method (WT_reweighting / direct_integration / Tiwary_Parrinello / WHAM), grid (with bounds + coverage flag), wall_correction (for post-hoc math fix), convergence (target + achieved boolean).$defs/results_metad with delta_F_dagger_eV: object (multiple estimates: apparent / extended_grid / wall_corrected_LB / extrapolated_2sigma) + cross_validation_eV (vs other methods) + quote_constraint (D-14 extension).G17_grid_coverage — FES grid covers CV_max + 3σ (bug #1 catcher)G18_wall_position — wall.position > max(initial_CV) (bug #2 catcher)G19_wt_convergence — block window analysis targetG20_no_grotthuss_exchange — CV(tracked_H) stays > threshold (CV proxy validity)G21_phase1_no_hot_start — T_mean steps 1-10 < 320 KG22_phase2_no_T_drift — |
T_slope | < 5 K/ps |
G23_hill_units_explicit — WW unit specifier present (CP2K Hartree gotcha)G24_wall_correction_applied — if wall sampled, F_real - V_wallkind: MDCalculation for plain MD (not enhanced sampling). Required sections: md_protocol (ensemble + thermostat + timestep + duration), results (results_md). Optional trajectory_analysis (msd, rdf, vacf, hbond_lifetime, diffusion_coefficient, grotthuss_hops, speciation).examples/w1_grotthuss_aimd.tm.yaml.kind: MLIPBenchmark for cross-method comparison (not a description of a single run, but a comparison across backends ± DFT reference). Required: benchmark_setup (reference + test_systems + test_observables), metrics (Ea_RMSE, abs_diff_saddle, frac_correct_basin etc.), results (results_mlip_bench with per_backend + verdict).examples/w2_mlip_benchmark.tm.yaml. Distinct from w2_us_pmf.tm.yaml (that file describes the run EVENT; this file describes the ANALYSIS comparison).nspin=1, U=0 for mack/pent/pyr) is community mainstream 2014-2026; no justification is needed in the paper. Tier 1 AFM+U=2 sensitivity (if included in SI) uses U=2, not U=4 (literature standard: Devey 2009 / Williams 2022 / Safeer cRPA 2026).state: AFM-G + U=4 to state: NM + U=0 (correctly reflects the production script).starting_magnetization ±2.5 μB (not ±1.0) — avoids FM collapse.Concept: TM-Spec → executable Python script via recipe template engine. Inverse tm_spec_extract.py.
Architecture:
# New block in TM-Spec (optional):
recipe:
name: canonical_neb_qe_vacancy_hop
version: 1.0
runtime: native # see Q-TMSPEC-10
overrides:
hop_mode: diagonal
pseudo_dir: /opt/pp/oncv_pbe
Do NOT encode algorithm logic in YAML (Turing-complete trap). Only pointer + parameters.
Recipe registry structure:
tools/tm_recipes/
├── canonical_neb_qe_vacancy_hop.py
├── canonical_neb_qe_vfe_proton_pair.py
├── plain_md_cp2k_aimd.py
├── us_pmf_mlip_native.py
├── wt_metad_cp2k.py
└── _builders/ # shared functions: pick_triple, prewrap, place_h
Each recipe is a Python class with render(doc) → str (jinja2 or f-strings) → ready-to-exec script source.
Orchestrator workflow (runtime.execute_tm_spec(yaml, instance)):
tm_spec_validator)name@versiontm_spec_sanity_fill)Benefits:
tm_spec_export_nomad → ZIP → upload (full pipeline)Pitfalls:
recipe.overrides.custom_python — last resort, document in notes)recipe.requirements or Docker tagPoC plan (~3 hr):
recipe block to schema (optional, 10 min)canonical_neb_qe_vacancy_hop (port neb_canonical_pyr_96at_qe.py, 90 min)tools/tm_spec_to_script.py generator (30 min)execute_tm_spec() (30 min)Status: [DEFERRED] — after paper #1 submission. Recipe registry is a medium-term investment; payoff after 5+ submissions.
Question: should we reuse AiiDA WorkChains / atomate2 Makers as backends for recipes?
Reality check (analysis 2026-05-10):
| Backend | Reusable for | NOT reusable |
|---|---|---|
AiiDA + aiida-quantumespresso/aiida-cp2k |
Standard relax/NEB/MD WorkChains; native provenance graph; aiida-nomad upload |
ASE issue #1130 fix; custom triple picker (diagonal mode); MLIP US PMF; ephemeral cloud GPU (requires permanent host for daemon + Postgres + RabbitMQ) |
| atomate2 Makers | Pydantic-typed input sets; emmet TaskDoc compat; Maker pattern as design inspiration | NEB Maker still in development 2026; VASP-biased (~80%); not for CP2K WT-MetaD / MLIP US |
Decision: hybrid runtime — TM-Spec supports multiple backends via recipe.runtime:
native (default) — our registry, ASE scripts. For ephemeral cloud GPU + custom patches + MLIP US (~80% of our cases).aiida — TM-Spec → AiiDA WorkChain inputs converter. For standard recipes on a permanent host when full provenance graph is desired.atomate2 — for future VASP work (currently 0%).What is worth adopting (without full reuse):
LinkType enum on export (INPUT_CALC, INPUT_WORK, CALL_CALC, CALL_WORK, CREATE, RETURN).aiida-common-workflows input conventions — standard keys for cross-code workflows (relax, eos, bands). Use as inspiration for recipe.overrides naming.aiida-nomad upload mapping — cross-check with our tm_spec_export_nomad.py; align mappings (we have it; reuse validation logic).Status: [DEFERRED]. Native backend covers paper #1 submission. AiiDA wrapper — v0.5 if demand arises (e.g., reviewer requests a full AiiDA provenance archive).
Question: are we competing with industry standards (AiiDA) or finding a complementary niche?
Landscape analysis: see landscape.md for a detailed table (10 tools).
Closest competitor — AiiDAlab QE (https://github.com/aiidalab/aiidalab-qe). Web app on top of AiiDA for declarative QE input. Addresses the “scientist without Python” use case, but: web app (not git-tracked text), QE-only, AiiDA daemon required.
Decision: complementary positioning, not head-to-head competition.
4 niches where TM-Spec can claim a position:
Strategic recommendations:
Precedents (how small declarative formats became standards):
requirements.txt (~5 years to standard)Dockerfile (5 years, conquered industry)schema.org JSON-LD (via Google adoption)citation.cff (~3 years, GitHub native support)All grew from: simple text + tool ecosystem + early adopters. TM-Spec already has the first two.
Main risk: over-scoping to a scale we cannot sustain (AiiDA-killer → failure; narrow Fe-S DSL → may work).
Status: [DECIDED] — complementary positioning. Paper #1 submission = test case for niche validation.
Question: should we use atomate2 Pydantic input sets (e.g. MPRelaxSet, NEBSet) as a type-checked structure for recipe.overrides?
Pros:
Cons:
MPRelaxSet uses INCAR keys: ENCUT, LDAUU); for QE pwscf these keys are irrelevant — a QESet is needed (not available in atomate2).pip install atomate2 (heavy: pulls jobflow, pymatgen, custodian).Alternative: a minimal in-house Pydantic layer (pydantic is already in our dependencies via FastAPI/etc). Simple dataclass-like models for each recipe.
Decision (preliminary): in-house Pydantic layer for recipe.overrides validation, but adopt naming conventions from atomate2 (e.g., relax_set.encut_ry, not cutoff_wfc). For cross-code consistency.
Status: [DEFERRED] — resolved at PoC implementation stage of Q-TMSPEC-9.
MLIPBenchmark.tm-spec → qcschema exporter feasibility (no QCSchema NEB analog exists).runschema plugin field names required).supercell: [3,3,1] field, but cell-specific overrides for defects/magmoms may be needed.