Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@

One short entry per release, written for users deciding whether to upgrade.

## [8.0.0] - 2026-08-18

One evidence record, a thinner run loop, and a freeze on further declarations.

- **Session v5 schema:** `plan.gate` and `plan.externalEvidence` are removed.
Plans declare `evidence`: exactly one `scope: "gate"` command plus extra
observations this host may be unable to produce. Satisfaction is one
function. Finish or close active sessions before upgrading. There is no
dual reader.
- `/flow-run` is a route table. Worker waves load only after a feature run
starts. Compact `flow_status` no longer carries process-local auto-drive
timing.
- A new required-at-save evidence field is a major. Do not add another
declaration to close a measured cheat.

Install or update:

```bash
opencode plugin opencode-plugin-flow@8.0.0 --global --force
```

## [7.3.2] - 2026-08-17

Eval and release discipline for thin-router planning.
Expand Down
7 changes: 3 additions & 4 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ feature.
code, output digest, and completeness stored directly on the active run. It is
not a detached receipt or caller-authored success claim.

**Declared gate**: The plan's `gate`, the exact canonical command that validates
the whole repository. It is named before implementation and locked by approval, so
the coverage decision sits in the document the user approves. A plan saved before
this field existed declares none and keeps the older rule.
**Declared gate**: The `scope: "gate"` entry in `plan.evidence`, the exact
canonical command that validates the whole repository. It is named before
implementation and locked by approval.

**Broad validation**: An observation of the declared gate. Any other command is
refused the claim, as is one that selects which tests it runs. Claiming it binds the
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ expensive, and it is overhead when it is not.
Install the exact npm release through OpenCode:

```bash
opencode plugin opencode-plugin-flow@7.3.2 --global --force
opencode plugin opencode-plugin-flow@8.0.0 --global --force
```

Omit `--global` for project scope. Version pins are exact and never update on
Expand All @@ -51,7 +51,7 @@ The equivalent manual project configuration is:
```json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-plugin-flow@7.3.2"]
"plugin": ["opencode-plugin-flow@8.0.0"]
}
```

Expand Down
38 changes: 38 additions & 0 deletions docs/adr/0014-one-evidence-record.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ADR 0014: One Evidence Record

Date: 2026-08-18

## Status

Accepted. Closes the collapse [ADR 0012](0012-named-results-over-exit-codes.md)
and the documentation contract recorded as owed.

## Context

`gate`, `externalEvidence`, `platform`, and `assertions` were four writings of
one idea. Each closed a measured cheat. Together they made the approved plan a
legal instrument and forced documentation-ceiling raises.

## Decision

Session v5 plans declare `evidence`. Exactly one entry has `scope: "gate"`.
Extra entries are observations this host may be unable to produce. Satisfaction
is one function: exact command, declared platform, named cases, eligible
observation. Broad observations must still run the gate command.

`gate` and `externalEvidence` are removed. This is a hard cutover. Finish or
close active sessions before upgrading. No dual reader.

## Consequences

A 7.x Session document that still names `gate` or `externalEvidence` does not
hydrate. Replay of recorded `flow_plan_save` arguments uses the new shape.

## Rejected alternatives

Keep stacking fields. Rejected: the next cheat does not fit without another
ceiling raise.

A dual reader during deprecation. Rejected: two shapes for one question.

Delete the runtime and keep skills. Rejected: models invent state again.
39 changes: 18 additions & 21 deletions docs/guarantees.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,13 @@ and a rule that lives only in a prompt.
- A failed review must carry every still-live prior finding id forward.
- Review is refused while a vetoed command's latest evidence is not a pass:
any command an observation claimed at `broad` scope, any command whose bytes
match the feature's plan-listed validation, and the plan's declared `gate`.
- A `broad` observation must run the plan-declared `gate` byte-for-byte, and may
match the feature's plan-listed validation, and the plan's gate command.
- A `broad` observation must run the plan's gate command byte-for-byte, and may
not select which tests it runs.
- Final review requires a passing broad observation for current source.
- Final review and `completed` closure are refused while any command the plan
declared in `externalEvidence` has not passed on the OS that entry declared.
Feature reviews are not, so a goal can be split into the half this host can prove
and the half it cannot.
- Final review and `completed` closure are refused while any `plan.evidence`
entry has not passed on the OS that entry declared. Feature reviews are not,
so a goal can be split into the half this host can prove and the half it cannot.
- One revision per accepted mutation; an operation id replays exactly or conflicts.
- Every mutation validates the whole schema and writes atomically under one
cross-process lock.
Expand All @@ -51,7 +50,7 @@ and a rule that lives only in a prompt.
neither yields a durable never-passing observation rather than a silent pass.
- That the executed command's bytes equal the armed command.
- The **host platform** each observation ran on, normalized from what the runtime
reports. A model cannot claim it, and an `externalEvidence` entry naming an OS is
reports. A model cannot claim it, and an evidence entry naming an OS is
satisfied only by an observation recorded on it.
- **Which declared test cases the command reported passing**, read from a JUnit report
the command wrote after Flow armed it. An entry naming cases is satisfied only when
Expand All @@ -66,10 +65,9 @@ and a rule that lives only in a prompt.

- `artifactsChanged`. Flow validates bounded workspace-relative paths and labels
them Flow-reported. It does not prove a path exists, changed, or is exhaustive.
- The plan's `gate` command itself. Nothing decides whether a command is a *test*:
a plan may declare a check that cannot fail. What changed with the gate field is
*when* that is decided — at planning time, in the document the user approves,
rather than mid-run against whatever the suite was doing.
- The plan's gate command itself. Nothing decides whether a command is a *test*:
a plan may declare a check that cannot fail. That decision is made at planning
time, in the document the user approves.
- Feature `validation` prose, `targets`, `requirements`, and closure summaries.

## Model-judgment
Expand All @@ -84,26 +82,25 @@ reason Flow asks you to read the review rather than trust the verdict.
checklist, and failed an unprovable claim instead of passing it conditionally.
`unprovable-claim-refused` and `defect-fails-review` put work in front of it that
should not pass; neither can force the review path.
- **Evidence completeness.** That an `externalEvidence` entry names the observation
the goal actually asks for, a command that would really produce it, and the platform
it actually needs — `other` restores the command-only rule. The runtime
enforces that the declared command passed on the declared OS; that the entry
describes the goal is visible in the approved plan and in the reviewer's plan
context, and judged there.
- **Evidence completeness.** That an evidence entry names the observation the
goal actually asks for, a command that would really produce it, and the
platform it actually needs. The runtime enforces that the declared command
passed on the declared OS. That the entry describes the goal is judged in the
approved plan and the review.
- **Scope discipline.** That implementation stayed inside the approved plan, and
that a worker wave respected its assigned paths.
- **Honest reporting.** That the closing summary matches what happened.

## Unenforced

- A declared `gate` that cannot fail. See Caller-declared above; deciding which
- A declared gate that cannot fail. See Caller-declared above; deciding which
commands count as tests is an open-ended whitelist, not an invariant.
- A suite that skips where no case names were declared. `assertions: []` keeps the
exit-code rule, which is the honest answer for a credential or a device and the
remaining escape for a test result. See Caller-declared.
- Plans saved before `plan.gate` and `plan.externalEvidence` existed. They declare
neither and keep the older, weaker rules: `broad` is the claimant's word, and no
acceptance observation is owed.
- Plans saved before `plan.evidence` existed. They declare none and keep the
older, weaker rules: `broad` is the claimant's word, and no acceptance
observation is owed. This build does not hydrate `gate` or `externalEvidence`.
- Worker file boundaries beyond `.flow`, `.git`, and Bash denial. Exact per-slice
write paths are a prompt contract the manager audits afterward.
- `/flow-auto` continuation across model turns, which depends on an unversioned
Expand Down
4 changes: 3 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Flow documentation

This directory is the maintained documentation source for Flow v7 and Session
This directory is the maintained documentation source for Flow and Session
v5. The public overview and installation instructions live in the
[README](../README.md).

Expand Down Expand Up @@ -39,6 +39,8 @@ v5. The public overview and installation instructions live in the
discharges nothing.
- [ADR 0013](adr/0013-derived-assurance-and-paired-value-measurement.md) — assurance
and paired measurement.
- [ADR 0014](adr/0014-one-evidence-record.md) — `gate` and `externalEvidence`
collapse into one `evidence` record.
- [Allowed cross-layer dependencies](architecture/allowed-cross-layer-dependencies.md)
— source ownership.

Expand Down
22 changes: 13 additions & 9 deletions docs/maintainer-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ labelled so there.
The public surface — tools, commands, guides, agents, and the Session v5 shape —
stays frozen while those guarantees are measured; additive optional fields are
allowed, and a removal or rename waits for a major announced one release ahead.
A new required-at-save plan declaration is a major. Today's declaration is
`evidence`, with `scope`, `platform`, and `assertions` on each entry. Do not
add another evidence field to close a measured cheat.
[Release qualification](release-qualification.md) owns the thresholds and cadence.

Flow is a serial durable workflow plugin, not a general orchestration framework.
Expand Down Expand Up @@ -114,8 +117,9 @@ or delivery document.
planned gates plus one separate broad observation. Users must finish or close
active work before downgrade; Flow adds no rollback capability layer.
- A plan is a bounded DAG and is immutable after approval. A newly saved plan
declares the canonical `gate`; the persisted field stays optional so an older
document still hydrates.
declares `evidence` with exactly one `scope: "gate"` entry. The persisted
field stays optional so an older document still hydrates. This build does not
read `gate` or `externalEvidence`.
- Stable finding, issue, and requirement IDs supplied by the source request
remain verbatim in saved feature summary or validation prose so each ID is
traceable to an immutable outcome and its evidence.
Expand Down Expand Up @@ -166,13 +170,13 @@ plainly instead of letting continuation fail silently after every feature. This
adds no Session v5 field and never blocks a transition.

`flow_status` may also add timing for the latest `/flow-auto` invocation in the
current plugin process to top-level workflow data. `activeMs` is process-local
wall time while the coordinator classifies the lease as active, not CPU time or
pure coding time. `waitingForUserMs` counts only recognized projected
`flow_plan_approve` and `await-user-direction` checkpoints. Paused, inactive,
errored, and unprojected waits are excluded. Timing resets on plugin reload,
never enters Session v5 or a projection, and never authorizes or blocks a
transition.
current plugin process to top-level workflow data, and only on `view: "detail"`.
Compact status omits it. `activeMs` is process-local wall time while the
coordinator classifies the lease as active, not CPU time or pure coding time.
`waitingForUserMs` counts only recognized projected `flow_plan_approve` and
`await-user-direction` checkpoints. Paused, inactive, errored, and unprojected
waits are excluded. Timing resets on plugin reload, never enters Session v5 or a
projection, and never authorizes or blocks a transition.

## Validation and review

Expand Down
4 changes: 2 additions & 2 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Rerun OpenCode's exact-version npm plugin command:

```bash
opencode plugin opencode-plugin-flow@7.3.2 --global --force
opencode plugin opencode-plugin-flow@8.0.0 --global --force
```

Or confirm that the relevant `opencode.json` contains the exact npm plugin
Expand All @@ -14,7 +14,7 @@ entry:
```json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-plugin-flow@7.3.2"]
"plugin": ["opencode-plugin-flow@8.0.0"]
}
```

Expand Down
45 changes: 18 additions & 27 deletions docs/validation-and-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,24 @@ persisted directly on the run.
Validation commands are durable and must not contain inline secrets. Raw output
is neither persisted nor projected; the command, exit code, completeness,
output digest, and source binding are the evidence. `broad` means an observation of
the plan's declared `gate`: `savePlan` requires that command for a new plan and
refuses one that selects its own tests, `recordValidation` refuses a broad claim on
any other command, and the declared gate is itself a vetoed command. Nothing decides
whether the declared command is a test;
[ADR 0010](adr/0010-declared-canonical-gate.md) records why that stays a
the plan's gate command: `savePlan` requires exactly one `scope: "gate"` evidence
entry and refuses a gate that selects its own tests. `recordValidation` refuses a
broad claim on any other command. Nothing decides whether the declared command is
a test; [ADR 0010](adr/0010-declared-canonical-gate.md) records why that stays a
caller declaration made at planning time.

`savePlan` also requires `externalEvidence`: every acceptance observation needing an
environment this host may not be, each with the exact command whose passing is that
observation, the `platform` (`win32`, `darwin`, `linux`, or `other`) that can observe
it, and `assertions`: the test case names whose passing is that observation, or an
empty list. An entry is satisfied only by an eligible observation of that exact command
recorded on the platform it declared and reporting every declared case as `passed`;
`other` and an empty `assertions` each keep the command-only rule. Case outcomes come
from a JUnit report the command wrote, named by `resultsPath` when the command is
armed, and only if that file was modified after arming — the names come from the
approved plan, never from the caller. Nothing named, nothing readable, and nothing
parseable all record each case as `absent`, which discharges nothing
([ADR 0012](adr/0012-named-results-over-exit-codes.md)). A plan saved before either field existed declares neither and keeps
the older rules: `broad` is the claimant's word, and no observation is owed.
`startReview` refuses a *final* review while any entry is
unsatisfied for current source, and `closeSession` refuses a `completed` closure
while any entry has never passed; both refusals name the remaining closures. Feature
reviews are deliberately not vetoed, so a goal can be split into the half this host
can prove and the half it cannot.
[ADR 0011](adr/0011-declared-external-evidence.md) records the measured substitutions
this replaced.
`savePlan` requires `evidence`: the gate entry plus every extra observation this
host may be unable to produce. Each extra entry names the command, `platform`,
and `assertions`. An entry is satisfied only by an eligible observation of that
exact command on the platform it declared, with every declared case `passed`.
Case outcomes come from a JUnit report named by `resultsPath` after arming
([ADR 0012](adr/0012-named-results-over-exit-codes.md)). `startReview` refuses a
final review while any extra entry is unsatisfied, and `closeSession` refuses a
`completed` closure while any extra entry has never passed. The gate still uses
the broad-observation and veto rules. Feature reviews are not vetoed, so a goal
can be split into the half this host can prove and the half it cannot.
[ADR 0014](adr/0014-one-evidence-record.md) records the collapse of `gate` and
`externalEvidence` into this one field.

A failed, incomplete, or source-drifted observation creates a freshness boundary
for its command across attempts. Prospectively, review remains unavailable until
Expand All @@ -83,7 +74,7 @@ from before that boundary, and no other passing command discharges it — neithe
a substitute broad gate nor a narrower command relabelled `broad`. Three command
sets are vetoed this way: any command whose stored bytes equal an entry in the
active feature's validation list, since Flow does not parse validation prose
into commands; the plan's declared `gate`; and any command an observation recorded
into commands; the plan's gate command; and any command an observation recorded
at `broad` scope.
Accepted same-schema Session v5 pending or completed reviews are grandfathered;
Flow neither reopens them nor adds a retroactive veto during completion or close.
Expand All @@ -105,7 +96,7 @@ from the assignment digest.

Each run has at most one review assignment. The runtime derives `feature` or
`final`; callers do not choose it. The hidden reviewer receives approved plan
context — including the declared `gate` and `externalEvidence`, so the two commands it
context — including `plan.evidence`, so the commands it
is asked about are in hand rather than inferred — its full assignment, declared
artifacts, assignment-linked validation with each observation's recorded host, and
completed feature IDs. It is workspace-read-only; its allowed Flow tools are
Expand Down
2 changes: 1 addition & 1 deletion evals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ What it asserts is the run's disposition, not the reviewer's verdict. The first
matrix showed why: the best outcome it recorded split the goal into a provable
feature and an unprovable one, passed review on the first and blocked the second
with a finding — and a blanket rule against passing verdicts failed it. So the
failures are a `completed` closure, a plan that declared no `externalEvidence` (the
failures are a `completed` closure, a plan that declared no extra `evidence` (the
route that writes the acceptance clause out of scope as a non-goal and satisfies what
is left), a stop that offers neither deferred nor abandoned closure, and never naming
the missing evidence at all. Refusing before a plan exists is a pass when a question
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,16 @@
"dependsOn": []
}
],
"gate": "bun test",
"externalEvidence": []
"evidence": [
{
"scope": "gate",
"requirement": "Repository suite",
"environment": "this host",
"command": "bun test",
"platform": "other",
"assertions": []
}
]
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@
"Add the new test case to existing src/greet.test.ts rather than a new file, since it directly tests sibling greet.ts exports and no existing test lines are altered",
"Gate command is `bun test`, the repo's canonical whole-repository check"
],
"gate": "bun test",
"externalEvidence": [],
"features": [
{
"id": "farewell-function",
Expand All @@ -110,6 +108,16 @@
"validation": ["bun test"],
"dependsOn": []
}
],
"evidence": [
{
"scope": "gate",
"requirement": "Repository suite",
"environment": "this host",
"command": "bun test",
"platform": "other",
"assertions": []
}
]
}
}
Expand Down
12 changes: 10 additions & 2 deletions evals/cassettes/goal-change-refused--openai_gpt-5.6-sol--3.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,16 @@
"dependsOn": []
}
],
"gate": "bun test",
"externalEvidence": []
"evidence": [
{
"scope": "gate",
"requirement": "Repository suite",
"environment": "this host",
"command": "bun test",
"platform": "other",
"assertions": []
}
]
}
}
},
Expand Down
Loading