Bristlenose · mockup

The People lens, at three scopes

One row per person — not per speaker code, not per session. The same lens answers a different question at each of three altitudes, and the change of question is what the scope control is really switching.

Fictional corpus used throughout, continuous with people-provenance-paths.html: client folder NHS Trust holds Ward handover app — round 1 (8 sessions, Sep 2025), round 2 (12 sessions, Jan 2026) and Discharge letters — diary study (on an external drive, currently unplugged). Client folder Kestrel Bank holds Mobile onboarding (6 sessions). At the root, in no folder: Oral history — early free software (10 sessions).

Palette Appearance follows your system light/dark
Artefact Inside a frame is product only — real tokens, the real section-heading atom, the real speaker badge and editable-name rules, the real subgrid construction. No labels that would not ship.
Commentary Hatched, ruled, mono-labelled. Says / true, and the consequence. Never the product.
ScopeThe question it answersWhat the researcher does hereWhat the app may propose
This project Are these the right people, with the right names and roles? Confirm a guess, type a name, fix a role, separate one code that holds two humans. Names, roles — it already guessed them during the run.
This client
(a folder)
Have I met any of these people before? Say "same person" or "different people" — once, and it holds. Matches, within this folder only.
Everyone Who do I actually work with? Read. Occasionally assert a link the app is not allowed to suggest. Nothing. Cross-folder matching is refused by design, not unbuilt.
Commentary — why this is not three filters

A filter narrows one list. These three change the object. At project scope the identity anchor is the speaker codep3 is who this person is, it is what the quotes say, it is what the export ships. One folder up, the same human is p3 in one project and p6 in another, so the code stops identifying anything and the name becomes the anchor. That inversion is why the People grid's degradation ladder drops the code column first, where the sessions grid drops the name first and keeps the badge (docs/design-sessions-grid ladder, rung 3). Same product, opposite priority, one altitude apart.

It is also why the scope control cannot be a segmented control that quietly re-filters. Moving up a scope changes what a row is, what the columns mean, and — the part with teeth — what the app is willing to propose.

Part 1 — the object What a row is, and where the scope control lives.

1 · The healthy case, and the row it establishes

Round 1. One moderator, platform-sourced names, nothing to fix. The sweep line under the heading is absent because its count is zero — which is the only way a count line earns its place.

People · project scope · 1120px proposed lens

People

Name
Role
Sessions
Words
Quotes
m1
Rachel Okonjo Senior UX researcher
Moderator
all 8
12,400
p1
Sarah Chen Ward sister, acute medicine
Participant
4,120
9
p2
Dr Amara Nwosu Registrar
Participant
3,880
12
p3
Marcus Bell Healthcare assistant
Participant
5,010
7
p4
Joyce Adeyemi Night charge nurse
Participant
4,640
11
Commentary
true as shown
New here
The whole organism. The section-heading atom, the badge, the editable name and the subgrid construction are all shipped; one row per person is not.
Reused deliberately
The scope control is .toolbar-btn + .toolbar-arrow — the same control as the tag filter and view switcher — sitting in the section-heading-action slot the Codebook Library button already occupies. No new control was invented for it.

The job-title line under each name (PersonEditable.role) is worth pausing on: it round-trips through people.yaml, it is filled by the same model pass that guesses the name, and it is rendered nowhere in the app todayget_people builds a three-key dict and drops it. So does persona, so do notes. This lens is the first surface where a researcher could see what the pipeline wrote about a named person. It is also, uncomfortably, already in the anonymised export (see bench 10).

scope control, open proposed
Commentary
one honest count, two guesses

Only the first count is knowable. 26 people for the client is the number of rows, not people — nothing is linked yet, so Rachel is three of those 26. And 58 silently excludes the diary study, which is on an external drive that is not plugged in. A menu is the wrong place to explain either. The lens has to, on arrival — bench 8.

Naming: the middle item carries the folder's real name rather than the word "folder", on the All Sessions precedent in docs/glossary.md — name a scope by its content. "Folder" is the app's word for the container; "NHS Trust" is the researcher's word for who these people are.

Part 2 — the four shapes of getting it wrong Two moderators · nobody named · roles inverted · the observer nobody invited.

2 · Two moderators, one code — and the lens is the only surface that could say so

Round 2. Rachel ran sessions 1–8, Priya ran 9–12. The moderator counter resets every session, so both are m1, and people.yaml is keyed by code alone — it is structurally incapable of holding two of them.

People · project scope · today's data proposed lens, shipped data

People

Name
Role
Sessions
Words
Quotes
m1
Rachel Okonjo Senior UX researcher
Moderator
all 12
4,210
p1
Sarah Chen Ward sister, acute medicine
Participant
4,120
9
Commentary
false, and the numbers give it away
Screen says
Rachel Okonjo moderated all twelve sessions, speaking 4,210 words.
Actually true
Rachel moderated eight. Priya Raman moderated four. 4,210 is Priya's word count from session 12 alone, wearing Rachel's name.

The two halves come from different places, which is what makes it undetectable by eye on the Sessions lens and detectable here. Editable fields are preserved by key across runs, so Rachel's typed name survives; computed stats are overwritten by key, so the last session in the run wins. The lens puts a name and a word count in the same row for the first time, and 4,210 words across twelve sessions is arithmetic nobody who moderates would believe.

This is the argument for the lens existing at all, and it is not a UI argument: the serve-mode database already models this correctly — SessionSpeaker joins person↔session per session, and its docstring says cross-session moderator linking is why it exists. The database knows more than the file does. A person-shaped surface is the only one that can show the difference.

People · after the per-session rekey proposed

People

One speaker code covers two names. Sort it out

Name
Role
Sessions
Words
Quotes
m1
Rachel Okonjo Sessions 9–12 introduce themselves as Priya Raman.
Moderator
all 12
18,900
p1
Sarah Chen Ward sister, acute medicine
Participant
4,120
9
Commentary
needs the rekey first — it is not a rendering change

The evidence for the contest already exists and is thrown away one step before it could be used. Stage 5b extracts a name per speaker per session from self-introductions; the pipeline then funnels it through a flat {code: info} dict, so session 9's "Priya" overwrites session 1's "Rachel" and no record survives that they disagreed. Rekey that dict — and people.yaml with it — by (session, code), and the contest becomes a two-line query.

Two deliberate restraints in the pixels. No error colour: the row takes --bn-colour-quote-bg, not a red or amber. Nothing has gone wrong for the researcher — the app has a question. No auto-split: two extracted names is strong evidence, not proof, and the same signal fires for one person who says "Rachel here, covering for Priya today". The app states what it heard and where; a human decides.

The sweep line says one thing and links to a place, on the pattern four review agents converged on independently: a count line under the heading costs no column width, survives every rung of the degradation ladder, and is one translated string rather than a mark on every one of thirty rows.

Separate — sheet proposed

Separate m1 into two people?

Bristlenose numbers moderators within each session, so one code can cover more than one person. Sessions 1–8 and 9–12 introduce different names.

Rachel Okonjosessions 1–8 · 12,100 words and Priya Ramansessions 9–12 · 6,800 words

Quotes are not affected — moderators do not have quotes. The speaker code stays m1 in both halves and in every transcript.

Commentary

Three buttons, and the third one matters. "Keep as one person" is not a synonym for Cancel — it records the decision, so the contest never re-appears on the next run. Without it the researcher who genuinely has one moderator with two names is nagged forever, which is how a correctness affordance gets switched off. It is the not_same half of the linking vocabulary, one altitude down.

The sentence beginning "Bristlenose numbers moderators…" is doing the load-bearing work: it explains the consequence before asking the researcher to choose, and it names the mechanism in a way that makes the question answerable rather than mysterious. Cancel is not the default; the trailing button is.

3 · Nobody named, and the two ways an absent name looks

The tail of round 2. Four participants, four different relationships between a row and a name: a real record, a guess, a researcher's own typing, and nothing at all. Only one of them is a name in the sense the researcher means.

A — reuse the shipped placeholder proposed

1 person has no name. 1 name is a suggestion. Review

Name
Role
Sessions
Words
Quotes
p9
Participant
Participant
3,400
5
p10
j.okafor@nhs.example
Participant
4,900
8
p11
Danny
Participant
3,100
6
p12
Hannah Wu
Participant
5,200
10
B — absence, plus the count line proposed

1 person has no name. 1 name is a suggestion. Review

Name
Role
Sessions
Words
Quotes
p9
Participant
3,400
5
p10
j.okafor@nhs.example
Participant
4,900
8
p11
Danny
Participant
3,100
6
p12
Hannah Wu
Participant
5,200
10
Commentary
open — A stutters, B risks reading as broken

A reuses the shipped placeholder and it stutters. speakerRolePlaceholder() renders the role word — "Participant" — in the name slot, which reads perfectly on the Sessions lens because no role column exists there. Move it into a table that has a Role column and row p9 says "Participant  ·  Participant". A string is only as good as the surface around it; this is a straight import of one lens's solution into another lens's geometry.

B leaves the cell empty and lets the count line carry it — the house move, and cheaper in every language. But an empty cell is pixel-identical to a failed fetch: the Sessions lens swallows a /people error in an empty catch and renders exactly this. What saves B is the line above the table: it is absent when the count is zero, so its presence is what distinguishes "one person is unnamed" from "the request failed" — and the failure path has to say something of its own for that to hold.

Only one of the four rows is a plain fact. Hannah Wu was typed by the researcher. "Danny" is the model repeating a first name it heard, set in italic and nothing else — one treatment, no chip, no dot, no extra tab stop, and it survives every rung of the ladder. p9 is silence.

And p10 is the one to worry about. An email address in the name column has the highest confidence of the four — it is a verbatim record from the Teams file, not a guess — and it is also direct, unambiguous, contactable PII, sitting in a field that ships in exports and reads as machine output rather than as a name. The confidence axis and the sensitivity axis are orthogonal, and the design so far only draws one of them.

4 · The roles are inverted, and only a person-shaped table shows it

Oral history — early free software. Ten interviews, one interviewer. Stage 5b tagged the interviewer as a participant and each interviewee as a moderator: exactly the failure the FOSSDA stress test found, now with its downstream cost visible.

People · project scope proposed lens, shipped data

People

Name
Role
Sessions
Words
Quotes
p1
Zach Kaplan
Participant
all 10
8,900
47
m1
Marta Ellis Debian maintainer, 1994–2003
Moderator
14,200
m1
Yusuf
Moderator
11,600
Commentary
every role on this screen is backwards
The tell
A participant in all ten sessions. Nobody is interviewed ten times in one study; a person who appears in every session is running them.
The second tell
A moderator who spoke 14,200 words in one session against a participant's 8,900 across ten. In oral history the interviewer speaks least — the asymmetry the heuristic now scores is sitting in the Words column, legible.
The cost
47 quotes against the interviewer's name, and none against the interviewees'. Quote extraction skips segments tagged researcher, so it kept every question and discarded every answer. The study's actual content is not in the report.

Both tells are arithmetic across sessions, so neither is visible on the Sessions lens, where each session is a row and Zach is simply "p1" ten times. This is the second argument for the lens after bench 2, and it is the same argument: some defects are only visible when the person is the row.

The Role cell is a popup button — the native control for a closed set of three. It is borderless at cell density (text plus a muted chevron), which is what macOS does in a table; the bordered .toolbar-btn form would put thirty boxes on the screen.

after changing both roles proposed

Roles changed for 11 people. Quotes were pulled out using the old roles. Analyse again…

Name
Role
Sessions
Words
Quotes
p1
Zach Kaplan
Moderator
all 10
8,900
47
m1
Marta Ellis Debian maintainer, 1994–2003
Participant
14,200
Commentary
honest, and deliberately unsatisfying

The roles are now right and the Quotes column is unchanged — 47 against the interviewer, none against the interviewee. That is the truth and the screen says it. A role is a label on a person; quotes were produced by a stage that read the old label and has already finished.

The alternative — silently re-running extraction when a role changes — is worse in three ways: it spends the researcher's money on a cloud call they did not ask for, it discards every edit made to the affected quotes, and it makes a dropdown into a destructive action. So the line offers the existing verb instead. Analyse again is already built, already counts what it will replace in its confirmation sheet, and is already the researcher's decision. The lens surfaces the need; it does not take the decision.

Wording, deliberately: "Quotes were pulled out using the old roles", not "quote extraction used stale role assignments". Same fact, no machinery.

5 · The observer, who is on the recording and not on the research team

Round 2, sessions 3 and 4. The client's product manager sat in. He is a speaker, so he has a code, a name and a row — and a set of privileges nobody chose for him.

People · project scope proposed
Name
Role
Sessions
Words
Quotes
m1
Rachel Okonjo Senior UX researcher
Moderator
1–8
12,100
o1
Tom Blake Product manager, Meridian Health
Observer
310
Commentary
correct on screen, wrong in the export

The row is right: Tom spoke 310 words across two sessions and contributed no quotes. What the row does not say is that the anonymise switch keeps his name. Anonymising an export blanks participant names and preserves both moderators and observers, on the reasoning that the research team is not the study's subject. That reasoning holds for Rachel. It does not hold for a client-side stakeholder who wandered into a session, whose name and employer then travel in a document the researcher hands to other people at the same client.

The checkbox hint the researcher actually reads says only "Moderator names are preserved" — which is not false, and is also not the whole list. Observers are a second category wearing the first one's rationale.

Note also that "Observer" is the role and Product manager, Meridian Health is the job title, and they sit two columns apart because they are different things. Four senses of "role" already coexist in the codebase — the stored enum, a translated display label nothing reads, the UI word "Moderator", and this job-title field — and the glossary adjudicates none of them. A lens named after this vocabulary has to settle it before it ships, not after.

Part 3 — above the project Where the speaker code stops meaning anything and identity has to be asserted.

6 · One folder up, and everyone is there twice

Client scope, NHS Trust. Nothing is linked, so a person who appears in two projects is two rows — because the importer creates a fresh person row for every speaker in every session, and no step has ever joined them.

People · client scope · nothing linked yet proposed

People

4 people may appear twice. Go through them

Name
Role
Project
Sessions
Words
Quotes
Rachel OkonjoSenior UX researcher
Moderator
8
12,400
Rachel OkonjoSenior UX researcher
Moderator
8
12,100
Same name in both projects, and both were read from the meeting files.
Sarah ChenWard sister, acute medicine
Participant
1
4,120
9
Sarah ChenWard sister, acute medicine
Participant
1
3,980
7
Same name in both projects, and both were read from the meeting files.
Priya RamanResearch contractor
Moderator
4
6,800
Commentary
the whole point of the scope, and its whole cost
Gone
The code column. p1 in round 1 and p4 in round 2 are the same nurse; showing both codes shows the machinery. This is why the People grid's degradation ladder drops the code first — at this altitude it has already stopped identifying anyone.
Arrived
The Project column, and a suggestion that sits under the pair it is about rather than beside either row. It is about the relationship, so it belongs to neither.

Two answers, both recorded. "Different people" is not a dismissal — it writes a negative link, so the pair is never proposed again. Without it, every re-run re-offers the same wrong match and the researcher learns to ignore the whole affordance. Same shape as "Keep as one person" in bench 2, one altitude up.

Both suggestions here rest on exact name equality plus platform provenance — the sentence says so in the researcher's words rather than showing a score. The design doc allows near-matches (Levenshtein ≤ 2) as well; a fuzzy match should not wear the same sentence as an exact one, because the researcher's answer depends entirely on which it is.

after "Same person" on both proposed
Name
Role
Projects
Sessions
Words
Quotes
Rachel OkonjoSenior UX researcher
Moderator
Ward handover app — round 1, round 2
16
24,500
Sarah ChenWard sister, acute medicine
Participant
Ward handover app — round 1, round 2
2
8,100
16
Priya RamanResearch contractor
Moderator
4
6,800
Commentary

Sarah Chen: 2 sessions, 16 quotes, across two rounds. That row is the reason a researcher would ever visit this scope voluntarily — it is a longitudinal finding, and until the link exists there is no object in the system it could hang on. Everything else in this lens is correction work; this one row is the payoff.

Two things the merged row must not do. It must not delete anything — a link changes how rows are presented, and un-linking has to put both back exactly as they were. And it must not leak: an export from round 2 carries round 2 only, link or no link, so the leave-behind Rachel hands the client never gains a second study's sessions because of a bookkeeping decision she made in a different window.

The job title shown is round 2's, because that project has more of her. Auto-choosing the fuller record is right; it also silently picks a winner between "Ward sister, acute medicine" and a shorter title from round 1, so the choice has to be visible and reversible in one click.

7 · A suggestion built on two guesses

Two participants the model named "Danny" from a first name it heard once each. Same folder, so a match is proposed. Neither name was ever a record.

People · client scope proposed
Name
Role
Project
Sessions
Words
Quotes
Danny
Participant
1
2,900
4
Danny
Participant
1
3,100
6
Same name in both projects — but both names are suggestions, each from one spoken first name. Open the sessions before answering.
Commentary
the failure mode the whole feature has to survive

A link suggestion is a claim about two names. If the app guessed both names, the suggestion is a guess about a guess, and it is offered in a control whose two buttons look exactly like the well-founded case in bench 6. Confidence does not compose, and a design that draws the same row for "two platform records agree" and "the model heard a first name twice" is inviting a wrong merge that then travels — it will pool quotes, and pooled quotes reshape agreement counts in the analysis.

Three consequences drawn here. The sentence names the weakness in plain words rather than showing a percentage. Neither button is the default — the primary fill is removed, so returning is as easy as deciding. And the sentence sends the researcher to the evidence ("open the sessions"), because for this class of match the transcript is the only thing that can settle it.

The sharper option is to not suggest at all when either side is a guess, and let the pair sit unmerged. Suggestions are cheap to add and expensive to trust; a lens that only proposes matches it can stand behind is the one whose proposals get read.

8 · Everyone, which is a roster and not a list

Fifty-eight person rows exist. Fifty-two of them are someone who took part in one session of one study and will never be looked at again. Showing all fifty-eight is showing the database.

People · everyone proposed

People

People you have worked with more than once. Show everyone (58)

Name
Role
Client
Projects
Last worked
Rachel OkonjoSenior UX researcher
Moderator
NHS Trust
2
Jan 2026
Sarah ChenWard sister, acute medicine
Participant
NHS Trust
2
Jan 2026
Priya RamanResearch contractor
Moderator
NHS Trust
1
Jan 2026
Priya RamanResearch contractor
Moderator
Kestrel Bank
1
Mar 2026
Sarah ChenOperations analyst
Participant
Kestrel Bank
1
Mar 2026
Zach Kaplan
Moderator
1
Nov 2025

Discharge letters — diary study is on Samsung T7, which is not plugged in. Nobody from it is counted here.

Commentary
two names appear twice, and the app proposes nothing — correctly
Both Priyas
Are the same contractor. The researcher hired her twice, for two clients.
Both Sarah Chens
Are two different people who have never met.
What the app offers
Nothing, for either. It cannot tell them apart and it must not try.

Matching is folder-scoped by design, and this is the row where that rule earns its keep. Across clients, name equality carries almost no evidence — the two Sarah Chens would be proposed as one person by any algorithm that looked, and a wrong merge here pools quotes from two organisations into one person's record. The rule also gives a clean answer for projects in no folder at all: the oral history study sits at the root, so it receives and offers nothing. Rachel and Priya are one folder each; the folder is not decoration, it is the consent boundary for matching.

The default view is the roster, not the table. The question at this altitude is "who do I work with", and its answer is the six people who recur — moderators, contractors, and the occasional longitudinal participant. The other fifty-two are one link away and behind a plain count, because a lens that opens on fifty-eight rows of noise is a lens that gets opened once.

The last line is the one nobody would think to write. Half a freelancer's projects are on drives and shares that come and go, so a total at this scope is always a total of what is currently readable. Saying which drive and naming it is the difference between a count the researcher can trust and a count they cannot audit. Same principle as the greyed-out project cards on the home screen: unavailable is normal, not an error — but it has to be said out loud wherever a number depends on it.

9 · Asserting a link the app refused to suggest, and the cascade it starts

The researcher selects both Priya rows and says they are the same person. Round 1 and round 2 are already tied together, so this link is not the only thing that changes.

Same person — sheet proposed

Link Priya Raman across two clients?

Bristlenose never suggests a match across clients, because two people can share a name. You are telling it these are one person.

Ward handover — round 1NHS Trust — same — Ward handover — round 2NHS Trust — new — Mobile onboardingKestrel Bank

Round 1 is already linked to round 2, so it joins as well — three projects, two clients.

Nothing moves between the projects. An export always carries one project, so a report you send Kestrel Bank cannot gain anything from the NHS work. What changes is that a name or job title you fix in one shows in the other.

Commentary
the cascade is the whole risk, so it is the whole sheet

The chain is drawn, not described. Linking A to B when B is already linked to C links A to C, and a researcher who is told that in a sentence will not picture it. Three nodes and two relations fit on one line and make the consequence a thing you look at rather than parse. Un-linking needs the same picture, showing what breaks.

The cross-client crossing is drawn twice — once as the dashed node, once in the sentence — because it is the only part that is irreversible in the social sense. Bristlenose can un-link at any time; the researcher who realises they have wired two clients' records together cannot un-see it.

The third paragraph exists because the researcher's actual fear is not modelled by the data model: "will Kestrel see the NHS material?" The answer is no, structurally — export is project-scoped whatever the links say — and the sheet says so before asking, rather than leaving it to be discovered. Naming the real limit (a shared name and title) buys the credibility for the reassurance.

Cancel is not the default and is not destructive-styled; the trailing button is the default. Nothing here is destructive — which is exactly why the sheet must not borrow destructive styling to signal seriousness.

Part 4 — what the lens must refuse to do The obligations that come with putting people in rows.

10 · The lens does not travel, and the export it exposes already does

Round 2, anonymise ticked, sent to the client. The shipped checkbox and its shipped hint, beside what actually leaves the machine.

Export report shipped

Export report

Creates a standalone report that anyone can open in a browser. Recipients can view and search but cannot edit.

what is in the file shipped
Name
Role
Job title in the file
 
 
blank p1
Participant
Ward sister, acute medicine
Rachel Okonjo m1
Moderator
Senior UX researcher
Tom Blake o1
Observer
Product manager, Meridian Health
Commentary
the right-hand frame is not a proposal — it is the file today
  • The job title is not stripped. Anonymising blanks the name fields and leaves role, which the model extracted from the same speaker pass. It renders nowhere in the app, so it is invisible in the UI and present in View Source — and job-title-plus-employer is the product's own documented example of indirect identification. Stripping it was decided in the export design doc and never implemented; this lens is the first surface that would show a researcher the field exists.
  • Tom Blake ships, under a rationale written for moderators. See bench 5.
  • Rachel's name ships attached to twelve sessions she did not all run. The bench 2 collision travels into the leave-behind intact, and the recipient has no way to detect it. That is what raises the collision from a tidiness problem to a correctness one: it is the only defect here that leaves the building.

And the lens itself does not ship in the export. Not because export mode is read-only — that is a mechanism — but because everything in it is a correction affordance for someone who can correct, and one part of it is actively unsafe to send: telling a recipient that p7's name was heard in a session tells them a real name exists, that it is in the transcript body they already have, and that the pipeline located it. That converts a latent leak into a targeted one, precisely for the participants whose names were deliberately removed. Every other lens ships; this one is the exception, and the exception needs the one-line reason written next to the code that enforces it.

What the benches force Commentary throughout. None of this is product.
Commentary — the load-bearing conclusions
1 · Three questions
The scope control changes what a row is, not which rows are shown. Project scope verifies, client scope links, everyone scope is a roster. The app proposes names and roles at the first, matches at the second, and nothing at the third.
2 · The anchor inverts
The speaker code identifies a person inside a project and identifies nobody above one. The People grid sheds the code column first; the sessions grid sheds the name first and keeps the badge. Same product, one altitude apart, opposite priority.
3 · Prerequisite
Benches 2 and 4 are the reason to build the lens, and bench 2 does not work until people.yaml and the pipeline's speaker-info dict are rekeyed by (session, code). That reshape has a home already — the speaker-editing roadmap, §11c, with its eight-reader list. The lens should extend it, not restate it.
4 · Two answers, always
Every question the lens asks needs a recorded negative: "Keep as one person", "Different people". A prompt that can only be satisfied or postponed comes back every run and gets ignored, taking the true positives with it.
5 · Confidence does not compose
A match between two guessed names is a guess about a guess and must not wear the same row as a match between two platform records. The strongest option is to withhold the suggestion entirely.
6 · Zero-geometry states
A guessed name is italic; an unnamed row is empty; counts live in one absent-when-zero line under the heading. No chips, no dots, no per-row marks — thirty rows of qualifiers is the failure mode, and one line is one translated string instead of five.
7 · Say what it cannot do
Changing a role does not re-extract quotes; a total at everyone scope excludes unplugged drives; a link never moves data between projects. Each is a sentence on the surface, not a note in a design doc.
8 · The lens does not travel
It is the one lens absent from the exported report, and the three leaks it exposes — job title, observers, the mis-attributed moderator — are in the file today.

Not settled here, deliberately. Whether the placeholder for an unnamed person is the role word or nothing (bench 3). Whether "Everyone" belongs in a report lens at all or in the app's own window, given that every other tab means "in this project". Whether the job title gets the same italic-when-guessed treatment as the name, since it is filled by the same model pass and is just as inventable. And what a person-shaped API owes a participant who withdraws consent after analysis — the erasure verb does not exist, and this is the design where it would be cheap to allow for.