Repository navigation
Description
Follow-up to #431. PR #466 adds the raw log writer to the Rust API on v3. This issue exposes it in every binding, so the migration tool for temporal_reasoning#378 can live in the temporal_reasoning Python package. Python comes first because it is Tier 1.
What lands in core (PR #466)
pub struct FactRecord { // already public since #430
pub entity: EntityId, pub attribute: String, pub value: Value,
pub tx_count: u64, pub tx_id: u64,
pub valid_from: i64, pub valid_to: i64, // i64::MAX = forever
pub asserted: bool,
}
impl LogWriter {
pub fn create(path, opts: OpenOptions) -> Result<Self>;
pub fn append(&mut self, rec: &FactRecord) -> Result<()>;
pub fn advance_tx_count(&mut self, tx_count: u64) -> Result<()>;
pub fn tx_count(&self) -> u64;
pub fn finish(self) -> Result<()>;
}-
Records come in transaction order. A record opens a later transaction or joins the open one with the same
tx_id. Gaps are allowed, and:as-ofon a gap shows the state before it. -
The file is built at
<path>.partialand renamed into place byfinish. Dropping the writer withoutfinishdeletes the.partial. -
Errors:
- STG-043: the target or its WAL exists (at
create, and again atfinish). - API-015: a record out of transaction order, or
advance_tx_countgoing backwards. - API-016: a second
tx_idin one transaction. - API-011: two valid-time windows for one fact in one transaction.
- WAL-003: an oversize value or ident.
- API-014:
read_onlyoptions. - STG-025 or STG-026: a second writer for the same path.
A rejected record changes nothing, and the writer stays usable.
- STG-043: the target or its WAL exists (at
Design: docs/superpowers/specs/2026-10-07-log-writer-design.md.
Binding shape
- A
FactRecordrecord type with the eight fields above.valueuses the binding's existing value type.valid_to=i64::MAXmeans forever. - A
LogWriterobject with:create(path, options), whereoptionsis the record from enhancement (v3.0.0): expose open_with_options (read_only, page_cache_size, allow_unlocked) in every binding #465;append(record);append_batch(records), so a binding can cross the FFI once per batch, not once per fact. It appends in order and stops at the first rejected record, reporting its index;advance_tx_count(n);tx_count();finish().
- UniFFI objects are shared (
Arc), sofinishconsumes the inner writer behind a mutex. Every call afterfinishis a coded error, not a panic. - The error codes above reach the caller as the binding's coded error, like every other code.
- Idiom:
- Python: a context manager whose
__exit__callsfinishon success and drops the writer on an exception. - Java:
AutoCloseable. - Node:
finish()plusclose().
- Python: a context manager whose
The extract side, fact_log() as an FFI cursor (next_batch(n)), is planned with #462 (binding cursors). This issue needs the same FactRecord type, so whichever lands first defines it.
Checklist
- minigraf-python (Tier 1)
- minigraf-node
- minigraf-java
- minigraf-android
- minigraf-swift
- minigraf-c
- minigraf-wasm:
LogWriteris file-backed only (not built on wasm32), so document why it does not apply
Each binding needs tests for:
- a round trip: records appended and finished, then the reopened file gives the same
fact_logrecords andcurrent_tx_count - a hole left by a skipped transaction
- API-015 and STG-043 reaching the caller as coded errors
- dropping or closing without
finishleaving no file
Related: #431, #465 (open_with_options), #462 (binding cursors), #430 (fact log), temporal_reasoning#378.
🤖 Generated with Claude Code
Done (2026-10-07)
minigraf-python#6 (context manager), minigraf-java#9 (AutoCloseable), minigraf-android#6, minigraf-swift#6, minigraf-node#5 (finish() + close()), minigraf-c#4, and minigraf-wasm#4 (README: LogWriter isn't built for wasm32). Every binding exposes fact_log as a next_batch cursor and a lossless FactRecord; the UniFFI four share a MiniGrafValue enum. Each tests a round trip with identical records and current_tx_count, a hole, API-015/STG-043, and close-without-finish leaving no file. Use after finish/close is the new API-018 (core #468). append_batch reports (batch index N).
Activity
Merge pull request #468 from project-minigraf/feat/binding-etl-surface
feat: open options, query cursors, fact log and log writer (v3) (#6)
feat: open options, query cursors, fact log and log writer (v3) (#5)
feat: open options, query cursors, fact log and log writer (v3) (#4)
adityamukho commentedon Oct 7, 2026
All checklist items done; see the 'Done' section in the description. Ships in v3.0.0.