`pipe verify .` failed with "verify needs --baseline" even in a repo
whose baseline sits where the README's CI recipe writes it. nuwayze's
scripts/testing/pipe_state_flow_gate.sh commits exactly that file,
.pipe-baseline.json at the repo root, so every verify there had to
repeat the path.
Without --baseline, verify now reads <path>/.pipe-baseline.json when it
exists and says so on stderr ("pipe: no --baseline given; using ..."),
so a run never silently picks a file nobody named. With neither, the
error names both remedies: pass --baseline, or write the conventional
file with `pipe check <path> --write-baseline <path>/.pipe-baseline.json`
before the fix. pipe had no baseline-name constant; defaultBaselineName
is now the one place it is spelled.
Tests (test/verify_default_baseline_test.dart): an explicit --baseline
wins and announces nothing; the conventional file is used and
announced; with neither the error carries both remedies; and end to
end, `pipe verify <copy>` against a baseline written at the copy's
root reads it (--expect-resolved fails on the 28 still-present
findings). README and docs/usage.md show the shorter form.
On nuwayze-w3, `pipe verify /Users/.../nuwayze-w3` with no flag reads
its .pipe-baseline.json (65 accepted findings). 225 tests pass.
76 lines
3.7 KiB
Markdown
76 lines
3.7 KiB
Markdown
# pipe
|
|
|
|
Static state-flow analysis for Dart and Flutter apps. `pipe` maps how state
|
|
moves through an app's state management and reports the breakages that make it
|
|
behave worse than the code suggests: a spinner that never stops, an error the
|
|
user never sees, a tap that does nothing.
|
|
|
|
It is built to guide agents and reviewers on large codebases, not to score
|
|
style. Every finding carries `file:line` evidence, a confidence, a severity and
|
|
a remediation, and every report states how much of the project it covered.
|
|
|
|
## Coverage
|
|
|
|
| State management | Support |
|
|
| --- | --- |
|
|
| BLoC / Cubit (`on<Event>`, `emit`, sealed, abstract, enum or freezed unions) | yes |
|
|
| Single state class with a `bool loading`-style flag (`copyWith`) | yes |
|
|
| Riverpod (`FutureProvider`, `StreamProvider`, `NotifierProvider`, `.family`, ...) | yes |
|
|
| `provider` + `ChangeNotifier` | yes, with [limits](docs/rules.md#provider-and-changenotifier) |
|
|
| C++ `enum class` state (experimental, via libclang) | [see design](docs/design.md#c-front-end-experimental) |
|
|
| Firestore query inventory (`pipe queries`, no rules) | [see queries](docs/queries.md) |
|
|
| Navigation, layout, theming | no |
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
dart pub get
|
|
tool/build_release.sh # prints the binary's path under build/
|
|
# below, `pipe` is that binary on your PATH (or `dart run bin/pipe.dart`)
|
|
|
|
pipe index <path> # can the project be analysed?
|
|
pipe check <path> # ranked findings
|
|
pipe suggest <path> # what to fix first, per file
|
|
pipe guide <path> --format agent # a brief to paste into an agent prompt
|
|
pipe queries <path> # every Firestore query, as typed records
|
|
```
|
|
|
|
In CI, accept today's findings once and fail only on new ones:
|
|
|
|
```bash
|
|
pipe check . --write-baseline .pipe-baseline.json
|
|
pipe check . --baseline .pipe-baseline.json --fail-on warning
|
|
pipe verify . --expect-resolved # after a fix; reads .pipe-baseline.json
|
|
```
|
|
|
|
## Rules
|
|
|
|
| Rule | Meaning |
|
|
| --- | --- |
|
|
| `emitted-not-rendered` | A state is emitted but no UI code matches it, so the user never sees it. |
|
|
| `rendered-not-emitted` | A UI branch no emitted state can reach: dead UI. |
|
|
| `loading-not-reset` | An in-progress state whose failure path never resolves, so the spinner sticks. |
|
|
| `loading-flag-not-reset` | The same, for a `bool loading` flag left set after an error. |
|
|
| `event-without-handler` | A dispatched event with no `on<Event>`, so the interaction does nothing. |
|
|
| `dead-handler` | An `on<Event>` that nothing dispatches or constructs. |
|
|
| `riverpod-async-gap` | An async provider read in the UI whose error or loading state is never handled. |
|
|
| `notifier-never-notifies` | A `ChangeNotifier` method changes observable state without notifying. |
|
|
| `notifier-inert-consumer` | A consumed notifier that never notifies, so its consumers never rebuild. |
|
|
| `provider-read-in-build` | A `Listenable` read without subscribing inside `build`, so it can render stale. |
|
|
| `notifier-field-unread` | A public member of a consumed notifier that nothing reads. |
|
|
| `provider-created-in-build` | A provider constructed in `build`, so its state is recreated on rebuild. |
|
|
|
|
Measured precision, recall and the limits of each rule are in
|
|
[docs/rules.md](docs/rules.md).
|
|
|
|
## Documentation
|
|
|
|
- [Usage](docs/usage.md): commands, flags, SDK discovery, CI ratcheting,
|
|
verification, fix order, agent briefs.
|
|
- [Rules](docs/rules.md): what each rule claims, the evidence behind it, and how
|
|
precision and recall are measured.
|
|
- [Firestore queries](docs/queries.md): the query inventory, its schema and
|
|
adapter config.
|
|
- [Design](docs/design.md): why pipe exists, how it is built, the state-model
|
|
seam, and the experimental C++ front end.
|
|
- [Development](docs/development.md): building, performance, tests and hooks.
|