Diagnostics API
The s3dgraphy.diagnostics module collects the paradata-aware
diagnostic walks introduced with the unified xlsx pipeline (DP-02 / DP-32).
These functions answer questions of the form “who made this claim?” and
“is the stratigraphic order self-consistent?” without imposing a fixed
schema on the calling code.
Chronology diagnostics: claim attribution and cycle detection.
The AI-assisted extraction pipeline (DP-02 / StratiMiner) can produce two classes of incoherence:
Paradoxical seeds — a PropertyNode declares a date that is inconsistent with the stratigraphic order. The Hard policy in
Graph._propagate_tpq_taq()already preserves the declared seed and warns, but doesn’t say who made the claim.Stratigraphic cycles —
is_after/overlies/cuts/fillsforming a loop (A is_after B is_after C is_after A), which is physically impossible. These loops are almost always an AI extraction error: the BFS in_propagate_tpq_taqhandles them via avisitedset so nothing crashes, but the user must be told.
This module provides two orthogonal utilities:
attribute_temporal_claim()walks the paradata chain to find the agent responsible for a temporal PropertyNode:PN → has_author: the claim was directly attributed.otherwise: find the paradata group that contains the PN, look at the sibling ExtractorNodes and walk their
has_author(an AuthorAINode for AI-derived claims, an AuthorNode for claims transcribed from the document author).
Returns a tuple
(display_text, kind, author_uuid_or_None)wherekindis one of"author"(claim transcribed from the PDF author),"extractor"(claim derived by an AI extractor), or"unknown".detect_stratigraphic_cycles()returns every non-trivial cycle in the stratigraphic order, together with the attribution for each involved node, so the user can pinpoint which extractor(s) produced the loop.
Both functions are side-effect-free; they do not mutate the graph.
Graph._propagate_tpq_taq() now includes the attribution in its
paradox warnings, and Graph.calculate_chronology() runs a cycle
detection pass before propagation and reports the cycles under the
[stratigraphic cycle] tag.
- s3dgraphy.diagnostics.attribute_property_node(graph, property_node) Tuple[str | None, str, str | None][source]
Return
(display_text, kind, author_uuid)for a PropertyNode.Resolution order (first hit wins):
Direct:
property_node → has_author → AuthorNode.Via provenance chain:
PN → has_data_provenance → Extractor → has_author(xlsx pipeline) or through a CombinerNode (PN → has_data_provenance → Combiner → combines → Extractor → has_author). This is how theUnifiedXLSXImporterwires attribution in the in-memory graph before the exporter bakes the paradata into yEd groups.Via paradata group siblings (yEd-sourced graphs): find groups containing the PropertyNode, then sibling ExtractorNodes in those groups; follow their
has_authoredges.
If none of the lookups yields an author, returns
(None, "unknown", None).AuthorAINode→ kind"extractor";AuthorNode→ kind"author".
- s3dgraphy.diagnostics.attribute_temporal_claim(graph, strat_node, temporal_type) Tuple[str | None, str, str | None][source]
Attribute the temporal claim (
absolute_time_start/absolute_time_end) onstrat_nodeto an author or extractor.Finds the PropertyNode of the given temporal type attached to
strat_nodeviahas_property, then delegates toattribute_property_node(). Returns(None, "unknown", None)when no such PropertyNode exists.
- s3dgraphy.diagnostics.format_attribution(graph, strat_node, temporal_type) str[source]
Short human-readable attribution suffix, e.g.
"[attributed to StratiMiner-v1 (extractor)]", or an empty string when the claim cannot be attributed. Intended for inclusion in warning strings.
- s3dgraphy.diagnostics.detect_stratigraphic_cycles(graph) List[List[str]][source]
Return a list of stratigraphic cycles. Each cycle is a list of
node_idstrings in traversal order; the first id is repeated implicitly at the end (not included). Self-loops (A → A) are included as one-element cycles.Uses iterative Tarjan SCC over the “more recent than” adjacency: a non-trivial SCC (size ≥ 2) is a cycle. Nodes that only sit on a self-loop are also reported.
See also
Property Propagation — how property resolution walks the
has_data_provenance/has_paradata_nodegroupchains.Temporal Inference Engine — TPQ / TAQ propagation and the
[chronology paradox]warnings thatattribute_temporal_claimannotates.Chronology — the high-level chronology calculation pipeline and how diagnostics surface inside it.