Skip to content

Resolution: "Recursive block" concern #365

@nikomatsakis

Description

@nikomatsakis

Resolution: Recursive Blocking

This is a resolution document for the "recursive blocking" concern raised in #360.

Summary of the concern

Should someone who raised a concern be able to block an FCP that resolves their own concern? The current draft says no - the concern-raiser must convince another team member to block on their behalf.

Two views on reaching strong designs

Rust teams have always operated by consensus, not by voting. Consensus-based decision making aims to avoid some of the failure modes of voting:

The advantage of consensus-based decisions as compared with majority rule voting is that it avoids a fundamental problem often associated with voting. Voting may unintentionally result in a split or division in a group, a satisfied majority and disgruntled minority, a sense of winners and losers. [..] If a proposal is deeply troubling to even one person, that concern is respected; if it is ignored, the group is likely to make a mistake.

A Practical Guide for Consensus-Based Decision Making

However, consensus is not just one thing - there are many ways to structure a consensus process. Our de jure rules have always included release valves: RFC 1068 states that team leads can resolve deadlocks; our own docs require concerns to be seconded.

But our de facto process has been different. In practice, the right to block progress has been sacrosanct: any team member can raise a concern, and only that team member can withdraw it. We have never invoked the lead's tie-breaking power, and we have never required a concern to be seconded.

The question before us is whether to formalize this de facto practice - or to move toward a process where the team collectively decides when a concern has been addressed.

Common ground

Many Rust decisions are one-way doors that are challenging to change later. We're often evaluating hypotheticals and counterfactuals that we can't easily gather evidence about until after we've gone through the door.

The lang team is a small group of people (no more than 8) who work closely together and have established trust. The expectation is that when someone raises a serious concern, it won't be papered over - it will be engaged with genuinely. The dissenter may participate in the discussion thread, explain their concern in detail, and request a design meeting where they can prepare a document for focused discussion.

Both views agree on the following:

  • Minority perspectives matter. We intentionally select for high-judgment individuals who cover a wide range of perspectives. In any particular case, a given perspective may be represented by only 1-2 people. Each concern is an opportunity to learn new insights.
  • The cost of indecision is not zero. Choosing not to decide is still a choice with consequences.
  • Blocking comes with responsibilities. Concern-raisers should work to externalize their concerns, evaluate potential resolutions, and seek resolution rather than deadlock.
  • We can't achieve perfect foresight. Some constraints only emerge after shipping, regardless of how much deliberation we do beforehand.

Where the views differ is in how they weigh the tradeoffs. In View A, the dissenter may block the resolution; it cannot proceed without their agreement. In View B, the resolution proceeds if (a) enough of the team checks their boxes and (b) no other team member raises a concern. Both views agree that if someone else chooses to block, that is fine and a meaningful signal.

View A: Treasure dissent

Emphasis: the risk of making a misstep.

The process of reaching full-team consensus produces results we can feel more confident in. We weigh correctness higher than velocity, and treasure dissent when it arises. A decision without full consensus is a decision that cannot reach our confidence threshold to proceed.

Given the stakes of getting one-way-door decisions right, serious doubts from any team member should give us pause. Full consensus wouldn't scale to a large group, but it works for a team of around 6-7 trusted people. Beyond that size, we should spin up focused subteams anyway.

The risk of this view: We move too slowly, or get stuck entirely.

The mitigation: The burden falls on the dissenter. They must weigh carefully: is this really worth blocking? After thorough discussion, continuing to hold a blocking concern is a serious act. Anyone maintaining a block should explicitly confirm: is the risk high enough that "deciding to do nothing" is an acceptable outcome?

View B: Perfection is a process

Emphasis: the cost of not deciding and the limits of pre-ship deliberation.

The cost of indecision is real: lost momentum, missed opportunities, and the disenchantment that comes when people can't count on making progress.

What's more, consensus doesn't prevent the mistakes we should fear most. Many mistakes arose from decisions where nobody raised a concern at all.

Finally, blocking on consensus can sometimes paradoxically prevent us from solving the problem in a mutually satisfactory way. If consensus hasn't been reached after extensive discussion, it may be that what is needed is to ship something that unblocks the most critical use cases, even if it closes off some others. Shipping brings an influx of new experiences, new people, and new ideas that can reveal a path forward that wasn't under consideration before.

The risk of this view: We move when we should have stood still, or ship more than necessary.

The mitigation: The burden falls on the team. Particularly when the person who raised the original concern is still unsatisfied, the team should ask: can we ship something more minimal? What options exist to course-correct later? Is there a two-way door version of this decision?

The crux of the debate

Both views acknowledge they carry risk. Both have mitigation strategies. The difference is who bears the burden and what question they're asking.

Let us assume that there has been significant discussion and there is a proposal to move forward, but the dissenter that raised the original concern is not satisfied:

  • Under View A, the dissenter must decide if their concern is serious enough to be worth blocking forward progress. The team cannot proceed if the dissenter decides it is.
  • Under View B, the rest of the team must ask, "Have we engaged genuinely, and can we course-correct if we are wrong?" They can proceed if they all agree the answer is "yes", even over the dissenter's objection.

Put differently: when, after thorough discussion, a single team member remains unconvinced - which way do we tilt? View A tilts toward the dissenter's judgment. View B tilts toward the team's collective judgment.

Proposed resolution

Do not add recursive blocking. The person who raised a concern cannot block the FCP to resolve that concern.

However, add process scaffolding that encouages genuine engagement with concerns, particularly in cases where the concern-raiser does not sign off on the resolution:

  • Template for resolution write-ups, including specific reflection questions (see the FAQ for details)
  • Option for concern-raiser to request a design meeting before final decision is complete (where they provide the document)

Rationale: Niko's "vibe check"

I favor View B: perfection is a process. For me, it comes down to two things.

First, View A underestimates the cost of consensus. Yes, debate improves quality, but at the cost of time and morale, and with sharply diminishing returns. In my experience, we map out the problem space fairly quickly. What follows is protracted rehashing of the same points that can be extremely frustrating.

Once the space is mapped, I trust the team as a whole to decide whether we should (a) move forward with a subset, (b) pick a direction, or (c) do nothing at all. With 100% consensus, a single person can have undue influence on that decision, and that doesn't feel right to me.

Pushing a new feature over the line is a lot of work and people need to know they can make progress in a reasonable period of time. If a single team member can block the process indefinitely and nobody can do anything about it, then the team cannot make that promise. And when people can't count on progress, they become disenchanted with the process entirely.

Second, View A exaggerates the cost of mistakes and consensus's ability to prevent mistakes. I believe strongly in stability without stagnation. We've shown that just because we make strong backwards compatibility guarantees doesn't mean we can't evolve the language. And it's a good thing, too, because the reality is that making mistakes is just part of the process, and 100% consensus doesn't prevent it.

We have walked through many one-way doors without anyone raising an eyebrow, much less a concern: think of things like "every value can be moved". Sometimes I think consensus can even make it harder for us to prevent mistakes, as protracted debate around one issue (say, whether to write await x or x.await) exhausts everyone so much that other weighty questions get short shrift.

In those cases where we made decisions that were clearly "wrong", for the most part, I don't regret it. Take the "Leak-pocalypse": we shipped 1.0 without guaranteed destructors, and I'm glad we did. The fixes we had at the time (focused on 'static) weren't the right ones anyway. We're in a better position now to get the design right, even with backwards compatibility constraints, precisely because we shipped something. That let us see where the lack of guaranteed destructors really hurts us and also gave us more time to invent alternatives.

--nikomatsakis

Proposed design axioms

This resolution suggests two design axioms for our decision-making principles:

Trust the team to decide, trust the champion to design. The team provides feedback, but we trust champions to weigh and balance that feedback into a coherent design. We trust the team to collectively make the final decision, not any individual.

Perfection requires progress. You can't know everything upfront - the full set of constraints only reveals itself as you take steps. Step carefully but deliberately into the future, confident that we can course-correct when we learn more.

FAQ

What is your proposed template for concern resolutions?

You've been reading it. I would start with a template like this:

# Resolution: *problem title*

## Summary of the concern

* Explain what's going on, give context

## Alternatives on the table

* Explain the design
* Cover common ground
* Present the alternatives 

## The crux of the debate

* Crystallize the key decision to be made

## Proposed resolution

* What you propose to do: short and to the point
* Details can come in the FAQ

## Rationale

* Your explanation of how you arrived at that
* This should be personal and draw on your experience
* Show how you are balancing the concerns

## FAQ

* Elaborate here
* Answer the standard FAQ (or put N/A if they don't apply)
    * What doors are closed with this decision? Can it be reversed? If so, how?
    * What would convince you that you were wrong about this decision?

What doors are closed with this decision? Can it be reversed? If so, how?

This decision is reversible. We could amend the decision process to add recursive blocking through a future FCP. The process scaffolding (template, design meetings) would remain valuable either way.

What would convince you that you were wrong about this decision?

For me (nikomatsakis): If we saw a pattern where people were following the "letter of the law" rather than the spirit - quickly moving to resolve concerns without deeply engaging. The process scaffolding is meant to prevent this, but if it doesn't work in practice, the underlying mechanism may need to change.

Signs that should prompt reconsideration:

  • Repeated "Cassandra concerns", where the concern was dismissed but proven right in hindsight
  • Shallow rationale used to address concerns
  • Team members feeling like there is no point in raising a concern because "the team won't listen anyway"

What wouldn't change my mind: concerns regularly being resolved without the concern-raiser checking their box. That alone doesn't bother me. Decisions will not always go the way we prefer - consensus is not unanimity.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions