Tech Lead NotesRohit’s interview study guide
Chapter 09

Communication and Stakeholders

Design documents, status updates and escalations, working inside a client's engineering team, explaining trade-offs to people who don't write code, and running discussions that end in a decision.

5 topics
Parts marked Advanced are extra depth. Skip them on a first read or a quick revision.

#Writing a design document

Added

A design document is a decision made in writing before the code exists. It says what problem you're solving, what you're deliberately not solving, the design you propose, the alternatives you rejected and why, and what's still open. Its job isn't to describe the code (the code will do that); its job is to let the right people disagree with you while changing your mind is still cheap. A wrong API shape caught in a doc costs a comment; caught after two sprints in two time zones, it costs a rewrite and a partner migration.

A good mental model: the design doc is the code review you hold before the code. Reviewers can't comment on what they can't see, and on a distributed team they can't see what's in your head or in a call they slept through. Writing it down turns a design into something a developer in Pune, an architect on the client's platform team and a QA lead can each read at their own desk, comment on line by line, and sign off. It's also the most honest prototype you have: if you can't write the "Alternatives considered" section, you haven't considered any.

Malte Ubl's widely read description of the practice, Design Docs at Google (industrialempathy.com, July 2020), gives the usual sections (context and scope, goals and non-goals, the design, alternatives considered, cross-cutting concerns such as security, privacy and observability), suggests 10 to 20 pages for a large project and a 1 to 3 page "mini design doc" for smaller changes, and is just as clear about when not to write one: when the solution is obvious and there are no real trade-offs, or when the doc would only be an implementation manual. The template below follows that shape and adds what a client engagement needs: who decides, by when, and what changes for teams outside yours.

Design doc, ADR, RFC or PR description?

Teams use several written formats for decisions, and choosing the right one is part of the skill:

FormatSizeAnswersTypical audience
PR descriptiona few paragraphswhat this change does, why, how it was testedreviewers of one PR
ADRone pageone decision, its context and its consequencesthe team, future maintainers
Mini design doc1–3 pagesa small cross-team change: proposal, one or two alternativesa few reviewers outside the team
Design doc5–20 pagesa significant change: design, alternatives, rollout, risksseveral teams, an approver
RFC (request for comments)variesa proposal open to a wide audience, often an organisation-wide standardthe whole engineering org

The names vary between companies (some call every design doc an RFC); what matters is that the format's weight matches the decision's.

When a change needs a design doc

Write a doc when…Skip it (a ticket or a PR description is enough) when…
it changes a contract other teams or partners rely on (a REST or Telnet API, a settings schema, an event format)it's internal to one module and reversible in one PR
more than one team has to build or approve somethingone engineer can build and review it in a day or two
there are at least two credible designs and the choice has consequencesthere's one obvious way and everybody agrees
it touches security, data migration, firmware compatibility or the update pathit's a bug fix with a clear root cause
the work spans several sprints or several peopleit's a spike whose output is itself a short write-up
design-doc-template.md
# <Title: the change, not the project name>

Status: Draft | In review (comments close <date>) | Decided | Superseded by <link>
Author: <name>    Reviewers: <names and teams>    Approver: <one name>
Last updated: <date>    Tickets: <links>

## 1. Summary
Three or four sentences: the problem, the proposal, what it changes for whom.

## 2. Context
What exists today, with links. What's wrong with it, with evidence (bug counts, support tickets, metrics).
Assume the reader is a capable engineer who has never seen this part of the product.

## 3. Goals
- Measurable outcomes. "Saves are atomic" beats "better saving".

## 4. Non-goals
- What this deliberately does NOT do, so nobody reviews it for that.

## 5. Proposed design
### 5.1 Overview (a diagram)
### 5.2 API / interface changes (request and response examples)
### 5.3 Data and storage
### 5.4 UI changes
### 5.5 Compatibility and migration (old clients, old firmware, partners)

## 6. Alternatives considered
For each: what it is, why it's attractive, why it loses here.

## 7. Cross-cutting concerns
Security · privacy · performance on the device · observability · accessibility · localisation

## 8. Testing and rollout
How it's tested (unit, contract, integration, lab), how it's released (flags, stages), how it's rolled back.

## 9. Risks and open questions
| # | Question or risk | Owner | Needed by |

## 10. Decision log
| Date | Decision | Who decided | Why |

## 11. Sign-off
| Role | Name | Status |
What’s happening
  1. The header is for the reader who arrives from a link a year later. Status tells them whether this is a proposal, a decision or history; Superseded by stops someone implementing a design that was replaced. Approver is one name, not a committee: a doc with five approvers is a doc nobody can close (see Running technical discussions and making decisions).
  2. Comments close <date> makes the review asynchronous on purpose. Across a US–India split there's no hour when everybody is fresh. A comment window of a few working days lets every reviewer read it in their own morning, and the meeting, if there is one, only covers what the comments couldn't settle.
  3. Context comes before the design and carries evidence. "Two admins overwrite each other" is an opinion; "14 support tickets in Q3 traced to concurrent saves" is a reason. The context section is also where you link the existing API docs and code, because on a team with thin documentation the doc is often the first written description of how the current system works.
  4. Non-goals save more review time than any other section. Without them, reviewers ask for everything adjacent ("while you're there, can it also…?") and the doc grows into a project. Writing "Telnet commands are out of scope; separate doc" ends that thread before it starts.
  5. Alternatives considered is the section reviewers trust you by. If every alternative is a straw man, they assume you picked first and justified later. Give each one its real strength, then the specific reason it loses here.
  6. Open questions have owners and dates; the decision log records what was settled and by whom. Together they turn the doc from an essay into a working tool: the India team can see which questions block them, and nobody re-opens a decision without reading why it was made. This is the same discipline as an architecture decision record, but for a whole change rather than one decision.
AdvancedFilled example: device settings API change

A filled example: a device web UI and API change

Here's the template filled in for a change typical of the role: the web UI and REST API of a video-conferencing room device. This is illustrative. The device, the endpoints and the numbers are made up to show how a doc reads; they are not Poly's API or any real product's internals.

settings-v2-design.md
# Settings v2: atomic, conflict-safe settings saves for the device web UI

Status: In review (comments close Thu 12 Nov)
Author: <web UI/API lead>    Approver: <client platform architect>
Reviewers: API dev lead (India), web UI dev lead (India), Android platform team, QA lead, security
Tickets: WEB-412, API-388

## 1. Summary
The device web UI saves each changed setting with its own request, so a save can half-apply and two
admins can silently overwrite each other. We propose one PATCH request per save that is validated as a
whole, applied atomically, rejected if someone else saved first, and tells the UI which changes need a
restart. The existing v1 endpoints keep working for partners and older firmware.

## 2. Context
- The settings page calls PUT /api/v1/settings/{key} once per changed field (the network page sends up to 9).
- If request 5 of 9 fails validation, requests 1–4 are already applied: the device is half-configured.
- There is no concurrency check: the last writer wins. Support traced 14 tickets in Q3 to this.
- Some settings only take effect after a restart; the UI can't tell which, so it says "some changes may
  need a restart" after every save.
- Partner integrations and the cloud management service use the v1 endpoints; firmware 4.x devices will
  stay in the field for years and never get v2.

## 3. Goals
- One save = one request, validated in full, applied all-or-nothing.
- A save based on stale data is rejected, and the UI shows what changed.
- The response lists exactly which saved settings need a restart.
- v1 behaviour is unchanged for existing callers.

## 4. Non-goals
- New settings, or changes to which settings exist.
- Telnet / SSH command changes (tracked separately in API-401).
- Cloud management changes; the cloud service keeps using v1 until it opts in.

## 5. Proposed design
### 5.1 Overview
Web UI → PATCH /api/v2/settings → validate all → apply in one config-store transaction → respond.

### 5.2 API
GET /api/v2/settings
  200, ETag: "cfg-1742", body: { "network": { "dhcp": true, ... }, "audio": { ... } }

PATCH /api/v2/settings
  Content-Type: application/merge-patch+json      (RFC 7396)
  If-Match: "cfg-1742"
  body: { "network": { "dhcp": false, "ipv4": "10.0.4.20" }, "audio": { "echoCancel": true } }

  200  ETag: "cfg-1743"
       { "applied": ["network.dhcp", "network.ipv4", "audio.echoCancel"],
         "restartRequired": ["network.dhcp", "network.ipv4"] }
  412  Precondition Failed: someone saved since "cfg-1742"; body says which keys differ
  422  Unprocessable Content, RFC 9457 problem details, one entry per invalid field; nothing applied
  428  Precondition Required: If-Match missing

POST /api/v2/settings/validation      same body; validates only, never applies (dry run for the UI)

### 5.3 Data and storage
Needs an all-or-nothing multi-key write in the device's config store. If the store can't do that
(open question Q1), write to a staging copy and swap it in one step.

### 5.4 UI changes
One Save button per page; a summary of pending changes before saving; on 412, show the other admin's
values next to yours and let the user choose; a persistent "Restart needed for: …" banner.

### 5.5 Compatibility
v1 endpoints stay, re-implemented on top of the v2 apply path, so both share validation. v2 is only
offered by firmware that advertises "settings.v2" in GET /api/capabilities; the UI falls back to v1.

## 6. Alternatives considered
A. Keep per-field PUTs and retry failures in the UI. Smallest change; still not atomic, still last-writer-wins.
B. PUT the whole settings document. Atomic and simple, but every save sends ~40 KB, and an older UI
   would reset settings it doesn't know about (newer firmware adds them).
C. JSON Patch (RFC 6902). More expressive (array operations, test ops), but harder for partners to
   produce by hand, and no setting today is an array that needs element edits. Merge Patch is enough.
   Known limitation: Merge Patch can't set a value to null (null means "remove"); no setting is nullable today.

## 7. Cross-cutting concerns
- Security: same roles as v1 (admin only); every save writes one audit entry with the diff and the user.
- Device performance: one transaction instead of up to 9 requests; to be measured on the lowest-spec model.
- Observability: count 412 and 422 responses; a rising 412 rate means admins are colliding.
- Accessibility: the conflict view must work with a keyboard and a screen reader.

## 8. Testing and rollout
- Contract tests generated from the OpenAPI spec; a concurrency test (two saves, one stale → 412).
- Lab: power-cut during save → device boots with either the old or the new settings, never a mix.
- Behind a feature flag on 5.x builds; lab devices → internal beta fleet → general release.
- Rollback: turn the flag off; the UI falls back to v1 automatically.

## 9. Risks and open questions
| #  | Question or risk                                              | Owner           | Needed by |
| Q1 | Does the config store support multi-key transactions?         | Android platform| 10 Nov    |
| Q2 | Authoritative list of restart-required settings               | Android platform| 13 Nov    |
| R1 | Cloud service sees ETag changes it didn't cause; may resync more | Cloud team    | before beta |

## 10. Decision log
| Date | Decision | Who | Why |
| 3 Nov | Merge Patch over JSON Patch | API lead + author | Partners write it by hand; no array edits needed |

## 11. Sign-off
| Role | Name | Status |
| Approver (client platform) | | pending |
| Security | | pending |
What’s happening
  1. The summary is written last and read first. Four sentences tell a busy approver the problem (half-applied saves, silent overwrites), the proposal (one atomic PATCH with a conflict check), and the blast radius (v1 unchanged). Most stakeholders read only this and section 9; write them for that.
  2. The context proves the problem with things a reviewer can check: the request count per page, the half-applied failure mode, the 14 support tickets, and the fleet fact that 4.x devices never get v2. That last line is what makes compatibility a goal rather than an afterthought, and it's specific to device platforms: you can't upgrade every client at once, because some clients are firmware in a drawer.
  3. The API section shows requests and responses, including the failures. If-Match with an ETag gives optimistic concurrency (RFC 9110's 412 Precondition Failed when the tag is stale, and 428 Precondition Required from RFC 6585 when it's missing); 422 with RFC 9457 problem details lists every bad field so the UI can mark them all at once; the validation endpoint gives the UI a dry run. Reviewers argue about shapes, so give them the shapes.
  4. Alternatives are given their real strengths. Whole-document PUT is simpler and atomic; it loses on payload size and on a subtle compatibility bug (an older UI wiping settings it doesn't know). JSON Patch is more expressive; it loses on partner ergonomics. The Merge Patch limitation (no way to set null) is written down where a reviewer will find it, rather than discovered by a partner.
  5. Open questions are owned by other teams and dated. Q1 and Q2 belong to the Android platform team, and the whole design depends on Q1. Putting a date on it is how you turn "waiting on platform" into something a status update can report and, if needed, escalate (see Status updates and escalation).
  6. The decision log already has an entry while the doc is still in review. Small decisions get made during drafting; logging them with the reason stops the same argument recurring in every review round, and tells the India-based leads which questions are settled so they can start the parts that don't depend on Q1.
AdvancedHow the review runs across time zones
Draft author + 1–2 Async review 3–5 working days Review meeting open items only Decided approver signs Build, keep kept current big change? revise and re-share India and US comment in their own day the meeting uses the overlap hour
Most of the review happens in writing; the meeting is for what writing couldn't settle.

The meeting is the exception, not the default. When you do hold one, send the agenda as a list of unresolved comment threads, give everyone ten minutes at the start to reread them, and end with each thread marked resolved, accepted or turned into an open question with an owner. Record the outcome in the decision log the same day; the India-based team will read it in their morning and start work, so a decision that only lives in the meeting is a decision they don't have.

AdvancedReviewing a design doc someone else wrote

As the lead you'll review more design docs than you write, many of them from engineers on your India-based team who are writing their first. The review is both quality control and teaching, so it has two passes.

First pass: is it the right problem and the right shape? Read only the summary, context, goals and non-goals. Ask:

  • Is the problem real and evidenced, or assumed?
  • Would I know, from the goals, whether the finished work succeeded?
  • Is anything missing from the non-goals that reviewers will otherwise demand?
  • Does someone outside the team (partners, the platform team, the cloud service) depend on this? Are they reviewers?

If the first pass fails, stop and say so in one comment ("Before the details: I think the goal should be X, because Y. Can we agree that first?"). Line comments on a design that's solving the wrong problem waste both people's time.

Second pass: does the design hold up? Now read the design and alternatives:

  • Contracts: are request and response examples given, including errors? What does an old client or old firmware see?
  • Failure: what happens on a timeout, a reboot mid-operation, a power cut, two users at once?
  • Device cost: memory, CPU, connections, flash writes on the lowest-spec model. Measured or guessed?
  • Security: who can call it, what's logged, what's exposed on the network?
  • Testing and rollout: can it be tested in CI, does it need the lab, how is it turned off?
  • Alternatives: is the strongest alternative given a fair hearing?

Write comments the way you'd want them on your own doc: label the weight ("blocking:", "question:", "suggestion:", "nit:"), explain the reason, and propose something when you can. "Blocking: a 412 here means the UI loses the user's edits; could the response include the current values so the UI can show both?" teaches; "This won't work" doesn't.

Which of these needs a design doc?

Your team is asked for four changes this sprint. (a) Rename an internal React component and its file. (b) Add a restartRequired field to every settings response of the public REST API. (c) Fix a bug where the language dropdown shows the wrong default. (d) Replace the polling status page with a WebSocket stream from the device. Which ones get a design doc, and how big?

Show answer

(b) and (d) get a doc; (a) and (c) don't. (b) can be a 1–2 page mini doc; (d) needs a full one.

What’s happening
  1. (a) is internal to the web UI, one PR, trivially reversible, with no consumer outside the team: a PR description is enough.
  2. (b) looks small but changes a public contract: partners and the cloud service parse those responses, and older firmware won't have the field. A short doc settles the field name, when it's present, what older clients see and how it's documented in the OpenAPI spec. That's a mini design doc: one decision, a few reviewers, but written down because outsiders depend on it.
  3. (c) is a bug with a clear cause and fix; a ticket and a test are the right paperwork.
  4. (d) changes device resource use (open connections on a constrained device), adds a new interface the platform team must support, has real alternatives (SSE, long polling, smarter polling) and needs a reconnection story for reboots. That's every row of the "write a doc" table: a full doc with alternatives, device performance and rollout sections.
  5. The rule underneath: size the doc to the cost of being wrong and the number of people outside your team who depend on the decision, not to the number of lines of code.

#Status updates and escalation

Added

A status update exists to change what its reader does next. A sponsor reads it to decide whether to worry, a client PM to decide what to tell their management, a dependent team to decide whether to start their part. So a good update leads with the answer to "are we on track for what we promised, and do you need to do anything?", then gives just enough evidence to trust that answer. Everything else is detail for those who want it.

Escalation is the other half: asking someone with more authority or a wider view to make a decision or remove a blocker that you can't, before it costs the date. It isn't complaining, and it isn't blame. Done well it's the most useful thing a lead does for a team, because the alternative is engineers in two time zones quietly waiting on a decision that nobody with the power to make it knows is needed.

A good mental model for both is a weather forecast. It says what it's like now, what's coming, how sure it is, and what to bring. It's issued on a schedule whether or not the weather is interesting, and a forecaster who said "sunny" until the storm hit would never be trusted again. Your status is the same: regular, honest, forecast-shaped, and early about bad news. The single rule that matters most with stakeholders is no surprises: they can handle late, they can't handle late and unannounced.

Red, amber, green: agree what the colours mean

Most teams report each workstream as green, amber or red (RAG). The colours are useless unless everybody agrees what they mean before anything goes wrong; otherwise every lead's instinct is to report green until it's obviously red (a "watermelon" status: green outside, red inside). Write the definitions down with the client at the start. One workable set:

StatusMeansWhat the reader should do
Greenon track for the committed date and scope; no blocker older than a daynothing
Amberat risk: forecast slipped a little, or a blocker is ageing; the team has a planread the plan; be ready to help
Redwill miss the date or scope without a decision or help from outside the teammake the decision or give the help we ask for, by the date we give

The model below applies a rule set like that to four items of a web UI/API workstream. The thresholds are an example of what a team might agree with its client, not a standard.

status-rag.mjs
// Turns a workstream's facts into a RAG status and an "escalate?" answer, using rules agreed with the client up front.
// Dates are ISO strings; "working days" skip Saturday and Sunday (no holiday calendar in this model).
const RULES = { amberSlip: 1, redSlip: 6, amberBlocker: 2, redBlocker: 4 }; // working days

const day = (iso) => new Date(`${iso}T00:00:00Z`);
function workingDaysBetween(fromIso, toIso) {
  let n = 0, sign = 1, a = day(fromIso), b = day(toIso);
  if (b < a) [a, b, sign] = [b, a, -1];
  for (const d = new Date(a); d < b; d.setUTCDate(d.getUTCDate() + 1)) {
    const wd = d.getUTCDay();
    if (wd !== 0 && wd !== 6) n++;
  }
  return n * sign;
}

function status(item, today) {
  const slip = workingDaysBetween(item.committed, item.forecast); // > 0 means late
  const blockerAge = item.blockedSince ? workingDaysBetween(item.blockedSince, today) : 0;
  let rag = "GREEN";
  if (slip >= RULES.amberSlip || blockerAge >= RULES.amberBlocker) rag = "AMBER";
  if (slip >= RULES.redSlip || blockerAge >= RULES.redBlocker) rag = "RED";
  // Escalate when it's red, or amber for a reason the team can't fix itself.
  const escalate = rag === "RED" || (rag === "AMBER" && item.cause === "external");
  return { rag, slip, blockerAge, escalate };
}

const today = "2026-11-04"; // a Wednesday
const items = [
  { name: "Settings page parity", committed: "2026-11-20", forecast: "2026-11-19" },
  { name: "Settings PATCH API", committed: "2026-11-13", forecast: "2026-11-17", cause: "internal" },
  { name: "Telnet command parity", committed: "2026-11-27", forecast: "2026-11-27", blockedSince: "2026-11-02", cause: "external" },
  { name: "Firmware upload page", committed: "2026-11-13", forecast: "2026-11-24", cause: "external" },
];

for (const it of items) {
  const s = status(it, today);
  const why = [s.slip > 0 ? `${s.slip} working days late` : "on time", s.blockerAge ? `blocked ${s.blockerAge} working days` : ""].filter(Boolean).join(", ");
  console.log(`${s.rag.padEnd(5)} ${it.name.padEnd(24)} ${why.padEnd(38)} ${s.escalate ? "→ escalate" : ""}`.trimEnd());
}
Result
GREEN Settings page parity     on time
AMBER Settings PATCH API       2 working days late
AMBER Telnet command parity    on time, blocked 2 working days        → escalate
RED   Firmware upload page     7 working days late                    → escalate
What’s happening
  1. The rules come first and are numbers, not moods. RULES says one working day of slip is amber, six is red; a blocker becomes amber after two working days and red after four. The exact values are a choice you make with the client; what matters is that they're agreed in advance, so a colour change is a fact rather than a confession.
  2. Slip is measured in working days between the committed date and today's forecast. workingDaysBetween walks the calendar and skips weekends, because "Friday to Tuesday" is two working days, not four. "Settings page parity" forecasts one day early, so the slip is -1 and it stays green.
  3. "Settings PATCH API" is two working days late (Fri 13 → Tue 17) and amber, but not escalated. Its cause is internal: the team knows why and has a plan (say, a reviewer was out). Amber with an internal cause goes in the update with the plan; it doesn't need anyone else to act.
  4. "Telnet command parity" is on time and still amber, and it is escalated. It's been blocked since Monday 2 November (two working days by Wednesday) on something outside the team, perhaps an answer from the platform team. The date hasn't moved yet; the blocker is what predicts that it will. Escalating at amber for an external cause is the "no surprises" rule in code: you raise it while there's still time for someone to fix it.
  5. "Firmware upload page" is seven working days late (Fri 13 → Tue 24) and red. Red always escalates, because by definition the team can't recover it alone: someone has to cut scope, move the date or unblock the dependency.
  6. What this shows: a status colour is a forecast plus a cause, and the escalation decision follows from both. Reporting by rule removes the temptation to keep a slipping item green for one more week, which is exactly how a two-day slip becomes a two-week surprise.
AdvancedA weekly status update template
weekly-status-template.md
Subject: <Workstream> status, week of <date>: <GREEN | AMBER | RED>

**Bottom line:** <one or two sentences: on track or not for <milestone> on <date>, and what you need from the reader, if anything.>

**Asks** (who, what, by when)
- <Name>: <decision or help needed> by <date>, because <consequence if not>.

**Milestones**
| Milestone | Committed | Forecast | Status | Note |
|---|---|---|---|---|

**Done this week**
- <outcome, not activity: "Settings PATCH API merged behind flag", not "worked on API">

**Next week**
- <the two or three things that move the milestones>

**Risks and blockers**
| Risk / blocker | Since | Impact | Owner | Next step |

**FYI** (no action needed)
- <decisions made, links to docs, demos recorded>
What’s happening
  1. The status is in the subject line. People triage email by subject; "Web UI/API status, week of 2 Nov: AMBER" tells a sponsor whether to open it now. If the colour changed since last week, say so ("AMBER, was GREEN").
  2. "Bottom line" goes first (the convention is often called BLUF, bottom line up front). Two sentences answer the only question most readers have. Everything below is evidence for those who want it.
  3. Asks have a name, a date and a consequence. "Need input from platform" is a sigh; "Ana (platform): confirm whether the config store supports multi-key transactions by Tue 10 Nov, or the settings save design slips a week" is something Ana can act on and her manager can prioritise.
  4. Milestones show committed and forecast dates side by side, so slippage is visible without anybody having to remember last week's numbers. Never quietly move the committed date; if it's re-planned, add a note saying when and why.
  5. "Done" lists outcomes, not activity. Stakeholders can't evaluate "worked on the API"; they can evaluate "merged behind a flag, contract tests green". Outcomes also make the India-based team's work visible to the client, which matters for how that team is valued.
  6. FYI is last and optional. It's where decisions and demo links go so the update doubles as a record, without burying the asks.
AdvancedThe template filled in

Here's that template filled in for the same four items as the model, as the client's PM and sponsor would receive it. It's illustrative: names, dates and items are made up.

weekly-status-2026-11-04.md
Subject: Web UI / API status, week of 2 Nov: RED (was AMBER)

**Bottom line:** Settings parity is on track for 20 Nov. The firmware upload page will miss 13 Nov:
it can ship 24 Nov if the platform team shares the signed-package format this week, later if not.
I need a decision from Sam by Fri 6 Nov (see Asks).

**Asks**
- Sam (client PM): choose by Fri 6 Nov between (1) platform shares the package format this week and
  the page ships 24 Nov, or (2) the page moves to the first 5.x update. Without either, 24 Nov slips further.
- Ana (platform): the Telnet command allow-list for 5.x, blocking since Mon 2 Nov; needed by Mon 9 Nov
  to keep 27 Nov.

**Milestones**
| Milestone             | Committed | Forecast | Status | Note                                   |
|-----------------------|-----------|----------|--------|----------------------------------------|
| Settings page parity  | 20 Nov    | 19 Nov   | GREEN  | 41 of 45 settings done                 |
| Settings PATCH API    | 13 Nov    | 17 Nov   | AMBER  | reviewer out 2 days; extra reviewer added |
| Telnet command parity | 27 Nov    | 27 Nov   | AMBER  | blocked on allow-list (Ask 2)          |
| Firmware upload page  | 13 Nov    | 24 Nov   | RED    | waiting for package format (Ask 1)     |

**Done this week**
- Network and audio settings pages merged behind the 5.x flag; contract tests green.
- Validation dry-run endpoint merged (design doc section 5.2).

**Next week**
- Remaining 4 settings; PATCH API review and merge.

**Risks and blockers**
| Risk / blocker            | Since | Impact               | Owner | Next step             |
|---------------------------|-------|----------------------|-------|-----------------------|
| Package format not shared | 28 Oct| firmware page date   | Sam   | decision by 6 Nov     |
| Telnet allow-list         | 2 Nov | Telnet parity date   | Ana   | answer by 9 Nov       |

**FYI**
- Demo of the new network page (6 min recording): <link>. Presented by Meera and Arjun (Pune).
What’s happening
  1. The subject shows the colour and that it changed ("RED (was AMBER)"). A reader who sees only the subject knows something got worse this week.
  2. The bottom line contains both the good news and the bad, with the date at risk and the decision needed. A sponsor who reads two sentences knows exactly what's needed and from whom.
  3. Each ask names one person, offers options and states the consequence of no answer. "Without either, 24 Nov slips further" makes the cost of not deciding visible, which is usually what gets a decision made.
  4. The milestone table matches the model's output: the same four items, committed next to forecast, colours by the agreed rules. The amber item with an internal cause carries its own fix ("extra reviewer added"), so nobody has to ask.
  5. "Done" is outcomes, and the FYI credits the India-based engineers by name with a link to their recorded demo. That's how the client comes to know and trust the people doing the work, not just their lead.
AdvancedEscalation ladder and message template

Escalating well

1 · In the team you + the engineer 2 · Peer team engineer or lead 3 · Leads together their lead + client PM 4 · Sponsor scope, date, money Go up a step only when the step below can't decide in time. Every step gets the same facts, one clear ask, a deadline, and a heads-up first.
Escalate to the lowest level that can make the decision, and tell the person you're going over before you do.

When to escalate is a judgement, but these are the common triggers for a lead on a client engagement:

  • A committed date or scope is at risk for a reason the team can't fix (a dependency, a decision nobody is making, a resource you don't control).
  • A blocker on another team has aged past the agreed limit and a direct, polite chase hasn't moved it.
  • Two stakeholders want incompatible things (the client PM wants the date, the platform architect wants the extra feature) and you're not the person who should choose.
  • Anything about security, data loss or safety, immediately, regardless of the schedule.
  • A person problem you can't solve at your level, raised privately with your own manager, never in a status email.
escalation-template.md
Subject: Decision needed by <date>: <the decision, in a few words>

<Name>, I need your help with a decision on <topic> by <date>.

**Situation:** <two or three sentences of fact: what's blocked, since when, what's been tried.>

**Impact if unresolved by <date>:** <the milestone, the date, the users or partners affected.>

**Options**
1. <option>: <consequence for date / scope / risk>. ← my recommendation, because <reason>
2. <option>: <consequence>
3. <do nothing>: <consequence>

**What I need from you:** <choose an option | unblock X | approve Y> by <date>.

<Name of the person whose area this touches> is aware and is copied. Happy to walk through it in <time slot>.
What’s happening
  1. The subject says it's a decision and when it's needed, so it's not mistaken for another status email. Escalations that read like updates get read like updates.
  2. Situation is facts only: what's blocked, since when, and what's already been tried. "We've asked twice, on 2 and 4 Nov, and the owner is on leave until the 16th" shows you did the work at the lower step, which is what makes escalating legitimate rather than impatient.
  3. Impact is stated in the reader's terms: the milestone, the date, the partner integration that breaks. A sponsor can't weigh "the PATCH endpoint is blocked"; they can weigh "the 5.x settings page ships a week late".
  4. Options include "do nothing" and a recommendation. You're escalating a decision, not a problem; arriving with options and a view is the difference between being seen as a lead and being seen as someone who needs rescuing.
  5. The ask is one verb and a date. Choose, unblock or approve, by Friday.
  6. The last line is the courtesy that keeps relationships intact: the person whose area this touches already knows, because you told them first and copied them. Going over someone's head without telling them is the fastest way to lose a peer's trust; telling them "I'm going to ask Priya to decide this, because we're stuck and the date is at risk" usually isn't resented.
AdvancedCommunicating during an incident

An incident (a release that breaks saving settings on some models, an API change that breaks a partner integration, a security report) changes the rules of status communication. People need updates on a clock, not when there's news, and they need to know what's known, what isn't, and when they'll hear next. The worst incident communication is silence while the team investigates; the second worst is a confident cause that turns out to be wrong.

incident-update-template.md
Subject: [INCIDENT] <short description> — update <n>, <time + time zone>

**Status:** Investigating | Identified | Mitigated | Resolved
**Impact:** <who is affected, how many, since when> (e.g. "devices on build 5.0.2 can't save network settings from the web UI; REST v1 and Telnet unaffected")
**What we know:** <facts only>
**What we don't know yet:** <open questions>
**What we're doing:** <current action, owner>
**Workaround:** <if any, for support and partners>
**Next update:** <time + time zone>, or sooner if anything changes.
What’s happening
  1. The subject carries the update number and a time with its time zone. On a US–India incident, "update at 9" is ambiguous by nine and a half or ten and a half hours, depending on the season; "update 3, 09:00 EDT / 18:30 IST" isn't.
  2. Status uses a fixed vocabulary (investigating → identified → mitigated → resolved), so readers can tell progress at a glance without parsing prose.
  3. Impact is the most important line: who, how many, since when, and just as important, what's not affected. "REST v1 and Telnet unaffected" tells partners whether they need to act.
  4. "What we don't know yet" is what keeps you credible. Saying "we don't know yet whether 4.x devices are affected; we'll know by the next update" is far better than guessing and correcting yourself later.
  5. Next update is a promise with a time, and you keep it even if there's nothing new ("no change; still investigating; next update 11:00 ET"). Regular updates stop stakeholders from interrupting the people fixing the problem.
  6. After resolution, a blameless write-up (what happened, why, what changes) goes to the same audience. That's where the root cause belongs, once it's confirmed, not in update 2.
AdvancedWhich news goes to whom, and when

What to say, to whom, and when

NewsWho hears firstHowWhen
a slip you can recover inside the sprintyour team, then the client PM in the normal updateweekly update, amber with a planthe next update
a committed date will be missedyour manager and the client PM, before the wider audiencea call or direct message, then writtenthe day you know, not the day it happens
a blocker on another teamthe owner on that team, directlymessage with the ask and dateas soon as it blocks
a security issue or data lossthe security contact and your managercall, then a written incident noteimmediately
a disagreement with the client's designthe person who owns the design, privatelyconversation, then a written summarybefore it's in a review with an audience
Green, amber or red?

Today is Wednesday. The Telnet API work is committed for the 27th and still forecast for the 27th. But the platform team has owed you an answer about which commands the new OS still allows since last Thursday, and you've chased them once. Using the rules in the model (amber after 2 working days blocked, red after 4), what's the status, and what do you do?

Show answer

Red, and you escalate today.

What’s happening
  1. Count working days blocked: Thursday → Friday → Monday → Tuesday → Wednesday. The blocker started Thursday, so by Wednesday it has aged four working days (Thu, Fri, Mon, Tue), which meets redBlocker: 4.
  2. The forecast date hasn't moved, but that's not what the rule measures. A four-day external blocker on a piece of work means the forecast is now a hope; the rule makes the colour follow the cause instead of the optimism.
  3. Red always escalates. You've done step 2 of the ladder (you chased the platform engineer once), so the next step is the platform team's lead, with the escalation template: the question, since when, the impact on the 27th, and the options (for example, build against the commands both OS versions support and add the rest later).
  4. Tell the platform engineer you chased that you're raising it with their lead and why. Then report it as red in the weekly update with the ask in the "Asks" section.
  5. The lesson: an on-time forecast with an old, external blocker is the classic watermelon. The blocker age is the leading indicator; the date is the lagging one.

#Working with a client's engineering team

Added

On a client engagement you're building part of someone else's product, inside their organisation, using their platform, their release train and often their repositories. The client's engineering team owns things you depend on (here, the Android OS build, the device SDK, the platform services and their architects' decisions), and they will maintain what you build long after your contract or project ends. You bring a workstream (the web UI and APIs), your own team (often a group of developers in India) and a responsibility to deliver it. Neither side can succeed without the other, and neither side reports to the other.

A good mental model: you're a guest with keys. You have real access and real responsibility, so you act like an owner: you flag risks, you hold a quality bar, you push back when something's wrong. But it's their house: they set the rules, they make the final call on things they'll live with, and you never rearrange the furniture without asking. The relationship runs on three things you can deliberately build: clear interfaces (who owns what, how changes are agreed), predictability (doing what you said, and saying early when you can't) and disagreeing well (pushing back with evidence, then committing to the decision).

A working agreement between the teams

The single most useful document at the start of an engagement is a short working agreement, written with the client's leads in the first couple of weeks (see the first 30, 60 and 90 days). It turns a dozen future arguments into a lookup.

working-agreement.md
# Working agreement: <your team> × <client team>     Last reviewed: <date>

## Who owns what
| Area | Owner (decides) | Consulted | Informed |
|---|---|---|---|
| Web UI (admin pages) | Our web lead | Client UX, QA | Client PM |
| Device REST / Telnet API contract | Client platform architect | Our API lead | Partners via release notes |
| Android OS, SDK, platform services | Client platform team | Our API lead | Us |
| Release dates and scope | Client PM | Our lead | Everyone |

## How changes are agreed
- API contract changes: design doc or OpenAPI PR, approved by <owner>; 3 working days to review.
- Changes in the other team's repo: PR reviewed by one of their CODEOWNERS; we never merge our own.
- Urgent decisions: <name> can decide alone within <scope>; logged in the decision log.

## Communication
- Overlap window: <e.g. 08:00–09:30 US Eastern = 18:30–20:00 IST in winter, 17:30–19:00 IST in US summer time>; standing sync <day/time>.
- Channels: <chat channel> for questions (answer within 1 working day), email for decisions, tickets for work.
- Weekly status: from us, <day>, to <list>. RAG definitions: <link>.
- Escalation path: engineer → leads → <client PM> + <our manager> → <sponsor>.

## Quality
- Definition of done: <link>. Required CI checks: <list>. Who signs off releases: <name>.

## When we disagree
- Raise it with the owner first, privately, with evidence; then in writing.
- The owner decides (table above). We record the decision and commit to it.
- Either side can ask to revisit if <named trigger> happens.
What’s happening
  1. "Who owns what" is a responsibility table in the style of RACI (Responsible, Accountable, Consulted, Informed), collapsed to the column that matters most in disputes: who decides. The device API contract is owned by the client's platform architect even though your team builds much of it, because the client supports it for years; the web UI is yours. Writing that down before the first disagreement prevents the worst one: two teams each believing they have the final say.
  2. "How changes are agreed" makes the review path explicit, including the review time. "3 working days to review" sets your expectations (and your plan); "we never merge our own PR in their repo" is a guest-with-keys rule that costs a little speed and buys a lot of trust.
  3. Urgent decisions get a named shortcut with a scope. Without one, every urgent question becomes a meeting, and across time zones a meeting is a day.
  4. Communication rules include the overlap window in both time zones and response-time expectations per channel. "Answer within one working day" lets an engineer in India post a question at the end of their day and know when to expect an answer, instead of pinging repeatedly. (More on async habits in Async communication that works.)
  5. "When we disagree" is agreed while nobody is disagreeing. It names the process (privately first, then in writing, then the owner decides, then commit) and a revisit trigger, so a later "disagree and commit" doesn't feel like losing, it feels like following the rules both sides signed up to.
  6. "Last reviewed" is there because the agreement drifts. Revisit it at a retrospective every quarter or when the team or scope changes.
AdvancedShared roadmaps and managing expectations

Expectations are set by what you say and by what you don't contradict. A few habits that keep them realistic:

  • One roadmap, owned by the client, with your workstream's items on it. Don't run a separate "real" plan in your own tool; two plans drift, and the client will believe theirs.
  • Commit to dates only for work you understand; give ranges for the rest. "Settings parity by 20 Nov; the firmware upload page 2–4 weeks after the platform answers Q1" is honest and still useful. A single date for unknown work becomes a promise you didn't mean to make.
  • Separate a forecast from a commitment out loud. "My forecast is the 13th; I'll commit once the spike is done on Friday." Clients hear a date as a promise unless you label it.
  • Every new request costs something visible. When a stakeholder adds scope mid-sprint, answer with the trade-off rather than yes or no: "We can add the audit log export; it moves the firmware page by about a week, or we drop the bulk import from this release. Which do you prefer?" The decision stays with the owner of scope, and nobody is surprised later.
  • Bring the India-based team into the relationship, not just into the work. Have their leads present demos to the client, put their names on the work, and route technical questions to them directly. A client who knows the people behind the work is more patient with it, and your engineers grow faster (see Delegation and trust without micromanaging).
AdvancedWhen the client changes priorities mid-sprint

Priorities will shift: a partner escalation, a trade show demo, a security fix. Shifting priorities are normal on a device platform; what you control is whether the change is explicit. When a client stakeholder asks your team to switch, say yes to the conversation and make the trade visible:

"Understood, the partner demo is the priority. If we move Meera and Arjun onto it now, the firmware upload page moves from the 24th to about the 2nd, and the settings work stays on track. Is that the trade you want? I'll update the roadmap and tell the team today."

Then do three things: confirm it in writing to the person who owns priorities (usually the client PM, even if a director asked), update the shared roadmap so nobody is surprised next week, and explain the why to your engineers, especially the ones being moved. A team that hears "drop that, do this" without a reason twice a month stops caring about the plan; a team that hears why stays engaged. If changes become constant, raise it in a retrospective with the client: maybe the sprint is too long, or the work needs a reserved capacity for interrupts (see Kanban and when it fits better).

AdvancedDisagreeing well, then committing

You'll disagree with the client's engineers: about an API shape, a security trade-off, a timeline. Disagreeing is part of the job; you were brought in for judgement, and silence when you see a problem is a failure of that job. The skill is disagreeing in a way that improves the decision and leaves the relationship stronger.

Amazon's Leadership Principles name this precisely: "Have Backbone; Disagree and Commit" asks leaders to challenge decisions respectfully when they disagree, and, once a decision is made, to "commit wholly" (amazon.jobs, Leadership Principles, checked October 2026). Jeff Bezos's 2016 letter to shareholders describes using the phrase himself when he disagreed with a team but trusted them to own the outcome. The point isn't Amazon; it's that disagreement and commitment are two phases of the same behaviour, and interviewers for lead roles ask for both.

A sequence that works:

  1. Understand their reasons first. Ask what constraints you might not see (support cost, a partner contract, the release train). Restate their position until they agree you've got it right.
  2. Raise it privately with the owner before any audience. Nobody changes their mind well in front of their team or their manager.
  3. Bring evidence and a proposal, not just a concern. Data, a failing test, a small prototype, an option that addresses their constraint.
  4. Propose a cheap way to find out if it's uncertain: a spike, a lab test, a time-boxed trial with a review date.
  5. Let the owner decide, and say clearly that you'll support whatever they choose.
  6. Commit visibly: build it properly, defend it to your team, don't relitigate in code review or say "I told you so".
  7. Write it down with a revisit trigger: what would make you both look at it again.

Here's that sequence written up after a disagreement about the design-doc example above. It's illustrative: the people and the situation are invented to show the shape.

disagreement-summary.md
Subject: Settings save for the 5.x launch: decision and follow-up

Ana, thanks for walking me through the release constraints today. Summary so we have it in writing:

**What we discussed:** I proposed shipping the atomic PATCH (settings v2 doc) with the 5.x launch.
Your concern: the config-store transaction support (Q1) won't be verified on all models before the
release branch is cut on 20 Nov, and a late storage change is riskier than the current behaviour.

**My concern, for the record:** per-field saves can half-apply (14 support tickets in Q3), and
partners will start building on 5.x from day one.

**Decision (yours, as API contract owner):** 5.x launches with the existing v1 per-field saves.
v2 ships in the first 5.x update, behind the "settings.v2" capability flag.

**What we'll do now:**
- Web UI: add the validation dry-run before saving, so most invalid saves are caught before any
  request is applied (us, by 18 Nov).
- Platform: verify Q1 on all models by 4 Dec (Ana's team).
- Docs: mark v1 per-field saves as "may partially apply" in the API reference (us).

**Revisit if:** support tickets about partial saves exceed 5 in the first month after launch, or Q1
is verified before 20 Nov.

I'm fully on board with this plan and will brief our team today.
What’s happening
  1. It opens by thanking and restating their constraint first: the release branch date and the risk of a late storage change. Ana can see her reasoning was heard, which is what lets her accept the record as fair.
  2. Your concern is stated once, factually, "for the record". Not to win, but so that if the risk materialises, the decision can be revisited on evidence rather than blame. Notice there's no adjective in it.
  3. The decision is attributed to its owner. The working agreement says the client's platform architect owns the API contract; the summary says so. That's what makes this disagree-and-commit rather than a grudging compromise.
  4. The follow-ups shrink the risk you were worried about inside the decision: the dry-run catches most invalid saves before anything is applied, the API reference warns partners, and Q1 gets a date. You've turned "we lost the argument" into "we lowered the risk of their choice".
  5. The revisit trigger is concrete and measurable: more than five tickets in a month, or Q1 verified early. It saves both sides from reopening the question every week, and gives your concern a fair, pre-agreed path back.
  6. The last line is the commitment, said out loud. Then live it: brief your team on why the decision is reasonable, build the v1 path properly, and never let your engineers hear "we're doing it their way" in a tone that says it's wrong.
AdvancedAsking good questions when documentation is thin

A legacy device platform usually has less written down than you need: the 4.x web UI may be the only specification of how a setting behaves, and the person who knows why a Telnet command answers the way it does may be on the client's platform team. You'll ask the client's engineers a lot of questions, and how you ask decides whether they're glad to help.

question-template.md
**Context:** <what I'm building, one line> (ticket <link>)
**Question:** <one specific question>
**What I've checked:** <docs, code, tests, devices tried, with what result>
**My current assumption:** <what I'll build if I don't hear otherwise>
**Needed by:** <date>, because <what it blocks>
What’s happening
  1. One specific question per message. "How does the network page work?" can't be answered in a reply; "When DHCP is switched off with no static IP set, does 4.x reject the save or keep the old address?" can.
  2. "What I've checked" shows you've done your homework and saves the expert from repeating it. It also often reveals the answer: half the time, writing it out makes you notice the test you hadn't run.
  3. "My current assumption" makes silence productive. If nobody answers, your team keeps moving on the stated assumption, and the expert can correct it in one line ("no, it keeps the old address"). Record the assumption in the ticket or the design doc's assumptions list.
  4. "Needed by" with a reason lets the expert prioritise you against their own work honestly, and it's the date you'll use if the question later has to be escalated.
  5. Teach your India-based engineers to ask the client this way too, and to ask directly rather than through you. You're not a relay; a lead who routes every question through themselves becomes the bottleneck and keeps the team from building its own relationships. (More on working this way in Shifting priorities and incomplete documentation.)
AdvancedWorking in the client's repositories and reviews

When your team commits to the client's repositories, follow their conventions before you suggest changing them: their branch naming, commit message style, PR template, CODEOWNERS and CI checks. Suggest improvements through their process (a proposal in their engineering forum or a design doc), not by doing it your way in your PRs. Reviews from their engineers on your team's code are a gift: they carry the context about the platform you lack, so make it easy for them (small PRs, clear descriptions, links to the ticket and the design doc) and respond quickly. And review their PRs when asked, with the same care and tone as your own team's: being a good reviewer on their code is one of the fastest ways to earn trust on a client engagement.

Who decides?

Your India-based API developer wants to rename a field in a Telnet command's response for consistency with the REST API. The working agreement above says the client platform architect owns the device API contract, your API lead is consulted, and partners are informed via release notes. The developer asks you to approve the PR. What do you do?

Show answer

You don't approve it alone: it's a contract change, so it goes to the client's platform architect for a decision, with your API lead's view and a compatibility plan.

What’s happening
  1. Find the area in the "who owns what" table: a Telnet command's response is part of the device API contract, so the owner is the client platform architect, not you.
  2. Renaming a field in a response is a breaking change for any partner script that parses it, and Telnet integrations are often brittle line parsers on old systems. Consistency is a good reason; it isn't enough on its own to break a contract.
  3. So the right move is to turn the PR into a proposal: what changes, why, who's affected, and a compatible alternative (keep the old field, add the new one, deprecate the old in release notes).
  4. Your API lead is "consulted" and gives a view; the architect decides; partners are "informed" in release notes if it goes ahead.
  5. Then explain the reasoning to the developer. This is mentoring as much as process: they learn why a device API is a contract, and they see that you follow the same rules you ask them to follow.

#Explaining technical trade-offs to non-engineers

Added

Product managers, client managers, sponsors and support leads make decisions that depend on technical facts, but they don't think in endpoints or threads. They think in outcomes, dates, costs and risks: what customers get, when, what it costs and what could go wrong. Explaining a trade-off to them is translation, not simplification: you keep the substance and change the units.

A good mental model is a menu with prices. Don't explain how the kitchen works; show two or three dishes, what each one gets the customer, what it costs (time, money, people, risk), and which you'd order and why. The listener's job is to choose; yours is to make the choice clear and the consequences honest. If you've given a lecture and they still can't choose, you've explained the wrong thing.

A few rules make the translation work:

  • Start with the decision and the deadline, not the background: "We need to choose by Friday how much of the old settings page to rebuild for the launch."
  • Two or three options, never one. One option is an announcement; five is a burden.
  • Describe each option by its consequences: what users get, when, what risk remains, what it costs later. Leave the mechanism out unless they ask.
  • Give your recommendation and the reason in one sentence. They're paying for your judgement.
  • Be honest about uncertainty with ranges and confidence, not false precision: "two to three weeks, fairly confident" beats "13.5 days".
  • Check understanding by asking what they'd tell their boss, not "does that make sense?"

Here's a written version for a decision a web UI/API lead might face during an OS migration. It's illustrative: the numbers and the situation are invented to show the shape.

tradeoff-one-pager.md
# Decision needed: how much of the settings page to rebuild for the 5.x launch     Needed by: Fri 6 Nov

## Why now
The 5.x release branch is cut on 20 Nov. The old settings page has ~120 settings; we've rebuilt 45.

## Options
| | A. Rebuild all 120 | B. Rebuild the top 45, link the rest to the old page | C. Rebuild 45, hide the rest until the first update |
|---|---|---|---|
| Admins get | one consistent new page | the new page for daily tasks; old-style pages for rare settings | the new page only; rare settings unavailable in the web UI for ~6 weeks |
| Launch date | slips ~3 weeks | on time | on time |
| Risk | rushed work on rarely used, poorly documented settings | two styles in one product; old page needs testing on 5.x | support calls from admins who need hidden settings |
| Cost later | none | ~2 sprints to finish the rest | ~2 sprints, plus support load |

## Recommendation: B
It keeps the date, covers the settings used most (support data: the top 45 are most
of settings-page traffic), and leaves nothing unreachable. The cost is a mixed look for a few
weeks, which we'd fix in the first update.

## What we need from you
Choose an option by Friday, and confirm whether a mixed look is acceptable for the launch.
What’s happening
  1. The title is the decision and its deadline. A sponsor can tell from one line whether this is theirs to make and how urgent it is. "Settings page update" would hide both.
  2. "Why now" is two facts, not a history: the branch-cut date and how far along you are. That's all the context a non-engineer needs to see why the choice can't wait.
  3. The table describes each option in the reader's units: what admins get, whether the date moves, what could go wrong, what it costs later. There's no mention of components, routing or API versions; those are the kitchen. Note that option C is a real option, even if you wouldn't choose it: sometimes hiding a feature is the right business call, and leaving it out makes the menu look rigged.
  4. "Risk" is concrete. "Rushed work on poorly documented settings" is something a PM can picture; "technical risk" isn't. Being plain about A's risk is what stops "just do everything" from looking free.
  5. The recommendation is one option with one reason, tied to evidence the reader trusts (support data). Then the ask: choose, and confirm the one judgement call (a mixed look) that's genuinely theirs.
  6. Notice the honest numbers: "~3 weeks", "~2 sprints", "~120". Ranges and approximations signal that these are estimates; a reader who later sees "3.5 weeks" won't feel misled.
AdvancedThe trade-off said aloud in a minute

The same trade-off, said out loud in a minute

Often you won't have a one-pager; you'll have a minute in a meeting with the client's director. The spoken version keeps the same skeleton (decision, options, recommendation, ask) but cuts to one consequence per option and says the recommendation twice, because listeners lose things that readers can scroll back to.

"We need a decision by Friday on the settings page for launch. We've rebuilt the 45 settings admins use most; there are about 75 rarely used ones left. We can rebuild them all and slip about three weeks, or launch on time with the rare ones on the old-style page, and finish them in the first update. I recommend launching on time with the old-style page for the rare settings. The cost is a mixed look for a few weeks. Are you comfortable with that, or is a consistent look worth the three weeks?"

That's about 95 words, well under a minute at a calm pace. It ends with a question that has two possible answers, both of which you can act on.

AdvancedTalking about risk: likelihood and impact

Non-engineers hear "risk" as "maybe bad". Make it concrete with two dimensions and a plan: how likely, how bad if it happens, and what you're doing about it.

RiskLikelihoodImpact if it happensWhat we're doing
Config store can't do multi-key transactions on the oldest modelmediumthe atomic save needs a staging-copy design: about a week moreplatform team verifying by 10 Nov; staging design drafted as a fallback
A partner script depends on the v1 field orderlowthat partner's integration breaks on upgradev1 responses unchanged; contract tests pin field order
Admins confused by two page styleshighmore support tickets for ~6 weeksin-page note, support briefed before launch

Three or four rows is enough; a risk register with thirty rows says "we haven't prioritised". Say which one you'd lose sleep over, and why.

AdvancedShow it: demos for stakeholders

For a web UI, the clearest explanation of a trade-off is often a two-minute demo. Showing the old-style page next to the new one answers "is a mixed look acceptable?" better than any paragraph. Keep demos for non-engineers short and outcome-shaped:

  1. Say what the viewer is about to see and what you want from them ("whether the old-style page is acceptable for rare settings").
  2. Show the user's task, not the code: an admin changing the network settings, saving, seeing the restart banner.
  3. Show the failure path too (a conflict, an offline device): that's where trust in the work comes from.
  4. End with the decision or feedback you need, and the date.

Record it (a few minutes of screen recording with narration) so the other time zone and the stakeholder who missed the call see the same thing. A recorded demo presented by the India-based engineer who built it does more for that engineer's visibility than any status line.

AdvancedAnalogies: useful, and when they mislead

Analogies help when they carry the one property that matters and nothing else. Technical debt as a loan is the classic: you borrow time now (ship faster), and you pay interest (every change in that area is slower) until you pay it back (refactor). It works because the interest is the point: debt isn't bad, unpaid debt that keeps growing is. A firmware fleet as cars on the road helps explain why an API can't just change: you can update the dealer's showroom (the cloud), but cars already sold (devices in the field) keep their old parts for years.

Analogies mislead when the listener extends them. "The API is like a contract" invites "so the lawyers can sort it out". Use one, say where it stops ("unlike a loan, nobody sends a bill; the interest shows up as slower releases and more bugs"), and move on to the real consequence.

AdvancedSaying no, and "not yet"

Much of trade-off communication is saying no to something reasonable. Turn a no into a choice: "Yes, if we move the firmware page to the next release; or not this release, and it's first in the next one." If something is genuinely unsafe (shipping Telnet enabled by default on a new device, skipping a security fix to hit a date), say that plainly, separately from the menu: some items aren't options. Tie it to something they already care about ("this is the kind of issue that ends up in a security bulletin with our name on it") rather than to principle.

Rewrite this for a sponsor

An engineer writes to the client's sponsor: "We can't use SSE because the device's embedded HTTP server buffers every response until the handler returns, so an event stream never reaches the browser; we'll need WebSockets or long polling, which means a new dependency in the platform image or more request overhead." Rewrite it as a sponsor would need it.

Show answer

Something like: "To show live device status in the web UI, we have two workable options. Option 1 needs the platform team to add a component to the device software, which costs them about a week and gives the smoothest live updates. Option 2 needs nothing from them and is a little less efficient on the device, but works with what's there today. I recommend option 2 for the launch and revisiting option 1 in the first update. Could you confirm by Thursday whether the platform team's week is available?"

What’s happening
  1. Find the decision hidden in the original: it's really "do we ask the platform team for work, or accept a less efficient approach?" That's a resource and timing question, which a sponsor can answer.
  2. Remove the mechanism (response buffering in the embedded server): it explains why SSE is out, which the sponsor doesn't need in order to choose. Keep it for the design doc.
  3. Translate each option into consequences: who has to do work, roughly how much, what users get, what it costs the device.
  4. Add a recommendation and the reason (no dependency for the launch; revisit later), and turn the ending into a single ask with a date.
  5. The result is shorter, has no jargon, and ends with something the sponsor can do. That's the test of a good translation: the reader can act on it.

#Running technical discussions and making decisions

Added

A technical discussion has one of two jobs: to reach a decision, or to build a shared understanding that a decision will need later. A discussion that does neither is a status meeting with whiteboards. On a distributed team every synchronous discussion is expensive: it uses the one or two overlap hours, it excludes whoever's asleep, and its conclusions evaporate unless written down. So a lead's job is to make each one count: the right question, the right people, the right inputs, a clear way to decide, and a record.

A good mental model: a meeting is a synchronous API call. It needs a contract: the inputs (a pre-read, the options, the constraints), the expected output (a decision, a list of open questions, owners) and a timeout (what happens if it doesn't converge). Calling it without inputs wastes everyone's time; calling it without a defined output means nobody knows whether it succeeded. And like any API call, if it can be done asynchronously (comments on a doc), it usually should be.

Who decides, and how fast

Two questions settle most process arguments before they start. Who decides? Atlassian's Team Playbook describes the DACI framework (checked October 2026): a Driver who runs the process and makes sure a decision happens by a date, one Approver who makes the call, Contributors who "have a voice, but not a vote", and the Informed, who are told the outcome. Naming those roles at the start of a contentious decision is half the facilitation.

How reversible is it? Bezos's 2016 shareholder letter observes that many decisions "are reversible, two-way doors", which deserve a light, fast process, and suggests most decisions should be made with "somewhere around 70%" of the information you wish you had. Irreversible, high-impact decisions deserve the full doc-review-approve path. The mistake teams make is using the heavy process for everything (slow) or the light one for contracts that partners will depend on for years (dangerous).

easy to reverse ←→ hard to reverse small ←→ large impact Lead decides, quickly short discussion, feature flag, review the result e.g. a UI layout change Design doc, owner approves alternatives, review window, one named approver e.g. a public API contract Engineer decides tell the team in the PR e.g. a component's structure Short ADR write down why, one reviewer e.g. a new dependency
Match the weight of the process to how hard the decision is to undo and how many people it affects.

A decision matrix, and why it's a conversation tool

When a team is split between options, a weighted decision matrix makes the disagreement visible: list the criteria, agree weights, score each option, add up. The total isn't the point. The point is that it shows which criterion the disagreement is really about. Here's one for "how should the device web UI get live status?" with weights from two teams who care about different things. The scores are illustrative.

decision-matrix.mjs
// A weighted decision matrix for "how should the device web UI get live status?", plus the check that matters:
// which weight would have to change for a different option to win. Scores (1–5) are the team's, from the discussion.
const criteria = ["device cost", "UI latency", "team effort", "proxy-friendly", "two-way"];
const scores = {
  "Poll every 2 s": [2, 2, 5, 5, 1],
  "SSE stream":     [4, 5, 4, 4, 1],
  "WebSocket":      [4, 5, 2, 3, 5],
};
const weightSets = {
  "web team":      [3, 3, 2, 1, 1],
  "platform team": [5, 1, 2, 2, 3],
};

const total = (w, s) => s.reduce((sum, x, i) => sum + x * w[i], 0);
function rank(w) {
  return Object.entries(scores).map(([name, s]) => [name, total(w, s)]).sort((a, b) => b[1] - a[1]);
}

for (const [who, w] of Object.entries(weightSets)) {
  const r = rank(w);
  console.log(`${who.padEnd(14)} ${r.map(([n, t]) => `${n} ${t}`).join(" | ")}`);
}

// Sensitivity: starting from the web team's weights, push one criterion's weight to 5 and see who wins.
const base = weightSets["web team"];
console.log(`\nweb team winner: ${rank(base)[0][0]}; what if one weight were 5?`);
criteria.forEach((c, i) => {
  const w = base.map((x, k) => (k === i ? 5 : x));
  const [first, second] = rank(w);
  const note = first[0] === rank(base)[0][0] ? "same winner" : "WINNER CHANGES";
  console.log(`  ${c.padEnd(15)} ${first[0].padEnd(15)} by ${String(first[1] - second[1]).padStart(2)}  ${note}`);
});
Result
web team       SSE stream 40 | WebSocket 39 | Poll every 2 s 28
platform team  WebSocket 50 | SSE stream 44 | Poll every 2 s 35

web team winner: SSE stream; what if one weight were 5?
  device cost     SSE stream      by  1  same winner
  UI latency      SSE stream      by  1  same winner
  team effort     SSE stream      by  7  same winner
  proxy-friendly  SSE stream      by  5  same winner
  two-way         WebSocket       by 15  WINNER CHANGES
What’s happening
  1. Each option gets a 1–5 score per criterion, agreed in the discussion. Polling scores high on effort and proxies (it's plain HTTP) and low on device cost and latency; SSE is strong everywhere except two-way messaging; WebSocket is two-way but costs more effort and is less friendly to some proxies.
  2. With the web team's weights, SSE wins narrowly: 4·3 + 5·3 + 4·2 + 4·1 + 1·1 = 40 against WebSocket's 4·3 + 5·3 + 2·2 + 3·1 + 5·1 = 39. With the platform team's weights, which put device cost first and value two-way messaging at 3, WebSocket wins 50 to 44. Same scores, different priorities, different answers: the matrix has shown that the teams don't disagree about the technologies, they disagree about the weights.
  3. The sensitivity check pushes one weight at a time to 5. Raising device cost, latency, effort or proxy-friendliness doesn't change the winner. Raising two-way flips it to WebSocket by a wide margin (59 to 44).
  4. So the discussion should stop debating protocols and answer one product question: does the web UI need to send messages to the device over the live channel (for example, interactive diagnostics), or only receive status? If yes, WebSocket; if no, SSE. That's a question with an owner (product or the platform architect) and it can be answered in a day.
  5. Also notice how close 40 and 39 are. A one-point margin is a tie; a decision matrix with a narrow margin is telling you the options are equivalent on what you measured, so pick the one that's easiest to reverse, or decide on the criterion you left out.
  6. What this demonstrates: a decision matrix is a facilitation tool. Its value is in exposing the criterion that drives the decision, so the discussion converges on the real question instead of on whoever argues longest.
AdvancedFacilitating so that everyone is heard
  • Send a pre-read 24 hours ahead (a working day earlier across time zones), with the question, the options and the constraints. Start the meeting with five or ten minutes of silent reading and commenting; people who'd never interrupt will write.
  • State the decision rule at the start: "We're aiming for agreement; if we don't have it by the end, Ana decides as API owner." People argue differently when they know how it ends.
  • Ask the quietest and most junior people first, by name, before the senior people anchor the room. On a mixed US–India call this matters doubly: the hierarchy and the accent of the most fluent speaker both pull the discussion.
  • Separate generating options from judging them. List options without criticism first; evaluate after. Early criticism kills the third option that might have been the best.
  • Keep a visible "parking lot" for good points that aren't this decision, with an owner each.
  • Summarise the decision, the reasons, the dissent and the actions out loud before ending, then write it within the day.
decision-notes.md
## <Decision>: <what was decided, in one line>       Date: <date>     Approver: <name>

**Question:** <what we were deciding>
**Options considered:** <A, B, C, one line each>
**Decision:** <option>, because <the deciding reasons>.
**Dissent recorded:** <who disagreed and why, in their words, if they want it recorded>
**Revisit if:** <measurable trigger>
**Actions:** <owner: action by date>
**Not decided (parking lot):** <item: owner>
What’s happening
  1. The heading is the decision, not the meeting name. Searching notes for "SSE" a month later should find "Decision: device status uses SSE", not "Sync 14 Nov".
  2. Options considered prove the alternatives were heard, which matters to the people who argued for them.
  3. The deciding reasons are what later readers need most; without them a decision looks arbitrary and gets relitigated by the next person who joins.
  4. Dissent recorded, in their words, is how you make disagree-and-commit safe: the person who lost knows their view is on the record, so they don't need to keep arguing it.
  5. Revisit if, actions with owners and the parking lot turn the meeting into work. For architecture-level decisions, the same content becomes an ADR.
AdvancedDeciding without a meeting

Many decisions don't need a call at all, which matters when the overlap is an hour a day. Two written patterns work well:

  • A decision request with a deadline ("lazy consensus"). Post the question, the options and your proposal in the team's channel or doc, and say "If there are no objections by 10:00 IST Thursday, we'll go with option B." Silence becomes agreement, objections surface in writing, and nobody waits for a meeting. Use it for two-way doors; for contracts, still get the owner's explicit approval.
  • A written decision by the approver. The driver collects comments on the doc, summarises the positions fairly (and checks the summary with the people who hold them), and the approver decides in a comment. Everyone in both time zones sees the same reasoning at the same time.
decision-request.md
**Decision needed by Thu 12 Nov, 10:00 IST / Wed 11 Nov, 23:30 ET:** which charting library for the diagnostics page.

Options: (A) the library the cloud portal already uses; (B) a lighter one, about a third of the bundle size.
Proposal: **B**, because the device serves the web UI from limited storage and the page only needs line charts.
Details and bundle numbers: <link to ADR draft>

👍 if you agree. Objections in this thread before the deadline; otherwise we go with B and I'll merge the ADR.
What’s happening
  1. The deadline is given in both time zones, and here it falls on different calendar days. Writing both prevents the classic "I thought you meant my Thursday" mistake.
  2. Options are one line each, the proposal is bold and has a reason tied to a real constraint (storage on the device). People can agree in seconds or object with something specific.
  3. The details live in a linked ADR draft, so the message stays short enough to read on a phone, and the decision is recorded in the right place when it's made.
  4. The rule for silence is explicit: no objection by the deadline means B. That's what makes it lazy consensus rather than "I posted it, nobody read it, I did what I wanted".
  5. This works because a library choice is a two-way door. Don't use it for a public API field name or a security default; those need the owner to say yes, not just nobody to say no.
AdvancedA 45-minute decision meeting across time zones

A shape that works when a decision really does need a call, held in the overlap window (for example 08:00–08:45 US Eastern, which is 18:30–19:15 IST in winter but 17:30–18:15 IST while the US is on daylight saving time; India doesn't change its clocks, so the overlap moves twice a year):

MinutesWhat happensWhy
0–5Driver states the question, the decision rule and the approvereveryone argues knowing how it ends
5–15Silent reading and commenting on the pre-readpeople who'd never interrupt get heard; latecomers catch up
15–30Open comments discussed, quietest and most junior first; criteria agreed before options are judgedthe discussion converges on the real disagreement
30–40Approver decides, or names what's missing and who gets it by whena meeting always ends with a decision or a dated next step
40–45Driver reads back decision, reasons, dissent, actionseveryone leaves with the same understanding

If the meeting can't decide, that's an acceptable outcome only if it ends with the specific missing input, an owner and a date. "Let's take it offline" without those is how a decision drifts for a month.

AdvancedWhen the discussion goes wrong
SymptomWhat's going onWhat to say
20 minutes on the name of a field, no time for the designbike-shedding: the easy topic expands"Let's park naming; Priya proposes three names in the PR. Back to the save semantics."
the same two people repeat the same pointsthey've stopped hearing each other"Let me restate both positions… Is that fair? The difference seems to be X. What would tell us who's right?"
one voice dominatesseniority, fluency or confidence"I'd like to hear from people who haven't spoken. Ravi, you built the 4.x page; what are we missing?"
silence from the offshore half of the callhierarchy, audio quality, or not wanting to disagree in publicask by name, and also ask for written comments by their morning
a decision needs someone who isn't therethe wrong attendeesstop, write down the question for them, set a date; don't decide around the owner
new options keep appearing at the endgenerating and judging weren't separated"Good idea. Is it better enough to delay the decision? If not, it goes in the parking lot."
One-way or two-way door?

Classify each: (a) choosing between two charting libraries for the admin UI's diagnostics page; (b) the JSON field names in a new public REST endpoint partners will script against; (c) the order of tabs on the settings page; (d) whether the device accepts Telnet connections from any network by default.

Show answer

(a) two-way, light process (a short ADR is enough); (b) one-way: design doc and the contract owner approves; (c) two-way: the lead or designer decides, ship and watch; (d) one-way, and a security decision: design review, security sign-off, owner approves.

What’s happening
  1. (a) A library choice inside the web UI can be undone and affects only your team, so it's a two-way door. Undoing it isn't free, though (every chart gets rewritten), which is why the diagram puts "a new dependency" in the "short ADR" quadrant rather than the free one: write down why, one reviewer, move on.
  2. (b) Public field names are a contract. Once partners script against them, and once firmware with them is in the field, renaming means a versioned API and years of compatibility. Hard to reverse, large impact: the full design-doc path, decided by the contract owner.
  3. (c) Tab order is fully reversible in the next release and low-stakes: decide quickly, ship, look at the data.
  4. (d) Telnet sends everything, including passwords, in clear text. A default that accepts connections from any network ships on every device and is very hard to take back from a fleet in the field. It's a one-way door and a security decision, so it needs security sign-off on top of the owner's approval.
  5. The test for each: if we're wrong, how expensive is it to undo, and how many people outside the team pay? That decides the weight of the process, not how interesting the argument is.

Written fresh for a lead full stack role. Git examples were run; GitHub Actions workflows were checked with actionlint. Behavioural stories are yours to write in My notes.

RohitDownloads · All chapters

Sync progress across devices

Type the same private phrase on your Mac and your phone, and your Learned ticks follow you between them — on every study site.

The phrase never leaves this device: only a fingerprint of it is sent, and the server stores a fingerprint of that. Anyone who knows the phrase could see or change your ticks, so pick something you don’t use elsewhere.

Sync is on in this browser.

Sync ID

This ID must be the same on every device. If another device shows a different one, its phrase is different (capital letters count): tap “Turn off here” on it and type the phrase again exactly.