fix(guide,suggest): word agent guidance no stronger than the evidence #2

Merged
trevon merged 13 commits from docs/honest-agent-guidance into main 2026-09-22 21:19:58 +00:00
Owner

Stacked on #1; review after it. Retarget to main once it merges.

Problem

Agent-facing text claimed more than the rules support:

  • The rule legend ignored --policy and led with removal under the default wire-up policy.
  • Epithets were stronger than rule confidence ("dead code", "can never affect", "state is lost").
  • "Safe even without product context" / "nothing references it" ignored that only --dir lib is scanned.
  • suggest --format agent said "Work them in this order" with no caution, scored wiring up a dead handler as needing no product judgement, and grouped fixes named only the first event.
  • verify: hints dropped the path and --baseline, so an agent that followed one saw accepted findings return and concluded its fix failed.
  • The README, PR template, CODEOWNERS, commitlint, and pre-push skip variable had drifted from the code.

Solution

Remediation text now follows --policy. Epithets are softened to match rule confidence, and scope claims are tied to the scanned directories. The agent plan opens with a caution ("Order is a score, not a mandate"), and grouped actions name every target. Verify hints are paste-ready commands. The README fix-order example is now real output from the stuck_loading fixture instead of a hand-written sample. Process files are aligned: security is allowed by commitlint, PIPE_SKIP_PREPUSH_GATE is used everywhere, and dead CODEOWNERS and template items are removed.

Rule changes

  • No rule behaviour change. Under wire-up, suggest no longer gives dead handlers the +15 "no product judgement" bonus.

Release Note

  • Agent briefs and plans word fixes according to --policy, scope their claims to what was scanned, and emit verify commands that can be pasted as-is.

Breaking Changes

  • None

Tests

  • Unit (policy, suggest, guide). scripts/lint.sh format|analyze|test: clean, 142 passed.

Documentation

  • README updated (formats, defaults, file list, coverage, exit codes, real example)
  • CHANGELOG: generated by release-please

AI usage

  • Written with Claude Code, verified with the full local gate.
Stacked on #1; review after it. Retarget to `main` once it merges. ## Problem Agent-facing text claimed more than the rules support: - The rule legend ignored `--policy` and led with removal under the default wire-up policy. - Epithets were stronger than rule confidence ("dead code", "can never affect", "state is lost"). - "Safe even without product context" / "nothing references it" ignored that only `--dir lib` is scanned. - `suggest --format agent` said "Work them in this order" with no caution, scored wiring up a dead handler as needing no product judgement, and grouped fixes named only the first event. - `verify:` hints dropped the path and `--baseline`, so an agent that followed one saw accepted findings return and concluded its fix failed. - The README, PR template, CODEOWNERS, commitlint, and pre-push skip variable had drifted from the code. ## Solution Remediation text now follows `--policy`. Epithets are softened to match rule confidence, and scope claims are tied to the scanned directories. The agent plan opens with a caution ("Order is a score, not a mandate"), and grouped actions name every target. Verify hints are paste-ready commands. The README fix-order example is now real output from the `stuck_loading` fixture instead of a hand-written sample. Process files are aligned: `security` is allowed by commitlint, `PIPE_SKIP_PREPUSH_GATE` is used everywhere, and dead CODEOWNERS and template items are removed. ## Rule changes - [x] No rule behaviour change. Under wire-up, suggest no longer gives dead handlers the +15 "no product judgement" bonus. ## Release Note - Agent briefs and plans word fixes according to `--policy`, scope their claims to what was scanned, and emit verify commands that can be pasted as-is. ## Breaking Changes - [x] None ## Tests - [x] Unit (policy, suggest, guide). `scripts/lint.sh format|analyze|test`: clean, **142 passed**. ## Documentation - [x] README updated (formats, defaults, file list, coverage, exit codes, real example) - [ ] CHANGELOG: generated by release-please ## AI usage - [x] Written with Claude Code, verified with the full local gate.
`ruleFix` was a constant map that ignored `--policy`. Under the default
wire-up policy the brief's legend still said "Remove the dead handler, or
dispatch the event" and "delete the variant and its emits" as equal choices,
directly above findings whose remediation said removal needs explicit
approval - the legend contradicted the policy the README describes.

ruleFixFor(policy) now returns the legend's fixes for a policy: under wire-up
the choice-bearing rules (emitted-not-rendered, rendered-not-emitted,
event-without-handler, dead-handler, notifier-field-unread) lead with making
the code reachable and say removal needs explicit approval; under remove they
keep offering both. `ruleFix` remains, as the default policy's map.
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.
The brief said "nothing outside the bloc references it" and, under
--policy remove, that removing a dead handler "is safe even without product
context", while the scan defaults to --dir lib. The dead-handler finding
itself was scoped in f0fc57e; these three statements were not. A handler
dispatched only from test/ still read as safe to delete.

The decision line and the dead-handler section now say "nothing under <dirs>"
and tell the reader to rule out unscanned directories (rerun with --dir)
before wiring or removing; the remove-policy remediation in rules.dart says
the same. buildGuidance takes the scanned directories, which the guide
command passes from the project.
Three ways the agent plan claimed more than it knew:

- It opened with "Work them in this order" and nothing else. It now opens with
  "Static heuristics; confirm each against the cited file. Order is a score,
  not a mandate."
- Under the default wire-up policy a dead handler still scored "no product
  judgement needed (+15)". Wiring one up means deciding which control should
  dispatch the event, which is product judgement; the bonus now applies only
  under --policy remove, and buildWorkPlan takes the policy.
- A grouped action used its first finding's remediation, so a union with five
  dead handlers said "dispatch LoadItems from the UI" and nothing about the
  other four. A group now gets an action built from all of its targets
  ("dispatch each of A, B, C ..."), and targets include the variant and member
  lists that grouped findings carry.
Every brief entry and plan action ended with `verify: pipe check --rule X`.
Pasted, that checks the current directory, over lib/ only, against no
baseline - not the run that produced the finding. Run from anywhere but the
project root, or after a scan with --dir or --baseline, it answered a
different question.

The hint is now built by checkCommand(): `pipe check <root> --rule X`, plus
`--baseline <path>` and every `--dir` when the run used them, with paths
shell-quoted when needed.
The markdown report's summary line counted every finding while its heading and
the severity counts beside it counted only new ones, so a fully baselined run
read "20 findings ({error: 0, warning: 0, info: 0})" above "## Findings (0)".
The summary now counts new findings and notes how many are baselined.

Also: loading-flag-not-reset rendered its flag as `SettingsState`loading``, a
missing `.` that produced two adjacent code spans. It now reads
`SettingsState.loading`.
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.
- The pre-push hook skipped on PIPE_SKIP_PREPUSH_CI_GATE while the gate
  script it runs skipped on PIPE_SKIP_PREPUSH_GATE, so each name worked in only
  one place. Both now use PIPE_SKIP_PREPUSH_GATE.
- The PR template asked for a hand-written CHANGELOG entry; release-please
  generates CHANGELOG.md from commit subjects, so the item now says that. It
  also asked for a "Stability note" the repo does not have; removed.
- CODEOWNERS listed /docs/**, which does not exist.
- commitlint accepted `merge` but rejected `security`, a type
  release-please-config.json maps to its Security section; `security` is now
  allowed.
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.
trevon force-pushed docs/honest-agent-guidance from 1d2eae16f6 to dd74828e1d 2026-09-22 18:23:00 +00:00 Compare
trevon changed target branch from fix/verify-soundness-and-injection to main 2026-09-22 18:24:12 +00:00
Merge branch 'main' into docs/honest-agent-guidance
Some checks failed
Lint Commits / commitlint (pull_request) Successful in 16s
Tests / Static Analysis (pull_request) Has been cancelled
Tests / Tests (pull_request) Has been cancelled
c850ce42c8
Merge branch 'main' into docs/honest-agent-guidance
Some checks failed
Lint Commits / commitlint (pull_request) Successful in 16s
Tests / Static Analysis (pull_request) Has been cancelled
Tests / Tests (pull_request) Has been cancelled
d1b430b795
trevon merged commit 9453853260 into main 2026-09-22 21:19:58 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
trevon/pipe!2
No description provided.