fix: MR/issue identity and window semantics

Problem

Three correctness defects in the merge-request (MR) and issue collectors:

  1. Project-scoped id stored as identity. mrs.go and issues.go stored the project-scoped iid as mr_id / issue_id. Two MRs (or issues) in different projects can share an iid, so any consumer keyed on mr_id / issue_id alone conflates distinct records.
  2. Asymmetric window semantics. Issue collection windowed on updated_after / updated_before, while MR and event collection bound on creation time. Mixed semantics across collectors skew domain comparisons.
  3. Null / ghost author bucketing. author decoded into a non-pointer struct, so a deleted author (author: null) became {ID:0}. Orphaned MRs and issues were bucketed under sentinel user 0.

Fix

  1. Add id (global, instance-wide id) to the gitlabMR and gitlabIssue structs and map it to MRID / IssueID. The iid is retained only for building per-project application programming interface (API) paths (/projects/:id/merge_requests/:iid), not as a stored identity. merge.go dedup keys renamed from IID to MRID / IssueID to match.
  2. Window issue collection on created_after / created_before for symmetry with MR and event collection. A doc comment records this as a deliberate choice; active-in-window (updated_after) semantics are deferred to a methodology pass.
  3. Decode author into a pointer so a deleted author is nil rather than {ID:0}; skip records with a nil or zero-id author. merge_user, closed_by, and assignees were already pointer / guarded and are unchanged.

Validation

  • make check passes on Go 1.24.2.
  • go test -race ./... passes on Go 1.24.2 (no data races).
  • Fails-on-old proof: with the global-id mapping reverted to the iid, TestCollectMRs_PaginationAndConversion fails ("duplicate mr_id 1 across distinct MRs (iid leaked into mr_id?)" and "global mr_id collision"). Restoring the mapping passes. New tests also cover the issue window params (created_*, never updated_*) and ghost-author skips for both MRs and issues.

Scope

Touches only the MR / issue / merge collectors and their tests. Three additional collector test files (incremental_test.go, integration_test.go, orchestrator_test.go) are updated only to keep their gitlabMR / gitlabIssue fixtures compiling against the new struct shape (pointer author, global id). pipelines.go and orchestrator.go are untouched (separate MR).

Merge request reports

Loading