Skip to content

LocalApplication

LocalApplication

LocalApplication(
    store: ProjectStore,
    *,
    owner_instance: str,
    policy: PolicyFile | StaticPolicy,
    capability: CapabilityReference | None,
)

One project, opened by one owner. Construct through create, open or in_memory.

The Python transport of the application contract: every operation of the operations table is a method of the same name, taking the request's members as parameters and returning the result type whose as_document() is the response the CLI, HTTP and MCP carry.

Examples:

>>> from openflowsheet.application.local import LocalApplication
>>> with LocalApplication.in_memory() as app:
...     models = app.list_models()

project_id property

project_id: str

policy property

policy: ProjectPolicy

The project policy in force now (hot-reloaded).

files_root property

files_root: Path

The directory jobs/ and imports/ live under: the project's, or an in-memory project's scratch directory.

create classmethod

create(
    directory: str | PathLike[str],
    *,
    project_id: str | None = None,
    exist_ok: bool = False,
) -> LocalApplication

A new project in directory (absent or empty), opened by the local owner.

With exist_ok, a directory that already holds a project is opened instead (MSG §3.8, FB-01), so a script that creates its project can run twice. It tries to create first and opens only on the typed refusal project_exists, so there is no check-then-act race.

Parameters:

Name Type Description Default
directory str | PathLike[str]

Where the project is created; it must be absent or empty, or (with exist_ok) hold a project.

required
project_id str | None

The project's id; a fresh project-<hex> id when omitted. With exist_ok, an existing project must have this id when it is given.

None
exist_ok bool

Open the project the directory already holds instead of refusing it.

False

Returns:

Type Description
LocalApplication

The new (or, with exist_ok, the existing) project, opened with the inline executor.

Raises:

Type Description
StoreError

Coded (.code): project_exists (without exist_ok), project_id_mismatch, directory_not_empty (files that are not a project) or not_a_directory.

open classmethod

open(
    directory: str | PathLike[str],
    *,
    capability: CapabilityReference | None = None,
    executor: Executor | ProcessExecutor = "inline",
) -> LocalApplication

Open a project: load its policy, take an owner lock, recover dead owners' jobs, then start the executor (§9.1): "inline", "process", or an unbound ProcessExecutor (a Python caller's, e.g. one constructed with test_hooks=True). The process executor takes the policy's executor settings in force now.

An invalid policy file with no valid one before it refuses the open (PolicyRefusedError): a policy is never defaulted (§10.3).

Parameters:

Name Type Description Default
directory str | PathLike[str]

An existing project directory (create, or openflowsheet project init).

required
capability CapabilityReference | None

The capability to act as; the local owner, holding every right, when omitted.

None
executor Executor | ProcessExecutor

"inline" (jobs run in the calling process), "process" (a worker process), or an unbound ProcessExecutor.

'inline'

Returns:

Type Description
LocalApplication

The opened project. Close it with close, or use it as a context manager.

in_memory classmethod

in_memory() -> LocalApplication

SQLite :memory:, inline execution only, the local owner only; nothing survives.

Returns:

Type Description
LocalApplication

A throw-away project; its files live in a scratch directory removed on close.

close

close() -> None

Shut the executor down (§9.3), then release the store and the owner lock.

validate

validate(
    revision_id: str,
    task: Task,
    optimization: Mapping[str, Any] | None = None,
) -> ValidationReport

§4.2: the stored revision's validation report for task; no side effects. read.

Parameters:

Name Type Description Default
revision_id str

A revision of this project.

required
task Task

"simulation" or "optimization" (OPT design §4.11, ADR 0071 D8).

required
optimization Mapping[str, Any] | None

The optimization request (optimization-request.schema.json), ADR 0019 Amendment 16's optional member; read only for the optimization task, and required there. The static readiness only: nothing is solved.

None

Returns:

Type Description
ValidationReport

The status (INVALID, DRAFT, READY_FOR_SIMULATION or, for the optimization task, READY_FOR_OPTIMIZATION) and every check.

Raises:

Type Description
ApplicationError

invalid_request (also the missing optimization), unsupported (nlp_solver_unavailable, before the revision is read) or not_found.

commit_change

commit_change(
    change: Change,
    expected_revision: str | None,
    idempotency_key: str,
) -> TransactionResult

§4.2: the K06 algorithm, persistent and typed. Needs draft.

The order: authorize; canonical check (Q29); ledger lookup (§7); build, validate and diff outside the write lock from a snapshot; then, inside one BEGIN IMMEDIATE transaction, the ledger again, the head check, the insert, the head move, the ledger row and the audit row. Returned: committed, replayed (same key, same request), conflict (the head moved) or rejected (a bad edit path, a taken or unknown id, a non-canonical value). Raised: a refusal, and a key reused with a different request.

Parameters:

Name Type Description Default
change Change

The edits to apply to the head (Change), with its optional new revision id.

required
expected_revision str | None

The head the change was written against; None for a project's first revision.

required
idempotency_key str

A key of the caller's choosing: the same key with the same request returns the first result (replayed) and never commits twice.

required

Returns:

Type Description
TransactionResult

status is committed, replayed, conflict or rejected; a commit carries the new revision_id, the semantic diff and the validation report.

Raises:

Type Description
ApplicationError

A refusal, for example forbidden, document_not_canonical or idempotency_key_reused (the key with a different request).

preview_change

preview_change(
    change: Change, expected_revision: str | None
) -> TransactionResult

§4.2: commit_change's steps 2 and 4–6 — no head check, no write, no ledger. read.

The validation report names the id the commit would assign, so a preview and the commit that follows it with nothing in between report the same thing.

solve

solve(revision_id: str, policy_id: str) -> RunResult

§4.2: submit_job with a fresh auto: key, wait_job until it ends (no time-out), then get_job_result(...).run_result. Needs execute; a refusal at submission is raised. policy_id may be "default", the route's registered policy (R2.3).

Parameters:

Name Type Description Default
revision_id str

A revision that validates READY_FOR_SIMULATION.

required
policy_id str

An offered solve policy id, or "default".

required

Returns:

Type Description
RunResult

The job status, the solver's outcome, the verifier's verdict and the artifacts the run registered (solution certificate, run manifest, replay bundle). A failed solve is a result, not an exception.

Raises:

Type Description
ApplicationError

A refusal at submission, for example revision_not_ready, not_found (an unknown policy) or unsupported (a registered policy that is not offered).

reproduce

reproduce(
    bundle_path: str | PathLike[str], policy: ReplayPolicy
) -> ReplayReport

§4.2: import the bundle at bundle_path (its regular files, no symlink followed) as import-<ordinal>:bundle, submit reproduce with a fresh auto: key, wait, and return the report. Needs execute. A job that ends without a report raises its error, or, when it has none (cancelled, timed_out), not_ready (§5.8 as amended by ruling round 4).

submit_job

submit_job(request: JobRequest) -> SubmitResult

§4.2: authorize execute; canonical form (Q29), then the schema; the ledger (§7); semantic admission (§5.3); accept (job, accepted, ledger row and audit row in one transaction); hand it to the executor. Returns the job as the executor leaves it — ended inline, queued or running under the process executor — or, same key, same request, the existing one with replayed = true.

get_job

get_job(job_id: str) -> Job

§4.2: any job of the project (read covers every principal's jobs).

list_jobs

list_jobs(
    *,
    status: JobStatus | None = None,
    cursor: str | None = None,
    limit: int = 50,
) -> Page[Job]

§4.2, §11.4: the project's jobs in acceptance order, by ordinal cursor.

list_job_events

list_job_events(
    job_id: str,
    *,
    after_sequence: int = -1,
    limit: int = 100,
) -> Page[JobEvent]

§4.2, §11.4: a job's events after after_sequence; the next cursor is the last sequence returned, to pass back as after_sequence.

wait_job

wait_job(
    job_id: str,
    *,
    after_sequence: int = -1,
    timeout_s: float = 20.0,
) -> JobWait

§4.2: return once the job has events after after_sequence (a cancellation request among them), once it has ended, or at timeout_s (in-process, math.inf waits for either); polls every 0.1 s. At most 100 events.

cancel_job

cancel_job(job_id: str) -> Job

§4.2: needs execute, and policy as well for another principal's job. A queued job ends cancelled at once; a running one is flagged and signalled, and stops at its next checkpoint; an ended one is returned as it is. Idempotent.

get_job_result

get_job_result(
    job_id: str, *, display_units: str | None = None
) -> JobResult

§4.2 as amended by R4: {operation, run_result, replay_report, error} of an ended job; not_ready before it ends. display_units (ADR 0075 D7.4, ADR 0019 Amendment 17) is a display preference, resolved against the project's declared ambient pressure: the result echoes it and every explanation it holds is rendered under it; its SI content is the result without it.

get_project

get_project() -> ProjectSummary

§4.2: the project, its head and counts, its solve policies, and the caller as its credential makes it. read.

list_models

list_models() -> ModelRegistryView

§4.2: each model id in MODEL_BUILDERS with its declarative ModelSignature; nothing is constructed ("inspect manifests without executing them"). read.

Returns:

Type Description
ModelRegistryView

Every model with its ports, required parameters, pins and one-of specifications, and for each pin the specification targets that can fix it.

list_revisions

list_revisions(
    *, cursor: str | None = None, limit: int = 50
) -> Page[RevisionSummary]

§4.2, §11.4: the project's revisions in commit order, by ordinal cursor. read.

get_revision

get_revision(
    revision_id: str,
    *,
    pointer: str = "",
    depth: int = DEFAULT_DEPTH,
    cursor: str | None = None,
    limit: int = DEFAULT_PAGE,
) -> Projection

§11.4: the stored revision's document — Revision.as_document(), as validate reads it and a bundle's revision.json holds it — projected. read.

diff_revisions

diff_revisions(
    from_revision: str, to_revision: str
) -> SemanticDiff

§4.2: the semantic diff (content paths added, removed, changed; the title and other descriptive members excluded) from one stored revision to another, with its elements (ADR 0019 Amendment 3, A3.2: the items of instances, connections and specifications that differ, paired by id). read.

inspect_structure

inspect_structure(
    revision_id: str,
    *,
    pointer: str = "",
    depth: int = DEFAULT_DEPTH,
    cursor: str | None = None,
    limit: int = DEFAULT_PAGE,
) -> Projection

§4.2 as amended by R1.5: the structural report of the formulation solve would use, naming its solve_path, or {"not_run_reason": …} when no route binds the revision — revision_run.route_structure, projected. read.

get_artifact

get_artifact(
    artifact_id: str,
    *,
    pointer: str = "",
    depth: int = DEFAULT_DEPTH,
    cursor: str | None = None,
    limit: int = DEFAULT_PAGE,
) -> Projection

§11.4: a registered artifact, projected; any principal's (read covers them all).

A file is its JSON when it holds a canonical JSON document, else its text lines. A replay_bundle is {manifest, files: [{name, kind, artifact_id, sha256, size_bytes}]}, its members listed — solution-state.json among them when the bundle has one (ruling round 2) — and each read in turn as <bundle id>/<file>. sha256 is the registered one: the file's bytes, or the bundle's directory hash.

Parameters:

Name Type Description Default
artifact_id str

An artifact id from a run's outputs, or <bundle id>/<file> for a bundle member.

required
pointer str

A JSON pointer into the document; the whole document when empty.

''
depth int

Bounds of the projection, and the cursor of its next page.

DEFAULT_DEPTH
cursor int

Bounds of the projection, and the cursor of its next page.

DEFAULT_DEPTH
limit int

Bounds of the projection, and the cursor of its next page.

DEFAULT_DEPTH

Returns:

Type Description
Projection

The value at pointer, with the artifact's SHA-256 and whether it was truncated.

artifact_bytes

artifact_bytes(artifact_id: str) -> bytes

§4.3, §10.4: an artifact file's bytes exactly as stored — the raw export (Python, CLI, HTTP; never MCP). A bundle is a directory, exported member by member. read.

Parameters:

Name Type Description Default
artifact_id str

A file artifact, for example <bundle id>/solution-state.json.

required

Returns:

Type Description
bytes

The file's bytes as stored.

list_audit

list_audit(
    *,
    principal_id: str | None = None,
    operation: str | None = None,
    order: AuditOrder = "ascending",
    cursor: str | None = None,
    limit: int = 50,
) -> Page[AuditRecord]

ADR 0019 Amendment 3 (A3.3; M06 design note §4.3): the project's audit rows — every effect and every refusal — by seq, optionally of one principal and one operation, each allowed row with the ledger's idempotency key. read; another principal's rows, or all principals' (principal_id omitted), need policy as well (cancel_job's rule). The cursor is {order, seq}; one issued for the other order is refused at /cursor.