LearnNewsExamplesServices
Frontmatter
id13776
titlefeat(ai): sync-writer redaction guard — the re-introduction keystone (sibling of #13772)
stateClosed
labels
aiarchitecture
assigneesneo-opus-ada
createdAtJun 21, 2026, 4:24 PM
updatedAtJun 21, 2026, 6:53 PM
githubUrlhttps://github.com/neomjs/neo/issues/13776
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 21, 2026, 6:53 PM

feat(ai): sync-writer redaction guard — the re-introduction keystone (sibling of #13772)

neo-opus-ada
neo-opus-ada commented on Jun 21, 2026, 4:24 PM

Sync-writer redaction guard (the re-introduction keystone)

Sibling of #13772. The content mirrors are SyncService output; scrubbing them (or re-syncing) is necessary but not sufficient — without redaction at the WRITE choke-point, the next sync re-introduces any sensitive term from the live source (especially external-handle activity-logs that cannot be edited out of GitHub). This wires the shared redactSensitiveContent (#13773) into the syncers so re-sync redacts on write.

Design (decided — Tier-2, reversible)

  • The body-projection seam is #projectAuthoredNode(node, contentTrust, field) (per-syncer; sanitizes untrusted-author content via the existing contentTrust). contentTrust is author-TRUST-based → it does NOT redact the partner name (which must go regardless of author trust). So the redaction is a SEPARATE, trust-independent step applied to all projected content.
  • A shared helper (DRY, one choke-point) applies redactSensitiveContent(body, aiConfig.redaction?.denyPairs ?? []) at the body-projection in all three syncers (Issue / PR / Discussion), after the contentTrust step.
  • Deny-pairs from aiConfig.redaction.denyPairs: config.template.mjs default [] (name-clean); the gitignored config.mjs carries the pairs (operator exception: partner name in, real external handles out). Read the resolved leaf at the use-site (ADR-0019).

Acceptance Criteria

  • shared redaction helper applied at the body-projection in Issue/PR/Discussion syncers, trust-independent.
  • aiConfig.redaction.denyPairs config-seam (template default []); read at the use-site.
  • tests: a configured term in a synced body is redacted on write; empty denyPairs = no-op; external-handle policy honored.
  • coordinate the SyncService touch with the re-sync owner (surface D) to avoid collision.

Sibling of #13772. Builds on #13773 (redactSensitiveContent). Part of the gate-9 remediation (surface E).