# RustProxy 0.26.2 implementation note ## Scope Version 0.26.2 is a UI/query follow-up to the Stored Logs explorer. It does not change SQLite schema 8 or the saved proxy configuration format. The release: - combines Stored Logs and Live Logs under one top-bar Logs menu; - replaces the fixed Stored Logs filter matrix with an optional source selector, one bounded field-query input and a page-size selector; - discovers selectable table columns from parsed record fields; - parses RustProxy RAW error-log lines into basic fields; - removes the configured-file inventory while retaining the source selector as an optional index-like scope; - moves column configuration to the upper-right table toolbar; - uses arrow symbols for backend sort direction. ## Stored Logs query syntax The `q` parameter remains bounded and now accepts clauses separated by whitespace or explicit `AND`. Supported forms include: ```text req: GET AND !country: Poland status:>=500 AND path:/api/* error:"connection reset" ``` `req`/`request` aliases `method`, `ip`/`client` aliases `client_ip`, and `source` aliases the internal source ID. A leading `!` negates a clause. Quoted text keeps spaces together. `*` is a wildcard. Numeric fields accept `>`, `>=`, `<` and `<=`; status values also accept forms such as `5xx`. All clauses are ANDed. `OR` is deliberately rejected rather than being interpreted ambiguously. Existing `source`, `event`, `status_class`, `client_ip` and `vhost` query parameters remain accepted by the API for compatibility. The dashboard emits `source` only when one specific log is selected; `All configured files` leaves the source parameter unset. ## Parsed records and dynamic columns JSON/JSONL lines are normalized as before, including recovery of canonical fields from configured JSON mappings. The query response also returns a bounded list of discovered leaf field names. The browser uses those names to build the column picker dynamically. The default concise columns remain time, event, status, client IP, vhost, record summary and source. Protocol-specific fields such as `matched_by` and `sni` are no longer hard-coded columns; they appear automatically when present in returned JSON and can be selected like any other discovered field. Stored-log column preferences remain account-scoped. Validation now accepts up to 64 bounded, control-free field names so discovered JSON fields can be persisted without widening any filesystem or proxy configuration authority. ## RAW error-log parsing The built-in RAW error format is parsed into: - `timestamp`; - `level`; - `target`; - message text before the first recognized `key=value` field; - subsequent detected `key=value` fields. Space-separated text following a `key=value` token is attached to that field until another valid field token begins. Because RAW is intentionally not a fully self-describing serialization, the original line is retained in `raw` and remains available in the expanded record view. ## UI details Selecting a row shows parsed field/value pairs inline and offers the normalized raw JSON in a collapsible section. Column configuration sits in the table toolbar instead of the filter row. The previous Configured files block remains removed. Stored Logs keeps an optional Source selector as an index-like scope: `All configured files` is the default, and choosing one configured log limits the query to that source. The server continues to derive every readable path from active RustProxy logging configuration; the browser submits only a source ID, never a filesystem path. Stored Logs and Live Logs remain technically independent. The combined Logs top-bar control changes navigation only; Live Logs still reads the bounded in-memory request history, while Stored Logs reads bounded tails of configured files. ## Security and bounds Existing file-reader protections remain unchanged: regular-file checks, Unix `O_NOFOLLOW`, configured-source derivation, blocking-worker I/O, bounded scan bytes/lines/source count, bounded result offsets and page size. Search parsing is bounded to 512 input bytes and at most 32 clauses. Field names and individual values are bounded before matching. Dynamic column discovery is capped at 64 leaf fields. ## Regression coverage Source tests cover field aliases, negation, quoted values, status/numeric matching, wildcard matching and RAW error parsing in addition to the retained 0.26.1 stored-log normalization tests. A Rust-enabled release host must still run `cargo fmt --check`, Clippy with warnings denied, all-target/all-feature tests and the complete `dev.sh` release build before the package is considered compiler-verified.