Documentation has moved to protention.dev.

Python API reference

Version 0.5.0.

The ocura_oss package exposes typed workflow functions, read-oriented state access, frozen result and record types, enums, and public exceptions.

Names listed in ocura_oss.__all__ form the documented top-level API. Internal record writers and implementation helpers remain package internals.

API status

The Python API is provisional during the 0.x series. Minor releases may refine signatures, result fields, and record semantics before 1.0.

Ocura OSS supports CPython 3.11 through 3.14 and includes a py.typed marker. The runtime uses only the Python standard library.

Optional root parameters accept a path-like object, a string, or None. None resolves to the current working directory. Relative paths and ~ are resolved without changing the process working directory.

File operations can propagate OSError when a rejected read, write, replacement, or directory operation remains an operating-system error. run_demo() wraps stage failures in DemoError.

A crafted pathway lineage that exceeds Python's recursion limit can propagate RecursionError from programmatic loading, verification, branching, or comparison. The CLI converts that condition to exit status 2.

Declared parameter mappings require nonempty string values. Keys must begin with a letter or underscore and may then contain letters, digits, underscores, periods, or hyphens. Values are stored without type conversion.

In 0.5.0, run(parameters=...) requires a dict or None; convert other mapping containers with dict(parameters). branch(parameters=...) converts its mapping to a dictionary before validation. The published annotations use Mapping[str, str] for both functions.

Invalid parameter declarations in run() and branch() can raise ocura_oss.model.ValidationError. This exception is defined in ocura_oss.model and is not a subclass of StoreError, so catching only StoreError does not catch these parameter errors.

Use these operations from a script or an AI agent inside its existing execution environment. The automation guide describes caller responsibilities; the training example supplies PyTorch/JAX workloads with an optional local Ray executor.

Workflow example

import sys
from pathlib import Path

from ocura_oss import ComparisonState, branch, compare, initialize, run, verify

root = Path("experiment")
initial = initialize(root, name="batch study")

baseline = run(
    [sys.executable, "-c", "print('baseline')"],
    root=root,
    pathway_id=initial.pathway.id,
    parameters={"batch": "1"},
)

child = branch(
    baseline.chokepoint.id,
    root=root,
    reason="increase batch",
    parameters={"batch": "4"},
)

run(
    [sys.executable, "-c", "print('child')"],
    root=root,
    pathway_id=child.id,
    parameters={"batch": "4"},
)

comparison = compare(baseline.chokepoint.id, root=root)

assert comparison.state is ComparisonState.READY
assert verify(root).ok

Workflow functions

ocura_oss.initialize

initialize(
    root: os.PathLike[str] | str | None = None,
    *,
    name: str = "ocura-oss",
) -> Initialization

Create one den and one default pathway under a project root.

Parameters

NameTypeDefaultDescription
rootpath-like, string, or NoneNoneProject root that will contain .ocura-oss/; None selects the current working directory
namestringocura-ossNonblank name stored in the den record

Returns

Initialization containing the resolved root, created den, and default pathway.

Raises

ExceptionCondition
StoreError.ocura-oss/ already exists, name is blank or invalid, or state cannot be written

Notes

Initialization fails if .ocura-oss/ already exists, including when the directory contains incomplete state. All created state remains under the selected project root.

Example

from ocura_oss import initialize

initial = initialize("experiment", name="optimizer study")
print(initial.pathway.id)

ocura_oss.run

run(
    command: Sequence[str],
    *,
    root: os.PathLike[str] | str | None = None,
    pathway_id: str | None = None,
    parameters: Mapping[str, str] | None = None,
    mirror: bool = False,
    capture: bool = True,
    masked_arguments: Iterable[int] = (),
    substitute: bool = False,
    context: bool = False,
    context_files: Iterable[os.PathLike[str] | str] = (),
) -> RunExecution

Run one trusted local command and record terminal evidence.

Parameters

NameTypeDefaultDescription
commandsequence of stringsrequiredExecutable followed by its argument tokens; a plain string or bytes object is rejected
rootpath-like, string, or NoneNoneProject root containing initialized state
pathway_idstring or NoneNonePathway that receives the atom; None selects the den's default pathway
parametersdict of string to string, or NoneNoneDeclared parameters stored on the atom; convert other mappings with dict(parameters). Values configure the command only when used with substitute=True
mirrorbooleanFalseStream stdout and stderr to the current terminal while retaining the same bytes in logs
capturebooleanTrueRetain stdout and stderr as logs; False writes no output to disk and records that it was not captured
masked_argumentsiterable of integers()Zero-based positions in command whose tokens are stored as <masked>; the command still receives the real values
substitutebooleanFalseReplace {KEY} in command tokens with that parameter's value, and record each parameter used
contextbooleanFalseRecord the platform and the git revision and dirty state at launch
context_filesiterable of paths()Files whose size and SHA-256 are recorded at launch; relative paths are resolved against the project root

Returns

RunExecution containing the recorded Atom and terminal Chokepoint.

Raises

ExceptionCondition
StoreErrorCommand tokens, masked positions, placeholders, state, pathway, or evidence persistence is invalid, or a context file cannot be read
ocura_oss.model.ValidationErrorparameters is neither a dictionary nor None, or a declared parameter key or value is invalid

Child command failures and launch failures are returned as atom outcomes rather than raised as exceptions.

Outcome mapping

Outcomereturn_codelaunch_error_categoryMeaning
Outcome.PASSED0NoneProcess launched and returned zero
Outcome.FAILEDnonzero integerNoneProcess launched and returned nonzero
Outcome.LAUNCH_FAILEDNonecategory stringProcess could not be launched
Outcome.INTERRUPTEDNoneinterruptedFirst Ctrl+C interrupted the attempt and partial output was retained

Launch categories include executable_not_found, permission_denied, not_a_directory, invalid_argument, and os_error.

run() never returns Outcome.ABANDONED. That outcome is written by recover() for an attempt whose recording process stopped first.

Notes

The child runs with shell=False and the project root as its working directory. It inherits the invoking process environment, while the inherited environment remains outside recorded state.

Stdout and stderr are stored separately under .ocura-oss/logs/. With capture=False, no log files are written: the returned atom has output_capture set to OutputCapture.NONE and None in its six log fields, and mirror=True still streams the output.

Each position in masked_arguments must index command; position 0 is the executable. The attempt and atom records store <masked> at those positions and list them. Masking does not alter output, so a command that prints a masked value still writes it to a captured log.

With substitute=True, a value comes from parameters first and then from the pathway's effective parameters. The returned atom's command is the substituted command, and its declared_parameters are parameters plus every parameter a placeholder used. {{ and }} are literal braces; a placeholder without a value, or an unbalanced brace, raises StoreError before anything runs. Braces are untouched when substitute is false.

context and context_files fill the returned atom's context with a RunContext; it is None when neither is used. Nothing is queried, executed, or read for context otherwise. See optional launch context for what is recorded and what it does not establish.

The attempt is journaled under .ocura-oss/attempts/ before the command launches. One atom and one branchable terminal chokepoint are written after the command ends, and the journal entry is then removed. A second Ctrl+C, or a killed process, leaves the entry in place; recover() closes it. Several processes may call run() against one root at the same time.

The host machine, network, and process tree form the execution context. The trust model is trusted, same-owner local work.

Example

import sys

from ocura_oss import Outcome, run

execution = run(
    [sys.executable, "-c", "print('recorded')"],
    root="experiment",
    parameters={"batch": "1"},
    mirror=True,
)

assert execution.atom.outcome is Outcome.PASSED

ocura_oss.branch

branch(
    source_chokepoint_id: str,
    *,
    reason: str,
    root: os.PathLike[str] | str | None = None,
    parameters: Mapping[str, str] | None = None,
) -> Pathway

Create a metadata-only child pathway from verified terminal evidence.

Parameters

NameTypeDefaultDescription
source_chokepoint_idstringrequiredIdentifier of a terminal, branchable chokepoint
reasonstringrequiredNonblank branch reason stored on the child pathway
rootpath-like, string, or NoneNoneProject root containing the source evidence
parametersmapping of string to string, or NoneNoneOverrides applied to the parent pathway's effective parameters

Returns

The created child Pathway. It has no atom until a later run() explicitly names its ID.

Raises

ExceptionCondition
StoreErrorState or the branch reason is invalid; the source is missing, nonterminal, nonbranchable, or unverifiable; or the child cannot be written
ocura_oss.model.ValidationErrorA declared parameter key or value is invalid after the mapping is converted to a dictionary

Notes

Source verification covers the chokepoint, atom, pathway, their relationships, and both referenced logs before the write occurs.

Leading and trailing whitespace is removed from reason before storage. The resulting pathway contains lineage metadata only: parent, source chokepoint, reason, creation time, and effective parameters.

Example

from ocura_oss import branch

child = branch(
    "chokepoint-<id>",
    root="experiment",
    reason="increase batch",
    parameters={"batch": "4"},
)

ocura_oss.compare

compare(
    source_chokepoint_id: str | None = None,
    *,
    root: os.PathLike[str] | str | None = None,
) -> ComparisonResult

Compare a verified source run with the newest run on each child pathway created from its chokepoint.

Parameters

NameTypeDefaultDescription
source_chokepoint_idstring or NoneNoneExplicit source chokepoint; None selects the newest chokepoint referenced by a child pathway after full-state verification, or the newest terminal chokepoint when no branches exist
rootpath-like, string, or NoneNoneProject root containing initialized state

Returns

ComparisonResult with the source summary, ordered child comparisons, and a ComparisonState.

Raises

ExceptionCondition
StoreErrorState, source evidence, selected child evidence, or automatic source selection is invalid

Notes

Explicit selection verifies the pinned source and relevant child evidence. To discover children, it also reads and validates every pathway record, and every atom record when the selected source has children. An unrelated malformed or checksum-invalid pathway or atom record can therefore block an explicit comparison. Verification of logs and relationships remains scoped to the selected evidence.

Automatic selection requires complete state verification and selects the newest chokepoint referenced by a child pathway. A state with no child pathways selects its newest terminal chokepoint and reports NO_BRANCH. Any verification problem causes automatic selection to fail.

Comparison is a read-only operation over recorded state. For a child with more than one atom, it selects the newest atom by start time and identifier.

ComparisonState.READY means every child has evidence. PARTIAL means at least one child lacks evidence. NO_BRANCH means the source has no child pathways.

Parameter deltas contain inherited, added, and changed values.

Example

from ocura_oss import ComparisonState, compare

result = compare("chokepoint-<id>", root="experiment")
if result.state is ComparisonState.PARTIAL:
    missing = [child.pathway_id for child in result.children if child.missing_evidence]

ocura_oss.verify

verify(
    root: os.PathLike[str] | str | None = None,
    *,
    against: Iterable[str] | None = None,
) -> StateVerification

Recheck every state record and every log referenced by a recorded run.

Parameters

NameTypeDefaultDescription
rootpath-like, string, or NoneNoneProject root containing initialized state
againstiterable of strings, or NoneNoneManifest lines retained from an earlier verification; each must still be present unchanged. Blank lines and lines starting with # are skipped; a manifest left with no entries is an error

Returns

StateVerification. report.ok is true when report.problems is empty. The report contains record counts, the number of individual logs that passed verification, and the identifiers of running and abandoned attempts.

Raises

ExceptionCondition
StoreErrorInitialized state is absent; the den record is missing, unreadable, malformed, or unverifiable; or against has a malformed entry or lists no records

Problems in other records and logs are normally collected in the returned report instead of raised.

Notes

Verification checks record envelopes, checksums, identifiers, filenames, required fields, semantic relationships, lineage, that every atom has exactly one chokepoint, referenced log containment, byte counts, log digests, orphaned log files, unexpected directories under logs/, and unfinished attempts.

It may run while other processes record runs under the same root. An attempt that a live process is still recording appears in running_attempts and is not a problem. An abandoned attempt is a problem until recover() closes it.

When the state is intact, report.manifest holds one KIND ID CHECKSUM line per verified record and report.digest is the SHA-256 of those lines. Retain the manifest where this state's writers cannot change it and pass it back as against to detect a record that was rewritten together with its checksum. Records added since are allowed. See retained manifests.

Verification establishes local consistency among records and logs. Authorship and execution-environment reproduction require separate evidence.

Example

from pathlib import Path

from ocura_oss import verify

report = verify("experiment")
for record, problem in report.problems:
    print(record, problem)

retained = Path("trusted/experiment.manifest")
if report.ok:
    retained.write_text("".join(f"{line}\n" for line in report.manifest))

# Later, possibly after more runs:
assert verify("experiment", against=retained.read_text().splitlines()).ok

ocura_oss.recover

recover(
    root: os.PathLike[str] | str | None = None,
) -> tuple[RecoveredAttempt, ...]

Close every attempt whose recording process stopped before finalizing it.

Parameters

NameTypeDefaultDescription
rootpath-like, string, or NoneNoneProject root containing initialized state

Returns

A tuple with one RecoveredAttempt for each attempt that was closed. It is empty when nothing was abandoned.

Raises

ExceptionCondition
StoreErrorInitialized state is absent, or an attempt record or its evidence is malformed or unreadable

Notes

What recovery writes depends on how far the recorder got:

RecoveredAttempt.actionWhenResult
RecoveryAction.ABANDONEDNo outcome had been recordedAn atom with Outcome.ABANDONED and its terminal chokepoint
RecoveryAction.COMPLETEDThe atom existed without its chokepointThe missing chokepoint, with the atom's recorded outcome
RecoveryAction.CLEAREDThe atom and chokepoint both existedThe leftover attempt record is removed

An abandoned atom has None for finished_at, duration_seconds, return_code, and launch_error_category. Output captured before the recorder stopped is retained and measured, so it verifies afterward.

Attempts that a live process is still recording are left alone, so recovery is safe while other runs are in flight. Call it only after the abandoned command itself has stopped: Ocura OSS does not stop a command whose recorder died, and one that is still running can keep writing to logs that recovery has measured.

Example

from ocura_oss import recover, verify

for closed in recover("experiment"):
    print(closed.atom_id, closed.action.value)

assert verify("experiment").ok

ocura_oss.run_demo

run_demo(
    root: os.PathLike[str] | str,
) -> DemoReport

Run the complete retained demonstration in a new directory.

Parameters

NameTypeDefaultDescription
rootpath-like or stringrequiredDestination directory; it must not exist

Returns

DemoReport containing the retained root, completed stages, and a ready comparison.

Raises

ExceptionCondition
DemoErrorThe destination exists or any demonstration stage fails

Notes

The directory is retained on success and failure. Both demonstration commands must pass and the final state must verify before a report is returned.

Stages are initialize, baseline-run, chokepoint, branch, rerun, verify, and compare.

Example

from ocura_oss import run_demo

report = run_demo("ocura-oss-demo")
print(report.comparison.state.value)

Store

ocura_oss.Store

Store(
    root: os.PathLike[str] | str | None = None,
)

Read and verify Ocura OSS state under one project root.

The documented constructor, attributes, loading methods, listing methods, initialization method, verification methods, and recovery method form the provisional low-level API. Direct record writers are internal.

Parameters

NameTypeDefaultDescription
rootpath-like, string, or NoneNoneProject root; None selects the current working directory

Attributes

NameTypeDescription
rootpathlib.PathResolved project root
state_dirpathlib.PathResolved .ocura-oss/ directory
pathways_dirpathlib.PathPathway record directory
atoms_dirpathlib.PathAtom record directory
chokepoints_dirpathlib.PathChokepoint record directory
attempts_dirpathlib.PathUnfinished attempt records and their lock files
logs_dirpathlib.PathRecorded log directory
den_pathpathlib.PathDen record path

Constructing a Store resolves paths only. exists(), require(), and initialize_state() provide the state-presence operations.

Example

from ocura_oss import Store

store = Store("experiment")
if store.exists():
    print(store.load_den().name)

Store.exists

store.exists() -> bool

Return whether the .ocura-oss/ state directory exists.

Returns

True when the state directory exists, including when its contents are incomplete. Use require() or verify_state() for stronger checks.

Store.require

store.require() -> None

Require an initialized den under the project root.

Returns

None.

Raises

ExceptionCondition
StoreErrorden.json is not a file

This method checks den.json presence only. load_den() parses the den, and verify_state() performs complete verification.

Store.load_den

store.load_den() -> Den

Load and validate the den record.

Returns

The parsed Den.

Raises

ExceptionCondition
StoreErrorThe record is missing, unreadable, malformed, checksum-mismatched, or fails payload validation

Store.load_pathway

store.load_pathway(
    pathway_id: str,
) -> Pathway

Load a pathway and validate its den and lineage references.

Parameters

NameTypeDescription
pathway_idstringIdentifier of the pathway record to load

Returns

The parsed Pathway.

Raises

ExceptionCondition
StoreErrorThe identifier or record is invalid; the den, parent, or source reference is invalid; or lineage is cyclic
RecursionErrorA crafted lineage exceeds the Python recursion limit

Child pathways must set parent and source fields together, and their source chokepoint must belong to the parent pathway.

Store.load_atom

store.load_atom(
    atom_id: str,
) -> Atom

Load an atom and validate its pathway reference.

Parameters

NameTypeDescription
atom_idstringIdentifier of the atom record to load

Returns

The parsed Atom.

Raises

ExceptionCondition
StoreErrorThe identifier, record, payload, outcome invariants, or referenced pathway is invalid

This method validates the atom and its log metadata fields. verify_atom_evidence() reads and verifies the referenced files.

Store.load_chokepoint

store.load_chokepoint(
    chokepoint_id: str,
) -> Chokepoint

Load a chokepoint and validate its atom, pathway, and outcome.

Parameters

NameTypeDescription
chokepoint_idstringIdentifier of the chokepoint record to load

Returns

The parsed Chokepoint.

Raises

ExceptionCondition
StoreErrorThe identifier or record is invalid; the atom or pathway is invalid; or atom and chokepoint fields disagree

verify_atom_evidence() provides the corresponding log-file verification.

Store.list_pathways

store.list_pathways() -> list[Pathway]

Return pathway records in deterministic creation order.

Returns

A list sorted by created_at, then id.

Raises

ExceptionCondition
StoreErrorAny listed JSON record has an invalid envelope, checksum, payload, kind, or filename-to-ID relationship

The method fails closed instead of skipping an invalid record. Use load_pathway() or verify_state() when reference validation is required.

Store.list_atoms

store.list_atoms() -> list[Atom]

Return atom records in deterministic start order.

Returns

A list sorted by started_at, then id.

Raises

ExceptionCondition
StoreErrorAny listed JSON record has an invalid envelope, checksum, payload, outcome invariants, kind, or filename-to-ID relationship

load_atom() adds pathway validation. verify_state() adds complete relationship and log verification.

Store.list_chokepoints

store.list_chokepoints() -> list[Chokepoint]

Return chokepoint records in reverse deterministic creation order.

Returns

A list sorted by created_at, then id, both descending.

Raises

ExceptionCondition
StoreErrorAny listed JSON record has an invalid envelope, checksum, payload, kind, or filename-to-ID relationship

load_chokepoint() adds atom relationship validation. verify_state() adds complete relationship and log verification.

Store.has_terminal_evidence

store.has_terminal_evidence(
    pathway_id: str,
) -> bool

Return whether any listed atom records the supplied pathway ID.

Parameters

NameTypeDescription
pathway_idstringPathway identifier to match against atom records

Returns

True when at least one atom names the pathway, otherwise False.

Raises

StoreError if atom listing fails.

The result reflects atom membership only. Pathway loading and log verification are separate operations.

Store.resolve_log_path

store.resolve_log_path(
    atom: Atom,
    stream: Literal["stdout", "stderr"],
) -> pathlib.Path

Resolve one recorded log path after containment checks.

Parameters

NameTypeDescription
atomAtomAtom whose recorded log path is resolved
streamstdout or stderrSelects the corresponding log field

Returns

The resolved pathlib.Path directly inside this store's .ocura-oss/logs/ directory.

Raises

ExceptionCondition
StoreErrorstream is invalid; the atom was recorded without output capture; or the recorded path is empty, absolute, escaping, or outside the direct logs directory

The returned path has passed containment checks only. Use read_verified_log() to consume bytes that have been checked against the stored atom; verify_atom_evidence() checks both logs without returning their contents.

Store.read_verified_log

store.read_verified_log(
    atom_id: str,
    *,
    stream: Literal["stdout", "stderr"] = "stdout",
) -> bytes

Read one complete recorded log and verify the exact bytes returned. Added in 0.4.0.

Parameters

NameTypeDefaultDescription
atom_idstringrequiredIdentifier of the stored atom whose output is read
streamstdout or stderrstdoutSelects the recorded output stream; keyword-only

Returns

The selected log as bytes, unchanged, after loading and validating the stored atom and its lineage, checking path containment, and verifying the returned bytes' count and SHA-256 digest against the atom.

Raises

ExceptionCondition
StoreErrorThe atom or lineage is invalid; the stream is invalid; the atom was recorded without output capture; or the selected log is missing, unreadable, outside containment, or inconsistent with its recorded byte count or digest
RecursionErrorA crafted lineage exceeds the Python recursion limit

Notes

The complete log is read into memory. Binary output is preserved, and output from failed commands can be read. Decoding and metric interpretation belong to the caller.

This is a targeted check of one stream. It does not verify the other stream or the whole ledger; use verify_state() for the complete state check. Reading does not lock the ledger or create an atomic snapshot of records and logs. The returned bytes remain the verified contents even if the log file later changes.

Example

import json

from ocura_oss import Store

store = Store("experiment")
raw = store.read_verified_log("atom-<id>", stream="stdout")
metrics = json.loads(raw.decode("utf-8"))  # For a workload that emits UTF-8 JSON.

diagnostics = store.read_verified_log("atom-<id>", stream="stderr")

Store.verify_atom_evidence

store.verify_atom_evidence(
    atom: Atom,
) -> None

Verify the log files referenced by one atom.

Parameters

NameTypeDescription
atomAtomAtom containing stdout and stderr paths, byte counts, and SHA-256 digests

Returns

None when both logs pass verification. An atom recorded without output capture has no logs and passes.

Raises

ExceptionCondition
StoreErrorA path escapes containment, a log is missing, or a byte count or SHA-256 digest differs

The checksum supports local change detection. Authorship requires separate authenticated evidence.

Store.initialize_state

store.initialize_state(
    *,
    name: str,
) -> tuple[Den, Pathway]

Create one den and one default pathway.

Parameters

NameTypeDescription
namestringNonblank name stored in the den

Returns

A (den, pathway) tuple.

Raises

ExceptionCondition
StoreErrorState already exists, the name is invalid, or state cannot be written

Use top-level initialize() when the resolved root should be included in the result.

Store.verify_state

store.verify_state(
    *,
    against: Iterable[str] | None = None,
) -> StateVerification

Verify every state record and every log referenced by a valid atom.

Returns

StateVerification. Problems outside the den are collected by record name when possible. logs_checked counts individual log files that passed verification. running_attempts and abandoned_attempts name unfinished attempts. manifest and digest are filled when the state is intact. against behaves as described for top-level verify().

Raises

ExceptionCondition
StoreErrorThe den is missing, unreadable, malformed, checksum-mismatched, or invalid

Notes

The scan reports invalid record files, broken relationships, invalid lineage, source-parent disagreement, atoms without exactly one chokepoint, missing or changed logs, orphaned files, unexpected directories under logs/, and abandoned attempts.

Other processes may record runs under the same root during the scan. A running attempt is not a problem, and its logs are not checked until it is finalized.

Store.list_attempts

store.list_attempts() -> list[tuple[Attempt, AttemptState]]

Return unfinished attempts with their state, ordered by start time and then identifier.

Returns

A list of (attempt, state) pairs. The state is AttemptState.RUNNING while a live process is recording the attempt and AttemptState.ABANDONED once that process has stopped without finalizing it. A finalized attempt is an atom and is not listed.

Raises

StoreError if an attempt record is malformed, checksum-mismatched, misnamed, or unreadable.

Store.recover

store.recover(
    *,
    now: Callable[[], datetime.datetime] | None = None,
) -> tuple[RecoveredAttempt, ...]

Close every unfinished attempt whose recording process has stopped. Top-level recover() calls this method and documents the actions, results, and limits.

Parameters

NameTypeDefaultDescription
nowcallable returning a timezone-aware datetime.datetime, or NoneNoneClock for a newly created chokepoint when the atom has no recorded finish time; None uses the current UTC clock

The clock supplies the chokepoint's creation timestamp. It does not add a finish time, duration, or return code to an abandoned atom.

Raises

ExceptionCondition
StoreErrorInitialized state is absent, or an attempt record or its evidence is malformed or unreadable
ocura_oss.model.ValidationErrorThe now callback returns a value that is not a timezone-aware datetime.datetime

Record types

Public records and results are frozen dataclasses. Their fields cannot be reassigned. Mapping fields should be treated as read-only values.

The dataclasses describe values returned by workflows and Store. Direct construction creates an in-memory value only; workflow functions and Store loading provide persistence and validation.

Identifiers use a kind prefix followed by 32 lowercase hexadecimal characters. Timestamps are normalized UTC ISO 8601 strings with offsets.

ocura_oss.Den

Den(
    id: str,
    name: str,
    created_at: str,
    default_pathway_id: str,
)

Project-local state identity and default pathway.

Attributes

NameTypeDescription
idstringDen identifier
namestringUser-supplied state name
created_atstringUTC ISO 8601 creation timestamp
default_pathway_idstringPathway selected when run() omits pathway_id

ocura_oss.Pathway

Pathway(
    id: str,
    den_id: str,
    created_at: str,
    parent_pathway_id: str | None,
    source_chokepoint_id: str | None,
    reason: str,
    parameters: Mapping[str, str],
)

One lineage of declared parameters and recorded evidence.

Attributes

NameTypeDescription
idstringPathway identifier
den_idstringOwning den identifier
created_atstringUTC ISO 8601 creation timestamp
parent_pathway_idstring or NoneParent for a branch; None on the default pathway
source_chokepoint_idstring or NoneSource boundary for a branch; None on the default pathway
reasonstringBranch reason or default pathway
parametersmapping of string to stringEffective pathway parameters after inheritance and overrides

Parent and source fields are either both set or both None.

ocura_oss.Atom

Atom(
    id: str,
    pathway_id: str,
    started_at: str,
    finished_at: str | None,
    duration_seconds: float | None,
    outcome: Outcome,
    return_code: int | None,
    launch_error_category: str | None,
    declared_parameters: Mapping[str, str],
    command: tuple[str, ...],
    stdout_log: str | None,
    stderr_log: str | None,
    stdout_bytes: int | None,
    stderr_bytes: int | None,
    stdout_sha256: str | None,
    stderr_sha256: str | None,
    output_capture: OutputCapture = OutputCapture.FULL,
    masked_arguments: tuple[int, ...] = (),
    context: RunContext | None = None,
)

One recorded command attempt and its referenced output logs.

Attributes

NameTypeDescription
idstringAtom identifier
pathway_idstringPathway receiving this evidence
started_atstringUTC ISO 8601 start timestamp
finished_atstring or NoneUTC ISO 8601 finish timestamp; None for an abandoned atom
duration_secondsfloat or NoneNonnegative finite elapsed duration, rounded to six decimal places for package-created atoms; None for an abandoned atom
outcomeOutcomeTerminal command outcome
return_codeinteger or NoneProcess return code for passed and failed outcomes
launch_error_categorystring or NoneNormalized launch category, or interrupted
declared_parametersmapping of string to stringLabels supplied to this run
commandtuple of stringsExecutable and argument tokens retained in the raw record, with <masked> at each masked position
stdout_logstring or NoneProject-relative stdout log path
stderr_logstring or NoneProject-relative stderr log path
stdout_bytesinteger or NoneRecorded stdout byte count
stderr_bytesinteger or NoneRecorded stderr byte count
stdout_sha256string or NoneLowercase SHA-256 digest of stdout bytes
stderr_sha256string or NoneLowercase SHA-256 digest of stderr bytes
output_captureOutputCaptureWhether stdout and stderr were retained as logs
masked_argumentstuple of integersAscending positions in command that hold the masked placeholder
contextRunContext or NoneLaunch context, when it was requested

Outcome, return code, and launch category must satisfy the invariants described by run(). An abandoned atom carries neither a return code nor a launch category.

The six log fields are all set when output_capture is OutputCapture.FULL and all None when it is OutputCapture.NONE. For an abandoned atom, the byte counts and digests describe each log as recovery found it.

ocura_oss.Attempt

Attempt(
    id: str,
    pathway_id: str,
    chokepoint_id: str,
    started_at: str,
    declared_parameters: Mapping[str, str],
    command: tuple[str, ...],
    stdout_log: str | None,
    stderr_log: str | None,
    output_capture: OutputCapture = OutputCapture.FULL,
    masked_arguments: tuple[int, ...] = (),
    context: RunContext | None = None,
)

One run that has started and is not yet finalized, as returned by Store.list_attempts().

Attributes

NameTypeDescription
idstringIdentifier of the atom this attempt becomes when finalized
pathway_idstringPathway the run was started on
chokepoint_idstringIdentifier reserved for the atom's terminal chokepoint
started_atstringUTC ISO 8601 start timestamp
declared_parametersmapping of string to stringLabels supplied to this run
commandtuple of stringsExecutable and argument tokens, with <masked> at each masked position
stdout_logstring or NoneProject-relative stdout log path; None without capture
stderr_logstring or NoneProject-relative stderr log path; None without capture
output_captureOutputCaptureWhether stdout and stderr are being retained as logs
masked_argumentstuple of integersAscending positions in command that hold the masked placeholder
contextRunContext or NoneLaunch context, when it was requested

An attempt has no outcome, byte counts, or digests: its logs may still be growing.

ocura_oss.RunContext

RunContext(
    platform: Mapping[str, str] | None,
    git_revision: str | None,
    git_dirty: bool | None,
    files: Mapping[str, FileDigest],
)

Facts about where a command attempt started, recorded only on request.

Attributes

NameTypeDescription
platformmapping of string to string, or Nonesystem, release, and machine of the recording machine; None unless context=True
git_revisionstring or NoneFull object name of the checked-out commit; None unless context=True found a work tree with a commit
git_dirtyboolean or NoneWhether the work tree had modified or untracked files other than .ocura-oss/; None whenever git_revision is
filesmapping of string to FileDigestOne entry per file named in context_files, keyed by the path as given with forward slashes

Context describes the moment of launch. Verification does not recheck it.

ocura_oss.FileDigest

FileDigest(
    bytes: int,
    sha256: str,
)

Size and lowercase SHA-256 digest of one file named for context capture.

ocura_oss.RecoveredAttempt

RecoveredAttempt(
    atom_id: str,
    chokepoint_id: str,
    pathway_id: str,
    action: RecoveryAction,
)

One unfinished attempt closed by recover().

Attributes

NameTypeDescription
atom_idstringAtom the attempt was closed as
chokepoint_idstringThat atom's terminal chokepoint
pathway_idstringPathway containing the atom
actionRecoveryActionWhat closing the attempt had to do

ocura_oss.Chokepoint

Chokepoint(
    id: str,
    pathway_id: str,
    atom_id: str,
    created_at: str,
    kind: str,
    outcome: Outcome,
    branchable: bool,
)

Terminal evidence boundary that can serve as a branch source.

Attributes

NameTypeDescription
idstringChokepoint identifier
pathway_idstringPathway shared with the source atom
atom_idstringSource atom identifier
created_atstringUTC ISO 8601 creation timestamp
kindstringterminal in schema version 2
outcomeOutcomeOutcome that must agree with the source atom
branchablebooleanWhether branching may use this boundary

ocura_oss.Initialization

Initialization(
    root: pathlib.Path,
    den: Den,
    pathway: Pathway,
)

State created by initialize().

Attributes

NameTypeDescription
rootpathlib.PathResolved project root
denDenCreated den
pathwayPathwayCreated default pathway

ocura_oss.RunExecution

RunExecution(
    atom: Atom,
    chokepoint: Chokepoint,
)

Records produced by one command attempt.

Attributes

NameTypeDescription
atomAtomRecorded attempt and log metadata
chokepointChokepointTerminal boundary created for the atom

ocura_oss.RunSummary

RunSummary(
    id: str,
    pathway_id: str,
    outcome: Outcome,
    started_at: str,
    duration_seconds: float | None,
    return_code: int | None,
)

Reduced command fields used in comparisons and public summaries.

Attributes

NameTypeDescription
idstringSource atom identifier
pathway_idstringPathway containing the atom
outcomeOutcomeTerminal outcome
started_atstringUTC ISO 8601 start timestamp
duration_secondsfloat or NoneRecorded elapsed duration; None for an abandoned run
return_codeinteger or NoneProcess return code when applicable

Methods

to_dict() -> dict returns these fields with outcome converted to its string value.

ocura_oss.ParameterDelta

ParameterDelta(
    inherited: Mapping[str, str],
    added: Mapping[str, str],
    changed: Mapping[str, Mapping[str, str]],
)

Declared parameter relationship between source and child values.

Attributes

NameTypeDescription
inheritedmapping of string to stringKeys present with the same value in source and child
addedmapping of string to stringKeys present only in the child
changednested string mappingChanged keys, each with source and child values

Removed source keys are outside the parameter-delta representation.

Methods

MethodReturnsDescription
to_dict()dictionaryDeterministically sorted inherited, added, and changed mappings
phrase()stringConcise text summary, or (none) when the delta has no represented entries

ocura_oss.ChildComparison

ChildComparison(
    pathway_id: str,
    reason: str,
    source_chokepoint_id: str,
    parameters: ParameterDelta,
    source_run: RunSummary,
    child_run: RunSummary | None,
    run_parameters: ParameterDelta | None,
    missing_evidence: bool,
)

Comparison of one child pathway with its source run.

Attributes

NameTypeDescription
pathway_idstringChild pathway identifier
reasonstringRecorded branch reason
source_chokepoint_idstringShared source chokepoint
parametersParameterDeltaParent-to-child pathway parameter delta
source_runRunSummarySource atom summary
child_runRunSummary or NoneNewest child atom summary, or None when evidence is missing
run_parametersParameterDelta or NoneSource-atom-to-child-atom parameter delta when child evidence exists
missing_evidencebooleanWhether the child has no atom

Methods

to_dict() -> dict returns a nested JSON-compatible representation.

ocura_oss.ComparisonResult

ComparisonResult(
    state: ComparisonState,
    source_chokepoint_id: str,
    source_pathway_id: str,
    source_run: RunSummary,
    children: tuple[ChildComparison, ...],
)

Comparison state and every child associated with one source chokepoint.

Attributes

NameTypeDescription
stateComparisonStateEvidence completeness across children
source_chokepoint_idstringSelected source boundary
source_pathway_idstringPathway containing the source atom
source_runRunSummarySource atom summary
childrentuple of ChildComparisonChild comparisons in creation order

Methods

to_dict() -> dict returns a nested JSON-compatible representation with enum values converted to strings.

ocura_oss.StateVerification

StateVerification(
    pathways: int,
    atoms: int,
    chokepoints: int,
    logs_checked: int,
    problems: tuple[tuple[str, str], ...],
    running_attempts: tuple[str, ...] = (),
    abandoned_attempts: tuple[str, ...] = (),
    manifest: tuple[str, ...] = (),
    digest: str | None = None,
)

Result of verifying records and referenced logs under one state directory.

Attributes

NameTypeDescription
pathwaysintegerValid pathway records collected by the scan
atomsintegerValid atom records collected by the scan
chokepointsintegerValid chokepoint records collected by the scan
logs_checkedintegerIndividual referenced logs that passed verification
problemstuple of pairs(record, problem) entries collected during verification
running_attemptstuple of stringsAttempts a live process is still recording; not problems
abandoned_attemptstuple of stringsAttempts whose recorder stopped; each also appears in problems
manifesttuple of stringsSorted KIND ID CHECKSUM lines for every verified record; empty when there are problems
digeststring or NoneSHA-256 of the manifest lines, each newline-terminated; None when there are problems

Properties

ok -> bool is True when problems is empty.

ocura_oss.DemoStep

DemoStep(
    step: str,
    detail: str,
)

One completed stage in a demonstration report.

Attributes

NameTypeDescription
stepstringStable stage label
detailstringRecorded summary of that stage

ocura_oss.DemoReport

DemoReport(
    root: pathlib.Path,
    steps: tuple[DemoStep, ...],
    comparison: ComparisonResult,
)

Retained demonstration location, completed stages, and comparison.

Attributes

NameTypeDescription
rootpathlib.PathResolved retained destination
stepstuple of DemoStepCompleted stages in execution order
comparisonComparisonResultFinal ready comparison

Methods

to_dict() -> dict returns a JSON-compatible representation. root is converted to a string.

Enumerations

ocura_oss.Outcome

String enum describing one terminal command attempt.

MemberValueMeaning
Outcome.PASSEDpassedProcess returned zero
Outcome.FAILEDfailedProcess returned nonzero
Outcome.LAUNCH_FAILEDlaunch_failedProcess could not be launched
Outcome.INTERRUPTEDinterruptedAttempt was interrupted and partial output was recorded
Outcome.ABANDONEDabandonedThe recording process stopped before an outcome was recorded; the attempt was closed by recover()

Outcome derives from enum.StrEnum, so members also behave as strings.

ocura_oss.OutputCapture

String enum stating whether a run's stdout and stderr were retained as logs.

MemberValueMeaning
OutputCapture.FULLfullBoth streams were written to logs
OutputCapture.NONEnoneNo output was written to disk

ocura_oss.AttemptState

String enum describing an unfinished attempt.

MemberValueMeaning
AttemptState.RUNNINGrunningA live process is still recording the attempt
AttemptState.ABANDONEDabandonedThe recording process stopped without finalizing the attempt

ocura_oss.RecoveryAction

String enum describing what closing an unfinished attempt had to do.

MemberValueMeaning
RecoveryAction.ABANDONEDabandonedNo outcome had been recorded; an abandoned atom and its chokepoint were written
RecoveryAction.COMPLETEDcompletedThe atom existed; its missing chokepoint was written
RecoveryAction.CLEAREDclearedThe atom and chokepoint existed; the leftover attempt record was removed

ocura_oss.ComparisonState

String enum describing evidence completeness for one comparison.

MemberValueMeaning
ComparisonState.NO_BRANCHno_branchSource has no child pathways
ComparisonState.PARTIALpartialAt least one child lacks evidence
ComparisonState.READYreadyEvery child has evidence

ComparisonState derives from enum.StrEnum.

Exceptions

ocura_oss.StoreError

StoreError(message)

Raised for invalid workflow input and missing, malformed, checksum-mismatched, semantically inconsistent, unverifiable, or unwritable state.

In 0.5.0, parameter validation in run() and branch() can raise ocura_oss.model.ValidationError, which is not a StoreError.

run() returns normal command failures and launch failures as Outcome values. It raises StoreError when the workflow or evidence persistence fails.

ocura_oss.DemoError

DemoError(
    step: str,
    message: str,
)

Raised when a retained demonstration cannot complete.

Parameters

NameTypeDescription
stepstringStage that failed
messagestringFailure detail

Attributes

NameTypeDescription
stepstringStage that failed
messagestringFailure detail

The destination is retained when it was created before the failure.

Module metadata

ocura_oss.__version__

ocura_oss.__version__: str

Installed package version. Version 0.5.0 reports "0.5.0".

Typing

The wheel includes py.typed, so package annotations are visible to compatible static type checkers.

from pathlib import Path

from ocura_oss import Initialization, Store, initialize

initial: Initialization = initialize(Path("experiment"))
store: Store = Store(initial.root)

Dataclass fields use concrete record and result types. Command arguments are annotated with collections.abc.Sequence, and declared parameters with Mapping. In 0.5.0, run(parameters=...) requires a dictionary at runtime; convert other mappings with dict(parameters). branch(parameters=...) accepts a mapping and converts it to a dictionary before validating its keys and values.

State and concurrency

The supported programmatic workflows write project-local .ocura-oss/ state in schema version 2. State written by 0.4 and earlier is not compatible.

Several processes may record runs under one state root at the same time, and verification and comparison may run while they do. Public workflow functions perform record mutation; direct record writers remain internal. The liveness of an unfinished attempt is read from an operating-system file lock, which is reliable on local filesystems only.

Raw atoms retain command arguments and logs retain command output. Keep secrets out of command arguments, parameter mappings, branch reasons, and output. Where one cannot be avoided, masked_arguments keeps a command token out of the records and capture=False keeps output off disk.

For command syntax and exit status, see the CLI reference. For the record layout and execution boundary, see the documentation overview.