symfonic.core.prompt.blocks.memory_lane_facts¶
memory_lane_facts ¶
Turning one scanned graph node into the facts it carries.
The node-to-fact half of :mod:symfonic.core.prompt.blocks.memory_lane.
That module owns the scan -- which nodes to read and what revision the
result carries; this one owns the reading of a single node: which of
its parts carry a statement, in what order, and with whose provenance.
Provenance a node did not record stays None. Nothing here invents a
source or a timestamp, and nothing here ranks: :func:_scan_order is a
deterministic sort key, not a score, so two scans over an unchanged lane
emit the same bytes and an unchanged block keeps the cached prompt prefix.
node_to_facts ¶
The node's label fact, then one fact per declared profile field.
Fields are emitted in sorted order so two scans of an unchanged lane still produce identical bytes -- the property that lets an unchanged block keep the cached prompt prefix. Set iteration order would not.
Each field carries its own provenance when the writer recorded
one under _field_provenance. A role corrected today must not
inherit the onboarding form's timestamp from three months ago: the
node-level stamp describes when the node was written, and once one
node carries several independently-sourced facts that is no longer
the same question as when each fact was recorded. Falling back to
the node-level stamp keeps a node written before this existed
rendering exactly as it did.
Source code in src/symfonic/core/prompt/blocks/memory_lane_facts.py
scan_order ¶
Deterministic scan order: label, then recorded time, then id.
Not relevance -- there is no score to order by, and that is the point. Two scans over an unchanged lane emit the same bytes, so an unchanged block does not invalidate the cached prompt prefix.
Review fix (LOW, per-task t7-resolver): the tiebreak used to be
node.created_at -- the row-creation time -- while
:func:_node_to_fact resolves the displayed provenance from
properties['recorded_at'] first, falling back to created_at
only when the node recorded nothing. Two nodes sharing a label sort
by row-creation order here but can carry recorded_at values in
the opposite order, so the rendered facts read out of chronological
sequence even though both this function's own docstring and the
module's provenance rule call for "recorded time". Reusing
:func:_recorded_at -- the same resolution :func:_node_to_fact
performs -- keeps the two in agreement.