Skip to content
Edit on GitHub

Chemistry foundations

Task C0-001 records the two decisions that unblock Chemistry C0. They are implementation contracts, not optional tuning.

VoxelSandbox.Chemistry owns DeterministicMath.Exp, Ln, Pow, and Sqrt. The assembly has no Unity reference and must not call System.Math transcendental functions. Its hot path uses fixed range reduction, fixed polynomial/Newton iterations, IEEE-754 arithmetic, and bit-level power-of-two scaling; it allocates no managed memory after warmup.

The initial numerical contract for normal finite C0 reference inputs is at most 2 ULP for Exp, Ln, and Sqrt, and 12 ULP for Pow, plus a 2e-13 relative-error ceiling. The standalone benchmark sweep used during implementation observed maxima of 1 ULP for Exp, Ln, and Sqrt, and 10 ULP for Pow. Repeated evaluation on one runtime is required to be bit-identical now; cross-runtime bit identity remains a C0 gate.

All kinetic rates are multiplied by 60. Thermodynamic state is never scaled: equilibrium constants, enthalpy, entropy, temperature, pressure, voltage, heat capacity, mass, and charge use their real units and values.

The chemistry simulation remains fixed at 20 Hz, so one solver tick represents three seconds of elapsed process time. One calendar day is 86,400 process seconds and lasts 1,440 wall-clock seconds (24 minutes); the scene’s day/night and seasonal reference clocks use the same 1,440-second day.

This is a declared simulation approximation. Player-facing journal text must distinguish process duration from wall-clock duration and may state the full-scale duration where it helps interpretation.

The C0 solver estimates a reaction’s stiffness as |r|·dt/n_limit: the fractional limiting-reagent change predicted over the fixed process tick. It then chooses the smallest power of two whose equal sub-steps meet a 5% fractional-change target, capped at 64. The possible counts are exactly 1, 2, 4, 8, 16, 32, 64; selection is a pure, allocation-free function of the current vessel state.

At the 20 Hz / 60× clock contract, a full tick is three process seconds. This selector never applies the 60× rate factor itself: it accepts rates already expressed in mol/process-second, avoiding accidental double scaling. A vessel whose estimate exceeds the cap still takes exactly 64 equal sub-steps, with the later limiting-reagent clamp remaining the non-negativity invariant.

Every reaction in a vessel sub-step reads the same charge-and-temperature snapshot. The solver collects the resulting extent proposals, projects their aggregate consumption onto the finite material available in that snapshot, and only then commits them in ascending ReactionId order. That last order is strictly an arithmetic and serialization convention: it must not decide which reaction wins a shared reagent.

The first C0 projection uses one conservative scale for all proposals in the domain. It may defer otherwise compatible reactions to the next sub-step, but it preserves non-negativity, is allocation-free, and is invariant under input-array permutations. A later sparse constrained projection may recover more throughput only if it retains those three properties and passes the same reaction-permutation tests.

Visible charge entries are projected downward to the 1e-12 mol grid. Every positive remainder is kept in a bounded, canonical per-charge trace ledger instead of being deleted; further additions can promote it back to a visible quantum. Trace entries participate in mass conservation and event-state fingerprints, but stay below the rate/pressure/interaction visibility threshold until promotion. Multi-species reaction steps preflight trace capacity before their first mutation. If the bounded ledger cannot represent a new remainder, the step fails cleanly rather than creating a partial reaction or losing material.

ScienceEventContext is supplied by the run/save owner and carries stable run, domain, tick and event-sequence IDs. The vessel solver can write into a caller-owned fixed-capacity ScienceEventBuffer. It reserves the maximum event footprint before a tick starts, emits one aggregate accepted-extent fact for each reaction that moved material, then emits a completed-tick fact with temperature, pressure, heat, mass drift and canonical before/after charge fingerprints. No event is appended for a rejected or conservation-failed tick.

These are authoritative causal facts, not observations and not player-facing prose. The apparatus, instrument and notebook layers must supply observation availability, uncertainty, source/model labels and language. That separation is what prevents a completed solver event from revealing the identity or cause of an unobserved reaction.

ScienceEventLog owns a bounded committed prefix. It only accepts a whole buffer whose IDs begin at its next expected ID and remain contiguous; a stale, malformed or over-capacity batch changes nothing. ScienceVesselRun is the C0 transaction owner: it reserves both its tick buffer and committed log capacity before calling the solver, then advances temperature/tick sequence only after the complete event batch commits. A full log therefore pauses before chemistry advances rather than dropping history.

VesselChargeSnapshot preserves both visible components and conservation traces, while ScienceVesselRunCheckpoint packages that charge, temperature, tick sequence and validated event prefix as one restore unit. Restore first validates bounded scratch owners, then replaces live state; a malformed charge or event prefix cannot produce a half-restored run. Snapshot creation allocates only at the save boundary; ticking and committing a pre-sized batch allocate nothing. A filesystem save adapter must still encode this checkpoint as one atomically replaced payload alongside the containing world checkpoint—separate successful vessel and journal files are not an acceptable implementation.

ScienceAfterActionBuilder turns one committed vessel-tick batch into localisation-ready journal claims only through declared ScienceObservationChannels. Contents, temperature and pressure can be shown when their direct/instrument channel was available. A solver reaction ID is never surfaced unless an explicit ReactionIdentity observation channel says an apparatus actually identified it; otherwise an observed change receives an honest CauseUndetermined claim. This is the first working “what just happened?” path, not final notebook UI or provenance: calibration, uncertainty, sampling cadence, localisation templates and durable observation records remain C1/C5 work.

User-contributed notes

Corrections, clarifications, and practical tips for this page. Anonymous is fine — a name is optional. Basic Markdown works: **bold**, *italic*, `code`, and links.

Notes policy

Notes are lightly filtered for spam and may be edited or removed. Keep them about this page — no support requests, no personal data, nothing you would not publish. Links are limited and marked nofollow.

  1. Loading notes…