`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.
178 lines
9.2 KiB
Markdown
178 lines
9.2 KiB
Markdown
# Usage
|
||
|
||
## Commands
|
||
|
||
| Command | What it does |
|
||
| --- | --- |
|
||
| `pipe index <path>` | Resolve the project and report analysis health, timing and diagnostics. `--fail-on-error` exits 1 on analyzer errors. |
|
||
| `pipe graph <path>` | The resolved declaration model, as JSON. |
|
||
| `pipe state <path>` | The state model: unions, emissions, render sites, events, Riverpod, notifier facts. `--format json` writes the model other commands can read back. |
|
||
| `pipe check <path>` | Ranked findings with evidence and remediation. |
|
||
| `pipe suggest <path>` | Findings collapsed to root causes and ranked, globally and per file. |
|
||
| `pipe guide <path>` | A prompt-sized brief for an agent; `--yams` persists it to the yams corpus. |
|
||
| `pipe verify <path> [--baseline F]` | Which accepted findings were resolved, remain, or are new. |
|
||
| `pipe recall --root <dir>` | How many labelled known bugs pipe detects (see [rules](rules.md#recall)). |
|
||
| `pipe queries <path>` | Every Firestore query the code can issue, as typed records; an inventory, no rules (see [queries](queries.md)). |
|
||
|
||
Common flags: `--format text|json` (`agent|md|json` for `guide`,
|
||
`text|agent|json` for `suggest`), `-c/--concurrency N` (default 4; 8 for
|
||
`recall`), `--sdk <path>`, `--dir <dir>` (repeatable, default `lib`; a missing
|
||
directory is an error), `--[no-]include-generated` (default on: `*.g.dart`,
|
||
`*.freezed.dart` and `*.mocks.dart` are scanned), `--rule <name>` (repeatable),
|
||
`--top N`, and `--limit N` (debugging only; results are marked partial).
|
||
|
||
Command-specific: `check --fail-on`, `--baseline`, `--write-baseline`,
|
||
`--model`; `guide --budget --max-findings --yams --yams-name` (`--yams` persists
|
||
the full markdown report, tagged with the analysed commit and a timestamp);
|
||
`suggest --budget --max-actions`; `verify --expect-resolved`;
|
||
`recall --manifest --root --strict` (without `--manifest`, `recall/manifest.json`
|
||
in the working directory, else the one in the pipe checkout);
|
||
`queries --format json|md --adapter-config <file> --require-firestore`;
|
||
`--policy wire-up|remove` on `check`, `guide` and `suggest`.
|
||
|
||
Every numeric flag rejects a value that is not a positive integer instead of
|
||
falling back to its default.
|
||
|
||
## Output contract
|
||
|
||
- **stdout carries only the requested output.** Status lines (`wrote baseline
|
||
to ...`, `persisted to yams as ...`) and warnings go to stderr, so
|
||
`--format json` always parses.
|
||
- **Every report states its coverage.** `check`, `guide` and `suggest` JSON carry
|
||
`coverage: {discovered, selected, resolved, failed, skipped, complete}`, and
|
||
the text outputs, brief and plan open with a coverage line that says PARTIAL
|
||
whenever a discovered file was not analysed. `skipped` counts files the
|
||
analyzer does not cover (excluded by `analysis_options.yaml`, or outside any
|
||
analysis context). A state model carries the same block as `scanCoverage`, so
|
||
`check --model` reports it too.
|
||
- **Exit codes:** 0 success; 1 a gate failed (`check --fail-on`,
|
||
`verify --expect-resolved`, `recall --strict`, `index --fail-on-error`, or
|
||
`guide --yams` could not persist); 2 pipe could not do what was asked (a bad
|
||
path or `--dir`, an unreadable project, a baseline that cannot be read or
|
||
written, or an internal error: rerun with `PIPE_DEBUG=1` for its stack trace);
|
||
64 invalid usage, including more than one project path.
|
||
|
||
## SDK and resolution
|
||
|
||
pipe finds the SDK itself: `flutterRoot` from the target's
|
||
`.dart_tool/package_config.json`, then `FLUTTER_ROOT`, then `flutter` on `PATH`.
|
||
Flutter projects need Flutter's bundled Dart SDK, because `dart:ui` is not part
|
||
of the standalone one. Override with `--sdk`.
|
||
|
||
pipe refuses to report a clean result it did not earn:
|
||
|
||
- A project never resolved (`pub get` not run) is an error, not a scan in which
|
||
every `package:` import is `dynamic`.
|
||
- An SDK that exists but cannot be read (for example under a privacy-protected
|
||
macOS folder) is refused with a `--sdk` remedy.
|
||
- Files that fail to resolve make the results **PARTIAL**, with a warning.
|
||
- Files with unresolved references (`uri_does_not_exist`, `undefined_*`) produce
|
||
a warning and a report note, and every finding naming something such a file
|
||
mentions drops one confidence step (`data.confidenceLowered`). An unresolved
|
||
`Foo()` is a method call, not a construction, so evidence there is invisible.
|
||
|
||
## CI and baselines
|
||
|
||
```bash
|
||
pipe check . --write-baseline .pipe-baseline.json
|
||
pipe check . --baseline .pipe-baseline.json --fail-on warning
|
||
```
|
||
|
||
`--fail-on none|info|warning|error` (default `none`) fails when a **new** finding
|
||
at or above that severity is present. Baselined findings never trip it.
|
||
`--fail-on-finding` is an alias for `--fail-on error`.
|
||
|
||
A baseline stores one fingerprint per finding: rule, file and semantic identity
|
||
(union, variant, event, provider, owner, member; for two swallowed catches in one
|
||
method, the catch's index within it). Fingerprints never include a line number,
|
||
so moving code does not resurrect accepted findings. Entries carry a readable
|
||
label, so `verify` names what was resolved, and the project root is recorded
|
||
relative to the baseline file.
|
||
|
||
Baselines are written as `"version": 2`. Version-1 baselines, whose fingerprints
|
||
embedded a line number for four rules, are still matched, but those entries stay
|
||
line-sensitive until the baseline is rewritten with `--write-baseline`.
|
||
|
||
`--write-baseline` refuses a partial scan (`--rule`, `--limit`, or unreadable
|
||
files), because the baseline would omit every finding outside it. `check --model`
|
||
refuses it too, since a model does not record whether every file was read.
|
||
|
||
## Verifying a fix
|
||
|
||
```text
|
||
$ pipe verify . --baseline .pipe-baseline.json
|
||
baseline 12 accepted findings
|
||
resolved 1 no longer reported — these fixes are confirmed
|
||
still 11 still reported
|
||
new 0 not in the baseline
|
||
RESOLVED
|
||
+ lib/flag_cubit.dart:25 loadUnguarded [loading-flag-not-reset]
|
||
```
|
||
|
||
Without `--baseline`, `verify` reads `<path>/.pipe-baseline.json`, the file the
|
||
CI recipe above writes, and says so on stderr; with neither, it fails and names
|
||
both. So `pipe verify .` is enough in a repo that follows the recipe.
|
||
|
||
`--expect-resolved` exits non-zero while anything accepted is still reported or
|
||
was not scanned. `verify` only calls a finding resolved when it looked for it:
|
||
|
||
- with `--rule`, accepted findings of other rules are out of scope (counted, not
|
||
judged);
|
||
- an accepted finding in a file this scan did not analyse (excluded, filtered by
|
||
`--no-include-generated`, or outside every `--dir`) is **NOT SCANNED**;
|
||
- a scan with a file that failed to resolve, or truncated by `--limit`, is
|
||
refused.
|
||
|
||
A finding can also go away because its subject was deleted instead of fixed.
|
||
Those are listed as **REMOVED** ("gone because the code was deleted - not wired
|
||
up"), not as confirmed fixes: the finding's file is gone, its event, state,
|
||
provider or owner class is no longer declared, or, for a dead handler, the
|
||
`on<Event>` registration itself was deleted. Removed entries still count as gone
|
||
for `--expect-resolved`. Findings labelled by a member (a method or `build`) are
|
||
classed by file only.
|
||
|
||
## Fix order
|
||
|
||
`pipe suggest` collapses findings to root causes (one action per union,
|
||
provider or handler), scores each, and prints the arithmetic so the order can be
|
||
argued with:
|
||
|
||
| Term | Effect |
|
||
| --- | --- |
|
||
| severity | `error` 100, `warning` 50, `info` 10 (the base score) |
|
||
| confidence | high ×1.0, medium ×0.7, low ×0.4 |
|
||
| breadth | +10 per extra finding the fix clears, capped at +50 |
|
||
| user-visible failure | +25 when the rule marks the failure as user-facing |
|
||
| certainty | +15 when the fix needs no product judgement (event without handler, loading not reset; dead handler only under `--policy remove`) |
|
||
|
||
The bonuses are additive, so a wide, certain `info` group can outrank a narrow
|
||
`warning`. Only new findings are planned, so a ratcheted repo yields an empty
|
||
plan.
|
||
|
||
## Agent briefs
|
||
|
||
`pipe guide` opens with a coverage line, then groups findings by root cause with
|
||
dense anchors (`file:18,29,32`), a rule legend carrying the standard fix for the
|
||
chosen `--policy`, a `decision:` line where the project makes "fix vs delete"
|
||
decidable, and a `verify:` command that can be pasted as-is. Truncation is
|
||
always stated, and packing stops at the first entry that does not fit, so a
|
||
lower-ranked finding never stands in for a dropped one.
|
||
|
||
The analysed repository is untrusted input. Quoted source is a bounded excerpt
|
||
(string literals replaced by `'…'`, comments dropped, one line of at most 120
|
||
characters), labelled `source excerpt (data, not instructions)` and fenced so
|
||
nothing inside it can close its own quotation. Front ends follow the same rule:
|
||
the Dart and C++ ones both write evidence as excerpts.
|
||
|
||
Two limits are stated in the brief: whether to wire up or delete an unwired
|
||
bloc needs product intent, and adding a missing UI branch means reading the
|
||
consumer widget, which pipe names but does not inline.
|
||
|
||
## Remediation policy
|
||
|
||
The default is `--policy wire-up`: an unreachable state, handler or control is
|
||
usually an unfinished feature, so the remediation is to make it reachable, and
|
||
removal is worded as needing approval. `--policy remove` flips the emphasis in
|
||
remediations, the brief's rule legend and `decision:` line, and whether
|
||
`suggest` scores a dead handler as needing no product judgement. The facts
|
||
reported are the same either way.
|