Skip to content

fix: reduces update logs that contain no actual changes#547

Open
andrestejerina97 wants to merge 2 commits into
mainfrom
fix/reduce-noise-logs
Open

fix: reduces update logs that contain no actual changes#547
andrestejerina97 wants to merge 2 commits into
mainfrom
fix/reduce-noise-logs

Conversation

@andrestejerina97
Copy link
Copy Markdown
Contributor

@andrestejerina97 andrestejerina97 commented May 19, 2026

ref: https://app.clickup.com/t/86b9xe3fk

Summary by CodeRabbit

  • Bug Fixes

    • Improved audit log handling to suppress entries when entities are updated with no meaningful changes, preventing generation of audit records for effectively unchanged data.
  • Refactor

    • Enhanced audit log equality detection to more accurately identify when field values are unchanged across various data types.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Warning

Review limit reached

@andrestejerina97, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes and 49 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8632fd00-2ec0-49ec-a980-1eff7d430902

📥 Commits

Reviewing files that changed from the base of the PR and between 13b5897 and aabffc5.

📒 Files selected for processing (120)
  • app/Audit/AbstractAuditLogFormatter.php
  • app/Audit/AuditLogOtlpStrategy.php
  • app/Audit/ConcreteFormatters/AffiliationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/AssignedSelectionPlanExtraQuestionTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/CompanyAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/ExtraQuestionTypeValueAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/FeaturedSpeakerAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/FileAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationAttendeeVoteAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationCategoryAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationCategoryGroupAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/BasePresentationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationActionTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationEventApiAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationLinkAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationMediaUploadAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationSlideAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationSpeakerAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationSpeakerSummitAssistanceConfirmationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationSubmissionAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationTrackChairRatingTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationTrackChairScoreTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationUserSubmissionAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationFormatters/PresentationVideoAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/PresentationTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/RSVPAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/RSVPInvitationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/RSVPQuestionTemplateAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/RSVPTemplateAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/ScheduledSummitLocationBannerAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SelectionPlanAllowedEditablePresentationQuestionAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SelectionPlanAllowedPresentationQuestionAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SelectionPlanAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SpeakerAssistanceAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SpeakerRegistrationRequestAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorAdAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorBadgeScanAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorBadgeScanExtraQuestionAnswerAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorMaterialAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorSocialNetworkAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorSummitRegistrationDiscountCodeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorSummitRegistrationPromoCodeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SponsorUserInfoGrantAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SubmissionInvitationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAccessLevelTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAirportAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAttendeeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAttendeeBadgeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAttendeeNoteAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAttendeeTicketAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAttendeeTicketTaxAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBadgeFeatureTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBadgeTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBadgeViewTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBookableVenueRoomAttributeTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBookableVenueRoomAttributeValueAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitBookableVenueRoomAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitEventAttendanceMetricAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitEventAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitEventTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitExternalLocationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitGeoLocatedLocationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitHotelAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitLocationBannerAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitLocationImageAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitMediaUploadTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitMemberScheduleAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitMetricAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitOrderAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitOrderExtraQuestionTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitPresentationCommentAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitProposedScheduleAllowedLocationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitRefundPolicyTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitRegistrationFeedMetadataAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitSelectedPresentationAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitSelectedPresentationListAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitSponsorExtraQuestionTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitSponsorshipAddOnAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitSponsorshipAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitTaxTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitTicketTypeAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitTrackChairAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitVenueAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitVenueFloorAuditLogFormatter.php
  • app/Audit/ConcreteFormatters/SummitVenueRoomAuditLogFormatter.php
  • tests/OpenTelemetry/Formatters/ExtraQuestionTypeValueAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/FileAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/PrePaidSummitRegistrationDiscountCodeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/ScheduledSummitLocationBannerAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorAdFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorBadgeScanExtraQuestionAnswerFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorBadgeScanFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorMaterialFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorSocialNetworkFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorSummitRegistrationDiscountCodeFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorSummitRegistrationPromoCodeFormatterTest.php
  • tests/OpenTelemetry/Formatters/SponsorUserInfoGrantFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitAccessLevelTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitAttendeeBadgeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitAttendeeNoteAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitAttendeeTicketAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitBadgeFeatureTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitBadgeTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitBadgeViewTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitBookableVenueRoomAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitEventTypeFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitLocationBannerAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitLocationImageAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitOrderAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitOrderExtraQuestionTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitRefundPolicyTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitSponsorExtraQuestionTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitTaxTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitTicketTypeAuditLogFormatterTest.php
  • tests/OpenTelemetry/Formatters/SummitVenueFloorAuditLogFormatterTest.php
  • tests/Unit/Audit/SummitSponsorExtraQuestionTypeAuditLogFormatterTest.php
📝 Walkthrough

Walkthrough

AbstractAuditLogFormatter now returns null from buildChangeDetails() when no changed fields remain and suppresses audit output for semantically-equal field values via a new valuesAreEffectivelyEqual() helper. All 50+ concrete formatters guard against null change details during update events by returning null. AuditLogOtlpStrategy now wraps processing in try-catch and routes jobs directly to the audit-logs queue. Tests expect null instead of no-change messages.

Changes

Suppress Meaningless Audit Log Changes

Layer / File(s) Summary
Equality checking and field-level change suppression
app/Audit/AbstractAuditLogFormatter.php
buildChangeDetails() return type changed to ?string and now returns null when no changed fields remain. formatFieldChange() returns null to suppress output when values are effectively equal via strict identity, DateTime instant/U.u equivalence (with exception safety), or scalar/null comparisons. New valuesAreEffectivelyEqual() method implements the equality logic.
Audit strategy and job queue routing
app/Audit/AuditLogOtlpStrategy.php
Audit processing wrapped in explicit try { ... } block. Job emission changed from JobDispatcher::withDbFallback(...) to EmitAuditLogJob::dispatch(...) routed to the audit-logs queue.
Null guards in concrete formatters for empty changes
app/Audit/ConcreteFormatters/*, app/Audit/ConcreteFormatters/PresentationFormatters/*
All 50+ formatter format() implementations now check whether buildChangeDetails($change_set) returns null during EVENT_ENTITY_UPDATE and immediately return null instead of proceeding to format update messages with missing change details.
Presentation formatter base type and custom implementations
app/Audit/ConcreteFormatters/PresentationFormatters/BasePresentationAuditLogFormatter.php, app/Audit/ConcreteFormatters/PresentationFormatters/PresentationEventApiAuditLogFormatter.php, app/Audit/ConcreteFormatters/PresentationFormatters/PresentationSubmissionAuditLogFormatter.php
BasePresentationAuditLogFormatter::formatUpdate() return type updated to nullable ?string. PresentationEventApiAuditLogFormatter and PresentationSubmissionAuditLogFormatter refactored to compute change details into a local variable, return null when empty, and only format the update message when details exist.
Test assertion updates for null results
tests/OpenTelemetry/Formatters/*
30+ formatter tests updated: testFormatterHandlesEmptyChangeSet() assertions changed from expecting non-null "updated" messages to asserting null results when change sets are empty.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested reviewers

  • smarcet
  • caseylocker

🐰 A fields-gone-quiet, formatters fall still,
No change yet no message—audit's got the will.
Null returns flow free through fifty-plus gates,
Where datetime whispers and equality waits.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: reducing update logs that contain no actual changes by making formatters return null for no-op updates, which is the core objective of this changeset.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reduce-noise-logs

@github-actions
Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-547/

This page is automatically updated on each push to this PR.

@andrestejerina97 andrestejerina97 marked this pull request as ready for review May 19, 2026 13:52
@andrestejerina97
Copy link
Copy Markdown
Contributor Author

@caseylocker it's ready to review

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Audit/AuditLogOtlpStrategy.php`:
- Around line 81-85: The current direct call
EmitAuditLogJob::dispatch($this->getLogMessage($event_type),
$auditData)->onQueue('audit-logs') removed the DB fallback and can drop audit
logs on queue failures; restore the previous fallback-backed emission by
replacing this line with the project's fallback helper (e.g.,
EmitAuditLogJob::dispatchWithFallback(...) or the existing
emitAuditJobWithDbFallback helper) passing $this->getLogMessage($event_type) and
$auditData and targeting 'audit-logs'; if no helper exists, wrap
EmitAuditLogJob::dispatch(...)->onQueue('audit-logs') in a try/catch and persist
$auditData to the AuditLog/backup store inside the catch so queue failures fall
back to the DB.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2216cbcc-c568-4c92-9d61-54cd0664dc07

📥 Commits

Reviewing files that changed from the base of the PR and between 12a29e2 and 620d972.

📒 Files selected for processing (5)
  • app/Audit/AbstractAuditLogFormatter.php
  • app/Audit/AuditLogOtlpStrategy.php
  • tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php
  • tests/Unit/Audit/AbstractAuditLogFormatterHasMeaningfulChangesTest.php
  • tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php

Comment thread app/Audit/AuditLogOtlpStrategy.php Outdated
@andrestejerina97 andrestejerina97 force-pushed the fix/reduce-noise-logs branch from 620d972 to 6a6d3eb Compare May 19, 2026 15:11
@github-actions
Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-547/

This page is automatically updated on each push to this PR.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php (1)

90-90: ⚡ Quick win

Assert dispatch targets the expected queue as well.

Given this stack’s contract, the positive-path test should also verify EmitAuditLogJob is queued on audit-logs, not just dispatched.

Proposed patch
-        Bus::assertDispatched(EmitAuditLogJob::class);
+        Bus::assertDispatched(EmitAuditLogJob::class, function (EmitAuditLogJob $job): bool {
+            return $job->queue === 'audit-logs';
+        });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php` at line 90,
Update the positive-path assertion to verify the job was queued on the expected
queue: replace or augment Bus::assertDispatched(EmitAuditLogJob::class) with
Bus::assertDispatched(EmitAuditLogJob::class, function ($job) { return /* check
queue name */ $job->queue === 'audit-logs' || method_exists($job, 'onQueue') &&
$job->onQueue === 'audit-logs'; }); ensuring the closure inspects the dispatched
EmitAuditLogJob instance to confirm it's targeted at 'audit-logs'.
tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php (1)

37-37: ⚡ Quick win

Use the shared no-changes constant instead of a string literal.

These assertions should reference AbstractAuditLogFormatter::NO_CHANGES_REGISTERED_MESSAGE to keep tests aligned with the formatter contract and avoid brittle message duplication.

Proposed patch
-        $this->assertSame('properties without changes registered', $details);
+        $this->assertSame(AbstractAuditLogFormatter::NO_CHANGES_REGISTERED_MESSAGE, $details);
@@
-        $this->assertSame('properties without changes registered', $details);
+        $this->assertSame(AbstractAuditLogFormatter::NO_CHANGES_REGISTERED_MESSAGE, $details);

Also applies to: 57-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php` at line 37,
Replace the hard-coded string 'properties without changes registered' in the
test assertions with the shared constant
AbstractAuditLogFormatter::NO_CHANGES_REGISTERED_MESSAGE; update the assertions
in AbstractAuditLogFormatterDateNoiseTest (both occurrences around the current
checks that compare $details) to use that constant so the test references the
formatter's contract instead of duplicating the literal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php`:
- Line 37: Replace the hard-coded string 'properties without changes registered'
in the test assertions with the shared constant
AbstractAuditLogFormatter::NO_CHANGES_REGISTERED_MESSAGE; update the assertions
in AbstractAuditLogFormatterDateNoiseTest (both occurrences around the current
checks that compare $details) to use that constant so the test references the
formatter's contract instead of duplicating the literal.

In `@tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php`:
- Line 90: Update the positive-path assertion to verify the job was queued on
the expected queue: replace or augment
Bus::assertDispatched(EmitAuditLogJob::class) with
Bus::assertDispatched(EmitAuditLogJob::class, function ($job) { return /* check
queue name */ $job->queue === 'audit-logs' || method_exists($job, 'onQueue') &&
$job->onQueue === 'audit-logs'; }); ensuring the closure inspects the dispatched
EmitAuditLogJob instance to confirm it's targeted at 'audit-logs'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1056b6fc-96e5-4488-a922-290a6046d636

📥 Commits

Reviewing files that changed from the base of the PR and between 620d972 and 6a6d3eb.

📒 Files selected for processing (5)
  • app/Audit/AbstractAuditLogFormatter.php
  • app/Audit/AuditLogOtlpStrategy.php
  • tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php
  • tests/Unit/Audit/AbstractAuditLogFormatterHasMeaningfulChangesTest.php
  • tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/Audit/AbstractAuditLogFormatter.php
  • app/Audit/AuditLogOtlpStrategy.php

Copy link
Copy Markdown
Contributor

@caseylocker caseylocker left a comment

Choose a reason for hiding this comment

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

LGTM to land this, closes the SelectionPlan screenshot case Mark reported.

@smarcet , the following came out of a second-pass review and extends the fix to more fully cover Mark's "widespread, not just Selection Plans" hypothesis and the preferred shape ("return a null description").
It's your call since the current pr already addresses the specific clickup ticket. Just wanted to be complete.

Follow-up plan (separate PR)

Correctness gaps in the current implementation

  • AbstractAuditLogFormatter.php:228-238getTimestamp() returns integer seconds, so the format('U.u') fallback is unreachable and same-second microsecond changes are wrongly suppressed. Collapse to a single format('U.u') === format('U.u') compare.
  • AbstractAuditLogFormatter.php:240-242 — scalar branch reuses formatChangeValue() for equality, so null vs "null", true vs "true", and 1 vs "1" all compare equal. Replace with: null pair → strict ===; otherwise require gettype match plus strict ===. No string-coercion fallback.
  • AuditLogOtlpStrategy.php:65-71hasMeaningfulChanges() isn't on IAuditLogFormatter, and AuditLogFormatterFactory.php:163 can instantiate config-driven formatters that don't extend the abstract. Drop the pre-gate; switch the existing is_null($description) check at line 73 to empty($description) so null-bubble from format() does the work.

Coverage gaps (Mark's "widespread" concern)

  • EntityUpdateAuditLogFormatter: apply valuesAreEffectivelyEqual before every branch (child-entity at lines 103-108, BaseEntity at 111-142, plain at 145-157), so same-instance objects and same-instant datetimes are skipped while different entity instances still log. Return null on empty result. This closes the OTLP fallback case AND the DB-strategy noise for SummitEvent / SummitAttendeeBadge (the only entities AuditLoggerFactory resolves).
  • Make buildChangeDetails(): ?string return null instead of the "properties without changes registered" sentinel, then update each of the ~85 callers (and BasePresentationAuditLogFormatter::formatUpdate(): ?string) to propagate the null so each concrete format() returns null on no-op. That lets both strategies' existing is_null/empty guards
    do the suppression — matching Sebastian's directive structurally and removing the need for a strategy-level gate.

Polish

  • Trailing whitespace at AuditLogOtlpStrategy.php:86, indent of try at line 53, blank EOF in the new OTLP test (AuditLogOtlpStrategyNoOpSuppressionTest.php:93).
  • DefaultEntityManyToManyCollectionDeleteAuditLogFormatter.php:73 emits "Removed IDs: []" when $deletedCount === 0. Same family of audit noise; return null instead. Outside the original ticket but cheap to fix together — call out as adjacent cleanup in the PR description.

Tests to add

  • Microsecond DateTime change → logged.
  • null vs "null", true vs "true", false vs "false", 1 vs "1" → logged.
  • Ignored-fields-only change_set → null description, no dispatch on both strategies.
  • EntityUpdateAuditLogFormatter: same-instance BaseEntity → skipped; different-instance BaseEntity (same id) → logged; tz-noise DateTime → skipped; real DateTime change → logged.
  • OTLP suppresses empty-string description (not just null).
  • DB strategy does not call createAuditLogEntry when format() returns null.
  • PrePaid + Sponsor discount-code formatters return null on no-op (they currently add "current state" context).

@smarcet
Copy link
Copy Markdown
Collaborator

smarcet commented May 22, 2026

@Andres-Tejerina — review note on the approach.

The fix at lines 65–71 should not exist. The strategy already has the right null-check at line 73; the pre-check duplicates logic that belongs inside the formatter.

Root cause of the pattern:
buildChangeDetails() returns the string 'properties without changes registered' when no fields survive the filter, instead of null. Because it never returns null, format() never returns null for a no-op update, so the existing guard at line 73 never fires for this case. The PR works around that by adding hasMeaningfulChanges() as a parallel pre-pass — but that's two methods doing equivalent work.

Proposed fix:

  1. Change buildChangeDetails() return type to ?string — return null instead of NO_CHANGES_REGISTERED_MESSAGE when no fields survive the filter.
// AbstractAuditLogFormatter
protected function buildChangeDetails(array $change_set): ?string
{
    // ... same loop, unchanged ...

    if (empty($changed_fields)) {
        return null; // was: return self::NO_CHANGES_REGISTERED_MESSAGE
    }

    return count($changed_fields) . ' field(s) modified: ' . implode(' | ', $changed_fields);
}
  1. Each concrete formatter propagates the null out of format():
case IAuditStrategy::EVENT_ENTITY_UPDATE:
    $details = $this->buildChangeDetails($change_set);
    if ($details === null) return null; // no meaningful scalar change — skip entry
    return sprintf('Entity (%s) updated: %s by %s', $id, $details, $this->getUserInfo());
  1. Remove hasMeaningfulChanges() from AbstractAuditLogFormatter and the block at lines 65–71 from AuditLogOtlpStrategy. The guard at line 73 already handles null and skips the job dispatch — nothing new needed in the strategy.

The valuesAreEffectivelyEqual() logic in formatFieldChange() is correct and should stay — that is what suppresses unchanged scalar fields. Only the signalling path needs fixing: unchanged → null from buildChangeDetails() → null from format() → early return at line 73.

Copy link
Copy Markdown
Collaborator

@smarcet smarcet left a comment

Choose a reason for hiding this comment

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

@andrestejerina97 please review

@github-actions
Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-547/

This page is automatically updated on each push to this PR.

@andrestejerina97 andrestejerina97 force-pushed the fix/reduce-noise-logs branch from 13b5897 to aabffc5 Compare May 26, 2026 21:05
@github-actions
Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-547/

This page is automatically updated on each push to this PR.

@andrestejerina97 andrestejerina97 requested a review from smarcet May 26, 2026 21:26
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.

3 participants