Fusiform keeps one SQLite database per host, opened through cortexkit-store
from the storage descriptor the supervisor sends in its connection handshake
(see module-surface.md). This document describes what
that database holds and the rules every write follows. The served shape of
the same data is in wire-contract.md.
Test names below are libtest paths inside each crate's integration target
(--test it), for example history::a_restore_cannot_rewind_the_catalog_version
in crates/fusiform-store/tests/it/history.rs.
Tables, as shipped: observation, era, catalog_version,
observation_artifact_event, plan_price_era, cortexkit_schema_version,
cortexkit_fence.
observation,era,catalog_version,observation_artifact_eventandplan_price_eraare fusiform's own, created by the migration chain incrates/fusiform-store/src/schema.rsunder the namespacecatalog.cortexkit_schema_versionbelongs to the store crate and records which migrations have been applied.cortexkit_fencebelongs to the store crate and is created on the first fenced write, not at open. A store that has been opened and never written to does not have it, and that is not a fault.
The list above is held against a real store in both directions by
schema_doc::the_design_note_names_the_tables_that_exist: a table the store
creates and this list omits fails it, and so does a name here that the store
does not create.
| Version | Adds |
|---|---|
| 1 | observation, era, catalog_version, and the point-in-time and uniqueness indexes on era |
| 2 | a partial index over corrected eras, so a read can ask cheaply whether a correction covers its instant |
| 3 | an index on era.observation_id, which catalog.status uses to count what each poll wrote |
| 4 | a first artifact table, replaced by version 5 |
| 5 | observation_artifact_event, an event log of artifact marks and retractions |
| 6 | plan_price_era |
A store whose recorded schema version is newer than the running binary's chain
is refused at open, and the error names the store's version
(schema_doc::a_store_written_by_a_newer_binary_is_refused). Migrations 4 and
6 are tested against stores that already hold rows
(schema_doc::the_artifact_table_arrives_on_a_populated_store,
schema_doc::the_plan_price_table_arrives_on_a_populated_store).
One observation row is written per poll, whatever happened. Columns:
| Column | Meaning |
|---|---|
source |
the upstream; models.dev is the only source |
observed_at_ms |
when the poll happened |
outcome |
changed, unchanged, not_modified, failed or seeded |
failure_class |
set only for failed: network, http_status, parse or implausible |
detail |
producer detail for diagnostics; consumers do not branch on it |
normalized_hash |
hash of the normalized catalog; moves only when a served fact moves |
raw_hash |
hash of the fetched bytes; moves when the upstream reformats |
etag |
the upstream's validator, sent as If-None-Match on the next poll |
duration_ms |
how long the fetch took |
The rules:
- A
failedpoll observed nothing. It never confirms current values and is never the near edge of an observation window (history::a_failed_poll_does_not_narrow_the_window). Anot_modifiedpoll does confirm them (history::a_not_modified_response_does_narrow_the_window). seededis not a poll. It records the instant the embedded snapshot was fetched, so the first real fetch that disagrees has a left edge for its window (bootstrap::the_seeded_observation_is_stamped_when_the_snapshot_was_fetched).- The confirming outcomes are listed once in the domain and once in a partial
index;
seed_boundary::the_schema_index_matches_the_domain_listholds the two together. - The failure class round-trips through its stored word, and an unknown word
reads back as no class rather than a guess
(
failure_class_roundtrip::an_unknown_word_reports_no_class_rather_than_guessing). - Reformatted bytes with the same normalized content are not a change
(
tick::reformatted_bytes_do_not_produce_a_change).
An era row states that one fact held one value from an instant onward. The
fact is identified by (source, provider_id, model_id, fact_key); the value is
value_json, in the served vocabulary (see
wire-contract.md §4).
The store never updates or deletes a row in era, observation,
observation_artifact_event or plan_price_era.
- There is no
valid_tocolumn. An era ends where the next era for the same fact begins. - There is no
is_currentflag. The value in force at instant T is the era with the greatestboundary_at_msnot exceeding T. - A model that disappears gets an
existenceera with value"absent"; a rate that disappears gets an era whose value is unpriced with reasonmissing_rate; a limit or capability that disappears getsnull. The old value stays readable (ingest::a_disappeared_model_is_tombstoned_and_stays_readable,ingest::a_withdrawn_rate_is_tombstoned_rather_than_left_current,ingest::a_withdrawn_limit_becomes_null). - A correction is a new era with boundary kind
corrected(§5), never an edit. - Two eras for one fact at the same instant are refused by a unique index
(
history::one_fact_cannot_have_two_eras_at_the_same_instant), and a batch of eras is written all or nothing (history::a_batch_of_eras_is_all_or_nothing). - Every write goes through the store crate's single-writer fence, which
checks that this process still holds the writer lease before committing, so
a superseded writer cannot write
(
every_write_is_fenced::no_write_escapes_the_fence).
boundary_kind is a closed vocabulary enforced by a CHECK constraint:
| Kind | Meaning | prior_observation_at_ms |
|---|---|---|
observed |
a poll saw the value change | required: the previous confirming observation |
asserted |
the source stated the effective instant | absent |
seed |
the store started from the embedded snapshot | absent; observation_id must also be absent |
corrected |
fusiform's own record was wrong over a window | absent; the four correction columns of §5 are required |
For an observed era the change happened somewhere in
(prior_observation_at_ms, boundary_at_ms], and that window has positive
width (history::an_observation_window_is_never_zero_width). A seed era claims
no window (seed_boundary::a_seed_boundary_claims_no_window). The schema and
the encoder agree on the vocabulary in both directions
(boundary_vocabulary::every_kind_the_encoder_produces_is_accepted_by_the_schema,
boundary_vocabulary::the_schema_accepts_no_kind_the_encoder_cannot_produce).
Ingest diffs the normalized document against the values in force and writes
only facts whose value changed
(ingest::re_ingesting_the_same_document_writes_nothing,
ingest::one_rate_change_opens_exactly_one_era). Values are compared as
parsed JSON, not as text, and with every field fusiform adds removed first.
That removal is one function, upstream_claim_of in
crates/fusiform-store/src/ingest.rs, used by both the diff and the catalog
digest so the two always agree about what counts as a change. A field that
fusiform attaches to a stored value, rather than one the upstream published,
must be listed there or it will open eras and move the digest
(ingest::a_producer_annotation_moves_neither_the_digest_nor_the_diff,
ingest::the_digest_moves_exactly_when_the_diff_does).
Order matters only where the upstream's order is meaningful: reordering a
modality list is not a change, reordering reasoning option values is
(ingest::reordering_a_modality_array_is_not_a_change,
ingest::reordering_reasoning_option_values_is_a_change).
A read at instant T serves, per fact, the era with the greatest
boundary_at_ms <= T. The boundary is inclusive: a read at the boundary
instant gets the new value
(serve::a_read_at_a_boundary_instant_returns_the_new_value). Facts resolve
independently (serve::facts_that_moved_at_different_times_resolve_independently).
When T falls strictly inside a later era's observation window, the served
value may already have changed. The read still serves it and reports the
bracket as uncertain on the wire. Both bracket endpoints are themselves
certain instants
(uncertain_reads::the_bracket_comes_from_the_next_era_and_excludes_both_endpoints),
and the current value is never uncertain
(uncertain_reads::the_current_value_is_never_stale).
catalog_version is a single row. Each poll that writes eras advances it to
max(now_ms, current + 1) after the eras are durable. Because the next value
is at least the wall clock, restoring an older copy of the database cannot make
the version go backwards (history::a_restore_cannot_rewind_the_catalog_version,
store_durability::a_restore_rewinds_the_row_counts_but_not_the_catalog_version),
and a clock that steps backwards still yields a larger value
(history::the_catalog_version_survives_a_backwards_clock). A failed poll does
not advance it (tick::a_failure_does_not_advance_the_version). A freshly
seeded store reports the snapshot's fetch instant as its version
(bootstrap::a_seeded_store_serves_the_snapshots_vintage_as_its_version).
The version answers "has anything changed since I last looked". It does not
identify a snapshot; see wire-contract.md §3.
A correction records that fusiform's own record of one fact was wrong over a
window. It is an era with boundary_kind = 'corrected' carrying four columns
that are required together and forbidden otherwise:
| Column | Meaning |
|---|---|
corrected_fields_json |
the field ids the correction names |
affected_from_ms |
start of the bad window; a lower bound, set to the earliest plausible instant when the true start is unknown |
affected_until_ms |
when the fix landed and fusiform stopped recording the bad value |
correction_reason |
a reference to the finding document (a defect report) that explains why the record was wrong |
The rules:
- A correction carries no value. The value in force after the window was
written by an ordinary poll once the fix landed
(
correct::a_correction_does_not_move_the_current_value). - A read at an instant inside
[affected_from_ms, affected_until_ms], both ends included, refuses that fact instead of serving the recorded value (corrections::a_read_inside_a_corrected_interval_refuses,corrections::both_endpoints_are_inside_the_corrected_interval). The catalog read omits it and names it as withheld (corrections::the_bulk_read_omits_a_corrected_fact). - A correction is scoped to the fact it names
(
corrections::a_correction_is_scoped_to_its_fact), and the recorded value is still reachable through history (corrections::the_recorded_value_is_still_reachable_deliberately). - A correction cannot reach past the instant it is recorded, so it can never
refuse a read of the present
(
correction_never_denies_now::a_correction_cannot_refuse_a_read_at_now). - The planner refuses, collecting every reason at once
(
correct::all_refusals_are_collected): a fact with no history (correct::correcting_a_fact_with_no_history_is_refused), a window that contains the value currently in force (correct::a_window_containing_the_current_value_is_refused), a value that did not change across the window (correct::a_correction_with_nothing_to_repair_is_refused), an identical correction recorded twice (correct::an_identical_correction_is_refused_the_second_time), and a store that changed between planning and applying (correct::a_poll_between_plan_and_apply_is_refused).
How an operator writes one is in operations.md.
Some polls write eras that record fusiform changing its own representation
rather than the upstream changing its data. An operator can mark such a poll;
the mark is a row in observation_artifact_event:
| Column | Meaning |
|---|---|
observation_id |
the marked poll |
action |
marked or retracted (closed by a CHECK) |
reason |
a reference to the evidence that the poll was, or was not, a representation change |
recorded_at_ms |
when the event was recorded |
The current state of a poll is its newest event. A mark excludes the poll's
restating eras (eras whose value states the same upstream claim as the one
already in force) from the last_changed_at_ms derivation; a genuine change
written by the same poll still counts
(ingest::a_real_change_inside_a_marked_poll_is_kept). A retraction appends
an event rather than removing the mark, so the history of the claim survives
(ingest::a_retracted_mark_stops_excluding_and_stays_on_the_record). A mark
changes no era and no served value.
plan_price_era holds the curated subscription prices served by
plan.prices. It is a separate table from era, keyed (provider_id, tier).
The full contract is in plan-prices.md; the storage rules
are:
boundary_kindis alwaysasserted: every row carries a date the vendor stated, with no fetch behind it. Any other kind is refused by aCHECK.boundary_at_msis the vendor's effective date. There is no column for when the row was committed, so a price recorded late is indistinguishable from one recorded on time.- A row is either priced (
minor_units,exponent,currencyandperiodall present,refusal_reasonabsent) or a refusal (all four absent,refusal_reasonpresent). Every other combination is refused byCHECKconstraints (schema_doc::the_plan_price_table_arrives_on_a_populated_store). - There is no unique key on
(provider_id, tier, boundary_at_ms). A correction of a mistyped price is a new row at the same boundary, and the row in force at T is the newestidamong rows withboundary_at_ms <= T. - The curated file is applied on every start. Re-applying an unchanged file
writes nothing, and a change of provenance alone is not a change
(
schema_doc::re_applying_the_curated_file_is_a_no_op). - A key that disappears from the file is tombstoned with a refusal row whose
reason says the key is no longer carried, rather than left serving its old
price (
schema_doc::a_key_dropped_from_the_file_is_tombstoned).
On upstream rows, model.name and provider.name are stored per model as ordinary
eras, not derived at serve time. A rename opens a new era; a missing or empty name
is absent from the catalog, with a null withdrawal era if previously published.
The provider. namespace describes the offering's provider, not the creator
of the weights. Curated model names and alias labels are served only on current
reads, not written to era history. Their provider labels are joined from current
upstream model eras, or sourced in curation for a provider absent upstream.
- Billing-plane rules, curated model rows, aliases and open-weight rate
inheritance are applied when a read is served and are never written as eras
(
ingest::ingested_eras_never_carry_serve_only_billing_states,route::billing_plane_tests::plane_views_never_change_stored_rows_or_catalog_versionincrates/fusiform-module/src/route.rs). A point-in-time read therefore replays what the upstream published, not a rule fusiform holds today. - The currency provenance of a rate is attached when it is served, not stored
(
served_vocabulary::a_stored_rate_carries_no_annotation_fusiform_invented). - Request header/body overrides and experimental mode selectors are never
stored as facts. Published client packages, endpoints and request shapes are
stored verbatim as
wire.*claims; renderer mapping remains the consumer's (served_vocabulary::unreliable_and_renderer_selecting_fields_are_not_facts).
The database runs in WAL mode so reads proceed while the poll loop writes
(journal_mode::the_store_runs_in_wal_so_reads_survive_writes). One process
holds the single-writer lease; a second instance cannot take it
(store_durability::a_second_instance_cannot_steal_the_writer_lease). Reads
use separate read-only connections that refuse writes and do not wait for each
other (unit tests in crates/fusiform-store/src/tests/read_connections.rs).