Skip to content

Add Jev sensitivity classifier to Brain's capture pipeline - #5632

Merged
sanyamkamat merged 9 commits into
mainfrom
ai_main_8f8d8ff852f84269a5fa
Sep 23, 2026
Merged

sanyamkamat merged 9 commits into
mainfrom
ai_main_8f8d8ff852f84269a5fa

Conversation

@sanyamkamat

@sanyamkamat sanyamkamat commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Jev as the default sensitivity classifier for the Brain template's capture pipeline, giving each capture a calibrated per-category probability score that decides whether it's allowed, quarantined, or blocked, while letting workspaces still choose an approved model or deterministic-only screening instead.

Problem

Brain captures needed a way to detect and strip sensitive information (e.g. employee performance, compensation, health data) before storage, similar to how Glean filters sensitive content. Previously, sensitivity classification relied only on deterministic regex screening or a manually configured approved model/engine pair, with no calibrated confidence signal and no integration with Jev.

Solution

Introduced a new jev-classifier module that sends deterministically pre-screened content to Jev, which scores each sensitivity category as a probability. Scores above a block threshold quarantine and name the category; scores in an uncertain middle band quarantine without naming a category (fail-closed); clearly low scores allow the capture. Jev only decides the verdict — safe content is always derived from the deterministic line screen or the configured sanitizer. The classification pipeline degrades gracefully: Jev → approved model → deterministic screening, with uncertain captures staying quarantined if a configured classifier fails.

Key Changes

  • New server/lib/jev-classifier.ts: resolves Jev credentials (workspace-stored key first, falling back to Builder gateway), requests per-category probability scores in a single batched call, caches results, and maps scores to a BrainSensitivityDecision with block/allow/uncertain thresholds.
  • Credential resolution ladder: resolveJevAuth prefers a stored JEV_API_KEY, then falls back to Builder gateway auth; probeJevCredential reports readiness state (stored-key, builder-gateway, none, unavailable) with short-lived caching for health/onboarding surfaces.
  • privacy-readiness.ts rewritten: now takes the resolved Jev credential status and the workspace's privacyClassifier preference (jev | model | deterministic) to compute readiness and produce targeted warnings (e.g. credential lookup failed vs. not configured vs. deterministic-only chosen deliberately).
  • New privacyClassifier setting: added to BrainSettings, set-settings action, and settings UI (Select control) to let workspaces pick Jev, a custom model, or deterministic-only screening. Defaults to jev.
  • Capture sanitization pipeline (capture-sanitization.ts): now runs classifyWithJev before falling back to the approved-model classifier, threading through failure reasons and auth source for observability.
  • Schema/db changes: added decisionScoresJson column to brain_sensitivity_events (migration v27) to persist per-category probability scores; list-proposals action now annotates quarantine reasons with the classifier's probability (e.g. "performance 92%").
  • search-index-contracts.ts: extracted BRAIN_SENSITIVITY_CATEGORIES as a shared const array, bumped BRAIN_SENSITIVITY_POLICY_VERSION to 2, and added "jev" as a classifier type plus categoryScores on the decision contract.
  • Settings/health UI: settings.tsx and brain-health.ts now surface classifier choice, Jev credential status, and readiness warnings; onboarding step description updated to reflect the new classifier options.
  • Localization: added new i18n strings (classifier choice, Jev credential labels, hours formatting) across all supported locales.
  • Tests: new jev-classifier.test.ts covering preference resolution, probability-to-disposition mapping, transport/credential ladder behavior, end-to-end classification, and graceful degradation; updated privacy-readiness.test.ts for the new readiness logic.
  • Changelog entry documenting the Jev-based screening and new settings option.

Edit in Builder  Preview


To clone this PR locally use the Github CLI with command gh pr checkout 5632

You can tag me at @BuilderIO for anything you want me to fix or change

@builder-io-integration builder-io-integration Bot changed the title Update from the Builder.io agent Add Jev sensitivity classifier to Brain's capture pipeline Sep 22, 2026
@sanyamkamat
sanyamkamat requested review from a team, shawnmcclelland and shomix and removed request for a team and shawnmcclelland September 22, 2026 16:19
builder-io-integration[bot]

This comment was marked as outdated.

@github-actions
github-actions Bot temporarily deployed to pr-5632-forms September 22, 2026 16:40 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-slides September 22, 2026 16:41 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-fw September 22, 2026 16:41 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-design September 22, 2026 16:42 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-content September 22, 2026 16:43 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-dispatch September 22, 2026 16:43 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-starter September 22, 2026 16:43 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-assets September 22, 2026 16:44 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-calendar September 22, 2026 16:45 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-analytics September 22, 2026 16:45 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-clips September 22, 2026 16:46 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-plan September 22, 2026 16:46 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-mail September 22, 2026 16:48 Destroyed
- Resolve the Jev credential with the capture source identity instead of the
  ambient request context, so an editor of a shared source cannot classify the
  owner's content with their own credential.
- Redact contact details, credentials, and links before the payload leaves the
  process for Typesafe.
- Fail closed when the capture was too long for Jev to see in full.
- Ask Jev the workspace's own sensitivityCustomInstructions as an extra
  question so workspace rules keep tightening under the Jev path.
- Reject out-of-range probabilities instead of clamping them into a confident
  "not sensitive".
- Treat a Jev credential-lookup failure as a classifier outage rather than an
  unconfigured workspace.
- Make the allow bar exclusive so a score of exactly 0.2 is uncertain.
@github-actions

github-actions Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Visual recap — not generated

The recap was suppressed because the diff matched a secret/credential pattern. No plan was published.

Reason: high-confidence secret in diff.

builder-io-integration[bot]

This comment was marked as outdated.

… contract

- Mount PrivacySensitivitySettings in the general tab. It was only attached as
  a `content` property on a SettingsSearchEntry, which has no such field, so
  the card (and the new classifier selector) never rendered. Deep-link by hash
  instead.
- Correct the BRAIN_SENSITIVITY_POLICY_VERSION comment: a bump stamps new
  decisions and separates quarantine rows, but does not retroactively
  re-screen, because indexSnapshotMatches compares a capture against its own
  artifact rather than the current constant. Document resanitize-captures as
  the migration path in the brain skill.
builder-io-integration[bot]

This comment was marked as outdated.

…tion

- resolveBuilderGatewayAuth() reads the ambient request user/org, so wrap it in
  runWithRequestContext bound to the same identity used for the stored-key
  lookup. Otherwise a shared-source editor or a queue worker spends their own
  Builder OAuth grant on the capture owner's content.
- Redact unlabelled provider credentials (Slack xox*, AWS access key ids,
  Google API keys, JWTs) and run all credential patterns before the phone
  number rule. The phone rule was matching the digit runs inside a Slack token
  and leaving the token tail in the output.
- Pass the request organization to probeJevCredential so org-scoped
  JEV_API_KEY values are not reported as missing in health and onboarding.
builder-io-integration[bot]

This comment was marked as outdated.

sensitivityCustomInstructions is admin-authored free text on the same egress
path as the capture, but was the only part of the payload not passing through
sanitizeSensitiveText.
builder-io-integration[bot]

This comment was marked as outdated.

- Add Slack, AWS, Google, SendGrid, and JWT formats to the secret-credential
  hard-category screen, not just to the egress redactor. Redaction alone let a
  credential-bearing capture be stored as 'allowed', while the existing policy
  for a labelled secret is to suppress the whole capture.
- Run the entire Jev credential ladder under the capture owner's identity, so
  workspace-connection discovery is scoped the same way the vault lookup is.
- Preserve source orgId through resanitize-captures so an org-scoped
  JEV_API_KEY is still discoverable when re-screening.
builder-io-integration[bot]

This comment was marked as outdated.

The same provider formats were duplicated between the secret-credential
hard-category screen and sanitizeSensitiveText, so each new format had to be
added twice and could silently drift. They now come from one
UNLABELLED_CREDENTIAL_SOURCES list, and Google OAuth client secrets are
included.
builder-io-integration[bot]

This comment was marked as outdated.

… action

- PEM private key headers and Authorization Bearer/Basic values are
  credential-bearing but carry no 'private key:' style label, so add them to
  the shared unlabelled-credential list.
- The quarantine retention input clamped to 8760 hours while set-settings
  rejects anything over 720, so a user could enter a value that failed to
  save. This was unreachable until the privacy card started rendering.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 2 potential issues 🔴

Review Details

Incremental Code Review Summary

The latest commit fixes both previously open issues: the egress redactor now covers PEM/bearer secrets, and the retention-hours UI range is consistent with the action limit. I verified and resolved those stale review threads. Focused Brain classifier, sanitization, readiness, and resanitization tests passed according to the reviewers.

This remains high risk because workspace instructions and classifier output cross the external Jev boundary. Two new high-severity redaction gaps remain: the unlabelled credential regex is case-sensitive, and the sanitizer does not cover all credential labels recognized by the hard-category detector. Both can expose secrets embedded in workspace rules or classifier-produced text sent through the Jev path.

🧪 Browser testing: Will run after this review (PR includes Brain settings UI), subject to Chrome automation availability.

Comment thread templates/brain/server/lib/sensitivity-policy.ts
Comment thread templates/brain/server/lib/sensitivity-policy.ts Outdated
The detector was case-insensitive and recognised access-token/private-key/
api-key, while the redactor was case-sensitive on the unlabelled formats and
only knew password/passcode/secret/token/api key. Either direction of that
drift is a leak: a label in only the detector suppresses without redacting,
and one in only the redactor stores a credential-bearing capture as allowed.
Both now compile from one CREDENTIAL_LABELS alternation, case-insensitive.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes — no new findings

Review Details

Incremental Review Completion

This review cycle is now finalized. The latest code-review results contained no additional findings beyond the credential-redaction issues already posted in the preceding review; those existing comments were not duplicated. The previously checked Brain settings and classifier changes remain high-risk because they process sensitive capture content and credentials across an external Jev boundary.

Focused tests reported passing classifier, sanitization, readiness, and resanitization coverage. Browser verification remains unavailable because Chrome automation tools are not exposed in the environment; route/source-level checks were previously healthy.

🧪 Browser testing: Skipped for this completion pass — prior browser attempts were blocked environment-wide by unavailable Chrome automation tooling.

@github-actions
github-actions Bot temporarily deployed to pr-5632-analytics September 22, 2026 19:36 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-plan September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-assets September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-content September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-mail September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-dispatch September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-forms September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-clips September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-calendar September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-design September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-fw September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-starter September 22, 2026 19:37 Destroyed
@github-actions
github-actions Bot temporarily deployed to pr-5632-slides September 22, 2026 19:37 Destroyed
@sanyamkamat
sanyamkamat merged commit 73f68ba into main Sep 23, 2026
88 checks passed
@sanyamkamat
sanyamkamat deleted the ai_main_8f8d8ff852f84269a5fa branch September 23, 2026 03:13

This branch was successfully deployed

No deployments
pr-5632-slides 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-starter 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-fw 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-design 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-calendar 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-clips 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-forms 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-dispatch 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-mail 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-content 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-assets 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-plan 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
pr-5632-analytics 38af3214 Deployed Sep 22, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants