gugen 0.8.0

Explainable materials synthesis and process planning
Documentation
//! 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.

#![forbid(unsafe_code)]

mod balance;
mod candidate_generator;
#[cfg(feature = "chematic_crystal")]
mod chematic_crystal_adapter;
#[cfg(feature = "commercial_catalog")]
mod commercial_catalog;
mod composition;
mod condition_precedents;
mod config;
mod error;
mod evidence;
mod execution_record;
mod frac;
mod literature_conditions;
mod literature_evidence;
#[cfg(feature = "literature_corpus")]
mod literature_observation_conflicts;
#[cfg(feature = "literature_corpus")]
mod literature_observations;
#[cfg(feature = "materials_project")]
mod materials_project_adapter;
#[cfg(feature = "mikiwame")]
mod mikiwame_adapter;
mod multi_step;
mod planner;
mod precursor;
mod prior_experiment_evidence;
mod process;
mod provenance;
mod provider;
mod reaction;
mod rejection;
mod report;
mod route_suitability;
mod score;
mod target;
mod thermodynamics;
#[cfg(feature = "experimental_grammar")]
mod transformation_grammar;

pub use balance::{balance, curated_byproducts};
pub use candidate_generator::{
    CandidateGeneratorEnsemble, CatalogExactGenerator, EnsembleOutput, FrequencyPriorGenerator,
    GeneratedCandidate, GeneratorId, ThermodynamicStabilityGenerator,
};
#[cfg(feature = "chematic_crystal")]
pub use chematic_crystal_adapter::to_mikiwame_structure;
#[cfg(feature = "commercial_catalog")]
pub use commercial_catalog::{
    AvailabilityStatus, CasNumber, CommercialCatalogColumnMap, CommercialCatalogError,
    CommercialCatalogLoadMode, CommercialCatalogLoadReport, CommercialCombination,
    CommercialExclusion, CommercialExclusionCode, CommercialOfferId, CommercialOfferSelection,
    CommercialPlanAssessment, CommercialPlanningConfig, CommercialPlanningRequest,
    CommercialPrecursorCatalog, CommercialPrecursorOffer, CommercialRankingPolicy,
    CommercialSourceType, CommercialWarning, CurrencyCode, MissingCommercialDataPolicy, Money,
    OfferProvenance, PackageMass, ParticleSizeRangeUm, PurityFraction, RejectedOffer,
    SearchBudgetSummary, UnresolvedCommercialField, assess_commercial_plans,
    assess_commercial_plans_with_policy, assess_commercial_precursors,
    assess_commercial_precursors_with_policy,
};
pub use composition::{Composition, ELEMENT_SYMBOLS, Element};
pub use condition_precedents::{ConditionConflict, ConditionPrecedent, ProcessPrecedent};
pub use config::{PlanningConfig, SearchBudget};
pub use error::{GugenError, ProviderError, Result};
pub use evidence::{EvidenceKind, EvidenceScope, EvidenceStrength, PlanningEvidence};
pub use execution_record::{
    ActualPrecursorAmount, ActualProcessStep, ActualStepDetail, Deviation, DeviationCategory,
    EXECUTION_RECORD_SCHEMA_VERSION, ExecutionCharacterization, ExecutionProvenance, PlanIdentity,
    SynthesisExecutionRecord, SynthesisOutcome,
};
#[cfg(feature = "serde")]
pub use execution_record::{
    ExecutionRecordLoadMode, ExecutionRecordLoadReport, parse_execution_records,
};
pub use literature_conditions::{CuratedConditionRecord, InMemoryLiteratureConditionProvider};
pub use literature_evidence::{
    CrossDoiFieldStatus, LiteratureRouteEvidence, RouteObservationAssessment, SourcedValue,
    StepGroupAssessment, StepGroupKey, literature_evidence_limitations,
};
#[cfg(feature = "literature_corpus")]
pub use literature_observation_conflicts::LiteratureObservationCorpusProvider;
#[cfg(feature = "literature_corpus")]
pub use literature_observations::{
    CORPUS_SNAPSHOT_SCHEMA_VERSION, CorpusHeatingObservation, CorpusManifest,
    LiteratureObservationCorpus, LoadMode, LoadReport, RejectedObservation,
};
#[cfg(feature = "materials_project")]
pub use materials_project_adapter::MaterialsProjectSnapshotProvider;
#[cfg(feature = "mikiwame")]
pub use mikiwame_adapter::{StructuralDiagnosticEffects, structural_effects};
pub use multi_step::{RouteError, SynthesisRoute, search_two_step_routes};
pub use planner::{Planner, PlannerBuilder};
pub use precursor::{
    AcceptedPrecursorSet, AvailabilityMetadata, InMemoryPrecursorCatalog, PrecursorCandidate,
    PrecursorId, PrecursorSearchOutcome, PrecursorSelection, search_precursor_sets,
};
#[cfg(feature = "search_diagnostics")]
pub use precursor::{SearchDiagnosticTrace, TieBreakPolicy, search_precursor_sets_diagnostic};
pub use prior_experiment_evidence::{InMemoryExecutionRecordProvider, PriorExperimentEvidence};
pub use process::{
    Atmosphere, CharacterizationMethod, CoolingMode, DurationRange, FormingMethod, GrindingMethod,
    HeatingPurpose, InertGas, MaterialAmount, MixingMethod, PlannedStep, PressureRange,
    ProcessStep, ProcessTemplateResult, RampRateRange, ReducingAgent, RouteFamily, StepRequirement,
    TemperatureRange, applicable_route_family_templates, conventional_solid_state_template,
    mechanochemical_template,
};
pub use provenance::PlanningProvenance;
pub use provider::{
    CandidateGenerator, LiteratureEvidenceProvider, PrecursorCatalog,
    PriorExperimentEvidenceProvider, ProcessEvidenceProvider, RouteSuitabilityProvider,
    ThermodynamicProvider,
};
pub use reaction::{
    BalancedReaction, CompetingPhase, ReactionEnergy, ReactionSpecies, ThermodynamicConditions,
};
pub use rejection::{RejectedCandidate, RejectionCode};
pub use report::{
    ApplicabilityAssessment, ApplicabilityLevel, NotRecommendedPlan, PlanId, PlanningWarning,
    SCHEMA_VERSION, SynthesisPlan, SynthesisPlanningReport, TargetSummary, UnresolvedRequirement,
    WarningSeverity,
};
pub use route_suitability::{
    CuratedSuitabilityRecord, InMemoryRouteSuitabilityProvider, RouteRecommendation,
    RouteSuitabilityAssessment, SuitabilityFinding, SuitabilityVerdict, derive_recommendation,
};
pub use score::{
    ConfidenceAssessment, PlanAssessment, PlanScoreBreakdown, PlanningAssumption, RankingWeights,
    Score01, ranking_weights_digest, score_plan,
};
pub use target::{
    PhaseRequirement, PlanningConstraints, TargetMaterialView, TargetSpecification, TargetStructure,
};
pub use thermodynamics::{
    DecompositionComparison, Kelvin, SolidThermodynamicEntry, ThermodynamicDatasetIdentity,
    ThermodynamicSelectivityAssessment, balanced_reaction_delta_ev_per_atom,
    decomposition_margin_ev_per_atom, reduced_mass_amu, relative_solid_gibbs_ev_per_atom,
};
#[cfg(feature = "experimental_grammar")]
pub use transformation_grammar::{
    AcidCarbonatePhosphateGrammar, CarbonateToOxideGrammar, DedupedProposal, GrammarEvidenceClass,
    GrammarId, HydroxideToOxideGrammar, NitrateToOxideGrammar, ProposedIntermediate,
    TransformationGrammar, default_grammars, propose_all,
};