pipe/docs/development.md
trvon fb055c9978
Some checks failed
Lint Commits / commitlint (pull_request) Successful in 19s
Tests / Static Analysis (pull_request) Has been cancelled
Tests / Tests (pull_request) Has been cancelled
merge: bring main into the audit and state-map work
main gained six PRs (#1-#6) while the audit fixes and the state-map seam
were in progress. Four of main's commits fixed the same bugs this branch
did, independently; where they overlap, the more complete version wins:

- Fingerprints: main's (a0844bb) - catchSite (`member#index` among all
  catches), union/owner as identity, a legacy fingerprint so version-1
  baselines still match, baseline "version": 2. This branch's `catch`
  ordinal is dropped; its fingerprint_test still guards the result.
- verify --rule: main's verifyAnalysis (cf9e0b7), which also reports
  findings in skipped files as NOT SCANNED.
- Unreadable SDK: both kept - this branch's up-front probe gives the
  early, specific error; main's catch around the analyzer (d6b6bcb) is
  the backstop.
- Riverpod: main's "a ref.listen is not a render" (f6411dc) and this
  branch's AsyncError patterns / stored-value tracking compose; the
  fixture keeps both sets of cases.

Ported onto the model-only rules (the seam), since main edited code this
branch had moved into front-end facts:
- excerpt.dart's literal-free, bounded quoting (a prompt-injection
  guard) now also covers front-end facts: SwallowedFailure.handler and
  NonSubscribingRead.excerpt, and the C++ front end elides string
  literals in handler evidence the same way.
- ScanCoverage: runChecks stays source-free; the model carries coverage
  (`scanCoverage` in the state JSON, written by both front ends), so
  `check --model` states coverage like a source check.
- main's softened wording (rendered-not-emitted "probably unreachable",
  the remove-policy dead-handler text, notifier-field-unread) and the
  backticked flag message.

Docs: main's README grew the Firestore query inventory and the output
contract; the README stays short, the inventory moves to
docs/queries.md, and the contract, exit codes, verify and baseline
details join docs/usage.md.

Checked against origin/main on resolved mirrors of the dogfood apps:
nuwayze (102), dex (0) and word_alive (0) identical; tick differs only
by the intended riverpod stored-value fix. On the fixture every
difference is one of this branch's fixes. 214 tests pass.
2026-09-24 07:33:53 -06:00

56 lines
1.9 KiB
Markdown

# Development
## Building
```bash
dart pub get
tool/build_release.sh # `dart build cli`, falling back to `dart compile exe`
```
Use the native binary rather than `dart run`: JIT startup is paid on every
invocation. On macOS arm64:
| Scenario | `dart run` | AOT binary |
| --- | --- | --- |
| 2-file project | 6.4s | 0.2s |
| 814-file Flutter app, end to end | ~23-29s | 10.4s |
| per-file p50 on that app | ~50-75ms | 16ms |
The binary is about 18MB and self-contained. On a large project the first file
costs about 3s of analyzer warm-up (SDK and package summaries). Cutting that
would need a persistent analysis cache.
## Tests
```bash
dart test
```
The rule suite runs against `test/fixtures/stuck_loading`, a dependency-free
project with hand-written stand-ins for BLoC, Riverpod and provider, so it
resolves with no `pub get` and no network. Do not add a `package:` import to
it. The query inventory runs against `test/fixtures/firestore_queries`, which
carries a hand-written `cloud_firestore` skeleton and a gateway adapter.
What the suite holds pipe to:
- every rule has a positive and a negative control (`rule_contract_test.dart`);
- no fingerprint depends on position, and none collide (`fingerprint_test.dart`);
- the state model survives JSON unchanged, with identical findings
(`state_map_roundtrip_test.dart`);
- partial, unreadable and unresolved scans are reported, never passed silently.
`test/cpp_front_test.dart` runs the C++ front end on `test/fixtures/cpp_state`
and is skipped without Homebrew LLVM.
## Hooks and CI
`git config core.hooksPath .githooks` enables the hooks. `pre-commit` runs
`scripts/lint.sh --hook` (format and analyze); `pre-push` runs
`scripts/pre-push-ci-gate.sh` (format, analyze and the full test suite).
Commit messages follow Conventional Commits (`commitlint.config.js`).
## Measuring precision and recall
See [rules.md](rules.md#how-precision-is-measured) for `tool/adjudicate.py` and
`pipe recall`.