opencode-plugin-flow 7.0.1 → 7.1.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 +191 -0
- package/README.md +33 -7
- package/dist/index.js +459 -180
- package/dist/index.js.map +20 -19
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,197 @@ One short entry per release, written for users deciding whether to upgrade.
|
|
|
6
6
|
|
|
7
7
|
No changes yet.
|
|
8
8
|
|
|
9
|
+
## [7.1.0] - 2026-07-28
|
|
10
|
+
|
|
11
|
+
The last route to a dishonest `completed` closure is closed, and the two claims
|
|
12
|
+
that rested on prompt prose are now measured.
|
|
13
|
+
|
|
14
|
+
Qualified on Flow 7.0.2 / OpenCode 1.18.6 from the 81-run matrix of 2026-07-28T16:23Z
|
|
15
|
+
across `opencode/claude-sonnet-5`, `openai/gpt-5.6-sol`, and `xai/grok-4.5`: 81/81
|
|
16
|
+
passed, nothing excluded, nothing aborted, and all 81 cassettes reproduced without a
|
|
17
|
+
fidelity caveat. Two earlier matrices needed a merged re-run to qualify — one for a
|
|
18
|
+
wedged `grep` call, one for an attempt excluded over a question it was right to ask.
|
|
19
|
+
Neither recurred.
|
|
20
|
+
|
|
21
|
+
- **A plan declares its canonical gate.** `plan.gate` is the exact command that
|
|
22
|
+
validates the whole repository, named at planning time and locked by approval. A
|
|
23
|
+
`broad` observation has to run that command byte-for-byte, and the gate joins the
|
|
24
|
+
vetoed-command set, so its latest failure blocks review whatever scope an
|
|
25
|
+
observation claimed. This closes the escape [ADR
|
|
26
|
+
0009](docs/adr/0009-scope-keyed-validation-veto.md) recorded as open: a measured
|
|
27
|
+
run had closed `completed` by claiming `git diff --check` as its gate — a command
|
|
28
|
+
that cannot fail, so nothing was ever observed red.
|
|
29
|
+
- **A plan declares evidence this host cannot produce.** `plan.externalEvidence`
|
|
30
|
+
names each acceptance observation needing an operating system, service, credential,
|
|
31
|
+
or device this machine may lack, with the exact command whose passing is that
|
|
32
|
+
observation. Final review and `completed` closure are both refused until that
|
|
33
|
+
command passes, so a self-written proxy cannot stand in for it. The first
|
|
34
|
+
three-provider eval matrix found three runs substituting one — two closed
|
|
35
|
+
`completed` over a Windows-only criterion on a Linux host, with the independent
|
|
36
|
+
review passing, and the suite's own false-completion metric reported zero. Each
|
|
37
|
+
entry also names the `platform` that can observe it — `win32`, `darwin`, `linux`, or
|
|
38
|
+
`other` for a service, credential, or device — and Flow records the host every
|
|
39
|
+
observation ran on, so the declared command passing on the wrong machine no longer
|
|
40
|
+
discharges it. The next matrix run found exactly that: a declared Windows entry
|
|
41
|
+
cleared by its own command's exit zero on Linux, green because the Windows case is
|
|
42
|
+
skipped there. The refusal now distinguishes a command never observed from one that
|
|
43
|
+
passed on the wrong host, because those call for opposite moves. See
|
|
44
|
+
[ADR 0011](docs/adr/0011-declared-external-evidence.md).
|
|
45
|
+
- **Acceptance evidence names test cases, not exit codes.** Each `externalEvidence`
|
|
46
|
+
entry also declares `assertions`: the case names whose passing *is* that
|
|
47
|
+
observation. `flow_validation_start` takes `resultsPath`, the JUnit XML the command
|
|
48
|
+
writes, and Flow records what that report said about each declared name. An entry is
|
|
49
|
+
satisfied only when every one is reported `passed` — `skipped` and `absent`
|
|
50
|
+
discharge nothing. This closes the limitation ADR 0011 recorded rather than fixed:
|
|
51
|
+
comparing the host closed the *wrong machine* and left the same skip on the right
|
|
52
|
+
one, where a case guarded, filtered, renamed out of the run, or never written still
|
|
53
|
+
exits zero. The names come from the approved plan and never from the caller, and a
|
|
54
|
+
report that predates the arming is read as no report at all. Declare an empty list
|
|
55
|
+
when the evidence is not a test result; that keeps the exit-code rule, which is the
|
|
56
|
+
honest answer for a credential or a device. See
|
|
57
|
+
[ADR 0012](docs/adr/0012-named-results-over-exit-codes.md).
|
|
58
|
+
- **The reviewer can see the two commands the plan declares.** Its plan context now
|
|
59
|
+
carries `gate` and `externalEvidence`, which it was asked to judge and was never
|
|
60
|
+
shown: it could not tell a `broad` observation that ran the canonical gate from one
|
|
61
|
+
that ran something else, and could not check a declared environment against the host
|
|
62
|
+
the observation recorded.
|
|
63
|
+
- **Session v5 schema:** `plan.gate` is a new optional string. A document written by
|
|
64
|
+
an earlier build still hydrates and keeps the older rule where `broad` is the
|
|
65
|
+
claimant's word; `flow_plan_save` requires the field for any new plan, so a plan
|
|
66
|
+
this build writes always declares one. `plan.externalEvidence` is a new optional
|
|
67
|
+
array under the same rule: older documents declare nothing and owe no acceptance
|
|
68
|
+
observation, and `flow_plan_save` requires the field — an empty list is the answer
|
|
69
|
+
when the goal is fully observable here. Each entry carries an optional `platform`
|
|
70
|
+
that `flow_plan_save` likewise requires for a new plan, and each validation
|
|
71
|
+
observation carries an optional runtime-written `hostPlatform`; an entry hydrated
|
|
72
|
+
without a platform keeps the command-only rule. Each entry also carries an optional
|
|
73
|
+
`assertions` list that `flow_plan_save` requires for a new plan, and each observation
|
|
74
|
+
may carry a `resultsPath` and the `observedAssertions` the runtime read from it; an
|
|
75
|
+
entry hydrated without assertions keeps the exit-code rule. Rolling an active session
|
|
76
|
+
back to a build without these fields is not supported, as with every previous
|
|
77
|
+
widening.
|
|
78
|
+
- **The bar is published, not described.** [What Flow
|
|
79
|
+
guarantees](docs/guarantees.md) states which claims are enforced by types, attested
|
|
80
|
+
by the host, declared by the caller, judged by a model, or unenforced.
|
|
81
|
+
[Release qualification](docs/release-qualification.md) publishes the eval
|
|
82
|
+
thresholds a release clears, and `bun run qualify` applies them.
|
|
83
|
+
- **Evals measure false completion and reviewer activity**, derived from durable
|
|
84
|
+
documents rather than model prose, and a scheduled workflow runs the suite against
|
|
85
|
+
at least two providers weekly. A new scenario checks that a requirement no run can
|
|
86
|
+
observe is never reported as verified. A run that aborts mid-flight is counted and
|
|
87
|
+
excluded rather than scored as a failure — one wedged attempt was the only failing
|
|
88
|
+
threshold in a measured report, on a guarantee that never ran — and `bun run
|
|
89
|
+
qualify` refuses a report holding one on a gated pair. A wedge diagnostic now names
|
|
90
|
+
the command each incomplete tool call was running.
|
|
91
|
+
- **Recorded model decisions replay for free.** Every paid attempt now writes a
|
|
92
|
+
cassette — its tool calls, in order, with their arguments — and `bun run replay`
|
|
93
|
+
feeds those back through the real handlers against a fresh workspace with no model
|
|
94
|
+
and no host. It is deliberately the decision layer, not the HTTP wire: freezing tool
|
|
95
|
+
results too would mean Flow's own refusals never execute on replay, which is the one
|
|
96
|
+
class of defect this suite exists to catch. Every runtime change up to now needed
|
|
97
|
+
another paid matrix before anyone knew it had not broken a sequence a model already
|
|
98
|
+
performed. CI gates the committed cassettes; a run whose recording holds something a
|
|
99
|
+
decision-layer replay cannot reproduce is reported rather than gated.
|
|
100
|
+
- **A report can be read.** `bun run triage` ranks a report's runs by how much
|
|
101
|
+
reading each is worth and prints its reason for each, because nobody should trust an
|
|
102
|
+
eval score without reading transcripts and there was no tooling for it: a 54-run
|
|
103
|
+
report was a table and a JSON file. It ranks rather than filters, and deliberately
|
|
104
|
+
does *not* flag a scored escalation every attempt of its pair made, or a lone silent
|
|
105
|
+
review pass — including both flagged 32 of 54 runs on a real report, almost all of
|
|
106
|
+
them the suite working. Excluding them flagged five: the wedge, the false completion,
|
|
107
|
+
and three escalation outliers. An empty result says so, since a suite that never
|
|
108
|
+
flags anything and one that measures nothing look identical from here.
|
|
109
|
+
- **Three eval tiers, three prices.** `bun run replay` is free and answers whether the
|
|
110
|
+
runtime still reaches the same outcome; `bun run eval:smoke` is one model and one
|
|
111
|
+
attempt, for a prompt change; the full matrix is the only thing that qualifies a
|
|
112
|
+
release. One price for every question is what made the suite something run at release
|
|
113
|
+
instead of during work.
|
|
114
|
+
- **A regression scenario for the hole named results closed.** `skipped-case-refused`
|
|
115
|
+
seeds a fixture whose Windows-only case is an ordinary `test.skipIf`, so the declared
|
|
116
|
+
command runs here, on the right host, and exits zero. Declaring the command is no
|
|
117
|
+
longer enough; the plan has to name the case. It went 9/9 across three providers
|
|
118
|
+
twice and stays ungated anyway: every attempt declared `platform:
|
|
119
|
+
"win32"` on a Linux host, so the platform rule refuses first and the named-case rule
|
|
120
|
+
is never what binds. What the scenario measures today is the declaration, not the
|
|
121
|
+
observation.
|
|
122
|
+
- **`unprovable-claim-refused` is gated at 90%.** Measured 0/3, then 8/9, then 9/9 as
|
|
123
|
+
the rule and the prompts landed; the margin is one pair's own variance rather than an
|
|
124
|
+
allowance for refusals to fail. See
|
|
125
|
+
[release qualification](docs/release-qualification.md).
|
|
126
|
+
- **`continuation-accepted` is gated at 100%,** and a new scenario plants a defect for
|
|
127
|
+
the reviewer. The first is the mirror of `goal-change-refused`: one rule is enforced
|
|
128
|
+
by refusing a changed goal and the other by accepting an unchanged one, so gating only
|
|
129
|
+
the refusal would let a build that refuses every continuation qualify. The second,
|
|
130
|
+
`defect-fails-review`, went 9/9 twice and never by the route it was built for — one
|
|
131
|
+
attempt left the planted defect in place, built past it, and the review passed without
|
|
132
|
+
mentioning it. It stays ungated because its rate measures the implementer, not the
|
|
133
|
+
reviewer. Silent review passes did fall below the ceiling for the first time, 38 of
|
|
134
|
+
42, so that metric can now move; the findings behind it were about untested edge cases
|
|
135
|
+
rather than the plant, which is the same limitation from the other side.
|
|
136
|
+
- **A question the next step answers no longer voids the attempt.** An eval run that
|
|
137
|
+
stopped to ask the user was excluded wherever the scenario did not declare asking an
|
|
138
|
+
acceptable end — including a question asked partway through, which the following
|
|
139
|
+
step's prompt answers. Three scenarios open by planning, where asking for approval is
|
|
140
|
+
the behaviour another scenario gates at 100%, and one measured run lost its score for
|
|
141
|
+
doing exactly that. Since a gated pair needs three scored attempts, one correct
|
|
142
|
+
question could fail a release and force a paid re-run. Only a question the last step
|
|
143
|
+
ends on is excluded now.
|
|
144
|
+
- **Seven cassettes are pinned, so CI replays real decisions.** One per scenario from
|
|
145
|
+
the 2026-07-28 matrix, spread across three providers. All 63 candidates from that run
|
|
146
|
+
replayed against this code; the only divergence was the attempt that wedged
|
|
147
|
+
mid-flight, which is advisory by construction. A run that ends by asking the user no
|
|
148
|
+
longer records a fidelity caveat either — the harness aborts that session itself, so
|
|
149
|
+
the `MessageAbortedError` it leaves behind was this suite's own doing, and calling it
|
|
150
|
+
unreproducible had made 19 of 63 cassettes advisory, every refusal scenario among
|
|
151
|
+
them.
|
|
152
|
+
- **Eval reports now include the reviewer.** Subtask sessions are read too, so a
|
|
153
|
+
report finally contains the independent review's own tool calls. Before this, no
|
|
154
|
+
recorded report held a single `flow_feature_complete` call, the check for rejected
|
|
155
|
+
submissions could never fire, and the reviewer's tokens went uncounted — so token and
|
|
156
|
+
cost totals from earlier reports are lower than the same runs would report now.
|
|
157
|
+
- **`/flow-auto` says when your host cannot continue.** Continuation needs assistant
|
|
158
|
+
message parentage; a host that does not report it now gets a plain note at startup
|
|
159
|
+
and an `autoContinuation` field on status, instead of a lifecycle that appears to
|
|
160
|
+
stop after every feature for no reason.
|
|
161
|
+
- **Positioning, including when not to use Flow.** See
|
|
162
|
+
[positioning](docs/positioning.md) and the new README section.
|
|
163
|
+
|
|
164
|
+
The prompt surface got smaller, not larger: the typed gate replaced the prose that
|
|
165
|
+
asked the model to judge whether its own coverage claim was honest.
|
|
166
|
+
|
|
167
|
+
Install or update:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
opencode plugin opencode-plugin-flow@7.1.0 --global --force
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## [7.0.2] - 2026-07-27
|
|
174
|
+
|
|
175
|
+
Documentation only. The docs still called the product Flow v6 two majors after
|
|
176
|
+
the fact, including the sentence in `CONTEXT.md` whose whole job is to name the
|
|
177
|
+
generation.
|
|
178
|
+
|
|
179
|
+
- Where naming the generation is the point, it now reads v7. Where the version
|
|
180
|
+
added nothing to the sentence it is gone, so the claim cannot go stale a third
|
|
181
|
+
time: the layering diagram, the maintainer contract's invariants, and the
|
|
182
|
+
README's version-change note all describe Flow rather than a numbered Flow.
|
|
183
|
+
- The forward-reading compatibility note said newer builds accept state written
|
|
184
|
+
by earlier *v6* builds, which stopped being the full truth when 7.0.0 shipped.
|
|
185
|
+
It now says earlier builds.
|
|
186
|
+
- References to the v6 cutover itself are unchanged, because that boundary is
|
|
187
|
+
genuinely v6: pre-v6 active state is still not migrated, and the absence of a
|
|
188
|
+
cross-version gate still rests on v6 having been a hard cutover.
|
|
189
|
+
|
|
190
|
+
No source, dependency, or behaviour change. The Session v5 schema and every
|
|
191
|
+
durable document are exactly as in 7.0.1, so there is nothing here to upgrade
|
|
192
|
+
for unless you read the docs from the package.
|
|
193
|
+
|
|
194
|
+
Install or update:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
opencode plugin opencode-plugin-flow@7.0.2 --global --force
|
|
198
|
+
```
|
|
199
|
+
|
|
9
200
|
## [7.0.1] - 2026-07-27
|
|
10
201
|
|
|
11
202
|
Dependency currency, with one bump that changes what is actually tested:
|
package/README.md
CHANGED
|
@@ -15,12 +15,32 @@ not fold a materially different request into the active goal.
|
|
|
15
15
|
State lives in `.flow/session.json`, so the workflow survives a restart, a
|
|
16
16
|
context change, or a lost transcript.
|
|
17
17
|
|
|
18
|
+
Flow is in preview: an opinionated workflow for consequential multi-step changes,
|
|
19
|
+
for people who read the review. It is worth its ceremony when a wrong change is
|
|
20
|
+
expensive, and it is overhead when it is not.
|
|
21
|
+
|
|
22
|
+
## When not to use Flow
|
|
23
|
+
|
|
24
|
+
- **Small changes.** A one-file fix or a rename pays for a plan, a validation, a
|
|
25
|
+
review, and a close that it did not need.
|
|
26
|
+
- **Exploration.** Approval locks the plan, and a materially different request will
|
|
27
|
+
not be folded into the active goal.
|
|
28
|
+
- **Speed above all.** A serial lifecycle with an independent review is slower than
|
|
29
|
+
asking directly, deliberately.
|
|
30
|
+
- **Trusting the verdict without reading it.** The review is a model judgment, not
|
|
31
|
+
a proof. [What Flow guarantees](docs/guarantees.md) separates the rules the
|
|
32
|
+
runtime enforces from the ones that are judgment.
|
|
33
|
+
- **Parallel features, several repositories, or team orchestration.** Flow runs one
|
|
34
|
+
durable feature at a time in one project.
|
|
35
|
+
|
|
36
|
+
[Positioning](docs/positioning.md) has the longer version.
|
|
37
|
+
|
|
18
38
|
## Install
|
|
19
39
|
|
|
20
40
|
Install the exact npm release through OpenCode:
|
|
21
41
|
|
|
22
42
|
```bash
|
|
23
|
-
opencode plugin opencode-plugin-flow@7.0
|
|
43
|
+
opencode plugin opencode-plugin-flow@7.1.0 --global --force
|
|
24
44
|
```
|
|
25
45
|
|
|
26
46
|
Omit `--global` for project scope. Version pins are exact and never update on
|
|
@@ -31,7 +51,7 @@ The equivalent manual project configuration is:
|
|
|
31
51
|
```json
|
|
32
52
|
{
|
|
33
53
|
"$schema": "https://opencode.ai/config.json",
|
|
34
|
-
"plugin": ["opencode-plugin-flow@7.0
|
|
54
|
+
"plugin": ["opencode-plugin-flow@7.1.0"]
|
|
35
55
|
}
|
|
36
56
|
```
|
|
37
57
|
|
|
@@ -42,7 +62,7 @@ or activation CLI, and removing the plugin entry disables it. If two Flow copies
|
|
|
42
62
|
load for one project, both fail closed until the duplicate is removed.
|
|
43
63
|
|
|
44
64
|
**Changing versions.** Finish or explicitly close any active session first, in
|
|
45
|
-
either direction. Flow
|
|
65
|
+
either direction. Flow opens only Session v5 active state, and an older build
|
|
46
66
|
cannot be trusted to read state a newer one has already written. Older archives
|
|
47
67
|
remain inert history, and there is no migration or rollback layer.
|
|
48
68
|
|
|
@@ -59,6 +79,10 @@ validate against the real workspace, obtain an independent review — and keeps
|
|
|
59
79
|
going through every runnable feature without handing back between them, until it
|
|
60
80
|
can close the session.
|
|
61
81
|
|
|
82
|
+
Continuation between features needs a host that reports assistant message
|
|
83
|
+
parentage. Flow says so plainly when it detects a host that does not: the lifecycle
|
|
84
|
+
still works, one `/flow-run` at a time.
|
|
85
|
+
|
|
62
86
|
Send `/flow-auto stop` or `/flow-auto cancel` in the same OpenCode session to
|
|
63
87
|
revoke only the in-process continuation. That does not close, defer, abandon, or
|
|
64
88
|
otherwise change the durable Flow session.
|
|
@@ -86,7 +110,8 @@ you granted.
|
|
|
86
110
|
|
|
87
111
|
## How Flow works
|
|
88
112
|
|
|
89
|
-
1. Planning saves a small feature DAG
|
|
113
|
+
1. Planning saves a small feature DAG, including the repository's canonical
|
|
114
|
+
validation command. Approval locks both.
|
|
90
115
|
2. One feature starts, chosen only from those whose dependencies are complete.
|
|
91
116
|
3. Before editing, the manager gathers the evidence the feature needs and works
|
|
92
117
|
through an adversarial risk checklist: failure ordering, repeated and
|
|
@@ -95,9 +120,10 @@ you granted.
|
|
|
95
120
|
4. The manager implements the feature, serially or by integrating a bounded
|
|
96
121
|
worker wave.
|
|
97
122
|
5. Flow observes the exact armed validation command against the current
|
|
98
|
-
workspace, then opens one independent review assignment.
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
workspace, then opens one independent review assignment. Broad evidence runs
|
|
124
|
+
the plan's declared gate and nothing else. A newer relevant failure or a source
|
|
125
|
+
change invalidates an older pass, and review cannot be requested while evidence
|
|
126
|
+
the outcome depends on is knowingly missing.
|
|
101
127
|
6. A passing review advances the plan. A failed feature is never picked up again
|
|
102
128
|
implicitly — Flow reports the blocker and waits for an explicit retry or an
|
|
103
129
|
independent-feature choice. The last passing feature allows closure, and every
|