Skip to content

feat(api): extend Gary header parsing to embeddings, search, and rerank#4

Merged
OriginalGary merged 1 commit intomainfrom
feat/gary-header-contract
May 5, 2026
Merged

feat(api): extend Gary header parsing to embeddings, search, and rerank#4
OriginalGary merged 1 commit intomainfrom
feat/gary-header-contract

Conversation

@OriginalGary
Copy link
Copy Markdown
Owner

Summary

  • parseGaryContext() wired into POST /v1/embeddings, POST /v1/search, and POST /v1/rerank — closing the coverage gap from PR feat(api): Gary header contract — read-only parsing of X-Gary-* headers #3 which only covered handleChat() routes
  • 8 new tests in gary-coverage-extension.test.ts verifying ring buffer capture, null-field handling, entry shape parity, and multi-handler accumulation
  • docs/GRAZE.md §header-contract updated: coverage surface table, architecture rationale for per-handler approach, health endpoint note

Option selected: per-handler injection (Option B)

Investigation findings: No middleware.ts exists in this repo. Next.js middleware runs on Edge Runtime — incompatible with better-sqlite3 (SQLite) used by logAuditEvent and with the Node.js in-process ring buffer (recentGaryContexts). CLAUDE.md explicitly documents "No global Next.js middleware — interception is route-specific." Per-handler is the only viable pattern.

Routes not covered (intentionally): GET /v1/embeddings (model list — read-only, no agent payload), GET /v1/search (provider list), GET /v1/models, /v1/registered-keys (admin), /v1/batches, ws:// WebSocket handshake.

Test coverage

✔ embeddings POST captures gary context in ring buffer
✔ embeddings POST captures null gary fields when no headers sent
✔ search POST captures gary context in ring buffer
✔ search POST captures null gary fields when no headers sent
✔ rerank POST captures gary context in ring buffer
✔ rerank POST captures null gary fields when no headers sent
✔ gary context ring buffer entries from non-chat handlers have same shape as chat entries
✔ all three handlers register entries that accumulate in the shared ring buffer

curl examples

# Embeddings with Gary context
curl -X POST http://localhost:20128/v1/embeddings \
  -H "x-gary-action-id: action-abc123" \
  -H "x-gary-stage: draft" \
  -H "x-gary-playbook: code-pr" \
  -H "x-gary-sensitivity: tier-2" \
  -d '{"model":"text-embedding-3-small","input":"hello"}'

# Search with Gary context
curl -X POST http://localhost:20128/v1/search \
  -H "x-gary-action-id: action-xyz789" \
  -H "x-gary-stage: scout" \
  -d '{"query":"FSIS regulations","search_type":"web"}'

# Rerank with Gary context
curl -X POST http://localhost:20128/v1/rerank \
  -H "x-gary-stage: validate" \
  -d '{"model":"cohere/rerank-english-v3.0","query":"test","documents":["a","b"]}'

# Verify ring buffer captured all three
curl http://localhost:20128/monitoring/health | jq '.garyContextHistory[:3]'

Surprises

The route handlers fail fast (400) on invalid JSON before reaching any DB or credential code, which made testing straightforward: send Gary headers with an unparseable body, verify the ring buffer entry, done. No mocking required.

🤖 Generated with Claude Code

…nk handlers

parseGaryContext() is now called at the entry point of POST /v1/embeddings,
POST /v1/search, and POST /v1/rerank — matching the existing coverage in
handleChat(). Audit ring buffer entries from all four surfaces are identical
in shape. Architecture note recorded in GRAZE.md: per-handler injection is
the only viable pattern because Next.js middleware runs on Edge Runtime,
which is incompatible with the SQLite audit log and the in-process ring buffer.

8 new tests in gary-coverage-extension.test.ts verify that each handler
captures all four Gary fields, that null fields are correctly represented
when no headers are sent, that the ring buffer entry shape matches the chat
handler's shape, and that entries from all three new handlers accumulate in
the shared ring buffer in newest-first order.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@OriginalGary OriginalGary merged commit 81c3c02 into main May 5, 2026
44 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

CI Coverage Report

  • Coverage job: success
  • PR test policy: success

Coverage artifact was not available for this run.

@OriginalGary OriginalGary deleted the feat/gary-header-contract branch May 5, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants