Document statement-pattern / best_fit_sink11 investigation + stale-build lesson

ober

dc71a2b29cb93c381717dea1bc433e3396795b84

diff --git a/HANDOFF_OPUS_4_8.md b/HANDOFF_OPUS_4_8.md
index 42090b3..98839fb 100644
--- a/HANDOFF_OPUS_4_8.md
+++ b/HANDOFF_OPUS_4_8.md
@@ -404,3 +404,37 @@ propagated sources can safely re-propagate. This is a core-engine rework, not a
 surface rule. lambda1 is unrelated (needs `@RequestParam Map<$TYPE,$TYPE> $VALUE`
 annotated-generic-param method-sig pattern-inside matching + a `$QUERY` focus
 off-by-one).
+
+## Statement-pattern matching / best_fit_sink11 — investigated (2026-06-02)
+
+NOT a generic gap: java statement/decl SEARCH patterns DO match in-process on a
+CLEAN build — `$T $V = $R;` matches `int x = foo();` (count 1), `foo.bar.Sink
+$SINK = ...;` matches a foo.bar.Sink declaration. best_fit_sink11 (handler-off)
+fails for three SPECIFIC reasons:
+1. Its sink uses the typed-metavariable syntax `(foo.bar.Sink $SINK) = ...;`.
+   Built `java-strip-typed-metavars` (mirrors `go-strip-typed-metavars`):
+   `(TYPE $VAR)` -> `TYPE $VAR`. The pattern then matches (`(foo.bar.Sink $SINK)
+   = ...;` count 1). BUT wiring it into `rewrite-metavariables` for java
+   REGRESSES the "Java query string taint" smoke test (the stripper should not
+   touch `query($QUERY,...)` — c0 is `$`, so it returns #f — yet smoke breaks;
+   unexplained, needs a `DBGS` trace inside rewrite-metavariables run under
+   `make test`). Reverted.
+2. Even with the pattern matching, the full taint rule yields 0 — the source
+   `source()` (inside `sink(source())`) must reach a sink that is a DECLARATION,
+   and `$VAR = sink(...)` (an assignment pattern) does not match a
+   variable_declarator. Needs assignment-pattern <-> declarator equivalence +
+   source-contained-in-decl-sink reach.
+3. best-fit dedup (when both sink patterns match, pick the typed-decl).
+
+## CRITICAL TOOLING LESSON (2026-06-02)
+
+Incremental `make build` goes STALE after many revert+rebuild cycles, producing
+SPURIOUS `zero?: #f is not a number` (CLI) / empty results / "variable not bound"
+(in-process harness with missing imports). This wasted a long investigation.
+ALWAYS `make clean && make build` before trusting an ad-hoc measurement, and use
+the full smoke import list in any in-process harness:
+  (semgrep main) (semgrep cli) (semgrep rule) (semgrep result)
+  (semgrep output sarif) (semgrep output text) (std text json)
+The merged features stand (validated via fresh upstream-sweeps, handler-ON,
+162/162) and a CLEAN-build handler-off recount confirms java taint 11/16
+(numbers1, booleans1, get_set_sensitivity, _sensitivity1 match exactly).