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.
4.1 KiB
kind, name, description, version
| kind | name | description | version |
|---|---|---|---|
| function | search-stack-visibility | Makes the shared search stack observable. Every agent reaches one SearXNG instance (http://192.168.68.7:8888) and one extraction service (Firecrawl, http://192.168.68.7:3002). Before this check the stack could degrade to a single engine, or an enabled engine could return nothing at all, without any error surfacing anywhere. This contract runs scripts/search-stack-check.py, which: * runs two fixed queries against SearXNG and FAILS when fewer than two engines contribute, printing the contributing engines and every unresponsive_engines entry; * checks extraction by scraping a known page through Firecrawl and FAILS when the returned markdown is empty or the request fails; * reports every silent-zero engine explicitly (enabled, not in unresponsive_engines, contributed no results). Multi-engine post-fix state (2026-09-25): bing, google cse, brave, yandex contribute on every query; duckduckgo is best-effort via a VPS egress network and is expected to regress when DuckDuckGo flags the datacenter IP. SCHEDULED: /etc/cron.d/contract-runner on CT 100 (abiba), hourly at :15, via scripts/contract-run.sh search-stack-visibility. Logs land in /var/log/contract-runs/. A failure also raises a firstmate inbox note. | 1.0.0 |
Purpose
The fleet has exactly one search endpoint and one extraction endpoint. If either degrades, every agent silently loses capability at the same moment. The failure mode this contract exists to close is silent degradation: a query that still returns a page of results while all but one engine have stopped contributing, or an enabled engine that answers with zero results and raises no error.
Execution model
The contract is a host-scheduled check, not an agent workflow. It is driven by
scripts/contract-run.sh search-stack-visibility from
/etc/cron.d/contract-runner on CT 100. contract-run.sh resolves the
mapping to scripts/search-stack-check.py, runs it under a timeout, writes a
timestamped log to /var/log/contract-runs/, and on non-zero exit raises a
firstmate inbox note through bin/fm-inbox.sh.
What passing looks like
$ bash scripts/contract-run.sh search-stack-visibility
Expected engines, enabled (4): ['bing', 'brave', 'google cse', 'yandex']
queries: 'proxmox backup server' -> contributing: bing, brave, google cse, yandex
unresponsive: (none)
'python asyncio tutorial' -> contributing: bing, brave, google cse, yandex
unresponsive: (none)
EXTRACTION: 71016 chars of markdown returned
VERDICT: PASS -- multiple engines contributing, extraction healthy
What failing looks like
- A query whose results come from fewer than
SEARCH_CHECK_MIN_ENGINESengines (default 2) fails and names the engines that did contribute. - An extraction request that errors or returns empty markdown fails.
- An enabled, expected engine that contributed nothing without reporting an
error is printed under
SILENT-ZERO ENGINES REPORTED.
Configuration
Environment overrides (see the script docstring for the full list):
| Variable | Default | Meaning |
|---|---|---|
SEARXNG_URL |
http://192.168.68.7:8888 |
SearXNG base URL |
FIRECRAWL_URL |
http://192.168.68.7:3002 |
Firecrawl base URL |
SEARCH_CHECK_QUERIES |
proxmox backup server,python asyncio tutorial |
fixed queries |
SEARCH_CHECK_MIN_ENGINES |
2 |
minimum contributing engines per query |
SEARCH_CHECK_ENGINES |
bing,brave,google cse,yandex,duckduckgo |
engines a silent zero is reported for |
SEARCH_CHECK_EXTRACT_URL |
Wikipedia Proxmox article | page used for the extraction leg |
Known residual risk
DuckDuckGo is reached through a forward proxy on the VPS
(10.10.10.1:3128, WireGuard) because the house egress IP is CAPTCHA'd. The
VPS is a datacenter address and DuckDuckGo may flag it, so DuckDuckGo is
coverage, never a required engine. When it regresses it appears either in
unresponsive_engines (an explicit error) or under the silent-zero report;
neither fails the check, but both are visible.