Explicit point publication
gestaltdb.reasoning.adapters.publication.reconcile_point is an opt-in
persistence boundary, separate from inference. It recomputes from fresh positive
entity claims under the database-wide temporal writer lock, then publishes one
logical temporal commit into a caller-selected, separate target world. It never
accepts an old inference result, changes current property-graph records or
installs generated rules in the global rule catalog.
from tempfile import TemporaryDirectory
from gestaltdb.graphdb import GraphDB
from gestaltdb.ontology import Ontology, SubPropertyOf, compile_ontology
from gestaltdb.reasoning import ReasoningLimits
from gestaltdb.reasoning.adapters.claims import ClaimMapping, ClaimSelection
from gestaltdb.reasoning.adapters.publication import reconcile_point
plan = compile_ontology(Ontology("relations", [SubPropertyOf("p", "q")]))
with TemporaryDirectory() as directory:
graph = GraphDB.create(directory, backend="lmdb", serializer="json")
try:
graph.assert_claim(subject="a", predicate="p", object="b", agent="registry",
polarity="positive", valid=(0, 100))
params = dict(valid_time=50, source_world="default", target_world="derived",
publication_key="my-job", selection=ClaimSelection(),
mapping=ClaimMapping(), limits=ReasoningLimits())
first = reconcile_point(graph, plan, **params)
assert first.asserted == 2 # complete closure, including input p
assert reconcile_point(graph, plan, **params).commit_id is None
assert not list(graph.iter_claims_as_of(world="derived", valid_time=51))
finally:
graph.close()
Identity, reconciliation and stale-input policy
Validity is exactly the single microsecond quantum [t, t+1 microsecond).
Keys, points and worlds have separate output identities. publication_key
names a managed namespace; do not reuse it for unrelated jobs or edit its reserved
gestaltdb:ontology claims manually. Mapping, source policy and ontology revision
can change within a namespace; the next call reconciles against the new closure.
Other agents/sources in the target world remain untouched.
The generation digest includes database identity, point/world/key, revision, mapping, policy and the exact selected input version references. The receipt and claim provenance also record the authenticated input context. Unchanged inputs produce a no-op retry even though prior output commits advanced the database horizon. After an interrupted call, rerun with the same parameters; visible publication is recognized through canonical claim versions, not a separate possibly missing dependency index. Failed inference publishes nothing. Writes use the existing temporal commit visibility/recovery mechanism; see Temporal Version History for orphan audit/reclamation. No new storage protocol or power-loss durability guarantee is invented here.
On a nontransactional backend, interruption before the visibility marker can
leave derived temporal indexes ahead of canonical history. Reads/reconciliation
fail closed rather than returning a partial closure. Quiesce writers, audit with
report = graph.list_temporal_orphans(), explicitly reclaim validated unpublished
artifacts with graph.reclaim_temporal_orphans(through_commit=report.through_commit),
rebuild temporal indexes if still required, then retry reconciliation.
The adapter rejects unreclaimed incomplete commits even if older-prefix reads
would otherwise succeed; it never silently repairs indexes. Transactional
backends avoid this partial index-publication window.
Stale policy is recompute latest while holding the temporal writer guard. This intentionally serializes writers during extraction and inference. Work bounds limit kernel/adapter counts, not lock duration or backend authentication cost. The input policy must exclude recognized derived claims. Full recomputation from base evidence, not bounded witness removal, eliminates self-supporting cycles and preserves independent support. Losing the final support retracts the managed output; losing only one support updates its generation. This is not incremental truth maintenance or an all-support proof index.
Interval semantics before any broader materialization
This API deliberately accepts no output interval or window. For a future interval publisher, every rule application must intersect the validity sets of all its premises, then union all independent supports of each conclusion. Maintain a normalized, sorted, disjoint union of half-open intervals; merge adjacent intervals but never fill gaps with a min/max envelope. Iterate those interval sets to a bounded fixed point, retain revision/system-horizon separation, and recompute or maintain all supports when deleting. Point witnesses cannot establish these unions. Such an interval publisher and incremental support index are not supplied by this operation.