Expand description
gugen (具現): explainable materials synthesis and process planning.
This crate turns a target inorganic composition (and optionally a target
structure) into candidate precursor sets, balanced reactions, and
solid-state process plans — each with its evidence, assumptions, and
unresolved conditions kept explicit. It does not predict experimental
success. See docs/scientific_scope.md for what is and is not in
scope, and CHANGELOG.md for the user-facing capability list.
This implements typed errors, validated numeric types, composition,
target specification, the public report schema, provenance, provider
trait boundaries, exact
reaction balancing, bounded precursor-set search, a solid-state process
template, plan scoring/confidence, end-to-end orchestration via
Planner, an optional mikiwame structural-diagnostics adapter, a
CLI (src/bin/gugen.rs: plan, balance, explain, validate-target,
doctor, batch), a validation suite against curated literature
fixtures (tests/, docs/benchmark_report.md), and v0.1 release
preparation (license files, docs.rs metadata, a dependency license
audit — see tasks/todo.md’s Phase 9 section). The chematic-crystal
adapter remained blocked on that crate’s publication through v0.1
(Phase 16 below addresses part of this), and two
validation findings are documented rather than fixed (see
tasks/todo.md’s Phase 8 section). v0.1.0 is published (crates.io,
merged to main, tagged v0.1.0) — see tasks/todo.md’s Phase 9
section for the release record. Post-v0.1 development toward v0.2.0
(Phase 10-14 — real literature-sourced process conditions, a
large-scale blind benchmark, a second route family, a thermodynamic-
provider adapter boundary, and a validation-fixture citation repair) is
tracked from tasks/todo.md’s Phase 10 section onward, not AGENTS.md
§26 (which only defines the original 9 phases). v0.2.0 is published
(crates.io, tagged v0.2.0). Work toward v0.3.0 has begun with Phase
15A (route_suitability module): a report-level evidence model for
whether a route family suits a target (Supports/Contradicts/
Unknown findings, never an aggregated score). Phase 15B added
derive_recommendation, a pure function deriving a discrete
RouteRecommendation from that evidence, and wired only its
NotRecommended state into Planner::plan: a plan with strong,
uncontested contradicting evidence is moved from plans into the new
SynthesisPlanningReport.not_recommended (kept, with its findings, not
dropped), and a target where every generated plan is excluded this way
abstains explicitly via unresolved rather than returning an empty
success. No numeric score is affected by either phase. Phase 16 added
an optional chematic_crystal feature: to_mikiwame_structure
converts a caller-supplied chematic_crystal::PeriodicStructure (now
published, 0.15.0) into a mikiwame::OwnedStructure, closing the
specific conversion gap the mikiwame adapter had named since Phase 6.
Still not auto-wired into Planner::plan – TargetSpecification has
no geometry field, so a caller still applies the result themselves.
Phase 17 audited how much literature evidence for route suitability
actually exists in a real synthesis corpus, and evaluated
derive_recommendation against a hand-verified holdout record –
explicitly not a route-family prediction-accuracy benchmark (see
docs/route_suitability_corpus_audit.md); no production code changed.
Phases 15A/15B/16/17 together are v0.3.0’s planned development work.
v0.3.0 is published (crates.io, tagged v0.3.0). Post-v0.3.0
development toward v0.4.0 added finite-temperature Gibbs-energy
estimation for gas-free solid systems (Phase 19P/19P.1), deliberately
not connected to ranking (thermodynamic_support stays None); a
bulk literature-corpus snapshot loader and exact-match observation
provider (Phase 20B); cross-DOI field comparison across independent
sources for that corpus (Phase 20C); a manual extraction-accuracy
audit against original source papers (Phase 20D); and Integration,
which surfaces that cross-DOI evidence on
SynthesisPlan.literature_evidence for reference-only display –
never auto-filling ProcessStep conditions and never affecting
score/confidence/ranking. Together these are v0.4.0’s planned
development work: gas-free solid finite-temperature thermodynamic
primitives, a bulk literature observation snapshot API, cross-DOI
agreement/conflict classification, and reference-only literature
evidence in Planner – an evidence-infrastructure release, not a
ranking-accuracy or synthesis-success-prediction claim.
v0.4.2 is published (crates.io, tagged v0.4.2) – adds the
optional, off-by-default commercial_catalog feature (Commercial
Precursor Catalog: matches an existing SynthesisPlan’s precursors
against a caller-supplied catalog of commercial offers, as
post-planning processing that never affects the plan’s score,
confidence, reaction, or process steps). Phase 23 (v0.5.0) is a
breaking, core-API-hardening release, independent of the commercial
catalog work: BalancedReaction/ReactionSpecies close a
validation-bypass gap (private fields, a required element-
conservation check, Phase 23A); Planner::builder(...) covers any
combination of the 4 optional providers, deprecating the 5 named
constructors that didn’t (Phase 23B); the existing provider-call
dedup extends to ProcessEvidenceProvider::precedents (Phase 23C);
and 5 enums are marked #[non_exhaustive] where their own doc
comments already anticipated new variants, alongside a new
docs/api_stability_policy.md (Phase 23D). v0.5.0 is published
(crates.io, tagged v0.5.0). Phase 24 makes the commercial-catalog
feature (v0.4.2) usable by a researcher directly, not just from Rust
code: a gugen commercial-plan CLI subcommand (24A); declarative
CSV column-name mapping for real-world supplier exports via
CommercialCatalogColumnMap (24B); and named procurement ranking
policies via CommercialRankingPolicy (Balanced/CostFirst/
LeadTimeFirst/PurityFirst/MinimumUnresolvedData/Pareto, 24C).
Phase 25 adds SynthesisExecutionRecord: an append-only, versioned-
schema record of what actually happened when a gugen-proposed plan
was attempted in a real lab, structurally separate from Planner/
score_plan by construction. Phase 26 surfaces those records back
during planning as reference-only PriorExperimentEvidence on
SynthesisPlan (a new 5th optional provider,
PlannerBuilder::prior_experiment_evidence_provider(...)) – same
display-only discipline as the existing literature-evidence
integration: never a success rate, never fed into score,
confidence, or ranking. v0.6.0 is published (crates.io, tagged
v0.6.0).
Phase 31 adds SynthesisRoute/search_two_step_routes:
validated, stoichiometrically connected two-step (precursor →
intermediate → target) routes for targets a one-step search can’t
reach within budget – a primitive, not an accuracy claim;
intermediate_candidates is always caller-supplied and Planner
never invokes this automatically. The same phase’s real-corpus
testing found and fixed a spurious identity-reaction acceptance bug
in search_precursor_sets (a candidate matching a
curated_byproducts() composition exactly could be accepted as a
no-op unrelated to the target). An optional, explicitly experimental
experimental_grammar feature (default off) adds hand-written
intermediate-candidate decomposition grammars
(transformation_grammar module); measured against the same
corpus, they did not recover any target beyond a plain
corpus-frequency prior, so this is not yet promised-stable API.
v0.7.0 is published (crates.io, tagged v0.7.0).
v0.8.0 is a bug-check-and-refactoring sweep: SolidThermodynamicEntry’s
two numeric fields are now private (closing the same validation-bypass
gap Phase 23A closed for BalancedReaction/ReactionSpecies –
breaking), HydroxideToOxideGrammar’s missing metal-presence guard is
fixed, and process.rs’s condition-conflict-resolution code moved to
condition_precedents.rs (no public API change). See CHANGELOG.md
for the user-facing summary.
Structs§
- Accepted
Precursor Set - One accepted candidate plan: which precursors, and the balanced
reaction that resulted (AGENTS.md §10’s byproduct handling is folded
in here –
reactionmay include a curated byproduct the search had to introduce to make the elements balance). - Acid
Carbonate Phosphate Grammar 2 H3PO4 + M2CO3 -> 2 MH2PO4 + CO2 + H2O, restricted to phosphoric acid (exact H:P:O = 3:1:4 signature, no other elements) paired with a monovalent-metal carbonate (exact M:C = 2:1, no hydrogen, and an exact O:C = 3:1 – deliberately stricter thanCarbonateToOxideGrammar’s own carbonate check, which accepts O:C >= 3:1 to also correctly handle oxycarbonate-like compositions with extra oxide oxygen beyond the carbonate group; this grammar produces a fixed-formula guess rather than a pure mass-balance derivation, so the tighter, exact signature is the safer choice here). The proposed composition is always the fixed monobasic-phosphate formula unitMH2PO4, independent of the pair’s actual relative amounts (matching every other grammar here: a formula-unit-shaped candidate, not a balanced-reaction claim). Does not attempt di-/tri-basic phosphate salts, does not handle divalent/trivalent carbonate metals, and does not generalize to other oxo-acids despite the “acid+carbonate” pattern – narrowed deliberately to the one real case this grammar is modeled on (DOI 10.1016/j.tca.2014.08.028, see this phase’s own doc).- Actual
Precursor Amount - What was actually weighed for one precursor. Deliberately not
process::MaterialAmount– that type’sformula_units: u64is required andmass_gramsoptional, the right shape for a planned amount computed from stoichiometry; a lab log needs the reverse emphasis, since an operator weighs grams, not formula units. - Actual
Process Step - One real process step actually performed.
planned_step_indexis the position of the corresponding step inSynthesisPlan.steps, when this step corresponds to one gugen proposed –Nonefor an ad-hoc step the operator performed that wasn’t in the plan (itself worth aDeviation { category: DeviationCategory::SequenceDeviation, .. }). - Applicability
Assessment - Availability
Metadata - Minimal placeholder for provenance about where/whether a precursor is obtainable. AGENTS.md §9 lists availability as a filter candidate but doesn’t specify a shape; kept intentionally small until a real provider exists. Missing availability must not block a precursor from being used – it’s a gap in metadata, not evidence the compound is unavailable (AGENTS.md §21.2’s “availability metadata欠損” test case).
- Balanced
Reaction - An element-balanced reaction with integer, gcd-normalized coefficients (AGENTS.md §10). The exact-rational null-space solver that produces these from a target/precursor set is Phase 2 work (docs/architecture.md); this type is the Phase 1 foundation it returns into.
- Candidate
Generator Ensemble - Combines multiple
CandidateGenerators into one candidate list via min-rank fusion, and implementsPrecursorCatalogitself – so an ensemble is a drop-inPlanner::buildercatalog argument, requiring zero changes toPlanner/PlannerBuilder. PR 1 does not wire this intoPlanner; every measurement in this PR calls the ensemble directly, the same way every existing exploration-recall benchmark already bypassesPlannerand callssearch_precursor_setsdirectly. - Carbonate
ToOxide Grammar MCO3 -> MO + CO2(per carbonate carbon: -1 C, -2 O, all other elements unchanged). Narrowed to compositions with no hydrogen, deliberately excluding bicarbonates and other mixed H+C+O species rather than guessing which decomposition applies to them.- CasNumber
- A CAS Registry Number as supplied by a catalog row.
checksum_verifieddistinguishes “checksum verified” from “checksum failed or the string isn’t CAS-shaped at all” – Phase 22 never uses CAS as a basis for chemical-identity matching (composition is), so a malformed CAS is recorded, not rejected. - Catalog
Exact Generator - Wraps an existing
InMemoryPrecursorCatalogas aCandidateGenerator– “exact” means literally whatever the catalog returns, in its own element-overlap-filtered order, stamped with rank = output position. Near-zero new logic: reusesInMemoryPrecursorCatalog’s existing filter/sort/dedup verbatim rather than reimplementing it. - Commercial
Catalog Column Map - A declarative mapping from gugen’s canonical CSV column names (e.g.
formula,manufacturer) to the header names an actual supplier’s export file uses (e.g.Chemical Formula,Supplier) – letsCommercialPrecursorCatalog::load_csv_with_column_mapaccept non-standard headers without inventing per-manufacturer adapters. Only the columns that differ need an entry; anything omitted is looked up under its canonical name as usual. - Commercial
Catalog Load Report - Commercial
Combination Serializeonly – seeCommercialOfferSelection’s doc comment (selectionstransitively carries its&'static strfields).- Commercial
Exclusion - Commercial
Offer Id - Commercial
Offer Selection Serializeonly, deliberately noDeserialize:unresolved_fieldsisVec<&'static str>, which cannot deserialize into a non-'staticborrow from an arbitrary input buffer (the general reason every&'static str-bearing type below is Serialize-only, matching this crate’s existing precedent for output-only report types –reaction.rs/process.rs/thermodynamics.rs/score.rs).- Commercial
Plan Assessment Serializeonly – seeCommercialOfferSelection’s doc comment (combinations/unresolved_commercial_fieldstransitively carry&'static strfields).- Commercial
Planning Config - Commercial
Planning Request - Commercial
Precursor Catalog - A loaded, deduplicated commercial-offer catalog.
offersis private (unlikeSynthesisPlan’s all-pubconvention):offer_iduniqueness is a real invariant this type guarantees – it is what makes the combination search’s final tie-break key total. - Commercial
Precursor Offer - Commercial
Warning - Its own type (not a reuse of
PlanningWarning), deliberately – keeps this module’s return type structurally separate from anythingscore_plancould ever consume, reinforcing at the type level that commercial data can never leak into scientific scoring. - Competing
Phase - A candidate phase’s formation energy, offered for context alongside a
BalancedReaction– e.g. “would this target’s elements more readily form some other known compound instead” (Phase 13,ThermodynamicProvider::competing_phases). Additive toThermodynamicProvider, not toReactionEnergy: that type’s own doc comment forbids growing unrelated fields onto it specifically, but says nothing against a sibling type for a genuinely different quantity. gugen does not compute a selectivity/likelihood score from this data (AGENTS.md §4.3) – it is surfaced only asPlanningEvidence. - Composition
- An elemental composition: element -> stoichiometric/formula amount.
Amounts must be finite and strictly positive; the composition must
contain at least one element. Iteration order is always by element
symbol (via
BTreeMap), so results built from aCompositionare invariant to the order elements were supplied in (AGENTS.md §21.4). - Condition
Conflict - Condition
Precedent - One provider’s structured, citable evidence for how a specific
Heatstep’s conditions should be resolved (Phase 10; AGENTS.md §7/§21.3). Every field the provider doesn’t actually have real, sourced data for staysNone– never fabricated to fill a gap.evidence_kind,strength, andsource_idare set by whichever provider returns this, not assumed by the planner:ProcessEvidenceProvideris also the trait a user-supplied lab-precedent source implements (EvidenceKind::UserProvidedPrecedent), so a curated-literature-only assumption in the planner would mislabel provenance for every other kind of implementation. - Confidence
Assessment - AGENTS.md §16, verbatim. Kept as four independent dimensions rather
than collapsed into
overall, specifically because a reaction can be stoichiometrically certain while its process conditions are completely unresolved (“条件未確定でも反応式が確実なケースがあります。単一 confidenceに潰さないでください”). - Corpus
Heating Observation - One reported heating operation from the literature corpus: a target,
the precursor set used to reach it, and whatever this operation’s
temperature/duration/atmosphere conditions resolved to –
Nonefor any field the source paragraph didn’t report, or reported ambiguously (see the module doc comment). Never carries aHeatingPurpose– see this module’s doc comment for why that is structural, not conventional. - Corpus
Manifest - Identifies the snapshot file itself – source corpus, the offline
build’s own release/checksum, and gugen’s schema version.
checksumandreleaseare informational provenance only: gugen never has access to the original upstream corpus file to verifychecksumagainst, so it is recorded, not independently re-verified.record_countis actively checked at load time (must equal the actual number of observation entries in the file), since that catches a truncated or corrupted snapshot cheaply without needing the upstream source at all. - Curated
Condition Record - One hand-verified literature condition record (AGENTS.md §21.3: never
authored from memory).
target/precursor_idsidentify which route this applies to;conditionscarries the actual per-step temperature/ duration/atmosphere data, each traceable to a real citation via its ownConditionPrecedent.source_id. - Curated
Suitability Record - One hand-verified route-suitability record (AGENTS.md §21.3: never
authored from memory). Keyed on
(target, route_family), not on a precursor set – unlikeCuratedConditionRecord(literature_conditions.rs), suitability doesn’t depend on which precursor combination was chosen. - Currency
Code - A 3-letter uppercase ASCII currency code. Format-validated only, not a
full ISO 4217 whitelist: unlike
Element(which must reject typos against a closed table because the crate needs to refuse invalid symbols outright), the only thing this module’s arithmetic needs from a currency is “is this the same currency as that one” – format validation plus preventing cross-currency summing satisfies that without a table that would go stale. - Decomposition
Comparison - One named alternative assemblage compared against a target, and the
resulting margin – the
decomposition_margin_ev_per_atomresult paired with the caller’s own free-text label for what it compared against (e.g."BaO + TiO2"), since the raw function alone has no way to say whatalternative_assemblagewas once collapsed into a singleOption<f64>. - Deduped
Proposal - A composition proposed by one or more grammars, after
propose_alldeduplicates identical compositions across grammars and retains every contributing grammar’s id. - Deviation
- Duration
Range - Element
- A validated element symbol. Construction is the only way to get one, so
every
Elementin the crate is guaranteed to be a real periodic-table symbol. Matching is case-sensitive ("Co"cobalt vs"CO", which is not a valid symbol at all) — a catalog or fixture file using non-standard casing will fail to parse rather than being silently reinterpreted. - Ensemble
Output - Combined output of every generator in a
CandidateGeneratorEnsemblerun, per design principle 5 (every branch/provider outcome stays distinguishable, never silently dropped):candidatesis what aPrecursorCatalogcaller (e.g.search_precursor_sets) actually consumes,provenancekeeps every generator that proposed each id, andgenerator_errorskeeps every generator that failed outright, labeled by which one. - Execution
Characterization - Facts about the resulting material, as measured/reported – every field
left
Nonewhen not actually measured, never guessed. Plainf64, notcommercial_catalog::PurityFraction: that type only exists behind the optionalcommercial_catalogfeature, and this module is deliberately feature-independent (seeSynthesisExecutionRecord.selected_commercial_offers’s own doc comment). - Execution
Provenance - What “provenance mandatory” requires at minimum for a record entered by a human after a real lab experiment, not generated by the deterministic core.
- Execution
Record Load Report - Frequency
Prior Generator - Proposes precursors ranked by a caller-supplied frequency table –
never computed or bundled by this crate itself, matching the
established “caller supplies the data, core never fetches/bundles it”
convention (
ThermodynamicProvider/MaterialsProjectSnapshotProvider’s own precedent). A caller can build the table from anything: their own literature database,LiteratureObservationCorpus, or a benchmark’s own precursor-formula counts. - Generated
Candidate - One precursor candidate as proposed by exactly one generator. This is
where “full provenance” actually lives – deliberately a wrapper type,
not a field added to
PrecursorCandidate(not#[non_exhaustive], adding a field there would be a breaking change).rankis a plain ordinal (0 = the generator’s own top pick), never a float/confidence: a generator’s internal priority can never be read as a success probability, because the type has no score field to misuse (mirrorsSearchPriority’s own score/priority separation,src/precursor.rs). - Generator
Id - A generator’s stable identity, stamped onto every
GeneratedCandidateit produces and used to label a failedgenerate()call inEnsembleOutput::generator_errors. A string newtype rather than an enum: PR 1 only populates 2 of the eventual 6 named generators, and an enum with unbuilt variants would force a premature#[non_exhaustive]decision the crate’s own API stability policy reserves for types whose doc comment already states a growth expectation. Adding generator #3 later never forces a semver decision this way. - Grammar
Id - A grammar’s stable identity, stamped onto every
ProposedIntermediateit produces. A string newtype, not an enum – same rationale asGeneratorId(src/candidate_generator.rs): only 4 of an open-ended family are implemented here, and an enum with unbuilt variants would force a premature#[non_exhaustive]decision. - Hydroxide
ToOxide Grammar M(OH)n -> MO(n/2) + (n/2) H2O, identified by an exact O:H = 1:1 ratio (every OH- group contributes exactly one O and one H). Narrowed to compositions with no carbon, to avoid confusion with hydrated carbonates or other mixed C+O+H species. Requires at least 3 distinct elements (metal + O + H), matchingCarbonateToOxideGrammar’s ownlen() < 3guard – without it, a metal-free 2-element O:H=1:1 composition (e.g. H2O2) would pass this grammar’s own ratio check and produce a bare-oxygen “proposal” with no metal for the claimed hydroxide-decomposition mechanism to apply to (the same missing-guard bug classNitrateToOxideGrammar’s own hydrogen exclusion was added to close, for HNO3).- InMemory
Execution Record Provider - The one real
PriorExperimentEvidenceProviderimplementation this crate ships: an in-memory index over a caller-suppliedVec<SynthesisExecutionRecord>(already parsed by the caller, e.g. viaparse_execution_records– this type performs no file I/O and no JSON parsing itself). MirrorsLiteratureObservationCorpusProvider’s own architecture: grouped once at construction into aBTreeMapkeyed by the exact identity triple (Compositiondoesn’t deriveHash, soBTreeMap, notHashMap, is required here, same constraint that provider has). - InMemory
Literature Condition Provider ProcessEvidenceProviderbacked by a small, hand-verified set of real, cited firing conditions (Phase 10), expanded from the same 5 literature-cited routestests/validation.rsalready uses for precursor-set recovery. Not a general literature-mining pipeline: that’s a different trust tier (bulk statistical corpus vs. individually verified citable evidence), left to a future large-scale benchmark rather than mixed into this small, hand-checked set.- InMemory
Precursor Catalog - In-memory
PrecursorCatalog(AGENTS.md §8: in-memory/JSON/fixture providers are the v0.1 priority, no network access). Candidates are kept sorted byPrecursorIdregardless of construction order, socandidates_forresults – and everything built on them – are invariant to catalog insertion order (AGENTS.md §21.4). - InMemory
Route Suitability Provider RouteSuitabilityProviderbacked by a small, hand-verified set of real, cited findings (Phase 15A, expanded once since). Deliberately minimal: this is still not a comprehensive suitability database – see this module’scurated_records()doc comment for what each record proves and what’s intentionally deferred.- Kelvin
- A validated temperature within the range Bartel et al. 2018 actually
validated the SISSO descriptor against,
[300.0, 1800.0]K (deliberately narrower than pymatgen’s[300.0, 2000.0]K – see this module’s doc comment). - Literature
Observation Corpus - A loaded, deduplicated, deterministically-ordered snapshot of the
corpus, queryable by exact target and exact precursor set. Does not
implement
ProcessEvidenceProvideror any other Planner-facing trait – see the module doc comment for why that connection is structurally unavailable, not merely unwired. - Literature
Observation Corpus Provider - Adapts
LiteratureObservationCorpus::cross_doi_comparisonsto the ungatedLiteratureEvidenceProvidertrait. Computescross_doi_comparisons()exactly once, at construction time, and indexes the result by route – a per-planroute_evidence()call is an O(log n)BTreeMaplookup, never a fresh corpus-wide pass. This is what makes calling it once per candidate plan (asPlanner::plandoes) affordable; measured for real inexamples/literature_evidence_integration_report.rs. - Literature
Route Evidence - A
RouteObservationAssessmentplus the disclosures a consumer needs to not overread it – whatPlannerattaches to aSynthesisPlanwhen aLiteratureEvidenceProvideris configured and finds matching evidence for that plan’s exact route. Reference-only: never auto-applied toProcessStepconditions, never fed toscore_plan, never converted to aConditionPrecedent. - Load
Report - What happened during a
LiteratureObservationCorpus::loadcall. A complete accounting of the input:accepted + rejected.len()always equals the snapshot’sobservationsarray length – every input record either parsed successfully (contributing toaccepted) or didn’t (contributing torejected), mutually exclusively.duplicates_collapsedis not a third disjoint count on top of those two – it’s a subset breakdown withinaccepted, counting how many of the successfully-parsed entries were then found to be duplicates of another and collapsed.accepteditself is counted before deduplication (how many entries parsed successfully at all) – it is deliberately not the same number as the final loaded corpus’s ownlen(), which isaccepted - duplicates_collapsed; a reader wanting “how many end up queryable” wants the corpus’slen(), not this field. - Material
Amount - AGENTS.md §6’s
Weighstep.mass_gramsisNoneuntil gugen has an atomic-weight table (not built yet, no §26 phase currently owns it – see tasks/todo.md); formula units alone already say what’s being weighed relative to the rest of the plan. - Materials
Project Snapshot Provider - A
ThermodynamicProviderover a fixed, caller-supplied snapshot of competing-phase formation energies – e.g. a pre-fetched slice of a Materials Project query. See the module doc comment: this type never fetches anything itself, and has no notion of “stale” or “refresh”. - Money
- Money as integer minor units – never
f64, which has nochecked_*arithmetic. Any(minor_units, currency)pair is valid oncecurrencyitself validated, so construction is infallible. - Nitrate
ToOxide Grammar M(NO3)n -> MO(n/2) + n "NOx"– the oxide side only, derived from charge balance (npositive charges on M needn/2O2-), never fixing which nitrogen oxide leaves (balance()’s owncurated_byproducts()already includes NO2 and settles that side independently). Narrowed to compositions with exactly one non-N/non-O/non-H element and no hydrogen – excluding hydrogen specifically rules out nitric acid (HNO3) and hydrated nitrates, which are not metal nitrates and for which “the metal” would otherwise wrongly resolve to hydrogen itself.- NotRecommended
Plan - A plan excluded from the recommended list by route-suitability findings
(Phase 15B) –
planis unchanged from what would otherwise have appeared inSynthesisPlanningReport.plans(same score/confidence/ evidence, since filtering happens after scoring, not instead of it);contradicting_findingsis just theContradictsfindings that triggered exclusion (not the full assessment, which may also carrySupports/Unknownfindings for other purposes). - Offer
Provenance - Package
Mass - A package size, canonically stored in grams.
from_milligrams/from_kilogramsare convenience constructors for spec’s minimum “mg/g/kg” requirement – volume packaging is out of scope for Phase 22. - Particle
Size Range Um - Phase
Requirement - Plan
Assessment - Everything
score_plancomputes for one plan, ready to be merged into the rest of aSynthesisPlan. - PlanId
- Deterministic plan identifier (AGENTS.md §20: “plan IDを決定的にする”). Phase 5 derives this from plan contents; Phase 1 only needs the type.
- Plan
Identity - A synthesis attempt’s own long-lived identity – self-describing
without needing the originating
SynthesisPlanningReportfile to still exist.PlanIdalone is not enough (it’s an opaque hash, not reversible back to route family/composition); Phase 26’s own matching criteria (target composition + canonical precursor set + route family - Plan
Score Breakdown - AGENTS.md §13, verbatim. Most of this breakdown is structurally
constant across every plan the crate can currently produce:
stoichiometric_validityandprecursor_coverageare always1.0(reaction balancing is exact andsearch_precursor_setsalready hard-filters on full element coverage – both are re-derived defensively here rather than assumed, but neither can discriminate between plans yet);thermodynamic_supportis alwaysNone– with noThermodynamicProviderconfigured there’s simply no data, and even with one configured (Phase 13’sMaterialsProjectSnapshotProvider, for one) a resolved reaction energy still isn’t converted into this score, deliberately (seescore_plan’s own doc comment);safety_penaltyis always0.0(no hazard data source exists – seemanual_review_requiredonPlanAssessment).uncertainty_penaltywas always1.0before Phase 10 (no condition was ever resolved); with aProcessEvidenceProviderthat actually resolves conditions (e.g.InMemoryLiteratureConditionProvider) wired in, it varies for the targets that provider has real cited coverage for – still1.0whenever no condition provider is configured, or when one is configured but has no matching precedent for this target.evidence_strengthuses weakest-link aggregation (seestrength_value) and is0.25for every plan the current generator produces, since every route attaches at least oneWeaktemplate-default entry – this stays true regardless of condition resolution, since resolved-condition evidence doesn’t remove the template’s own baselineWeakentries.total_ranking_scorevaries withprocess_simplicityalways, and withuncertainty_penaltyonly for targets a condition provider actually covers. Since Phase 12,process_simplicityis computed against a per-RouteFamilystep-count range (step_bounds), not one shared range – a plan’s route family can therefore change itsprocess_simplicity(and sototal_ranking_score) relative to a same-precursor-set plan under a different route family, but this is still the same one real driver, not a new independent dimension: two plans that each happen to sit at their own family’s maximum step count still score identically (see the worked BaTiO3 example inREADME.md, where both route families tie at 0.0625). This is the true extent of v0.1/v0.2.0’s ranking discriminating power; it is not a seven-dimensional judgment yet. - Planned
Step - Pairs a
ProcessStepwith itsStepRequirement. AGENTS.md §11 mandates this per-step distinction, but §6 showsSynthesisPlan.stepsas a bareVec<ProcessStep>with nowhere to carry it –SynthesisPlanusesVec<PlannedStep>instead to satisfy both. - Planner
- Orchestrates every subsystem built in Phases 2-5 into the single public
entry point AGENTS.md §18 illustrates: catalog lookup, bounded precursor
search, process templating, and scoring, assembled into one
SynthesisPlanningReport. - Planner
Builder - Builds a
Plannerwith any combination of its 5 optional providers (v0.5.0, Phase 23B) –catalog/configare required up front (there is nothing to plan from without a catalog), each provider is attached by name in any order or combination, andbuild()is infallible (no constructor, named or builder, performs any validation beyond field assignment). The crate’s first builder pattern; created because the 5 named constructors below only covered 3 of the real 2+-optional-provider combinations. - Planning
Assumption - AGENTS.md §6’s
SynthesisPlan.assumptions. Not given a verbatim shape.score_planpopulates this only with premises that aren’t already surfaced as aPlanningEvidence.limitationsentry or aPlanningWarning(most of the v0.1 generator’s defaults are – e.g. “method choice is a fixed template default” – so this stays short). - Planning
Config - Top-level planner configuration (AGENTS.md §18).
- Planning
Constraints - User-supplied constraints on the planning search. Deliberately minimal in Phase 1 — Phase 3 (precursor enumeration) adds the rest of the filters listed in AGENTS.md §9 alongside the search that consumes them.
- Planning
Evidence - AGENTS.md §7.
source_idmust never carry a fabricated DOI, paper title, patent number, or URL – only what an evidence provider actually returned. - Planning
Provenance - Everything needed to answer “why did this report look the way it did” without re-deriving it from logs (AGENTS.md §7).
- Planning
Warning - Precursor
Candidate - Redox-compatibility, atmosphere-compatibility, and hazard/toxicity metadata are out of Phase 3’s scope (AGENTS.md §26 Phase 3’s checklist doesn’t list them; they belong to later process/safety phases) and are not modeled here yet.
- Precursor
Id - Precursor
Search Outcome - Result of a bounded precursor search (AGENTS.md §9).
rejectedalways carries a reason for every candidate set the search actually evaluated and turned down. If the search stopped early becauseSearchBudget::max_precursor_setswas exhausted,rejectedalso carries one sentinel entry withRejectionCode::SearchBudgetExhaustedand an emptyprecursorslist – distinguishing “we looked and found nothing” from “we ran out of budget before looking everywhere” (AGENTS.md §9: “budget不足を「候補なし」と混同してはいけません”). - Precursor
Selection - One precursor’s role in a candidate plan.
- Pressure
Range - Prior
Experiment Evidence - Every
SynthesisExecutionRecordwhoseplan_identitymatches one plan’s exact (target, canonical precursor set, route family) –Plannerattaches this toSynthesisPlanwhen aPriorExperimentEvidenceProvideris configured and finds a match. Records are kept in whatever order the provider returned them (an append-only log’s natural order is chronological) – never sorted or filtered here. Process conditions, selected commercial offers, and catalog provenance differ freely between records and are shown as-is, not compared against each other or against this plan’s own (usually unresolved) conditions – seeSelf::outcome_tally’s own doc comment for why this is never a success rate. - Process
Precedent ProcessEvidenceProvideroutput (AGENTS.md §8).descriptionis free text with no structure – still valid on its own for a provider that only has prose precedent to offer.conditions(Phase 10) carries structured, per-purpose temperature/duration/atmosphere/ramp data, each entry traceable to its own citation; empty for a prose-only precedent.- Process
Template Result - Output of
conventional_solid_state_template: everything Phase 4 can determine about a solid-state route for one accepted precursor set, ready to be folded into aSynthesisPlan. - Proposed
Intermediate - One candidate intermediate composition, as proposed by exactly one
grammar from a set of real input precursor compositions. Mirrors
GeneratedCandidate‘s single-source-provenance shape (src/candidate_generator.rs) – combining multiple grammars’ output happens one layer up, inpropose_all. - Purity
Fraction - A validated purity fraction,
0 < x <= 1. NotScore01:Score01allows0.0(a meaningful “no support” score elsewhere in the crate), while a0.0purity is meaningless/rejectable here, and nothing else in the crate reusesScore01outsidescore_plan’s own domain. - Ramp
Rate Range - Ranking
Weights - AGENTS.md §13, verbatim fields.
- Reaction
Energy - Deliberately carries only the energetic quantity. AGENTS.md §4.3 requires thermodynamic favorability to stay separate from experimental likelihood, so this type must not accumulate unrelated “likelihood” fields later.
- Reaction
Species - Rejected
Candidate - Rejected
Observation - One observation entry that failed to parse,
Lenient-mode only.positionis this entry’s index within the snapshot’sobservationsJSON array (0-based) – the entry may have failed before enough of it parsed to recover acorpus_record_index, so this is the only coordinate guaranteed available for every rejection. - Rejected
Offer - Route
Observation Assessment - One route (target + precursor set + route family) with at least one
StepGroupAssessmentbacked by 2+ independent DOIs. Routes with no cross-DOI replication anywhere are never emitted – seeLiteratureObservationCorpus::cross_doi_comparisons. - Route
Suitability Assessment - One route family’s suitability picture for a target – deliberately a
Vec, never an aggregated single verdict, so contradictory findings are never force-merged (the owner’s explicit Phase 15A instruction). Emptyfindingsmeansinsufficient_evidence, not “route rejected” – absence of evidence must never be read as evidence of unsuitability (AGENTS.md §13’s existing rule – no evidence lowers confidence, it doesn’t reject – applied to route suitability specifically). Nothing inscore.rsreads this type in Phase 15A: it carries no ranking weight yet. - Score01
- A validated score in
[0.0, 1.0]. Not given a concrete shape by AGENTS.md (only referenced asScore01) – a rejecting newtype matches every other validated numeric type in this crate (TemperatureRange,ReactionEnergy, …). - Search
Budget - Bounds on the deterministic precursor-set search (AGENTS.md §9). Exhausting the budget must be reported, never silently treated as “no candidates” (AGENTS.md §9: “budget不足を「候補なし」と混同してはいけません”).
- Search
Budget Summary - Search
Diagnostic Trace - Diagnostic-only result (Phase 30.5,
search_diagnosticsfeature) – seesearch_precursor_sets_diagnostic’s own doc comment. Targeted at one caller-known “gold” precursor set rather than a general per-state pop log, which would be unboundedly large across a full factorial sweep over a real corpus. - Solid
Thermodynamic Entry - A caller-supplied 0 K formation enthalpy and crystal-structure volume
for one solid phase, plus which dataset/release/correction-scheme it
came from – the Phase 19P input type, deliberately new rather than an
extension of
CompetingPhase(seeThermodynamicDatasetIdentity’s doc comment). gugen never fetches this data itself; the caller has already queried a real thermochemical/structural database (e.g. Materials Project) and pre-fetched it, mirroringMaterialsProjectSnapshotProvider’s existing contract. - Sourced
Value - One distinct value among 2+ conflicting independent reports, with one
representative contributing DOI (the alphabetically-first DOI that
reported this exact value, for determinism) – mirrors
process.rs’s ownFieldResolution::Conflictshape, which also keeps one source per distinct value rather than every contributor. - Step
Group Assessment - A positional comparison across independent DOIs, conditioned on one
operation shape – never “the route’s step N,” always “among
independent DOIs whose heating was extracted with this many steps,
step N.”
source_doisis every distinct DOI that contributed any field at this key (a superset of any one field’s own contributors, since not every DOI reports every field). - Step
Group Key - The grouping key within one route – target/precursors/route_family
are already fixed by the enclosing
RouteObservationAssessment, so only the operation shape and position remain. Two step groups with the sameoperation_indexbut differentheating_operation_countare never the same key – seeliterature_observation_conflicts’s module doc comment for why that’s the whole point. - Structural
Diagnostic Effects - Effects one
mikiwame::MaterialDiagnosticReportshould have on gugen planning, decided by a caller that has structure data to analyze. - Suitability
Finding - One independent piece of evidence about whether
route_familysuits a target. ReusesEvidenceStrength/EvidenceScopefromevidence.rsrather than inventing parallel enums (AGENTS.md §7’s closed-vocabulary discipline applies here too). - Synthesis
Execution Record - One synthesis attempt’s full record. See the module doc comment for the append-only/versioned-schema/reference-only-later principles this type exists under.
- Synthesis
Plan - A candidate synthesis plan (AGENTS.md §6).
stepsisVec<PlannedStep>rather than the bareVec<ProcessStep>AGENTS.md §6 shows, so each step can carry theStepRequirement§11 mandates.manual_review_requiredisn’t in §6’s snippet, but §15 requires the v0.1 JSON plan to carry it (or an equivalent) regardless – seecrate::score_planfor why it’s alwaystruein v0.1. - Synthesis
Planning Report - Synthesis
Route - An ordered sequence of
BalancedReactionstages, where each stage after the first consumes only compositions already “available” – a base precursor, or a product of an earlier stage. ABalancedReactionis already a valid hyperedge (many reactants -> many products); this type’s only job is enforcing that a sequence of them forms a genuinely connected route totarget, not an arbitrary bag of unrelated reactions. - Target
Specification - Target
Structure - Minimal structural hint about the target: free text, deliberately.
chematic-crystalis now published and, with thechematic_crystalfeature enabled,crate::to_mikiwame_structurecan convert a realchematic_crystal::PeriodicStructureinto somethingmikiwame::analyzeconsumes (Phase 16) – but that conversion is a standalone, caller-driven bridge, not a field here. GivingTargetStructureitself a geometry field would need realPlanner/report-level wiring decisions (how a report should represent per-target structural diagnostics) that Phase 16 deliberately left out of scope; seedocs/integration.md. gugen does not implement its own crystal- structure representation either way (AGENTS.md §5). - Target
Summary - Temperature
Range - Thermodynamic
Conditions - Minimal Phase 1 placeholder for
ThermodynamicProviderinputs; extended once a real provider is implemented (Phase 2/6). - Thermodynamic
Dataset Identity - Identifies the specific dataset a batch of
SolidThermodynamicEntryvalues was drawn from – deliberately separate fromCompetingPhase(reaction.rs), which stays exactly as it was in v0.3.0: adding these fields to that existing type would have changed its meaning from “a simple competing-candidate context note” to a data-provenance-tracking type, a caller-facing contract change advisor recommended against. Every field is caller-supplied, free text – gugen never fetches or validates dataset identity itself (AGENTS.md §8/§25, same “gugen never queries an external API” disciplinematerials_project_adapter.rsdocuments forCompetingPhase). - Thermodynamic
Selectivity Assessment - One target’s finite-temperature thermodynamic picture at a given
temperature – raw physical quantities only, structurally mirroring
RouteSuitabilityAssessment’s own shape (Phase 15A): a vessel of independent, never-force-merged results plus its ownlimitations, not a verdict. UnlikeRouteSuitabilityAssessment’sSupports/Contradicts/Unknownfindings, nothing here is a judgment – every field is a number this module actually computed, orNonewhere it couldn’t. Never read byscore_plan:thermodynamic_supportstaysNoneregardless of what this type holds (checked as a permanent regression guard bytests/thermodynamics_ranking_invariance.rs, not left as an unverified claim).decomposition_comparisonsis aVecfor the same reasonRouteSuitabilityAssessment.findingsis: a caller may name more than one alternative assemblage, and none should be silently dropped or merged into an aggregate. - Thermodynamic
Stability Generator - Ranks caller-supplied precursor candidates by absolute thermodynamic
stability – most-negative 0 K formation enthalpy per atom first, the
standard materials-informatics cross-compound stability proxy (a
convex-hull y-axis value). Never computed or fetched by this crate
itself, matching the established “caller supplies real data, core
never bundles it” convention (
ThermodynamicProvider/MaterialsProjectSnapshotProvider’s own precedent, andFrequencyPriorGenerator’s own shape). - Unresolved
Commercial Field Serializeonly – seeCommercialOfferSelection’s doc comment (fielditself is&'static str).- Unresolved
Requirement
Enums§
- Actual
Step Detail - Mirrors
process::ProcessStep’s variants and field names – reusingprocess’s own method/purpose enums directly, so “what was actually done” is drawn from the same closed vocabulary as “what was planned,” and a deviation is a straightforward field-by-field diff – but with point-valueOption<f64>measurements instead ofprocess’s validatedmin<=maxrange types: a range describes a planned target window, a real measurement is one number. - Applicability
Level - Whether this planner can meaningfully handle the target at all (AGENTS.md §16). Distinct from per-plan confidence: applicability is about domain fit, not about how well-evidenced any particular plan is.
- Atmosphere
- AGENTS.md §12: atmosphere is never a bare string. v0.1 does not predict precise oxygen partial pressure; these variants are a formal oxidation-state / atmosphere-compatibility heuristic, not a guarantee of real phase equilibrium.
- Availability
Status - Characterization
Method - AGENTS.md §11 names XRD explicitly (“XRD等による中間確認” – XRD etc.); v0.1 only needs the one it names.
- Commercial
Catalog Error - Commercial
Catalog Load Mode - Commercial
Exclusion Code - Commercial
Ranking Policy - Named procurement-combination ranking policies (Phase 24C), selected via
assess_commercial_precursors_with_policy/assess_commercial_plans_with_policy. The plainassess_commercial_precursors/assess_commercial_plansalways useBalanced, unchanged from their pre-24C behavior. - Commercial
Source Type - How an offer’s data entered gugen – describes the ingestion mechanism, not anything about the product itself.
- Cooling
Mode - Cross
DoiField Status - One field’s cross-DOI comparison result within one
StepGroupKey. Seeliterature_observation_conflicts’s module doc comment for the full rationale, especially whyInsufficientIndependentSourcesandUnresolvedare distinct (exactly one DOI reported this field vs. zero did) and why a lone value never resolves the field here, unlike Phase 19’sapply_condition_precedents– that function answers “do we have any data to fill this slot,” this one answers “do independent replications agree,” so a single source is insufficient by design, not an oversight. - Deviation
Category - A closed set of deviation kinds for querying, plus free text for
nuance – mirrors
PlanningWarning { message, severity }’s own message-plus-category shape. - Evidence
Kind - AGENTS.md §7: every proposal must point at why it’s there, and the
“why” is one of a closed set of kinds. If nothing here applies, the
evidence kind is
RuleBasedwithsource_id: None– stated explicitly, never a gap left implicit. - Evidence
Scope - How directly a piece of evidence applies to the plan it’s attached to,
versus having been generalized from a related case (AGENTS.md §7’s
SimilarComposition/SimilarStructureevidence kinds exist precisely because that distinction matters and must not be hidden). - Evidence
Strength - Categorical strength of one piece of evidence. Distinct from
PlanScoreBreakdown.evidence_strength: Score01(AGENTS.md §13), which is a plan-level aggregate across many evidence items with a weighted, documented rationale – that aggregation is Phase 5 work. This type must not grow an unstated enum-to-number mapping before then. - Execution
Record Load Mode - Whether a malformed or schema-mismatched line aborts the whole parse
(
Strict) or is skipped and reported (Lenient) – mirrorscommercial_catalog::CommercialCatalogLoadMode’s identical two-mode precedent. - Forming
Method - Grammar
Evidence Class - How certain a proposal’s own arithmetic is, never a claim about
whether the reaction actually occurs. Declaration order is
significant: variants are ordered most- to least-certain, and
propose_allkeeps the most-certain evidence class when the same composition is proposed by more than one grammar.#[non_exhaustive]because a third category (Speculative, for a future looser grammar) is already anticipated but not needed for this PR’s four grammars, which are either exact charge/mass-balance derivations (Stoichiometric) or a single empirically-motivated heuristic (CommonDecompositionHeuristic). - Grinding
Method - Gugen
Error - Crate-wide error type. Construction of any public numeric or compositional type goes through validation that returns this error instead of panicking (AGENTS.md §25: “panicを通常入力の処理に使用しない”).
- Heating
Purpose - Calcination/sintering/annealing map directly onto AGENTS.md §11’s own 仮焼/本焼成 outline.
- Inert
Gas - Not given verbatim by AGENTS.md §12 – kept to the two gases a v0.1
atmosphere heuristic actually needs to name. Add a variant only when a
real curated fixture (Phase 8) needs one this doesn’t cover.
#[non_exhaustive](v0.5.0, Phase 23D) since this doc comment already states the growth expectation. - Load
Mode - Whether
LiteratureObservationCorpus::loadfails the entire load on the first malformed observation (Strict), or skips and counts malformed observations while still returning every observation that did parse (Lenient). Manifest-level problems (schema version, record-count mismatch) are hard failures in either mode – they mean “this is not a snapshot this gugen version can read at all,” not “this snapshot has some noisy rows.” - Missing
Commercial Data Policy - Mixing
Method - Method/purpose sub-enums
ProcessStepreferences (AGENTS.md §6). Not given verbatim – each is kept to the standard techniques the §11 template outline itself needs, not an exhaustive taxonomy. Add a variant only when a real curated fixture (Phase 8) needs one this doesn’t cover.#[non_exhaustive]on all three (v0.5.0, Phase 23D) since this doc comment already states the growth expectation for all three. - Process
Step - AGENTS.md §6’s
ProcessStep. Step meaning is kept as structured data; only final display is stringified. - Provider
Error - Error returned by external data providers (AGENTS.md §8). Deliberately
separate from
GugenError: one provider failing must not by itself fail planning that doesn’t depend on it (AGENTS.md §21.5). - Reducing
Agent - Rejection
Code - Closed set of rejection reasons (AGENTS.md §14).
ThermodynamicDataUnavailablemust not by itself force a reject — callers may downgrade it to a warning or lowered confidence instead (AGENTS.md §13). - Route
Error - Failure modes specific to assembling/validating a
SynthesisRoute. Deliberately a separate enum fromGugenError, not a new variant on it –GugenErroris a public, non-#[non_exhaustive]enum, so adding a variant there would be a breaking change for every downstream exhaustivematch.ProviderErroralready establishes the “a distinct concern gets its own error enum” precedent in this crate (src/error.rs); route assembly is similarly distinct from core numeric/compositional validation. - Route
Family - AGENTS.md §13. v0.1 shipped with exactly one route family; add a new
variant only with real literature grounding for its process structure
(never invented from memory, AGENTS.md §21.3), following the process
used for
Mechanochemical(Phase 12) – not pre-added speculatively.#[non_exhaustive](v0.5.0, Phase 23D) since this doc comment already states the growth expectation; matches this crate’s existingSuitabilityVerdict/RouteRecommendationprecedent. - Route
Recommendation - Discrete recommendation derived from a
RouteSuitabilityAssessment(Phase 15B) – never a numeric score.#[non_exhaustive], matchingSuitabilityVerdict’s precedent.Recommendedcarries no ranking weight in this phase: nothing inscore.rsreads it, and onlyNotRecommendedhas a real behavioral effect (Planner::planexcludes that plan from the recommended list – seederive_recommendation). - Step
Requirement - AGENTS.md §11: every step must declare how firmly it applies. A step
with unknown conditions is kept as
Unresolved, never silently dropped. - Suitability
Verdict - AGENTS.md §4.3: thermodynamic favorability alone must not be read as
experimental likelihood. This type extends the same separation to
route-family choice – a
Contradictsverdict is one specific, sourced reason to question a route, never a computed probability.#[non_exhaustive]since this is a genuinely new, still-evolving vocabulary (Phase 15A) – none of gugen’s other public enums have this guard, but this one is deliberately started with it rather than retrofitted later. - Synthesis
Outcome - A 7-state outcome, not success/failure (the owner’s explicit
requirement) –
NotMeasuredis itself a distinct, honest state, not the same as omitting the field. - TieBreak
Policy - Diagnostic-only, public tie-break selector (Phase 30.5,
search_diagnosticsfeature) forsearch_precursor_sets_diagnostic. Never accepted bysearch_precursor_setsitself, which always behaves exactly as it did before this type existed. - Warning
Severity
Constants§
- CORPUS_
SNAPSHOT_ SCHEMA_ VERSION - gugen’s own snapshot schema identifier, unrelated to the source
corpus’s own versioning.
LiteratureObservationCorpus::loadrejects a snapshot whosemanifest.schema_versiondoes not match this exactly – there is no cross-version compatibility logic, deliberately: a schema change is a breaking change to what this module can parse, not something to silently paper over. - ELEMENT_
SYMBOLS - The 118 IUPAC element symbols, used to validate that a symbol supplied by a caller is a real element rather than a typo. This is chemical-notation fact, not a synthesis claim, so it is safe to hold as a static table (contrast with AGENTS.md §4.1’s rule against unsourced temperature/time values, which does not apply here).
- EXECUTION_
RECORD_ SCHEMA_ VERSION - Namespaced and independently versioned – deliberately distinct from
report::SCHEMA_VERSION, whichdocs/api_stability_policy.mddocuments as not a strict shape guarantee for exactly this reason: aSynthesisExecutionRecordis a long-lived, externally-persisted artifact accumulated across gugen versions over months, unlike aSynthesisPlanningReportgenerated fresh each run. Matchesliterature_observations.rs’s ownCORPUS_SNAPSHOT_SCHEMA_VERSIONprecedent for this exact kind of artifact. - SCHEMA_
VERSION - Bumped whenever
SynthesisPlan’s orSynthesisPlanningReport’s JSON shape changes in a way a strict deserializer (e.g. one rejecting unknown fields) would need to account for.2as of v0.4.0: addsSynthesisPlan.literature_evidence, confirmed as a breaking addition bycargo semver-checks’sconstructible_struct_adds_fieldlint – seedocs/literature_evidence_integration.md.3as of Phase 26: addsSynthesisPlan.prior_experiment_evidence, the identical breaking class – seedocs/prior_experiment_evidence.md.
Traits§
- Candidate
Generator - One source in a multi-source candidate-generation ensemble (Phase 30,
PR 1:
catalog-exactandfrequency-prior; later PRs addthermodynamic,prior-experiment, andliterature-analog). Deliberately narrower a contract thanPrecursorCatalog:PrecursorCataloganswers “what’s in the catalog for this target,” unranked;CandidateGeneratoranswers “what does this specific signal propose, in its own preferred order” –GeneratedCandidate::rankcarries that order as a plain ordinal, never a score, so a generator’s internal priority can never be read as a success probability (mirrorsSearchPriority‘s own score/priority separation,src/precursor.rs).CandidateGeneratorEnsemble(src/candidate_generator.rs) is the only place multiple generators’ outputs are combined, and it does so by implementingPrecursorCatalogitself – so an ensemble is a drop-inPlanner::buildercatalog argument, requiring no change toPlanner/PlannerBuilderat all. - Literature
Evidence Provider - Source of reference-only, cross-DOI literature evidence for an exact
target/precursor-set/route-family combination (v0.4.0 Integration).
Deliberately narrower in spirit than
ProcessEvidenceProvider: this trait’s output (LiteratureRouteEvidence) is never applied to aProcessStep, never converted to aConditionPrecedent, and never passed toscore_plan–Plannerattaches it toSynthesisPlanas its own field, structurally isolated from every scoring input. Not gated behind theliterature_corpusfeature: this trait andLiteratureRouteEvidenceare always compiled, soPlanner’s public API and report schema never change shape depending on which crate features are enabled. The one real implementation (LiteratureObservationCorpusProvider, backed byLiteratureObservationCorpus::cross_doi_comparisons) lives behind that feature – same splitThermodynamicProvideralready has againstMaterialsProjectSnapshotProvider. - Precursor
Catalog - Source of candidate precursor compounds for a target (AGENTS.md §8). Core ships in-memory/JSON/fixture implementations only — no network access lives in this crate (AGENTS.md §8, §25).
- Prior
Experiment Evidence Provider - Source of reference-only prior-experiment evidence for an exact
target/precursor-set/route-family combination (Phase 26). Mirrors
LiteratureEvidenceProvider’s own exact-match contract exactly: this trait’s output (PriorExperimentEvidence) is never applied to aProcessStep, never converted to aConditionPrecedent, and never passed toscore_plan–Plannerattaches it toSynthesisPlanas its own field, structurally isolated from every scoring input. Not gated behind any Cargo feature: unlikeLiteratureEvidenceProvider(whose one real implementation needs theliterature_corpusfeature’s corpus loader),crate::execution_record::SynthesisExecutionRecorditself carries no feature gate, so neither does the one real implementation of this trait (crate::prior_experiment_evidence::InMemoryExecutionRecordProvider).Ok(Some(evidence))impliesevidence.recordsis non-empty – an empty match isOk(None), never a rendered “0 prior experiments” disclosure. UnlikeLiteratureEvidenceProvider,Plannerdoes not restrict which route families this provider is asked about (seedocs/prior_experiment_evidence.mdfor why that restriction doesn’t apply here). - Process
Evidence Provider - Source of process-condition precedent for a target/precursor combination (AGENTS.md §8).
- Route
Suitability Provider - Source of route-suitability findings for a target/route-family
combination (Phase 15A; AGENTS.md §8 sketches providers as a floor, not
an exhaustive list – Phase 13’s
competing_phasesalready extended this pattern once). Deliberately narrower thanProcessEvidenceProvider: suitability depends only on the target and route family, not on a specific precursor set, since a route family’s fitness for a material (e.g. whether high-temperature firing is even reachable before the target decomposes) doesn’t change with which precursors were chosen to reach it. - Target
Material View - Boundary trait gugen depends on instead of a concrete crystal-structure
type (AGENTS.md §5). Implemented directly by
TargetSpecificationtoday; a futurechematic-crystaladapter implements it over the real structure types without changing anything downstream oftarget.rs(docs/integration.md). - Thermodynamic
Provider - Source of reaction-energy estimates (AGENTS.md §8). Returning
Ok(None)means “no data available,” which must not by itself reject a plan (AGENTS.md §13, §14 — seeRejectionCode::ThermodynamicDataUnavailable). - Transformation
Grammar - A transformation grammar: given the real precursor compositions
available for a synthesis, proposes candidate intermediate
compositions via one fixed, explainable mechanism. Implementations
must never assert that a proposal is a real reaction product –
only
search_precursor_sets’s ownbalance()check, applied downstream, decides that.
Functions§
- applicable_
route_ family_ templates - Every route family gugen currently supports, applied unconditionally to
the same accepted precursor set (Phase 12). One accepted precursor set
now generally becomes more than one ranked
SynthesisPlan– callers (Planner::plan) turn each returnedProcessTemplateResultinto its own plan, rather than assuming exactly one template per accepted set. - assess_
commercial_ plans - Maps
assess_commercial_precursorsover each plan independently (freshmax_combinations_evaluatedbudget per plan).Erris reserved for a self-contradictoryrequest– checked once, up front, since it is identical for every plan in the batch; a single malformed plan never aborts the batch (seeassess_commercial_precursors’s degraded-Okhandling for plan-shape issues). Always ranks viaCommercialRankingPolicy::Balanced– unchanged from this function’s pre-24C behavior. Seeassess_commercial_plans_with_policyfor named-policy selection. - assess_
commercial_ plans_ with_ policy - assess_
commercial_ precursors - Always ranks via
CommercialRankingPolicy::Balanced– unchanged from this function’s pre-24C behavior. Seeassess_commercial_precursors_with_policyfor named-policy selection. - assess_
commercial_ precursors_ with_ policy - balance
- Solves for integer, gcd-normalized coefficients balancing
reactantsagainstproducts(AGENTS.md §10), using exact-rational Gauss-Jordan elimination over the element x species matrix — never floating-point approximation. - balanced_
reaction_ delta_ ev_ per_ atom - Products’ total
relative_solid_gibbsminus reactants’ total, weighted by each species’ReactionSpecies::coefficientand formula-unit atom count, normalized per atom of the reactant side (mirrorsMaterialsProjectSnapshotProvider::reaction_energy’s exact convention and doc comment for why the reactant side is used). - conventional_
solid_ state_ template - AGENTS.md §11’s conventional solid-state route: weigh, mix, grind, optionally form, calcine (only if the balanced reaction shows a byproduct that needs decomposing off), sinter, cool, and characterize.
- curated_
byproducts - Curated allow-list of byproduct compositions v0.1 permits assuming
without target-specific evidence (AGENTS.md §10). A reaction that needs
a byproduct outside this list is
RejectionCode::UnsupportedByproductRequired, not a silently invented one. - decomposition_
margin_ ev_ per_ atom - The energy margin between
targetand one specific, caller-named alternative combination of phases covering the exact same total elemental composition – e.g. “doesBaTiO3have lower Gibbs energy thanBaO + TiO2”. Deliberately not a hull search or an automatic “find the best decomposition” function (the owner’s original Phase 19P sketch asked for a “small binary/ternary hull”; this is a considered substitution, not a silent scope cut – see this phase’s work report). A hull search would require gugen itself to decide which candidate assemblages to enumerate fromentries, so a returned margin would only ever mean “no cheaper decomposition among the phases this particular caller happened to supply,” not “the target is thermodynamically stable” – a reader could easily misread the former as the latter, which is exactly the false-confidence risk the owner’s own stop-and-report list names. Requiring the caller to name the specific alternative assemblage keeps the claim exactly as narrow as what was actually computed. - default_
grammars - Every grammar shipped in this PR, in a fixed order (used by
propose_all’s callers, e.g. the PR 3 benchmark harness, so “grammar -only” runs are reproducible without hand-listing grammars at each call site). - derive_
recommendation - Pure function: no
Planner/provider dependency, safe to unit-test directly against a hand-builtRouteSuitabilityAssessment. Order- and duplicate-invariant by construction (any/iterover the wholefindingsslice, not the first match). - literature_
evidence_ limitations - A fixed baseline of disclosures every
LiteratureRouteEvidencecarries (Phase 20D’s own findings about what this corpus can and cannot certify), plus conditional additions whenassessmentitself shows step-count diversity or a field-level conflict. Deliberately never phrases “more evidence surfaced” as “conditions are more accurate” – this reports what was found, not a confidence claim. - mechanochemical_
template - Phase 12’s second route family: weigh, then high-energy ball milling
(
GrindingMethod::BallMilling) as one combined mixing-and-grinding operation, optionally consolidated (pressed) into a bulk shape, with a post-milling anneal only when the balanced reaction needs one. - parse_
execution_ records - Parses a JSONL document (one
SynthesisExecutionRecordper non-blank line) – pure, no file I/O (see the module doc comment). Every line’sschema_versionis checked againstEXECUTION_RECORD_SCHEMA_VERSIONhere, per line rather than via a single whole-file header: a real execution log accumulates appends across gugen versions over months, so no one file-wide version gate fits its lifecycle, and a header line would itself be a mutation hazard for an append-only file under concurrent or crash-prone writers that per-line self-description avoids entirely. - propose_
all - Runs every grammar in
grammarsagainstprecursors, caps each grammar’s own raw output atper_grammar_cap, then deduplicates identical compositions across grammars – retaining every contributing grammar’s id and the most-certain evidence class seen – sorted most-certain/most-corroborated first and capped combined atcombined_cap. MirrorsCandidateGeneratorEnsemble’s own per-source-cap-then-merge shape (src/candidate_generator.rs). - ranking_
weights_ digest - A deterministic fingerprint of
weights, forPlanningProvenance.ranking_config_digest(AGENTS.md §13: “weightをprovenanceに保存”). Not a cryptographic hash –DefaultHasheris enough to detect “did the ranking config change between two runs”, which is all provenance needs it for. - reduced_
mass_ amu - Bartel et al. 2018 Eq. 6: a composition-ratio-weighted pairwise
combination of atomic masses.
Nonefor a single-element composition (no pairs exist – callers must special-case pure elements the same way pymatgen’sgf_sissodoes, returning a zero correction, since a pure element’s formation enthalpy is 0 by definition and has no SISSO correction to add). - relative_
solid_ gibbs_ ev_ per_ atom formation_enthalpy_ev_per_atom + Gδ(T)– a finite-temperature formation-Gibbs-energy estimate relative to the same 0 K elemental reference frameformation_enthalpy_ev_per_atomalready uses, not an absolute value (this module never computes or needs the elemental re-basing term – see the module doc comment). Meaningful only in differences between entries sharing the same total elemental inventory (a balanced reaction, or a decomposition margin) – seebalanced_reaction_delta_ev_per_atom.- score_
plan - Scores one plan’s ingredients (AGENTS.md §13/§16).
route_family(Phase 12) only affectsprocess_simplicity, viastep_bounds– every other dimension is computed the same way regardless of route family. - search_
precursor_ sets - Searches for precursor sets that can plausibly produce
target, drawn fromcandidates(typically the output of aPrecursorCatalogquery), respectingconstraintsandbudget. - search_
precursor_ sets_ diagnostic - Diagnostic-only (Phase 30.5,
search_diagnosticsfeature): runs the exact same frontier mechanismsearch_precursor_setsuses (search_precursor_sets_core, shared, unchanged pruning/budget/dedup rules), under a caller-selectedTieBreakPolicy, tracing only what this phase’s pre-registered questions need about one specific known-correct (“gold”) precursor set. - search_
two_ step_ routes - Searches for routes to
targetof depth 1 (today’s existingsearch_precursor_sets, unchanged) and depth 2 (via each composition inintermediate_candidates).intermediate_candidatesis caller-supplied, never computed or fetched by this function – matchingFrequencyPriorGenerator’s own “caller-supplied, never computed by the crate” convention (src/candidate_generator.rs); a caller with aThermodynamicProvidercan source it fromcompeting_phases(target), but this function stays provider-agnostic and trivially testable with plain fixtures. - structural_
effects - Maps one
mikiwame::MaterialDiagnosticReportto gugen-native effects. - to_
mikiwame_ structure - Converts a chematic-crystal structure into a mikiwame one. See the module doc comment for why this isn’t a plain field-by-field copy.