Skip to main content

verdict4

Four-value evaluation for agentic AI loops.

Replace pass/fail with NO / YES / MAYBE / IFF.

Most agentic loops evaluate with a boolean. Pass or fail. That works when every non-pass condition is actually failure. But it is not. Some outputs cannot be evaluated yet because evidence is missing. Some outputs are correct only if another result holds. A boolean check compresses both into failure and destroys correct work.

This package provides a four-value Verdict enum, a structured CheckResult, and a loop runner that handles all four branches.

Read the full explanation: Your Loop Has Two States. It Needs Four.

The finite-rank controller is specified in Quaternary Iteration Control for Looped Transformers. The controller is included in this release; looped-transformer substrate integration is in preparation.

Install

Install directly from GitHub:

pip install git+https://github.com/MetaCortex-Dynamics/verdict4.git@v0.2.0

Or from source:

git clone https://github.com/MetaCortex-Dynamics/verdict4.git
cd verdict4
pip install -e .

After the GitHub release has published the package to PyPI, install the pinned release with:

pip install verdict4==0.2.0

Until that release workflow completes, use the GitHub install above.

Quick start

from quaternary import Verdict, CheckResult, no, yes, maybe, iff, run

# Define your check function — return a CheckResult, not a bool
def check(output):
    if not output.get("valid"):
        return no("validation failed: missing required field")
    if not output.get("schema_available"):
        return maybe("schema file not found")
    if output.get("depends_on_auth"):
        return iff("auth module deployed")
    return yes()

# Define your generator
def generate(task, *, exclusions):
    # Your agent generates output here
    # `exclusions` carries named reasons from prior NO results
    return {"valid": True, "schema_available": True}

# Run the loop
outcome = run(
    task="build parser",
    generate=generate,
    check=check,
)

print(outcome.status)       # "accepted" | "held" | "blocked" | "exhausted"
print(outcome.exclusions)   # accumulated NO reasons
print(outcome.rounds)       # how many iterations

The four verdicts

Verdict Meaning Loop action
NO Fails a named condition Add reason to exclusions, retry
YES Satisfies conditions Accept
MAYBE Cannot evaluate — evidence missing Hold, gather evidence, recheck
IFF Correct if dependency holds Bind to dependency, resolve, recheck

API

Core types

from quaternary import Verdict, CheckResult, no, yes, maybe, iff

Verdict — IntEnum with values NO=0, YES=1, MAYBE=2, IFF=3

CheckResult — frozen dataclass:

  • verdict: Verdict
  • reason: str | None — required for NO
  • needed: str | EvidenceNeed | ComputeNeed | None — required for MAYBE
  • dependency: str | None — required for IFF
  • meta: dict[str, Any] — optional domain metadata

Constructors: no(reason), yes(), maybe(needed), iff(dependency) — all accept **meta kwargs.

Runner

from quaternary import run, LoopOutcome

run(task, *, generate, check, ...) — runs the quaternary loop.

Required:

  • generate(task, *, exclusions) -> output
  • check(output) -> CheckResult

Optional:

  • gather(needed) -> evidence — called on MAYBE
  • recheck(output, evidence?) -> CheckResult — called after gather or dependency resolution
  • is_resolved(dep) -> bool — called on IFF
  • is_failed(dep) -> bool — called on IFF
  • max_rounds: int — default 10
  • on_hold(output, reason) — callback when holding
  • on_blocked(output, dep) — callback when blocked

LoopOutcome:

  • status: "accepted" | "held" | "blocked" | "exhausted"
  • output: the final output (or None if exhausted)
  • exclusions: accumulated NO reasons
  • rounds: iterations used
  • held_reason / blocked_by: why the loop stopped
  • contradiction: flagged contradictory exclusion pairs (if any)

Finite-rank controller

Version 0.2.0 adds a substrate-free controller for repeated computation. It preserves the v0.1.0 runner API while adding typed MAYBE needs, finite one-use alphabets, dependency bindings, logical leases, and replayable accounting receipts.

from quaternary import (
    ComputeNeed,
    QICTConfig,
    QICTController,
    maybe,
    rank,
    yes,
)

config = QICTConfig(compute_alphabet={"next_1", "next_2"})
controller = QICTController(config)
initial_rank = rank(config, controller.state)

controller.process(maybe(ComputeNeed("next_1")))
controller.process(maybe(ComputeNeed("next_2")))
controller.process(yes())

assert controller.state.evaluation_count <= initial_rank + 1
assert controller.audit().valid

Every evaluation that continues consumes exactly one finite opportunity: a new exclusion, an evidence request, another computation, or a dependency. Therefore the controller terminates in at most initial_rank + 1 evaluations, without assuming that the evaluator is sound.

Receipts contain controller accounting state and transition data. Candidate activations are excluded from the receipt state by type.

Examples

python examples/json_parser.py
python examples/multi_file_refactor.py

Design constraints

  • Zero domain logic. The runner is a protocol over user-supplied callables.
  • No framework. The fix is local — an enum and a branch.
  • Bounded MAYBE. A second MAYBE after evidence gathering → hold and report. No infinite gather loops.
  • Exclusion memory. NO reasons accumulate across rounds. Contradictions are flagged, not resolved.
  • No dependencies. Standard library only.

License

MIT — MetaCortex Dynamics

Metadata

Release files for verdict4 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for verdict4 0.2.0
File Size Uploaded
verdict4-0.2.0.tar.gz 19.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for verdict4 0.2.0
File Interpreter ABI Platform
verdict4-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.9 kB

Release files / verdict4-0.2.0.tar.gz

Download URL verdict4-0.2.0.tar.gz
Size 19.3 kB
Tags Source
SHA-256 checksum
How to use checksums
35fc03e570900feafa7565150fee199d5bb6ee4ad863b8869ce68d2743806a7f
BLAKE2b-256 checksum
How to use checksums
123f6248947998b7938eb0193f87d87a021fc7c624b02726db4c7070de30b68f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / verdict4-0.2.0-py3-none-any.whl

Download URL verdict4-0.2.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c03fcbbaa98c017aeb14560f73c9b83a126ee9b716d0ea39f49016e7225d2618
BLAKE2b-256 checksum
How to use checksums
738ba57154d5c44a278aa0e3d919e6d59eebd791f4ac41f08e9dd38f5982f1d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page