Skip to content

Name the null reverse-path instead of showing bare angle brackets - #202

Merged
michaelTBF merged 2 commits into
mainfrom
fix/render-null-sender-envelope-from
Aug 30, 2026
Merged

Name the null reverse-path instead of showing bare angle brackets#202
michaelTBF merged 2 commits into
mainfrom
fix/render-null-sender-envelope-from

Conversation

@michaelTBF

Copy link
Copy Markdown
Contributor

The per-source panel printed <> verbatim in its Envelope from list. That is
not corrupt data and not an escaping bug: it is the RFC 5321 null reverse-path,
which a reporter sends when the source's envelope sender was empty — what
bounces, delivery status notifications and auto-replies use. It just reads as a
glyph nobody outside SMTP recognises.

It now renders as null sender <>, with a title explaining what sends it.

Not "none" or "empty"

The issue asked for that wording and this deliberately does not use it, because
the panel has two distinct states and those labels name the wrong one:

what the reporter did stored as shown as
omitted <envelope_from> "" nothing — the row is dropped
reported an empty sender <> null sender <>

Calling the second one "empty" would say a source sent no envelope sender when
what it actually sent was a bounce. The label loses a real signal about the
traffic.

The bug next door

Tracing it turned up a second problem in the same list. GroupValuesAsync took
the top ten values in the database and then dropped the blanks client-side:

.Take(10)
.ToListAsync(ct);

return rows
    .Where(x => !string.IsNullOrWhiteSpace(x.Value))   // too late

An omitted identifier is a large group in practice — often the largest a source
has — so it won a place in the ten and was then discarded. The panel showed
nine values and gave no sign a tenth had been displaced. The filter moves into
the query, ahead of the cap.

It trims, because nothing trims these identifiers on ingest: a reporter that
pretty-prints its XML stores the surrounding newline and indentation as the
value, which is the same absence as an empty string. (The parser already trims
source_ip for a related reason, with a comment saying so.)

Verification

  • dotnet test src/api.tests — 802 passed
  • dotnet test src/api.integration.tests — 78 passed
  • cd src/web && npm run build && npm run lint && npm test — clean, 35 passed

The new backend tests are in the integration suite, not the fast one, and
have to be: the filter exists to stop an omitted value consuming one of ten
slots, which only means anything if the database applies the cap — and InMemory
would evaluate Trim() in C# whether or not Npgsql can translate it, so the
fast suite cannot tell a working query from one that 500s the panel at runtime.
Confirmed against PostgreSQL 18, and confirmed failing against the pre-fix code.

Not verified in a running browser — the change is a fifteen-line render branch
covered by a DOM test, and standing the authenticated app up with report data
was more than it warranted. Worth a glance on the panel before merge if you
disagree.

One thing left open

An omitted identifier now disappears from the list cleanly rather than
displacing a value, but it still disappears silently — its message volume is
simply absent from a panel that otherwise accounts for everything. Showing it
as a (not reported) row is a product call rather than a bug fix, so it is not
in here.

Refs #196

A reporter that sees an empty envelope sender reports it as `<>`, the RFC 5321
null reverse-path, and the per-source panel printed it verbatim — a glyph that
means nothing outside SMTP. It now reads "null sender <>", with a title
explaining that it is what bounces, delivery status notifications and
auto-replies look like.

Not relabelled "none" or "empty" as the issue asked: that is the *other* case,
a reporter omitting the element entirely, and conflating the two would report a
source as having sent no envelope sender when what it actually sent was a
bounce.

Those omitted values turned out to be dropped in the wrong place — after the
top-ten cap rather than before it. An omitted identifier is a large group in
practice, often the largest, so it took a slot and was then discarded, leaving
the panel showing nine values with no sign a tenth had been displaced. The
filter moves into the query, and trims while it is there, because nothing trims
these on the way in and a reporter that pretty-prints its XML stores the
surrounding indentation as the value.

Refs #196

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 0b255aab-53dd-4d02-a592-c5c9fdfd253b

📥 Commits

Reviewing files that changed from the base of the PR and between 577a42c and 324a1e0.

📒 Files selected for processing (2)
  • src/web/src/pages/DomainDetailPage.identifiers.test.tsx
  • src/web/src/pages/DomainDetailPage.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The API filters empty and whitespace-only source identifiers before top-ten aggregation. The web interface identifies RFC 5321 null reverse-path values as “null sender” while preserving the raw marker. Integration and component tests cover these cases.

Changes

Source Identifier Handling

Layer / File(s) Summary
Pre-limit source identifier filtering
src/api/Application/Analytics/AnalyticsQueryService.cs, src/api.integration.tests/SourceIdentifierAnalyticsPostgresTests.cs
Source analytics exclude empty and whitespace-only identifiers before grouping. PostgreSQL tests verify top-ten behavior and retain <> with its message count.
Null reverse-path rendering
src/web/src/pages/DomainDetailPage.tsx, src/web/src/pages/DomainDetailPage.identifiers.test.tsx
ValueList labels trimmed <> values as “null sender”, preserves the raw marker, and tests ordinary, invalid, and empty values.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🔵 Low · up to 324a1

This PR makes null reverse-paths clearer and prevents omitted identifiers from consuming displayed slots. A bounded UI correctness risk remains because some header-from values may still be labeled as envelope senders, which could mislead users; merge is reasonable with explicit owner follow-up.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: labeling the RFC 5321 null reverse-path instead of displaying bare angle brackets.
Description check ✅ Passed The description directly explains the null reverse-path labeling, blank-value filtering, scope, testing, and remaining product decision.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/render-null-sender-envelope-from

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
src/web/src/pages/DomainDetailPage.tsx-216-216 (1)

216-216: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restrict the null-sender label to envelope-from values.

ValueList also renders detail.headerFroms at Line 1632. A header-from value of <> therefore receives an RFC 5321 envelope-sender label. Pass an explicit value type or formatter, and enable this special rendering only for detail.envelopeFroms.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: fe0d7ccd-65d9-4e03-ad3b-21c9b0e42ba5

📥 Commits

Reviewing files that changed from the base of the PR and between ac27515 and 577a42c.

📒 Files selected for processing (4)
  • src/api.integration.tests/SourceIdentifierAnalyticsPostgresTests.cs
  • src/api/Application/Analytics/AnalyticsQueryService.cs
  • src/web/src/pages/DomainDetailPage.identifiers.test.tsx
  • src/web/src/pages/DomainDetailPage.tsx

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.

ValueList renders the header-from panel as well, and `<>` there is a malformed
`From:` rather than a null reverse-path — that is an SMTP envelope concept. The
label would have asserted the source sent bounces on the evidence of a broken
reporter, which is the same conflation this change set out to avoid. It is now
opt-in per list.

Refs #196

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Labels RFC 5321 null reverse-paths clearly and prevents omitted identifiers from consuming top-ten analytics slots.

Changes:

  • Renders <> as null sender <> with explanatory context.
  • Filters blank identifiers before grouping and limiting.
  • Adds frontend and PostgreSQL integration coverage.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/web/src/pages/DomainDetailPage.tsx Adds null-sender rendering.
src/web/src/pages/DomainDetailPage.identifiers.test.tsx Tests identifier rendering states.
src/api/Application/Analytics/AnalyticsQueryService.cs Filters blank identifiers before aggregation.
src/api.integration.tests/SourceIdentifierAnalyticsPostgresTests.cs Verifies filtering and null-path preservation against PostgreSQL.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@michaelTBF
michaelTBF merged commit bbbfefc into main Aug 30, 2026
6 checks passed
@michaelTBF michaelTBF mentioned this pull request Aug 30, 2026
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.

2 participants