- SDKs & APIs
- Push Conformance
Push Conformance
ironflow conformance push checks a push endpoint against the
push protocol. It sends the requests the engine sends, and
it checks each answer. It needs no Ironflow server. Use it when you write a push
handler in a language that has no Ironflow SDK.
A language is supported for push mode when its handler passes every check at level 3 (ADR 0079).
Host the fixture functions
Section titled “Host the fixture functions”The suite cannot know what your own functions return. Your endpoint must therefore host four fixture functions with the exact behavior below. Register them next to your real functions, or in a test build of your service.
Each step returns a fixed JSON object. The suite plants different outputs in
steps, so it can see whether your handler replayed a step or ran it again.
conformance-echo (level 1)
Section titled “conformance-echo (level 1)”No steps. Return the run fields you received:
return { run_id, function_id, attempt, data: event.data }Return event.data unchanged. It can contain HTML characters such as <, >
and &. Sign and verify the raw request bytes, not a re-serialized body.
conformance-fail (level 1)
Section titled “conformance-fail (level 1)”No steps. Fail without retry. Answer HTTP 200 with status: "failed",
error.message set to event.data.message, and error.retryable: false.
conformance-steps (level 2)
Section titled “conformance-steps (level 2)”o1 = step.run("plain") -> {"s":"plain#1"}o2 = step.run("plain") -> {"s":"plain#2"}o3 = step.run("a:b\c") -> {"s":"escaped"}[b0, b1] = parallel("fan:out", [ branch 0: step.run("leaf") -> {"s":"leaf-0-0"}, then step.run("leaf") -> {"s":"leaf-0-1"} branch 1: step.run("leaf") -> {"s":"leaf-1-0"}])return [o1, o2, o3, b0, b1]A branch returns the output of its last step. For run R, the step IDs must be:
R:plain:0R:plain:1R:a\:b\\c:0R:fan\:out:0:leaf:0R:fan\:out:0:leaf:1R:fan\:out:1:leaf:0conformance-sleep (level 3)
Section titled “conformance-sleep (level 3)”before = step.run("before") -> {"s":"before"}step.sleep("nap", 1 hour)after = step.run("after") -> {"s":"after"}return [before, after]Run the suite
Section titled “Run the suite”ironflow conformance push --url http://localhost:8080/ironflow --signing-key $KEYBuild in levels, as the any-language guide recommends:
| Level | Checks | Fixtures needed |
|---|---|---|
| 1 | 405 for GET, 404 for an unknown function, unknown fields ignored, echo, failure encoding, signatures | conformance-echo, conformance-fail |
| 2 | Step IDs and escaping, parallel scopes, memo replay, delta-only steps, failed memo entries, stable IDs across attempts | adds conformance-steps |
| 3 | Sleep yield and resume | adds conformance-sleep |
Pass --level 1 until level 1 passes. Without --signing-key, the signature
checks are skipped. The flag reads IRONFLOW_SIGNING_KEY when you do not set it.
Each request has a 10-second limit. Change it with --timeout, for example --timeout 30s.
Read the report
Section titled “Read the report”PASS L1 transport.method-not-allowedFAIL L2 steps.full-replay delta step IDs want: (none) got: run_conf_x:plain:0 run_conf_x:plain:1 contract: https://docs.ironflow.run/reference/api/push-protocol/#memoization-rulesEach failure shows what the suite expected, what your endpoint sent, and the
rule on the push protocol page. Add --json for a report that a CI job can
read. Exit code 0 means that no check failed. The
CLI reference lists the other exit codes.
The suite is stricter than the engine in a few places. The engine accepts these step results, and the suite fails them:
- A step result with no
id - A step result with an empty
name - A
statusother thancompletedorfailed - A step result in
stepsthat is notcompleted, or that has a wrongoutput - A
typeother thaninvokeforstep.run
The engine makes up an ID for a step result that has none. Your handler cannot compute that ID, so the next replay runs the step again.
What the suite does not check
Section titled “What the suite does not check”wait_for_event,invoke_functionandinvoke_function_asyncyields- The
compensate:andpublish:step-name prefixes - The capacity fencing headers (
Ironflow-Execution-Seq,Ironflow-Lease-*) secretsand trace headersstarted_atandended_aton step results- Constant-time signature comparison. Timing is not visible from outside your handler. Use a constant-time compare anyway.