Metadata-Version: 2.5
Name: oro-env-runtime
Version: 0.2.11
Summary: Portable sealed-pack runtime and verifier for Oro environments
Project-URL: Homepage, https://oroagents.com
Author: ORO AI
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Requires-Dist: iso4217>=1.12
Requires-Dist: openai>=1.50
Requires-Dist: pydantic>=2.7
Description-Content-Type: text/markdown

# oro-env-runtime

Portable sealed-pack execution and verification for ORO environments.

The package owns the public runtime contract used by environment generators and validators:

- sealed-pack schemas, versions, integrity checks, and portable validation;
- pack-pinned, index-backed catalog and local-search access;
- `TaskSession`, environment execution, replay, and user simulation;
- deterministic verification, rewards, and runtime family behavior.

It deliberately excludes private catalogs and task packs, seed search, task-family generation,
catalog profiling, compiler orchestration, model configuration, and deterministic recompilation.

Requires Python 3.11 or newer and is distributed under the MIT License.

## Pack boundary and compatibility

The runtime consumes a sealed directory with exactly `manifest.json`, `checksums.sha256`,
`tf4_hybrid_release_gate.json`, and `data/tasks/private_tasks.jsonl`. Catalog source files and the
Lucene index stay outside the archive. The manifest pins their hashes and the search-server identity
that must be available when the runtime validates or opens the pack.

This source revision supports pack format `oro_compiled_epoch_v5`, environment contract
`oro.env.v3`, runtime contract `0.3.2`, tool contract `oro_task_tools_v5`, verifier `0.3.4`, and
result schema `v2`. It also requires the exact event and replay contract versions exported from
`oro_env_runtime.contracts`. These values are execution compatibility identities. They are not the
same namespace as the Python distribution version in this package's `pyproject.toml`.

`validate_epoch()` fails closed unless the pack file set and checksums are exact, every manifest
contract equals the runtime constants, the search server matches the sealed index identity, and the
task schemas, catalog references, admission evidence, counts, fingerprints, and TF4 release gate
are valid. `TaskSession` validates an uncached pack and stores a process-local seal for that path.
For performance, each file digest is reused while its size and `mtime_ns` are unchanged. This cache
invalidation is not an adversarial tamper-detection boundary because a same-length mutation can
restore the original timestamp. Consumers must extract or mount each pack on a read-only or
otherwise immutable filesystem and prevent concurrent mutation for the full execution lifetime.
Within that trust boundary, `TaskSession` compares the seal before and after construction and
revalidates when an ordinary file change alters the observed metadata.

The control plane may derive a qualifying or race delivery subset with
`build_delivery_subset_archive()`. The helper preserves the parent pack as immutable provenance,
selects an exact task roster, updates the manifest aggregates and task-set fingerprint, regenerates
the checksums, and emits deterministic archive bytes with their own SHA-256. Delivery manifests
carry an explicit scope, parent hash, and roster. `validate_epoch()` applies the same task,
catalog, verifier, and checksum checks as a full pack while allowing a race subset to have
non-uniform family counts; `validate_delivery_binding()` additionally binds those valid bytes to
the scope and roster authorized by the control plane. A parent artifact signature does not sign
derivative bytes and must not be presented as their signature.

## Policy boundary and state visibility

`TaskSession.policy_view()` returns the task query, local tool schemas, and contract versions.
`TaskSession.step()` and `step_parallel()` return only `observation`, `done`, and `error`. The
complete immutable ledger stays inside the session for replay and verification.

State has these visibility classes:

- Public: the goal, budget, frozen catalog facts, cart, tool schemas, policy errors, and terminal
  status.
- Private: `gold_set`, `acceptance`, admission evidence, verifier checks and rewards, the complete
  ledger, verifier signals, and true-state hashes.
- Conditionally revealed: the market-event kind and delta. The environment applies the event to
  the first product that the cart accepts. The solver already supplied this product. The
  environment reveals the event only in the response to that successful `add_to_cart` call.

Before and after the trigger, a change to a private field must not change any policy-visible value
when public state, seed, and actions are equal. The event target comes from the public action, not
from acceptance, gold, admission, or verifier state. Acceptance, gold, admission, verifier, ledger,
and true-state hash data stay private. A task without an event has no conditionally revealed state.
The sealed-pack validator records its event noninterference check as `not_applicable`.

For an event task, the first successful add is also the family-owned public commitment used by the
reward contract. Exploratory adds remain valid environment actions, but an add before the intended
commitment makes the event construct unsuccessful.

## Shopper interaction protocol (`oro_task_tools_v5`)

`TaskSession.run()` owns the managed solver and shopper-simulator loop. The `message` tool may be
called once or alongside other tools in an ordered solver turn. After the group finishes, the loop
may append one simulator reply to the solver transcript and records it as an authoritative
`user_message` ledger entry. A group containing multiple `message` calls still produces one reply
to the complete turn.

The managed loop may add one unsolicited shopper reply after a visible market event. It deliberately
waits for one unaided solver turn after the event fires, then appends the reply to the transcript and
ledger if the session remains active and the task is not state-blind. It does not push for arbitrary
policy actions. A terminal action during the unaided turn ends the episode without simulator rescue.

The lower-level `TaskSession.step()` and `step_parallel()` APIs do not run the shopper simulator.
They execute one ordered action group and return only `observation`, `done`, and `error` for each
call. Later calls in a group return `skipped_after_terminal` after a terminal action and cannot
change state. `policy_view()` advertises `oro_task_tools_v5` and result schema `v2`; `verdict()`
returns the typed `VerifierResult`. The immutable ledger and verifier internals are not included in
policy-visible step results.

The simulator has dialogue authority only. It cannot mutate commerce state or assign reward.
Provider timeout, unavailability, or invalid output is an environment failure and quarantines the
session; it is never classified as miner failure. Episode evidence records each delivered message
and the simulator model, prompt, configuration, normalized response, latency, and sanitized failure
type. Credentials, provider exception detail, hidden task fields, verifier state, and reward remain
private.

## Scripted intervention delivery

A multi-call solver group is one atomic turn. The harness delivers all due scripted
interventions after a nonterminal group, before the next solver turn. A group containing
`add_to_cart` followed by `place_test_order` can finish before a newly due cart-count
intervention is delivered. The harness does not deliver updates after termination or
apply an undisclosed intervention budget to an earlier order.

Adapters use `oro_env_runtime.loop.due_interventions` to select due updates and
`oro_env_runtime.loop.record_user_message` to record delivered shopper decisions in the
authoritative ledger. The private `_record_user_message` name remains available for
validators using the 0.2.7 interface.

## Releasing

Bump `project.version` in this package's `pyproject.toml` as part of a reviewed pull request.
When that change reaches `main`, GitHub Actions creates the matching `runtime-vMAJOR.MINOR.PATCH`
tag and dispatches the protected publish workflow at that tag. The publish workflow reruns the
generator tests and lint, builds and audits the public wheel, verifies it in a clean Python 3.11
environment, and publishes it to PyPI through Trusted Publishing.

PyPI releases are immutable. Fix a bad release with a new version rather than reusing a tag or
overwriting an existing artifact.
