← all branches

feat/hoymiles

needs attention
4de48f3 · fullPR #272reviewed 2026-07-08 02:23 UTC5H · 8M · 9L · 4I
The branch
Purpose
Port the Hoymiles solar integration (largest legacy fleet, 311 devices) to the v2 metrics engine at 5m/15m native granularity, replacing the legacy 15m→3×5m triplication and curve-smearing.
Goal
Production-ready Hoymiles metrics + connection workers with CDK stack, live-validated against 3 representative sites in the branch preview.
Sub-goals
  • SG-1: API probe + worker package (metrics + connection + translation); 60 unit tests
  • SG-2: CDK IntegrationHoymilesLambdaStack + main.ts + coordinator grants
  • SG-3: Preview data plane (catalog seed, D2 secrets, snapshot-scoped D3, ARN seed)
  • SG-4: Live Site-SFN validation + Tinybird + parity vs prod-ddb
  • SG-N: Framework learnings #12–#20 → scope.md; hoymiles Tier-3 → integrations CLAUDE.md
The changes (whole branch)
What
New Hoymiles worker package (metrics.lambda.ts + connection.lambda.ts + points-to-batu.ts translation layer + hoymiles-client.ts); CDK stack (IntegrationHoymilesLambdaStack, 120s/512MB metrics + 30s/256MB connection, IAM scoped to GetSecretValue {env}/hoymiles/*); hoymiles manifest (api_key credential, ['5m','15m','1d'] solar, ['1d'] grid); migration scripts (seed-migration-sites.ts); framework learnings documentation.
Why
Hoymiles is the largest fleet (311 devices) of the 12 legacy brand ports. This is the second port (after victron) and validates the end-to-end recipe for the remaining 10 brands.
Areas
services/metrics/integrations/hoymiles/+11000infra/cdk/src/stacks/services/metrics/integrations/hoymiles/+1500packages/integration-manifests/src/manifests/+600scripts/metrics/+800infra/cdk/src/app/main.ts + coordinator+250.branch/ (scope, intent, tools)+4000
Blast
29 files in feat/hoymiles itself (stacked on feat/int-base #268); new Lambda stack; seeds for hoymiles only. The 12-manifest and seed changes are on the base branch.
stacked-on-feat-int-base live-validated billing-critical-translation-helpers-shared
CI checks· No GitHub Actions checks visible on this PRunit tests (declared)· 60 unit tests; typecheck/lint green per PR descriptionlive SFN validation· 1,166 Tinybird points; grid 6/6 exact (Δ≤0.0002%); cadence guard proven liveCodeRabbit· No .coderabbit.yaml present

Findings · 27

correctness7

high

Credential field drift: seed stores 'token', worker reads 'api_key'

packages/database/src/seed-metrics-catalog.ts:159

FE wizard onboarding stores key under 'token'; worker reads parsed['api_key'] → MissingSecret on every collection. Fix: change name to 'api_key' in the DB seed row.

medium

Retention pre-check off-by-one: allows the 16th day back (not 15)

services/metrics/integrations/hoymiles/src/handlers/metrics.lambda.ts:169

medium

probeFailurePayload: credentialValid:false for transient failures (timeout, rate-limit)

services/metrics/integrations/hoymiles/src/handlers/connection.lambda.ts:97

medium

Cadence detection skips mismatch when every day has ≤1 point

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts:248

low

gpw bogus-plant: reachable:true even when defaultLooking is set

services/metrics/integrations/hoymiles/src/handlers/connection.lambda.ts:119

low

Single per-day fetch failure aborts entire multi-day intraday window

services/metrics/integrations/hoymiles/src/handlers/metrics.lambda.ts:203

low

Cadence tie-breaking non-deterministic at the pooled-day level

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts:251

security3

medium

API key sent as URL query param — logged by HTTP infrastructure

services/metrics/integrations/hoymiles/src/engine/hoymiles-client.ts:61

low

IAM wildcard {env}/hoymiles/* also covers the /portal/ credential path

infra/cdk/src/stacks/services/metrics/integrations/hoymiles/iam.ts:43

low

copy-legacy-secrets.ts: error messages may partially expose secret-adjacent data

scripts/metrics/copy-legacy-secrets.ts:128

conventions3

medium

externalVariableId carries legacy vendor channel names, not canonical keys

packages/integration-manifests/src/manifests/hoymiles.ts:53

info

INTEGRATION_STANDARDS §8 references descriptor.ts (acknowledged dead)

services/metrics/integrations/INTEGRATION_STANDARDS.md

info

Translation layer and handler error boundaries are FCIS-compliant

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts

tests7

high

Status code string parsing ('0'/'1'/'2') untested at HTTP client layer

services/metrics/integrations/hoymiles/src/__tests__/metrics-handler.test.ts:255

high

Retention window 1d fallback path not tested

services/metrics/integrations/hoymiles/src/__tests__/metrics-handler.test.ts:139

medium

enumerateLocalDays: fall-back DST transition untested

services/metrics/integrations/hoymiles/src/__tests__/points-to-batu.test.ts:76

medium

gpw unknown-plant caveat: tested at pure-function level only, not through handler

services/metrics/integrations/hoymiles/src/__tests__/connection-handler.test.ts:137

medium

Cadence detection multi-day mixed evidence not covered

services/metrics/integrations/hoymiles/src/__tests__/points-to-batu.test.ts:130

low

localWallTimeToUtcMs fall-back DST hour (ambiguous wall time) not tested

services/metrics/integrations/hoymiles/src/__tests__/points-to-batu.test.ts:67

low

dominantSpacingMinutes tie-breaking (equal votes) not tested

services/metrics/integrations/hoymiles/src/__tests__/points-to-batu.test.ts:87

improvement7

high

Billing-critical timezone helpers copy-pasted verbatim across brands

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts:65

Move to @batu/metrics-engine/lib/local-time.ts — 10+ brand ports coming, any DST fix must apply to N copies.

high

InvocationResult envelope helpers triplicated across integrations

services/metrics/integrations/hoymiles/src/handlers/metrics.lambda.ts:309

medium

resolveChannels duplicated across 3 integrations without sharing

services/metrics/integrations/hoymiles/src/handlers/metrics.lambda.ts:79

medium

Two intraday retention checks are redundant

services/metrics/integrations/hoymiles/src/handlers/metrics.lambda.ts:167

low

allPoints flatMap allocates 4320-element array for an emptiness check

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts:235

low

secretsClient() singleton pattern will be copied to 10+ more brands

services/metrics/integrations/hoymiles/src/engine/hoymiles-client.ts:263

info

powerDaysToBatu hardcodes 'solar_generation' key in units object

services/metrics/integrations/hoymiles/src/translation/points-to-batu.ts:279

History · 2 commits

  1. 4de48f3needs attentionfull5H · 8M · 9L2026-07-08 02:23current
  2. e804a8eneeds attentionfull2H · 7M · 6L2026-07-07 21:41