ontocast.tool.facts_validation.critic_patch¶
Compile critic-proposed fixes into a validated graph patch, with no LLM call.
The loop's invariant is that every mutation is a compiled, validated
GraphUpdate -- that is what keeps the two-namespace contract, IRI policy
and literal repair in one place. It had drifted into a stricter and less
defensible rule: that every mutation must come from a render call. The
consequence was that a critic fix naming the exact triple to drop still cost a
full re-extraction of the unit, so the loop only ever spent that on fixes it
considered blocking and dropped the rest.
A fix that names the statements it removes and supplies the ones it adds is
already a patch. Compiling it here costs nothing and leaves the invariant
intact: the result goes through the same GraphUpdate the renderer's wire
compiles to.
How a fix names what it removes matters more than anything else here. The
original contract asked the critic to retype the offending statement into
incorrect_value, and to match it had to reproduce the stored triple exactly
-- same prefix form, same predicate, same literal shape. Across a large corpus
of real critiques that reproduction succeeds a minority of the time for
REPLACE and almost never for a bare REMOVE: the payload arrives as
prose, as a plausible-but-invented IRI, or as a node-shaped quote spanning
several statements with one predicate wrong, which fails the all-present check
as a whole. Authoring new content in correct_value has no such problem,
because nothing has to match.
So the primary path is by id: the critic is shown a numbered graph and cites
:attr:TripleFix.triple_ids, which resolve by lookup. Requoting remains as a
fallback for a fix that cites no id, under the same exact-match rule as before.
Still deliberately conservative. A cited id the index never issued sends the whole fix back rather than acting on the part that resolved; a statement already gone is not deleted again; and a fix that removes exactly what it re-adds is recorded as asking for nothing rather than counted as a fix that landed.
Attributes¶
logger = logging.getLogger(__name__)
module-attribute
¶
Classes¶
CompiledFixes
dataclass
¶
The mechanical half of a critique, split from the half needing a render.
Source code in ontocast/tool/facts_validation/critic_patch.py
Attributes¶
applied = field(default_factory=list)
class-attribute
instance-attribute
¶
bad_index_refs = 0
class-attribute
instance-attribute
¶
delete_capped = False
class-attribute
instance-attribute
¶
deletes_refused = 0
class-attribute
instance-attribute
¶
junk_refused = 0
class-attribute
instance-attribute
¶
noop = field(default_factory=list)
class-attribute
instance-attribute
¶
patches = field(default_factory=list)
class-attribute
instance-attribute
¶
quarantined_literal = 0
class-attribute
instance-attribute
¶
residual = field(default_factory=list)
class-attribute
instance-attribute
¶
unresolved_prefix = 0
class-attribute
instance-attribute
¶
update = None
class-attribute
instance-attribute
¶
Methods:¶
__init__(update=None, patches=list(), applied=list(), residual=list(), noop=list(), bad_index_refs=0, delete_capped=False, deletes_refused=0, unresolved_prefix=0, junk_refused=0, quarantined_literal=0)
¶
CriticPatchPolicy
dataclass
¶
How much destruction one critic pass is allowed to do.
A compiled patch is transparent -- both halves are known before anything is touched -- so the limits are enforced by withholding the delete half rather than by inspecting the wreckage afterwards. Every rule here drops something and counts it; none of them raises.
Source code in ontocast/tool/facts_validation/critic_patch.py
FixPatch
dataclass
¶
One kept fix as its own delete-then-insert patch.
The loop applies these one at a time and judges each on its own, so a fix that leaves the unit worse is undone alone instead of taking the whole pass with it -- which is how a critique used to lose its good corrections to one bad one.
Source code in ontocast/tool/facts_validation/critic_patch.py
Attributes¶
deletes = 0
class-attribute
instance-attribute
¶
fix
instance-attribute
¶
insert_triples
property
¶
The statements this patch declares it writes.
Not the same as what applying it adds to the graph. A REPLACE re-states the whole corrected node, so the parts that were already right are written as no-ops and the graph diff shows only the delete. The rollback test has to judge "wrote nothing" against what the fix meant to write, or it undoes corrections whose replacement the graph already held.
inserts = 0
class-attribute
instance-attribute
¶
update
instance-attribute
¶
Methods:¶
__init__(fix, update, deletes=0, inserts=0)
¶
Functions:¶
apply_compiled_patch(graph, update)
¶
Apply a compiled patch to graph in place, deletes before inserts.
The ordering is the one :meth:GraphUpdateRenderReport.to_graph_update
fixes, and the operations are the same TripleOps a render produces --
this is the render's apply step over an in-memory graph, not a second way
to mutate one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
RDFGraph
|
The unit graph to patch. |
required |
update
|
GraphUpdate
|
The compiled patch. |
required |
Source code in ontocast/tool/facts_validation/critic_patch.py
compile_critic_fixes(fixes, graph, *, index=None, policy=None)
¶
Split a critique into a mechanical patch and the fixes needing a render.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fixes
|
Sequence[TripleFix]
|
Fixes from the critique report, in the order proposed. |
required |
graph
|
RDFGraph
|
The rendered unit graph the fixes refer to. |
required |
index
|
TripleIndex | None
|
The ids handed to the critic for this graph. When present, a fix that cites ids is resolved by lookup; the requoting path is the fallback for a fix that cites none. |
None
|
policy
|
CriticPatchPolicy | None
|
Limits on what the patch may destroy. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
CompiledFixes |
CompiledFixes
|
|
CompiledFixes
|
|
|
CompiledFixes
|
for nothing. |
Source code in ontocast/tool/facts_validation/critic_patch.py
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | |