observability: AST linter check_event_names#108
Merged
Conversation
Add tools/lint/check_event_names.py implementing two AST checks
required by RFC-0013 INV-OBS-1/2 and RFC-0015 §3.4:
- registered_event_name: every logger.{debug,info,warn,warning,error}
call site that passes a string literal as the first positional
argument uses a name registered in EVENTS.
- registered_metric_name: every counter.inc/observe/set call site
with a string-literal first argument uses a name registered in
METRICS. The check stays dormant until METRICS ships (#25) by
returning early when discover_registered_metrics() returns None.
The metric-call detector is intentionally name-heuristic to avoid
flagging vector .inc()/.set() math. It only triggers when the receiver
identifier contains counter/histogram/gauge/metric.
Parses observability.py with ast to discover the legal name set so
the linter has no runtime dependency on the package.
Tests in tests/lint/test_check_event_names.py cover:
- registry discovery against the real module
- registered/unregistered events (positive + negative)
- dynamic event names (variable / f-string) skipped
- every logger level method (debug/info/warn/warning/error)
- metric check armed only when METRICS is present
- unrelated .inc() calls ignored
- self-skip on observability.py
- format spec, main() exit codes, no-args call tolerated
The .github/workflows/lint-errors.yml workflow renames to ``lint``
and gains a check-event-names job alongside check-error-codes.
Closes #27
3 tasks
This was referenced May 20, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
RFC-0013 INV-OBS-1/2 require every logged event name and every metric name to be a literal registered in
EVENTS/METRICS. Without a linter, a typo likelogger.info('training.step')vs'training_step'slips through silently.Solution
tools/lint/check_event_names.pyregistered_event_name: walks everylogger.{debug,info,warn,warning,error}(...)call. If the first positional arg is a string literal, asserts it is inEVENTS. Dynamic event names (Name or f-string) are skipped — they're a runtime check.registered_metric_name: same shape forcounter.inc()/histogram.observe()/gauge.set(). Receiver-name heuristic restricts the check to obvious metric handles to avoid flagging unrelated.inc()calls.observability.py— no runtime import.observability.pyitself (theEventSpec(...)literals would otherwise look like raises).METRICSdiscovery if absent, so this check stays dormant until observability: implement metrics registry + Prometheus textfile exporter #25 ships..github/workflows/lint-errors.ymlrenamed tolintand gains acheck-event-namesjob alongsidecheck-error-codes.tests/lint/test_check_event_names.py(19 cases): registry discovery; positive / negative event names; dynamic / f-string event names skipped; parametrized over all logger levels; metric check armed only when registry present; format spec; self-skip; no-args tolerated.Validation
Caveats
counter|histogram|gauge|metricsubstring in the receiver identifier — strict enough that ordinarybox.inc(1)does not trigger.Closes #27