Highlights
- Subject partition + person bucketing for
user_events. The curated table is now laid outsubject › date › bucket(person_id)and sorted byperson_id, so category, time-window, and single-person reads all prune well.person_idis hashed intoNbuckets (bucket(N, person_id)) — DuckLake's recommended way to partition a high-cardinality key without the small-files problem. Tune withNILA_USER_EVENTS_BUCKETS(default 16). - Subjects. Every event is classified into a low-cardinality subject —
errors/activities/ai_usage/traceability/other. An explicitnila.subjectattribute wins; otherwise it's derived (severity/exception → errors,gen_ai/llm→ ai_usage, identify/audit → traceability). Unknown values clamp toother. - Identity lookup by any key. Users are defined by any stable, unique key (email / account id / phone), hashed into a
person_id. Newnilalytics identify <key>prints that id, andnilalytics query user --key <value> [days]hashes it for you. - New reads.
query subject <name> [days], a subject breakdown inquery user_events, and the emitter now sends sampleai_usageevents.
Upgrade note
The user_events table gains a subject column and a new partition layout. On first start after upgrade, the server rebuilds it from otlp_logs (the source of truth) automatically.
Full changelog: v0.2.0...v0.3.0