bayesmith.artifacts.base
Source-derived signatures and contracts. See the reference index for coverage and conventions.
Module contract
The artifact envelope: what every artifact carries, and how it retires. Plan §0.2's frozen envelope, plus the small value objects a run record is made of. Three rulings shape nearly every line here. **An artifact is data, and data does not change under you.** Everything is a frozen dataclass; :class:``NamedArray`` copies its input into a C-contiguous read-only array, so a caller who keeps a reference to the array they passed cannot edit an artifact that has already been fingerprinted. The copy and the read-only flag close different holes -- one from outside the artifact, one from inside -- and neither substitutes for the other. **Identity and content are different axes.** ``artifact_id`` and ``run_id`` are UUID4s minted once and preserved across round trips; they say WHICH artifact. What it was made OF is the fingerprint bundle, and that is what caching and invalidation read. The version identity is ``(artifact_id, revision)``: :func:``invalidate_meta`` APPENDS revision ``n + 1`` marked INVALIDATED, carrying the changed input kinds and the time, and leaves revision ``n`` exactly as it was. Provenance that can be rewritten is not provenance, and a verdict that can be deleted is not a record of having judged. **Refusals happen at construction, in the smallest type that can see the problem.** A budget refuses a negative count, a timestamp refuses a naive or offset time, a lifecycle refuses "invalidated, but nothing changed". The alternative is a validator somewhere upstream that a second caller does not know to run. **Which exception a refusal raises is a contract, not a mood.** A ``TypeError`` means "that is the wrong kind of thing" -- a bare string where an enum member belongs, a list where a tuple of refs belongs. A ``ValueError`` means "right kind of thing, malformed or out of range" -- a negative count, a non-UTC timestamp, a UUID that is not version 4. The split is worth stating because most fields here can fail either way, and a caller sanitising input needs to know which question it just got an answer to. Two details that look like fussiness and are not. Times are UTC RFC 3339 and are NORMALISED to the ``Z`` spelling: ``+00:00`` is the same instant, and two spellings of one instant are two byte strings for one artifact. And the enums are checked with ``isinstance`` rather than by string value, because a :class:``enum.StrEnum`` member IS its value -- ``ApproximationClass.EXACT`` and ``TargetFidelity.EXACT`` are equal strings answering different questions, and a string check would let them be swapped. Layering: ``_codec ← identity ← base``. NumPy and the standard library, and nothing of the Graph, the dispatch layer or JAX (§0 ruling 5).
SCHEMA_VERSION
Defined in bayesmith.artifacts.base, line 102.
SCHEMA_VERSION = 1CanonicalScalar
Defined in bayesmith.artifacts.base, line 107.
CanonicalScalar = bool | int | float | str | NoneCanonicalValue
Defined in bayesmith.artifacts.base, line 108.
CanonicalValue = CanonicalScalar | tuple['CanonicalValue', ...]canonical_scalar_options
Defined in bayesmith.artifacts.base, line 281.
canonical_scalar_options(label: str, pairs: object) -> tuple[tuple[str, CanonicalScalar], ...]Sorted, key-unique options whose values are :data:``CanonicalScalar``.
canonical_value_options
Defined in bayesmith.artifacts.base, line 288.
canonical_value_options(label: str, pairs: object) -> tuple[tuple[str, CanonicalValue], ...]Sorted, key-unique options whose values are :data:``CanonicalValue``.
utc_timestamp
Defined in bayesmith.artifacts.base, line 197.
utc_timestamp(moment: _dt.datetime | None=None) -> str``moment`` (default: now) as an RFC 3339 UTC string in the ``Z`` spelling.
NamedArray
Defined in bayesmith.artifacts.base, line 300.
class NamedArray
name: str
value: np.ndarray
dims: tuple[str, ...]The one public container for an array in an artifact (§0.5). The value is copied in and handed back read-only, and ``dims`` names one axis each. A repeated dim name is allowed on purpose: a covariance matrix is indexed by the same parameter axis twice, and refusing that would push every covariance into an unnamed array. Equality is over NAME, DIMS and BYTES rather than by ``==`` on the arrays. Element-wise comparison would make ``artifact == artifact`` raise for any array of more than one element, and byte equality is what a fingerprint already means -- which is also why two NaNs with one bit pattern compare equal here, while ``np.array_equal`` would call them different.
RunWarning
Defined in bayesmith.artifacts.base, line 375.
class RunWarning
code: str
message: str
scope: str | None = NoneSomething a run noticed and did not fail over. ``scope`` is a plain string here. Task 4 introduces the structured ``ScopeRef`` that the Refusal family uses, and borrowing it before it exists would make this module depend on a type nobody has designed yet.
ErrorRecord
Defined in bayesmith.artifacts.base, line 395.
class ErrorRecord
code: str
message: str
exception_type: str
traceback_ref: str | None = NoneA serialisable summary of a failure -- never the exception object. ``traceback_ref`` is an opaque external reference (§0.6): a traceback is not one of the three :class:``ArtifactKind`` the invalidation matrix reasons about, so it is stored beside the artifacts rather than as one.
ComputeBudget
Defined in bayesmith.artifacts.base, line 417.
class ComputeBudget
draws: int | None = None
warmup: int | None = None
chains: int | None = None
max_iterations: int | None = None
max_wall_clock_seconds: float | None = NoneWhat a run was allowed to spend. ``None`` where a count does not apply. ``None`` and ``0`` are different answers -- "this task has no such knob" against "you may take none" -- so the field is kept and left empty rather than filled with a stand-in.
SeedRecord
Defined in bayesmith.artifacts.base, line 443.
class SeedRecord
seed: int
key_algorithm: strThe entropy a run started from, and the key algorithm it was fed to.
DeviceRecord
Defined in bayesmith.artifacts.base, line 456.
class DeviceRecord
platform: str
device_kind: str
device_id: intOne device a run used, described the way a backend describes it.
BackendRef
Defined in bayesmith.artifacts.base, line 471.
class BackendRef
name: str
version: str | None = NoneThe backend that RAN, which is never the policy value ``"auto"``. A task may ask for ``"auto"`` (§0.4); a run record answering ``"auto"`` would be provenance that forgot which backend produced the numbers.
TerminationReason
Defined in bayesmith.artifacts.base, line 492.
class TerminationReason(StrEnum)Why a run stopped, which is not the same question as whether it worked.
COMPLETED = 'completed'
CONVERGED = 'converged'
BUDGET_EXHAUSTED = 'budget_exhausted'
TOLERANCE_UNMET = 'tolerance_unmet'
DIVERGED = 'diverged'
INTERRUPTED = 'interrupted'TerminationRecord
Defined in bayesmith.artifacts.base, line 505.
class TerminationRecord
reason: TerminationReason
iterations: int | None = None
message: str = ''No additional source docstring. Read the signature and owning module contract above.
TimingRecord
Defined in bayesmith.artifacts.base, line 519.
class TimingRecord
started_at: str
finished_at: str
wall_clock_seconds: float
compile_seconds: float | None = NoneWhen a run ran and how long it took. Wall clock only -- §0.3 keeps timing out of every fingerprint, so nothing here can change an identity.
ApproximationClass
Defined in bayesmith.artifacts.base, line 550.
class ApproximationClass(StrEnum)How the representation was PRODUCED (§0.2).
EXACT = 'exact'
CERTIFIED_DETERMINISTIC = 'certified_deterministic'
MONTE_CARLO = 'monte_carlo'
HEURISTIC = 'heuristic'TargetFidelity
Defined in bayesmith.artifacts.base, line 560.
class TargetFidelity(StrEnum)Whether the TARGET is the intended one, or an approximation of it.
EXACT = 'exact'
APPROXIMATE = 'approximate'ApproximationRecord
Defined in bayesmith.artifacts.base, line 569.
class ApproximationRecord
representation_class: ApproximationClass
target_fidelity: TargetFidelity
details: tuple[tuple[str, CanonicalScalar], ...] = ()Two orthogonal answers, kept apart (§0.2). iid exact-linear draws are ``MONTE_CARLO`` and ``EXACT``: sampled, but from the posterior itself. NUTS is ``MONTE_CARLO`` and, with no target approximation, also ``EXACT``; an amortized posterior is ``HEURISTIC``/``APPROXIMATE``. One enum would have to call the first case something, and every available something is a lie about one of the two axes.
ProducerRef
Defined in bayesmith.artifacts.base, line 593.
class ProducerRef
package: str
version: strThe package and version that wrote an artifact.
ArtifactStatus
Defined in bayesmith.artifacts.base, line 605.
class ArtifactStatus(StrEnum)No additional source docstring. Read the signature and owning module contract above.
CURRENT = 'current'
INVALIDATED = 'invalidated'ArtifactRef
Defined in bayesmith.artifacts.base, line 612.
class ArtifactRef
artifact_id: str
revision: int
artifact_type: ArtifactKindA reference to one VERSION of one artifact. The revision and the kind travel with the id because ``(artifact_id, revision)`` is the version identity: a reference carrying only an id would be silently satisfied by a later, invalidated revision of the same artifact, which is exactly the impersonation §0.2 rules out.
LifecycleRecord
Defined in bayesmith.artifacts.base, line 633.
class LifecycleRecord
status: ArtifactStatus
invalidated_at: str | None = None
changed_inputs: tuple[FingerprintKind, ...] = ()Current, or invalidated with the reason and the time recorded.
ArtifactMeta
Defined in bayesmith.artifacts.base, line 681.
class ArtifactMeta
artifact_type: ArtifactKind
schema_version: int
artifact_id: str
revision: int
created_at: str
producer: ProducerRef
parent_refs: tuple[ArtifactRef, ...]
fingerprints: FingerprintBundle
lifecycle: LifecycleRecord
warnings: tuple[RunWarning, ...]
summary: strThe §0.2 envelope every artifact carries.
RunRecord
Defined in bayesmith.artifacts.base, line 732.
class RunRecord
run_id: str
plan_ref: ArtifactRef
fingerprints: FingerprintBundle
seed: SeedRecord | None
dtype: str
devices: tuple[DeviceRecord, ...]
jax_config: tuple[tuple[str, CanonicalScalar], ...]
backend: BackendRef
budget: ComputeBudget
termination: TerminationRecord
timing: TimingRecord
approximation: ApproximationRecord
warnings: tuple[RunWarning, ...]
initial_values: tuple[NamedArray, ...] = ()
sampling_details: tuple[tuple[str, CanonicalValue], ...] = ()What one execution of a plan actually did (§0.2).
new_artifact_meta
Defined in bayesmith.artifacts.base, line 783.
new_artifact_meta(*, artifact_type: ArtifactKind, fingerprints: FingerprintBundle, producer: ProducerRef, summary: str='', parent_refs: tuple[ArtifactRef, ...]=(), warnings: tuple[RunWarning, ...]=(), schema_version: int=SCHEMA_VERSION, artifact_id: str | None=None, created_at: str | None=None) -> ArtifactMetaA CURRENT envelope at revision 0, with a freshly minted UUID4. ``artifact_id`` and ``created_at`` are arguments so that a caller restoring an artifact keeps its identity; left out, they are minted here. They are not derived from the content: two artifacts with identical fingerprints are still two artifacts, with separate lineage and separate verdicts.
invalidate_meta
Defined in bayesmith.artifacts.base, line 817.
invalidate_meta(meta: ArtifactMeta, *, before: FingerprintBundle, after: FingerprintBundle, policy: InvalidationPolicy, at: str | None=None) -> ArtifactMetaThe INVALIDATED copy of ``meta`` at ``revision + 1`` (§0.2, §0.3). Same ``artifact_id``, same fingerprints -- the retired revision records what it was MADE from, not what replaced it -- with the changed input kinds and the time written into its lifecycle. ``meta`` itself is untouched, because the point of a revision is that the earlier one survives. Refused, loudly, in four cases: ``before`` is not this artifact's own bundle (so the comparison would be about some other artifact), nothing changed, the policy says this artifact kind does not depend on what changed, and the artifact was already invalidated. Each of these is a caller error that would otherwise produce a plausible-looking revision recording a judgement nobody made.