@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 +171 -0
- package/README.md +396 -332
- package/dist/cli.js +30 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/llm/index.d.ts +1 -0
- package/dist/llm/index.js +4 -1
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/prompt.js +66 -66
- package/dist/llm/telemetry.d.ts +150 -0
- package/dist/llm/telemetry.js +230 -0
- package/dist/llm/telemetry.js.map +1 -0
- package/dist/reports/healStats.d.ts +132 -0
- package/dist/reports/healStats.js +303 -0
- package/dist/reports/healStats.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/package.json +1 -1
- package/templates/heal.ts.tmpl +452 -452
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
|