diff --git a/plans/015-serper-integration-ci-failure-adr.md b/plans/015-serper-integration-ci-failure-adr.md new file mode 100644 index 00000000..10ffc911 --- /dev/null +++ b/plans/015-serper-integration-ci-failure-adr.md @@ -0,0 +1,20 @@ +# ADR 015: Serper Integration CI Failure Triage + +## Status +Blocked + +## Context +The `Serper Integration` GitHub Actions check run fails when executed on pull request branches or fork environments that lack access to the `SERPER_API_KEY` repository secret. Because Serper is a paid provider requiring this API key, its availability is set to false in key-less environments. + +While the query resolver cascade is designed to gracefully fallback to DuckDuckGo, the GHA runner shared IP pool faces heavy rate-limiting and CAPTCHA blocking when attempting unauthenticated/free queries to DuckDuckGo via the Jina Reader proxy (`https://r.jina.ai/https://html.duckduckgo.com/html/?q=...`). This results in a final resolution timeout and raises the error `No query resolution method available`. + +## Root Cause +1. **Repository Secret Access**: The GHA workflow runs integration tests on external pull request/head branches where secrets like `SERPER_API_KEY` are not populated, disabling the Serper provider. +2. **DuckDuckGo/Jina Rate-Limiting**: The fallback DuckDuckGo provider is blocked or rate-limited under GHA shared IP pools, returning a resolution failure and failing the entire query cascade with no active providers left. + +## Mitigation / Action Items (Future Scope) +1. Configure dummy/mocked query responses for the release and integration tests when live keys are absent. +2. Update the `ci-integration.yml` GHA workflow to gracefully skip the live `Smoke test CLI (Serper)` step if `SERPER_API_KEY` is not present, or if it has a masked/empty value. + +## Scope of Current Task +This pre-existing issue is out of scope for the current micro-UX accessibility focus indicators improvement task. This ADR is documented under the `AGENTS.md` triage protocol for unfixable pre-existing failures. diff --git a/plans/GOAP_STATE.md b/plans/GOAP_STATE.md index e3d478b8..571a32b7 100644 --- a/plans/GOAP_STATE.md +++ b/plans/GOAP_STATE.md @@ -103,3 +103,12 @@ Allowed scopes: `resolver, cli, web, ci, docs, deps, security, release, agents` - `.agents/skills/do-wdr-issue-swarm/references/agent-prompt.md` § CRITICAL **RULE**: Never merge, auto-merge, or admin-merge a PR with ANY failing CI check. No exceptions. + +--- + +## Triage State — 2026-07-31 + +### Serper Integration Test Failure +- **Status**: Blocked (Pre-existing on main) +- **Root Cause**: GHA runner lacks access to `SERPER_API_KEY` on PR head branches, and fallback free DuckDuckGo is blocked/rate-limited by the GHA IP pool. +- **ADR Link**: [ADR 015: Serper Integration CI Failure Triage](015-serper-integration-ci-failure-adr.md) diff --git a/web/app/components/History.tsx b/web/app/components/History.tsx index 265d283c..ca4b7a3d 100644 --- a/web/app/components/History.tsx +++ b/web/app/components/History.tsx @@ -106,7 +106,7 @@ export default function History({ onLoad }: HistoryProps) {
- + Help
diff --git a/web/app/components/MetadataBar.tsx b/web/app/components/MetadataBar.tsx index c218f90b..cfa493b3 100644 --- a/web/app/components/MetadataBar.tsx +++ b/web/app/components/MetadataBar.tsx @@ -53,7 +53,7 @@ export function MetadataBar({
diff --git a/web/app/components/ProfileCombobox.tsx b/web/app/components/ProfileCombobox.tsx index fa0e4ee9..2f2c92cf 100644 --- a/web/app/components/ProfileCombobox.tsx +++ b/web/app/components/ProfileCombobox.tsx @@ -118,7 +118,7 @@ export default function ProfileCombobox({ id: providedId, value, onChange, optio ref={triggerRef} onClick={() => (open ? handleClose() : handleOpen())} onKeyDown={handleKeyDown} - className="w-full bg-[#141414] border-2 border-border-muted px-3 py-2 text-left flex items-center justify-between text-[12px] min-h-[44px] hover:border-border-strong focus:border-accent" + className="w-full bg-[#141414] border-2 border-border-muted px-3 py-2 text-left flex items-center justify-between text-[12px] min-h-[44px] hover:border-border-strong focus:border-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" aria-haspopup="listbox" aria-expanded={open} aria-controls={open ? listboxId : undefined} diff --git a/web/app/components/ResultCard.tsx b/web/app/components/ResultCard.tsx index a32403f3..8820cceb 100644 --- a/web/app/components/ResultCard.tsx +++ b/web/app/components/ResultCard.tsx @@ -20,7 +20,7 @@ const ResultHeader = ({ id, title, url, normalizedUrl }: { id: string; title: st href={url} target="_blank" rel="noreferrer" - className="text-accent text-[15px] hover:underline" + className="text-accent text-[15px] hover:underline focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" > {title} @@ -76,7 +76,7 @@ export default function ResultCard({ result, onCopy, onHelpfulToggle, helpful }:
@@ -167,7 +167,7 @@ export default function Sidebar({ const tooltipId = `provider-hint-${provider.id}`; const showHint = needsKey || (provider.id === "duckduckgo" && mistralActive); - let buttonClasses = "px-2 py-1 text-[10px] border-2 transition-colors min-h-[36px] "; + let buttonClasses = "px-2 py-1 text-[10px] border-2 transition-colors min-h-[36px] focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 "; if (isActive) { if (isManual) { buttonClasses += "bg-accent text-background border-accent font-bold"; @@ -227,7 +227,7 @@ export default function Sidebar({ onClick={() => setApiKeysOpen(!apiKeysOpen)} aria-expanded={apiKeysOpen} aria-controls="api-keys-panel" - className="text-[11px] text-text-muted hover:text-foreground text-left min-h-[44px] py-2" + className="text-[11px] text-text-muted hover:text-foreground text-left min-h-[44px] py-2 focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" > API Keys @@ -239,7 +239,7 @@ export default function Sidebar({ type="checkbox" checked={skipCache} onChange={(e) => setSkipCache(e.target.checked)} - className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent" + className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" /> Skip cache @@ -249,7 +249,7 @@ export default function Sidebar({ type="checkbox" checked={deepResearch} onChange={(e) => setDeepResearch(e.target.checked)} - className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent" + className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" /> Deep research @@ -267,7 +267,7 @@ export default function Sidebar({ value={value} onChange={(e) => handleKeyChange(key, e.target.value)} placeholder={hasServer && !value ? "Using server key" : "sk-..."} - className="bg-[#141414] border-2 border-border-muted px-2 py-2 text-[12px] text-foreground placeholder:text-text-dim focus:border-accent min-h-[44px]" + className="bg-[#141414] border-2 border-border-muted px-2 py-2 text-[12px] text-foreground placeholder:text-text-dim focus:border-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 min-h-[44px]" /> );