feat/int-base
needs attentionviewing older commit595484f · incrementalPR #268reviewed 2026-07-13 04:29 UTC1H · 3M · 7L · 5I- Purpose
- Land every shared seam the 12 device-integration ports depend on — manifests, catalog seeds, ARN-seed registry, CDK path entries, and legacy-registry/credential migration scripts — so each per-brand branch only touches its own vendor directories.
- Goal
- Integration base branch for 12 device integrations (hoymiles, shelly, solis, huawei, solark, fronius, apsystems, abb, victron, enphase, sma, powerradar) with shared seams proven live on the consolidated estate.
- Sub-goals
- SG-1: 12 manifests + registration
- SG-2: Catalog seed rows (Makes, Integrations, MetricTypes)
- SG-3: ARN-seed REGISTRY entries
- SG-4: CDK paths.ts handler entries
- SG-5: D3 registry-migration script
- SG-6: D2 credential-copy script
- SG-7: 1M calendar-month granularity end to end
- SG-8: Multi-granularity worker contract canonicalization
- SG-9: Inert coverage clamp fix (union semantics)
- SG-10: Consolidation merge of 12 brand branches
- SG-11: Sync latest main + hoymiles seed fix
- SG-12: Combined estate validation (12 brands)
- SG-13: Loop C review remediation (enphase/fronius/apsystems/victron/abb/sma/solark)
- SG-14: Review 4 Loop-C-uncovered brands (victron/abb/sma/solark) — current commit
- What
- SG-14 SMA documentation: corrects the tier lineage classification in sma.ts manifest comment and points-to-batu.ts translation comment ({5m,1h} = high-res power series, not counters; {1d,1M} = energy counters), and adds BILLING_TIER.md with the probe evidence (4-day per-tier correctness table, two-series divergence quantification, round-trip identity check).
- Why
- The prior port note incorrectly grouped 1h with 1d/1M as counter tiers. SG-14 ran a direct API probe (2026-07-12) that confirmed the correct split: {5m,1h} are power (W) from the Day/Week sets; {1d,1M} are energy counters (Wh) from the Month/Year sets. Each tier is faithfully reproduced from its own vendor source; the ~+17–20% inter-series gap is a vendor characteristic, not a pipeline error.
- Areas
- packages/integration-manifests/src/manifests/sma.ts+11−7services/metrics/integrations/sma+149−3
- Blast
- Documentation only — 3 files, +150/-10, no runtime logic. The stale CLAUDE.md claim (line 604) is the only follow-up action item.
Findings · 17
correctness3
5m correctness check is circular — verified against legacy store, not live vendor endpoint
services/metrics/integrations/sma/BILLING_TIER.md:56
The OUR 5m = VENDOR 5m match is guaranteed by construction (worker transform ×300/3.6e6 ≡ legacy /12000 — algebraically identical). The Day endpoint was down at probe time, so VENDOR 5m was sourced from the legacy store. Footnote 2 discloses this but the verdict table entry says 'YES' without distinguishing 'proven identical to legacy' from 'confirmed against live vendor endpoint'. Live endpoint parity remains unconfirmed.
1h verdict table uses hedged-positive phrasing rather than explicit UNVERIFIED
services/metrics/integrations/sma/BILLING_TIER.md:74
The 1h table row says 'transform trivially loss-free; not live-reconfirmed this run (endpoint down + tier unprovisioned)'. This could be read as a positive verdict by a reader skimming the table. UNVERIFIED or N/A would be more accurate given both the endpoint outage and the tier being unprovisioned.
~+20% header is slightly imprecise — measured range is +17.4%–+20.2%
services/metrics/integrations/sma/BILLING_TIER.md
The manifest comment says 'stable ~+20%' and the section header also uses '~20%' but the measured range across 4 days is +17.4% to +20.2%. '~17–20%' would be more precise while still conveying the structural nature of the gap.
security3
AWS management account ID 397762539248 committed to docs
services/metrics/integrations/sma/BILLING_TIER.md:14
Account IDs are not secrets but narrow the attack surface for IAM confused-deputy attacks and resource enumeration. Low risk in a private repo; worth noting as hygiene if repo ever becomes public.
Production DynamoDB table names committed to docs
services/metrics/integrations/sma/BILLING_TIER.md:13
Exact DynamoDB table names (prod-ddb-metrics-sites-devices, prod-ddb-batu-metrics) and path-structured IDs committed. These aid reconnaissance for an attacker with partial AWS access. Low severity in a private repo.
Plant/device identifiers committed — consistent with existing codebase convention
services/metrics/integrations/sma/BILLING_TIER.md
Plant ID 6862260, oid 25, stream ULID mst_01KWZV6G30YZMVZNGJF5H22ANM, and site_key /25/18/2 are recorded. These also appear in INFRA_DESIGN.md and CLAUDE.md — no new sensitivity class introduced. No action required.
conventions3
CLAUDE.md still classifies 1h with energy counters — directly contradicts the new evidence
services/metrics/integrations/CLAUDE.md:604
Line 604: 'Counter-vs-samples lineage split: 1h/1d/1M come from the plant's energy COUNTERS'. The diff corrects this in sma.ts and points-to-batu.ts (split is {5m,1h} power vs {1d,1M} counter) but did NOT update CLAUDE.md. A future reader hitting the CLAUDE.md SMA section will read the old wrong claim.
BILLING_TIER.md naming inconsistent with per-brand INFRA_DESIGN.md convention
services/metrics/integrations/sma/BILLING_TIER.md
Every other brand uses INFRA_DESIGN.md as its per-brand reference doc. SMA already has INFRA_DESIGN.md in the same directory. Convention is to extend INFRA_DESIGN.md with a new section rather than add a sibling file with a unique name that has no parallel in any other brand.
Manifest cross-reference to BILLING_TIER.md is path-ambiguous
packages/integration-manifests/src/manifests/sma.ts:29
The JSDoc writes BILLING_TIER.md as a bare filename with no repo-relative path. A reader of the manifest file (in packages/integration-manifests/src/manifests/) cannot resolve this without knowing to look in services/metrics/integrations/sma/. The reference in points-to-batu.ts correctly uses ../BILLING_TIER.md.
tests5
BILLING_TIER.md round-trip probe value not pinned as regression test
services/metrics/integrations/sma/src/__tests__/points-to-batu.test.ts
The doc documents a concrete round-trip: 1_762_178 Wh → 1_762.178 kWh (error < 1e-6). A golden-value test using this July-8 vendor counter would pin the BILLING_TIER.md evidence against code regression. The formula is already algebraically correct; this is a documentation-traceability gap, not a bug risk.
maxWindowDays skip behavior (Lambda timeout guard) has no test
services/metrics/integrations/sma/src/__tests__/points-to-batu.test.ts
GRAIN_SPECS declares maxWindowDays (5m=31, 1h=92, 1d=400, 1M=1900). The test asserts the field exists via toMatchObject but nothing tests that the caller correctly skips a grain when the requested window exceeds maxWindowDays. This is the §9 resilient-skip contract, load-bearing for correctness under large backfill windows.
W×300/3.6e6 ≡ /12000 identity already covered in transforms.test.ts
The algebraic identity (300/3_600_000 = 1/12_000) is proven by the SG-5 equivalence test at domains/metrics/src/site-metrics/__tests__/transforms.test.ts line 31. No additional SMA-specific test needed.
1h live correctness unverifiable from test suite — documented gap, not a test gap
services/metrics/integrations/sma/BILLING_TIER.md
The 1h suite in points-to-batu.test.ts covers time-shift and running-hour guard logic but cannot cover the passthrough claim (mean-W ≡ Wh/h numerically identical) against a live vendor sample. This is a known evidence gap, not a test suite gap. Follow-up: re-probe once PINELLI is provisioned at 1h or the Week endpoint recovers.
No test asserts the worker does NOT reconcile the two-series divergence
services/metrics/integrations/sma/src/__tests__/points-to-batu.test.ts
BILLING_TIER.md documents a structural ~+17–20% divergence and explicitly states 'the worker performs NO reconciliation'. A guard test asserting multi-grain collection returns two independent MetricsPayloads with raw values (no cross-tier correction) would protect against a future well-intentioned 'fix'.
improvement3
1h unverified status needs a ⚠ callout, not just a parenthetical
services/metrics/integrations/sma/BILLING_TIER.md:74
The verdict table for 1h says 'transform trivially loss-free; not live-reconfirmed this run (endpoint down + tier unprovisioned)'. The 1h lineage classification (power, not counter) is the core finding of this doc — but its per-grain correctness is structurally unverifiable from this probe. Deserves an explicit ⚠ UNVERIFIED marker in the verdict column, matching the ⚠ used in the manifest for the overall lineage warning.
Deferred authority question lacks a concrete resolution path
services/metrics/integrations/sma/BILLING_TIER.md:122
'Deferred' appears three times but never states: (a) when it resolves, (b) whether it needs re-probing once 1h is provisioned and the Week endpoint recovers, or (c) where to file the follow-up. One sentence noting the resolution path would make the deferral actionable rather than terminal.
BILLING_TIER.md mixes transient probe state (endpoint outage) with permanent structural findings
services/metrics/integrations/sma/BILLING_TIER.md
The endpoint availability table documents a transient outage that will be outdated once the vendor fixes the Day/Week endpoint. Consider a top-level note separating probe-state artifacts (the outage table) from the permanent structural finding (the two-lineage split). The structural finding is permanent; the outage is transient.
History · 11 commits
- f7b9554safeincremental0H · 0M · 0L2026-07-13 20:18
- 9ca23adneeds attentionincremental0H · 3M · 3L2026-07-13 19:17
- 595484fneeds attentionincremental1H · 3M · 7L2026-07-13 04:29current
- 2ed62f4safeincremental0H · 0M · 0L2026-07-13 04:13
- 2812f54needs attentionincremental1H · 3M · 10L2026-07-11 00:19
- 1794b23needs attentionincremental2H · 2M · 5L2026-07-10 21:59
- e5674dcneeds attentionincremental3H · 7M · 6L2026-07-09 19:29
- ca45a96needs attentionincremental0H · 3M · 3L2026-07-09 18:56
- 5d19484safeincremental0H · 0M · 1L2026-07-08 02:04
- dd403feneeds attentionincremental12H · 22M · 12L2026-07-07 20:02
- e663ae9needs attentionincremental2H · 7M · 7L2026-07-07 19:02