pyxlog lets you compile and run XLOG programs from Python and exchange CUDA
tensors with PyTorch, CuPy, JAX, and TensorFlow through DLPack. Transient inputs
and query-result handoffs share device allocations; persistent relation imports
and stored-relation exports make device-to-device ownership copies so session
state cannot be mutated through an external tensor.
Always
import pyxlog, never pyxlog._native. The package has two layers: a native
PyO3 extension (pyxlog._native) and a pure-Python wrapper that re-exports it and adds
convenience methods. Some documented methods — including evaluate_async,
evaluate_stream, the relation callbacks, temporal provenance, and the nn/4 lineage
helpers — live only on the wrapped classes. Importing from pyxlog._native directly
will make those methods appear missing.Overview
Thepyxlog Python module provides:
- Deterministic (ordinary, non-probabilistic) Datalog execution via
LogicProgram - Probabilistic inference (facts and rules carry probabilities) via
Program - Term embedding registration and lookup via
register_embedding/forward_embedding - Differentiable inductive logic programming (ILP) — learning Datalog rules from
labeled examples — via
pyxlog.ilp - Reusable diagnostics for downstream applications (“external consumers”): learned-rule inventories, audits of the tight GPU inner loop (“hot loop”), and grouped transfer metrics
- DLPack GPU tensor exchange, with zero-copy transient inputs and query-result handoffs plus owned persistent relation storage
- Optional, experimental Apache Arrow C Device interop (enabled by a build feature)
- Runtime introspection surfaces (“living-world diagnostics”): rule provenance, proof traces, incremental relation-change (“delta”) debugging, temporal relation metadata, native whole-fact relation evidence, and neural hot-loop audits
host-io Cargo build feature. Keeping them
optional lets device-result code keep result buffers out of host memory. Individual
routes can still observe bounded status or terminal-summary data; their documented
transfer measurements, not the final tensor’s device field alone, establish residency.
For the full map of runtime introspection surfaces, see
Living-World Diagnostics.
Installation
To install a published wheel:pyxlog checks for bundled CUDA kernel artifacts under
pyxlog/kernels/ and, when present, exports that directory to
XLOG_CUBIN_DIR automatically. Any pilot script, probe harness, or artifact
replay that runs outside the packaged wheel layout should set
XLOG_CUBIN_DIR explicitly before importing pyxlog, for example:
XLOG_CUBIN_DIR, startup can fail if the active install does not contain
pyxlog/kernels/.
For local development or an API present in this checkout but absent from the
selected wheel:
maturin build -i, installs the wheel
with the same interpreter’s pip, and verifies that the installed package has
pyxlog/kernels/. Generated .ptx and .cubin files remain build artifacts
and are not tracked in git.
Build Features
Build features are compile-time flags that turn optional API surfaces on:host-io: enable host-read convenience APIs (e.g.CompiledProgram.evaluate(...))arrow-device-import: enable experimental Arrow C Device export/import helpers
Semantic task binding
SemanticTransitionColdTask executes its admitted observer once during
construction and exposes task_content before final task import. This read
returns (query_identity, theory_program_identity, result_identity, truths)
with three 32-byte identities and three truth codes (0=Neither, 1=True,
2=False, 3=Both). It carries no use authority. Final import executes the
observer again and must reproduce the same identities and truths; a mismatch
refuses the native session. Cold content observation does not run the model or
prefill its cache.
The semantic controller’s task_observation_roots and import_task methods
share five explicit keyword arguments in addition to their admission and
authority inputs. import_task also requires task_priority_levels:
Import runs the authored program through XLOG’s native GPU evaluator and derives
expected Boolean answers from its completed results. There is no expected-answer
argument or built-in task. Source, selected queries, observed results, scoring,
ordered priorities, masks, and actor eligibility become part of the task identity
checked during restoration. The imported
TaskUse.task_priority_levels() returns
the exact native order before Proposal; completed task_ground.priority_levels
returns the same record after execution. TaskUse.semantic_goal_root() returns
the existing bound 32-byte native goal root after import and before Proposal;
completed task ground retains that exact root. The read requires the creator
thread and current issued task use, and does not recompute the goal or grant
execution authority. For each goal the native truth match is
normalized to zero or one. Selection compares weighted progress against the
acquired base of the current step, level by level; forbidden truth statuses
exclude a candidate before ranking. Predictive query agreement, lower measured
cost, then lowest candidate index break remaining ties. The six scoring
coefficients still measure work and return; they are not priority levels. See the
Rust task contract for scoring and
numerical-policy build requirements. These inputs replace the former implicit
task; there is no legacy fallback.
Semantic replay carrier
Each nonemptyreplay_rows entry has this shape:
basis is episode or anchor. The adapter consumes the original producer’s
training identity: manifest hash, example identifier, split, tokenizer hash and
revision, mask-policy hash, training seed, epoch and variant. These nine values
and their original digest must match the canonical record. Integers remain exact,
including values larger than 64 bits. No additional native identity projection or
rewritten record is required.
The transported material pairs retain the original ordered references and exact
bytes (or an explicitly declared reconstruction). The training-view material
uses the producer’s training-view/v2 bytes; the older v1 layout is not
accepted or converted. Its 264-byte header binds identity, source, dimensions,
answer boundary and three declared branch spans (all zero without branches).
The row then contains token IDs, MASK labels and weights, autoregressive and
causal-memory retention labels, branch labels and IDs, and the forest’s source
slots, logical positions, kinds and parents. The original bytes, dimensions,
target coordinates and branch supervision are checked before device selection.
An episode requires authentic native execution evidence. An anchor instead
retains the original admission evidence and retention group; it cannot be
selected as native execution replay or confer actor credit. Its record contains
exactly example_id, group, training_view, training_view_identity and
content_sha256 (plus the three task-content identities for a symbolic anchor).
An admitted live anchor must carry the exact envelope supplied in
live_authorities, the train partition, the durable-slow-consolidation purpose,
and both cross-request reuse and durable-checkpoint rights. The current snapshot
checks expiry and revocation on import and subsequent use. Corpus and live
anchors use the same row owner and wire domain; neither gains an invocation’s
model generation. Carrier integrity and admission do not replace the trusted
application’s fresh use permissions. Importing a carrier does not establish that
device-side training, Update publication or restoration has completed.
task_observation_roots requires the same task_scope and live_authorities
that will be passed to import_task. It binds a live anchor to that original
authority before computing coverage; import_task still independently checks
the current snapshot and use rights.
During replay, restore_invocation(task_use, restored_parent, full_row, transition) returns (original_model_output, finalize_continuation, consumer_stream). The callable retains the same original invocation; it does
not return or seal the final continuation during restoration. For Proposal,
the importer first consumes the original pack_policy result and snapshots all nine
CUDA operands before binding the same parent’s continuation. Native retains
these pending banks and the original witness, joins the supplied consumer stream,
and rechecks the original seals at continuation binding without replacing the
snapshots. Pending snapshots cannot execute or draw until that join succeeds.
The importer calls finalize_continuation(task_use, restored_parent, original_model_output) once after the policy handoff and before capture/launch,
within the same guarded import read scope and without native locks. It returns
(text_rows, text_row_count, selected_text, active_rows, active_row_count, numerical_admissibility, numerical_blocks, model_schema_digest, model_identity, tensors, producer_witness) for Proposal. Recompute and Drain omit the three
physical-certificate fields and use the same delayed callback immediately before
their continuation binding. The consumer stream is fixed by the first result;
the final callback supplies the services and their final witness, not a new stream.
This ordering does not supply a uniform numerical certificate or replace the
required pre-draw admission. During proposal replay, the native importer owns
final use of its original policy invocation and schedules native finalization before
asking the Runtime to retire its temporary aliases; reader retirement then joins
the named consumer streams. Full predecessor and successor comparisons remain
required. The Runtime
cleanup callback must not call public policy finish or backward methods during
import. A failed final-use call quarantines the original invocation, and uncertain
completion prevents reader release. Import does not retry final use, repeat
publication, or substitute a backward call.
For a prepared Proposal with a sealed physical-parameter roster,
controller.bind_continuation(..., parent=step, bank=bank, numerical_blocks=blocks, model_content_witness=model_content) consumes the
original witness returned by bind_model_content for that same Session, step
and bank. Omit model_schema_digest and model_identity: the original bank guard
must already have recorded its private acquired model-contract snapshot before
the model forward. Native retains that snapshot, the model witness and its
producer owners; the existing CUDA continuation node reads its schema and
generation identity on each replay before validating the acquired record. There
is no host identity readback, recapture or certificate reassignment after Update.
producer_witness remains the distinct transient witness covering the complete
continuation tensor roster and all seven services, including the original
FP64 [N_physical,2,3] blocks as the seventh service. Non-drawing prepared steps
omit both blocks and the model witness. Acquired replay retains the verified host
identity interface above and rejects a prepared model witness. These bindings do
not establish scientific numerical acceptance or measured ZERO TRANSFER.
The original nine policy operands are CUDA FP32 text logits [32,V], Bool8
product support, FP32 packed parameters [P], FP32 component baselines
[1,136], FP64 pointwise errors [P,2] and [1,136,2], then FP64 domains
[P,4], [32,V,4] and [1,136,4]. Errors use (O,U) order; domains use
(M,O,U,I) order. I bounds the ideal formula independently of actual magnitude
and error radii. Domain O/U cover the allowed domain; they do not replace the
pointwise errors. Supply the baseline’s independent ideal bound from its
original producer, with the same parent, step/bank, physical model roster,
generation and consumer stream as the witnessed policy pack. The actor keeps
the frozen original FP32 baseline exact; the critic retains its live envelope.
Late policy differentiation returns nine capsules: three actual FP32 parameter,
text and baseline cotangents, three full FP64 error arrays with trailing extent
2, then contiguous FP64 domains [2,P,4], [2,32,V,4] and [2,1,136,4].
The first axis is actor/full; each entry is (M,O,U,I). Full errors and
D.full.O/U come from the same result. Only the first three capsules enter the
original GraphTask. These selected-tape bounds do not certify every allowed
support or prefix before a draw, or the subsequent physical model accumulation.
This replaces the former three-field layouts; existing compiled artifacts are
not compatible with the new shapes.
Semantic runtime checkpoints
The fresh parent’sacknowledgement_payload_capacity_bytes reserves the full
receipt bytes for every possible native intent. With N = intent_entry_capacity,
P = intent_payload_capacity_bytes, and E = len(intent_effect), it must be at
least 169*N + P + (N-1)*E. The native initializer checks this bound and owns
the acknowledgement queue; callers cannot supply role 32 records. Proposal and
Drain each reserve a continuation and a delivery-acknowledgement fuel unit.
For an external effect, the trusted application binds its live receiver once
with controller.bind_delivery_receiver(task_use, recipient_id=bytes32, verification_key=bytes32, expected_effect=bytes). The key stays in the local
rights store, not the checkpoint. After FINAL, the application saves a durable
checkpoint, obtains its native intent, and sends its exact stable identity,
effect and payload to the receiver. The receiver durably records those bytes
before returning a receipt. The receipt is
b"xlog.delivery.receipt.v1\0" || stable_identity || recipient_id || LE64(len(effect)) || effect || LE64(len(payload)) || payload || record_digest || mac,
where record_digest is SHA-256 of the same identity, recipient, length and
content fields prefixed by b"xlog.delivery.record.v1\0", and mac is
HMAC-SHA256 of the receipt body under the bound key. Both domain terminators
are single NUL bytes. A retry of the same stable identity must return the same
stored receipt, without applying the effect again.
controller.acknowledge_delivery(task_use, parent=..., snapshot=..., receipt=...) checks the fresh use rights and full receiver receipt against the
actual FINAL intent, then appends it through the native publication CAS. It
returns the new (instance, word, logical_digest, state_digest); the caller
must acquire that new parent and save a new checkpoint. The CAS does no model
step and preserves the selected model allocation, text, theory, cache and RNG.
The old parent cannot acknowledge again. After a cold restore, bind the same
trusted receiver to the newly issued task use before invoking
controller.checkpoint_pending_output_intents(task_use, checkpoint). That
projection verifies both sealed queues and every stored receipt MAC, returning
only unacknowledged (stable_identity, effect, payload) rows. The older
checkpoint_output_intents(checkpoint) remains an all-intents audit read, not
a delivery queue. An exhausted FINAL parent cannot start an unacknowledged
delivery; an already acknowledged terminal intent cannot be activated again.
SemanticTransitionController.save_checkpoint(task_use, *, parent, consumer_streams, snapshot, snapshot_model_state) returns one sealed bytes
value containing the selected native publication, the task capsule, the session
allocation contract, and the application’s exact model-state bytes. The controller
joins every listed consumer stream before the cold native export. It then calls
snapshot_model_state() exactly once on the creator thread without holding the
native owner or task-state lock, and revalidates the task binding and acquired
publication before sealing the result. The callback must return exact builtin
bytes; failure or concurrent mutation returns no checkpoint.
The serializer runs inside native’s temporary controlled-reader scope for that
actual parent. It can bind and verify the selected model against the original
publication even when the stable task is Imported. Native does not invent an
inference/training operation for that state. Reader acquisition and release are
allowed for the original serializer’s aliases; build, execution, nested import,
and nested checkpoint save remain unavailable. The scope closes on return,
exception, or unwind before the post-callback checks. A saved task reference
does not retain that temporary permission.
SemanticTransitionSession.restore_checkpoint(checkpoint, *, device_ordinal, snapshot, restore_model, training_domain) validates every section and the retained
authority before allocating a fresh, never-reused native owner. snapshot must be newer than the
snapshot sealed into the checkpoint. The application must project its original
sealed input set and loader again into training_domain; it must exactly match
the saved task capsule before allocation or any model callback. After restoring
the selected native bank, the session creates one controller and task use,
acquires their parent once, and invokes
the trusted factory exactly once as
restore_model(controller, task_use, parent, exact_model_bytes). The application
must return its reconstructed semantic runtime. The frozen
SemanticTransitionRestoredCheckpoint exposes that same session, controller,
task_use, parent, and returned model through read-only properties; none is a
replacement or second acquisition.
The same controlled-reader owner encloses the factory and the existing cold
arena/learning-phase model callbacks. It permits authentic native tensor/content
reads, not segment execution or public activation of a private candidate. After
the factory returns, native closes the scope and checks the original task phase,
authority and actual selected bank. Failure retains the existing abort or
private-pending custody; closing a reader scope is not phase acceptance or
permission to retry an unknown operation.
task_use.task_objective_law() returns
(scoring_law_identity, (evaluator_min_bits, evaluator_max_bits), coefficient_bits, (cost_unit_identity, cost_cap)) before any Proposal and after
cold restore. Identities are 32-byte values; the evaluator endpoints are exact
FP64 bit patterns and the nine coefficients are exact FP32 bit patterns. The
native task freezes the proven signed return interval with outward rounding,
then sets the first six and ninth coefficients to one, the actor coefficient
to RN32(1/M) and the critic coefficient to RN32(1/(M*M)), where
M = max(1, abs(R_min), abs(R_max)) in FP64. Training arenas must retain these
same bits and structural-cost law. Reading them grants no actor eligibility,
selects no future denominator, and does not certify the full physical pullback.
The scoring-law identity binds immutable task content, not the authority binding
that a cold arena transfer must advance. Content, goal and authority checks
remain separate. The projection follows the existing immutable TaskUse read
scope, including the private arena’s model-restore callback.
Task identity now binds this frozen numerical law; older task identities are
not accepted as restoration matches.
import_task, restore_checkpoint, and admit_training_arena require the
training_domain keyword. For prospective training, pass this exact primitive
projection before the first Proposal, including when replay_rows is empty:
u64 values (positive caps, window, block size and batch size;
1 <= mask_permille <= 1000). The nonnegative integer seed is arbitrary-width
and remains lossless. The trusted application validates the manifests and their
cap/hash association; native code retains that projection, not an independent
authentication of external data ownership. None explicitly binds no prospective
training arena and cannot acquire one through later admission.
The native task/checkpoint identities retain the entire domain. Its record
bound is R = min(max_records_per_input) over the same manifests. Initial and
restored arenas require at most R distinct episode rows and at most R distinct
anchor rows, and every mandatory group keeps its actual, nonempty, nonrepeated
membership and exact denominator in [1,R]. Regular task groups use episodes;
retention groups use their corresponding anchor basis. Every packed view must
name one of those manifests and retain the seed, mask-policy identity, window,
block size and padding/mask tokens; its source extent must satisfy 2*L <= W.
The existing packed-view parser bounds branch geometry and target arrays by W.
Byte caps and arena storage capacities are never substituted for R.
task_use.task_training_domain() returns
(domain_identity_bytes, original_domain_projection) in the same immutable read
scope as task_objective_law(), or None for a task without prospective training.
This is metadata custody, not a selected future denominator, actor grant or
uniform physical numerical certificate. Task capsules now use version 3;
version 2 capsules and older task/scoring identities cannot restore under the
new binding. Restore and late arena admission require exact original-domain
equality; changed manifests, caps or loader fields cannot enlarge it.
task_use.policy_numerical_domains(parent, bank, consumer_stream) returns three
owner-bearing FP64 DLPack capsules in parameter, full-MASK text, and baseline
order, with shapes [2,P,4], [2,32,V,4], and [2,1,136,4]. Region zero is the
actor label; region one is the full label. Coordinates are (M,O,U,I), with an
independent ideal bound and separate ordinary/underflow errors. These are native
uniform pre-draw outputs, not the selected backward’s late numerical arrays.
For a prepared Proposal, pass its original step and bank 0 or 1, after
bind_prepared_policy has snapshotted all nine original operands, while its
original model work is still recording and before freezing the continuation.
During ordinary replay/restoration, pass the acquired parent and bank=None
inside the original finalization callback, after those same snapshots. The
producer joins supported category/prefix alternatives using the original policy
primitives, the frozen task law, and all permissible training denominators. No
selected receipt or second forward/backward supplies this domain.
Consume the capsules in the same retained model numerical owner and keep every
view alive through final use. The declared stream is ordered after the producer
without a host result read. Export aliases are not authoritative: native retains
the original coherent labels and checks the exports before draw. Changed bytes
are content corruption; nonfinite bounds refuse the original proposal before
its first draw. Reading these outputs grants neither actor eligibility nor a
physical certificate: the original model consumer must still propagate both
labels, accumulate all required loss groups into the actual physical parameters,
and supply both independent physical-block checks.
SemanticTransitionController.admit_training_arena(task_use, *, parent, consumer_streams, snapshot, snapshot_model_state, restore_model, replay_rows, training_objective, training_domain, dependencies, publication_grants, inference_grants, training_grants, capacities, memory_bytes, max_material_bytes, max_total_material_bytes, max_evidence_bytes, refresh_snapshot) performs a
cold structural transfer from the current, successfully recomputed inference
or training publication. This same transition can append original episodes to
an already trained session; it does not reset the learning phase or parameters.
The source must hold its original operation rights and training rights, and
replay_rows must retain the complete existing roster as an unchanged prefix.
The original pre-action training_domain must be unchanged. The method quiesces and seals
the complete native/task/model checkpoint, restores it into a private session,
then binds the larger training arena and current authority there. It preserves
the saved model, optimizer, RNG, cache, learning-phase history, and native records;
the new authority binding and
publication have new identities and digests. restore_model has the same
four-argument factory contract as ordinary restore. After that factory returns,
refresh_snapshot() must return a newer authorized snapshot. Only after both
sessions pass revalidation does the method revoke the source task use and return
the single runnable SemanticTransitionRestoredCheckpoint. A preparation
failure leaves the source runnable only when it can still be revalidated; it
never grants execution to the unfinished candidate.
Task import requires proposal_capacity=original_limit to bind the original
whole-task nonnegative U64 nominal Proposal limit. It has no omitted or None
unbounded mode. A fresh Session has no task bound until import; re-import must
provide the same original bound and retains its already spent places. Neither
the limit nor expense is inferred from fuel or effective RNG draws. This is
not a phase-program budget. The native-issued task_use.proposal_expense
returns (capacity, spent).
The complete nominal Proposal roster is charged before segment construction
enters any producer callback, not from successful RNG draws or published
results. The single-transition admission path charges its nominal Proposal
before native admission as well. Failed construction, refused/skipped slots,
failed submission and abandoned private candidates do not refund expense.
Cold arena and phase successors share that original expense owner; ordinary
restore reconstructs the exact saved value. This cold accounting adds no
host/device observation inside a captured resident loop.
The full checkpoint’s task capsule uses format 5 and carries the original
bound, nominal expense and checkpoint-source registration, separately from
paired RNG/model coordinates. Earlier formats lack some of this information
and are not silently upgraded or assigned fabricated values. A coherent
source/artifact migration is required
before consuming checkpoints made by the earlier format. The getter alone
does not prove execution or resolve an unknown admitted operation. Durable
pre/post-operation persistence and full private-program recovery remain
separate requirements; an older final-result Python counter is not their
replacement.
SemanticLearningPhaseRecipe(*, source, target, phase_index, completed_updates_index, views) describes a cold learning-phase boundary.
The supported pairs are alignment to fast, fast to consolidation, and
consolidation to fast; construction grants no scientific acceptance.
views must cover every actual model/learning view in native (role, index)
order, exactly once. Each row is (role, index, operation, source_role, source_index). Operations are preserve, zero, master-from-effective,
and phase. Unused source coordinates are zero. The producer supplies the
actual phase and cumulative-progress scalar indices, not assumed ordinals.
phase addresses that role-23 I64 scalar. zero is restricted to optimizer,
gradient, and gradient-delivery views; it cannot reset cumulative progress,
masks, rates, loss scale, effective weights, replay cursor, RNG, or budgets.
master-from-effective names a matching BF16 effective view and its FP32
role-21 master. Native code converts its exact finite value without rounding.
Full backing allocations, padding, strides, and shared storage are retained;
conflicting effects on aliases refuse the entire private candidate.
controller.prepare_learning_phase_transition(task_use, *, parent, recipe, source_checkpoint, consumer_streams, snapshot, scientific_owner, source_model, execute_phase_instruction, resource_observer, feedback_interventions, learning_grant_ref, checkpoint_destination, snapshot_model_state, restore_model, snapshot_restored_model, retire_restored_model, refresh_snapshot, phase_record_owner, phase_record_limits, frozen_program_bytes) takes the exact builtin full
source_checkpoint bytes already used by the original scientific owner. It
quiesces the successful recompute parent and verifies the supplied native state,
task capsule, original Proposal expense, Session configuration, initial prefill
and complete live model against that source. The existing checkpoint decoder and
task encoder enforce these bindings. Fresh authority must advance both the saved
source snapshot and the current task snapshot; it does not replace the source
bytes or their digest. No omitted-source or newly serialized-source fallback is
provided. learning_grant_ref selects an original durable-slow-consolidation
grant covering the complete dependency closure; fast-adaptation permission alone
cannot authorize this durable full checkpoint. Fresh publication, data-use,
retention and revocation checks remain independent of scientific acceptance.
The pending owner retains the exact original source_model, callable
execute_phase_instruction, named xlog.resource_observer.v1 capsule and
feedback_interventions tuple before entering the original issuer/store callbacks.
The tuple contains exactly two builtin bytes objects in real/control order, each
b"xlog.learning-feedback-intervention.v1\0" followed by one byte: 0 for
real identity, 1 for control positive zero. Both original materials enter the
signed admission; native does not decode the scientific program to reconstruct them.
Admission of this transport does not by itself select a private branch, apply a
numerical intervention, certify observer coverage or establish final acceptance.
The installed C header is pyxlog/include/xlog_resource_observer.h. Native
captures the original capsule table, context and interval functions before
external callbacks. Source preparation uses the original first lifecycle entry
from scientific_owner.next_operation, checked by the same store’s
decode_phase_instruction; no native program JSON decoder is added. Its nonce
is minted after durable admission, before source work. The original serializer
return is retained before validation; the interval ends once after actual source
joins, before cold trace delivery. Explicit continue_preparation() may read
that same finished interval without repeating the serializer, joins or finish.
physical_peak_bytes is usable only with PHYSICAL_PEAK_VALID and
ALLOCATOR_COMPLETED, complete requested/enabled physical coverage without an
unsupported gap, valid original boundaries/nonce/ordinal and no process
loss/error/overflow. It is the absolute simultaneously occupied physical GPU
peak of the entire original process, including the initial occupied baseline,
driver backing and physical managed residency, not a reservation or delta.
Trace completion alone does not establish physical memory. Unknown physical
completion retains the original pending, capsule, interval, model and returned
source bytes, without release, a numeric observation or subsequent execution.
The header and consumer do not supply a physical producer, whole-operation work
accounting or the complete private-trajectory executor.
The private candidate uses the actual source Session’s allocation provider and
unchanged memory_bytes limit. Its graph and native state allocations share the
source’s live resource stack and serial stream; a clone does not receive a second
native allocation budget or consume another permanent stream-pool slot. Its
execution-domain marker and native graph owner remain distinct. This owner is
acquired only after exact durable readback of the original
signed admission. This native allocation bound is not whole-phase work, model
allocation or cold-continuation qualification.
The trusted original scientific owner must implement
accept_learning_phase(parent, recipe, source_checkpoint, original_grant, destination, snapshot, actual_final_parent, actual_final_model, verified_full_final_checkpoint, frozen_program_bytes, original_history_bytes) -> bytes. Its nonempty exact builtin bytes must contain
the original frozen criteria, result, model lineage and destination acceptance.
The owner must verify those inputs against its genuine scientific result; this
privileged boundary is not a cryptographic issuer verifier and never interprets
an arbitrary acceptance flag as that result. Native captures that original
callable before issuer/store callbacks. It does not call it before private
restoration or with the former six-argument preparation interface. Only the
original complete measured prefix, with delivery as its next operation, permits
the eleven-argument comparison. A candidate checkpoint alone is insufficient.
The result or exception is retained before later validation; explicit cold
continuation cannot repeat an entered comparison.
Private copy/reset and folding instead consume the exact signed Admission
after its original issuer pin and durable readback. The canonical restore
checks the original pending, full source bytes, complete recipe and that same
Admission before allocation. Native phase lineage retains those original
Admission bytes, not an early assertion of scientific success. Native publication
material now uses format 3; format 2 is not reinterpreted as admission-bearing
material. The signed preparation outcome holds three length-prefixed materials:
the unchanged full final checkpoint, its original scientific history, and the
acceptance bytes. Acceptance stays outside the checkpoint whose bytes it binds.
This boundary migration does not implement the still-required native schedule,
whole-operation work/call measurements, private feedback binding or cold-process
recovery; refusal of an incomplete prefix is not completion of that executor.
Destination acceptance must be derived from the original durable-training
permission’s resolved scope, never merely from the caller’s destination string,
grant reference, or purpose. The original owner checks controller/tenant,
repository, confidentiality, purpose, retention/deletion, cross-request reuse,
and revocation restrictions for the full checkpoint and all derived weights;
sealed-evaluation material is excluded. Returning serialized callback inputs
does not establish this acceptance. Alignment acceptance concerns the actual
jointly trained generation. Entering consolidation authorizes that phase, not
its future result. Returning from consolidation requires an already accepted
slow generation with absorbed residual, neutral adapters, retained accepted
heads and a complete cache of that generation. Copy/reset neither performs
nor proves absorption or the scientific retention and causality criteria.
Restoration uses the same native Session allocation and task admission path as
ordinary restore. For this transition only, the trusted factory is called once
as restore_model(controller, task_use, parent, None): reconstruct from the
actual private native bank, including its new phase and reset optimizer values,
not from the old model bytes. snapshot_restored_model(returned_model) -> bytes
must serialize that complete real model, including physical aliases, optimizer
and phase state. snapshot_model_state() verifies the unchanged source model
against the supplied checkpoint; it does not create a replacement source.
refresh_snapshot() supplies strictly newer original authority snapshots.
These callbacks execute cold, on the creator thread, outside native/task locks.
Both model snapshots and native banks are checked again before any handoff.
retire_restored_model(returned_model) -> None is the original model/runtime
owner’s mandatory retirement callback, retained before the factory is entered.
Abandonment calls it once with the exact factory model while source use is still
private. It requires already canonically retired segment/evaluation consumers,
then releases the original held residency and its native/model ownership.
Native then positively verifies the original lease has
no reader, retained step, unfinished evaluation or captured executable; abort,
reader-only release and a failed identity lookup do not establish retirement.
Only after known retirement does native drop its candidate owners and resume the
unchanged source, without refunding expense. The full candidate checkpoint remains
available as cold material. A callback failure or uncertain native release retains
the same pending and candidate with unknown status; neither the callback nor a
factory is repeated. If retirement is known but later source authority validation
fails, resolution may finish that source validation without repeating retirement
or the durable resolver. This is not fresh-process or frozen-program recovery.
The source retains the native pending owner before its first serializer,
scientific callback or restoration operation. During preparation its status is
preparing; completion methods cannot be nested from those callbacks. Canonical
restore retains the actual private Session before native phase writes, then its
Controller, task use, parent and returned model as they are constructed. A callback,
restore or verification exception leaves that same pending owner unknown, with
the original callbacks and all constructed owners retained. It does not abort the
private bank, repeat a callback, refund the shared original Proposal expense or
resume the source merely because the source still matches its checkpoint. The
application must recover the same object through
controller.pending_learning_phase_transition() after an exception and retain its
original model/runtime lifetime even when no complete candidate exists yet.
checkpoint_sha256 requires a complete candidate checkpoint; no synthetic digest
is provided for an incomplete preparation. The resolver never treats absence of a
final checkpoint as proof that private operations did not execute.
abandon_prepared() cannot resolve an unknown preparation.
The original application must supply phase_record_owner before preparation, with
the explicit tuple phase_record_limits=(max_record_bytes, max_total_record_bytes, max_records) from its original run document. There are no default limits. Native
requires 0 < max_record_bytes <= max_total_record_bytes <= sys.maxsize and
0 < max_records <= sys.maxsize, checks the complete initial record before copying
its payload, and reserves a complete bounded preparation-outcome slot before
admission. These storage bounds are not checkpoint-source limits, learning rights,
or whole-execution resource accounting.
Native binds the original complete source checkpoint, frozen_program_bytes, full
five-field recipe, original grant, destination, both original feedback intervention
materials and exact storage limits to a
deterministic 32-byte pending.phase_id. The same inputs identify the same attempt.
frozen_program_bytes must exactly match the scientific owner’s program_bytes
before the signed admission is issued;
native neither synthesizes a program nor interprets a shorter program as equivalent.
pending.issuer_anchor exposes only its independently generated Ed25519 public key;
the private key remains in native memory and is never exported in a phase record.
pending.phase_record_limits returns the exact original tuple.
The same trusted store must implement:
pin_phase_issuer(destination, phase_id, native_pending) -> bytes: independently pin the public key read from the actual native-issued pending under the original exclusive lock, and return the exact durably read-back 32-byte public key. Enforce the original run/attempt mapping; a new namespace cannot evade an unresolved attempt.resolve_phase_issuer(destination, phase_id) -> bytes | None: read that same original pin without repeating its write. A key taken only from submitted signed bytes is not an independent anchor.commit_phase_record(destination, phase_id, ordinal, complete_native_bytes, sha256) -> bytes: single-attempt append-only storage and exact durable readback.resolve_phase_record(destination, phase_id, ordinal, expected_sha256) -> bytes | None | False: read the original attempt, never rewrite or replay it.
history_bytes. Each record binds its phase ID, issuer,
ordinal, predecessor digest, cumulative serialized bytes and immutable limits.
The signature covers the complete versioned record, not merely its payload digest.
Exact readback is verified against the original native key before progress advances.
An issuer/store exception or nonexact readback keeps that same pending unknown.
Use pending.resolve_checkpoint() for readback: native selects early preparation-record
readback or attempted final-checkpoint resolution from its retained state. The
application must not guess the stage from status == "unknown", try two resolvers,
or select a fallback from an exception. Early readback uses only the captured
issuer/record resolvers. It never repeats a pin, write, serializer, factory or
restoration. Resolving admission alone cannot prove completion of preparation
or resume the source. Only exact readback of the retained full preparation outcome
can restore prepared; None remains unknown and early False never proves
nonexecution. The public pending owner has no separate phase-record resolver.
The store’s resolve_phase_record callback is unchanged.
For the same live pending, pending.continue_preparation() is a separate deliberate
action, not part of resolution. Native permits it only after exact readback of the
original issuer pin, with no unresolved record write. Before native/model entry it
writes the initial Admission only if that original write was never attempted; a
confirmed Admission is not written again. Both initial preparation and continuation
use the same captured inputs, callbacks, immutable limits,
store and shared irreversible expense. Fresh original data-use rights are checked
before the remaining Admission or any native/model preparation. Successful continuation
returns the identical pending in prepared, not a runnable checkpoint; publication
remains a separate action. After entry, continuation is allowed only when the
canonical save returned the complete original candidate and native retained its
immutable checkpoint/history outcome before a late cold verification failure.
It repeats fresh source/candidate verification and issues that original outcome
once, without invoking the restore factory or scientific acceptance again. An
already attempted outcome write must instead use the existing readback resolver;
continuation cannot sign or send a replacement. Partial restoration, unknown model
execution, or failure before the complete outcome was retained stays unknown
and cannot be continued by this path. This live-owner path
does not implement recovery after process loss or prove absence of earlier GPU work.
The canonical resolver returns these distinct result/status pairs:
prepared permits a separate deliberate initial commit_checkpoint with the
same original early store, or abandon_prepared before any final write attempt.
Reading resolution must not choose either action. After a final write attempt,
native never returns to prepared or permits another commit or explicit abandonment.
If the original call raised before returning a candidate/model, those actual owners
remain private in the same native pending; only durable activation returns their
complete SemanticTransitionRestoredCheckpoint. Never reconstruct them from a
digest or manufacture a replacement candidate. Exceptions preserve the original
pending and owners, and inconsistent result/status pairs do not authorize cleanup.
Final checkpoint publication must use this same original phase_record_owner.
This interface supplies signed admission/outcome custody for preparation, not a
complete frozen-program operation journal, cold continuation, issuer rotation, or
a full private learning executor. It does not establish whole-chain freshness,
executor/GPU fencing, all-branch storage capacity or whole-execution resource usage.
The supported scientific acceptance callback takes exactly eleven arguments.
Checking its complete scientific prefix does not implement the private executor
or establish full GPU execution or cold recovery.
The returned native-issued SemanticLearningPhaseTransition retains both
owners privately. A fast successor resumes inference; consolidation resumes
training, subject to its original rights. A later fast training segment requires
current-request-fast-adaptation grants, while consolidation requires
durable-slow-consolidation grants. Phase adoption does not issue those rights
or make the resident fast Update a durable consolidation commit.
The original Session blocks further import, execution and abort until resolution.
controller.pending_learning_phase_transition() recovers that same retained
object if the application loses its reference.
Call pending.commit_checkpoint(durable_owner) exactly once. That original
owner implements commit(destination, complete_checkpoint, sha256) -> bytes
and resolve(destination, sha256) -> bytes | None | False. commit must
atomically persist the full checkpoint in the accepted destination and return
its exact durable readback. Only after readback and fresh revalidation does
native code revoke the source task use and return the single runnable
SemanticTransitionRestoredCheckpoint. Any uncertain completion leaves
pending.status == "unknown", retains both owners and forbids another commit.
For an attempted final publication, pending.resolve_checkpoint() only calls the
same retained final resolver: None remains unknown; exact checkpoint bytes allow
activation; False must prove
the write did not commit and permits revalidated source continuation only if
native code has never observed exact durable readback. Once either callback has
returned the complete original checkpoint bytes, that knowledge is retained
before fresh authority and model/native revalidation. A later False is a
contradiction: it leaves the same owners unknown, cannot authorize abandonment
or source continuation, and does not refund expense or repeat the write.
pending.abandon_prepared() is allowed only before a commit attempt.
Ordinary save/restore and resident Update preserve this phase history and
cumulative progress. The embedded native publication material uses version 2;
older native material is not accepted by this phase-owning contract.
For actor replay, retain the complete original pre-action checkpoint with its
application owner and call SemanticTransitionSession.checkpoint_referent(checkpoint)
to obtain the compact native record. Store the exact record bytes as the episode’s
downstream-snapshot material. inspect_checkpoint_referent(record) exposes its
checkpoint SHA-256 and length, original publication, model and task identities,
content and scoring identities, authority scope, the native authority_root,
and saved phase. This root is the original task goal witness’s domain-separated
authority identity, not a raw hash of authority bytes. Referent records use
version 2; version 1 records are rejected. The record is not a replacement for
the complete checkpoint. The owner must check a retrieved
source with verify_checkpoint_referent(record, checkpoint); restore_checkpoint
accepts referent=record and performs that same exact check before allocating a
new owner.
The complete checkpoint uses version 3 and the compact referent remains version 2;
the embedded task capsule uses version 5 to retain the original training domain,
whole-task nominal Proposal expense and checkpoint-source registration.
Older complete checkpoints, task capsules and version 1 referent sources are not
accepted by this contract.
Initial and recovered starts keep their original initial_prefill child and
initial-prefill-bound referent (phase 2). For a completed late Proposal whose
completed_action_projection(consumer_streams=...).initial_prefill is None,
call step.save_checkpoint(consumer_streams=..., snapshot_model_state=callback).
The callback is the original model owner’s historical serializer for that same
retained step; it returns exact builtin bytes, not a snapshot of the current
model or a new forward. The native checkpoint contains that step’s complete
pre-action publication, model allocations, random state, semantic arena and task
capsule. The full task capsule retains its original segment operation; its compact
record uses the distinct pre-action-bound phase 3 with the same version 2 field
order and extent. It contains no initial-prefill section payload.
Read step.completed_action_projection(...) again after saving. Its
pre_action_checkpoint is the same action’s native-owned completed child, kind
pre-action-checkpoint, ordinal zero, with the compact record as its payload.
This child and initial_prefill are mutually exclusive. Keep the returned full
checkpoint bytes and persist them through the application’s immutable source owner
before retiring the step. Full checkpoint bytes do not enter the episode’s material
closure. An actor episode’s downstream-snapshot must be exactly this child’s
payload, not the first step’s referent. Rebinding one action to another checkpoint
is rejected. Saving the checkpoint does not publish an actor episode or perform
the actor’s same-publication atomic append.
When importing actor replay, pass one resolve_checkpoint(digest_bytes, item_limit) -> bytes callback plus max_checkpoint_bytes and
max_total_checkpoint_bytes to SemanticTransitionController.import_task.
The native importer checks both limits before calling the resolver, validates the
complete source against the record and the episode’s original predecessor, then
calls the existing refresh_snapshot() callback after each external read. That
fresh snapshot must advance and still permit training. The callback and retained
source are cold-path responsibilities; neither runs inside the resident segment.
Missing or mismatched sources and revoked rights reject actor admission.
This also applies when no replay row is selected: actor rows cannot enter the
training arena until every resolved checkpoint has passed the fresh training-rights
check. A fresh import may also preregister the complete resolver, both finite
positive byte limits and callable authority refresh before any draw. An empty
checkpoint-dependent row set validates this group without reading a source or
executing any callback. The same group remains available to a later arena
admission; it does not grant replay, restoration or execution rights.
Native retains the original registration, including its absence. Same-Session
re-import, arena admission and phase restoration cannot replace or drop its resolver,
change either byte limit, or add a previously absent group. These checks precede
source reads and candidate-model construction; they do not rely on the caller’s
retained argument dictionary.
The same resolver also checks late children on non-actor rows: the resolved native
section must equal that replay’s full predecessor, including its original task
identity and epoch. Late source rights use the original segment operation in that
verified full task capsule, not an operation inferred from the Proposal opcode;
actor rows additionally require current training rights.
admit_training_arena and prepare_learning_phase_transition
accept the same three resolver/limit arguments and use their existing
refresh_snapshot callback. SemanticTransitionSession.restore_checkpoint
accepts all four arguments to verify checkpoint-dependent rows retained inside the
task capsule before creating a new CUDA owner. Pass the originally registered
resolver and unchanged limits; these boundaries use the same checkpoint parser.
With no referenced
checkpoint sources, the complete preregistered group is allowed, or all source
resolver/limit arguments may be absent. Partial groups are rejected.
An already registered group remains required even when no source is referenced.
Task capsule format 5 records the original registration and both byte limits along
with nominal Proposal expense. Cold process restoration takes the trusted original
file-owner callback with exactly those saved limits, validates them before any
source read or CUDA-owner construction, and retains that callback for continuation.
Python callables are not serialized. Earlier task capsules are not assigned new
limits or rewritten implicitly; source, wheel and persisted-artifact migration must
be coherent. The outer full-checkpoint format and compact referent format do not
change.
The checkpoint carries content, not current permissions. With refresh_snapshot,
restore obtains another advancing authority snapshot after the model factory
returns and checks the reconstructed native publication before activation. A callback
error or final revalidation failure poisons the new native owner
and returns no reachable carrier. Checkpoint creation and restoration are cold-path
operations; they are not evidence of device-resident execution, training, or update
publication.
Acquired model numerical identity
The existing acquired parent’smodel_context(consumer_stream=...) returns
(parent_identity, descriptor_digest, semantic_root, prefix, ring, generations, contracts, capacities, numerical_state). Its final pair contains two 32-byte
identities from the same acquisition: complete model memory geometry, and the
device-sealed numerical state. Geometry includes allocation extents, independent
storage objects, view-to-storage offsets and all model tensor layouts. The
numerical identity folds that geometry with the typed-view and full-backing
seals of model roles 18 through 25, including optimizer and gradient-presence
state. It is independent of physical bank addresses.
Cold restoration checks the stored geometry against the complete saved map and
compares the device-recomputed numerical identity with the original saved value;
it does not replace the saved identity to accept a different state.
The numerical fold excludes the enclosing parent identity and ModelContract;
the full ModelContract remains covered by the parent identity. Consequently this
pair is not a replacement for model architecture, names, executable attributes,
Tensor-object/version-counter classes, or their complete restoration contract.
It confers no independent authority. This is a cold acquired-context projection,
not a host read permitted inside the measured resident loop.
For cold execution reconstruction, the same acquired parent also exposes
terminal_state(consumer_stream=...): a single-consumer CUDA DLPack capsule of
dtype U64, shape (1,) and element stride (1,). It contains the original
acquired terminal flag (0 active, 1 requires Drain), not a value inferred
from tokens or supplied by the model. It shares the native private step-input
owner used by source() and model_context(); it does not acquire another
parent or change the nine-field context tuple. Keep the imported tensor alive
until final use, treat its bytes as read-only and name all final consumer streams
when releasing the parent. The existing current-task, live-reader and consumer
stream checks apply. This export enables the existing model reconstruction
consumer; it does not establish complete restoration or Update execution.
Initial bind_parent metadata also requires model_contract_layout, the six
byte coordinates (S_begin, S_bytes, S_digest_offset, generation_offset, N_offset, identity_offset) in the single producer-owned ModelContract (role 44).
S contains the complete immutable model schema; XLOG does not parse its format.
The schema span and four output spans must be nonempty, disjoint and bounded by
the actual record length. Digests occupy 32 raw bytes, and the generation is an
eight-byte little-endian integer; no alignment is required. The layout is retained
in the existing native runtime contract and publication material.
For a fresh parent, task_use.initial_source_layout(prefix_capacity=..., feedback_capacity=..., max_position=..., pad_token=..., provenance_capacity_records=...) returns (source, prefix, prefill_tokens, ring_head). The source and prefix contain the eight-field rows accepted by
bind_parent; prefill_tokens is the exact ordered admitted portion preceding
the 32-row active ring. The task’s observed payload and source mapping, not a
second caller token list, determine these rows. Missing tokens, invalid mapping,
capacity and text geometry are rejected. Use ring_head in initial metadata.
When prefill_tokens is nonempty, instead issue the one-use
task_use.begin_initial_prefill(...) with the same geometry and the actual
model_generation; its source_layout() supplies the same tuple. At the
original model wrapper boundary, call
stage.bind_model_content(tensors=..., model_allocations=..., consumer_stream=...)
before the forward and retain its model-content witness. The first rows
are the exact role 18–25 model tensors, followed by role-zero backing allocations
in the same order later passed to bind_parent. After model binding and before
the forward, stage.capture_tensor_content(tensors=..., consumer_stream=...)
may seal the original pre-call boundary and execution inputs. Their witnesses
may be verified immediately, but do not replace input registration or authorize
the forward. At the model’s actual pre-hook, call
stage.record_input(token_tensor=..., consumer_stream=...) on the contiguous
I64 [1, len(prefill_tokens)] tensor passed to the model. Native checks its
admitted token values on device and completes that check before returning.
Verify the pre-call witnesses again before the first model embedding. During
that one original forward, use stage.capture_tensor_content(tensors=..., consumer_stream=...) to seal each transient or autograd-saved roster at its
original production point and retain the returned content witness. Before each
dependent read, call witness.verify(tensors=..., consumer_stream=...) with the
same original tensor storage, layout and interval and the actual dependent
consumer stream; native events join it to the guard even when it differs from
the prefill stream. The model witness verifies
the complete pre-forward model roster; no witness may establish a new baseline
after output recording. Execute the original model prefill once on that stream;
at the final post-detach
hook, call stage.record_outputs(tensors=..., consumer_stream=...) with all
original cache, recurrent and accumulator tensors (roles 4–13). It returns a
SemanticInitialPrefillReceipt. Pass that exact receipt as
prefill_receipt=... to controller.bind_parent for the same task and Session,
along with the original tensor and allocation rosters. The receipt is consumed
once; a changed source, generation, tensor owner or sealed content is rejected.
The native receipt authenticates the tensors observed at these wrapper hooks;
it does not independently execute or audit the external model forward. A
nonempty prefix cannot bind without it. An empty prefix needs no receipt. The
one-use stage retires after the completed parent copy and publication join, but
the Session retains the original model and transient seals for verification
through the dependent backward reads. Retain the Python witnesses, stage,
original producers and saved autograd graph until creator-thread cleanup.
After sealing the numerical model ranges, native initialization computes
S_digest = SHA256(S) and
identity = SHA256(b"xlog.semantic.model-identity.v1\0" + S_digest + LE64(actual_model_generation) + N). It fills those four output fields before
sealing the complete ModelContract and parent. There is no separate record serial.
The sampler’s u32 generation must equal the actual native model generation;
conversion cannot truncate or wrap.
Each publication bank owns a separate record-44 destination. The existing
prepared-input producer copies the acquired record into private fixed storage,
which prepared_record exports and the retained content guard checks. Ordinary
model-preserving continuations copy the original record into the unpublished
bank before the same finalizer and sole publication. Cold restore instead compares
all saved fields against the device-recomputed values without rewriting them.
The separate Update execution, producer restoration and subsequent forward still
require their connected runtime implementation and full GPU evidence.
Original model work recording
controller.build_segment requires the frozen tensor_content_capacity,
model_work_capacity, segment_capacity_bytes, and
other_external_cuda_bytes alongside the transition schedule and producer.
The last two values bound the producer’s CUDA slab and all later external
CUDA allocation classes, respectively. Native compares their combined declared
claim with free CUDA memory before the first segment allocation, then retains
the logical reservation through segment retirement. The snapshot is a necessary
cold refusal check. The instantiated graph is uploaded and completion-fenced on
the original stream before installation; upload failure refuses the segment
before draw. CUDA may later remap graph memory, so this does not establish a
permanent graph-memory upper bound, bound external-library allocations, or prove
that the full peak fits.
Numerical domain payload and scratch are not included in this interface yet,
so this claim alone does not admit a complete numerical execution.
The prepared producer records logical work on its original SemanticPreparedStep.
After the original memory_scope.__enter__ succeeds and before graph capture,
the builder calls prepared.prepare_unpublished_successors() exactly once on
the creator thread. It must return None and create every unpublished Update
successor and its retained learning inputs inside that same private allocation
scope; preparing them before the scope would put their backing outside the
required slab. A callback failure exits the scope through the original cleanup
path and aborts the segment; the builder never retries it.
Call step.reserve_tensor_content(tensor_content_capacity) and
step.reserve_model_work(model_work_capacity) during prepare_segment, before
capture. Each positive capacity must exactly match its frozen segment value.
Native allocates both buffers from the retained segment claim, not separate
late reservations. The work capacity bounds event occurrences, including every
saved tensor; native does not run the model to discover a capacity.
During the original enqueue_step, call
step.record_model_work(kind, dimensions) for each executed operator occurrence.
kind and every dimension must be exact unsigned integers, excluding booleans.
The geometry contains at most eight factors; their checked product is the number
of units. An empty geometry describes one scalar unit; any zero factor gives zero.
For each original autograd save clone, call
step.record_saved_tensor_work(witness) with that occurrence’s original native
content witness. Native derives shape and element width from its retained tensors.
Different save occurrences count independently even when storage is shared;
the same witness/tensor occurrence cannot be charged twice. Kind 15 is reserved
for this witness-bound method and cannot be submitted as an ordinary operation.
Views are not copies; masks do not discount executed dense geometry. Do not count
an opaque operation and its assumed internal decomposition together.
When enqueue_step returns, the native transition freezes the roster and checks
its exact, nonzero model-work sum. An empty or entirely zero-work recording is
not a valid model body. The immutable geometry is uploaded after capture,
before submission, and consumed once inside the original executed IF body.
Skipped bodies incur no model charge; later numerical refusal does not erase
the forward. Counter overflow returns work_counter_overflow without publishing
a successor. The original step retains the roster and allocation through
completion and retirement. This port excludes cold preparation and later Update.
This checked model-work sum is not the full attempt bound. Complete native-event
accounting, its proved total bound, the full return consumer, and path-specific
GPU evidence remain unfinished. The model receiver does not establish those gates.
Completed-step model inputs
Before retiring a completed segment, call its original step’scompleted_model_binding(consumer_streams=[...]) to authenticate that step’s
retained model inputs. With the semantic-policy feature enabled, the result is
(predecessor_identity, successor_identity_or_None, model_generation, model_geometry_digest, model_numerical_digest, carrier_or_None). Each identity
has the four fields returned by PublishedParent.identity(). The generation and
both 32-byte digests belong to the acquired predecessor, not the final segment
bank.
For a successfully published Proposal, carrier_or_None is a frozen
SemanticCompletedModelCarrier. Its numerical_realization, logits, and
random_state properties are three separate immutable
(native_owner_identity, canonical_bytes) pairs. The first pair binds the
completed step and action realization to the CUDA execution and typed launch
identities that produced it. The second carries the retained conditional edit
FP32 distributions and their placement from that execution; it never recomputes
logits or runs a second forward. The third carries the invocation and training
RNG header followed by the ordered native draw-receipt records.
The carrier is a cold observation owned by the original completed step. It
retains that step’s native owners only until retirement; it neither reacquires a
publication nor grants execution or publication authority. Native code validates
the same completed binding before and after serializing the carrier. Recompute,
Update, Drain, and refused steps return None for the carrier; a completed
numerical refusal also has no successor. A skipped step, an uncompleted segment,
or uncertain execution cannot return a binding. When the semantic-policy feature
is disabled, the method raises its typed feature-required error instead of
returning a six-field tuple with a fabricated None carrier.
Original Update measurements
Before retirement, readstep.update_measurements on the original completed
step, between the original and repeated completed_model_binding checks. It
returns a host-only dictionary for both accepted and refused Updates. A
completed non-Update returns None; skipped, uncompleted, unknown, retired, or
custody-invalid steps raise an error. This observation joins the original
registered consumer streams and never reacquires a publication, runs a forward,
recomputes a metric, or grants candidate execution authority.
The dictionary contains schema=1, predecessor, successor, bank, the
acquired model_generation, model_geometry_digest, model_numerical_digest,
the original native transition_status, selection, canaries,
forward_receipts, and canary_refusal. The identities and acquired model fields
must equal the same completed binding; a refused Update has no successor.
selection retains the native status, roster/selected-row coordinates, identities,
training RNG and complete original replay-origin record.
canaries is the original five-check tuple, in native kind order: symbolic utility,
retained behavior, logit drift, goal chain, resource limits. Each check retains
evaluator_abi, kind, row_ordinal, identity, row_identity,
row_content_identity, task_identity, exact lower_bound_bits and
upper_bound_bits, integer memory_used, memory_limit, work_used,
work_limit, obligation_positions, protected_member_offset,
protected_member_count, and protected_positions. These are original frozen
inputs and original device counters, not phase acceptance thresholds.
Each check’s device-authored availability is "not_executed", "incomplete",
or "obtained". measurement_bits is an unsigned integer containing the
original FP64 bits only for "obtained"; otherwise it is None, never an initial
zero or a partial accumulator. An obtained measurement survives bounds,
protected-retention, goal-chain, and resource refusals. The check’s independent
native reason is 0 for admissible, 1 non-finite, 2 outside bounds, 3 memory limit,
4 work limit, 5 incomplete operands, 6 protected retention lost, 7 invalid goal
witness, 8 work overflow, or 9 generation mismatch. canary_refusal separately
retains the prioritized native reason, identities, bounds and counters, with the
same availability and optional measurement_bits as its original check. It
does not expose a partial accumulator as a complete measurement. transition_status
and the original execute_segment refusal remain independent of individual
availability; the existing segment-row format is unchanged.
forward_receipts contains the original baseline and candidate records in that
order. Each has role (0 or 1), the same availability vocabulary, and material
(None if no complete receipt was obtained). Obtained material contains role,
the actual receipt’s generation, work_sequence, scalar_type, dimensions,
strides_bytes, model_geometry_digest, model_numerical_digest, logits_digest,
identity, and canonical_bytes. Native code validates the original logits
owner/layout, receipt SHA-256, baseline binding, receipt order, and published
candidate binding when present. The candidate generation is read from its receipt,
not reconstructed as acquired generation plus one. Canonical bytes are the exact
232-byte little-endian private receipt: ten scalar words, three stride words,
then four 32-byte digests (geometry, numerics, logits, identity). The last digest
seals the preceding 200 bytes. The original pointer word is inert evidence, not a
CUDA alias or a replay capability. All returned dictionaries, tuples and bytes
are host-owned and may outlive retirement; the getter itself may not.
This port does not change the six native execute_segment row fields, objective
reductions, canary algorithms, scientific acceptance, or the lifetime required
for an unpublished multi-Update candidate.
controller.resolve_completed_segment(task_use, *, refresh_snapshot) retrieves
the original final parent and complete six-field ordered rows retained by the
same execute_segment. Native retains them before refreshing authority for
handoff. If that callback fails, the task remains in a private pending-result
phase: it cannot submit another segment, publish, save an ordinary checkpoint,
or retire its producers. execute_segment raises the native
SemanticCompletedSegmentPending exception with the original exception as its
cause. The owning Runtime must retain its producers and result-collection state
instead of using its permanent abort path for this exception. Constructing that
exception in Python grants no result or execution rights. A further authority
callback or snapshot failure while resolving that same pending handoff raises
the same native exception and leaves the original task pending. Wrong-owner,
missing-roster and cold getter failures do not gain this continuation signal.
Resolution refreshes
original rights and returns those
same owners; it does not launch, collect another device outcome, invoke model
producers, reserve nominal Proposals, or reconstruct missing results. Returned
refusal dictionaries are checked against the retained native evidence again.
Only successful reconciliation of the entire original roster, work evidence,
publication lineage and reader release establishes known completion. An
integrity failure after a completed CUDA stream remains unknown and cannot use
this resolver. These retained in-process results are not durable admission,
private-program recovery, scientific acceptance, or process-restart evidence.
Use the same step’s record(44, 0, consumer_stream=...), tensor(...) and
tensor_allocation(...) exports to serialize the original model contract and
complete model backings. Their private storage is preallocated before capture
and populated by that step’s recorded acquisition. The observation does not
acquire an old publication bank or allocate another history of model states.
Treat every export as read-only, retain it until final
use, and include every original consumer stream in the binding call. Recheck the
binding after serialization to authenticate the same original seals. Input
corruption or unknown completion prevents further use of the session.
This method joins consumers and reads device metadata on the host. Call it only
outside capture and the measured resident loop, before retire_segment. It does
not finish policy use or retire the step. Its returned identities are not live
readers, complete predecessor/successor replay materials, or authorization for a
new model invocation.
Completed-step action projection
After capture finishes and before the firstexecute_segment, every original
Proposal step exposes completed_material_capacity. It returns
((count, largest_bytes, total_bytes), (numerical_bytes, logits_bytes, random_bytes), attempt_receipt_bytes, publication_evidence_bytes), with every size in bytes.
The first triple conservatively covers all projection children, the three raw
model carriers, every raw feedback, statement, and provenance record, the complete
predecessor publication, and its native reconstruction provenance. It
counts possible materials before digest deduplication, NULL choices, lane
refusals, or winner selection, including every possible structural delta and its
evidence, task ground, scoring law, edit solution, and physical certificate.
Both frozen input banks and their original recorded policies are inspected;
future values, selected results, and device tensor bytes are not read.
The carrier lengths use the order numerical realization, structural logits,
random state. An external codec must additionally bound its real wrappers and
model-owned materials. The AttemptReceipt child is already in the first triple;
its separate size bounds consumers that retain that child. Replay-kit evidence
must instead use full publication replay evidence, reported separately,
using all six native records’ complete allocation capacities. Neither evidence
value substitutes for the other. Combine this native capacity with all external
materials, record lines, views, anchors, and indexes under the same writer caps
before allowing any submit. This getter is unavailable during capture or after
submission and does not execute a forward, authorize replay, or enable an actor.
Replay materials from completed proposals
Usestep.completed_replay_materials(consumer_streams=[...]) when you need to
replay an earlier published Proposal after later steps have reused its device
banks. Call it outside capture and the measured resident loop, after known
completion and before retiring the original segment:
Controller.export_replay_materials for held
adjacent readers. These identities and bytes belong to this exact step, not the
first parent or final successor of the segment. Native custody copies the full
semantic arena and the selected model backings before reuse. It retains the
successor’s original records inside its publisher before publication. The full
allocation roster is reserved before capture and its byte copies are charged as
native work. An unpublished refusal returns None; unknown completion does not
return material. A scheduled Proposal that actually publishes another transition
must be handled using its observed transition, not exported as a Proposal.
For every saved published Proposal, retain all five tuple parts using your
existing replay format. Pass full_p, native_provenance, and
publication_evidence to the corresponding replay roots. Neither the compact
logical-state child nor an AttemptReceipt replaces any of them. This export does
not issue a use grant, invoke a model, or retire the original step.
Use SemanticTransitionSession.inspect_publication_material(full_p) to inspect
the same complete native material without creating a CUDA session or introducing
another parser. The host-only dictionary has schema=1, the original
publication=(instance, word, logical_digest, state_digest), semantic_root,
model_generation, model_geometry_digest, model_numerical_digest,
neural_generation, cache_generation, prefix_extent, ring_head, and
prefix_identity. Identities are exact 32-byte values, not hexadecimal strings.
prefix contains exactly the committed extent and source the 32 physical ring
slots. Each row is (token, logical_position, kind, provenance, valid, committed, recomputed, provenance_record). token_provenance preserves the complete native
ledger in original order. Its dictionaries retain source_slot,
logical_position, token, base_word, proposal, ordinal,
authority_generation, action_receipt_digest, origin_logical_digest,
authority_closure_digest, and record_digest. Filled rows must resolve to their
original token and position. SOURCE and GENERATED remain distinct; generated
origins are not rewritten as admitted observations.
cache is the complete original role/index roster for cache and running-state
roles 4–13. Each dictionary retains role, index, capacity_bytes,
logical_begin, logical_end, identity, layout, and logical_bytes.
layout is (role, index, element_bytes, scalar_type, rank, logical_axis, dimensions, strides_bytes), with both final fields four-element tuples.
logical_bytes traverses logical coordinates, excluding padding and unused
capacity, and is checked against the original CUDA tensor seal. The model owner
must compare its actual source/cache operands and entry-boundary generations
against this projection through its existing model codec. Historical origin
records still require the original execution closure and rights checks; this
inspection neither proves past publication nor enables an actor. Initial-prefill
evidence remains separate and must not be discarded or fabricated.
After known completion, the existing tensor and tensor_allocation getters
read that step’s private acquired model backings, not the reused publication
banks. They preserve the original allocation-sharing partition, complete backing
capacity, typed layout, and byte offsets. The supplied bank must be the branch
that actually executed. Prefix and cache aliases use the same custody in cold
exports and input guards. During original construction these getters still
expose the declared resident bank operands for capture. Content verification
continues to require the exact original tensor owners, layouts, and intervals;
for authentic native model aliases it checks the saved bytes against the
original publication seals. Separately owned operands continue to verify their
own retained bytes. No new baseline is sealed during cold observation.
Original input custody belongs to every prepared Proposal, Recompute, and Update,
not just exported Proposals. Later transitions cannot replace an earlier step’s
completed binding or Update measurement basis. Admission reserves all of these
step owners before capture, including their full backing and semantic arena
copies; actual device copies count as native work.
For a successfully published Proposal, call
completed_action_projection(consumer_streams=[...]) before consuming the
original policy tape or retiring the segment. Completion moves the executed
policy and receipts into that tape; the projection follows its original
publication bank, not the independently advancing model-weight bank. This
export authenticates the retained completed schedule; it does not reopen the
construction-only transition API or permit another capture. The
typed cold projection returns the authenticated predecessor and
successor, logical-state materials, proposal/stream/family/action-law/model
coordinates, native winner and pre-draw actor eligibility, exact signed-return
bits, the device-sealed batch receipt and root, the retained task-result material,
and distinct action RNG base and successor materials. It exposes the native
predecessor semantic-root digest but does not turn an application’s source-text
identity into that digest.
schema_generation contains the exact retained admission-schema preimage;
its SHA-256 is the native schema-generation identity. action_law is the
generated catalogue’s canonical declaration bytes with its
SHA-256 catalogue identity. edit_codebook is the exact native codebook byte
image used by this admission and completed action, with its admission-derived
binding identity. roster is the canonical little-endian encoding of the 136
actual components, including their admission-derived cardinalities and offsets;
its bytes bind the codebook identity and hash to the roster identity. All four
use the same byte-backed material interface as the other
projection children (identity, bytes, and bytes_sha256). The codebook image
is opaque: consumers bind its bytes and identity but must not decode private
device offsets from it. Neither material claims that target, behavior, CDF,
Philox, and hard-decode laws have separate native identities.
world_root is the canonical native root material decoded from this original
step’s private pre-mutation semantic arena. Every saved published Proposal has
its actual acquired root, including after Update, Recompute, and later requests;
its identity equals predecessor_semantic_root_digest. The same decoder produces
the graph in completed_replay_materials’ full parent. This is not the initial
admission’s theory relabeled as a later predecessor.
predecessor_semantic_root_digest always names the root in the authenticated
predecessor publication header; it is distinct from the logical-state digest
and from an application’s source-text theory identity.
initial_prefill is a completed-action child material for the original cold
parent’s nonempty model prefix. It is None for an empty prefix, a later
predecessor, or a restored parent; none of those cases gains an inferred prefill
witness. The native owner retains the prefill stage consumed by bind_parent,
including its original model and output tensor seals. The material is bound to
this completed action’s owner and authenticates the same predecessor,
semantic-root digest, model generation, task use, and three task-content
identities. Its byte-backed interface is identity, bytes, and
bytes_sha256; consumers must retain all three and reference the material
from their durable episode record, not merely check it during live export.
The child envelope uses XLOG-COMPLETED-ACTION-CHILD\0, version 1, owner
identity, the length-prefixed initial-prefill kind, ordinal zero, and a
length-prefixed payload. The payload is little-endian
XLOG-INITIAL-PREFILL\0, version 1, the 104-byte predecessor publication
identity (instance, word, logical digest, state digest), semantic-root digest,
model generation, task-use identity and epoch, and query, theory-program, and
result content identities. It then contains a token count and that many u64
prefill tokens, a mapping count and that many (UTF-8 source identity length, source identity bytes, token offset, logical position) rows, followed by two
tensor-seal groups: original model content and original output content. Each
group has a count and (role, index, four u64 digest words) rows. Mapping rows
are ordered by logical position, and the native parent join checks the full
source-provenance ledger in addition to the original device input and tensor
owners. This is a cold export; it adds no host transfer to the resident step.
estimator_bound is the original pre-draw physical certificate for an
actor-eligible Proposal with a physical parameter roster. It uses the same
immutable identity, bytes, and bytes_sha256 interface. Non-actor actions
and models without that roster return None; refused or skipped Proposals and
failed preflight do not produce a projection. A learned-lane refusal after a
successful preflight does not remove this certificate. The native owner reads
the retained FP64 snapshot, never the mutable producer tensor or a selected
backward bound. The existing device preflight checks all six values per block
for finiteness and nonnegativity and checks upward-rounded 100 * ordinary <= budget separately for actor and full-step areas. A zero budget requires zero
ordinary error; the separate underflow value is not forced to zero. Export
neither changes that law nor enables actor eligibility.
The completed-action child envelope has kind estimator-bound and ordinal
zero. Its native identity binds the original completed-action owner and that
kind; bytes_sha256 independently hashes the complete envelope. The payload
is little-endian XLOG-ESTIMATOR-BOUND\0, followed by u64 format version 1,
preflight-law version 1, multiplier 100, and original publication bank. Next
come the 104-byte predecessor publication identity, model generation (u64),
32-byte model geometry, model numerics, and native training-domain identities;
then scoring-law and batch-receipt references, each consisting of its 32-byte
native identity and 32-byte SHA-256 of its exact bytes. The batch receipt binds
the original task content and successful completed-action preflight.
The next two 32-byte fields are the original model-contract schema digest and
model identity. Six u64 model-contract layout fields follow in this order:
schema begin, schema byte length, schema-digest offset, generation offset,
numerical-digest offset, and identity offset. Two length-prefixed byte strings
contain the complete original model-contract record and native runtime-contract
profile. Finally, a u64 physical-block count precedes rows in the original
sorted physical-parameter order. Each row contains a u64 UTF-8 name length,
name bytes, and six original FP64 bit patterns encoded as u64: actor budget,
ordinary error, underflow, then full-step budget, ordinary error, underflow.
The block count and names are checked against the same frozen native model
roster, including physical parameters but not buffers. Consumers retain the
whole certificate in their episode or replay material, not just its identity.
Its complete encoded size is 632 + M + P + 56*N + sum(name_utf8_bytes),
where M and P are the original model-contract and runtime-profile byte
lengths and N is the physical-parameter count. This is the certificate size,
not a capacity bound for all other Proposal materials.
theory_deltas contains one entry for each actual native insertion attempt,
ordered by learned lane then edit slot. No-edit choices and actions stopped
before insertion produce no entry. A duplicate graph support attachment is
still an attempted edit. Each entry has delta (canonical owner-bound decoded
insertion bytes), verdict (accepted or rejected for the whole lane), and
evidence (the native hard-decode, lane-admission, and selected component
receipts). lane and slot retain the native source coordinates. A losing
admitted lane remains accepted; a later lane refusal does not erase an
insertion attempt.
For an editable positive binary program, INSERT_RULE decodes one
range-restricted rule with exactly two binary body atoms. Its kind="rule"
delta binds all ten rule fields and any preceding rule edit in that lane;
theory_generation binds the admitted program and preceding rule. The task’s
three queries are evaluated against the resulting program closure on device.
Graph support insertion is not offered in this mode because it does not alter
that program closure. For a graph-support edit, kind="fact" and
theory_generation names the acquired predecessor semantic-root digest.
Neither mode currently emits a forest delta. The invocation’s result also
contains program_rules: two lanes of two optional flat ten-field rule tuples,
including attempted rules in a lane rejected by a hard constraint. These are
distinct from graph-support edit results. Its truths and correct entries
each contain three ordered triples: base, first candidate, and second
candidate, with all three task queries in every triple.
The current semantic engine generation is the catalogue generation, so
engine_generation returns the same material as action_law. observation
returns the same native four-valued task-result material as result_material;
its bytes bind the observer query and program identities, actual result bytes,
and three expected truth values. These aliases do not mint new identities.
The projection’s task_ground is the one typed semantic ground retained by the
same completed Proposal owner. It binds acquired base B, ordered query identity
Q, expected observer results, the three actual base/no-op truth codes, and the
bound goal-authority closure. Its two ordered lane outcomes are tagged
EXECUTED, with the three actual lane truth codes, or REFUSED, with the
canonical native refusal kind. task_ground.facts retains all three ordered
truth-code vectors together with native agreement, eligibility, value, and work
facts; a refused lane’s terminal tag remains authoritative.
Candidate program-closure exhaustion is typed as fact-capacity or
fuel-exhausted; it does not discard the completed base or turn a native
infrastructure failure into a task refusal.
task_ground.scoring_law is a canonical native material bound to this
completed owner, original task identity, and versioned structural-cost law.
Its six scoring_weights are, in order, correct-query, all-correct,
measured-work, improvement, refusal, and
spent-work coefficients. For each candidate, measured work is the count of
actual edit commands plus added supports (new materialized facts for an editable
program) plus defined-truth changes; candidate
value is correct_weight * correct_count + all_correct_weight * solves_expected_truths - work_weight * measured_work. Eligible candidates are
selected by ordered task-priority progress, then exact query agreement, then
lower measured work, retaining the earlier slot on ties. Value measures the
return; it does not override this selection order.
The final return is improvement_weight * (selected_value - base_value) - refusal_weight * refused_lanes - spent_weight * spent_work, where spent work is
the executed query count plus edit-command and defined-truth-change counts for
discarded lanes. return_bound is the admitted symmetric signed bound for
this task return, using the resident fact capacity for an editable program
instead of the smaller graph-support cap. It is not a bound for an external
training objective. Cold projection
checks these equations against the retained native facts and work counters
before exposing the material.
controller.structural_cost_descriptor returns (unit_identity_bytes, cap)
before import_task: the native versioned structural-work law for this
Session’s graph-only or editable-program mode. The graph-only cap is 6; the
editable-program cap is 4101, including at most 4096 new materialized facts.
The unit is independent of task identity and sampled outcomes. Use
unit_identity_bytes.hex() and cap as the objective’s cost pair. Native cold
binding rejects any different pair for the actual bound task. The completed
task_ground.structural_cost_descriptor exposes the same pair for checking the
terminal ground; slot-zero work is zero, while candidate raw work is exactly
edit_commands + added_supports + defined_truth_changes.
Learned attempted requests are not duplicated in the ground. Read them from the
same projection’s lane decoded_text_actions and decoded_edit_actions. The
optional edit_solution is present only for the lowest-numbered admitted lane
with a nonempty effective support delta that satisfies the complete bound goal
while the base does not. It binds that lane’s complete original 68-component
prefix, both native decode receipts, sealed resulting-state receipt, actual
truths, catalogue, and device-forward component materials. Its half-open edit
component interval is 32..68 for lane 1 or 100..136 for lane 2; policy winner
and score do not determine membership.
For an authenticated episode row in the supervised-edit objective,
temporal_update_vjp(...) derives that same minimal decisive lane on device from
the original completed Proposal state and bound goal closure. Its direct edit
cotangent covers only the selected lane’s 36 edit components. Text components
and the other lane receive zero direct edit cotangent; the native backward still
walks the complete original edit recurrence and original categorical choices,
masks, catalogue, and decode-bound tape. It does not resample, consume a
historical score array, or invoke the model a second time.
The projection also contains the admitted slot-zero record, learned lane slots 1
and 2 with their native admission or refusal, exact non-NULL text actions and
hard-decoded edits, and exactly
136 ordered component objects. Each component retains its selected category,
legal and active counts, exact 192-bit probability and cumulative-mass values,
CDF interval, draw, rank, Philox address, and byte-backed final-mask, PWL-cell,
active-set, selected-score VJP, component-receipt, and applicable hard-decode
receipt materials. PWL-cell and VJP bytes are original device-forward records,
not host reconstructions. The successor publication’s native AttemptReceipt
remains a separate evidence material.
The method joins declared consumers and reads retained device storage outside
the resident loop. Its opaque owner is the original retained completed-step
carrier; typed children do not reinterpret that private ABI. It never runs a
second forward or reacquires a current publication. Native rechecks the
same completed binding after serialization; a changed owner, non-Proposal step,
refusal, unknown completion, or malformed retained law closes the call.
Completed-step raw feedback
Call the same retained step’scompleted_feedback_records(consumer_streams=[...]) outside capture and the
measured resident loop. It returns
(predecessor_identity, successor_identity_or_None, records), using the same
identity and completion rules as completed_model_binding. The native input
guard brackets the readback and joins the declared consumers. The call neither
acquires another bank nor runs a new encoder or semantic query.
Records are ordered by (role, index). Each tuple contains
(role, index, generation, capacity_bytes, logical_begin, logical_end, native_identity, raw_bytes). Role 15 contains the complete fixed-capacity raw
feedback slots, including validity and native query receipts; its logical extent
retains the original occupied interval. Role 16 contains each original statement’s
bytes. Role 17 contains the original provenance records. These records are copied
by the original device acquisition into preallocated private step storage and
remain available until step retirement, independently of publication-bank reuse.
Keep each native identity: it is the original role/index/extent/content seal,
not SHA-256 of raw_bytes alone. A canonical carrier stores the byte hash
separately. Do not replace the model identity from record 44 with a new hash of
these records. The six tensors returned by feedback() are separate encoded
features and projected service values, not this raw feedback material. This
raw-feedback export does not supply the canonical logits or complete RNG state
carried by completed_model_binding, does not supply complete
predecessor/successor replay material, and grants no new execution authority.
Package Details
API Reference
LogicProgram (Deterministic)
Compiles and runs an ordinary (non-probabilistic) Datalog program on the GPU and returns each query’s answer as DLPack columns (one tensor per column).Supplying Input Relations (DLPack)
CompiledLogicProgram.evaluate(dlpack_inputs=...) accepts a dict mapping relation name to a
sequence of DLPack columns.
Persistent Named Relations (DLPack)
For repeated evaluation with long-lived GPU relations, create a persistent session instead of re-supplyingdlpack_inputs on every call.
evaluate(dlpack_inputs=...)remains the stateless one-shot APIsession()exposes a mutable named relation store with schema-checked DLPack import/export
Persistent Relation Deltas
A delta is an incremental change to a relation — rows to add or remove — applied without recomputing the whole program. Persistent sessions accept DLPack-backed deltas so a caller can update its data in a loop.insert_relation(...), delete_relation(...), and apply_relation_delta(...)
update the session’s stored relations through the runtime’s incremental-recompute
path (RelationDelta / apply_deltas_and_recompute). Updates that only insert
rows into a mutually-recursive relation group (a strongly connected component, or
SCC) reuse previously computed output where the plan allows. Updates that delete
rows clear and recompute the affected groups so results stay correct.
changed_relations, insert_rows,
delete_rows, affected_sccs, recomputed_sccs, incremental_sccs,
input_delta_count, coalesced_insert_rows, coalesced_delete_rows, and
canceled_rows. Delta debug output also includes
changed_relation_names, equivalent_to_full_recompute, debug_trace, and
nested planner_telemetry. Planner telemetry reports cache_reused,
fallback_decision, affected/recomputed/incremental SCC counts,
estimated_delta_speedup, measured_delta_speedup, and planner_advice.
equivalent_to_full_recompute is None unless the caller opts into
check_equivalence=True.
Batch updates merge repeated changes to the same relation before the runtime
recomputes, using device-resident set operations. Update dictionaries reject
unknown keys before any relation is changed. A batch whose inserts and deletes
cancel completely is a semantic no-op: changed_relations is 0, no runtime
version or callback generation advances, and no callback fires for the canceled
relation. Callback and diagnostic code must not copy relation rows down to the
host.
If a delta operation fails before commit but after preparation takes ownership
of cached derived state, the authoritative relation rows and evidence remain
unchanged, but XLOG discards the derived cache and retained runtime. The next
evaluate() rebuilds them. This makes failure recovery safe at the cost of
losing cache-hit and incremental-planner continuity for that attempt.
Calling put_relation, remove_relation, or clear_relations directly
invalidates the cached runtime store. The next evaluate() then does a full plan
run before later deltas can reuse it.
Persistent sessions keep their runtime executor across evaluate() and
delta recompute calls, so persistent hash indexes can be reused through public
pyxlog mutation loops. session.join_index_cache_stats() returns the retained
executor’s lookups, hits, misses, builds, invalidation counters,
background-build counters, entries, and total_bytes.
session.wcoj_dispatch_stats() separates successful specialized dispatches
from actual fallbacks. Its wcoj_fallback object reports total and the
chain, dedicated_multiway, free_join, planned_hash, factorized_delta,
and groupby_fusion routes. wcoj_error_decline_count is narrower: it counts
pipeline errors that declined to a fallback, not ordinary eligibility or cost
decisions.
Relation Change Callbacks
Persistent sessions expose opt-in metadata callbacks for relation delta commits:relation, generation, input_delta_count,
insert_rows, delete_rows, has_deletes, coalesced_insert_rows,
coalesced_delete_rows, canceled_rows, affected_sccs,
recomputed_sccs, incremental_sccs, and nested telemetry.
Callbacks are invoked synchronously while the pyxlog method holds the Python
GIL. Registration order is callback order, and relation events are emitted in
the caller’s update order after duplicate relation names are coalesced. This
ordering is deterministic: a regression fixture confirms that 100 repeated runs
produce identical callback sequences. Relations whose net batch update cancels
completely are omitted from mixed-batch callback sequences and do not consume a
generation number. Building a callback payload does not export DLPack tensors or
download relation data rows; use explicit evaluate() or export_relation()
when you actually need the rows materialized.
Rule, proof, temporal, and relation provenance
Compiled logic/probabilistic programs and sessions can report where their results came from (provenance):rule_provenance() returns stable rule_id, source_kind,
generation_trace_hash, support_relation_ids, and
counterexample_relation_ids fields. proof_traces() returns each query’s
answer relation, deriving rule ids, source facts, and rejected alternatives.
Temporal stream loads can keep provenance metadata next to the relation:
timestamp_column, dataset_id,
row_hashes, field_hashes, uncertainty, stream_id, source,
order_column, process_boundary, and temporal_order. Temporal metadata is a
Python helper facility; it is separate from the native whole-fact evidence API
below.
Native relation evidence binds ordered semantic roles and provenance records to
complete facts of any positive arity. The role order must match the compiled
predicate argument order, and each fact is identified by all of its cells:
name; optional sort and type fields, when present,
must match the compiled schema. Returned snapshots resolve all three fields.
Source-named predicate arguments require their compiled names. Positional
arguments accept application-defined role names on the first metadata-bearing
load, then enforce that role contract on later metadata-bearing replacements and
manifest imports. A plain put_relation, a manifest import with
metadata_present=False, remove_relation, or clear_relations removes that
positional role contract. A later metadata-bearing load may then register new
positional names. Source-named arguments always remain bound to their compiled
names.
A fact supplies exactly one of tuple or cells. tuple is the convenient
Python representation. cells is a sequence of exact
{"type": ..., "hex": ...} values for bit-preserving values such as NaNs and
signed zero. Provenance records may contain source, document, span,
content_hash, kind, and polarity; at least one field must be non-null. Two
different records for the same complete tuple remain distinct. Replacement rows
retain their stored multiplicity, so row_count includes duplicate rows. Evidence
is keyed by the distinct complete typed tuple rather than by row offset: duplicate
stored rows share one fact entry, repeated fact entries merge their records, exact
duplicate records collapse, and facts and records are returned in deterministic
canonical order.
Evidence follows the native relation lifecycle atomically:
put_relation_with_provenancereplaces both rows and evidence;- plain
put_relationreplaces the rows and clears old evidence and any positional role contract; insert_relation(..., facts=...)andapply_relation_delta(..., insert_facts=...)add evidence for inserted facts;- batch and debug updates accept
insert_factsin each update dictionary; - deleting a complete fact deletes its evidence, and coalesced or canceled batch updates cannot leave stale evidence; and
- metadata-free manifest replacement,
remove_relation, andclear_relationsremove the matching evidence and positional role contract.
facts
or insert_facts requires insert columns for the same update, a positive-arity
relation, and a role contract previously registered by a metadata-bearing
replacement or manifest import. Every annotated fact must occur in that specific
insert buffer; being present only in the session’s existing rows is not enough.
Passing an empty facts=[] or insert_facts=[] still opts into these contract
checks, although it performs no membership-mask transfer. Duplicate or already
stored inserted rows may add distinct provenance records when the annotated fact
is present in the insert buffer.
All role, type, arity, evidence-tuple membership, and batch validation completes
before mutation. A validation or pre-commit preparation failure leaves relation
rows, evidence, delta statistics, callback generations, and callbacks unchanged.
Nullary relations support plain put_relation, metadata-free inserts, deletes,
deltas, evaluation, relation, and evidence. They reject
put_relation_with_provenance, every put_relation_from_manifest and
export_relation_with_provenance call, and any insert, combined delta, batch, or
debug update that supplies facts or insert_facts (including an empty list).
Persistent replacement methods take a device-to-device snapshot of imported
DLPack columns before committing them. Mutating a retained producer tensor after
put_relation, put_relation_with_provenance, or
put_relation_from_manifest therefore cannot change stored rows behind the
session’s versions, callbacks, or evidence. This is an owned GPU snapshot, not a
zero-copy persistent import. Transient evaluate(dlpack_inputs=...) inputs and
the handoff of query-result buffers to a DLPack consumer remain zero-copy.
For each tensor-like input, XLOG calls __dlpack_device__() exactly once. Only
CUDA device memory (kDLCUDA) is accepted; another device raises BufferError
before XLOG requests or consumes a capsule. XLOG then calls
__dlpack__(stream=1) exactly once so the CUDA producer orders pending work
before consumption on the legacy default stream. If the producer rejects that
stream argument, the exception propagates; XLOG does not retry without a stream.
Raw capsules bypass both protocol calls. The caller must create each capsule for
stream 1 or synchronize its producer first, and must pass it to only one
consumer. The native importer still validates the capsule’s device header.
Breaking in 0.12.0. This device gate is new, and it applies to every pyxlog
entry point that accepts a __dlpack__ object. A CPU tensor that previously
travelled some distance into XLOG before failing now raises BufferError
immediately, at import.
Membership is checked as complete tuples on the GPU. For a non-empty evidence
set, the runtime downloads one boolean membership mask in a single transfer—one
byte per distinct fact—not the relation rows. Role-only metadata and
metadata-free manifests need no membership transfer. Use
set_strict_deterministic_d2h(True) to reject even this deterministic mask
transfer; deterministic_d2h_violation_count() reports rejected attempts, and a
rejection is atomic.
relation(name) returns a frozen native RelationEvidence captured at that
call. Later session changes do not alter it, and each provenance() call returns
fresh Python dictionaries and lists whose mutation cannot change the captured
snapshot. evidence(name=None) returns a deterministic program_hash and a
relations mapping of packed snapshot dictionaries. With evidence(name), XLOG
still computes program_hash over every stored relation in the session and only
then filters the returned relations mapping to name; named and unfiltered
reads therefore share the same hash at the same session state. These are native
session snapshots, not Python package sidecar records.
Invalid role, whole-fact provenance, insert-evidence, or manifest input raises
pyxlog.RelationMetadataError, a ValueError subclass. Looking up an unstored
relation with relation(name) or evidence(name) raises KeyError. Without
pyxlog._native, the package-level RelationMetadataError and
RelationEvidence names remain importable. The fallback metadata error still
subclasses ValueError; constructing the fallback RelationEvidence raises
RuntimeError because it has no native snapshot. Native evidence instances and
all session operations require the extension. Source builds that compile the
extension expose this API; for a packaged build, determine availability from that
release’s notes.
Provenance manifest round trips
Use the paired DLPack-and-manifest API to reconstruct rows and native evidence in another compatible session:xlog.relation-provenance version 1 shape. Its
required top-level fields are format, version, predicate, row_count,
metadata_present, roles, and facts. predicate contains name, arity,
and the compiled schema_sha256. Manifest facts contain identity, exact
cells, and fixed-shape provenance records; they intentionally omit the
friendly tuple. Every dictionary level rejects missing or unknown fields.
version, arity, and row_count must be non-negative Python integers, not
booleans, and metadata_present must be an actual Python bool. If it is false,
both roles and facts must be empty and importing the manifest resets any
registered positional role contract.
Each exact cell contains only type and hex. Its type must match the compiled
column, and its lowercase hexadecimal value must encode exactly that scalar
type’s little-endian byte width; a boolean cell is exactly 00 or 01. Manifest
provenance records contain all six fields (source, document, span,
content_hash, kind, and polarity), using None for absent values. A
non-null span contains exactly start and end; both are non-negative Python
integers rather than booleans, both must be representable as u64, and
start <= end.
The schema fingerprint includes the predicate name and arity plus every compiled
column’s name, scalar type, and optional source-domain sort. A fact identity
includes the predicate name and arity plus each cell’s type code, byte length,
and exact bytes; it does not include provenance records. Both hashes use
domain-separated SHA-256 inputs. Fact identity is independent of row position
and role labels, and import recomputes both hashes instead of trusting the
supplied strings.
Import validates static manifest structure, compiled schema identity, and column
count before consuming a DLPack capsule. Once column import starts, all supplied
capsules are consumed before dtype, equal-column-length, manifest row-count, and
whole-fact membership validation completes. A failure at any of those stages
still leaves the target relation and evidence unchanged, but the spent source
capsules cannot be reused. Successful import consumes every column once.
Fact and record order and exact duplicates are normalized deterministically.
The DLPack columns are process-local, single-consumer ownership objects; the
manifest may be serialized as data, but it does not contain the relation columns
and is not a cross-process persistence format. Keep the exported columns alive
until import consumes them. For portable storage, use a host-serialized relation
format and treat native manifest reconstruction as a separate in-process
operation.
Migrating from Python-side relation evidence
The native API replaces the earlier Python helper contract. The oldrelation_schema, source_path, source_hash, row_hashes, field_hashes,
accepted_count, rejected_count, output_path, output_hash, and
decision_counts keyword arguments are not accepted by
put_relation_with_provenance. Pass ordered roles and complete facts
instead. A per-fact source location can map to a record’s source or document,
and a per-fact source digest can map to content_hash; XLOG derives exact fact
identities from the typed cells. Row/field hash collections, output locations and
hashes, and aggregate acceptance, rejection, and decision counters remain
application-level data rather than native whole-fact evidence. The returned
snapshot and evidence() payload contain native roles and facts, and unknown
named reads raise KeyError instead of returning an empty sidecar record.
Runtime controls and diagnostics
Long-running callers can submit logic or probabilistic evaluations to a background Python worker withevaluate_async(...). The returned
AsyncEvaluation is awaitable and also exposes done(), cancel(),
exception(), and result(timeout=None) for synchronous orchestration.
memory_mb is accepted by CompiledLogicProgram.evaluate,
LogicRelationSession.evaluate, CompiledProgram.evaluate, and
CompiledProgram.evaluate_device. A zero limit raises ValueError; a limit
below the provider’s current tracked allocation raises MemoryError before the
evaluation starts. The provider-level compile-time budget remains the hard GPU
allocator budget.
Runtime progress and diagnostics are exposed as stable dictionaries:
memory_stats() reports allocated_bytes, memory_limit_bytes,
peak_memory_bytes, and status. peak_memory_bytes is the high-water mark of
successful reservations recorded by the shared provider’s memory manager. It
spans the provider lifetime (or the window after an explicit quiescent reset),
so it is not reset between evaluations or executors that reuse that provider.
It is not physical/NVML usage, and direct CUDA allocations that bypass the
manager are not included. CUDA Graph stats report
csm_cuda_graph_captures, csm_cuda_graph_launches,
csm_cuda_graph_fallbacks, and csm_cuda_graph_cache_hits. If an environment
cannot supply a given diagnostic, it reports an explicit unavailable status or
error rather than a fabricated zero.
neural_hot_loop_diagnostics() is the single audit surface for the neural inner
loop. (nn/4 is a neural predicate declared with four arguments — the
classification form, which carries a list of output labels.) It reports
post_load_dtoh_bytes, post_load_htod_bytes,
control_plane_bytes_per_iteration, scalar_sync_checks, nested
cuda_graph, and nested circuit_cache diagnostics from the same runtime API.
When this runtime cannot yet provide a separate control-plane or scalar-sync
counter, the corresponding value is None and a *_status field explains why.
The top-level pyxlog wrapper also carries nn/4 training lineage:
checkpoint_hash, split_hashes,
calibration_metrics, and cuda_device. Its influence_audit object keeps
registration metadata under registration and copied event snapshots under
records; each event includes the changed_acceptance evidence recorded through
record_nn4_influence(...). Reading named lineage or recording an event for an
unregistered network is an error.
register_network also accepts three keyword-only arguments that record and
check the network’s typed signature. All three are available since 0.11.0:
arity=is the declared argument count. XLOG validates it against everynn/4declaration bound to that network name in the program rather than trusting it; a disagreement raisesValueError.arg_sorts=is a sequence of integer sort ids, one per argument. It requiresarityand must have exactly that length. Aboolelement is rejected outright — Python’sboolis anintsubclass, soTruewould otherwise be read as sort id1.artifact_hash=records the checkpoint identity.
program.network_metadata("mnist_net") reads that back, together with what the
program itself declares:
Epistemic evidence -> exact probability
CompiledLogicProgram.evaluate_conditioned(prob_source) runs a compiled epistemic
program (know / possible) on the GPU and conditions an exact probabilistic query
on its accepted world view. Only facts declared in the epistemic program’s own
source feed that world view.
Limitation: unlike evaluate, this method does not accept dlpack_inputs.
Caller-supplied input relations are NOT consulted. If the epistemic program depends
on a relation that would normally be supplied at call time via
evaluate(dlpack_inputs=...), that relation is empty here, no world view is
accepted, and evaluate_conditioned raises RuntimeError:
epistemic_evidence() first — it reports
accepted_world_views == 0 and does not raise.
gpu_conditioned_circuit_preparation_compiles counts actual GPU circuit
compiler invocations owned by that prepared handle: it is 1 after a fresh
compile and 0 after a verified disk-cache restoration or GPU-cache hit. The
three origin counters above are mutually exclusive for the handle’s single
materialization. Every later evaluation reports zero source/program compile
deltas.
For an independent lifetime-reuse check, compare the
gpu_conditioned_circuit_generation and gpu_conditioned_circuit_cache_slot
trace pair across evaluations. It is derived from the retained exact state and
cache handle and must remain unchanged as priors are updated. The generation is
opaque and process-local; do not persist it or compare it between processes.
These reuse keys are present on every EpistemicEvalResult. Results returned
directly by evaluate_conditioned() carry zeroes for the reuse fields;
gpu_conditioned_circuit_generation == 0 is the sentinel that no prepared
circuit identity is attached. A prepared evaluation always reports a positive
generation.
set_fact_probabilities() validates the complete mapping before one serialized
state change. Each variable id is its prob_var_map() list index. Index 0 is
unused padding with kind == "other", not a mutable variable id, and only
entries with kind == "fact" are mutable. Annotated-disjunction choices,
compiler-introduced entries, Monte Carlo and count-lift programs, non-finite
probabilities, and values outside [0, 1] are rejected without a partial update.
When a mutable fact is itself fixed by accepted evidence, changing its prior keeps
the evidence assignment fixed and changes the evidence likelihood (log_z_e),
matching a fresh conditioned compilation at the new prior.
Evaluations and setters on the same prepared handle serialize. Coordinate access
at a higher level when an application needs an update and its following evaluation
to behave as one larger transaction.
Waiting for the prepared handle’s shared native state, including in
prob_var_map(), releases the Python GIL. The Python dictionaries are constructed
only after the native metadata snapshot completes. A failed device write is rolled
back before set_fact_probabilities() returns. If that rollback also fails, the
prepared circuit is permanently invalidated: every later evaluation, gradient,
metadata read, or setter through that handle or any clone fails closed rather than
using potentially partial device weights.
On a CUDA device, conditioning 0.6::fact(). query(fact()). on know fact() raises
P(fact()) from the unconditioned 0.6 to the exact 1.0: the epistemic layer
already accepted fact() into its world view before the probabilistic query ran, so
result.log_z_e is ln(0.6), not 0.0.
result.log_z_e is log P(evidence): the exact log-probability of the conditioned
evidence under the probabilistic program’s distribution, computed by weighted model
counting over the compiled circuit, not the log-evidence of the whole query program.
Query probabilities are exp(log_z_eq - log_z_e). When the conditioned atoms are
independent root facts it coincides with the log of the product of their priors —
measured on GPU, one known atom at prior 0.6 gives log_z_e == ln(0.6) and two known
atoms each at prior 0.5 give log_z_e == ln(0.25) — but that is the independent-root
special case, not the definition. Evidence on a derived atom (0.6::a(). b() :- a().
with know b() gives ln(0.6) though b has no prior), on atoms sharing an ancestor,
or negated evidence all depart from the product form.
Trace invariant. Conditioning reached the GPU exact path when
gpu_conditioned_evidence_facts — the total the engine itself validates — is
non-zero. A direct result also requires the GPU exact, PIR/CNF, and
knowledge-compilation event counters to be positive; a prepared result instead requires
the prepared-circuit reuse counter to be positive, reports one materialization, and
identifies exactly one compile/cache origin. The four evidence classes
(gpu_conditioned_know_evidence_facts, gpu_conditioned_possible_evidence_facts,
gpu_conditioned_not_known_evidence_facts,
gpu_conditioned_not_possible_evidence_facts) decompose that total; a possible-only
or negated-evidence program conditions correctly with the know class at 0, so
check the total rather than the know class alone.
EpistemicEvalResult carries atoms, prob and log_prob (DLPack capsules, like
EvalResult), log_z_e, and trace. CompiledLogicProgram.epistemic_evidence()
runs the same epistemic program and returns an EpistemicEvidence with the
accepted-world-view counters alone (epistemic_mode, know_operator_count,
possible_operator_count, accepted_candidates, rejected_candidates,
accepted_world_views, final_output_rows), without touching the probabilistic
tier. Like evaluate_conditioned, it only ever sees facts declared in the
program’s own source — but a program that depends on a caller-supplied relation
reports accepted_world_views == 0 (with accepted_candidates and
final_output_rows at 0) here rather than raising. know_operator_count and
possible_operator_count are plan-level censuses and stay non-zero even then, so the
state to check is the accepted/consumed family, not “every counter”.
Which plans are accepted. Only single-component epistemic plans are supported;
split, stratified and WFS plans raise instead of being silently reduced. Both
epistemic modes reach this surface: FAEEL programs and non-recursive
#pragma epistemic_mode = g91 programs both lower to a single-component epistemic
plan and condition normally. epistemic_evidence().epistemic_mode names the mode, and
the trace’s accepted_faeel_world_view_evidence_consumed /
accepted_g91_world_view_evidence_consumed pair says which one supplied the evidence.
Only the recursive G91 shapes — positive possible cycles that need tuple-level
compatibility — compile to a dedicated G91-compatibility plan and are rejected at
planning.
Rejection also covers one case that reads like a false negative: an admissible
recursive modal program such as reach(X, Z) :- reach(X, Y), know link(Y, Z). is
reduced to ordinary recursion at compile time (the ordinary_recursive_modal_reduction
provenance class). The reduction erases the world-view machinery, so there is no
accepted world view left to condition on and the program is rejected as “ordinary”
despite being full of know. That is deliberate, not a compiler bug. A real CUDA
device is required.
Program (Probabilistic)
Compiles and runs a probabilistic Datalog program — facts and rules annotated with probabilities, such as0.3::rain — and computes query probabilities. The
prob_engine argument selects the inference method: "exact_ddnnf" compiles the
program to a Boolean circuit (a deterministic, decomposable negation normal form,
or d-DNNF) that makes exact probability and gradient computation tractable, while
"mc" estimates probabilities by Monte Carlo sampling.
Host Outputs (Requires host-io)
When built with --features host-io, you can call CompiledProgram.evaluate(...) to get host-derived
probability outputs as device tensors (DLPack):
Monte Carlo Inference (Device-Only)
For device-result workflows, preferCompiledProgram.evaluate_device(...): result
buffers stay on the GPU, while the runtime may still observe its bounded terminal
status and convergence summary.
The optional samples, seed, confidence, sampling_method, and
max_nonmonotone_iterations arguments override the corresponding source pragmas only
when supplied. When an argument is omitted, Python uses #pragma prob_samples,
prob_seed, prob_confidence, prob_method, or
prob_max_nonmonotone_iterations; if neither layer supplies a value, the documented
language default applies. This is the same source-then-explicit-override precedence as
the CLI. Supplying any of these Monte Carlo options, or allow_cpu_oracle=True, to an
exact-engine evaluate(...) call is an error; the binding does not silently ignore them.
Monte Carlo Inference (Host Outputs, Requires host-io)
When built with --features host-io, CompiledProgram.evaluate(...) computes probabilities and
confidence intervals and uploads them as device tensors (DLPack):
Experimental Arrow C Device Interop (Feature arrow-device-import)
These helpers bridge XLOG’s DLPack columns to Apache Arrow’s C Device interface —
a standard for sharing columnar data that already lives on a device (GPU) —
without host copies. When built with --features arrow-device-import, pyxlog
exposes:
pyxlog.export_arrow_device(...) -> PyCapsule(namearrow_device_array)pyxlog.import_arrow_device(...) -> (dlpack_tensors, names, num_rows)
Bool.
JointConstraintCarrier (joint constraint solving)
pyxlog.JointConstraintCarrier picks one label per entity subject to pairwise
constraints, entirely on the GPU. Its result buffers are handed back as DLPack
capsules, so a caller never copies them to the host. Available since 0.11.0.
register_schema(catalog_sha, solver_identity)must be givenpyxlog.SOLVER_ABI_IDENTITY— a module-level string naming the solver ABI this build speaks — so a carrier cannot be driven by a mismatched client.bind_signatures(head_masks, tail_masks)must run before any solve.note_producer_stream(...)andnote_consumer_stream(...)perform the CUDA stream handoff when the buffers cross into or out of another library’s stream.fuel_spentis a read-only property reporting how much offuel_limitthe solves consumed.
pyxlog.CarrierRefused, and running out of fuel_limit raises
pyxlog.SolverResourceExhausted. See Error Handling.
Term Embeddings
Theregister_embedding / forward_embedding API enables explicit PyTorch-side embedding training
through the logic program. Embedding predicates use the label-free nn/3
declaration form (a neural predicate declared with three arguments and no output
label list).
Embedding Registration
Forward Lookup
Cross-Registration Validation
- Embedding declarations (
nn/3, no labels) rejectregister_network()— error directs toregister_embedding() - Classification declarations (
nn/4, with labels) rejectregister_embedding()— error directs toregister_network() - Same network name as both embedding and classification → compile-time error
Constraints
trainable=Truerequiresnn.Embedding; rawtorch.Tensorwithtrainable=TrueraisesValueError- Raw tensors with
requires_grad=Trueare detached at registration (frozen contract enforced) - Integer IDs only (symbol/string lookup keys deferred)
- Optimizer ownership is user-managed; classification-network optimizer helpers do not cover embeddings
- Inference through rules (dot/cosine evaluation, grounded query API) is deferred to future embedding-rule integration
Training Loop API (Neural-Symbolic)
For neural-symbolic training with neural predicates (nn/k — a predicate backed
by a neural network), Program exposes loss computation, optimizer stepping,
gradient clipping, learning-rate control, and batched training loops, in addition
to the single-query forward_backward* helpers.
Loss computation
Thenll_loss* helpers compute a negative log-likelihood (NLL) loss — the
standard training objective that penalizes low predicted probability for the
target answer.
External Consumer Bridge Helpers
These helpers keep a four-valued evidence model (Belnap logic) in the Python/ML layer: each candidate carries separatepro (evidence for), contra (evidence
against), and quarantine (held-out) scores. The GPU structural kernels never see
those channels. The helper surfaces operate on PyTorch tensors and preserve
autograd unless the caller explicitly detaches inputs.
deterministic_topk(...) resolves ties by lower input index. neural_cache_stats()
reports circuit-cache size, hit/miss counters, template compile count,
query-signature cache size, and registered-network cache/top-k/deterministic
configuration. belnap_loss(...) returns a dictionary containing loss,
pro_reward, contra_penalty, quarantine_penalty, cfr_regret_proxy, and
the formula string.
Registered-network output modes reuse the existing register_network(..., k=N, det=True) configuration. forward_backward_tensor(...),
forward_backward(...), and batched neural-query training apply the configured
stable top-k or deterministic top-1 mode before NLL loss and cached circuit
probability import. Deterministic mode picks a single hard top-1 value on the
forward pass, then routes gradients straight through the selected probability on
the backward pass (a straight-through estimator, so the discrete choice still
trains).
Optimizer and scheduler control
Batched training epoch
Profiling
ILP Training (dILP Beta)
Thepyxlog.ilp subpackage provides differentiable ILP (Inductive Logic
Programming): it learns Datalog rules from labeled positive and negative examples
by gradient descent, treating rule choice as something that can be optimized like
neural weights. This surface is beta.
Training API
Artifact Persistence
TrainConfig Fields
The temperature fields (
tau_start, tau_floor) control a Gumbel-softmax
relaxation — a technique that makes discrete rule choices differentiable so they
can be trained by gradient descent. Training starts hot (tau_start, soft and
exploratory) and anneals toward tau_floor (sharp, near-discrete).
Result Types
External Consumer Diagnostics
These helpers package the ILP audit surface for downstream applications (“external consumers”) as reusable pyxlog utilities:NeuralBodySpec carries an opt-in train_phi_gradient flag, default False.
Left at the default, the entity features φ(x) are detached on the training
upload, and the uploaded values are byte-identical to earlier releases. Set it to
True to leave φ(x) attached, so gradients flow back into whatever produced the
features (backbone coupling). Only the autograd linkage changes — never the
values that are uploaded. Available since 0.12.0.
train_and_promote(...) accepts transfer-audit metadata through
training_fold, held_out_domains, base_kernel_checksum_before, and
base_kernel_checksum_after. The returned PromotionResult.rule_inventory
records those values with selected and rejected clauses, scores, and gate
outcomes.
Device Query APIs
For GPU-native ILP workflows,CompiledIlpProgram exposes device-resident query
helpers (results stay on the GPU) alongside the existing host-returning helpers:
batch_fact_membership()andbatch_tagged_credit()remain available for host-materialized Python outputsbatch_fact_membership_device()returns a DLPack bool tensor on CUDAbatch_tagged_credit_device()returns CSR-style device outputs:fact_row_offsets,entry_indices,entry_i,entry_j,entry_k- The device query path avoids semantic-loop device-to-host transfers; inspect
host_transfer_stats()/reset_host_transfer_stats()when enforcing that contract in tests - Unsigned metadata/count tensors are exported as DLPack
int32for broad framework compatibility
Bounded Exact Induction API
Bounded exact induction searches a bounded space of candidate rules and scores each one exactly on the GPU, rather than optimizing rule choice by gradient descent.pyxlog.ilp.induce_exact(..., backend="native") is the GPU-native
scorer. The public entry point returns an ExactInductionResult containing
ScoredCandidate rows grouped by join shape (topology): chain, star,
fanout, then fanin.
backend="python", strict_per_topology=True; leaving strict_per_topology
at its default preserves legacy prototype behavior and is not semantically
equivalent to native scoring.
Exact induction accepts pair relations whose two columns share one of these
scalar types: u64, u32, or symbol. Generated ilp_exact.portable.ptx and
.cubin files are packaged build artifacts, not checked-in source files.
Sparse Mask APIs
A rule mask selects which candidate rules are active during training. Sparse mask setters let you pass only the selected candidates instead of a full dense vector.CompiledIlpProgram exposes two:
set_rule_mask_sparse(name, candidate_ids, soft_probs, budget, allow_recursive=False)is the legacy compatibility path. Rust receives the full candidate soft-probability vector and ranks it internally.set_rule_mask_sparse_selected(name, selected_candidate_ids, selected_soft_probs, allow_recursive=False)is the preferred inner-loop path. Python/Torch performs ranking on CUDA, then Rust consumes only the selected subset and preserves that order as the sparse active-rule list.
GPU-Native Contract
For Python consumers that need an auditable GPU-native ILP inner loop, the intended contract is:- Zero provider-tracked device-to-host transfer inside the semantic loop:
set_rule_mask_sparse_selected(...),batch_fact_membership_device(...),batch_tagged_credit_device(...), andcompute_ilp_loss_grad_gpu(...) - Metadata/control-plane reads may still occur behind public runtime/provider helpers such as cached row-count access; these are not relation-column materializations
- Compatibility paths that are not suitable for a strict GPU-native inner loop:
set_rule_mask_sparse(...),batch_fact_membership(...),batch_tagged_credit(...), and any host-output API gated behindhost-io - Use
host_transfer_stats()/reset_host_transfer_stats()to audit the provider-tracked transfer behavior of the chosen path
DLPack integration
XLOG accepts CUDA-backed DLPack producer objects and returns single-consumer capsules. Transient input imports and framework wrapping of query-result capsules are zero-copy. Persistent relation replacement takes an owned device-to-device snapshot, and stored-relation export leaves a device-to-device clone in the session before transferring the exported allocation. Compatible CUDA-backed producers include:- PyTorch
- CuPy
- JAX
- TensorFlow
- Any CUDA-backed DLPack-compatible library
Input via DLPack
Your producer’s__dlpack_device__() must return an exact two-item tuple
(device_type, device_id). The device type accepts an integer enum such as
PyTorch’s CUDA tag, or another int instance with value 2; bool is rejected.
The device id must be an exact Python int in 0..=2147483647 and match the
selected native device. XLOG reads the integer payload without calling custom
__int__ or __index__ methods. This device-specific reader does not relax
general metadata validation or replace validation of the actual DLPack capsule.
Output via DLPack
dlpack_roundtrip helper
dlpack_roundtrip sends a CUDA tensor into XLOG and returns it as a fresh DLPack
capsule — a quick way to verify zero-copy interop end to end. All three arguments are
required:
Compile Options
LogicProgram.compile()
Program.compile() (Probabilistic)
Result Objects
Deterministic Results
Probabilistic Results
Device-Only MC Results
Error Handling
Python exceptions are raised for errors:relation(name) and evidence(name) use KeyError for an unstored relation.
export_relation_with_provenance(name) uses ValueError for the same condition.
The joint-constraint carrier raises two exceptions of its own, both
RuntimeError subclasses, available since 0.11.0:
pyxlog.CarrierRefused— every typed refusal: a schema or ABI mismatch, a zero-capacity dimension, use beforeregister_schema, rebinding already-bound signature masks, a signature-mask shape mismatch, solving beforebind_signatures, running the top-two stage before feasibility has solved, a malformed component plan, an out-of-range abstain label index, or an unavailable joint-solve kernel.pyxlog.SolverResourceExhausted— a solve used up itsfuel_limit, with the messagesolver fuel exhausted: spent {fuel_spent} of {fuel_limit} node expansions. The fuel meter lives in the carrier session, so a retry reproduces the identical refusal instead of making partial progress; build a new carrier with a largerfuel_limit.
Memory Management
- An unconsumed output capsule owns its exported GPU buffer and releases it when garbage collected.
- A framework conversion such as
torch.from_dlpack(capsule)consumes that capsule exactly once and takes over its managed-tensor ownership. - Passing a CUDA tensor object lets XLOG request a fresh capsule through the producer protocol. Do not manufacture or reuse raw input capsules unless you also satisfy the stream-ordering and single-consumer contract.
- Persistent relation replacement and stored-relation export use owned device-to-device copies rather than mutable views of session storage.
Thread Safety
compile()is thread-safeevaluate()is NOT thread-safe on the same program instance- Use separate program instances for concurrent execution
Examples
Integration with PyTorch
Batch Processing
Read-only semantic model evaluation
Thesemantic-policy native build provides
SemanticTransitionController.prepare_model_evaluation(task_use, parent, model_work_capacity=..., cohort=None) for an already admitted training operation
and its genuine acquired parent. It does not construct an Update, run backward,
draw randomness, update an optimizer, or publish a successor.
The returned SemanticModelEvaluation owns one recording. Export its
training_view(consumer_stream=...) and model_work_buffer(consumer_stream=...)
before begin(), then use the existing model content scope on the same parent
and the existing numerical/work registrar on the evaluation’s consumer_stream.
record_model_work(kind, dimensions) and
record_model_device_work(kind, upper_dimensions) use the same native recording,
geometry rules, scratch layout, and device work consumer as prepared execution.
Saved-autograd-copy recording is intentionally unavailable: this invocation is
forward/objective-only.
Retain evaluation.cohort separately for later observations. Passing that native
object as cohort= reuses the exact original seventeen ports and their private
content seals, including across full checkpoint restoration; no final-model RNG
selects another group. The cohort does not retain a Python Runtime or model.
The trusted phase owner must still bind the original source checkpoint and all
private branches; this API alone is not scientific phase acceptance.
finish(output_witness, consumer_streams=...) consumes the original parent’s
native content witness containing exactly three tensor rows, with role zero and
indices zero, one, and two: contiguous FP32 [6] losses in the numerical
producer’s canonical order, Bool [1] numerical admissibility, and the original
contiguous UInt8 slab backing. Outputs must lie in that actual CUDA allocation,
which must not alias publication storage. Native joins all consumers, validates
the original cohort and witness, consumes actual work, and rechecks the complete
original publication, including model allocations and RNG. It then returns
status, six loss_bits, model_work, operation_count, work_bound, and
retained_allocation_bytes. Status zero means the cohort, numerical outputs, and
work recording passed their native checks. Status one is a completed refusal:
the original selection refused, numerical admissibility is false, or at least
one loss is nonfinite. Status two means work overflow, an incomplete event count,
or a work-bound mismatch; it takes precedence over numerical refusal and does
not certify complete work. Neither nonzero status is a loss certificate. Do not
record status two as an ordinary numerical refusal or retry the invocation.
Operation count is registrar occurrences, not model forward calls.
These statuses exist only when completion returns its result. A witness validation,
consumer join, content-integrity, or full-publication recheck exception is not a
returned refusal status and does not establish reusable state or known completion.
It retains the existing cancellation or quarantine requirements.
finish accepts an output witness exactly once and retains the complete original
consumer-stream roster before submitting the result kernel. If a late cold
completion or observation-allocation failure occurs while that original native
submission remains unpoisoned, it raises SemanticModelEvaluationPending, with
the original exception as its cause. Keep the original Runtime, cold objective,
evaluation, output witness, tensors and content owners alive. Do not execute
another forward, call finish again, replace streams, cancel that submission,
or prepare a replacement evaluation.
Use evaluation.resolve_completion() without arguments to complete that same
submitted report through its retained streams and full-publication check. It
never begins recording or launches the numerical result kernel again. Once the
immutable observation is issued, resolution returns that identical Python
object; a late delivery failure cannot manufacture a replacement observation.
Further resolvable cold failure raises the same pending exception. CUDA/context
failure still poisons and retains the original Session; this resolver does not
clear quarantine or make that failure recoverable. Known incomplete work never
issues a completed observation or the resolvable pending signal.
Memory accounting includes the live native managers and the queried slab backing
allocation. It is not a time-sampled whole-process peak and does not cover unrelated
external allocations. The consumer’s original bounded memory scope and full-system
peak measurement remain necessary. Preparation and completion export full native
material and metadata cold; neither belongs inside a claimed zero-transfer loop.
Successful completion restores the original task phase without changing its
authority snapshot. Before output submission, cancel(consumer_streams=...) does
so only after joining actual consumers and revalidating the original full
publication. Cancellation is forbidden after output submission. Unknown
completion keeps native buffers retained and blocks mutation/release. Dropping an unfinished owner
quarantines its Session; it is not cancellation or proof of completion. Keep all
Python producers and aliases alive until known completion and creator-thread cleanup.
Limitations
- Linux x86_64 + CUDA only
- Source builds that compile the PyO3 extension expose the documented native API. For prebuilt packages, use the release notes for that package version to determine which surfaces it contains.
- Pure-Python helper modules can import without
pyxlog._native, but native-backed compile, evaluate, and session APIs still require the extension.RelationEvidenceandRelationMetadataErrorremain importable for annotations and exception handling in source-only mode. The fallbackRelationMetadataErroris aValueErrorsubclass, while constructing fallbackRelationEvidenceraisesRuntimeErrorbecause its state is native-owned.
See Also
- Living-World Diagnostics — Rule provenance, proof traces, delta debug, temporal metadata, and nn/4 hot-loop audit surface
- dILP Training Architecture — System design, mask backends, promotion pipeline
- Data Interoperability — DLPack and Arrow details
- Probabilistic Tier — Inference engine details
- CLI Reference — Command-line alternative