Skip to main content

pollard-jev

A Python companion to Pollard that turns timestamped observations and permitted choices into a governed decision, a bounded simulated action, and an outcome record. The first milestone runs entirely offline after installation. It needs no credentials, model weights, or GPU.

Current release: 0.13, with reproducible local OpenJev benchmarks and an opt-in numerical-boundary and action-priority input experiment. See the changelog.

python -m pip install --upgrade pollard-jev==0.13
pollard-jev demo --output artifacts

Published under the MIT license. The initial release is 0.1; minor increments are +0.01, major increments are +0.10, and releases at or above 1.0 require the owner's explicit approval. See the release policy.

Run on Windows PowerShell

Requires Python 3.11 or newer. Tested here on Python 3.12.2.

git clone https://github.com/jemsbhai/pollard-jev.git
Set-Location pollard-jev
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[test]"
.\.venv\Scripts\python.exe -m pollard_jev demo --output artifacts
.\.venv\Scripts\python.exe -m pytest -q

Setup uses PyPI; the demo and tests make no network requests. The equivalent installed entry point is .\.venv\Scripts\pollard-jev.exe demo --output artifacts. Each demo writes uniquely named JSONL records and a Pollard SQLite ledger.

Scenario Synthetic proposal Final policy Simulated action
Fresh coherent observations continue accept move 20 cm
Conflicting observations inspect need evidence none
Missing evidence inspect need evidence none
Evidence expires during inference continue defer none
Request budget exhausted none defer none
Provider failure none defer none

The stale scenario advances a virtual clock during inference so it is reproducible. Separate tests exercise real waiting, timeout, and cancellation. The state-machine baseline reads the same request at the final evaluation time. It has no provider and therefore no provider failures or inference-request cost; the table is a behavior comparison, not a performance benchmark.

Typed inputs and outputs

from datetime import datetime, timedelta, timezone
from pollard_jev.contracts import Observation
from pollard_jev.demo import example_request
from pollard_jev.loop import DecisionLoop
from pollard_jev.providers.fixture import FixtureProvider

now = datetime.now(timezone.utc)
range_reading = Observation(
    observation_id="range-42", source="front-range-sensor",
    feature="front_range_m", value=1.5, unit="m",
    observed_at=now, valid_until=now + timedelta(seconds=5),
)
# The demo request supplies all four required sensor features and four choices.
request = example_request(now, request_id="robot-42")
request = request.model_copy(update={
    "observations": (range_reading, *request.observations[1:]),
})
with DecisionLoop(FixtureProvider(), max_requests=2,
                  records_path="artifacts/decisions.jsonl",
                  pollard_path="artifacts/decisions.db") as loop:
    record = loop.decide(request)
    print(record.model_dump_json(indent=2))

Run the complete example with .\.venv\Scripts\python.exe examples\offline_loop.py. Unknown readings use status="unknown", value=None; absence of a required feature is also explicit insufficient evidence. Datetimes must have timezones, validity windows must be positive, and numeric values must be finite.

A successful record contains fields like these (excerpt):

{
  "schema_version": "1",
  "provider_status": "ok",
  "provider_result": {
    "semantics": "synthetic_support",
    "scores": {"continue": 0.94, "inspect": 0.12, "recover": 0.12, "request_help": 0.12},
    "proposed_action": "continue",
    "parameters": {"distance_cm": 20},
    "evidence": "sufficient"
  },
  "policy": {"disposition": "accept", "reason": "supported_and_feasible"},
  "action": {"action": "continue", "status": "completed", "simulated": true},
  "budget_limit_requests": 2,
  "budget_spent_requests": 1
}

Full records include observation IDs, timestamps and units; the question and allowed choices; provider identity, version and settings; policy configuration and version; simulated skill version and observed state; timing and budget fields; and Pollard root/model/action node IDs. Records round-trip through validated Pydantic models. The JSONL is a convenient export; the same complete record is also stored as a Pollard note.

How the loop works

DecisionProvider.infer(tuple[DecisionRequest, ...]) returns typed results. The interface is general; this milestone's policy and skill set are specific to the robot demonstration. Providers return data and receive no dispatcher.

Pollard 1.6.0 supplies the real model-call ledger, custom request budget, registered action allowlist, integer argument bounds, refusal nodes, action records, SQLite persistence, and integrity verification. The companion supplies contracts, evidence/support policy, sensor validity checks, deadlines, cancellation, simulation, and linked decision records. The older sibling Pollard checkout was inspected but is not modified or used as a dependency. See the API inspection for exact versions and boundaries.

The policy checks four engineered sensor features: range and camera clearance in metres, battery percentage, and a stuck indicator of 0 or 1. Conflicting, missing, duplicate, invalid, expired, and future-dated readings block action. Support threshold 0.80, score margin 0.15, clearance 0.5 m, battery 10%, and range disagreement 0.4 m are demonstration settings, configurable through PolicyConfig. Required physical units cannot be relabeled to change their meaning. The policy also checks feasibility separately from evidence support. Task utility is represented by the caller's question and choice hypotheses; there is no trained utility or physical success predictor here.

The bounded simulated skills are:

Skill Permitted integer parameter Default
continue distance_cm: 1–50 20
inspect samples: 1–5 2
recover distance_cm: 1–20 10
request_help retries: 1 1

The request's selected parameter values must also match the provider proposal. Acceptance never expands the caller's available actions. The registered handler rechecks policy, freshness, cancellation, and the monotonic deadline immediately before dispatch. A second action in the same batch requires new observations, including when the first attempted action fails.

Inference runs in one daemon worker per loop. A timeout or cancellation discards that worker's reply. Until it finishes, later calls return busy; this prevents unbounded abandoned workers. Python cannot terminate arbitrary native model compute. A timeout bounds response/dispatch eligibility, not GPU execution or total process resource use. Cancellation does not undo an action already dispatched. Actual controllers, watchdogs, immediate stopping, and motion limits remain outside this supervisor.

The resource budget counts logical provider batch attempts: one infer(requests) invocation costs one regardless of question count. Success, malformed output, provider failure, timeout, and cancellation after admission each consume one. Pre-cancelled, busy, and budget-refused calls consume zero. Actions and audit notes consume zero model requests. This is not token, HTTP request, measured energy, or estimated-joule accounting. An adapter may perform multiple internal forward passes per logical batch. Budgets last for one loop instance/run; creating a new loop creates a new budget.

Independent support/entailment scores remain independent; they are never normalized into an action distribution. Categorical results are validated as such only when explicitly declared. Neither score type proves physical success. The fixture scores are synthetic and uncalibrated.

History, policy simulation, and live reevaluation

These are separate operations:

$recordFile = (Get-ChildItem artifacts\decisions-*.jsonl | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
.\.venv\Scripts\python.exe -m pollard_jev history $recordFile
.\.venv\Scripts\python.exe -m pollard_jev simulate-policy $recordFile
$ledgerFile = (Get-ChildItem artifacts\pollard-*.db | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
.\.venv\Scripts\pollard.exe verify $ledgerFile --json

inspect_history(path) only loads recorded events. simulate_policy(record, config, at=...) evaluates recorded observations and provider output with a specified policy/time. Neither has a dispatcher or a provider. Policy simulation does not replay the resource ledger, cancellation state, or a new physical trajectory. A changed action does not reveal what its consequences would have been.

live_reevaluate(record, loop) is an explicit new provider invocation. It consumes the loop's request budget, writes a new record linked to the original, preserves the original timestamps, and always disables dispatch. It uses whatever provider the caller explicitly put in that loop; with a fixture it remains synthetic. Old evidence normally defers at today's time. Historical records are never overwritten.

Credential fields, arbitrary malformed responses, and exception text are not persisted. Provider authentication must remain inside the caller-owned client. Do not put secrets in questions, observations, model identities, or settings: these are intentional audit content, not automatically scrubbed free text. The JSONL export and SQLite ledger are not a cross-file transaction. A crash may leave an intent or action without the final JSONL record; use the ledger for inspection. This is a single-process demonstrator, not crash recovery or exactly-once actuator infrastructure.

Optional real backend and next milestone

The implemented adapter targets AlexWortega/openjev/qwen3.5-4b-nli-v2 at a pinned commit. Real 4B inference was verified on Windows/CUDA on 2026-09-27, reusing an existing local runtime and model cache without any downloads or installs. The local runner records hashes and runtime versions, enforces offline loading, and rejects input truncation. See OpenJev setup and evidence and benchmark method, command and results.

Across 32 held-out synthetic cases, model proposals matched 12 of 20 expected actions. Calibration-only threshold selection yielded 11 correct simulated actions, no incorrect accepted actions, and 21 abstentions, with a 0.534-second median end-to-end decision time. The state machine matched all expected outcomes; this run does not establish a model advantage. Package policy defaults are unchanged. Recorded-sensor validation and the 0.8B comparison remain outstanding.

The follow-up input experiment tested factual text and fixed task-rule prompting. Plain text did not help on development cases. Rules improved fresh-test proposal accuracy from 60% to 67.5%, but obstacle, near-threshold and observation-order failures remain. Both candidates are opt-in; JSON remains the default. The state machine still matched all expected outcomes.

Next: improve numerical/priority interpretation with new held-out validation and recorded sensor data. Add process-level inference cancellation before device integration. Measure energy with an actual meter when available; keep TOML and other proxies separate from joules. Native sensor encoders, controller connections, and MCU deployment are later work.

See implementation status for verified behavior and remaining limitations.

Metadata

Release files for pollard-jev 0.13

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

Source distribution (sdist)

Source distribution for pollard-jev 0.13
File Size Uploaded Provenance Actions
pollard_jev-0.13.tar.gz 135.0 kB Without provenance Details for pollard_jev-0.13.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pollard-jev 0.13
File Interpreter ABI Platform Actions
pollard_jev-0.13-py3-none-any.whl Python 3 none any Details for pollard_jev-0.13-py3-none-any.whl

Total release size: 174.7 kB

Release files / pollard_jev-0.13.tar.gz

Download URL pollard_jev-0.13.tar.gz
Size 135.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a6d9dc57336be43669a65604f6f9ec3cb31aef82c49b61e98968757375c4927f
BLAKE2b-256 checksum
How to use checksums
8561961af5cc60e9de335910d908935d00c214e17498b1f0bb88edcbc7ce6bc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.2

Release files / pollard_jev-0.13-py3-none-any.whl

Download URL pollard_jev-0.13-py3-none-any.whl
Size 39.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2da118212b151868ee8536a26934e4ad42cb63efb6344035c21a315259f789a6
BLAKE2b-256 checksum
How to use checksums
6d3deb26660d01cc1905560aaec1a956b998e46aa0ffb75317a81907d6a53582
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.2

Security for pollard-jev 0.13

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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