Skip to content

Checks

The checks an agent runs on the assessed nodes: what they accept, how they run, and what they record.

The targets are the document and analyst nodes of a type with assess = true. An agent proposes checks of the types the runner implements (tools.run_checks and tools.judge_citation):

  • recompute-numbers: an arithmetic expression over numerals of the cited chunks, and the reported result. Every numeral, the result included, must be one the cited chunks' text contains, compared exactly as the decimal each writes, so the agent cannot supply a number the document does not, not even one a float cannot tell apart from a number it does. The expression is evaluated exactly; it passes when it falls within the rounding the reported result's own digits imply.
  • rederive-maths: a step between equation chunks encoded as two sympy expressions over declared symbols, lhs and rhs, that the step claims are equal. It passes when sympy simplifies their difference to 0, fails when sympy shows the difference is never 0, and is an error otherwise.
  • rederive-maths-numeric: run, as a check of its own, only when rederive-maths errs and the rubric declares it: the same encoding compared at 32 points drawn in the symbols' domains, from a generator seeded by the encoding. The seed and the points are recorded with the check.
  • citation-support: the tool reads the cited source, finds the passage the agent quotes, and records the agent's judgement of whether it supports the node (judged); see citation.

A proposal the runner cannot run, being malformed, of an unknown type, on a node the type does not target, with a numeral the cited chunks do not contain, a second of its type on one node, or the same step as another check on another target, is refused with a code and, where it can say, what to change (fix). Two checks of one type on one node, or of one step however it is written, would fail or pass together, so they must not count as two observations.

Each check run becomes an evidence node c-NNN of its check type, numbered in the order run, joined to its target by the check edge target --observes--> c-NNN with the check type's sensitivity and false_pass. Its statement comes from a fixed template, never from the agent. attributes.check is the check record and attributes.observed is true for a pass and false for a fail; an errored check has no observed, so it is recorded but changes no credence. Each check's inputs, the tool's output and a log are written into checks/c-NNN/. The verdict on each target is derived from its checks, never asked of the agent (assess): fails if any failed, else holds if any passed, else undetermined if any ran, else not_assessed, because no check type the runner implements may run on the node, or none was run.

Result dataclass

What a check found.

Attributes:

Name Type Description
type str

The check type.

target str

The node the check bears on.

artifact Mapping[str, Any]

What the check was run against, as the check record's artifact.

inputs Mapping[str, Any]

The exact thing evaluated.

result str

passed, failed or error.

detail str

What the tool found, in words.

output Mapping[str, Any]

The tool's output, written to the check's directory.

sources tuple[SourceAnchor, ...]

Anchors of the external works checked against.

libraries tuple[str, ...]

The libraries the method used, named as in the run's versions.

model Mapping[str, Any] | None

The model that took part, as the call reported it, or None.

Source code in src/credencegraph_extract/checks.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@dataclass(frozen=True)
class Result:
    """What a check found.

    Attributes:
        type: The check type.
        target: The node the check bears on.
        artifact: What the check was run against, as the check record's ``artifact``.
        inputs: The exact thing evaluated.
        result: ``passed``, ``failed`` or ``error``.
        detail: What the tool found, in words.
        output: The tool's output, written to the check's directory.
        sources: Anchors of the external works checked against.
        libraries: The libraries the method used, named as in the run's versions.
        model: The model that took part, as the call reported it, or ``None``.
    """

    type: str
    target: str
    artifact: Mapping[str, Any]
    inputs: Mapping[str, Any]
    result: str
    detail: str
    output: Mapping[str, Any] = field(default_factory=dict)
    sources: tuple[SourceAnchor, ...] = ()
    libraries: tuple[str, ...] = ()
    model: Mapping[str, Any] | None = None

add_checks(graph, rubric, results, versions)

Add each result to a graph as a check node with its check edge, numbered after the graph's checks.

A check node c-NNN takes the first number the graph does not have. Its attributes.check is the check record, and attributes.observed is true for a pass and false for a fail; an errored check has no observed. The edge target --observes--> c-NNN carries the check type's sensitivity and false_pass. Verdicts are not set: assess derives them.

Parameters:

Name Type Description Default
graph Graph

The graph.

required
rubric Rubric

The rubric, which declares every result's check type.

required
results Sequence[Result]

The results, in the order they are numbered.

required
versions Mapping[str, str]

The versions of the code that ran the checks, by name, as session.versions gives them.

required

Returns:

Type Description
Graph

The graph with the checks; the files of each check's directory, by path in the run; and one

dict[str, bytes]

entry per check: its id, type, target and result.

Source code in src/credencegraph_extract/checks.py
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
def add_checks(
    graph: Graph, rubric: Rubric, results: Sequence[Result], versions: Mapping[str, str]
) -> tuple[Graph, dict[str, bytes], list[dict[str, Any]]]:
    """Add each result to a graph as a check node with its check edge, numbered after the graph's checks.

    A check node ``c-NNN`` takes the first number the graph does not have. Its ``attributes.check`` is
    the check record, and ``attributes.observed`` is ``true`` for a pass and ``false`` for a fail; an
    errored check has no ``observed``. The edge ``target --observes--> c-NNN`` carries the check type's
    ``sensitivity`` and ``false_pass``. Verdicts are not set: ``assess`` derives them.

    Args:
        graph: The graph.
        rubric: The rubric, which declares every result's check type.
        results: The results, in the order they are numbered.
        versions: The versions of the code that ran the checks, by name, as ``session.versions`` gives them.

    Returns:
        The graph with the checks; the files of each check's directory, by path in the run; and one
        entry per check: its id, type, target and result.
    """
    fresh = (node_id for n in count(1) if (node_id := f"c-{n:03d}") not in graph)
    nodes: list[Node] = []
    relations: list[Relation] = []
    files: dict[str, bytes] = {}
    report = []
    for result in results:
        check_id = next(fresh)
        check: Check = rubric.checks[result.type]
        tool = {
            "name": "credencegraph-extract",
            "version": versions.get("credencegraph-extract"),
            "python": versions.get("python"),
            **{library: versions.get(library) for library in result.libraries},
        }
        record, check_files = _record(check_id, result, tool)
        files.update({f"{CHECKS}/{check_id}/{name}": data for name, data in check_files.items()})
        attributes: dict[str, Any] = {"origin": EVIDENCE, "check": record}
        if result.result != ERROR:
            attributes["observed"] = result.result == PASSED
        nodes.append(
            Node(
                check_id,
                kind=result.type,
                statement=f"{result.type} on {result.target}: {result.result}",
                sources=result.sources,
                attributes=attributes,
            )
        )
        relations.append(
            Relation(
                f"{result.target}-{OBSERVES}-{check_id}",
                OBSERVES,
                result.target,
                check_id,
                sensitivity=check.sensitivity,
                false_pass=check.false_pass,
            )
        )
        report.append({"id": check_id, "type": result.type, "target": result.target, "result": result.result})
    out = Graph()
    for node in (*graph, *nodes):
        out.add_node(node)
    for relation in (*graph.relations.values(), *relations):
        out.add_relation(relation)
    return out, files, report

applicable(rubric, kind)

Return the check types the model may propose for a node type: proposed by the runner, declared and targeting it.

Parameters:

Name Type Description Default
rubric Rubric

The rubric.

required
kind str

The node type.

required

Returns:

Type Description
list[str]

The check type names, in the order of PROPOSED.

Source code in src/credencegraph_extract/checks.py
151
152
153
154
155
156
157
158
159
160
161
def applicable(rubric: Rubric, kind: str) -> list[str]:
    """Return the check types the model may propose for a node type: proposed by the runner, declared and targeting it.

    Args:
        rubric: The rubric.
        kind: The node type.

    Returns:
        The check type names, in the order of ``PROPOSED``.
    """
    return [name for name in PROPOSED if name in rubric.checks and kind in rubric.checks[name].targets]

assess(graph, rubric)

Set the verdict of every node the checks assess, from the checks that observe it.

A target's verdict comes from the results of the check nodes its observes relations lead to, never from a model: fails, holds or undetermined as verdict gives it, else not_assessed because no implemented check type may run on the node, or none was run.

Parameters:

Name Type Description Default
graph Graph

The graph.

required
rubric Rubric

The rubric.

required

Returns:

Type Description
Graph

The graph with attributes.assessment set on every target.

Source code in src/credencegraph_extract/checks.py
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
def assess(graph: Graph, rubric: Rubric) -> Graph:
    """Set the verdict of every node the checks assess, from the checks that observe it.

    A target's verdict comes from the results of the check nodes its ``observes`` relations lead to,
    never from a model: ``fails``, ``holds`` or ``undetermined`` as ``verdict`` gives it, else
    ``not_assessed`` because no implemented check type may run on the node, or none was run.

    Args:
        graph: The graph.
        rubric: The rubric.

    Returns:
        The graph with ``attributes.assessment`` set on every target.
    """
    by_target: dict[str, list[str]] = {}
    for relation in graph.relations.values():
        check = graph.nodes[relation.target].attributes.get("check") if relation.type == OBSERVES else None
        if isinstance(check, Mapping):
            by_target.setdefault(relation.source, []).append(check.get("result"))
    assessed = set(targets(graph, rubric))
    out = Graph()
    for node in graph:
        if node.id in assessed:
            found = verdict(by_target.get(node.id, []))
            if found is not None:
                assessment: dict[str, Any] = {"verdict": found}
            else:
                reason = NOT_SELECTED if applicable(rubric, node.kind) else NO_CHECK
                assessment = {"verdict": NOT_ASSESSED, "reason": reason}
            node = replace(node, attributes={**node.attributes, "assessment": assessment})  # noqa: PLW2901
        out.add_node(node)
    for relation in graph.relations.values():
        out.add_relation(relation)
    return out

citation_refusal(graph, rubric, target, reference)

Refuse a citation check the check pass would refuse, or one on a target whose citation check already passed or failed.

The target must be a node the rubric runs citation-support on, and it, or a node it is part of, must cite the reference, a bibliography entry of the document. A citation check that passed or failed stays: another on the same target is refused. One that erred moved no credence, so another may follow it.

Parameters:

Name Type Description Default
graph Graph

The graph.

required
rubric Rubric

The rubric.

required
target Any

The node the check bears on.

required
reference Any

The id of the bibliography entry.

required

Returns:

Type Description
dict[str, Any] | None

The rejection, with its code, message, record and, where the refusal knows what to change, a

dict[str, Any] | None

fix; or None when the check may run.

Source code in src/credencegraph_extract/checks.py
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
def citation_refusal(graph: Graph, rubric: Rubric, target: Any, reference: Any) -> dict[str, Any] | None:
    """Refuse a citation check the check pass would refuse, or one on a target whose citation check already passed or failed.

    The target must be a node the rubric runs ``citation-support`` on, and it, or a node it is part of,
    must cite the reference, a bibliography entry of the document. A citation check that passed or
    failed stays: another on the same target is refused. One that erred moved no credence, so another
    may follow it.

    Args:
        graph: The graph.
        rubric: The rubric.
        target: The node the check bears on.
        reference: The id of the bibliography entry.

    Returns:
        The rejection, with its code, message, record and, where the refusal knows what to change, a
        ``fix``; or ``None`` when the check may run.
    """
    record = {"target": target, "type": CITATION, "reference": reference}
    try:
        _plan(graph, rubric, record)
        settled = [
            node.id
            for node in graph
            if isinstance(check := node.attributes.get("check"), Mapping)
            and check.get("type") == CITATION
            and check.get("target") == target
            and check.get("result") != ERROR
        ]
        if settled:
            msg = f"{target!r} has the citation check {settled[0]}, which passed or failed: it stays"
            raise _ProposalError(
                DUPLICATE_RECORD, msg, f"leave {target!r}: a citation check runs again only after one that errs"
            )
    except _ProposalError as refused:
        rejection = {"node": target if isinstance(target, str) else None, "code": refused.code, "message": str(refused)}
        rejection["record"] = record
        if refused.fix is not None:
            rejection["fix"] = refused.fix
        return rejection
    return None

directory_digest(files)

Return the digest of a check's directory: of one line <name> <digest> per file, sorted by name.

Parameters:

Name Type Description Default
files Mapping[str, bytes]

The files by name.

required

Returns:

Type Description
str

The digest.

Source code in src/credencegraph_extract/checks.py
552
553
554
555
556
557
558
559
560
561
562
def directory_digest(files: Mapping[str, bytes]) -> str:
    """Return the digest of a check's directory: of one line ``<name> <digest>`` per file, sorted by name.

    Args:
        files: The files by name.

    Returns:
        The digest.
    """
    listing = "".join(f"{name} {bytes_digest(files[name])}\n" for name in sorted(files))
    return bytes_digest(listing.encode("utf-8"))

fix(code, record)

Say what to change in a refused proposal, as an instruction to the model, or None beyond the error.

Parameters:

Name Type Description Default
code str

The rejection code.

required
record Any

The proposal.

required

Returns:

Type Description
str | None

The instruction.

Source code in src/credencegraph_extract/checks.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
def fix(code: str, record: Any) -> str | None:
    """Say what to change in a refused proposal, as an instruction to the model, or ``None`` beyond the error.

    Args:
        code: The rejection code.
        record: The proposal.

    Returns:
        The instruction.
    """
    nodes = record.get("nodes") if isinstance(record, Mapping) else None
    label_fix = _label_fix(code, record)
    if label_fix is not None:
        return label_fix
    if code == UNFAITHFUL:
        return (
            f"write every number, the expected value included, exactly as a numeral the text of {nodes} writes, "
            "and add to nodes any chunk whose numeral you use; a constant no cited chunk writes, such as the 1 of "
            "1 - p or a 100, is not allowed: rewrite the expression without it, as a - a * p rather than "
            "a * (1 - p), where a and p are numerals the text writes"
        )
    return _FIXES.get(code)

judged(graph, target, reference, observation, *, passage, supports, untied, model)

Return the result of a citation check from what the tool read and what the agent judged.

The check is an error when the quoted passage is not in the source's text, or when the source is not tied to the reference (untied says why): an errored check moves no credence. Otherwise it passes when the agent judged that the passage supports the target, and fails when not.

Parameters:

Name Type Description Default
graph Graph

The graph.

required
target str

The citing node.

required
reference str

The bibliography entry.

required
observation Mapping[str, Any]

What the tool read: citation.read_cited or citation.read_url.

required
passage str

The passage the agent quoted.

required
supports bool

The agent's judgement.

required
untied str | None

Why the source is not tied to the reference, or None.

required
model str | None

The model the call reported.

required

Returns:

Type Description
Result

The result.

Source code in src/credencegraph_extract/checks.py
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
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
def judged(  # noqa: PLR0913 - the check, what was read, what the agent said, and how it is tied
    graph: Graph,
    target: str,
    reference: str,
    observation: Mapping[str, Any],
    *,
    passage: str,
    supports: bool,
    untied: str | None,
    model: str | None,
) -> Result:
    """Return the result of a citation check from what the tool read and what the agent judged.

    The check is an ``error`` when the quoted passage is not in the source's text, or when the source
    is not tied to the reference (``untied`` says why): an errored check moves no credence. Otherwise
    it passes when the agent judged that the passage supports the target, and fails when not.

    Args:
        graph: The graph.
        target: The citing node.
        reference: The bibliography entry.
        observation: What the tool read: ``citation.read_cited`` or ``citation.read_url``.
        passage: The passage the agent quoted.
        supports: The agent's judgement.
        untied: Why the source is not tied to the reference, or ``None``.
        model: The model the call reported.

    Returns:
        The result.
    """
    document = _document(observation)
    source = (
        {"file": observation.get("file")}
        if observation.get("kind") == "cited"
        else {
            "url": observation.get("url"),
            "final_url": observation.get("final_url"),
        }
    )
    artifact: dict[str, Any] = {
        "kind": "citation",
        "reference": reference,
        "document": document,
        "source": source,
        "tied": untied is None,
    }
    inputs = {"statement": node_text(graph, graph.nodes[target]), "source_digest": observation.get("text_digest")}
    output = {"passage": passage, "supports": supports, "read": dict(observation)}
    reported = {"model": model}
    found = observation.get("found")
    if not isinstance(found, list):
        detail = "the quoted passage is not in the text of the source"
        return Result(CITATION, target, artifact, inputs, ERROR, detail, output, model=reported)
    quote = normalise_text(passage)
    locator = f"chars={found[0]}-{found[1]}"
    artifact.update(locator=locator, quote=quote, digest=text_digest(quote))
    if untied is not None:
        detail = f"source not tied to the reference: {untied}"
        return Result(CITATION, target, artifact, inputs, ERROR, detail, output, model=reported)
    anchor = SourceAnchor(document, locator, quote, text_digest(quote))
    result = PASSED if supports else FAILED
    detail = f"the passage at {locator} {'supports' if supports else 'does not support'} the statement"
    return Result(CITATION, target, artifact, inputs, result, detail, output, (anchor,), model=reported)

plain(value)

Return a value as JSON gives it back: a graph's read-only mappings and its tuples become dicts and lists.

Parameters:

Name Type Description Default
value Any

A value made of JSON types, mappings and sequences.

required

Returns:

Type Description
Any

The value in JSON types only.

Source code in src/credencegraph_extract/checks.py
493
494
495
496
497
498
499
500
501
502
def plain(value: Any) -> Any:
    """Return a value as JSON gives it back: a graph's read-only mappings and its tuples become dicts and lists.

    Args:
        value: A value made of JSON types, mappings and sequences.

    Returns:
        The value in JSON types only.
    """
    return json.loads(json.dumps(value, default=lambda item: dict(item) if isinstance(item, Mapping) else list(item)))

rerun(graph, rubric, check)

Run a recorded deterministic check again, from the inputs its record holds.

The recorded inputs are checked as the run checked the proposal, numeral faithfulness included, and evaluated by the current code; rederive-maths-numeric draws its points again from the encoding's seed. A record that can no longer be run gives the result error, with the reason as its detail.

Parameters:

Name Type Description Default
graph Graph

The graph the check node is in.

required
rubric Rubric

The rubric of the run.

required
check Node

A check node of a type in DETERMINISTIC.

required

Returns:

Type Description
dict[str, Any]

The check record the re-run gives, with the recorded tool, and the files of its directory

dict[str, bytes]

by name. When the code and the record agree, the record equals check.attributes["check"].

Raises:

Type Description
ValueError

If the node is not a check of a type in DETERMINISTIC.

Source code in src/credencegraph_extract/checks.py
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
def rerun(graph: Graph, rubric: Rubric, check: Node) -> tuple[dict[str, Any], dict[str, bytes]]:
    """Run a recorded deterministic check again, from the inputs its record holds.

    The recorded inputs are checked as the run checked the proposal, numeral faithfulness included,
    and evaluated by the current code; ``rederive-maths-numeric`` draws its points again from the
    encoding's seed. A record that can no longer be run gives the result ``error``, with the reason as
    its detail.

    Args:
        graph: The graph the check node is in.
        rubric: The rubric of the run.
        check: A check node of a type in ``DETERMINISTIC``.

    Returns:
        The check record the re-run gives, with the recorded ``tool``, and the files of its directory
        by name. When the code and the record agree, the record equals ``check.attributes["check"]``.

    Raises:
        ValueError: If the node is not a check of a type in ``DETERMINISTIC``.
    """
    recorded = plain(check.attributes.get("check"))
    if not isinstance(recorded, dict) or recorded.get("type") not in DETERMINISTIC:
        msg = f"{check.id!r} is not a check of a type in {list(DETERMINISTIC)}"
        raise ValueError(msg)
    check_type, target = recorded["type"], recorded.get("target")
    artifact, inputs = recorded.get("artifact"), recorded.get("inputs")
    if not isinstance(artifact, dict) or not isinstance(inputs, dict):
        artifact, inputs = {}, {}
    # The proposal the record was run from: the symbolic encoding for both maths checks.
    proposed = RECOMPUTE if check_type == RECOMPUTE else REDERIVE
    proposal = {key: inputs.get(key) for key in _ALLOWED[proposed]}
    proposal.update(target=target, type=proposed, nodes=artifact.get("nodes"))
    try:
        plan = _plan(graph, rubric, proposal)
    except _ProposalError as refused:
        detail = f"the recorded inputs cannot be run: {refused}"
        result = Result(check_type, str(target), artifact, inputs, ERROR, detail, {"result": ERROR})
    else:
        if check_type == RECOMPUTE:
            result = _recompute(graph, plan)
        elif check_type == REDERIVE:
            result = _rederive(plan)
        else:
            result = _numeric(plan, artifact)
    return _record(check.id, result, recorded.get("tool") or {})

run_maths(graph, rubric, proposals, versions)

Check and run proposals of the maths check types, one tool call's worth, after the checks a graph has.

Each proposal is checked (_plan), in the order given, and is refused when it repeats the target and type of a check the graph has or an earlier proposal, or the same step on another target (_admit). A citation-support proposal is refused: the citation tool runs it. The admitted ones run in the order given; a rederive-maths that errs is followed by its numeric fallback when the rubric declares one. Verdicts are not set.

Parameters:

Name Type Description Default
graph Graph

The graph, with the checks already run.

required
rubric Rubric

The rubric.

required
proposals Sequence[Any]

The proposals.

required
versions Mapping[str, str]

The versions of the code that runs them.

required

Returns:

Type Description
Graph

The graph with the new checks; the files of their directories; each new check's id, type,

dict[str, bytes]

target, result and detail; and the refused proposals, each with its code, message and, where

list[dict[str, Any]]

the refusal knows what to change, a fix.

Source code in src/credencegraph_extract/checks.py
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
def run_maths(
    graph: Graph, rubric: Rubric, proposals: Sequence[Any], versions: Mapping[str, str]
) -> tuple[Graph, dict[str, bytes], list[dict[str, Any]], list[dict[str, Any]]]:
    """Check and run proposals of the maths check types, one tool call's worth, after the checks a graph has.

    Each proposal is checked (``_plan``), in the order given, and is refused when it
    repeats the target and type of a check the graph has or an earlier proposal, or the same step on
    another target (``_admit``). A ``citation-support`` proposal is refused: the citation tool runs it.
    The admitted ones run in the order given; a ``rederive-maths`` that errs is followed by its numeric
    fallback when the rubric declares one. Verdicts are not set.

    Args:
        graph: The graph, with the checks already run.
        rubric: The rubric.
        proposals: The proposals.
        versions: The versions of the code that runs them.

    Returns:
        The graph with the new checks; the files of their directories; each new check's id, type,
        target, result and detail; and the refused proposals, each with its code, message and, where
        the refusal knows what to change, a ``fix``.
    """
    plans: list[_Plan] = []
    rejections: list[dict[str, Any]] = []
    for record in proposals:
        if isinstance(record, Mapping) and record.get("type") == CITATION:
            target = record.get("target")
            rejections.append(
                {
                    "node": target if isinstance(target, str) else None,
                    "code": INVALID_RECORD,
                    "message": f"a {CITATION} check is not run with the maths checks",
                    "record": record,
                    "fix": f"send a {CITATION} check to the citation tool, with the source and the passage",
                }
            )
            continue
        rejections.extend(_admit(graph, rubric, [record], plans))
    results = [result for plan in plans for result in _maths(graph, rubric, plan)]
    out, files, report = add_checks(graph, rubric, results, versions)
    checks = [{**entry, "detail": result.detail} for entry, result in zip(report, results, strict=True)]
    return out, files, checks, rejections

targets(graph, rubric)

Return the nodes the checks assess: document and analyst nodes of a type with assess = true.

Parameters:

Name Type Description Default
graph Graph

The graph.

required
rubric Rubric

The rubric.

required

Returns:

Type Description
list[str]

Their ids, in document order.

Source code in src/credencegraph_extract/checks.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def targets(graph: Graph, rubric: Rubric) -> list[str]:
    """Return the nodes the checks assess: document and analyst nodes of a type with ``assess = true``.

    Args:
        graph: The graph.
        rubric: The rubric.

    Returns:
        Their ids, in document order.
    """
    return [
        node.id
        for node in graph
        if origin_of(node) in (DOCUMENT, ANALYST) and (spec := rubric.types.get(node.kind)) is not None and spec.assess
    ]

verdict(results)

Return the verdict the results of a node's checks give, or None when no check ran.

Parameters:

Name Type Description Default
results Sequence[str]

The results.

required

Returns:

Type Description
str | None

fails if any failed, else holds if any passed, else undetermined.

Source code in src/credencegraph_extract/checks.py
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
def verdict(results: Sequence[str]) -> str | None:
    """Return the verdict the results of a node's checks give, or ``None`` when no check ran.

    Args:
        results: The results.

    Returns:
        ``fails`` if any failed, else ``holds`` if any passed, else ``undetermined``.
    """
    if not results:
        return None
    if FAILED in results:
        return FAILS
    return HOLDS if PASSED in results else UNDETERMINED