Gate B3: EMS/medical talkgroup exclusion default and person-name redaction are not implemented #43

Open
opened 2026-08-23 17:33:09 -04:00 by logan · 3 comments
Owner

Board minutes #42 (2026-08-23) - Ratify BUSINESS_MODEL.md. - Gate B condition B3. Blocks charging any customer.

BUSINESS_MODEL.md §5.7 calls mitigation #1 (EMS/medical talkgroup exclusion) "the highest-leverage single mitigation in this entire document" and marks both #1 and #2 (person-name redaction) as cheap. Neither exists.

Verified by the CISO (#39) and re-checked by the chair:

  • No EMS-exclusion flag in drb-c2-core/app/internal/intelligence.py.
  • No redaction logic anywhere in the frontend outside marketing copy.

Today any self-serve signup (/login -> /signup -> real createUserWithEmailAndPassword) reaches AI-generated assertions naming private individuals, including EMS/medical calls, with no mitigation.

Ruled defaults (minutes #42, Decision 9, adopting BUSINESS_MODEL.md §9 Q2/Q3):

  • EMS/medical talkgroups excluded from the AI pipeline by default; opt-in per customer, under contract only.
  • Person names not published in incident titles or AI summaries. Raw transcript beside the audio on paid tiers only.

Entities are already extracted, so the redaction has a data source to work from.

Owner: CTO. Date: 2026-09-30.
Related: §8 item 7; minutes #42 Gate B, Decision 6, Decision 9.

Board minutes #42 (2026-08-23) - Ratify BUSINESS_MODEL.md. - **Gate B condition B3. Blocks charging any customer.** `BUSINESS_MODEL.md` §5.7 calls mitigation #1 (EMS/medical talkgroup exclusion) "the highest-leverage single mitigation in this entire document" and marks both #1 and #2 (person-name redaction) as cheap. Neither exists. Verified by the CISO (#39) and re-checked by the chair: - No EMS-exclusion flag in `drb-c2-core/app/internal/intelligence.py`. - No redaction logic anywhere in the frontend outside marketing copy. Today any self-serve signup (`/login` -> `/signup` -> real `createUserWithEmailAndPassword`) reaches AI-generated assertions naming private individuals, including EMS/medical calls, with no mitigation. **Ruled defaults (minutes #42, Decision 9, adopting `BUSINESS_MODEL.md` §9 Q2/Q3):** - EMS/medical talkgroups excluded from the AI pipeline **by default**; opt-in per customer, under contract only. - Person names **not published** in incident titles or AI summaries. Raw transcript beside the audio on paid tiers only. Entities are already extracted, so the redaction has a data source to work from. Owner: CTO. Date: **2026-09-30**. Related: §8 item 7; minutes #42 Gate B, Decision 6, Decision 9.
Author
Owner

Scope WIDENED by owner ruling 3 (board minutes #42, "Owner rulings, 2026-08-23" comment).

Owner, verbatim: "assume it will happen but get to product mvp, feedback, then go for company things" - i.e. no E&O spend before revenue. Gate B7's pre-agreed consequence therefore binds now, and it makes this issue bigger, not smaller:

  1. Person names are suppressed by DEFAULT on every surface - public, comped AND paid - until a media liability / E&O policy is actually bound. The original scope here was section 9 Q3's "redact in titles and summaries; raw transcript on paid tiers only". The paid-tier carve-out is withdrawn. Uninsured, we do not publish names anywhere.
  2. Binding implementation constraint: suppression is a display and policy layer, NEVER deletion. intelligence.py keeps extracting person entities and Firestore keeps storing them. The suppression belongs in the render / export / API paths, behind a single switch. Do not design a schema in which names are impossible to reinstate - this decision is explicitly meant to be reversed the day a policy is bound, and a deletion-based implementation would make a reversible ruling irreversible.
  3. EMS/medical exclusion is unchanged - default ON, opt-in per customer under contract only.

Corollary for #48: the 200-call entity-name accuracy measurement can no longer decide whether names are published, because they are suppressed regardless. It remains a Gate B condition for other reasons.

Still Gate B condition B3. Owner: CTO. Date unchanged: 2026-09-30.

**Scope WIDENED by owner ruling 3 (board minutes #42, "Owner rulings, 2026-08-23" comment).** **Owner, verbatim:** *"assume it will happen but get to product mvp, feedback, then go for company things"* - i.e. **no E&O spend before revenue**. Gate B7's pre-agreed consequence therefore binds now, and it makes this issue bigger, not smaller: 1. **Person names are suppressed by DEFAULT on every surface - public, comped AND paid** - until a media liability / E&O policy is actually bound. The original scope here was section 9 Q3's "redact in titles and summaries; raw transcript on paid tiers only". **The paid-tier carve-out is withdrawn.** Uninsured, we do not publish names anywhere. 2. **Binding implementation constraint: suppression is a display and policy layer, NEVER deletion.** `intelligence.py` keeps extracting person entities and Firestore keeps storing them. The suppression belongs in the render / export / API paths, behind a single switch. Do not design a schema in which names are impossible to reinstate - this decision is explicitly meant to be reversed the day a policy is bound, and a deletion-based implementation would make a reversible ruling irreversible. 3. **EMS/medical exclusion is unchanged** - default ON, opt-in per customer under contract only. Corollary for #48: the 200-call entity-name accuracy measurement can no longer *decide* whether names are published, because they are suppressed regardless. It remains a Gate B condition for other reasons. Still Gate B condition B3. Owner: CTO. Date unchanged: **2026-09-30**.
Author
Owner

Board minutes #79, decision 9, 2026-08-25 — a new stated precondition on this issue.

Confirmed at HEAD by the CISO this sitting (#77): name redaction and EMS exclusion are fully unimplemented, a case-insensitive grep across Server/drb-c2-core/app and Server/drb-frontend returning zero real hits (one false positive, layout.tsx:33 suppressHydrationWarning). Any authenticated account reads real person names attached to real EMS/medical dispatch traffic.

Ruled: no human, contractor, agency, prospect or trial account gets a product login until this issue ships. Precondition, not a preference. It is the reason the board could not have answered #69 with an outside hire even if the money had worked — there is no safe login to hand anyone. Compounded by #4, where /admin/users has no org_id filter, so an "admin scoped to their own org" is not scoped either.

Date unchanged: 2026-09-30. The board explicitly accepted the consequence rather than pulling engineering forward on a probability with no evidence behind it: this date lands eight days after the 2026-09-22 kill date, so a surviving beachhead cannot be converted into a trial account until this ships. The date does not move on speculation; it moves the moment a real prospect asks for a trial.

Does not block the 12 discovery conversations (no login involved) or the growth-ops persona (#78), which is barred from touching live or named product data at all.

Owner: CTO. Refs #79, #77, #69, #78, #66, #4, #62.

**Board minutes #79, decision 9, 2026-08-25 — a new stated precondition on this issue.** Confirmed at HEAD by the CISO this sitting (#77): name redaction and EMS exclusion are **fully unimplemented**, a case-insensitive grep across `Server/drb-c2-core/app` and `Server/drb-frontend` returning zero real hits (one false positive, `layout.tsx:33` `suppressHydrationWarning`). Any authenticated account reads real person names attached to real EMS/medical dispatch traffic. **Ruled: no human, contractor, agency, prospect or trial account gets a product login until this issue ships.** Precondition, not a preference. It is the reason the board could not have answered #69 with an outside hire even if the money had worked — there is no safe login to hand anyone. Compounded by #4, where `/admin/users` has no `org_id` filter, so an "admin scoped to their own org" is not scoped either. **Date unchanged: 2026-09-30.** The board explicitly accepted the consequence rather than pulling engineering forward on a probability with no evidence behind it: this date lands **eight days after** the 2026-09-22 kill date, so a surviving beachhead cannot be converted into a trial account until this ships. **The date does not move on speculation; it moves the moment a real prospect asks for a trial.** Does not block the 12 discovery conversations (no login involved) or the `growth-ops` persona (#78), which is barred from touching live or named product data at all. Owner: CTO. Refs #79, #77, #69, #78, #66, #4, #62.
Author
Owner

Gate B3 is now SCOPED. Unattended run 2026-08-28. Full document: Server/GATE-B3-SCOPE.md (committed alongside this comment). Ship date unchanged: 2026-09-30.

This closes the scoping precondition in board minutes #62 decision 6d — the owner is no longer barred from showing live data to a prospect on the grounds that #43 is unscoped. That mattered enough to do this week rather than next: the count at #66 is 0 of 12 with a hard checkpoint on 2026-09-05.

A premise in this issue's body does not hold. The body says "entities are already extracted, so the redaction has a data source to work from." It is not true at HEAD — intelligence.py's extraction prompt has no person-name entity field at all. Redaction therefore has to be built against raw free text, not a clean field. That is the single largest cost driver in the estimate: roughly 4-6 of the 6-10 engineering-days. The rest of the issue's ruled defaults are unaffected.

Design decision, defended in the document: redaction happens at write time, storing a redacted copy beside the raw one. The frontend reads Firestore directly for calls and incidents, and Firestore rules cannot mask individual fields — so redaction at the API layer alone would leave the raw document readable in the browser, which is not a mitigation. incident.title is template-composed rather than LLM-freeform and is already name-safe by construction.

EMS exclusion needs a data-model change. ai_flags is per-system only, and real systems mix EMS with police and fire on one system, so a system-level flag cannot express the ruled default. A per-talkgroup flag is required.

One live surface found leaking today, worth separating from the 2026-09-30 work: alerter.py writes a raw 200-character transcript_snippet into alert_events and POSTs it to the customer's own Discord webhook. Unredacted, today, on the sellable alerting path.

#48 does not block this — confirmed against #48's own thread, not assumed.

Needs an owner ruling — the first one is urgent and is not a 2026-09-30 question

  1. Is comped (friends-and-family) access to unredacted person names paused today, or knowingly left in breach until 2026-09-30? Minutes #42 suppressed names on every surface until E&O is bound, and comped is a surface. This needs an answer now, not at ship.
  2. How does a talkgroup get classified EMS/medical? Recommendation: name-pattern heuristic as the default classification, manual override, and default-exclude when nothing matches — the ruled default is exclusion, so an unclassifiable talkgroup must fail closed.
  3. Does exclusion and redaction apply retroactively to calls already processed? Recommendation: prospective only for 2026-09-30; backfill becomes a separate issue.

Recommendations are stated so the owner is confirming rather than deciding from scratch.

Refs #42, #62, #66, #48, #45.

**Gate B3 is now SCOPED.** Unattended run 2026-08-28. Full document: `Server/GATE-B3-SCOPE.md` (committed alongside this comment). Ship date unchanged: 2026-09-30. This closes the *scoping* precondition in board minutes #62 decision 6d — **the owner is no longer barred from showing live data to a prospect on the grounds that #43 is unscoped.** That mattered enough to do this week rather than next: the count at #66 is 0 of 12 with a hard checkpoint on 2026-09-05. **A premise in this issue's body does not hold.** The body says "entities are already extracted, so the redaction has a data source to work from." It is not true at HEAD — `intelligence.py`'s extraction prompt has **no person-name entity field at all**. Redaction therefore has to be built against raw free text, not a clean field. That is the single largest cost driver in the estimate: roughly 4-6 of the 6-10 engineering-days. The rest of the issue's ruled defaults are unaffected. **Design decision, defended in the document:** redaction happens at **write time**, storing a redacted copy beside the raw one. The frontend reads Firestore directly for calls and incidents, and Firestore rules cannot mask individual fields — so redaction at the API layer alone would leave the raw document readable in the browser, which is not a mitigation. `incident.title` is template-composed rather than LLM-freeform and is already name-safe by construction. **EMS exclusion needs a data-model change.** `ai_flags` is per-**system** only, and real systems mix EMS with police and fire on one system, so a system-level flag cannot express the ruled default. A per-talkgroup flag is required. **One live surface found leaking today**, worth separating from the 2026-09-30 work: `alerter.py` writes a raw 200-character `transcript_snippet` into `alert_events` and POSTs it to the customer's own Discord webhook. Unredacted, today, on the sellable alerting path. **#48 does not block this** — confirmed against #48's own thread, not assumed. ### Needs an owner ruling — the first one is urgent and is not a 2026-09-30 question 1. **Is comped (friends-and-family) access to unredacted person names paused today, or knowingly left in breach until 2026-09-30?** Minutes #42 suppressed names on *every* surface until E&O is bound, and comped is a surface. This needs an answer now, not at ship. 2. **How does a talkgroup get classified EMS/medical?** Recommendation: name-pattern heuristic as the default classification, manual override, and **default-exclude when nothing matches** — the ruled default is exclusion, so an unclassifiable talkgroup must fail closed. 3. **Does exclusion and redaction apply retroactively to calls already processed?** Recommendation: prospective only for 2026-09-30; backfill becomes a separate issue. Recommendations are stated so the owner is confirming rather than deciding from scratch. Refs #42, #62, #66, #48, #45.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logan/server-26#43