saffron-ai 0.8.3 → 0.8.5
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 +152 -0
- package/dist-pkg/cli.js +116 -108
- package/package.json +1 -1
- package/skills/saffron/SKILL.md +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,158 @@ All notable changes to Saffron, in one place: the `saffron-ai` runner (npm),
|
|
|
4
4
|
the VS Code extension (`ChathurangaJayasinghe.saffron-vscode`) and the
|
|
5
5
|
JetBrains plugin (`ai.saffron.jetbrains`). Dates are publish dates.
|
|
6
6
|
|
|
7
|
+
## 0.8.5
|
|
8
|
+
|
|
9
|
+
Released 2026-09-24.
|
|
10
|
+
|
|
11
|
+
Runner
|
|
12
|
+
|
|
13
|
+
- **A proposal is bound to what you reviewed.** Every proposal now carries
|
|
14
|
+
digests of the scenario's steps, of the committed recording it was
|
|
15
|
+
diffed against and of its own recording, taken when it was filed.
|
|
16
|
+
`saffron accept` recomputes them and refuses a proposal, by reason, when
|
|
17
|
+
any moved since: a step edited, a colleague's heal accepted, a locator
|
|
18
|
+
fix propagated, a pull, a hand edit ("step 3 now reads ... and was
|
|
19
|
+
..."). There is no override; run the scenario again for a proposal
|
|
20
|
+
bound to what is there now, or reject it. `saffron accept`, `saffron
|
|
21
|
+
diff`, `saffron status --json` (`stale`) and both IDE panels show STALE
|
|
22
|
+
with the reason first. A run that finds a stale pending proposal records
|
|
23
|
+
afresh instead of proving it again. Fingerprints are advisory and are
|
|
24
|
+
not bound; data tables, doc strings and the feature edits that
|
|
25
|
+
`--with-feature-edit` would apply are. Proposals filed before this
|
|
26
|
+
release carry no digests and are accepted with a note.
|
|
27
|
+
- **Recordings and proposals are validated on read.** The schema version,
|
|
28
|
+
every step, every action type and field are checked, along with the
|
|
29
|
+
operands each action needs (a click without a usable target, an
|
|
30
|
+
`expectUrl` without a URL, which used to compare "" and pass), and the
|
|
31
|
+
first problem is named by path. An unreadable recording makes its scenario red
|
|
32
|
+
with the reason instead of replaying as garbage or being recorded over;
|
|
33
|
+
`saffron status` marks it `invalid` with the reason (`cacheProblem`);
|
|
34
|
+
an unreadable proposal is reported and left out of listings
|
|
35
|
+
(`unreadableProposals`) instead of blanking them. A file from a newer
|
|
36
|
+
runner, a schema version or an action type this one does not know, says
|
|
37
|
+
to update `saffron-ai`. Fields added within the schema version stay
|
|
38
|
+
optional, so newer caches read on older runners. Hand-written caches may
|
|
39
|
+
omit `recordedAt` and `recordedBy`.
|
|
40
|
+
|
|
41
|
+
Editors (VS Code extension 0.2.10, JetBrains plugin 0.2.5)
|
|
42
|
+
|
|
43
|
+
- Both Proposals panels mark a stale proposal STALE, with the reason and
|
|
44
|
+
what to do, and note a proposal filed by an older runner.
|
|
45
|
+
|
|
46
|
+
## 0.8.4
|
|
47
|
+
|
|
48
|
+
Released 2026-09-24.
|
|
49
|
+
|
|
50
|
+
Runner
|
|
51
|
+
|
|
52
|
+
- **A check could point at the wrong element.** In a live heal the agent
|
|
53
|
+
recorded "the Morning Ritual package is applied" against `role=definition`
|
|
54
|
+
with no name. The booking summary has one definition per row, so replay
|
|
55
|
+
read the first one (the room) and the proof replay failed. `saffron_assert`
|
|
56
|
+
and `saffron_capture` now refuse a bare role unless it is one that occurs
|
|
57
|
+
once per page (`status`, `alert`, `dialog`, `main` and similar), and ask
|
|
58
|
+
the agent for a name, text, label or selector instead.
|
|
59
|
+
- **A baseURL's query string and path were lost on replay.** With
|
|
60
|
+
`baseURL` set to `http://localhost:5173/?flow=checkout-guest`, a recorded
|
|
61
|
+
visit to the start page replayed as `http://localhost:5173/`, silently
|
|
62
|
+
dropping the flag that picks the variant under test. A baseURL with a
|
|
63
|
+
path fared no better: under `http://host/app`, a cached `/rooms`
|
|
64
|
+
replayed as `http://host/rooms`, and a recorded `http://host/apple` was
|
|
65
|
+
cached as `/le`. Under `http://h/#/home`, a recorded visit to `/` with
|
|
66
|
+
no hash replayed back to `#/home`, a different page for a hash router;
|
|
67
|
+
it is now kept as `/#`, the way a missing query is kept as `?`.
|
|
68
|
+
The baseURL is now a prefix in both directions: cached
|
|
69
|
+
navigations keep its path and inherit its query, so a cache recorded
|
|
70
|
+
against `?flow=standard` replays against `--base-url
|
|
71
|
+
"...?flow=checkout-guest"`. A cached URL with a query of its own keeps
|
|
72
|
+
it, other origins stay untouched, and existing caches replay as before.
|
|
73
|
+
- **Heal summaries could describe a changed flow as a locator tweak.**
|
|
74
|
+
When an A/B variant folded the guest information page into checkout,
|
|
75
|
+
the heal was right (fields re-targeted, the "Continue to payment" click
|
|
76
|
+
dropped) but its note only said the selects were now found by label.
|
|
77
|
+
The heal prompt now asks the agent to name the kind of change (a locator
|
|
78
|
+
or label change, a page removed or merged, a page added or reordered)
|
|
79
|
+
and the page it happened on. Saffron also compares the healed recording
|
|
80
|
+
with the committed one and adds its own `flow change:` notes for any
|
|
81
|
+
click, key press, goto or tab move that was dropped or added, together
|
|
82
|
+
with the page replay stopped on. A renamed button still reads as a
|
|
83
|
+
locator change and adds no note.
|
|
84
|
+
- **Two data references holding the same value could bind a field to the
|
|
85
|
+
wrong one.** With `users.owner` and `users.recipient` both "Alice", the
|
|
86
|
+
recorder tokenized every typed "Alice" as the first reference, so a
|
|
87
|
+
recipient field read the owner. Change the recipient to "Bob" and the
|
|
88
|
+
scenario correctly went stale, but step reuse seeded the mis-bound
|
|
89
|
+
actions straight back and the proof replay agreed: verified, zero AI
|
|
90
|
+
calls, wrong field. The recorder now resolves an equal value by the
|
|
91
|
+
reference the step itself names, leaves the literal when the step names
|
|
92
|
+
both or neither (so the stale check catches it), and step reuse refuses
|
|
93
|
+
a step that names a reference its recording does not read.
|
|
94
|
+
- **The report could list `{unique:...}` values that were never typed.**
|
|
95
|
+
A recording seeded from earlier steps, and the proof replay of a pending
|
|
96
|
+
proposal, each drew their own seed while the report showed the values of
|
|
97
|
+
a third. One seed per scenario run now reaches every replay, recording
|
|
98
|
+
and proof, so the report's values are the ones in your application.
|
|
99
|
+
- **A second Ctrl-C during teardown exited before the cleanup finished.**
|
|
100
|
+
The first Ctrl-C started teardown; the next one fell through to Node's
|
|
101
|
+
default and killed the run on top of it. Saffron now answers it with a
|
|
102
|
+
note and keeps waiting.
|
|
103
|
+
- **Re-merging shards after a shard was re-run left the old result in
|
|
104
|
+
history.** The merge treated the run as already recorded and skipped it.
|
|
105
|
+
It now replaces that run's history line, and still never counts a run
|
|
106
|
+
twice. In CI the run is identified by the CI run id, the suite and the
|
|
107
|
+
base URL rather than by the earliest start time, so this holds whichever
|
|
108
|
+
shard was re-run; outside CI, `SAFFRON_RUN_ID` gives the same stability.
|
|
109
|
+
- **The proof replay of a recording reused the recording's `{unique:...}`
|
|
110
|
+
values.** Fixed alongside the report fix above: the proof is a second
|
|
111
|
+
execution, so creating the same record again failed, filed the proposal
|
|
112
|
+
unverified and paid for a refinement pass. Each proof now draws its own
|
|
113
|
+
values, and the report lists them separately from the recording's.
|
|
114
|
+
- **A heal or a refinement could redo earlier steps on the wrong tab and
|
|
115
|
+
file them under step 1.** When the agent takes over, it attaches to the
|
|
116
|
+
browser over CDP and sees every Saffron page as one tab list, starting
|
|
117
|
+
on the first. During a refinement the scenario's own page was still open
|
|
118
|
+
beside the proof replay's, so the agent started on the wrong page,
|
|
119
|
+
selected a tab, and in one run went back to the start page and redid the
|
|
120
|
+
search. Every action performed before its first `saffron_step` was filed
|
|
121
|
+
under step 1, and the merge adopted it over the recording replay had
|
|
122
|
+
already passed: proposals whose step 1 held only "switch to tab 1", or a
|
|
123
|
+
second copy of the search, and a proof replay that failed on them.
|
|
124
|
+
Saffron now closes the pages of other browser contexts before an agent
|
|
125
|
+
session, so the agent sees only the live tabs, and tells it which tab
|
|
126
|
+
replay left off on: the page replay was really acting on, not the newest
|
|
127
|
+
tab with a matching URL, which is a different page when two tabs share
|
|
128
|
+
one. A heal or refinement records nothing until the agent
|
|
129
|
+
announces the failed step: anything it clicks or navigates before that is
|
|
130
|
+
diagnosis and is discarded, and the prompt tells it to look with
|
|
131
|
+
snapshots instead. A seeded recording segment files early actions under
|
|
132
|
+
the first step it may record, never a step that already ran, and drops
|
|
133
|
+
an early tab selection. Actions the agent files under an already
|
|
134
|
+
completed step are discarded, and the merge keeps completed steps'
|
|
135
|
+
recordings whatever the session holds for them.
|
|
136
|
+
Each of these leaves a `recording:` note in the proposal's adaptations.
|
|
137
|
+
Fresh recordings from step 1 behave as before.
|
|
138
|
+
The live tab also follows the agent through a seeded recording: a tab
|
|
139
|
+
it selects, opens or closes in one segment is where the next seeded
|
|
140
|
+
island replays and the next segment starts, read from the browser
|
|
141
|
+
tool's own tab list rather than guessed from a URL.
|
|
142
|
+
- **A role with a text no longer matched any element showing that text.**
|
|
143
|
+
Role and text together now mean the element of that role that shows the
|
|
144
|
+
text, and nothing else.
|
|
145
|
+
- **Shards from different environments merged silently.** A staging shard
|
|
146
|
+
and a production shard combined into one report labelled with whichever
|
|
147
|
+
came first. The merge now refuses shards with different base URLs, by
|
|
148
|
+
name.
|
|
149
|
+
|
|
150
|
+
Editors (VS Code extension 0.2.9)
|
|
151
|
+
|
|
152
|
+
- **`{data:...}` diagnostics stayed stale after editing a data file.** The
|
|
153
|
+
extension watched feature files and caches but not the data folder or
|
|
154
|
+
`saffron.config.json`, so fixing a missing key in `users.json` left the
|
|
155
|
+
error on the feature until the feature itself was touched. Edits to data
|
|
156
|
+
files and to the config now refresh every open feature file, including a
|
|
157
|
+
custom data folder and environment overlays.
|
|
158
|
+
|
|
7
159
|
## 0.8.3
|
|
8
160
|
|
|
9
161
|
Released 2026-09-22.
|