saffron-ai 0.9.6 → 0.9.8

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
@@ -5,6 +5,236 @@ the VS Code extension (`ChathurangaJayasinghe.saffron-vscode`) and the
5
5
  JetBrains plugin (`ai.saffron.jetbrains`). Dates are publish dates. Each
6
6
  release heading names its main feature: `## <version>: <title>`.
7
7
 
8
+ ## 0.9.8: Run one scenario, from the editor too
9
+
10
+ Released 2026-10-06.
11
+
12
+ Behaviour changes
13
+
14
+ - **Tags now apply as in Cucumber**: a Feature's and a Rule's tags to
15
+ every scenario in it, an Examples block's to its rows. A CI filter can
16
+ select differently than before: `not @ignore` with `@ignore` on a
17
+ Feature now skips that feature, and `--filter @smoke` with a
18
+ Feature-level `@smoke` now takes all of its scenarios. Check your
19
+ `--filter` expressions when you upgrade. The dashboard's results per tag
20
+ and the IDEs' Tags tabs count the inherited tags too.
21
+
22
+ Runner
23
+
24
+ - **Run one scenario by its line or its name.** `saffron run
25
+ features/login.saffron:12` runs the scenario that line is in,
26
+ Cucumber-style: its Scenario line, a tag above it or any line inside it.
27
+ An Examples row runs that row alone, any other line of an outline runs
28
+ every row, and `:12:30` names two. `features/login.saffron:Successful
29
+ login` names it instead, which stays true while the file is edited,
30
+ and `:Roles (example 2)` one Examples row, as `saffron trace` lists it. A
31
+ line no scenario owns (the feature's header, a Background, a StepSet, a
32
+ Rule's header, past the end), a name no scenario has, or an outline
33
+ whose Examples have no rows yet stops the run with exit 2 and says
34
+ what is there. Works with `--filter`, `--shard` and `--rerecord`.
35
+ - **Tags on a Feature, a Rule or an Examples block apply to what they
36
+ hold**, as in Cucumber: `--filter @smoke` takes a feature tagged
37
+ `@smoke`, and `not @wip` leaves out a Rule's scenarios, or an Examples
38
+ block's rows, tagged `@wip`. Reports, history and the IDEs' tag lists
39
+ carry them; a scenario lists every row's tags.
40
+ - **A scenario whose own name ends in "(example N)" keeps its results.**
41
+ Report and history rows now carry the scenario's name; an older row is
42
+ read as a scenario of that exact name first, and as an outline's row
43
+ only when no such scenario exists, in status, the dashboard and CI
44
+ results alike.
45
+ - **A run that writes an outline's recording runs every row of it**
46
+ (`--rerecord`, or an outline not recorded yet or whose recording is
47
+ stale), also rows an Examples line or a `--filter` on Examples tags left
48
+ out: the rows share one recording. A row asked for records first and
49
+ the others replay the new recording in the same run, so one that fits
50
+ only that row comes back red, not as a proposal.
51
+ - **The dashboard keeps each Examples row's latest result** from whichever
52
+ run ran it: a run that left a row out (a tag filter, a named run) no
53
+ longer clears that row's failure; a row removed from the table stops
54
+ counting.
55
+ - **A run of named scenarios is not a suite run.** Its results replace
56
+ those scenarios' own in the last report, beside the rest of the last
57
+ run, and the report takes the run's own times and hook results. Its history line is
58
+ marked partial: the dashboard counts it for those scenarios (their
59
+ latest result, never run, recent failures), while trends, the pass-rate
60
+ series, the last run's figures and the next run's comparison count runs
61
+ of the suite only. A last report that was imported from CI, for another
62
+ base URL or billed another way (subscription or API key) is replaced,
63
+ and the run says so. Sharded, such a run merges the same way.
64
+ - **Two scenarios of one name in one file stop the run**, as any two
65
+ scenarios sharing a recording do: one per Rule was allowed, and each
66
+ overwrote the other's recording. The check now reads the configured
67
+ `features` folder, not only `features/`, and always the files the run
68
+ names.
69
+ - **One pass rate everywhere.** The run report, the trends and `saffron
70
+ status --json` (a new `passRate` per run) leave out a heal whose proof
71
+ replay failed, as the dashboard already did: the same run no longer
72
+ reads 100% in the report and 0% on the dashboard.
73
+ - **History written on Windows counts on the dashboard.** A history line
74
+ naming `features\login.saffron` is the same feature as
75
+ `features/login.saffron`, so its scenarios keep their latest result and
76
+ recent failures instead of reading as never run.
77
+ - **A refused run deletes no recording.** `--rerecord` removes recordings
78
+ only when the scenarios are about to run: a run stopped first (a cache
79
+ collision, an `{env:...}` or `{data:...}` reference, an invalid
80
+ `--trace`, `--browser` or `--assertion-policy`, a failed setup hook, a
81
+ missing browser) keeps them.
82
+ - **A path that does not exist stops the run.** `saffron run
83
+ features/chekout.saffron` (a typo) exits 2 naming it, instead of
84
+ running the other paths alone.
85
+ - **Run lenses from the language server**, for an editor that asks for
86
+ them (`initializationOptions.runLenses`). `saffron lsp` puts Run, Replay
87
+ only and Headed above each scenario, in the file's own Gherkin
88
+ language, each carrying the scenario's `file:name` and the project to
89
+ run it in. A `.feature` file outside a Saffron project gets none, and
90
+ neither does a file outside the editor's workspace, so a lens never runs
91
+ anywhere the user did not open (such a file keeps its own project's
92
+ completion and diagnostics). A scenario named like lines (`42`,
93
+ `10:30`) is targeted by its line. The JetBrains plugin also refuses a
94
+ lens whose folder is outside the IDE project.
95
+ - `saffron status --json` gives each scenario's line from the parsed file:
96
+ right in another Gherkin language, and never a `Scenario:` line inside a
97
+ doc string.
98
+ - **Open Trace on a CI run works from the editors again.** `saffron trace
99
+ --run <id>` takes `--max-download <MB>`, as the JetBrains plugin passes
100
+ it, and refuses a larger download exactly as `report --run` does: exit
101
+ 2, and with `--json` the same `kind: "too-large"` and `sizeBytes`.
102
+ - **Two editors can load one CI run at once.** Each request downloads
103
+ into its own temporary folder beside `.saffron/ci/<provider>-<id>/`, so
104
+ one never deletes another's download. When another request finished
105
+ first, Saffron uses its folder, checked as a cached one is, and removes
106
+ its own. A finished download removes only earlier attempts of the run,
107
+ never a later attempt or another request's download in progress; what
108
+ a killed download left (0.9.7's `.partial`, or a folder untouched for a
109
+ day) goes.
110
+ - **`--max-download` covers everything downloaded.** Saffron reads every
111
+ page of a GitHub run's artifacts, not just the first 100, and downloads
112
+ exactly the `saffron-bundle*` artifacts it sized, one by one by name, on
113
+ GitHub and Azure. An artifact whose name it does not accept is neither
114
+ counted nor downloaded.
115
+ - **Doc strings in `.saffron` files stay as written.** A line such as
116
+ `StepSet: sample` or `StepSet sample` inside a `"""` or ```` ``` ````
117
+ doc string is literal test data now, no longer read as a step set
118
+ definition or call.
119
+
120
+ VS Code extension 0.6.1
121
+
122
+ - **Health's pass rate of recent runs** is the runner's (saffron-ai 0.9.8
123
+ or later): a heal whose proof failed does not pass.
124
+ - **Open Report and Open Trace on a CI run keep `saffron.ciMaxDownloadMB`**
125
+ when the run's results are no longer on disk (trace with saffron-ai
126
+ 0.9.8 or later).
127
+ - **Run, Replay only and Headed above each scenario.** A click runs that
128
+ scenario alone, by name (`saffron run <file>:<name>`), as a task in the
129
+ project that owns the file. The file is saved first, and the panel's
130
+ replay-only and headed toggles apply as they do to every run. Lenses
131
+ and the side panel find scenarios in the file's own Gherkin language
132
+ (`# language:`), nameless ones too. Needs saffron-ai 0.9.8 or later; with
133
+ an older one in the project a click says so.
134
+ - **A CI run's yellow results read "pending review", not "healed".**
135
+ Yellow also covers first recordings and proposals not yet verified.
136
+ - **Each yellow or red CI scenario says whether the run verified it**:
137
+ "unverified" or "verified", and nothing when the run does not say.
138
+
139
+ JetBrains plugin 0.6.1
140
+
141
+ - **Health's pass rate of recent runs** is the runner's (saffron-ai 0.9.8
142
+ or later): a heal whose proof failed does not pass.
143
+ - **Run, Replay only and Headed above each scenario**, with LSP4IJ
144
+ installed. A click saves the files and runs that scenario alone, by
145
+ name, through a temporary run configuration made for it, so the run
146
+ widget runs it again. A saved configuration of the same name is left as
147
+ it is, and nothing from the Saffron template carries in, and a scenario
148
+ of the same name in another file gets its own. The lenses work while the
149
+ IDE indexes, and say when the project's saffron-ai is too old.
150
+ - **Right-click Run inside a scenario** runs that scenario alone, with or
151
+ without LSP4IJ, never reusing a lens's Replay only or Headed
152
+ configuration; outside one, or in a file in another Gherkin language,
153
+ it runs the whole file, as before. Both need saffron-ai 0.9.8 or later.
154
+ - **Open Trace works with every runner and keeps the download limit.**
155
+ With saffron-ai 0.9.8 it passes `--max-download` to `saffron trace`,
156
+ which downloads a run no longer on disk; with 0.9.7, which rejects the
157
+ option, it leaves it out.
158
+ - **Open Trace finds a Scenario Outline's example row** ("Login (example
159
+ 1)") by the name the run shows.
160
+ - **CI yellow results read "pending review", not "healed"**, and each
161
+ scenario says "unverified" or "verified" when the run reports it.
162
+
163
+ ## 0.9.7: CI results without importing
164
+
165
+ Released 2026-10-05.
166
+
167
+ Runner
168
+
169
+ - **See what a CI run found before you import it.** `saffron report --run
170
+ <id>` downloads the run's Saffron bundles once into
171
+ `.saffron/ci/<provider>-<id>/attempt-<n>/`, checks them as `saffron
172
+ import` does (repository, digests, sizes, format, the run, attempts and
173
+ shards), judges each proposal against this checkout without filing it,
174
+ and opens the run's report page. Your `.saffron/reports/`,
175
+ `.saffron/proposals/`, `.saffron/artifacts/` and import ledger are left
176
+ as they were. `--json` gives the run, its totals, each scenario with its
177
+ failing step, first error line, screenshot and trace, each proposal as
178
+ importable or not with the reason, and warnings: what the VS Code and
179
+ JetBrains CI runs views show under a run.
180
+ - **A run without results says why.** `running` (not finished),
181
+ `expired` (the service deleted the artifact) or `none` (nothing
182
+ uploaded; the guide's workflow exports only on failure, and `if:
183
+ always()` on the export and upload steps keeps every run's results), as
184
+ `reasonKind` and `reason`, exit 0.
185
+ - **Large runs ask first.** `--max-download <MB>` refuses a run whose
186
+ bundles add up to more, with `{"error", "kind": "too-large",
187
+ "sizeBytes"}` and exit 2, so an editor can ask and run again.
188
+ - **Replay a CI run, view only.** `saffron trace --run <id> [scenario]`
189
+ replays the run's traces from `.saffron/ci/`, taking the same scenario
190
+ forms as `saffron trace` (`<feature>:<scenario>` included). The page has
191
+ no Accept or Reject and its server no review routes: nothing was filed.
192
+ - **View, then import, downloads once.** `saffron import --run <id>`
193
+ reuses the viewed download of the run's latest attempt.
194
+ - **A cache that looks after itself.** `.saffron/ci/` keeps the newest 10
195
+ runs and at most 1 GB, removing the oldest first; a download goes
196
+ through a `.partial` folder and is renamed whole, so a cancelled one
197
+ leaves nothing behind. The folder writes its own `.gitignore` (`*`), so
198
+ it never shows in `git status`, even in a project set up before it
199
+ existed, and `saffron init` adds `.saffron/ci/` to the entries it
200
+ manages.
201
+
202
+ VS Code extension 0.6.0
203
+
204
+ - **Expand a CI run to see what it found, without importing it.** The
205
+ run lists its totals, each failed and healed scenario with its failing
206
+ step and first error line (the tooltip has what the agent changed), and
207
+ "N proposals: M importable" with the reason each one would not import.
208
+ Your reports, proposals and evidence are left alone. Needs saffron-ai
209
+ 0.9.7 or later; an older runner says so.
210
+ - **Open Report and Open Trace on a viewed run.** Open Report shows the
211
+ run's report in your browser; Open Trace replays a traced scenario,
212
+ view only. Import stays the only action that files proposals.
213
+ - **Large results ask first.** Results above the new
214
+ `saffron.ciMaxDownloadMB` setting (default 100, 0 for no limit) ask
215
+ "This run's results are N MB. Download?". Loading can be cancelled,
216
+ which stops the whole download, and never runs while the CI runs view
217
+ is hidden.
218
+ - **A run with no results says why:** still running, its artifacts
219
+ expired, or it uploaded none.
220
+
221
+ JetBrains plugin 0.6.0
222
+
223
+ - **CI Runs shows what a run found without importing it.** Select a run
224
+ to see its totals, each failed and healed scenario with its failing
225
+ step and first error line (the narrative in the tooltip), and
226
+ "N proposals: M importable" with the reason for each one that is not.
227
+ It loads in a background task you can cancel, only while the tab is on
228
+ screen. Needs saffron-ai 0.9.7 or later; an older runner says so.
229
+ - **Open Report and Open Trace on a viewed run.** Open Trace (or a
230
+ double-click) replays a failed or healed scenario's trace, view only.
231
+ Import Run stays the only action that brings proposals into the
232
+ checkout.
233
+ - **Large results ask first**, above the limit in Settings, Tools, Saffron
234
+ (default 100 MB, 0 for no limit), the same as the VS Code setting.
235
+ - **A run with no results says why:** still running, expired, or none
236
+ uploaded.
237
+
8
238
  ## 0.9.6: Dashboard figures you can trust
9
239
 
10
240
  Released 2026-10-05.
package/README.md CHANGED
@@ -73,7 +73,7 @@ node dist/cli/index.js -p examples accept --all
73
73
 
74
74
  | Command | What it does |
75
75
  |---|---|
76
- | `saffron run [paths] [--headed] [--filter expr] [--rerecord] [--no-agent] [--strict] [--browser b] [--no-hooks] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f] [--trace mode]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`, keep an execution trace with `--trace retain-on-failure`. Exit 1 on red (and on yellow with `--strict`). |
76
+ | `saffron run [paths] [--headed] [--filter expr] [--rerecord] [--no-agent] [--strict] [--browser b] [--no-hooks] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f] [--trace mode]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). A path with a line or a name, `features/login.saffron:12` or `"features/login.saffron:Successful login"`, runs that one scenario. Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`, keep an execution trace with `--trace retain-on-failure`. Exit 1 on red (and on yellow with `--strict`). |
77
77
  | `saffron accept [files... \| --all] [--include-unverified] [--include-imported] [--with-feature-edit] [--propagate]` | Promote cache proposals to committed caches (`--all` skips UNVERIFIED ones unless `--include-unverified`, and ones imported from a CI run unless `--include-imported`); `--with-feature-edit` also rewrites the adapted steps in the `.feature` file (and keeps the cache in sync); `--propagate` applies the heal's locator fixes to every other cache using the same locator. One heal repairs N scenarios before they ever fail. No args: list pending proposals. |
78
78
  | `saffron reject [files... \| --all]` | Discard proposals; the agent will try again next run. |
79
79
  | `saffron export [-o file] [--branch name]` / `saffron runs` / `saffron import <bundles...> \| --run <id>` | Carry a CI heal to your machine: export packs the run's proposals, report, screenshots and traces into one bundle for CI to upload; `runs` lists the branch's CI runs (GitHub Actions or Azure Pipelines); import (of a file, or of a run with `--run`) checks the bundle against your checkout (repository, each proposal's binding) and files it there, ready for `saffron diff` and `saffron accept`. `--branch` also has CI commit the proposals to a new branch and open a draft pull request with their diffs. |
@@ -155,8 +155,7 @@ milestones, statuses and decision gates, and everything shipped so far in
155
155
  its "Where we are" table.
156
156
  Headlines ahead: API testing (reusable REST operations, fixtures and schema
157
157
  validation), scenarios with two users in two browsers, a configurable
158
- features folder, running one scenario (`file:line`, with run icons in both
159
- IDEs), parallel recording and a browser matrix in one run, failure video,
158
+ features folder, parallel recording and a browser matrix in one run, failure video,
160
159
  agent-blind secrets, LLM-less MCP replay, the Level-2 shared step library
161
160
  (gated on Level-1 divergence data), and the long-term open-core SaaS layer.
162
161