Cefalo × Aqua Robotics — Platform & ML Infrastructure
The bill got smaller. The system got better.
Between January and early August 2026, I rebuilt the platform's three most expensive systems — Airflow, the EMR/Spark inference pipeline, and SageMaker training — around scale-to-zero, spot capacity, and Fargate, while pushing Claude Code from an editor plugin into the team's default way of shipping: Jira-to-PRD automation, automated PR review, and standardized testing across nine repositories.
Exhibit — aws-sagemaker daily training spend
Real AWS Cost Explorer data. Hover a bar for its date and cost.
Financial impact
Four separate levers, four separate units — a monthly infra bill, a per-run pipeline cost, a per-task-hour rate, and a risk eliminated from a single training job. Each figure below is sourced from a repo README, a written cost-audit plan, or a specific commit — not a blended estimate. Confidence is labeled per card.
Airflow platform — EKS → ECS Fargate + Aurora Serverless v2
airflow-pipelineidle cost, always-on cluster vs. scale-to-zero
PER YEAR≈ $1,450/yr saved — daily DAG, documented monthly figures × 12
Documented — README.mdRetired the always-on EKS deployment for a green-field rebuild on ECS Fargate + Aurora Serverless v2. An EventBridge-scheduled wakeup/shutdown chain scales all four services (api-server, scheduler, dag-processor, triggerer) to zero between DAG runs.
GPU image-inference pipeline (EMR + Spark)
spark-application~$111/mo baseline, five-point optimization plan
GPU inference (Stage 2) was already 84% efficient, but Stages 1 and 3
burned full EMR clusters on sub-3-minute jobs — moving both to Fargate.
The GPU fleet itself already runs on Spot: g5.2xlarge
on-demand is $1.29/hr in eu-north-1 vs. ~$0.48/hr current spot (~63%
cheaper) — alone worth ~$1.65/run before the plan above.
PER YEAR≈ $164/yr from the plan ($0.45/run × 365) + ~$1.65/run already banked from Spot
Documented — optimization-plan.mdAnalyzer shard-worker — Fargate → Fargate Spot
image_preparationdataset-quality-analyzer
~74% reduction, on top of a prior 12% right-size
Right-sized the task (16 GB → 12 GB), then moved it to Fargate Spot. Added a SIGTERM handler that flushes partial CSV progress to S3 within the 2-minute spot-interruption window, so the discount doesn't cost re-run risk.
AT SCALEper 1,000 task-hrs: $148 → $44 (manually triggered per dataset — no fixed $/yr is documented)
Documented — migration planSageMaker training — runaway-job cost
aws-sagemakeractual AWS bill for one stuck run, vs. the post-fix baseline
A dataloader-iteration bug let distributed jobs run for days instead of
~24 hours — see the exhibit above. Fixed the iteration logic and capped
max_run/max_wait to
86400s (24hr), bounding the cost of any future stall.
TO DATE$268.46 avoided across the 2 documented stuck runs — a one-time cap, not a recurring cost
Documented — AWS Cost ExplorerArchitecture decisions
The same four initiatives, expanded — what was wrong, what changed, and what it bought.
Airflow: off EKS, onto scale-to-zero Fargate +
- Problem
- Airflow ran on EKS as an always-on cluster, billed 24/7 for a DAG that runs a few hours a day.
- Decision
- Rebuilt on ECS Fargate (api-server, scheduler, dag-processor, triggerer as four services on one cluster) with Aurora Serverless v2 for metadata, discovered via Cloud Map instead of an always-on ALB. An EventBridge Scheduler → Lambda chain wakes the services before the scheduled DAG run and a shutdown Lambda, invoked as the DAG's last task, scales back to zero. UI access moved to on-demand SSM port-forwarding.
- Impact
- ~$125/mo → ~$3–5/mo idle; a full DAG run costs ~$3–5. Per-service breakdown in the scale-to-zero plan: webserver $18→$2.25, scheduler $12→$1.50, triggerer $10→$1.25, ALB $18→~$0.
GPU inference: spot capacity without spot risk +
- Problem
- The 3-stage image-inference pipeline ran every stage on full EMR clusters, even the two short (<3 min) stages where 68–84% of wall-clock was cluster bootstrap, not work.
- Decision
- Keep EMR only where it earns its keep: the GPU inference stage, on a g5.2xlarge fleet with a 100%-spot task fleet (
price-capacity-optimizedallocation, diversified instance types after an April spot-capacity stall). Move the short frame-extraction and package-export stages to Fargate. Checkpoint the GPU stage at the strip level so a spot interruption resumes instead of restarting, and shift the run to off-peak hours for cheaper spot pricing. - Impact
- Documented baseline ~$3.71/run (~$111/mo) → projected ~$3.26/run (~$164/yr on the daily DAG), ~11 minutes faster, with each spot interruption now costing a resume instead of a re-run (avoids doubling a day's cost on failure). On-demand vs. spot pricing for the GPU fleet itself, checked live:
g5.2xlargeon-demand is $1.29/hr in eu-north-1 against a current spot price of ~$0.48/hr — a ~63% discount that alone saves ~$1.65 of the $3.71 baseline, independent of the five optimizations above.
Data-quality analyzer: right-size, then go spot +
- Problem
- The analyzer shard-worker ran on-demand Fargate, over-provisioned at 16 GB per task.
- Decision
- Right-sized the task to 12 GB first (a safe ~12% cut with no capacity risk), then migrated to Fargate Spot. Since spot gives a 2-minute interruption warning, added a SIGTERM handler that flushes partial progress to S3 before the task dies, so the cheaper capacity doesn't cost re-processing. Also extracted the analyzer into its own repo and is moving its orchestration off ad-hoc EventBridge/Lambda triggers onto Airflow DAGs (in progress).
- Impact
- ~$0.148/task-hr → ~$0.044/task-hr, a combined ~74% reduction from the original on-demand, over-provisioned baseline.
SageMaker: capping the cost of a stuck job +
- Problem
- A dataloader-iteration bug meant a stalled distributed training run had nowhere to stop except SageMaker's configured ceiling — set to 345,600 seconds (96 hours). Pulling the actual AWS bill:
experiment-50-attempt-7(4×ml.g5.2xlargespot) ran 55 hours before finishing on its own and billed $153.29; a prior attempt (attempt-5, 2 instances) had to be killed manually after running 96 hours straight into the ceiling, billing $115.17. - Decision
- Fixed the dataloader iteration logic (commit
32d495d) and cutmax_run/max_waitto 86,400 seconds (24 hours) — the actual time a healthy run needs. Backed training with spot GPU instances and DynamoDB-based checkpoint resumption so spot interruption doesn't cost progress either. Later added an EventBridge Scheduler → Lambda → GitHub Actions chain for scheduled/on-demand runs, and an ECS Fargate step to export completed models from PyTorch to TorchScript. - Impact
- Confirmed post-fix baseline: 30-epoch run ≈ 24hr ≈ $15 (Jira, Jan 1 2026). Against the $153.29 stuck run that motivated the fix, that's roughly a 10x reduction per incident — and the 96→24hr cap now bounds the cost of any future stall outright.
Engineering practice
Cost work is one axis; the other is how the team ships. Made Claude Code the default path from a Jira ticket to a merged, tested, reviewed PR across nine repositories.
| Skill | Repo | What it does |
|---|---|---|
| jira-plan | infra-module | Reads an NDSW ticket, writes a scoped <TICKET>-PRD.md against the actual codebase — the Jira-to-implementation-plan step. |
| jira-create | infra-module | Drafts and files new NDSW tickets from a described bug or feature. |
| promote-lambda | infra-module | Promotes a Lambda through qa → stage → main via infra-live merges, and comments on the originating Jira ticket. |
| audit-lambda | infra-module | Code-quality audit of a Lambda against team conventions. |
| write-lambda-tests | infra-module | Backfills pytest coverage for a Lambda. |
| find-layer-usage | infra-module | Traces shared-layer usage across the Lambda fleet before a refactor. |
| generate-readme | infra-module | Generates/refreshes a Lambda's README from its actual code. |
| update-lambda | infra-module | Implements a scoped code/config/layer change to a Lambda. |
| execute-api | infra-module | Executes an API implementation plan end to end. |
| emr-debug | spark-application | Diagnoses an EMR step/cluster failure from its ID by pulling and root-causing AWS logs. |
| session-handoff | repo-wide (9 repos) | Standardized end-of-session handoff summary — adopted as a convention across every active repo. |
Guardrail hooks
block-dangerous-commands.sh blocks destructive Bash
before it runs; pre-bash.sh blocks a prod deploy
push unless explicitly overridden; lint-python.sh
auto-lints on every edit. Deployed across
infra-module and spark-application.
Automated review & testing in CI
Shipped claude-pr-review.yml — every PR
gets an automated Claude Code review once CI passes, re-triggerable with an
@claude comment, running Sonnet 5 at xhigh effort.
Paired with the Python 3.10 → 3.12 runtime migration across the Lambda
fleet, backfilling pytest coverage per family as each migrated.
FinOps visibility
Operate an AWS FinOps tool that posts daily cost visibility straight to Slack, and are now formally auditing ECS task costs — the natural next line item after the Fargate and EMR work above.
Timeline
Month-by-month record (Jan–Aug 2026) — expand
aws-sagemaker
infra-module
spark-application
spark-application
airflow-pipeline
airflow-pipeline
airflow-pipeline
airflow-pipeline
airflow-pipeline
aws-sagemaker
aws-sagemaker
infra-module · spark-application
airflow-pipeline
infra-module
image_preparation
dataset-quality-analyzer — in progress
Notes
Confidence key
Sources
- Git history across 9 repositories (airflow-pipeline, spark-application, infra-module, infra-live, aws-sagemaker, image_preparation, dataset-quality-analyzer, lambda-layers, model-validation) — ~530 commits authored Jan 1–Aug 7, 2026.
- Jira project NDSW ("Net Documentation System Workflow") — issues referenced above cross-checked against ticket status and comments.
- Repo documentation: airflow-pipeline/README.md, airflow-pipeline/plans/airflow-ecs-scale-to-zero.md, airflow-pipeline/plans/optimization-plan.md, image_preparation/FARGATE_SPOT_MIGRATION_PLAN.md.
- AWS Cost Explorer (SageMaker training-job billing, Nov 2025–Jan 2026) and sagemaker:DescribeTrainingJob — cross-referenced against instance count and billable seconds per run to attribute the $153.29 and $115.17 figures to specific training jobs, and to chart the daily spend exhibit in the hero.
- AWS Price List API (on-demand g5.2xlarge, EU Stockholm) and live EC2 spot price history (eu-north-1) — checked 2026-08-08, used for the GPU on-demand-vs-spot comparison.
Scope
- Limited to Cefalo client work authored under moniruzzaman@cefalo.com. A personal side project under a separate identity was excluded as out of scope for a client-impact report.