Skip to content

feat: v0.5.0rc1 polish — py.typed, @deprecated, OTel adapter (Proposal 3)#19

Merged
cipher813 merged 4 commits into
mainfrom
feat/proposal-3-polish
May 13, 2026
Merged

feat: v0.5.0rc1 polish — py.typed, @deprecated, OTel adapter (Proposal 3)#19
cipher813 merged 4 commits into
mainfrom
feat/proposal-3-polish

Conversation

@cipher813
Copy link
Copy Markdown
Owner

Summary

Closes Proposal 3 from private/plug-and-play-260513.md and cuts the v0.5.0 release. Three small, independent pieces of polish on top of PR #18.

What's in

  • flow_doctor/py.typed — zero-byte PEP 561 marker shipping in the wheel via [tool.setuptools.package-data]. Verified the file lands in the built wheel. Consumers using mypy/pyright in --strict mode now treat flow-doctor's annotations as authoritative.
  • PEP 702 @deprecated on flow_doctor.init() (runtime DeprecationWarning pointing at FlowDoctor.builder()) and NotifyChannelConfig (static-only via category=None since it's still the internal lingua franca the builder folds typed configs into). Adds typing_extensions>=4.5 to runtime deps (PEP 702 backport for Python 3.9–3.12; stdlib in 3.13+). Suite-level filterwarnings keeps our own legacy-path tests clean; downstream consumers still see the warning at their call site.
  • flow_doctor.otel.report_to_otel_span_event(report) — pure-Python OTel SpanEvent serialization. Maps flow_name → resource.service.name, context["stage"] → event.name, exception fields → OTel exception attributes, severity → severity_text + severity_number, created_at → time_unix_nano, context dict flattened with "context." prefix and primitives coerced. No opentelemetry-* dep — the OTLP exporter notifier itself stays deferred to v0.6.0 per the plan's open question Fix README badges — static shields #5.
  • v0.5.0 cut. __version__ + pyproject.toml version bumped 0.4.0 → 0.5.0. CHANGELOG.md gains a v0.5.0 section folding in Proposals 1+2+3 plus the dedup-signature normalization that had been queued under "Unreleased". 0.6.0 roadmap captures the deferred work (OTLP exporter, pydantic-settings BaseSettings, hard removal of deprecated APIs).

Not in this PR (manual / follow-up)

  • PyPI publish stays your manual step.
  • Morning-signal cutover — separate PR in the alpha-engine-morning-signal repo once 0.5.0 lands on PyPI.

Test plan

  • pytest tests/ → 356/356 pass (340 prior + 5 deprecation + 16 OTel = 21 new).
  • Built wheel contains flow_doctor/py.typed (verified via python -m zipfile -l).
  • FlowDoctor.builder() path is deprecation-clean (no runtime warnings); flow_doctor.init() emits the expected DeprecationWarning.
  • OTel adapter round-trip: severity text/number, time_unix_nano for tz-aware + naive datetimes, nested-dict flattening, mixed-list stringification, duplicate-promotion pruning.
  • PyPI publish.

🤖 Generated with Claude Code

cipher813 and others added 4 commits May 13, 2026 12:36
…Config

Two-thirds of Proposal 3 polish from the plan:

- flow_doctor/py.typed (zero-byte PEP 561 marker) ships in the wheel
  via [tool.setuptools.package-data] so mypy/pyright treat flow-doctor's
  annotations as authoritative when consumers depend on flow-doctor in
  --strict mode. Verified the marker lands in the built wheel.

- typing_extensions>=4.5 added to runtime deps (PEP 702 backport for
  Python 3.9-3.12; stdlib in 3.13+).

- @deprecated on flow_doctor.init() emits a runtime DeprecationWarning
  pointing at FlowDoctor.builder() (default category) so 0.4.0 consumers
  actually see the migration prompt on startup. Removed in 0.6.0.

- @deprecated on NotifyChannelConfig uses category=None — static-only,
  no runtime warning. The omnibus form is still the internal lingua
  franca that the builder folds typed configs into via to_channel_config(),
  so a runtime warning here would fire on every typed config that gets
  lifted to legacy. The static __deprecated__ attribute still surfaces
  the migration hint in mypy/pyright when consumers construct it
  explicitly.

- Suite filterwarnings entry suppresses init()'s runtime warning inside
  our own tests; downstream consumers still see it at their call site.

5 new tests cover: runtime DeprecationWarning emission from init(),
silent runtime + present __deprecated__ on NotifyChannelConfig, and a
regression that the recommended migration path (FlowDoctor.builder() +
typed notifier configs) is deprecation-clean even though it folds
typed configs through to_channel_config() internally.

Suite: 340/340 pass (335 prior + 5 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Final piece of Proposal 3 polish. Pure-Python, no opentelemetry-* dep —
the actual OTLP exporter is deferred to v0.6.0 per the plan's open
question #5 so the optional dep family lands in its own release cycle.
What ships here is the SHAPE that exporter will emit, so consumers
running on Datadog / Honeycomb / Grafana Cloud / Sentry-via-OTel can
convert reports themselves today via their own collector.

flow_doctor/otel.py implements report_to_otel_span_event(report) per
the plan's mapping table:

- flow_name        → resource.service.name
- context.stage    → event.name (falls back to "report")
- error_type       → attributes["exception.type"]
- error_message    → attributes["exception.message"]
- traceback        → attributes["exception.stacktrace"]
- severity         → severity_text + severity_number
                     (critical=FATAL/21, error=ERROR/17, warning=WARN/13)
- created_at       → time_unix_nano (handles naive-UTC datetimes safely)
- error_signature  → attributes["flow_doctor.error_signature"]
- cascade_source   → attributes["flow_doctor.cascade_source"]
- dedup_count > 1  → attributes["flow_doctor.dedup_count"]
- logs             → attributes["flow_doctor.logs"]
- context (rest)   → flattened into attributes with "context." prefix
                     (nested dicts dot-flatten; non-primitives coerced
                      to str so attribute values stay OTel-safe)

Duplicates are pruned: flow_name doesn't reappear as context.flow_name
on attributes (already on the resource), and stage doesn't reappear
as context.stage (already promoted to event.name).

16 new tests cover: top-level shape, resource mapping, event.name
promotion + fallback, severity text+number for error/warning/critical,
time_unix_nano correctness for both tz-aware and naive timestamps,
exception field placement, flow_doctor.* prefixed attributes, nested-
dict flattening, dedup_count gating, homogeneous-list preservation
vs mixed-list stringification, and duplicate-promotion pruning.

Suite: 356/356 pass (340 prior + 16 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Version bump 0.4.0 → 0.5.0 in flow_doctor/__init__.py + pyproject.toml.

CHANGELOG.md gains a v0.5.0 section folding in this release's three
proposals (Pydantic v2 config + builder, FlowDoctorProtocol + testing
plugin + async + contextvars, py.typed + @deprecated + OTel adapter)
plus the dedup-signature normalization that had been queued under
"Unreleased". 0.6.0 roadmap explicitly captures the deferred work:
OTLP exporter, pydantic-settings BaseSettings, hard removal of the
deprecated APIs.

PyPI publish stays a manual step.

Suite: 356/356 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bump 0.5.0 → 0.5.0rc1 in __init__.py + pyproject.toml so the planned
plug-and-play release ships as a release candidate first. PEP 440
pre-release tag means pip skips it by default — consumers must pass
`--pre` to opt in, which keeps the soak builds off anyone pinning
flow-doctor>=0.4 in production until 0.5.0 final lands.

CHANGELOG: rename the section header to 0.5.0rc1 with a one-paragraph
note about the soak intent. The full bullet list is the planned 0.5.0
content verbatim — 0.5.0 final will republish it once the rcN cycle
clears.

Suite: 356/356 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cipher813 cipher813 changed the title feat: v0.5.0 polish — py.typed, @deprecated, OTel adapter (Proposal 3) feat: v0.5.0rc1 polish — py.typed, @deprecated, OTel adapter (Proposal 3) May 13, 2026
@cipher813 cipher813 merged commit b7a63a1 into main May 13, 2026
1 check passed
@cipher813 cipher813 deleted the feat/proposal-3-polish branch May 13, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant