@vijaypjavvadi/bdd2pw 3.8.1 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,177 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  _Nothing yet._
11
11
 
12
+ ## [3.10.0] — 2026-06-06
13
+
14
+ ### Added — self-healing stats sidecar + `bdd2pw heal-stats` CLI
15
+
16
+ v1.1+ has shipped a runtime `healOrThrow` helper that emits
17
+ `register` / `heal_attempt` / `healed` / `heal_unavailable` events
18
+ to `<repo>/artefacts/heal-events.jsonl`. Until now those events
19
+ sat in a JSONL file with no offline analyzer — operators had to
20
+ grep the file themselves to see if healing was working.
21
+
22
+ v3.10.0 adds:
23
+
24
+ **1. `bdd2pw heal-stats <repo>` CLI** — reads
25
+ `<repo>/artefacts/heal-events.jsonl` and writes
26
+ `<repo>/artefacts/heal-stats.json` with:
27
+
28
+ {
29
+ "version": "3.10.0",
30
+ "generatedAt": "2026-06-06T...",
31
+ "source": "<events file>",
32
+ "totals": {
33
+ "registrations": 47,
34
+ "healAttempts": 6,
35
+ "healed": 4,
36
+ "healUnavailable": 2,
37
+ "healRate": 0.6667,
38
+ "uniqueFields": 23,
39
+ "uniquePages": 3
40
+ },
41
+ "topFailingFields": [
42
+ { "page": "LoginPage", "name": "submitButton",
43
+ "attempts": 3, "healed": 2 },
44
+ ...
45
+ ],
46
+ "topErrors": [
47
+ { "error": "timeout <n>ms exceeded", "count": 4 },
48
+ ...
49
+ ],
50
+ "topCandidates": [
51
+ { "selector": "[data-testid='submit']", "promotions": 2,
52
+ "averageConfidence": 0.87 },
53
+ ...
54
+ ],
55
+ "retryLatencyMs": { "p50": 1240, "p95": 3010,
56
+ "min": 880, "max": 3010 },
57
+ "perScenario": [
58
+ { "scenario": "User can log in", "attempts": 1, "healed": 1 },
59
+ ...
60
+ ]
61
+ }
62
+
63
+ Where v3.9.0's `llm-stats.json` measures the LLM batching ROI per
64
+ scaffold, v3.10.0's `heal-stats.json` measures the self-healing
65
+ ROI per TEST RUN.
66
+
67
+ **2. New module `src/reports/healStats.ts`** — pure
68
+ `aggregate(events, source, topN)` function plus the wrapper
69
+ `analyseHealStats(opts)` that resolves the input path
70
+ (file / repo-dir / artefacts-subdir) and writes the sidecar.
71
+
72
+ **3. Error normalisation.** The aggregator collapses error messages
73
+ into stable buckets (lowercase, strip "Error:"/"TimeoutError:"
74
+ prefixes, replace runs of 3+ digits with `<n>`) so transient
75
+ timestamps / IDs don't fragment the histogram.
76
+
77
+ **4. Retry latency derivation.** Pairs each `heal_attempt` with its
78
+ matching `healed` (by `page+name+method`) and reports the timestamp
79
+ delta as the retry latency. Computes p50 / p95 / min / max across
80
+ the run.
81
+
82
+ **5. Graceful empty-input behaviour.** Pointing the CLI at a repo
83
+ with no heal-events.jsonl writes a zero-event summary instead of
84
+ failing — `bdd2pw heal-stats` is now safe to run unconditionally
85
+ in CI after `npx playwright test`.
86
+
87
+ ### Tests
88
+
89
+ `tests/unit/v3100HealStats.test.ts`:
90
+ - Empty input → all-zero summary.
91
+ - Mixed register / heal_attempt / healed / heal_unavailable sequence
92
+ aggregates correctly (counts, healRate, topFailingFields,
93
+ topErrors, topCandidates, p50/p95 latency, per-scenario rollup).
94
+ - `topN` honored — top-3 returns 3 entries from 5 distinct fields.
95
+ - End-to-end: write JSONL → `analyseHealStats(file)` → read JSON
96
+ back and verify shape + version stamp.
97
+ - Missing-file safety: pointing at a directory with no
98
+ heal-events.jsonl returns total=0 and writes an empty summary.
99
+ - Repo-path resolution: passing a directory finds
100
+ `artefacts/heal-events.jsonl` automatically.
101
+
102
+ ## [3.9.0] — 2026-06-05
103
+
104
+ ### Added — opt-in LLM telemetry sidecar
105
+
106
+ `scaffold({ llmStats: true })` now writes
107
+ `<repo>/artefacts/llm-stats.json` capturing per-scaffold LLM activity:
108
+
109
+ {
110
+ "version": "3.9.0",
111
+ "scaffoldId": "scaffold-...",
112
+ "generatedAt": "2026-06-05T...",
113
+ "totals": {
114
+ "callsAttempted": 5,
115
+ "callsSuccessful": 5,
116
+ "bindingsGenerated": 23,
117
+ "cacheHits": 12,
118
+ "cacheMisses": 11,
119
+ "cacheHitRate": 0.522,
120
+ "inputTokens": 24500,
121
+ "outputTokens": 8200,
122
+ "estimatedCostUsd": 0.0735
123
+ },
124
+ "calls": [
125
+ { "index": 1, "model": "...", "inputTokens": 4900,
126
+ "outputTokens": 1820, "latencyMs": 2310,
127
+ "fromCache": false, "batchSize": 5 },
128
+ ...
129
+ ],
130
+ "latencyMs": { "p50": 2100, "p95": 3450, "min": 1200, "max": 3450 },
131
+ "pricing": { "model": "claude-sonnet-4-6",
132
+ "inputUsdPerMillion": 3, "outputUsdPerMillion": 15 }
133
+ }
134
+
135
+ **Why it exists.** v3.5.0 introduced per-scenario LLM batching with
136
+ the promise of ~75% cost reduction on unmatched-heavy scaffolds.
137
+ Until now, the savings were invisible — operators had no per-scaffold
138
+ record of cache hit rate, batch size distribution, token counts, or
139
+ estimated cost. This sidecar makes the ROI measurable per run.
140
+
141
+ **How it works.** New `src/llm/telemetry.ts` ships an `LLMTelemetry`
142
+ class that subscribes to the existing `LLMLogEvent` stream
143
+ (`cache_hit` / `cache_miss` / `provider_call_start` /
144
+ `provider_call_done` / `binding_parsed` events that
145
+ `AnthropicLLMClient` already emits). The scaffold orchestrator fans
146
+ the log callback to BOTH the existing pino logger AND the telemetry
147
+ collector. Zero overhead when disabled — no telemetry instance is
148
+ constructed and the fan-out is a single `?.` null check.
149
+
150
+ **Pricing.** Cost is an ESTIMATE — provider prices change. The
151
+ sidecar records the per-million rates used (default snapshot for
152
+ Claude Sonnet 4.6: $3/M input, $15/M output) so a reviewer can
153
+ re-derive the number against current pricing. Override via
154
+ `new LLMTelemetry(scaffoldId, version, pricingOverride)` if you
155
+ have negotiated rates or a different model.
156
+
157
+ **New exports** from `@vijaypjavvadi/bdd2pw`:
158
+ - `LLMTelemetry` — the collector class.
159
+ - `DEFAULT_PRICING` — per-million USD pricing snapshot. Pre-seeded
160
+ for `claude-sonnet-4-6`, `claude-3-7-sonnet-latest`,
161
+ `claude-opus-4-6`, `claude-haiku-4-5-20251001`.
162
+ - Types: `TelemetryCall`, `TelemetrySummary`.
163
+
164
+ ### Default behavior
165
+
166
+ `llmStats` is **off** by default — pure-UI scaffolds and existing
167
+ LLM-enabled scaffolds emit the same files as v3.8.x. Operators opt
168
+ in when they want to track spend or debug latency.
169
+
170
+ ### Tests
171
+
172
+ `tests/unit/v390Telemetry.test.ts`:
173
+ - Single-batch aggregates correctly (cache misses incremented,
174
+ tokens captured, latency recorded, bindings counted).
175
+ - Cache hit rate computed across mixed cached + uncached calls.
176
+ - p50 / p95 latency from a 10-element sample.
177
+ - Cost estimation against the known Sonnet pricing snapshot.
178
+ - Scaffold context (id, version, generated timestamp) stamped
179
+ into the summary.
180
+ - Zero-event scaffold produces a clean empty summary (no crash,
181
+ no NaN).
182
+
12
183
  ## [3.8.0] — 2026-05-24
13
184
 
14
185
  ### Added — four more opt-in domain rule packs