Storage limitation, GDPR Art. 5(1)(e), says personal data should be kept no longer than necessary for the purpose it was collected for. It is one of the easiest duties to break by accident, because adding a table or a cache is routine and adding the deletion path is the part everyone forgets. Here is how the bug ships and how a review catches it.
How it ships
A feature needs to remember something about a user: a support interaction, a device, an uploaded document. A new table goes in, the feature works, the PR is approved. Nothing about it looks wrong, because nothing about it is wrong as code. What is missing is invisible: there is no retention bound, no expiry job, and often no path for the existing delete-my-account flow to reach the new store.
Six months later there is personal data with no defined end of life, and possibly data that survives an erasure request, which is now also an Art. 17 problem.
What to look for in the diff
When a change introduces a new store of personal data, ask three questions in the review: what is the retention bound, what deletes it when that bound passes, and does the erasure path reach it. If any answer is missing, the change is incomplete from a data-protection standpoint even though it is complete as a feature.
The tell is usually a migration or model that adds a personal-data column with no corresponding change to a retention or deletion code path in the same PR.
What heygrc flags
heygrc is built to recognize a new personal-data store landing without a retention or deletion path and to raise it against Art. 5(1)(e), with Art. 17 noted where erasure is implicated, as a review comment. The point is to surface the missing half of the change while the author is still in it, not to make a legal determination. heygrc is in early access.