That is the claim, and it is the kind of claim that sounds true whether or not it is. So the ladder on this site was built a second time on Google Cloud and the difference was counted rather than described. Most of it held. One part did not, and the part that did not was ours.
Lines, counted after the port rather than estimated before it.
narrator/prompt.py, which hold the prompt
moved out of core.py rather than new text: the same strings, the retry hint renamed
from private to public, and the user message wrapped in a function.Each row says what changed: the name only, the code, or the behaviour. Those three get collapsed into one word in most migration stories, and that is exactly where a slogan hides.
| step | on AWS | on Google | what changed |
|---|---|---|---|
| draft | Bedrock, Claude Haiku 4.5 | Vertex, Gemini 2.5 Flash | code The SDK call and the usage record: 66 lines. The prompt, the retry hint and the message shape are one file, imported by both. |
| the gate | Lambda | Cloud Run | name only The module that recomputes every quoted figure is imported unchanged by both clouds. A test asserts it by module path, not by comparing text. |
| the human | Step Functions, waitForTaskToken | Workflows, await_callback | behaviour Same shape, different default: the callback wait defaults to 12 hours and is set explicitly here. The ceiling is one year on both. |
| the journal | DynamoDB | Firestore | code 44 lines. The record keeps the same field names, so a run from either cloud reads the same way. |
| publication | S3 | Cloud Storage | code 28 lines. The object key is built the same way. |
| logs and cost | CloudWatch | Cloud Logging | not measured Written, not yet run on Google, so this row has no number on the right-hand side. |
| the judge | ours | ours | nothing Google's Gen AI evaluation service is the managed equivalent. It is named here as the thing we did not need, not as something we ran. |
The second cloud could not read the first one’s prompt without installing Amazon’s SDK.
The narrator package imported, at module load, a file that builds a Bedrock client. So any runtime that merely wanted to ask the same question of a different model had to carry a client for a service it would never call. Nothing about that is Google’s doing, and nothing about it was visible until something tried to leave.
The fix
was small: the contract moved into a file with no imports beyond json, and the
package now loads its client on demand. Both narrators import that one file, so the two clouds ask the
model the same question by construction rather than by inspection. That is what the twenty-five added
lines bought.
The general form is worth more than the fix. A system is portable in the places where it was never allowed to assume, and a vendor’s SDK imported at the top of a file is an assumption that costs nothing until the day it costs a rewrite. Ours cost twenty-five lines because the thing underneath was already separated. It is not always twenty-five.
One side has run many times. The other has not run at all yet, and this page says so rather than leaving the column to look full.
What would fill the right-hand column. A project, a billing link and one deploy. The stand is designed to go up, run once, record its receipts and come down again: a second cloud kept running for the sake of a demonstration costs money every month and attention every time it drifts, and what this page needs is a recorded run rather than a live address.