Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/commercial/execute-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,21 @@ This pattern also covers a response loss after your endpoint accepted an
event: OpenAdapt can retry, and your `event_id` record makes the second delivery
safe.

## Process children are separate executions

A [ProcessContract](../concepts/process-contract.md) parent sequences
independently admitted capabilities. Each child is one `POST /v1/executions`
with that child's `qualification_id`, `workflow_version`, `workflow_digest`,
and its own `idempotency_key`. The parent doesn't collapse them into one
request.

Copy a handoff parameter into the next child's `parameters` only when the
predecessor receipt `outcome` is `verified` and the predecessor's effect
contract bound that fact. Don't replay the parent. If a predecessor returns
`reconciliation_required`, stop and reconcile; don't dispatch the successor.

See [Sequence work across two applications](../guides/compose-multi-application.md).

## Integration checklist

- Keep the service token and webhook secret on the server.
Expand Down
5 changes: 5 additions & 0 deletions docs/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ jump to what you need.

`lint` reports gaps, `certify` refuses an unsafe bundle before it deploys.

- [__Process contracts__](process-contract.md)

A parent receipt over independently admitted capabilities. Handoffs copy
effect facts. Compose sequences recordings; process points at admissions.

- [__Backends: where it runs__](backends.md)

Browser (Playwright), native Windows (UIA), native macOS, native Linux
Expand Down
46 changes: 46 additions & 0 deletions docs/concepts/process-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Process contracts

A ProcessContract is a parent receipt over independently admitted capabilities.
Schema `openadapt.process-contract/v0`. Each child already carries a live
`openadapt.qualification-admission/v1` envelope: one workflow version, one
bundle digest, a counted campaign, identity and effect contract digests, a
30-day lifetime, signed Ed25519. The parent names those admissions by
`admission_id`. It doesn't copy recordings.

`admission_id` is a UUID on the child's envelope, distinct from
`runtime_validation_id`. Sitting next to another child doesn't extend anyone's
validity interval or digest binding. A child whose admission is expired,
revoked, or bound to a different digest is refused before Execute is called.

## Handoffs are effect facts

A handoff copies a parameter from child A into child B only when A's run ended
`VERIFIED` and A's Effect CONFIRMed that parameter. Window titles and URLs are
not evidence. A missing, empty, or unbound fact stops the parent before B
starts.

The parent receipt records, for each child, the `admission_id`, workflow
version, bundle digest, terminal outcome, and model-call count. For each
handoff it records the source, the target, and that the source was `VERIFIED`.
Parent `VERIFIED` requires every child `VERIFIED` and zero model calls.

## The recording parent and the admission parent

`openadapt flow compose` writes `composition.json`
(`openadapt.composition/v1`) and copies compiled child bundles. Use it after
you recorded each surface, before those children are admitted. `certify` and
`run` execute that directory. `replay` refuses it.

`openadapt flow process` writes `process-contract.json` and points at
admissions. It copies nothing. Pointing it at a `composition.json` directory
is refused, because those children aren't admitted. Each child runs through
[OpenAdapt Execute](../commercial/execute-api.md) with that child's envelope.
`replay` of the process parent is refused.

A compiled bundle still has its own ProgramGraph. `visualize` on a process
parent shows admitted children, handoff edges, and a terminal labeled End of
declared steps. Open the child bundle for its steps. See
[Read a compiled program](program-visualizer.md).

RFC-0001 is the name of this contract. Qualify each child first:
[Qualify a workflow](../guides/qualify-a-workflow.md).
23 changes: 23 additions & 0 deletions docs/concepts/program-visualizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ It does not prove `VERIFIED`. The run outcome still depends on the exact
authorization, identity, postcondition, and effect evidence required by the
execution profile.

## Parents of children stay parents

`visualize` on a compiled bundle emits that bundle's ProgramGraph: steps,
ladders, gates, halt points.

`visualize` on a compose directory (`composition.json`, schema
`openadapt.composition/v1`) draws each compiled child as one node. Handoff
edges are labeled with the effect-bound parameter names they copy, never a
window title or a URL. Sequence edges follow `--after`, or `--child` order.

`visualize` on a process-contract directory (`process-contract.json`, schema
`openadapt.process-contract/v0`) draws each independently admitted child
(name, `admission_id`) and the same kind of handoff edge.

Both parents end at a terminal titled End of declared steps, not Success.
Traversal ended. The parent is `VERIFIED` only when every child's receipt says
so.

The parent view doesn't inline a child's steps. Open the child bundle for its
program map. See
[Sequence work across two applications](../guides/compose-multi-application.md)
and [Process contracts](process-contract.md).

## Follow one live occurrence

The same program node can run more than once inside a loop. A useful live view
Expand Down
21 changes: 17 additions & 4 deletions docs/get-started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,23 @@ for the real environment.

## Where to go next

To compile several recordings, read
[Induce a program](../guides/induce-a-program.md). [Durable
runs](../concepts/durable-runtime.md) explains how an operator can resume from
the last verified checkpoint after a halt.
To compile several recordings of the same task, read
[Induce a program](../guides/induce-a-program.md). A task that starts in one
application and finishes in another is two recordings. Don't record them as
one. Sequence the compiled bundles with `compose`, or after each child is
admitted, with a process parent:

```bash
openadapt flow compose \
--child intake=./intake-bundle \
--child posting=./posting-bundle \
--handoff intake.patient_id=posting.patient_id \
--out composed
```

See [Sequence work across two applications](../guides/compose-multi-application.md).
[Durable runs](../concepts/durable-runtime.md) explains how an operator can
resume from the last verified checkpoint after a halt.

<div class="grid cards" markdown>

Expand Down
123 changes: 123 additions & 0 deletions docs/guides/compose-multi-application.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
description: >-
Record one program per application, sequence the compiled recordings with
compose, then after qualification and admission author a ProcessContract
parent.
---

# Sequence work across two applications

One recording binds one surface. If the work starts in a browser intake form
and finishes in a native posting app, record both.

`for-each` loops one bundle over a worklist. `induce` recovers a program from
several traces of the same task on the same backend. The two parents that
sequence work *across* surfaces are `compose` (compiled recordings) and
`process` (independently admitted capabilities).

## Record one program per surface

Record and compile each application the way you already do:

```bash
openadapt flow record --backend web --url https://intake.example --out rec-intake
openadapt flow compile rec-intake --out intake-bundle --name intake

openadapt flow record --backend windows --out rec-posting
openadapt flow compile rec-posting --out posting-bundle --name posting
```

Decide the handoff before you sequence anything. The parent will copy
`patient_id` only if intake's effect contract already bound it. A window title
isn't that fact. Compose won't retarget the intake recording onto the
posting surface.

## Sequence the recordings with compose

`openadapt flow compose` writes a parent directory of compiled children:

```bash
openadapt flow compose \
--child intake=./intake-bundle \
--child posting=./posting-bundle \
--handoff intake.patient_id=posting.patient_id \
--out composed
openadapt flow certify composed --policy clinical-write
openadapt flow run composed --config deploy.yaml
```

Default order is `--child` order. `--after NAME=PRED` declares a DAG; a cycle
is refused at authoring. Child B starts only after child A ends `VERIFIED`, or
a halt class you named with `--allow-halt NAME=OUTCOME`.

Handoffs copy parameter values that A's confirmed effect contract already
bound. Missing evidence stops the run. The parent won't guess a URL.

The on-disk form is `composed/composition.json` (schema
`openadapt.composition/v1`) plus `composed/children/<name>/`. Subflows and
worklists stay inside each child. `replay` refuses this directory:

```text
replay refuses a composition artifact; use `openadapt-flow run`
```

`visualize` on `composed` shows the child bundles, the handoff edges, and a
terminal labeled End of declared steps. Open `intake-bundle` if you need
intake's program graph.

```bash
openadapt flow visualize composed -o composed.html
openadapt flow visualize intake-bundle -o intake.html
```

Flags and the `certify` / `run` path are in the
[CLI reference](../reference/cli.md#compose).

## Qualify and admit each child

Compose sequences recordings. A ProcessContract parent will refuse those
copies. [Qualify each child](qualify-a-workflow.md) on its own surface, run
its counted campaign, and keep the signed
`openadapt.qualification-admission/v1` envelope. The envelope's
`admission_id` is a UUID. It is distinct from `runtime_validation_id`.

A recording you compiled five minutes ago and forgot to qualify is not a
process child.

## Sequence admitted capabilities with process

After both envelopes exist, author the process parent:

```bash
openadapt flow process \
--child intake=./intake-bundle \
--admission intake=./intake-admission.json \
--child posting=./posting-bundle \
--admission posting=./posting-admission.json \
--handoff intake.patient_id=posting.patient_id \
--out process-parent
openadapt flow visualize process-parent -o process.html
```

`--handoff`, `--after`, and `--allow-halt` have the same shape as `compose`.
`--child NAME=BUNDLE` is the admitted bundle. `--admission NAME=ENVELOPE` is
that child's signed `openadapt.qualification-admission/v1` file. A compose
child path under `composition.json` is not an envelope. The parent file is
`process-parent/process-contract.json`, schema
`openadapt.process-contract/v0`. It points at the envelopes. It doesn't copy
recordings. It doesn't become a ProgramGraph.

Pointing `process` at a `composition.json` directory is refused. That check is
what keeps unqualified recordings out of a process receipt.

Each child runs through [OpenAdapt Execute](../commercial/execute-api.md)
with that child's envelope, qualification binding, and its own idempotency
key. `replay` of the process parent is refused.

`visualize` on the process directory shows admitted children, handoff edges,
and End of declared steps. That label means the declared sequence ended. It
doesn't mean `VERIFIED`. Parent `VERIFIED` requires every child `VERIFIED`
and zero model calls.

Open the child bundle when you need its steps. The parent view won't inline
them.
5 changes: 5 additions & 0 deletions docs/guides/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ How-to guides for real deployments. Each assumes you have
Recover a parameterized program from several demonstrations, and run it
over a worklist.

- [__Sequence work across two applications__](compose-multi-application.md)

Record one program per surface, sequence the compiled recordings with
`compose`, then after admission author a ProcessContract parent.

- [__Write and enforce a policy__](policy-and-certification.md)

Use `lint` to find gaps and `certify` to refuse a bundle that violates the
Expand Down
Loading