fix: MR/issue identity and window semantics
Problem
Three correctness defects in the merge-request (MR) and issue collectors:
- Project-scoped id stored as identity.
mrs.goandissues.gostored the project-scopediidasmr_id/issue_id. Two MRs (or issues) in different projects can share aniid, so any consumer keyed onmr_id/issue_idalone conflates distinct records. - 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. - Null / ghost author bucketing.
authordecoded 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
- Add
id(global, instance-wide id) to thegitlabMRandgitlabIssuestructs and map it toMRID/IssueID. Theiidis retained only for building per-project application programming interface (API) paths (/projects/:id/merge_requests/:iid), not as a stored identity.merge.godedup keys renamed fromIIDtoMRID/IssueIDto match. - Window issue collection on
created_after/created_beforefor 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. - Decode
authorinto a pointer so a deleted author isnilrather than{ID:0}; skip records with anilor zero-id author.merge_user,closed_by, andassigneeswere already pointer / guarded and are unchanged.
Validation
make checkpasses 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_PaginationAndConversionfails ("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_*, neverupdated_*) 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).