Case Study: Retroactive Accountability in Code Review

Background

A developer (Developer A) submitted a large pull request implementing distributed workload scheduling and trigger workflows for a SaaS platform. The PR included a Loom video walkthrough and was reviewed and approved by the engineering lead (Lead).

Within the PR, Developer A included a UI enhancement: a progress bar and step count labels on completed workflow runs. This was a minor addition bundled into the larger feature PR.

Approximately three months after the PR was merged, the Lead flagged the UI enhancement as problematic, citing that the feature had been explicitly rejected in a prior review of another team member’s (Developer B’s) work.

Additional Context: Onboarding

Developer A had joined the team at the beginning of that month. The time between joining and the PR in question was spent on specification development and implementation of a large, complex feature (distributed workload scheduling) - their first assignment. This was a substantial piece of work that consumed the entire onboarding period, from spec through to PR.

As a new team member whose entire tenure so far had been heads-down on a single demanding deliverable, Developer A had no reason or bandwidth to be monitoring other team members’ PR reviews for implicit design decisions. The expectation that they should have absorbed tribal knowledge from reviews they were never part of - while simultaneously ramping up on a new codebase, writing specs, and delivering a major feature - is unrealistic.

This also undermines the “misunderstood the requirements” framing. There were no documented requirements regarding this UI pattern. Developer A made a standard UI decision (progress indicators and step counts on workflow runs) that would be considered common sense in most product contexts. The Lead’s preference against it existed only as an undocumented, uncommunicated opinion formed during a review of someone else’s work.

The Confrontation

The Lead raised the issue in a team chat, expressing frustration:

  1. The feature had been present in production for three months without being noticed
  2. It was “buried” inside an unrelated PR
  3. Developer A had not mentioned it during a recent standup when asked about related issues

Developer A responded that they were not aware the feature had been previously rejected, as that decision was made during a review of Developer B’s work - a PR Developer A was not involved in.

The Lead then created two issue tickets for the fixes and stated the feature should have been submitted as a separate PR.

Investigation

A thorough audit of all pull requests preceding the one in question was conducted, specifically searching for:

  • Any PR where the Lead formally requested changes related to progress bars or step count labels
  • Any PR where the Lead left inline comments rejecting such a feature
  • Any PR review thread discussing the feature in question

No such record was found. The Lead’s review history across all prior PRs showed no documented rejection of the specific UI elements in question. If a decision to reject this feature existed, it was made verbally or through a channel not captured in the version control system.

Analysis

What Developer A did wrong

  • Scope creep. Including a UI enhancement in a PR titled and scoped for backend distributed workload infrastructure is poor practice. It makes changes harder to review, trace, and revert independently. The Lead’s feedback that it should have been a separate PR is valid.

What the Lead got wrong

  • Failed their own review. The Lead approved the PR that contained the feature. The commit was visible in the diff. If the feature was unacceptable, the review process was the appropriate checkpoint to catch it - and it wasn’t caught.

  • Undocumented decisions. No formal record exists of the feature being rejected in a prior PR. If a design decision was made to exclude this UI pattern, it was not documented in a way that was accessible to the broader team.

  • Asymmetric information treated as shared context. The Lead assumed Developer A should have known about a decision made in a review Developer A was never part of. Without documentation, this expectation is unreasonable.

  • Retroactive framing. Raising the issue three months later and expressing frustration that it wasn’t disclosed during a standup implies intent or negligence on Developer A’s part. Developer A cannot be expected to have instant recall of every commit in a months-old PR, nor to self-report features they had no reason to believe were controversial.

  • Post-hoc justification. The Lead had been using the same UI containing the progress bar and step counts for three months without raising a concern. The feature was visible in the product every day. The claim that it was “always wrong” is undermined by the fact that it went unnoticed by the person who supposedly rejected it. This is further supported by the investigation findings: no prior PR blocking this feature exists anywhere in the repository’s history. If a documented rejection existed, this point would not hold. But it doesn’t. The combination of no prior record and three months of silent usage strongly suggests the objection was formed after the fact - a retroactive opinion dressed up as a prior decision.

The standup dynamic

The Lead expressed frustration that Developer A didn’t raise the issue during a standup. Developer A’s position - that they didn’t understand what specifically was being referenced, and wouldn’t have recalled a three-month-old commit on the spot - is reasonable. Standups are not retrospective audits. The expectation that a developer would proactively flag a routine UI addition from a prior quarter is misaligned with how engineering teams operate.

Systemic Issues

This situation exposes several process gaps:

GapImpact
No enforced PR scope boundariesUnrelated changes get bundled, reducing review quality
Design decisions made verbally or in isolated reviewsKnowledge stays siloed; team members unknowingly contradict prior decisions
No shared record of rejected featuresDevelopers cannot learn from decisions they weren’t present for
Approval treated as the author’s responsibility, not the reviewer’sThe person who approved the change later assigns blame to the person who submitted it

Key Takeaway

Code review is a shared responsibility. When a reviewer approves a PR, they are signing off on its contents. A reviewer cannot approve a change and then, months later, hold the author solely accountable for the inclusion of that change - particularly when the decision to reject it was never formally documented or communicated to the author.

Process improvements that would prevent recurrence:

  1. Enforce single-concern PRs through team norms or automated scope checks
  2. Document design decisions in a shared, searchable location (e.g., ADRs, issue trackers, or PR templates with a “design decisions” section) rather than relying on tribal knowledge from individual reviews
  3. Treat PR approval as accountability - reviewers share ownership of what they approve
  4. Default to good faith - when a months-old change surfaces as problematic, the first assumption should be miscommunication, not negligence

Follow-Up: The Pattern Repeats

Following the confrontation described above, the Lead created a ticket to address the UI issues. The ticket was specific. It included file paths, line numbers, and exact code changes. For the progress bar, the specified fix was to add an execution.status === "running" guard - meaning the progress bar should still render during active execution but not on completed or failed runs. For the step count labels, the fix was deletion of the relevant JSX block.

Developer A implemented exactly what the ticket described. The progress bar was guarded behind a running status check. The step count labels were removed. A pull request was submitted.

The Lead’s response: “No progress bar! Where did this idea come from??”

Developer A had followed the ticket to the letter. The ticket said to guard the progress bar with a status check. Developer A guarded the progress bar with a status check. The Lead reacted as though Developer A had invented the feature from scratch - the same reaction as the first incident, now directed at work that was explicitly specified in the Lead’s own ticket.

What this reveals

The first incident could be attributed to a communication gap - an undocumented decision, a missed review, tribal knowledge that wasn’t shared. Those are systemic issues with identifiable fixes. But the second incident cannot be explained by communication failure, because the communication was explicit. The Lead wrote the requirements. Developer A followed them. The Lead still reacted with surprise and frustration.

There are two possible explanations, and both point to the same place.

The first is that the Lead does not track his own decisions. He wrote a ticket specifying a status guard, then reacted to the implementation of that guard as if someone had gone rogue. Under this reading, the “where did this idea come from” is answerable in one sentence: it came from your ticket.

The second is that the Lead never thought carefully about what he wanted. He wrote the ticket on autopilot - specifying a status guard when his actual preference was full removal - and when the implementation surfaced a result that didn’t match his unarticulated intent, he directed the frustration at the implementer rather than at his own specification. Under this reading, the ticket was poorly written, and the Lead’s reaction was to the gap between his preference and his spec - but he framed it as Developer A’s error rather than his own.

Either way, the failure belongs to the person who wrote the requirements, not the person who followed them. Whether the Lead forgot what he specified or never specified what he meant, the result for Developer A was identical: following the documented process produced the same confrontation as not having one.

The first incident taught Developer A that undocumented decisions were dangerous. The second taught something worse: that documented decisions weren’t safe either. The variable that changed between the two incidents - the existence of explicit, written requirements - made no difference to the outcome.

For Developer A, this narrows the remaining good-faith interpretations considerably. The first time, the reasonable assumption was miscommunication. The second time, the requirements were written down, followed exactly, and still treated as a transgression. Whether that reflects a Lead who does not track his own decisions or one who does not think through his own tickets, the practical consequence is the same: the dysfunction is not in the process. It is in the person operating it.


Appendix: Source Conversation

The following is the team chat exchange that prompted this case study. Names have been replaced with roles.

Lead - 12:24 PM Don’t you think this is weird - it’s March now the feature has been there the whole time: Mate this is not good [link to specific commit in PR]

I don’t remember discussing this or where this idea came from

And the fact that it is buried in another PR

Why didn’t you mention anything on the standup we just had when I asked about it?

Developer A - 12:26 PM On the call I wasn’t exactly aware of what you were referencing as wrong because I was still paying attention to the issue we had - what exactly is the issue? It’s a low chance that I would’ve remembered if I made that specific change given the change was back in Dec

The PR has a loom video and you approved: [link to PR]

Lead - 12:27 PM My link is referring to the specific commit - The red bar and step counts

Developer A - 12:28 PM Okay I must have misunderstood the requirements at the time - my bad

[Note: Concession made to de-escalate and move on. Developer A did not actually agree that requirements were misunderstood - there were no documented requirements to misunderstand. The only valid criticism accepted was the scope creep (separate PR).]

Lead - 12:28 PM [link to issue ticket: missing wallet env vars causing intermittent failures] [link to issue ticket: remove red progress bar on completed runs and step count labels]

Lead - 12:28 PM Should’ve been a separate PR

Developer A - 12:29 PM Yea went out of scope there. Will fix those issues ASAP

[Note: Agreeable response to end the conversation and get back to productive work. The scope point is genuine; the implied acceptance of fault for the feature itself is not.]

Lead - 12:29 PM thx