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.
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.
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:
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.
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.
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**.
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:33suppressHydrationWarning). 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.
**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.
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
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.
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.
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.
**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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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:
drb-c2-core/app/internal/intelligence.py.Today any self-serve signup (
/login->/signup-> realcreateUserWithEmailAndPassword) 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):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.
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:
intelligence.pykeeps 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.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.
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/appandServer/drb-frontendreturning zero real hits (one false positive,layout.tsx:33suppressHydrationWarning). 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/usershas noorg_idfilter, 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-opspersona (#78), which is barred from touching live or named product data at all.Owner: CTO. Refs #79, #77, #69, #78, #66, #4, #62.
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.titleis template-composed rather than LLM-freeform and is already name-safe by construction.EMS exclusion needs a data-model change.
ai_flagsis 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.pywrites a raw 200-charactertranscript_snippetintoalert_eventsand 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
Recommendations are stated so the owner is confirming rather than deciding from scratch.
Refs #42, #62, #66, #48, #45.