Skip to content

feat(logs): redact PII from workflow logs via configurable rules - #5136

Merged
TheodoreSpeaks merged 13 commits into
stagingfrom
feat/redact-pii-workflow-log
Jun 19, 2026
Merged

feat(logs): redact PII from workflow logs via configurable rules#5136
TheodoreSpeaks merged 13 commits into
stagingfrom
feat/redact-pii-workflow-log

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Adds enterprise PII redaction for workflow execution logs, configured under Data Retention as org-scoped rules — each rule selects which PII entity types to mask and which workspaces it applies to (empty workspaces = all; empty entity types = redact nothing).
  • Reuses the guardrails Microsoft Presidio engine in mask mode, applied at the single log-persist choke point (completeWorkflowExecution), covering both the inline and externalized write paths.
  • Redaction is byte-budgeted/chunked (one batched subprocess per persist, not per block), structure-preserving (masks string leaves, rebuilds via structuredClone), and fail-safe (scrubs rather than leaks on error).
  • Adds a check-digit-validated VIN recognizer so it won't false-match arbitrary 17-char codes.
  • Adds per-workspace data-retention-hours overrides (resolved workspace ?? org ?? plan default) via a new nullable workspace.data_retention_settings column.
  • UI mirrors Access Control: a rules list + ChipModal (grouped checkbox grid for entity types, workspace multiselect), persisting on save with an unsaved-changes guard.

Type of Change

  • New feature

Testing

  • Unit tests for the redaction transform (recursion, batched substitution, structure preservation, fail-safe scrub, oversized-string skip) — passing.
  • Verified Presidio masking end-to-end locally (email/phone/credit-card/VIN), incl. VIN check-digit precision (valid VINs masked, random 17-char tokens left alone).
  • bun run lint, bun run check:api-validation:strict, and bun run check:migrations origin/staging all pass. Migration is a single additive nullable column (expand-phase, backward-compatible).

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Enterprise PII redaction for workflow execution logs, configured under
Data Retention as org-scoped rules (each rule picks entity types + which
workspaces it applies to). Reuses the guardrails Presidio engine in mask
mode at the log-persist choke point, with a check-digit-validated VIN
recognizer. Also adds per-workspace data-retention-hours overrides.
@vercel

vercelBot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
docsSkippedSkippedJun 19, 2026 9:05pm

Request Review

@cursor

cursorBot commented Jun 19, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes sit on the workflow log persist path and handle sensitive data; incorrect masking or fail-open behavior could leak PII, while fail-safe scrubbing could hide debug content on Presidio outages.

Overview
Enterprise PII redaction is wired end-to-end: org dataRetentionSettings now includes piiRedaction rules (default for all workspaces plus optional per-workspace overrides), validated via new Zod schemas and persisted through the data-retention API.

The Data Retention settings page gains a PII Redaction section—modals with a searchable Presidio entity picker, immediate saves for rules, and unsaved-changes handling—while retention-hour saves stay separate. Form hydration is keyed to the active org so switches do not cross-save.

At log completion, completeWorkflowExecution resolves the effective rule for the workspace and runs structure-preserving masking over trace spans, outputs, inputs, errors, and related fields before inline or externalized storage. Masking batches string leaves through Presidio (byte-chunked subprocesses, shared VIN recognizer, stdin error handling); failures or oversized payloads replace text with [REDACTION_FAILED] instead of persisting raw PII. Policy resolution intentionally fail-safe (masks when rules exist rather than skipping on flaky enterprise checks).

Supporting pieces: shared client-safe PII entity catalog, resolveEffectivePiiRedaction, and unit tests for resolution and redaction behavior.

Reviewed by Cursor Bugbot for commit ad7d1fa. Bugbot is set up for automated code reviews on this repo. Configure here.

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

Comment threadapps/sim/lib/logs/execution/logger.ts
Comment threadapps/sim/lib/logs/execution/pii-redaction.ts
…rkflow-log
# Conflicts:
#	packages/db/migrations/meta/0241_snapshot.json
#	packages/db/migrations/meta/_journal.json
#	scripts/check-api-validation-contracts.ts
Comment threadapps/sim/lib/billing/retention.ts Outdated
Comment threadapps/sim/lib/logs/execution/logger.ts Outdated
@greptile-apps

greptile-appsBot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds enterprise-grade PII redaction for workflow execution logs, applied at the single completeWorkflowExecution choke point in logger.ts. Redaction is driven by org-scoped rules stored in organization.dataRetentionSettings, resolved per-workspace using a most-specific-wins policy, and executed via a batched Microsoft Presidio subprocess with a fail-safe scrub path that replaces all strings on error rather than persisting potentially sensitive data.

  • Redaction engine (pii-redaction.ts): Two-pass collect-then-substitute walk over traceSpans, finalOutput, workflowInput, and related fields; single batched (byte-chunked) Presidio call per log persist; scrubs all strings with [REDACTION_FAILED] on timeout, Presidio error, or when the 16 MB budget is exceeded.
  • VIN recognizer (validate_pii.py): Custom PatternRecognizer with ISO 3779 check-digit validation, making it precise enough to skip arbitrary 17-char codes (request IDs, SKUs).
  • Settings UI (data-retention-settings.tsx): Rules list with a ChipModal grouped-checkbox picker for entity types and a workspace multi-select; each save persists immediately via the data-retention route; unsaved-changes guard on modal close.

Confidence Score: 4/5

Safe to merge after addressing the orphaned-override visibility bug in the settings UI.

The redaction engine, Presidio integration, VIN recognizer, and API contract changes are all solid. The one concrete defect is in the settings UI: deleting the default (all-workspaces) rule while per-workspace override rules exist removes those overrides from view entirely — they stay active in the database and keep redacting PII, but an admin has no way to see, edit, or delete them without first re-adding a default rule. This creates a control-plane blind spot for enterprise privacy configuration that should be fixed before shipping.

apps/sim/ee/data-retention/components/data-retention-settings.tsx — the Workspace overrides section gating logic needs attention.

Important Files Changed

FilenameOverview
apps/sim/lib/logs/execution/pii-redaction.tsNew module for structure-preserving PII redaction across execution payloads. Two-pass approach (collect → batch mask → substitute) is correct and deterministic. Fail-safe scrub path works as intended. Tests cover key scenarios including fail-safe and large-string masking.
apps/sim/lib/logs/execution/logger.tsAdds applyPiiRedaction to the completion hot path. DB query for org settings on every execution is acknowledged in the code; error handling for the DB lookup (noted in prior threads) remains absent.
apps/sim/lib/billing/retention.tsCorrect most-specific-wins resolution. Empty entityTypes on a workspace-specific rule correctly maps to enabled: false (exemption), matching the schema.ts JSDoc updated in this PR. Well-tested.
apps/sim/lib/guardrails/validate_pii.tsAdds maskPIIBatch (byte-chunked sequential subprocess calls) and the shared runPythonScript helper. EPIPE guard on python.stdin correctly funnels the error into the promise. Chunking logic handles oversized individual texts correctly.
apps/sim/lib/guardrails/validate_pii.pyAdds mask_batch (reuses one engine pair per subprocess), VinRecognizer with ISO 3779 check-digit validation, and build_analyzer. VIN transliteration table and weight vector match the standard algorithm. Error propagation through main()'s outer try/except is intact.
apps/sim/ee/data-retention/components/data-retention-settings.tsxAdds PII rules UI (default rule + workspace overrides). Contains a P1 bug: the Workspace overrides section is gated on defaultRule being non-null, so deleting the default rule orphans existing override rules (invisible in UI but still active in DB).
packages/db/schema.tsAdds PiiRedactionRule and DataRetentionSettings interfaces; updates dataRetentionSettings column type to reference them. Additive/backward-compatible change with no migration breakage.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant E as ExecutionLogger
participant DB as Database
participant R as redactPIIFromExecution
participant P as maskPIIBatch (validate_pii.ts)
participant PY as validate_pii.py (Presidio)
E->>DB: SELECT orgSettings FROM workspace LEFT JOIN organization
DB-->>E: orgSettings (DataRetentionSettings)
E->>E: resolveEffectivePiiRedaction(orgSettings, workspaceId)
alt "enabled = false"
E-->>E: return payload unchanged
else "enabled = true"
E->>R: redactPIIFromExecution(payload, entityTypes)
R->>R: collect all eligible strings (two-pass walk)
alt "totalBytes > 16 MB"
R-->>R: scrub all strings with REDACTION_FAILED
else within budget
R->>P: maskPIIBatch(texts, entityTypes) chunked 256 KB each
loop for each chunk
P->>PY: spawn subprocess, write JSON to stdin
PY-->>P: __SIM_RESULT__ passed results
end
P-->>R: masked string array
end
R->>R: substitute masked strings back into payload structure
R-->>E: redacted RedactablePayload
end
E->>DB: INSERT/UPDATE workflowExecutionLogs (redacted data)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant E as ExecutionLogger
participant DB as Database
participant R as redactPIIFromExecution
participant P as maskPIIBatch (validate_pii.ts)
participant PY as validate_pii.py (Presidio)
E->>DB: SELECT orgSettings FROM workspace LEFT JOIN organization
DB-->>E: orgSettings (DataRetentionSettings)
E->>E: resolveEffectivePiiRedaction(orgSettings, workspaceId)
alt "enabled = false"
E-->>E: return payload unchanged
else "enabled = true"
E->>R: redactPIIFromExecution(payload, entityTypes)
R->>R: collect all eligible strings (two-pass walk)
alt "totalBytes > 16 MB"
R-->>R: scrub all strings with REDACTION_FAILED
else within budget
R->>P: maskPIIBatch(texts, entityTypes) chunked 256 KB each
loop for each chunk
P->>PY: spawn subprocess, write JSON to stdin
PY-->>P: __SIM_RESULT__ passed results
end
P-->>R: masked string array
end
R->>R: substitute masked strings back into payload structure
R-->>E: redacted RedactablePayload
end
E->>DB: INSERT/UPDATE workflowExecutionLogs (redacted data)
Loading

Reviews (11): Last reviewed commit: "fix(logs): re-hydrate data-retention for..." | Re-trigger Greptile

Comment threadapps/sim/lib/billing/retention.ts Outdated
Comment threadapps/sim/lib/logs/execution/pii-redaction.ts Outdated
Comment threadapps/sim/lib/logs/execution/logger.ts
@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds enterprise-grade PII redaction for workflow execution logs, a new per-workspace data-retention-hours override, and a check-digit-validated VIN recognizer. The core redaction pipeline is well-engineered: a deterministic two-pass collect/substitute approach batches all strings from a single execution into one chunked Presidio call, and a fail-safe ensures PII is never persisted when masking fails.

  • PII redaction: hooked at completeWorkflowExecution after filterForDisplay and redactApiKeys; org-scoped rules are resolved at persist time covering both inline and externalized write paths; oversized payloads (>16 MB) are scrubbed rather than leaked.
  • Workspace retention overrides: new nullable workspace.data_retention_settings column with a clean workspace ?? org ?? plan-default resolution chain; a new /api/workspaces/[id]/data-retention endpoint mirrors the org-level API with proper admin + enterprise gating.
  • Three copies of the comment \"Empty = redact all detected PII\" on entityTypes (in schema.ts, primitives.ts, and pii-redaction.ts) directly contradict retention.ts, which treats an empty entity-type list as "contribute nothing, rule is inactive." The PR description confirms the correct semantic is "empty = redact nothing", so those three comments need updating to avoid operators mistakenly believing empty rules provide full coverage.

Confidence Score: 3/5

The redaction pipeline and workspace-override logic are structurally sound, but three copies of a wrong comment on a security-sensitive field create a genuine risk of operators deploying empty-entity-type rules under the false impression that they cover all PII.

The core machinery — two-pass collect/substitute, byte-chunked Presidio calls, fail-safe scrubbing, and the workspace ?? org ?? plan-default retention resolution — is implemented correctly. Three conflicting entityTypes comments in schema.ts, primitives.ts, and pii-redaction.ts say the opposite of what retention.ts implements. An enterprise admin who follows those comments and creates a rule with no entity types selected will have no PII masked at all — a silent failure in a privacy-protection feature.

packages/db/schema.ts, apps/sim/lib/api/contracts/primitives.ts, and apps/sim/lib/logs/execution/pii-redaction.ts all carry the wrong entityTypes comment that contradicts retention.ts.

Important Files Changed

FilenameOverview
apps/sim/lib/logs/execution/pii-redaction.tsNew PII redaction transform: deterministic two-pass collect/substitute approach is sound; fail-safe scrubbing on error is correct; misleading entityTypes comment and reuse of REDACTION_FAILED_MARKER for the byte-ceiling case need fixing.
apps/sim/lib/logs/execution/logger.tsPII redaction correctly hooked at the single persist choke point after filterForDisplay + redactApiKeys; adds 2 extra DB queries per execution on the hot path that could be consolidated into the existing log fetch.
apps/sim/lib/billing/retention.tsNew file with clean resolution logic for both retention hours (workspace ?? org ?? fallback) and PII redaction (union of applicable rule entity types). Correctly returns disabled when union is empty, though this contradicts comments elsewhere.
packages/db/schema.tsAdds DataRetentionSettings interface and workspace.dataRetentionSettings column; PiiRedactionRule.entityTypes comment says Empty = redact all detected PII which contradicts the actual retention.ts behavior (empty = redact nothing).
apps/sim/lib/api/contracts/primitives.tsAdds well-validated piiRedactionRuleSchema and piiRedactionSettingsSchema; same misleading entityTypes comment as schema.ts.
apps/sim/lib/guardrails/validate_pii.tsNew maskPIIBatch function correctly chunks texts by byte budget (256KB), rejects on subprocess failure so callers can apply fail-safe; existing validatePII single-text path unchanged.
apps/sim/lib/guardrails/validate_pii.pyAdds mask_batch function reusing a single AnalyzerEngine + AnonymizerEngine across all texts in a chunk; VinRecognizer with ISO 3779 check-digit validation is well-implemented.
apps/sim/lib/billing/cleanup-dispatcher.tsAdds workspace-level settings to the cleanup scope query; fallback is null for all enterprise jobs so behavior is identical to the previous code for unconfigured orgs.
apps/sim/app/api/workspaces/[id]/data-retention/route.tsNew workspace-level data retention GET/PUT endpoints; auth gating (session, admin permission, enterprise plan) is correct.
apps/sim/lib/logs/execution/pii-redaction.test.tsGood coverage: structure preservation, immutability, fail-safe scrub on error, oversized-string skip, and no-op when no strings collected.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant E as Executor
participant L as ExecutionLogger
participant R as retention.ts
participant P as pii-redaction.ts
participant V as validate_pii.ts
participant Py as validate_pii.py
participant DB as Postgres
E->>L: completeWorkflowExecution
L->>L: filterForDisplay + redactApiKeys
L->>DB: SELECT org.dataRetentionSettings
DB-->>L: orgSettings
L->>R: resolveEffectivePiiRedaction
R-->>L: enabled + entityTypes
alt PII enabled
L->>DB: isWorkspaceOnEnterprisePlan
DB-->>L: true
L->>P: redactPIIFromExecution
P->>P: collect string leaves
loop Per 256KB chunk
P->>V: maskPIIBatch
V->>Py: spawn subprocess
Py-->>V: masked strings
V-->>P: masked strings
end
P-->>L: redacted payload
end
L->>DB: UPDATE workflowExecutionLogs
L-->>E: WorkflowExecutionLog
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant E as Executor
participant L as ExecutionLogger
participant R as retention.ts
participant P as pii-redaction.ts
participant V as validate_pii.ts
participant Py as validate_pii.py
participant DB as Postgres
E->>L: completeWorkflowExecution
L->>L: filterForDisplay + redactApiKeys
L->>DB: SELECT org.dataRetentionSettings
DB-->>L: orgSettings
L->>R: resolveEffectivePiiRedaction
R-->>L: enabled + entityTypes
alt PII enabled
L->>DB: isWorkspaceOnEnterprisePlan
DB-->>L: true
L->>P: redactPIIFromExecution
P->>P: collect string leaves
loop Per 256KB chunk
P->>V: maskPIIBatch
V->>Py: spawn subprocess
Py-->>V: masked strings
V-->>P: masked strings
end
P-->>L: redacted payload
end
L->>DB: UPDATE workflowExecutionLogs
L-->>E: WorkflowExecutionLog
Loading

Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/sta..." | Re-trigger Greptile

Comment threadapps/sim/lib/logs/execution/pii-redaction.ts
Comment threadapps/sim/lib/logs/execution/pii-redaction.ts
Comment threadapps/sim/lib/logs/execution/logger.ts
Comment threadpackages/db/schema.ts Outdated
Comment threadapps/sim/lib/api/contracts/primitives.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

Comment threadapps/sim/lib/logs/execution/logger.ts
…t lazy
- Extend PII redaction to span error/errorMessage/toolCalls and top-level
error/completionFailure/trigger/executionState (Bugbot: PII in execution
metadata). executionState is safe to redact — resume reads from the separate
pausedExecutions table, not the log copy.
- Lazy-import validate_pii in pii-redaction so the Python/child_process
guardrails module stays out of the static middleware/RSC graph.
- Type the org retention mutation to the contract body (optional, non-null).
Comment threadapps/sim/lib/logs/execution/pii-redaction.ts
…stays org-scoped
- Remove the unused per-workspace data-retention-hours override (no UI; superseded
by workspace-scoped PII rules). Reverts cleanup-dispatcher to org-only retention,
drops resolveEffectiveRetentionHours, the workspace.dataRetentionSettings column +
migration, and the workspace data-retention route/contract/hooks. Fixes Bugbot's
null-as-unset finding by removing the buggy path entirely; org retention behavior
is unchanged.
- Stop re-checking isWorkspaceOnEnterprisePlan at persist time (it returns false on
transient errors, which would fail-open and leak PII). Enabled rules already imply
entitlement; redact whenever rules apply (fail-safe).
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

Comment threadapps/sim/lib/logs/execution/pii-redaction.ts
- Drop the per-string size cap in PII redaction: oversized strings were left
unmasked (leak). Nothing is skipped now; large payloads still fail-safe via the
total-bytes ceiling + per-chunk timeout (scrub, never leak).
- Add executionData.environment (incl. variables) to the redaction set.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

…tion
Each rule now targets one scope — all workspaces (workspaceId: null) or a single
workspace — with workspaceId unique across rules. Resolution is most-specific-wins
(a workspace's own rule overrides the all rule), not union; an empty specific rule
exempts that workspace. Matches Access Control's resolveWorkspaceGroup precedence.
UI 'Applies to' becomes a single-select; Add rule disables when all scopes are taken.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

Comment threadapps/sim/lib/logs/execution/logger.ts
Comment threadapps/sim/lib/api/contracts/primitives.ts
Reshape the PII redaction settings into a 'Default (all workspaces)' block plus a
'Workspace overrides' list, making the most-specific-wins precedence explicit
(overrides replace the default; unlisted workspaces use it). Same data model
(workspaceId null = default), UI only.
Drop the uppercase section labels and the overrides description; gate the
Workspace overrides section behind a configured default; use a single Delete
action; 'Add redaction' creates the all-workspaces default and disappears once set.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

Comment threadapps/sim/lib/guardrails/validate_pii.ts
Attach an 'error' listener to the child's stdin in both runPythonScript (the
batch masking hot path) and executePythonPIIDetection. A 256KB chunk can exceed
the OS pipe buffer, so if the Python process exits mid-read (OOM/kill) the EPIPE
emitted on stdin was unhandled and would crash the Node process. Funnel it into
the promise rejection so the fail-safe scrub path handles it gracefully.
Comment threadapps/sim/lib/logs/execution/logger.ts
The top-level correlation field is copied from pre-redaction trigger data, so
webhook/schedule correlation values could persist unredacted. Add it to the
redaction set alongside trigger/environment.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@BugBot review

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

1 issue from previous review remains unresolved.

Fix All in Cursor

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 7313e18. Configure here.

The contract accepted multiple rules with the same workspaceId (or several
null all-rules); resolution is first-match, so duplicates could disagree with
the UI. Add a schema refine rejecting duplicate scopes.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

2 similar comments
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@BugBot review

The form hydrated once via a boolean ref, so switching the active org left stale
retention days + PII rules and saves targeted the new org with old config. Key
hydration on orgId so it re-loads per org.
@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@BugBot review

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ad7d1fa. Configure here.

@TheodoreSpeaks
TheodoreSpeaks merged commit 9d2a6ef into stagingJun 19, 2026
16 checks passed
@TheodoreSpeaks
TheodoreSpeaks deleted the feat/redact-pii-workflow-log branch June 19, 2026 21:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@TheodoreSpeaks