---
id: w3/m8/t003
title: QueryLogs honors type/level/statusCode/method/path/instance over the labeled streams
worker: worker3
status: todo
estimate: 30m
depends_on: [w3/m8/t001, w3/m8/t002]
---

## Objective

Close the accepted-but-unhonored gap: the `LogQuery` filter set maps to real LogQL — `type` selects the request/app streams, `level`/`statusCode`/`method` select labels, `path` becomes a line filter (per t001's taxonomy), `instance` selects the pod label m5 already ships. Filters the pipeline can't honor are **removed from the accepted set** (validation error naming them), not silently ignored — the DoD's "nothing silently ignored" rule. Pod-log fallback mode (`BEX_LOKI_URL` unset): structured filters return the documented 4xx/empty behavior — decide with the same honesty rule and document.

## Context

- `lego/backend/internal/logs/` — m5's `LogQuery`→LogQL builder (`loki.go`) is the extension point; `type=request` currently returns an empty page by design (`service.go` comment).
- Render semantics reference: the m13 audit's filter list (`level`/`statusCode`/`method`/`path`/`instance`/`host`/`direction`) — decide `host`/`direction` honestly (honor, or reject-with-error + document).

## Steps

1. Extend the LogQL builder per filter; injection-escape everything (extend m5's escaping tests).
2. Unhonorable filters → typed validation error; docs/ADR006-bex-api.md filter table updated.
3. Fallback-mode behavior decided + documented.

## Files

- `lego/backend/internal/logs/loki.go` (+ `service.go` validation)
- `docs/ADR006-bex-api.md`

## Acceptance criteria

- [ ] Every filter in the accepted set demonstrably narrows results; every removed filter errors with its name; fallback mode behaves as documented.

## Out of scope

- Discovery reads (t004); SSE tail filtering beyond what it already supports (note if drift).
