Repository navigation
Conversation
) A subroutine is a typed signature (inputs, surface kind, entry and exit checks) plus a ProgramGraph body, identified by the SHA-256 of both. Workflows embed it under subroutine/<name>/<sha256>, wrapped so the existing interpreter halts when an entry or exit check does not hold. The library keeps versions, qualifications and registered users. Publishing a new version lists every workflow pinned to an older one, and admission refuses those uses until they are re-embedded and registered again. Admission also refuses unknown, unqualified or unregistered digests, edited embedded bodies, surface and input mismatches. Detection proposes recurring sequences by step shape only, never by labels or application names.
Independent adversarial review: BLOCKFrom: Codex Reviewed head
Independent WSL checks: the head passed 95 tests across |
What kind of change does this PR introduce?
New engine feature, first slice. Part of #1892. It does not close the issue.
Summary
Workflows repeat the same steps, such as searching for a record or picking a date. This PR adds the reusable unit for those steps and the gate that decides whether a workflow may use it. It touches no existing file.
New module:
packages/flow/openadapt_flow/subroutines.py.Subroutineis a typed signature plus aProgramGraphbody. The signature lists the inputs and their types, the surface kind, the entry checks and optional exit checks. At least one entry check must read the live screen. A parameter comparison, an absence check, OR or NOT does not count. A subroutine's identity is the SHA-256 of its signature and body, so any change makes a new subroutine.embed()puts the subroutine intoWorkflow.subflowsundersubroutine/<name>/<sha256>. It wraps the body in branches: the run halts if an entry check fails, and halts again if an exit check fails before returning. The existing interpreter runs these branches as they are, so the replayer is unchanged.SubroutineLibraryrecords each name's versions, which digests are qualified, and which workflows use which digest. When a new version is published, it returns every registered workflow still pinned to an older one. Those workflows are refused until they embed the new version and register again. Loading a library from JSON recomputes every digest, so an edited document is refused.admit_workflow()refuses each use with a stable code: unknown, superseded, not qualified, not registered, embedded body edited (including a bypassed entry check), surface not declared or wrong, multi-surface, or an input missing, mistyped, wider enum, or secret. Messages name subroutines, inputs and codes only, never screen text. A workflow with no subroutines passes this gate unchanged.mine_recurring_sequences()proposes candidates that recur in at least 2 workflows. It compares steps only by action kind, whether a parameter feeds the step, key chord and accessibility role. It never compares labels, names, selectors, URLs or application names. Candidates are alwaysadmitted=Falseandrunnable=False.Design notes:
packages/flow/docs/design/SUBROUTINES.md.How it was tested
tests/test_subroutines.py: 28 tests. They fail on base, because the module does not exist there. They cover:Replayerwith fake backend and vision: the body runs only when the entry check holds, and the run halts with no actions when it fails. A failing exit check halts after the body ran.validate_workflowaccepts an embedded workflowmypy(594 sources), engine generality, release consistency, source boundary, and the Python 3.10 syntax check.Not tested / not in this slice
flow qualifyand certification don't callregisteroradmit_workflowyet. That wiring is the next slice.Predicate. Once the IR: a small, safe expression language for data transforms between steps #1891 expression language lands, they should move to it.Checklist