Skip to content

feat(0133): write-amplification probe + alarm (0132 guardrail) - #156

Merged
karczuRF merged 3 commits into
developfrom
feat/0133_live-pipeline-egress-write-volume-alarm
Jul 29, 2026
Merged

feat(0133): write-amplification probe + alarm (0132 guardrail)#156
karczuRF merged 3 commits into
developfrom
feat/0133_live-pipeline-egress-write-volume-alarm

Conversation

@karczuRF

@karczuRF karczuRF commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • The guardrail for task 0132. Nothing watched write volume, so a 9,413× asset re-emit bled ~$337/mo of egress undetected for weeks. This adds an hourly probe + CloudWatch alarm so the next amplification hits Slack (#stellar-prices-api-bot), not a bill.
  • New crate write-amplification-probe (mirrors the 0056 probe pattern): a scheduled Lambda reads rows-written-per-hour per prices.* table from system.part_log and republishes the max as the Prices/Ingest MaxRowsWrittenPerHour CloudWatch metric.
  • Alarm fires on a sustained 3-hour breach of config.opsAlarms.writeAmplificationRowsPerHour → existing 0056 SNS topic → Slack. OkAction set; missing data non-breaching (probe-down covered by its own -errors alarm).
  • Threshold set from data, not a guess (default 50M): a 14-day system.part_log measurement showed the highest sustained legit load is ~16M rows/hour (a backfill day), while one-hour bulk spikes reach ~154M but clear within the 3-hour window; 0132 ran ~130M/hour for days. 50M sits ~3× above sustained legit, ~2.6× below the runaway.
  • Infra: EventBridge rate(1h) rule + createWorkerLambda + PutMetricData scoped to Prices/Ingest; schedule + threshold in types.ts / envs/production.json.
  • Design note: absolute rows/hour + sustained window rather than a written÷real ratio; the ratio (legit bulk ~1×, re-emit high) is a documented future enhancement.

Verification

  • 4 unit tests pass; clippy clean; arm64 bootstrap builds.
  • Infra tsc build + full cdk synth pass; probe function, EventBridge rule, and the alarm (threshold 50M, 3-hour sustained, GreaterThanThreshold, notBreaching) all confirmed in the synthesized CloudFormation.

karczuRF added 3 commits July 29, 2026 14:15
The guardrail for task 0132: nothing watched write volume, so a 9,413x
asset re-emit bled ~$337/mo of egress undetected for weeks. This adds an
hourly probe + alarm so the next amplification hits Slack, not a bill.

New crate write-amplification-probe (mirrors the 0056 probe pattern): a
scheduled Lambda reads rows-written-per-hour per prices table from
system.part_log (as prices_reader) and republishes the max as the
Prices/Ingest MaxRowsWrittenPerHour CloudWatch metric. A CloudWatch alarm
fires when it exceeds config.opsAlarms.writeAmplificationRowsPerHour
(default 10M — the busiest legit table is <1M/h, 0132 was ~130M/h) → the
existing 0056 SNS topic → Slack.

Infra: EventBridge rate(1h) rule + createWorkerLambda on the api/reader
mTLS bundle + PutMetricData scoped to Prices/Ingest; observability alarm
with OkAction; schedule + threshold in types.ts and production.json.

Absolute rows/hour rather than a written/real ratio: prices_reader is
granted only system.part_log (+ prices.*), not system.parts, and an
absolute guardrail with wide margin is sufficient; a true ratio is a
documented future enhancement.

Deploy prerequisite (one-time, admin): GRANT SELECT ON system.part_log TO
prices_reader.

Verified: 4 unit tests, clippy clean, arm64 bootstrap builds, infra tsc
build + full cdk synth pass; probe/alarm/IAM confirmed in synthesized CFN.
…on alarm

Finding 1 (false-positive on legit bulk loads): system.part_log counts ALL
writes to prices.* — including the 0088 backfill, coarse pre-rolls, and
enrichment bursts — which an absolute row count cannot distinguish from a
re-emit amplification. Mitigate: require a sustained 3-hour breach (a 0132
runaway persists for weeks; legit bulk is bursty) and document the threshold
as operator-tunable / ack-able during known heavy loads. The threshold still
needs empirical validation against real backfill/pre-roll peaks (noted); a
written-vs-real ratio is the robust future fix.

Finding 2: alarm evaluationPeriods/datapointsToAlarm 1 -> 3 (sustained, not a
lone anomalous hour).

Finding 3: the 1h window was coupled across the SQL query, the schedule, and
the alarm period with no link — add WINDOW_HOURS + explicit coupling notes.

Finding 4: remove the unused thiserror dependency (copy-paste).

Verified: 4 tests pass, clippy clean (all features), infra tsc build + full
cdk synth pass; sustained-breach (eval/datapoints=3) confirmed in the CFN.
…log measurement

Finding 1 follow-up. A 14-day system.part_log measurement proved the absolute
threshold could not be a guess: a legit one-hour price_ohlcv_15m_bak copy (07-17
rollup rework) wrote 154M rows/hour — HIGHER than the 0132 bug's ~130M — so no
absolute value separates legit from amplification. The discriminator is duration:
the _bak spike was one hour; the highest sustained legit load is price_ohlcv_1m at
~16M/hour (07-26 backfill day, ~18h); 0132 ran ~130M/hour for days.

Set the threshold to 50M (was a guessed 10M): ~3x above the ~16M sustained legit
peak, ~2.6x below the ~130M bug. Combined with the existing 3-hour sustained
window (which clears the one-hour spikes), no legit event in the measured window
breaches it for 3 sustained hours, while a 0132-class runaway still does.

Verified: infra tsc build + full cdk synth pass; threshold 50M / eval 3 /
datapoints 3 confirmed in the synthesized CFN.
@karczuRF
karczuRF merged commit 5add848 into develop Jul 29, 2026
3 checks passed
@karczuRF
karczuRF deleted the feat/0133_live-pipeline-egress-write-volume-alarm branch July 29, 2026 13:02
karczuRF added a commit that referenced this pull request Jul 29, 2026
#157)

* Revert "feat(0133): write-amplification probe + alarm (0132 guardrail) (#156)"

This reverts commit 5add848.

* docs(lore-0133): complete + archive — BE owns the guardrail (shared-infra alarm)

After the BE response the approach changed: instead of a prices-owned
write-amplification probe, BE will cover this at the shared-infra layer with a
transfer-cost alarm they own. That meets the task goal (the next amplification
hits an alarm, not a bill) without a prices-owned probe or the system.part_log
grant that the prices CH users (XML-managed in BE's users_xml, readonly to SQL)
could not receive without a BE services.xml change.

PR #156's code is reverted in this branch (unused). Task marked completed and
moved to archive with a Resolution note; the design + measured threshold are
retained for the record.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant