Commit graph

28 commits

Author SHA1 Message Date
trvon
adf898be19
feat(verify): default --baseline to <path>/.pipe-baseline.json
`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.
2026-09-25 20:11:34 -06:00
trvon
fb055c9978
merge: bring main into the audit and state-map work
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
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
trvon
1779da7e4d
docs: trim the README and split usage, rules, design and development out
The README had grown to 500 lines mixing an overview, a CLI reference,
rule evidence, measurement method, architecture, build notes and
progress notes. It is now a 72-line overview (what pipe is, coverage,
quick start, the rule list, links), and the rest lives in:

- docs/usage.md: commands, flags (checked against `pipe help`), SDK and
  resolution behaviour, CI baselines, verify, fix order, agent briefs,
  remediation policy.
- docs/rules.md: each rule's evidence, the factual-vs-bug distinction,
  how precision and recall are measured, provider and other limits.
- docs/design.md: motivation, architecture, the state-model seam, the
  experimental C++ front end.
- docs/development.md: building and performance, tests, hooks.

Dropped as progress notes: the negative-result and recall-bug
narratives, before/after finding counts, review-round history, and
stale figures (a "5/5 recall" that depends on which branch a repo has
checked out, "84 tests", a duplicated recall.dart line, and the
adjudicator described as fully independent).
2026-09-23 20:40:40 -06:00
trvon
1f60197a15
feat(queries): inventory firestore query surfaces as typed records
Add `pipe queries`, which lists every Firestore query a project can issue:
scope, collection, path pattern, filters with operators and value types,
composites, orderBy, limit, cursors, realtime, aggregation, in-loop, plus a
confidence and the reasons it is not exact. Receivers are matched by static
type and cloud_firestore library URI, never by name.

Queries are followed through chains, local variables (flow-insensitive with
two cuts), fields, getters and one level of helper methods with arguments
bound. An --adapter-config (YAML or JSON) maps declarative query APIs such as
a server-side gateway onto the same schema.

Inventory only: no rules, findings or baseline changes. Every emitted name is
validated against a safe character set so no source text reaches the output.
2026-09-23 18:03:09 -06:00
trvon
4b499c1e21
feat(cpp): experimental C++ front end for scoped-enum state
tool/cpp_front.py is a second front end written against the state model,
not the rules: it reads a compile database with libclang (Homebrew LLVM)
and writes the JSON that `pipe check --model` takes. Every rule,
baseline and gate works on it unchanged.

Mapping, per project `enum class` (identity from clang's resolved AST,
so two enums both named QueryIntent are never confused):
- a reference that produces a value (assignment, atomic store, argument,
  return, initialiser) is an emission; a cast from an int is an indirect
  one;
- a `case`, `==` or `!=` is an observation;
- a busy enumerator written to the method's OWN state, followed by a
  top-level try whose catch neither writes state nor rethrows, is a
  swallowed failure;
- sources the build does not compile are recorded as unresolved, so
  findings naming them drop a confidence step.

One rule-side change, optional and Dart-neutral: an EmissionSite may name
its stateType. rendered-not-emitted attributed indirect emissions by owner
(a bloc owns one state type), so a cast to one enum made "never emitted"
unprovable for every other enum in the same C++ class. With stateType
set, the suppression is scoped to that enum. Dart output is still byte
identical on the fixture and all four dogfood apps.

Run on ~/work/tools/yams (375 translation units from build/debug, 0 clang
errors, about two minutes): 118 state enums, 82 findings. A grep-based
hand check of 13 found 12 factually correct - e.g. the IPC connection FSM
never enters ImplState::ReadingHeader, the downloader never reports
ProgressStage::Verifying though three CLI commands render it,
ExtractScopeType qualifiers are parsed but never acted on - and one false
positive (a nested JSON-parse fallback taken for a stuck busy state),
now excluded by requiring the method's own state and a top-level try.

Bugs found on the way and fixed: ccache/compiler wrappers passed as
inputs, relative -I paths resolved against the wrong directory (7 TUs
silently lost third_party headers), a symlinked path putting every TU
"outside" the project, and an empty compile database producing an empty
"clean" model with exit 0 - all now fail loudly or are handled.

test/cpp_front_test.dart runs the front end on test/fixtures/cpp_state
with positive and negative controls for each rule; skipped without LLVM.
138 tests pass.
2026-09-22 19:16:53 -06:00
trvon
00ef0e965b
fix(cli): close the remaining rough edges in paths, recall and yams
- reject a second project path as a usage error instead of analysing
  only the first
- resolve the default recall manifest from the working directory, else
  from the pipe checkout the binary was built from, so recall works
  outside the repo
- write --write-baseline even when guide --yams fails to persist
- drain the yams child's stdout so a chatty yams cannot block pipe
- report any unexpected exception in one line with exit 2; PIPE_DEBUG=1
  prints the stack trace
2026-09-22 15:26:30 -06:00
trvon
0d891919e9
feat(check): run the rules on a state model written by any front end
Third step of the state-map seam, and the proof that it holds.

stateFlowFromJson rebuilds a StateFlow from its toJson form (computed
members - totals, coverage differences, Riverpod gaps - are recomputed),
and `pipe check --model <file>` runs every rule on such a file instead
of analysing Dart. A front end for another language now only has to
write that JSON to get every rule, --baseline ratcheting and --fail-on
gating. StateUnion.toJson now carries uiReadsBaseFields (only when
true), which the round trip showed it had been dropping.

Checked byte for byte, through a file on disk: `pipe state --format
json` then `pipe check --model` reports exactly what `pipe check` does
on the fixture and on resolved mirrors of nuwayze (102 findings), tick,
dex and word_alive. state_map_roundtrip_test.dart asserts the same in
process (model JSON is idempotent; findings identical; every rule fires,
so the comparison is not vacuous), and model_cli_test.dart covers the
CLI path.

--model refuses --write-baseline: a model does not record whether its
front end read every file, so the baseline could silently be partial -
the hazard the source path already refuses. A malformed model is a
PipeException, not a crash.

134 tests pass.
2026-09-22 14:31:03 -06:00
trvon
17ff523a11
fix(check): lower confidence where unresolved code can hide evidence
check never looked at analyzer errors, so a project that resolved only
partly was analysed as if it were whole. pipe reads names off the syntax
tree, and an unresolved `Foo()` is a method call rather than a
construction, so a dispatch, emission or construction in such a file
simply disappears - and every finding is an absence claim that the
missing evidence could refute.

Found live during this work: with the Flutter SDK unreadable, nuwayze
resolved with 40,079 analyzer errors (package:flutter unresolvable) and
check still reported 102 findings at full confidence, with no warning.

Now, when any analysed file has an unresolved-reference diagnostic
(uri_does_not_exist, undefined_*, creation_with_non_type, ...):
- check warns on stderr and adds a report note naming the first one;
- a finding is lowered one confidence step, with
  data.confidenceLowered = unresolved-references, when an unresolved file
  mentions one of its identity names (event, variant, union, owner,
  provider, member). pipe's evidence is name-based, so a file that never
  names X cannot hide evidence about X; lowering everything for one stray
  error would bury the signal (a first cut did exactly that, taking all
  102 nuwayze findings down for a single unresolved file).

Validated on mirrors of the dogfood repos with a readable SDK (0 analyzer
errors): nuwayze 102 findings identical to the original main, dex 0,
word_alive 1 and tick 1 (the intended riverpod change). The fixture
test adds an unresolved file that constructs NeverDispatched: its
dead-handler finding drops to medium while UnhandledTap, which that file
never names, stays high.
2026-09-22 14:04:32 -06:00
trvon
682be14f97
fix(adjudicate): fail when uncertified, and state its independence limit
The adjudicator printed "controls FAILED" or "NO SIGNAL" and then exited
0, so a CI step reading the exit status took an uncertified run as a
pass. It now exits 1 unless the controls are meaningful and pass, in both
text and json output.

It was also described as independent. Its evidence is independent (its
own regex over source), but the list of unions, variants, events and
owners it checks comes from pipe's `state` output, so a variant pipe
fails to enumerate is never checked. The docstring and README now say so
instead of "independent adjudicator".
2026-09-22 13:30:49 -06:00
trvon
c065576e96
fix(cli): refuse subset baselines and scope verify to --rule
Two more ways a partial scan produced a false claim, the same hazard class
as the --limit and unreadable-file cases verify already refuses:

- `verify --rule X` compared the fresh X-only report against the whole
  baseline, so every accepted finding from any other rule was printed as
  RESOLVED ("these fixes are confirmed") when it had merely not been
  checked. The baseline is now filtered to the selected rules.

- `--write-baseline` (check and guide) wrote whatever the run produced.
  Under --rule or --limit, or with files that could not be analysed, the
  baseline silently omitted every finding outside that subset, and the
  next full `check --baseline` reported them all as new. It now refuses:
  --rule/--limit before analysis, unreadable files after it.

Each is covered by a test that fails against the previous cli.dart
(subset_scan_test.dart, and the unreadable-file case in
unreadable_test.dart). README documents the refusal.
2026-09-22 13:30:41 -06:00
trvon
dd74828e1d
fix(suggest): drop "work them in this order" from the agent plan
7ee8020 added the caution that the order is a score, not a mandate, but the
summary line two lines below still told the agent to work them in order.

The README fix-order example was hand-written with invented counts; it is now
the real output of the plan for the stuck_loading fixture.
2026-09-22 12:22:05 -06:00
trvon
f7eeef7baa
docs: bring the README in line with what pipe does and prints
Drift, corrected:

- The suggest example showed a "fix: Either render ..." line that no current
  remediation produces; it now shows the current agent-plan shape
  (caution line, coverage line, wire-up remediation), marked illustrative
  because it could not be regenerated from one run.
- Common flags: suggest's `text|agent|json` formats, `recall -c` defaulting to
  8 rather than 4, `--[no-]include-generated` defaulting on, and a missing
  --dir being an error.
- `--yams` persists the full markdown report, not the brief.
- The architecture list named recall.dart twice and omitted cli.dart,
  errors.dart, pool.dart and provider_rules.dart (and now excerpt.dart).
- The hardcoded "84 tests" is gone; the recall result and the word_alive
  manifest note are dated "as of 2026-09-20", since both describe branches that
  were unmerged at that date.

Documented from the previous PR: stdout carries only the requested output,
the `coverage` block and one-line coverage note, exit codes (0/1/2/64),
verify's --rule filter and NOT SCANNED category, version-2 baselines and how
version-1 fingerprints are still matched, packing that stops at the first
entry that does not fit, bounded source excerpts, pasteable verify commands,
and the policy's effect on the legend and on suggest's certainty bonus.
2026-09-22 12:22:04 -06:00
trvon
37d4864d54
fix(guide): word each rule's one-liner no stronger than its confidence
Four legend epithets claimed more than their rules establish:

- rendered-not-emitted (medium): "so it is dead code". The rule sees only the
  scanned code and suppresses owners whose helper-method emissions it cannot
  resolve; it now says the branch is probably unreachable.
- riverpod-async-gap: "a failure shows a blank or stale screen". It can; the
  rule downgrades `bool` guard providers to info precisely because it often
  does not.
- notifier-field-unread (medium): "can never affect what the user sees". The
  check is a by-name read search in the scanned code; the finding message and
  the epithet now say "likely".
- provider-created-in-build: "on every rebuild and state is lost". The rule is
  info because rebuild frequency is unknown; it now says "if the widget
  rebuilds".

The README rules table and the rendered-not-emitted and notifier-field-unread
messages are aligned with the same wording.
2026-09-22 12:22:03 -06:00
trvon
5c82518c57
docs: document the command-specific flags the execution sweep found undocumented
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
An execution sweep comparing README flags against what each command accepts found
no documented flag that the CLI rejects, but five working flags the README never
mentioned: index --fail-on-error, suggest --max-actions/--budget,
guide --max-findings/--yams-name, recall --manifest. Each is now described with
its verified behaviour (e.g. index exits 1 with analyzer errors, 0 without), plus
a note that numeric flags reject non-positive-integer values instead of falling
back to a default.
2026-09-20 21:50:41 -06:00
trvon
347f2ef51d
fix(adjudicate): stop the oracle from manufacturing contradictions
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
The independent precision adjudicator reported a pipe defect that did not exist.
Three defects in the checker, all found by chasing its own output against the
source:

1. It matched variant names by UNQUALIFIED name, so `is ExportSuccess` in
   analytics_tab.dart was credited to ArtistStoreManagementState.ExportSuccess -
   the very defect pipe's own per-union scoping had just fixed. Those three files
   reference AdminAnalyticsState, ContentModerationState and
   HelpCenterManagementState, and none of them mentions
   ArtistStoreManagementState, so pipe's finding was correct and the checker's
   "contradiction" was false. Evidence about a variant now requires a file that
   also names the union or its owner - unless the name is declared by only one
   union, in which case it is unambiguous and needs no scoping (event
   construction sites carry no type annotation, and demanding one rejected sound
   evidence: the dispatched control fell from 162/162 to 143/162).
2. Its notion of "rendered" was type-tests only, missing switch-expression arms
   (`ChatListOperationInProgress value =>` has no `case` keyword in Dart 3) and
   base-class payload reads (`state.upcomingBookings`, where BookingsLoaded
   passes `required super.upcomingBookings`). Both are real ways a variant reaches
   the screen; pipe models both.
3. `controls_pass` was `len(control1) == len(rendered) and ...`, which on a
   corpus with no control material is `0 == 0` - a vacuous pass. word_alive
   printed "controls pass: True" with 0/0 and a pristine-looking 100%. The control
   is now three-way (found / unattributable / missing), only `missing` fails, and
   an empty corpus exits NO SIGNAL with precision reported as UNDEFINED rather
   than perfect.

Also fixed: the scoping pass looked for union names in `all_names`, which holds
variant names only, so `union in file_ids` could never be true and every control
silently read 0.

Result on clean nuwayze main: controls 131/131 rendered, 143/162 dispatched (19
unattributable, 0 missing) - controls pass, and precision is 79/79 + 77/77 with
zero contradictions. No pipe defect was found this round; the adjudicator's one
apparent finding was its own.

84 tests still pass; dart analyze clean.
2026-09-20 21:30:14 -06:00
trvon
3c91db2946
fix: act on the external audit - 5 defects, 5 vacuous tests, a real fixture exclusion bug
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
An independent Gemini 3.8 Flash audit of this repo found real problems. Each was
reproduced before being fixed.

Confirmed defects:
- tool/adjudicate.py crashed with KeyError once R001 started grouping variants
  under 'variants' instead of 'variant'. Fixing that exposed a second bug of my
  own: it then divided verified VARIANTS by FINDINGS and reported 216% precision.
  Counts are now coherent (findings vs variant-level checks) and a clean repo
  reports 0/0 rather than a fake 100%.
- GuideCommand called _readPolicy but never registered --policy, so
   exited 64 despite the README documenting it.
- loading-flag-not-reset treated a constructor-invoked method as inheriting the
  loading flag without checking flag.defaultsTrue, so a default-FALSE flag was
  reported as in flight.
- Finding.fingerprint embedded the line number for rules whose only identity was
  , so moving code broke baseline entries.  is now a
  discriminating key; only loading-not-reset, which can emit two findings from one
  method, carries an explicit catchLine.
- suggest grouped unrelated provider-read-in-build findings by file; the group key,
  label and target list now use valueType/call.

Recall defect found while checking the auditor's own claim: UI variant mentions
were collected project-wide by unqualified name, so ExportSuccess - which appears
in FOUR unions on nuwayze - was cross-credited. Mentions are now scoped per union
to files that also name the state type or its owner, which surfaced
ArtistStoreManagementState[ExportSuccess] as a real finding.

Five negative controls could not fail (an event that is never handled can never be
reported as unhandled; a union with no render sites can never be reported as
rendered-not-emitted). Added fixture cases that make each one bite: HandledTap
(handled AND dispatched), PatternState render sites, GuardedCubit (guarded loading
path), QuietCubit._warmUp (constructor-invoked await on a default-false flag).

Root cause of a recurring mystery: this repo EXCLUDED test/fixtures/** from
analysis, which made any analyzer running in the repo context parse the fixture
without resolving its imports and report phantom undefined-class errors. I had
dismissed these as stale cache several times; they were my own exclusion. The
exclude is gone and the fixture governs itself. A new test asserts the fixture has
zero analyzer errors, not merely that it resolves, so IR distortion cannot hide.

84 tests (was 81).
2026-09-20 20:45:58 -06:00
trvon
883c661d7b
feat: default remediation policy is to WIRE IT UP, not to delete
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
An unreachable state, handler or control is usually an unfinished feature rather
than dead weight, so pipe now leads with making it reachable: render the missing
states, add the missing branch, dispatch the event from a control. Removal is the
exception and is worded as needing explicit approval instead of being offered as
an equal alternative.

New FixPolicy (wire-up default | remove), threaded through runChecks,
runProviderRules, analyzeProject and buildGuidance, with --policy on check, guide
and suggest. It changes every remediation that presents a choice, the brief's
decision line, and the dead-handler section heading ('Unreachable handlers - wire
up the control' vs 'Cleanly deletable').

It is a policy, not a finding: the same facts are reported either way.
81 tests, including 6 new ones asserting the default and that remove flips it.
2026-09-20 18:41:07 -06:00
trvon
c391171e6a
fix: attribute typed variable patterns, and stop treating base-field reads as unrendered
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Two real defects found by an audit of nuwayze, both confirmed against the code.

1. Recall: the switch 'case ChatListLoaded value => value' binds the type on a
   DeclaredVariablePattern, not the object pattern ChatListLoaded() this matcher
   looked for. An exhaustive switch was therefore invisible and two variants were
   wrongly reported as never rendered. Both the mention collector and the branch
   collector now handle declared variable patterns.

2. Precision: the UI often reads a union's payload off the BASE class
   (state.currentBooking, state.isRefreshing), so the data reaches the user even
   though the variant is never matched. StateUnion now records uiReadsBaseFields
   and those findings drop to info with an explanation instead of warning. That
   removed 5 false-positive warnings on nuwayze.

3. recall/manifest.json gains status=open|fixed. A fixed case that is reported
   again is a REGRESSION, so repaired bugs become permanent guards against the
   real code instead of deleted expectations. The three bugs fixed earlier today
   (dex x2, word_alive) are now fixed-status guards:
   recall --strict -> 5/5 accounted for, 0 regressions.

nuwayze: 111 findings, 11 warnings (was 16). 75 tests, fixture regression guard
patternView covers the typed-pattern case.
2026-09-20 18:10:56 -06:00
trvon
88ed85b43a
feat: add notifier-field-unread and provider-created-in-build, bound the brief header
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Completes the provider/ChangeNotifier rule set:

- notifier-field-unread: a public getter on a notifier the UI consumes that
  nothing reads, so the state it exposes cannot reach the user. Once per
  notifier. nuwayze: 3 (UserProvider.isInitializing,
  AppLocaleProvider.preferredLocale, and _AgentHubController with 8 members).

- provider-created-in-build: a provider constructed in build without .value, so
  create reruns on every rebuild. Reported once per build method, not once per
  provider: nuwayze's AppProviders.build constructs 45 of them and that is one
  decision, not 45 bugs. Deliberately info, not warning, because a root
  StatelessWidget rarely rebuilds and static analysis cannot tell rebuild
  frequency apart.

Also fixes a real defect the budget test caught: the brief's 'by rule:' line
grew with the rule count and crowded out the findings it summarises. It is now
capped at the top 6 with a '+N more' suffix, the omission note is reserved for
up front so the artifact stays inside its budget, and the overflow message is
shorter.

75 tests. Verified the fixture with pipe's own resolver (0 errors) and validated
that check by injecting a type error into a copy (errors=1).
2026-09-20 17:59:54 -06:00
trvon
2c7bea9ef0
feat: provider package support - model all provider declaration types, add provider-read-in-build
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Adds the provider half of the state-management surface:
- collects every provider-package declaration type (Provider,
  ChangeNotifierProvider, ListenableProvider, ValueListenableProvider,
  FutureProvider, StreamProvider, StateProvider, ProxyProvider family) and
  reports the counts by type in the coverage note
- new rule provider-read-in-build: a Listenable read with context.read or
  Provider.of(listen: false) directly in a build body, so the widget never
  subscribes and can render stale state

447 raw context.read calls in nuwayze reduce to 1 finding. The first four were
hand-checked and every one was a read inside a closure (a BlobListener-style
listener callback or a Selector builder), so the collector now refuses to
descend into nested functions; that costs recall on reads inside Builder and is
recorded in the README rather than hidden.

Also fixes a third fingerprint collision: valueType/call were missing from the
finding identity, so two provider-read-in-build findings in one file shared a
baseline fingerprint. Identity now requires a discriminating key and falls back
to the line only when there is none.
2026-09-20 17:46:30 -06:00
trvon
d87c0bf8e0
perf: group never-matched state markers by marker class instead of one finding per variant
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
The union-observed-but-variant-never-matched tier was one finding per variant,
so 67 findings described the same fix across 21 unions. Group by marker class
instead: failures and loading markers stay warnings because an unrendered
failure means the user gets no feedback, other markers drop to info.

nuwayze: 146 findings -> 108, and the actionable core is now visible: 14
warnings (2 dormant decisions + 12 missing-feedback groups), down from 49.

Also records a negative result in the README: tiering these by 'variant declares
no fields beyond its base' was tried and rejected, because 67/67 qualified and a
signal true of the whole population cannot discriminate.
2026-09-20 17:37:06 -06:00
trvon
5d0a704bc2
perf: collapse a fully unobserved state union into one decision-level finding
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Dogfooding after fixing the three reported bugs showed that high-confidence
emitted-not-rendered findings can be deliberately dormant scaffolding rather
than bugs: on nuwayze both such blocs were already documented as unreachable
in the repository's own action contract, and the CommentsBloc consumer had
been deleted on purpose when a StreamBuilder UI replaced it.

Reporting nine near-identical findings for one product decision buries the
findings that are real regressions, so an unobserved union now yields a single
finding listing its variants, and the remediation says to check the
repository's docs and action contracts before deleting anything.

nuwayze: 159 findings -> 146 (15 variant findings collapse to 2 decisions).
2026-09-20 17:18:51 -06:00
pipe-loop
e9a29077cd perf: AOT build script + measured perf (6.4s -> 0.2s startup, nuwayze 23-29s -> 10.4s) 2026-09-20 16:24:19 -06:00
pipe-loop
b83fca1e30 feat: suggest command - ranked fix order per file with transparent scoring 2026-09-20 16:22:29 -06:00
pipe-loop
3ebc78d1a7 feat: add verify command - prove fixes, not just find problems 2026-09-20 16:07:09 -06:00
pipe-loop
aae2d5e43b test: adjudicate all 159 nuwayze R001/R006 findings with a validated checker (82/82, 77/77) 2026-09-20 16:05:00 -06:00
pipe-loop
f2949dfbfd feat: rule contracts + recall measurement (5/5 real bugs) + real --fail-on gate 2026-09-20 16:00:10 -06:00
pipe-loop
513ce76150 feat: baseline/ratchet support, CI gate over new findings, README with precision table 2026-09-20 14:40:17 -06:00