Skip to content

fix(OMN-14513): reconcile node_projection_baselines to real producer schema - #1768

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-14513-seam-mismatch-structural-incompatibility-not-just-field-drop
Jul 15, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-14513-seam-mismatch-structural-incompatibility-not-just-field-drop

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OMN-14513: node_projection_baselines defined local Pydantic models sharing almost no field names with the real producer contract (omnibase_infra.services.observability.baselines.models.model_baselines_snapshot_event.ModelBaselinesSnapshotEvent / ModelBaselinesComparisonRow / ModelBaselinesTrendRow / ModelBaselinesBreakdownRow) — a required-no-default pattern_id the producer never sends, entirely fictional trend/breakdown handling on the consumer side, and a snapshot write that bound columns (patterns_compared/patterns_recommended) that don't exist on baselines_snapshots.

Live-checked on .201 stability-test before fixing (per the ticket's DoD): the projection_baselines consumer group had committed offset 2 with zero lag (both real events on the topic already consumed) yet all four target tables held zero rows — confirming failure mode #1 from the ticket description (every real event silently crashed inside the runtime's catch-all dispatch boundary; not a partial degrade).

Fix (both consumer paths declared in this node's contract, matching the OMN-14490/OMN-14506 precedent)

  • HandlerProjectionBaselines (the live-wired RuntimeLocal handler shim — confirmed via __init__.py's entry point + the single live .201 consumer group) and BaselinesProjectionRunner (the standalone Kafka→Postgres runner, still declared live in docker-compose.projection.yml) both now validate the canonical omnibase_infra producer models directly instead of local slim copies, stripping transport-injected _-prefixed keys first (_strip_transport_keys).
  • New migration 0002_realign_child_tables_to_producer_schema.sql recreates baselines_comparisons/baselines_trend/baselines_breakdown with the real producer row shapes (treatment_*/control_*/roi_pct, cohort/session_count, pattern_id/pattern_label). All three tables held zero rows in every known environment (verified live), so there was no data to preserve across the shape change.
  • Wired the OMN-13548 DLQ path: BaselinesProjectionRunner declares poison_dlq_topics/publish_dlq (the base class's own POISON safety net now routes an escaped ValidationError there); HandlerProjectionBaselines documents that a malformed payload propagates to the wiring layer's own dlq_topics route, matching the established HandlerProjectionRegistration precedent.
  • contract.yaml input_model/event_model now point at the canonical producer model path; metadata.yaml declares the omnibase-infra dependency the node-metadata scope checker requires.

Scope note: two sibling nodes patched to avoid a compile break, NOT fixed

node_projection_baselines_roi and node_projection_baselines_quality both imported this node's now-deleted fictional ModelBaselinesComputedEvent. Gave each its own local, behavior-identical copy of the same fictional model so this PR doesn't silently regress them — this is explicitly a no-op preservation, not a fix (their own aggregation semantics like token_delta/retry_delta/confidence tiers have no producer analog and need their own redesign). Filed OMN-14630 to track that follow-up.

Behavioral proof (non-vacuous)

tests/test_omn14513_baselines_seam.py drives the producer's real envelope through the real unwrap_envelope decode seam into BOTH consumer paths and asserts all 4 target tables receive real (non-default) A/B treatment/control data.

  • RED (verified via git stash against the pre-fix handlers on this branch): pydantic.ValidationError: comparisons.0.pattern_id Field required on the handler path, and the runner path silently degrading to a blank/'shadow'-keyed default row (5 of 7 expected SQL statements, missing the comparison/trend inserts).
  • GREEN: same test passes end-to-end with real treatment_sessions/control_sessions/roi_pct/cohort/pattern_id values landing in the in-memory DB / SQL binds.

Seams

  • Consumer input model: omnibase_infra.services.observability.baselines.models.model_baselines_snapshot_event.ModelBaselinesSnapshotEvent (UUID snapshot_id, datetime timestamps, extra="forbid") — matched field-for-field against the producer.
  • DB schema: baselines_comparisons/baselines_trend/baselines_breakdown columns now mirror ModelBaselinesComparisonRow/ModelBaselinesTrendRow/ModelBaselinesBreakdownRow field names exactly (see migration 0002 docstring for the full mapping rationale).
  • DLQ: event_bus.dlq_topics: [onex.dlq.omnimarket.projection-baselines-malformed.v1] added to contract.yaml.

Test plan

  • tests/test_omn14513_baselines_seam.py — new cross-boundary regression test (RED-vs-pre-fix verified, GREEN post-fix)
  • tests/test_golden_chain_projection_baselines.py — rewritten against the real producer model
  • tests/test_projection_baselines_migration_omn11887.py — extended to cover migration 0002's column shapes
  • tests/test_projection_handlers.py — TestBaselinesHandler rewritten to drive a real producer-shaped payload
  • tests/nodes/node_projection_baselines_{roi,quality}/ + their golden-chain tests — re-pointed imports, still green, unchanged behavior
  • uv run ruff format --check / uv run ruff check / uv run mypy --strict clean on all touched nodes
  • pre-commit run --files <changed> clean (Contract-state-coverage gate, Projection-DLQ path gate, node metadata dependency scope, import-check all pass)
  • Live .201 stability-test check performed before the fix (rpk consumer-group + psql readback) to pin the exact failure mode

Evidence-Source: OCC#4216
Evidence-Ticket: OMN-14513
Evidence-Commit: a9883449338cda6dd0fdbc374ee8866a1fa1e9a6
Evidence-Head: f0b9661

Closes OMN-14513

Merge-sweep conflict repair evidence

Codex merge sweep merged current origin/dev into this branch and resolved the ROI/quality sibling-node conflicts by keeping the newer OMN-14630 real-producer-schema implementation from dev, while preserving this PR's node_projection_baselines seam repair. Repair commit: f0b9661891a061bb8af87f8db9bcd13d9e7c3c82.

Local post-merge verification from the clean OMN-14513 worktree:

uv run pytest tests/test_omn14513_baselines_seam.py tests/test_projection_handlers.py tests/test_golden_chain_projection_baselines.py tests/test_projection_baselines_migration_omn11887.py tests/nodes/node_projection_baselines_roi/test_projection_baselines_roi.py tests/nodes/node_projection_baselines_quality/test_projection_baselines_quality.py tests/test_golden_chain_projection_baselines_roi.py tests/test_golden_chain_projection_baselines_quality.py -q
73 passed in 0.51s

git diff --check: PASS
conflict-marker scan for ^<<<<<<< / ^======= / ^>>>>>>>: PASS
commit hooks with OMNI_HOME and OMNIBASE_INFRA_PATH: PASS

…schema

node_projection_baselines defined local models sharing almost no field
names with the real producer contract (omnibase_infra's
ModelBaselinesSnapshotEvent / ModelBaselinesComparisonRow /
ModelBaselinesTrendRow / ModelBaselinesBreakdownRow): a required-no-default
pattern_id the producer never sends, entirely fictional trend/breakdown
concepts on the consumer side, and a snapshot write that bound columns
(patterns_compared/patterns_recommended) that don't exist on
baselines_snapshots.

Live-checked on .201 stability-test before fixing: the projection_baselines
consumer group had committed offset 2 with zero lag (both real events on
the topic consumed) yet all four target tables held zero rows -- confirming
failure mode #1 from the ticket (every real event silently crashed inside
the runtime's catch-all dispatch boundary, never a partial degrade).

Fix (both consumer paths declared in this node's contract, matching the
OMN-14490/14506 precedent):
- HandlerProjectionBaselines (the live-wired RuntimeLocal shim) and
  BaselinesProjectionRunner (the standalone Kafka->Postgres runner, still
  declared in docker-compose.projection.yml) both now validate the
  canonical omnibase_infra producer models directly instead of local slim
  copies, stripping transport-injected `_`-prefixed keys first.
- New migration 0002 recreates baselines_comparisons/baselines_trend/
  baselines_breakdown with the real producer row shapes (treatment_*/
  control_*/roi_pct, cohort/session_count, pattern_id/pattern_label). All
  three tables held zero rows in every known environment, so there was no
  data to preserve across the shape change.
- Wired the OMN-13548 DLQ path: BaselinesProjectionRunner declares
  poison_dlq_topics/publish_dlq (the base class's own POISON safety net
  routes an escaped ValidationError there); HandlerProjectionBaselines
  documents that a malformed payload propagates to the wiring layer's own
  dlq_topics route, matching the established RuntimeLocal-shim precedent.

Two sibling nodes (node_projection_baselines_roi,
node_projection_baselines_quality) imported this node's now-deleted
fictional models. Gave each its own local, behavior-identical copy to avoid
a compile break -- NOT a fix, tracked separately as OMN-14630 since their
own aggregation semantics (token_delta, retry_delta, confidence tiers) have
no producer analog and need their own redesign.

Behavioral proof: tests/test_omn14513_baselines_seam.py drives the
producer's real envelope through the real unwrap_envelope decode seam into
BOTH consumer paths. Verified RED against the pre-fix models on this branch
(pydantic ValidationError: comparisons.0.pattern_id Field required; runner
silently degraded to a blank/'shadow'-keyed default row) and GREEN against
the canonical ones.

Closes OMN-14513
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6080fdb0-f024-4f42-8586-54462baf59ea

📥 Commits

Reviewing files that changed from the base of the PR and between 535323a and f0b9661.

📒 Files selected for processing (9)
  • src/omnimarket/nodes/node_projection_baselines/contract.yaml
  • src/omnimarket/nodes/node_projection_baselines/handlers/handler_baselines.py
  • src/omnimarket/nodes/node_projection_baselines/handlers/handler_projection_baselines.py
  • src/omnimarket/nodes/node_projection_baselines/metadata.yaml
  • src/omnimarket/nodes/node_projection_baselines/migrations/0002_realign_child_tables_to_producer_schema.sql
  • tests/test_golden_chain_projection_baselines.py
  • tests/test_omn14513_baselines_seam.py
  • tests/test_projection_baselines_migration_omn11887.py
  • tests/test_projection_handlers.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-14513-seam-mismatch-structural-incompatibility-not-just-field-drop

Comment @coderabbitai help to get the list of available commands.

@jonahgabriel
jonahgabriel merged commit 846fda8 into dev Jul 15, 2026
219 of 270 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-14513-seam-mismatch-structural-incompatibility-not-just-field-drop branch July 15, 2026 14:02
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