Skip to content

docs: add features matrix + 100% test-coverage rule#322

Merged
TaprootFreak merged 1 commit into
developfrom
docs/features-test-coverage-matrix
May 15, 2026
Merged

docs: add features matrix + 100% test-coverage rule#322
TaprootFreak merged 1 commit into
developfrom
docs/features-test-coverage-matrix

Conversation

@TaprootFreak
Copy link
Copy Markdown
Contributor

Summary

Replace the bare README with a full project-overview document modelled on the zk-coins/app README. Adds:

  1. Contributing rule: 100% test coverage on the activated surface is required to merge into develop. Defensive code is exempted via // coverage:ignore-*. Branch protection enforces.
  2. Coverage scope: lib/packages/** + every cubits//bloc/ directory under lib/screens/<feature>/. Widget files render-tested via testWidgets only.
  3. Coverage infrastructure roadmap: honest list of what still needs to land before the rule is enforceable (CI --coverage step, lcov threshold gate, branch protection, build-time feature flags, inline ignore annotations).
  4. Features matrix: every user-facing function, its activation status, the triage decision (mvp / defer / planned), and the tests that currently cover it.
  5. Triage gaps: explicit list of mvp features still below 100%, with links to the in-flight PRs (#319, #320, #321) that close them.
  6. Testing tiers: ties the matrix to the 4-tier model in #314.
  7. Original Getting started section preserved at the end.

Why

The repo has no source of truth for "what does this wallet actually do" or "what is its test-coverage commitment". Tests in test/ exist but are unbound to features — a reviewer cannot tell at a glance whether a feature added in a PR has the required coverage. This document closes that gap.

The coverage rule deliberately mirrors zk-coins/app exactly (same wording, same scope shape) so that reviewers familiar with one project transfer their expectations to the other. The 4-tier testing model is owned by #314; this README references it but does not duplicate it.

What this PR is not

  • It does not wire flutter test --coverage into CI. That is item 1 of the roadmap and will land in a follow-up.
  • It does not add branch protection. That is item 3 of the roadmap.
  • It does not introduce build-time feature flags. That is item 4 of the roadmap and is a prerequisite for the rule being realistic across all features.
  • It does not add any new tests — the in-flight test PRs (#319, #320, #321) own that work.

Until the roadmap items land, the rule is aspirational, explicitly noted as such in the README, and not yet a merge blocker.

Test plan

  • Visual review of the rendered README on GitHub (tables align, all links resolve)
  • Confirm every widget-tagged row points at an existing *_test.dart file in test/
  • Confirm every "in flight" reference points at an open PR
  • Confirm "Coverage scope" wording matches what we want to measure once the lcov gate lands

Document every user-facing function, its activation status, and the tests
that cover it. Adopts the zkCoins-style coverage contract (100% on the
activated surface, CI-enforced, branch-protected) as the target state.

Honest about the current gap: the rule is aspirational until the coverage
infrastructure (CI lcov gate, branch protection, build-time gating) lands.
The roadmap section lists exactly what is missing.

Cross-references the three open PRs that close the largest gaps (#319,
#320, #321) and ties the feature matrix to the 4-tier testing model in
#314.
TaprootFreak added a commit that referenced this pull request May 15, 2026
)

## Summary
Adds 38 unit tests across six previously-untested files in
`lib/packages/utils/` and `lib/packages/wallet/`. Each spec lives in the
mirror path under `test/` per the project convention.

| File under test | Test file | Cases |
| --- | --- | --- |
| `lib/packages/utils/fast_hash.dart` |
`test/packages/utils/fast_hash_test.dart` | 5 |
| `lib/packages/utils/jwt_decoder.dart` |
`test/packages/utils/jwt_decoder_test.dart` | 7 |
| `lib/packages/wallet/payment_uri.dart` |
`test/packages/wallet/payment_uri_test.dart` | 4 |
| `lib/packages/wallet/wallet_account.dart` |
`test/packages/wallet/wallet_account_test.dart` | 7 |
| `lib/packages/wallet/wallet.dart` |
`test/packages/wallet/wallet_test.dart` | 11 |
| `lib/packages/wallet/eip7702_signer.dart` |
`test/packages/wallet/eip7702_signer_test.dart` | 4 |

## What each file covers
- **fast_hash:** FNV-1a determinism, distinct inputs differ, ordering
matters, unicode safety, empty-string offset basis.
- **jwt_decoder:** well-formed payload parsing, segment-count errors,
non-map payload rejection, all three valid base64url padding lengths,
illegal length-mod-4 rejection.
- **payment_uri:** empty-amount short form, dotted and comma-locale
amounts, preservation of decimal precision.
- **wallet_account:** BIP-44 derivation path format, deterministic
Hardhat account #0 address from the standard test mnemonic, distinct
indices, signMessage shape + determinism + sensitivity to addressIndex.
- **wallet:** `SoftwareWallet` walletType + primary/current account
identity + `selectAccount` semantics + id/name mutability; `DebugWallet`
sign refusal.
- **eip7702_signer:** hardware-credential refusal (BitBox cannot sign
EIP-7702), software-credential signing, signature determinism,
nonce-sensitivity.

## Why
Stage 2 of the coverage push tracked in the README features matrix
([#322](#322)). These six
files are pure-Dart with no platform dependencies, so they were the
cheapest meaningful coverage win available — no service mocks, no widget
rendering, no merge-conflict risk with the three in-flight test PRs
([#319](#319),
[#320](#320),
[#321](#321)).

## Test plan
- [x] `flutter analyze` clean on all six new test files (locally on
Flutter 3.38.5)
- [x] `flutter test test/packages/utils/ test/packages/wallet/` — 38 /
38 passing
- [ ] CI green on this branch
- [ ] Spot-check: coverage artifact from #323 (once that lands) shows
non-zero coverage on the six files above
@TaprootFreak TaprootFreak marked this pull request as ready for review May 15, 2026 07:24
@TaprootFreak TaprootFreak merged commit 4638576 into develop May 15, 2026
1 check passed
@TaprootFreak TaprootFreak deleted the docs/features-test-coverage-matrix branch May 15, 2026 07:24
TaprootFreak added a commit that referenced this pull request May 15, 2026
## Summary
Adds `flutter test --coverage` to the existing PR workflow and uploads
the (filtered) `lcov.info` as a CI artifact.

- `flutter test --coverage` replaces the plain `flutter test` invocation
- `coverage/lcov.info` is filtered with `lcov --remove` to drop
generated files (`lib/generated/**`) and `lib/main.dart` so the artifact
reflects only the activated surface
- The filtered report is uploaded as artifact `coverage-lcov` on every
run (`if: always()`)
- `lcov --summary` prints to the CI log so contributors can eyeball the
line/function/branch numbers without downloading the artifact

## Why
Step 1 of the coverage infrastructure roadmap documented in PR #322.
Without measurement, the 100% rule is unverifiable; with measurement but
no threshold, this PR is safe to merge today and lays the foundation for
the threshold gate in a follow-up.

## What this PR is _not_
- Does **not** enforce any threshold. The build still passes regardless
of coverage %. Hard-gating below 100% would block every open PR today
(current coverage ratio ≈ 10%).
- Does **not** add any new tests.
- Does **not** change which files exist in `test/`.

## Test plan
- [ ] CI run completes green
- [ ] `coverage-lcov` artifact is present on the PR's checks page
- [ ] `lcov --summary` line of the CI log shows non-zero coverage on
`lib/packages/**`
- [ ] Filtered report excludes `lib/generated/**`
TaprootFreak added a commit that referenced this pull request May 23, 2026
- fake_async example: add bitbox_flutter.dart import and inline the
  pairedServiceSync idiom so the snippet is copy-paste compilable
- platform-coupled section: real-plugin counterpart is Tier 2/3, not
  Tier 1/2 (Tier 1 is FakeBitboxCredentials by definition); add the
  CONTRIBUTING.md footnote-165 caveat that the annotation is the
  documenting form today
- README: PRs #319/#320/#321/#322/#323 are all merged since
  2026-05-15; replace "in flight"/"landing in"/"extended in" with
  "added via" / "have closed" / "partially covered after"
TaprootFreak added a commit that referenced this pull request May 23, 2026
Tier-1 integration tests stitching SellBitboxCubit → FakeBitboxCredentials
boundary → real RealUnitSellPaymentInfoService → MockClient. The cubit and
the service are both real production code; only the BitBox transport and
the HTTP wire are stubbed. This pins:

* happy path — full swap+deposit ceremony emits two BitBox signs and the
  correct broadcast order/wire-shape (unsignedTx + r/s/v padding). Regression
  class: silently double-signing on the device or swapping leg order.

* cancel mid-swap — FakeBitboxBehavior.cancel propagates as
  SigningCancelledException all the way to SellBitboxError instead of
  being silently accepted as a successful sign (PR #322 bug class).

* disconnect — BitboxNotConnectedException is caught EXPLICITLY by the
  cubit's typed catch and emits SellBitboxBitboxRequired, not a generic
  Error state. Regression class: re-pair screen replaced by raw error
  string (PR #341).

* malformed signature — FormatException from a frame-desync hits the
  generic catch and surfaces as SellBitboxError, NOT mis-classified as a
  BitBox disconnect (would mask sig bugs as UX disconnect prompts).

* deposit-retry — transient 5xx on the deposit broadcast lands the cubit
  in SellBitboxDepositRetry with both signed envelopes preserved; the
  user does not have to re-sign on the device. Regression class:
  funds-at-risk loss of the already-signed swap (PR #338).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant