# 050 — Bound logfmt-overfit param cardinality; derive params from `log stream`-style structured headers ## Summary A real-world `log stream` (macOS unified log) dump (`huig_dump.txt`, ~700 lines) exposes two related problems in the auto-param-derivation path (`auto_declare_params` in `src/engine.rs`, backed by `extract_pairs` in `src/logfmt.rs`, run on *every* ingested line at `src/engine.rs:155`): 1. **`=`-overfitting produces runaway, low-value param cardinality.** `extract_pairs` scans anywhere in the line for `key=value`/`key="value"` and treats every match as a declarable param. On the sample dump this discovers **220 distinct auto-declared param names** from under 700 lines — one-off WiFi/radio stat dumps alone contribute lines with 20-27 `key=value` pairs each (e.g. `txRTSFrm=169 txRTSFail=0 rxCTSUcast=168 ...`), most of which are internal counters that will never recur meaningfully. Some matches are outright false positives: base64-encoded blobs ending in padding (e.g. `rKTEtG7JmnThhoKPbZiVrA=='>,`) get parsed as a `key=value` pair because `=` precedes non-whitespace. Since `auto_declare_params` "never overwrites an existing declaration" and there is no cap or pruning anywhere in the ingest path, every distinct key seen ever becomes a permanent declaration — this is almost certainly the source of the reported ingest lag on this input (per-line nom scanning cost is presumably fine; the unbounded, ever-growing declaration/index set is the more likely culprit and should be measured either way) and it clutters the params UI with noise no user asked for. 2. **The input's real structure is being ignored.** `log stream` output is not logfmt at all — it's a fixed-column header (`Timestamp`, `Thread`, `Type`, `Activity`, `PID`, `TTL`) followed by a free-text `process: message` tail (see header row and body of `huig_dump.txt`). `Type` (`Default`/`Error`/`Activity`), the process name (`kernel`, `airportd`, `bluetoothd`, `WindowServer`, ...), and `PID` are low-cardinality, genuinely useful params that could be derived directly and cheaply from column position — with no `=`-scanning, no ambiguity, and no risk of false positives — instead of (or in addition to) whatever generic `key=value` pairs happen to appear later in the line. ## Scope - Add a bound/safeguard on `auto_declare_params` so a single burst of unusual lines can't permanently inflate the declared-param set: options include (pick and justify one, or combine) a cap on the total number of auto-derived declarations, a per-line cap on how many `key=value` pairs from one line are eligible for auto-declaration, and/or a heuristic to reject candidate pairs that look like base64 fragments (trailing `=`/`==` with a base64-alphabet value and no realistic bareword shape) in `src/logfmt.rs`'s `extract_pairs`/`pair`. - Add an optional structured-header extractor for `log stream`-shaped input: detect the fixed-column header/row shape (timestamp, thread id, log type, activity id, pid, ttl, `process: message`) and surface `Type`/process-name/`PID` as derivable params, analogous to how `ottyl_fmt` (ticket 044) records which format a line matched. Decide whether this is a new `ottyl_fmt` variant (e.g. `"log_stream"`) or a separate always-attempted extraction that runs alongside logfmt/JSON detection, and record the decision in the PR. - Use `huig_dump.txt` (already in the repo root) as the seed fixture for tests — copy the relevant lines into a test fixture under wherever existing ingest fixtures live, rather than reading the file from the repo root at test time. - Re-measure ingest throughput on this fixture before/after to confirm the lag is actually addressed, and note the before/after numbers in the PR description. ## Acceptance criteria - Ingesting `huig_dump.txt`'s lines no longer produces hundreds of permanent auto-declared params from one-off stat-dump lines; the bound chosen is verified by a test asserting the declared-param count stays under a stated threshold after ingesting the fixture. - Base64-padding false positives (e.g. the `==`-terminated blobs in the fixture) are not auto-declared as params. - `Type`, process name, and `PID` are available as derivable/queryable params for `log stream`-shaped lines, verified against the fixture. - Existing logfmt/JSON auto-declaration behavior for non-`log stream`-shaped lines (existing tests in `src/logfmt.rs`/`src/engine.rs`) is unchanged. ## Depends on 044 (reserved param naming / `ottyl_fmt` — this ticket likely extends the same format-detection mechanism).