Skip to content

fix: group-detail file_count via explicit M2M, not stored events (#91)#97

Draft
agent-p1p wants to merge 1 commit into
masterfrom
pip/goggles-91
Draft

fix: group-detail file_count via explicit M2M, not stored events (#91)#97
agent-p1p wants to merge 1 commit into
masterfrom
pip/goggles-91

Conversation

@agent-p1p

@agent-p1p agent-p1p commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Closes #91

Summary

group_detail_shell_context() derived the group's member-log count from stored events (AuditFile.objects.filter(events__group=group)) rather than the explicit AuditFile.groups M2M. A duplicate-heavy upload whose group events are all deduplicated away stores zero AuditEvent rows for that group, yet create_events() still records the file-to-group link on the M2M (audit_file.groups.add(*group_ids)). So events__group is a subset of groups, and the shell count could only undercount — the group header ("coalesced from N member log(s)") and the Files-tab badge disagreed with the Files tab listing itself.

This contradicted every other file-count path in the app and the goggles#37 fix:

  • analysis.py audit_files_for_group() -> filter(groups=group)
  • analysis.py annotated_group_list() -> Count("audit_files_linked", distinct=True)
  • analysis.py group_summary() -> len(audit_files) (M2M-derived)

Fix

One line in forensics/views.py: events__group=group -> groups=group, making the shell count consistent with the rest of the app. Added an explanatory comment referencing #37 and #91.

Test

Extended the existing duplicate-heavy re-upload regression test (AuditLogIngestionTests.test_duplicate_heavy_reupload_keeps_group_link_with_zero_stored_events) with assertions that the shell context's summary.file_count and tab_counts.files both equal 2 (matching the Files tab), not the undercounted 1.

RED/GREEN proven locally: without the fix the new assertion fails AssertionError: 1 != 2; with the fix it passes.

Verification (run locally — goggles CI gates)

  • uv run python manage.py test147 passed
  • uv run ruff check . — clean
  • uv run ruff format --check . — clean
  • uv run python manage.py check — no issues

Pre-existing master CI breakage (NOT introduced by this PR)

origin/master (94630b0, #87) currently has failing CI due to a migration-graph conflict: two 0007_* leaf migrations (0007_auditfile_groups from #80 and 0007_add_auditevent_line_hash_engine_index from #87) both depend on 0006 with no merge migration, so manage.py test aborts with Conflicting migrations detected; multiple leaf nodes. Master's own CI run for 94630b0 is red on the "Run tests" step for this reason.

Because of this, this PR's CI test step will also fail until a merge migration lands on master. This PR deliberately does not include that merge migration (migrations are a sensitive path and the drift is unrelated to this fix). The local verification above was run with a throwaway merge migration to confirm this fix is correct in isolation; that throwaway is not part of the diff. The master migration drift is being escalated separately.

Sensitive paths

None. Diff is forensics/views.py (one-line query change + comment) and forensics/tests.py (regression assertions + import). No models, no migrations.


Open in Stage

Summary by CodeRabbit

  • Bug Fixes
    • Corrected file count calculations in group details to accurately include all linked files, including duplicates with zero stored events.

group_detail_shell_context() derived file_count from
AuditFile.objects.filter(events__group=group), which excludes
duplicate-only linked files (zero stored AuditEvent rows for the group
but still linked via the AuditFile.groups M2M recorded by
create_events). This contradicted every other file-count path
(audit_files_for_group, annotated_group_list, group_summary) and the
goggles#37 fix, so the group header / Files-tab badge undercounted while
the Files tab itself listed the full set.

Switch to AuditFile.objects.filter(groups=group), matching the rest of
the app. Add a regression assertion to the existing duplicate-heavy
re-upload test confirming the shell count equals the Files tab count.

Closes #91
@coderabbitai

coderabbitai Bot commented Jun 22, 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: CHILL

Plan: Pro

Run ID: c7f83b53-d1d6-44a1-b8b5-495579b73097

📥 Commits

Reviewing files that changed from the base of the PR and between 94630b0 and 2867abd.

📒 Files selected for processing (2)
  • forensics/tests.py
  • forensics/views.py

Walkthrough

group_detail_shell_context in forensics/views.py now computes file_count by querying AuditFile.objects.filter(groups=group).distinct().count() instead of inferring file membership from stored AuditEvent rows. A regression test asserts that the returned count matches the Files tab and group-list table, including duplicate-only files with zero stored events.

Changes

Fix file_count undercount in group_detail_shell_context

Layer / File(s) Summary
file_count query fix and regression test
forensics/views.py, forensics/tests.py
group_detail_shell_context now derives file_count from AuditFile.groups M2M membership with .distinct().count() instead of filtering through AuditEvent rows. Explanatory comments document the deduplication scenario. The test module imports group_detail_shell_context and the existing duplicate-heavy reupload test gains assertions that file_count matches both the Files-tab count and the per-group detail row count, including the duplicate-only file with zero stored events.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 accurately and concisely describes the main change: fixing the group-detail file count to use explicit M2M relationship instead of stored events, which is the core issue addressed in the 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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pip/goggles-91

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.

@stage-review

stage-review Bot commented Jun 22, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 2 individual chapters for you:

Title
1 Fix group-detail file count logic
2 Verify file count consistency in regression tests
Open in Stage

Chapters generated by Stage for commit 2867abd on Jun 22, 2026 12:35pm UTC.

@agent-p1p

Copy link
Copy Markdown
Contributor Author

Pip adversarial review

Verdict: no PR-diff blocking findings.

Findings:

  • blocking: 0
  • suggestions: 0
  • nitpicks: 0

Reviewed scope:

  • forensics/views.py: group_detail_shell_context() now counts linked files via AuditFile.groups instead of events__group, matching audit_files_for_group(), annotated_group_list(), and group_summary().
  • forensics/tests.py: existing duplicate-heavy reupload regression now asserts the shell header count and Files-tab badge include the duplicate-only linked file.

Verification run:

  • uv run ruff check forensics/views.py forensics/tests.py — pass
  • uv run ruff format --check forensics/views.py forensics/tests.py — pass
  • DJANGO_DEBUG=1 uv run python manage.py check — pass
  • DJANGO_DEBUG=1 PYTHONPATH=/tmp:$PWD DJANGO_SETTINGS_MODULE=goggles_review_settings uv run python manage.py test forensics.tests.AuditLogIngestionTests.test_duplicate_heavy_reupload_keeps_group_link_with_zero_stored_events — pass (temporary review settings disabled only the conflicting forensics migrations so the regression could execute)

CI note: GitHub Django tests and checks is red before tests run because master currently has divergent forensics migration leaves (0007_add_auditevent_line_hash_engine_index, 0007_auditfile_groups). Existing follow-up: #96. Do not merge until that is resolved and this PR has green CI after rebase.

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.

Group detail shell file_count uses events__group, undercounting duplicate-only linked files (partial #37 regression)

1 participant