Summary
Federation and the flow stores disagree, in two directions. Both were found live on a dev instance running development at 1.1.5-unstable.20260827012918, and both report success while doing nothing.
1. federated-config/install returns a uuid for a flow that does not exist
POST /api/federated-config/install { type: openregister.flows, bundle, source: ConductionNL/flow-pack }
→ HTTP 200 {"installed":["af100293-801e-45b3-bed6-ab19ee2e27a8"]}
That uuid exists nowhere. Confirmed three independent ways:
GET /api/flows?_limit=1000 → 72 flows, af100293… not among them
GET /api/flows/af100293-… → HTTP 404 {"error":"No such flow"}
POST /api/flow-runs/test {flowId} → HTTP 404 {"error":"No such flow: af100293-…"}
It is not in the flows register either (2 objects, neither is it).
This is the worst shape a bug can take: the caller is handed an identifier, HTTP 200, and an installed array of length 1. Nothing about that response suggests the flow was not persisted. A consumer installing a flow pack gets a receipt for goods that were never delivered, and only discovers it when something tries to run the flow.
2. A flow authored in the flows register cannot be bundled
OpenRegister has two stores for "a flow":
| store |
written by |
read by |
openregister_flows table |
POST /api/flows |
FlowMapper, and so FlowShareableConfigType |
objects in the flows register |
POST /api/objects/{reg}/{sch} |
the resolver |
FlowShareableConfigType bundles via FlowMapper, so it reads only the first. Bundling a register-authored flow returns an empty set with HTTP 200:
POST /api/federated-config/bundle {flowIds: ["628a655b-…"]} (register-authored)
→ HTTP 200 {"type":"openregister.flows","version":"1.0","flows":[]}
Verified with a control — the same request for a table-backed flow returns 1:
POST /api/federated-config/bundle {flowIds: ["7f9ea270-…"]} (via /api/flows)
→ HTTP 200 {"flows":[{"name":"…","nodes":[…]}]}
This matters because the register is a documented place for a flow to live. lib/Settings/flow_register.json describes itself as "the store the resolver reads by default … so triggers, sub-flows and the /test endpoint all work with a flow authored here." A flow authored exactly as documented silently cannot be shared, and the empty bundle carries no hint that the store was the problem.
Why it went unnoticed
federated-config.spec.ts covers this path, but the whole file was dead: its beforeAll resolves a flows register that had never been seeded on the instance, so every test in the file errored before reaching an assertion. Once the register was imported (see #2903), the file ran and both defects surfaced within two assertions of each other.
Two further fixture problems had to be cleared first, both stale against the current flow grammar:
makeFlow() hung type + config off an edge. The validator refuses that outright — "a node is the action that runs and an edge is sequence, so nothing reads this step" — so the flow was never created and the failure surfaced later as flows.length === 0, reading exactly like a broken bundler. Fixed by moving the step onto a node.
- The fixture then authored into the register, which is symptom 2 above. Pointed at
/api/flows so the bundling test tests bundling.
Symptom 1 is what remains red after both fixture fixes, and it is a product defect, not a test one.
Suggested direction
Not prescribing the fix, but the shape of the question: either the two stores become one, or every federation path names which store it operates on and refuses — loudly — when handed an id from the other. What must not survive is an install that returns an id for nothing.
Summary
Federation and the flow stores disagree, in two directions. Both were found live on a dev instance running
developmentat1.1.5-unstable.20260827012918, and both report success while doing nothing.1.
federated-config/installreturns a uuid for a flow that does not existThat uuid exists nowhere. Confirmed three independent ways:
It is not in the
flowsregister either (2 objects, neither is it).This is the worst shape a bug can take: the caller is handed an identifier, HTTP 200, and an
installedarray of length 1. Nothing about that response suggests the flow was not persisted. A consumer installing a flow pack gets a receipt for goods that were never delivered, and only discovers it when something tries to run the flow.2. A flow authored in the
flowsregister cannot be bundledOpenRegister has two stores for "a flow":
openregister_flowstablePOST /api/flowsFlowMapper, and soFlowShareableConfigTypeflowsregisterPOST /api/objects/{reg}/{sch}FlowShareableConfigTypebundles viaFlowMapper, so it reads only the first. Bundling a register-authored flow returns an empty set with HTTP 200:Verified with a control — the same request for a table-backed flow returns 1:
This matters because the register is a documented place for a flow to live.
lib/Settings/flow_register.jsondescribes itself as "the store the resolver reads by default … so triggers, sub-flows and the /test endpoint all work with a flow authored here." A flow authored exactly as documented silently cannot be shared, and the empty bundle carries no hint that the store was the problem.Why it went unnoticed
federated-config.spec.tscovers this path, but the whole file was dead: itsbeforeAllresolves aflowsregister that had never been seeded on the instance, so every test in the file errored before reaching an assertion. Once the register was imported (see #2903), the file ran and both defects surfaced within two assertions of each other.Two further fixture problems had to be cleared first, both stale against the current flow grammar:
makeFlow()hungtype+configoff an edge. The validator refuses that outright — "a node is the action that runs and an edge is sequence, so nothing reads this step" — so the flow was never created and the failure surfaced later asflows.length === 0, reading exactly like a broken bundler. Fixed by moving the step onto a node./api/flowsso the bundling test tests bundling.Symptom 1 is what remains red after both fixture fixes, and it is a product defect, not a test one.
Suggested direction
Not prescribing the fix, but the shape of the question: either the two stores become one, or every federation path names which store it operates on and refuses — loudly — when handed an id from the other. What must not survive is an
installthat returns an id for nothing.