Language: English
In a Port, the Most Dangerous Thing Is a Plausible-Looking Value
While porting an AI generation pipeline to another workflow platform, several plausible-looking configuration values — thresholds, model names, external endpoint paths — turned out to diverge from the source system. A retrospective of those issues, along with the verification steps that would have caught them.
We ported an existing AI generation flow to a different workflow platform. It’s a pipeline covering image generation, video generation, subtitles, all the way to rendering.
What ate the time wasn’t rewriting the implementation. It was verifying what the source system’s configuration values actually were.
Threshold Drift
The set of thresholds in the destination didn’t match the source values.
Exporting the source workflow definition and extracting the real values showed that nearly all of the current settings were different. Apparently they had been left in place as placeholder “seems reasonable” values from the start.
| Parameter | Source | Destination setting |
|---|---|---|
| artifact_segarea_threshold | 20 | 64 |
| boundary_margin_threshold | 20 | 12 |
| dilate_kernel_size | 20 | 6 |
| padding_size | 50 | 10 |
| polygon_outline_width | 50 | 2 |
| popup_weight / spot_weight | 0.4 / 0.6 | 0.6 / 0.4 |
| resize_rate | 1 | 0.5 |
artifact_segarea_threshold sitting at 64 was the direct cause of the gate failing twice in a row.
popup_weight and spot_weight had their values swapped.
None of these values looks wrong in isolation. Whether 0.4 or 0.6 is correct can’t be determined by reading the code. Until we looked at the source definitions, there was no way to notice they were wrong.
We also found three parameters that existed in the source but had no corresponding processing in the destination. For those, rather than setting something plausible, we left comments noting that there was no corresponding place for them.
Verifying Model Names
The same problem came up with model specifications.
One of the gates failed with provider_rejected.
Reproducing against the real API returned this:
400 invalid_request_error
"Unrecognized request argument supplied: reasoning_effort"
The caller was sending reasoning_effort on every gate, but the specified model doesn’t accept that parameter.
Checking the source showed that the model actually in use was a different one, and there reasoning_effort does get sent.
In other words, the reasoning_effort side was correct, and it was the model name that was a guess.
At another gate, carrying the source’s model name over verbatim produced a 404.
"This model models/gemini-2.5-pro is no longer available to new users"
The source could call it under existing-user treatment, but with this project’s API key we counted as new users and couldn’t call it. A case where the literal simply cannot be ported as-is. We tested replacement candidates against the actual schema and actual images, and swapped in ones that worked.
What the Endpoints Actually Are
Text segmentation started returning 404. A comment in the configuration said that a certain service provided both detection and segmentation.
Fetching /openapi.json showed that the service only exposed detection paths.
Segmentation lived in a separate service in a different region — which also matched the source environment’s configuration.
It then returned 403, so we investigated: segmentation ran under a service account separate from detection’s, and it wasn’t among the three accounts granted read access to the artifact bucket.
The comment and the configuration may both have been accurate when written. But when running in the destination, the only thing you can trust is what the actual endpoints return.
Pre-Port Verification Steps
Looking back, everything that tripped us up had the same shape: places where we filled in plausible-looking values without verifying against the source.
Thresholds, model names, endpoint paths, environment specification. None of these can be judged right or wrong just by reading. And even when wrong, they usually surface not as errors but as “the output looks off.” Gates fail; the quality of the output changes. Getting to the root cause takes a long time.
When porting, start by exporting the source definitions to establish ground truth.
Parameters with no corresponding handling: leave them unmapped instead of inventing values.
Verify external service paths for real via /openapi.json and the like.
Hit model names for real and confirm they return 200.
Doing these four things up front would have eliminated most of the debugging.
Separately, the pitfalls unrelated to the source that came from the runtime environment itself are written up in What I Stepped On in the Destination Runtime Environment.