Skip to main content

Testing framework for FLUX bytecode agent policies

Project description

๐Ÿงช FLUX Policy Tester

Testing framework for FLUX bytecode agent policies โ€” verify behavior, fuzz edge cases, enforce conservation bounds.

Python License Tests

FLUX policies are bytecode programs that govern AI agent behavior โ€” conservation laws enforced by a register-based VM. But bytecode is notoriously hard to test. A policy that correctly blocks 99% of violations but has an off-by-one in its budget calculation could let through a critical overflow. The FLUX Policy Tester brings disciplined testing to bytecode policies: unit tests with expected outcomes, adversarial fuzzing, property-based testing, and conservation bound verification. It uses the same VM as production โ€” not a mock โ€” so you're testing the real execution path.

What It Does

The Policy Tester provides a PolicyTester class that wraps a FLUX bytecode policy and runs it against test inputs. Three testing modes cover the full quality surface:

Unit testing โ€” define specific inputs with expected outputs. "Given temperature=72, the deadband controller should return action=idle." The tester executes the bytecode, reads the output registers, and compares to expected values. Fast, deterministic, and CI-friendly.

Adversarial fuzzing โ€” throw extreme, edge-case, and malformed inputs at the policy to find cracks. What happens with temperature=-999? temperature=NaN? An empty string? A megabyte of input? The fuzz tester generates adversarial inputs automatically based on the policy's declared input types and runs them, flagging any that cause crashes, hangs, or unexpected outputs.

Conservation bound verification โ€” given a policy and a corpus of inputs, verify that the policy never exceeds its declared conservation limits (max steps, memory budget, execution time). This catches policies that are correct in behavior but have performance pathologies on certain inputs โ€” a policy that loops 10,000 times on one specific input is a denial-of-service risk.

The tester includes an inline FLUX VM (the same one used in conservation-enforcer) with zero external dependencies. This means tests run in CI without installing additional packages, and test results are guaranteed to match production execution โ€” because it's the same VM.

Install

pip install flux-policy-tester

For development:

git clone https://github.com/SuperInstance/flux-policy-tester.git
cd flux-policy-tester
pip install -e ".[dev]"

Quick Start

from flux_policy_tester import PolicyTester

# Load a policy from the registry or from raw bytecode
tester = PolicyTester.from_registry("deadband-controller")

# โ”€โ”€ Unit Tests โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# Test specific inputs with expected outputs
tester.test_input(
    inputs={"temperature": 72},
    expected={"action": 0},      # idle
    description="comfortable temperature โ†’ idle",
)

tester.test_input(
    inputs={"temperature": 80},
    expected={"action": 1},      # cool
    description="hot โ†’ cool",
)

tester.test_input(
    inputs={"temperature": 60},
    expected={"action": 2},      # heat
    description="cold โ†’ heat",
)

# Run all unit tests
results = tester.run_unit_tests()
print(f"{results.passed}/{results.total} tests passed")
for failure in results.failures:
    print(f"  โœ— {failure.description}: {failure.error}")

Adversarial Testing

# Fuzz with extreme inputs
tester.test_adversarial(
    inputs={"temperature": 99999},
    description="extreme high temperature",
)

tester.test_adversarial(
    inputs={"temperature": -99999},
    description="extreme low temperature",
)

tester.test_adversarial(
    inputs={"temperature": 0},
    description="zero boundary",
)

# Auto-generate adversarial inputs based on declared types
fuzz_results = tester.fuzz_type(
    input_name="temperature",
    input_type="float",
    strategies=["extremes", "boundaries", "nan", "negative"],
    iterations=100,
)
print(f"Fuzz: {fuzz_results.crashed} crashes, {fuzz_results.unexpected} unexpected")

Conservation Bounds

# Verify the policy never exceeds conservation limits
tester.test_conservation_bounds(
    corpus=all_test_inputs,
    max_budget=100,
    max_steps=1000,
    max_memory=256,
)

# Test for performance pathologies
perf = tester.profile(
    inputs=stress_test_inputs,
    iterations=10000,
)
print(f"Avg cycles: {perf.avg_cycles}")
print(f"Max cycles: {perf.max_cycles}")
print(f"P99 cycles: {perf.p99_cycles}")

YAML Test Suites

# suites/deadband.yaml
policy: deadband-controller
unit_tests:
  - inputs: {temperature: 72}
    expected: {action: 0}
    description: "comfortable โ†’ idle"
  - inputs: {temperature: 80}
    expected: {action: 1}
    description: "hot โ†’ cool"
  - inputs: {temperature: 60}
    expected: {action: 2}
    description: "cold โ†’ heat"

adversarial:
  - inputs: {temperature: 99999}
    description: "extreme high"
  - inputs: {temperature: -99999}
    description: "extreme low"

conservation:
  max_steps: 100
  max_budget: 256
# Run a YAML suite
tester.run_suite("suites/deadband.yaml")

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚               FLUX Policy Tester                      โ”‚
โ”‚                                                       โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ PolicyTester โ”‚                                    โ”‚
โ”‚  โ”‚              โ”‚     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”‚
โ”‚  โ”‚ .test_input()โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚   Inline FLUX VM     โ”‚       โ”‚
โ”‚  โ”‚ .fuzz_type() โ”‚     โ”‚  (zero-dep, from     โ”‚       โ”‚
โ”‚  โ”‚ .profile()   โ”‚     โ”‚   conservation-      โ”‚       โ”‚
โ”‚  โ”‚ .run_suite() โ”‚     โ”‚   enforcer)          โ”‚       โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
โ”‚         โ”‚                        โ”‚                    โ”‚
โ”‚         โ–ผ                        โ–ผ                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”‚
โ”‚  โ”‚ Test Results โ”‚     โ”‚  Execution Trace     โ”‚       โ”‚
โ”‚  โ”‚ .passed      โ”‚     โ”‚  .cycles             โ”‚       โ”‚
โ”‚  โ”‚ .failed      โ”‚     โ”‚  .register_states    โ”‚       โ”‚
โ”‚  โ”‚ .errors[]    โ”‚     โ”‚  .memory_accesses    โ”‚       โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

API Reference

PolicyTester

class PolicyTester:
    @classmethod
    def from_registry(cls, policy_name: str) -> PolicyTester
    @classmethod
    def from_bytecode(cls, bytecode: bytes) -> PolicyTester
    @classmethod
    def from_file(cls, path: str | Path) -> PolicyTester

    # Unit testing
    def test_input(self, inputs: dict, expected: dict,
                   description: str = "") -> TestResult
    def run_unit_tests(self) -> UnitTestResults

    # Adversarial
    def test_adversarial(self, inputs: dict,
                         description: str = "") -> AdversarialResult
    def fuzz_type(self, input_name: str, input_type: str,
                  strategies: list[str] | None = None,
                  iterations: int = 100) -> FuzzResults

    # Conservation
    def test_conservation_bounds(self, corpus: list[dict],
                                 max_budget: int,
                                 max_steps: int = 1000,
                                 max_memory: int = 256) -> ConservationResult

    # Profiling
    def profile(self, inputs: list[dict],
                iterations: int = 1000) -> ProfileResult

    # Suites
    def run_suite(self, path: str | Path) -> SuiteResult

Result Types

@dataclass
class TestResult:
    passed: bool
    description: str
    expected: dict
    actual: dict
    cycles: int              # VM cycles consumed

@dataclass
class FuzzResults:
    total_runs: int
    crashed: int
    unexpected: int          # non-crash but wrong output
    crashes: list[FuzzCrash]
    coverage: float          # 0.0-1.0

@dataclass
class ProfileResult:
    avg_cycles: float
    max_cycles: int
    p99_cycles: int
    avg_memory: float
    max_memory: int

Testing

pip install -e ".[dev]"

# Run the tester's own tests
pytest tests/ -v

# Run a specific test suite
pytest tests/test_unit_testing.py -v
pytest tests/test_fuzzing.py -v
pytest tests/test_conservation.py -v

CLI

# Run a test suite from the command line
flux-test suites/deadband.yaml

# Run with verbose output
flux-test suites/deadband.yaml --verbose

# Run a single policy against auto-generated fuzz inputs
flux-test --policy deadband-controller --fuzz --iterations 1000

Cross-Implementation

This component exists in two languages:

Both implement the same specification. Choose based on your runtime.

Philosophy

Conservation enforcement is only as trustworthy as its tests. A policy with a single untested code path is a policy with a potential exploit. The FLUX Policy Tester applies the same rigor to bytecode policies that you'd apply to any safety-critical code: unit tests for expected behavior, adversarial testing for unexpected inputs, and conservation bound verification for performance safety.

This is the testing layer of the SuperInstance conservation enforcement stack. Policies are written, compiled to FLUX bytecode, tested with this framework, published to the flux-registry, and enforced at runtime by the conservation-enforcer. Each layer has a job; this layer's job is making sure policies do what they claim.

For the theoretical foundation, see AI-Writings.

Ecosystem

FLUX Runtime

  • flux-vm โ€” Python VM (pip install flux-vm)
  • flux-core โ€” Rust VM (cargo add fluxvm)
  • flux-js โ€” JavaScript VM (npm install flux-js)

Conservation

Philosophy

License

MIT โ€” see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flux_policy_tester-0.1.2.tar.gz (28.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flux_policy_tester-0.1.2-py3-none-any.whl (21.8 kB view details)

Uploaded Python 3

File details

Details for the file flux_policy_tester-0.1.2.tar.gz.

File metadata

  • Download URL: flux_policy_tester-0.1.2.tar.gz
  • Upload date:
  • Size: 28.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for flux_policy_tester-0.1.2.tar.gz
Algorithm Hash digest
SHA256 6908b52d37ed284f7c0e476e1c2938454cee2488d8ebc6826e4b1508fa756c2f
MD5 97bf4896869b9a48352137897c3c299f
BLAKE2b-256 077c632a0a8e501ca584fe61fe20449739275bbaf41645e4bd976b295f14964f

See more details on using hashes here.

File details

Details for the file flux_policy_tester-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for flux_policy_tester-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f9fd36a55cb2b7cde83e47b38eec94c80034721227d167479cd2a81305cdddef
MD5 37de05a23957f2eefdba6a5a142f8ebf
BLAKE2b-256 b3fa51d11545b8c860d6b4f6fa0b23303d446b4ca3db0d43e1411b22e03021d2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page