ontocast.tool.facts_validation.literal_repair¶
LLM-free parse-time repairs on rendered facts graphs.
Every rewrite here either retypes a literal the schema grounds, resolves an unambiguous near-miss or code, or collapses a degenerate encoding — no repair invents a value.
dedupe_literal_variants(graph, fact_namespaces=None)
¶
Collapse duplicate literals differing only in language tag or datatype.
The renderer emits the same value inconsistently across chunks —
"X"@en in one unit, "X"^^xsd:string in another, a plain "X"
in a third — and after aggregation one (subject, predicate) carries
all three as distinct RDF terms. One survives per lexical form: the
language-tagged form (each distinct language kept — those are distinct
assertions), else the plain form, else the xsd:string form. Reified
provenance follows the survivor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
RDFGraph
|
Aggregated facts graph, mutated in place. |
required |
fact_namespaces
|
Sequence[str] | None
|
When set, only subjects under these namespaces are touched. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
One |
list[GraphRepairRecord]
|
|
Source code in ontocast/tool/facts_validation/literal_repair.py
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | |
normalize_literals_against_schema(graph, ontology_graph)
¶
Retype literals whose predicate declares a compatible rdfs:range.
Fixes the qudt:numericValue 230 vs "230"^^xsd:decimal drift at parse
time, and the same drift for the date-like datatypes: when the schema
declares a range in :data:_RETYPABLE_RANGE_DATATYPES and the lexical form
parses as that datatype, the literal is rewritten with it.
A literal is only retyped from an untyped, xsd:string, or numeric source
-- a string range must never be able to clobber a correctly typed value --
and language-tagged literals are left alone, since they are
rdf:langString and retyping would discard the tag.
Returns:
| Type | Description |
|---|---|
int
|
Number of retyped literals. |
Source code in ontocast/tool/facts_validation/literal_repair.py
promote_degenerate_bounds(graph, *, numeric_value_property, lower_bound_property, upper_bound_property, inclusive_flag_properties=())
¶
Rewrite equal lower/upper bounds into a single scalar value, in place.
A node whose lower and upper bounds carry the same canonical numeric value encodes an exact scalar as a fake range. The rewrite fires only when the encoding is unambiguous: exactly one literal per bound property, equal canonical values, no existing scalar on the node, and no exclusive-bound flag (an exclusive equal bound denotes an empty interval — malformed, and left for findings). Property IRIs are injected by the caller from configuration; nothing is hardcoded.
Returns:
| Type | Description |
|---|---|
int
|
Number of nodes rewritten. |
Source code in ontocast/tool/facts_validation/literal_repair.py
promote_degenerate_bounds_from_vocabulary(graph, ontology_graph, vocabulary)
¶
Run :func:promote_degenerate_bounds with properties from configuration.
Active only when the quantity vocabulary names all three roles —
numeric_value, lower_bound, upper_bound (roles containing
inclusive supply the optional bound flags). The default vocabulary
carries no bound roles, so this is off unless a deployment configures its
range encoding.
Source code in ontocast/tool/facts_validation/literal_repair.py
repair_literal_type_objects(graph)
¶
Coerce literal rdf:type objects into IRIs.
The renderer sometimes emits a "prefix:Class"^^xsd:string instead of
a prefix:Class (JSON-LD bare-string type values parse the same way).
A literal-typed node is invisible to SPARQL class queries, reasoning, and
the aggregator's URI minting/entity matching, all of which guard on
isinstance(obj, URIRef). Absolute IRIs and compact IRIs bound in the
graph are rewritten deterministically; unresolvable forms become MANDATORY
findings.
Returns:
| Type | Description |
|---|---|
int
|
Tuple of (number of rewritten triples, unresolved findings, |
list[FactsUnitFinding]
|
applied-repair records). |
Source code in ontocast/tool/facts_validation/literal_repair.py
repair_property_aliases(graph, ontology_graph, *, min_ratio=0.85, exempt_terms=None)
¶
Rewrite near-miss predicates in catalog namespaces; report ambiguity.
A predicate whose namespace belongs to the ontology context but which is
not itself a catalog term is a near-miss (qqval:lowerBound for
qqval:hasLowerBound). When exactly one candidate scores above
min_ratio (token containment counts as 1.0) the rewrite is applied
deterministically; otherwise a mandatory finding carries the top
suggestions.
Only namespaces the catalog declares terms in are eligible (see
:func:collect_declared_namespaces); exempt_terms (expanded fallback
vocabulary) are never treated as near-misses.
Returns:
| Type | Description |
|---|---|
int
|
Tuple of (number of rewritten triples, unresolved findings, |
list[FactsUnitFinding]
|
applied-repair records). |
Source code in ontocast/tool/facts_validation/literal_repair.py
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | |
resolve_code_literals(graph, ontology_graph, code_predicates=())
¶
Link nodes to the catalog individual whose code they already carry.
A renderer that reads 4-15 days often annotates the value node with the
code it saw — qudt:ucumCode "d" — instead of the object property that
points at the individual — qudt:unit unit:DAY. The graph is well-formed,
so no range check fires, but every query reading the object property gets
an unbound result. The code came from the text and the individual is in the
catalog, so the link is recoverable without asking the model again.
Fully schema-driven, no vocabulary compiled in: the connecting property is whichever object property the ontology context declares with a range the resolved individual is typed as, and a domain the subject satisfies. If the schema offers several such properties, or none, nothing is added.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
RDFGraph
|
Rendered facts graph, repaired in place. |
required |
ontology_graph
|
RDFGraph | None
|
Merged ontology context, read-only. |
required |
code_predicates
|
Sequence[str]
|
Predicates carrying machine-resolvable codes. |
()
|
Returns:
| Type | Description |
|---|---|
tuple[int, list[GraphRepairRecord]]
|
Tuple of (number of added triples, applied-repair records). |
Source code in ontocast/tool/facts_validation/literal_repair.py
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | |