Follow-up corrections after review:
1. DuckDuckGo is NOT fixed. The VPS fallback egress has since been flagged by
DuckDuckGo too (HTTP 202 + challenge markers), so it reports CAPTCHA on both
paths. The contract and script docstring now say so instead of claiming a
fix that had already expired. It stays enabled as best-effort coverage so a
recovery shows up as a contribution.
2. The relationship between silent zeros and the verdict is now explicit in
both the script output and the contract: an enabled expected engine that
contributes zero with no error is REPORTED, not fatal. Only the
<SEARCH_CHECK_MIN_ENGINES> floor and the extraction leg fail the run. This is
deliberate - de-duplication and query-shape make a zero non-probative.
3. Recorded that 'google cse' uses a THIRD PARTY's public search-engine id
hardcoded in the SearXNG build, not a key we own; its quota and availability
are outside our control, and our own free key would need a wrapper (not
built).
VPS forward proxy is now a real service: /opt/fwd-proxy docker compose with
restart: unless-stopped, a healthy healthcheck, and Docker enabled at boot.
Search stack (192.168.68.7) was effectively Bing-only: google served a JS
shell, duckduckgo CAPTCHA'd from the house egress, and every other shipped
engine returned a silent zero. Upgraded SearXNG to 2026.9.23 (same pinned
digest as the image already pulled by other hosts) which uses browser
impersonation, and routed DuckDuckGo through a VPS forward proxy over the
existing WireGuard tunnel via a per-engine 'network'.
Live result: bing, google cse, brave and yandex contribute on every query;
duckduckgo is best-effort via the datacenter egress.
Adds the visibility leg so a future regression cannot be silent:
scripts/search-stack-check.py
* two fixed queries; FAILS when fewer than two engines contribute,
printing contributing engines and every unresponsive_engines entry
* FAILS when Firecrawl extraction returns empty markdown or errors
* reports silent-zero engines explicitly
scripts/contract-run.sh
* maps search-stack-visibility -> search-stack-check.py
search-stack-visibility.prose.md
* contract text, execution model, pass/fail shapes, residual risk
Scheduled hourly at :15 on CT 100 via /etc/cron.d/contract-runner.