Skip to content

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

Open
andrestejerina97 wants to merge 1 commit into
mainfrom
fix/reduce-noise-logs
Open

fix: reduces update logs that contain no actual changes#547
andrestejerina97 wants to merge 1 commit 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

  • New Features

    • Audit logs now suppress insignificant changes (e.g., datetime “noise” across time zones) and display a clear "no changes" message when nothing meaningful changed.
    • Event processing skips job dispatch for updates without meaningful modifications and records a debug trace when suppression occurs.
  • Tests

    • Added unit tests covering datetime-noise filtering and meaningful-change detection in audit logging.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

Formatter equality checks suppress semantically identical field changes (including same-instant DateTimes) and expose hasMeaningfulChanges(); the OTLP strategy checks this and skips emitting audit jobs for no-op updates. Unit tests verify date-noise suppression and job dispatch behavior.

Changes

Suppress Meaningless Audit Log Changes

Layer / File(s) Summary
Change detection and field-level equality suppression
app/Audit/AbstractAuditLogFormatter.php
Adds NO_CHANGES_REGISTERED_MESSAGE constant; implements valuesAreEffectivelyEqual(); updates formatFieldChange() to return null for effectively equal values; adds hasMeaningfulChanges(); buildChangeDetails() returns the constant when no changes remain.
Strategy integration and no-op suppression
app/Audit/AuditLogOtlpStrategy.php
Wraps audit() logic in try; for EVENT_ENTITY_UPDATE checks formatter->hasMeaningfulChanges($change_set) and logs+returns when false; dispatches EmitAuditLogJob::dispatch(...)->onQueue('audit-logs') for emission.
Unit tests: date-noise and suppression
tests/Unit/Audit/AbstractAuditLogFormatterDateNoiseTest.php, tests/Unit/Audit/AbstractAuditLogFormatterHasMeaningfulChangesTest.php, tests/Unit/Audit/AuditLogOtlpStrategyNoOpSuppressionTest.php
Add tests validating DateTime same-instant/second noise is ignored, meaningful changes are detected, hasMeaningfulChanges() behaviour, and that EmitAuditLogJob is skipped or dispatched appropriately.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • caseylocker
  • martinquiroga-exo

Poem

🐰 I nibble through timestamps, sniffing for what's true,
Same-second echoes hush—no false alarms ensue.
When moments differ, I trumpet the change loud and clear,
Otherwise I sit quiet, keeping logs sincere. 🎩✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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 PR title 'fix: reduces update logs that contain no actual changes' directly aligns with the main change: suppressing audit logs when no meaningful changes are detected.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reduce-noise-logs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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).

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