fix(frontmatter): drop the shipped rule binding a personal folder to a sensitive category (#3949)

Wave-assembled from PR #3949 by @Masashi-Ono0611.

Co-Authored-By: masashiono0611 <masashi.ono.0611@gmail.com>
This commit is contained in:
Garry Tan
2026-08-12 14:38:36 -07:00
committed by Sina Matian
co-authored by masashiono0611
parent 23c7b0eb16
commit a849d833eb
4 changed files with 36 additions and 10 deletions
+2 -2
View File
@@ -40,7 +40,7 @@ import { MinionQueue } from '../minions/queue.ts';
import { waitForCompletion, TimeoutError } from '../minions/wait-for-completion.ts';
import { makeSubagentHandler } from '../minions/handlers/subagent.ts';
import type { MinionJobInput, MinionJobContext, MinionHandler, SubagentHandlerData } from '../minions/types.ts';
import { discoverTranscripts, type DiscoveredTranscript } from './transcript-discovery.ts';
import { discoverTranscripts, DEFAULT_EXCLUDE_PATTERNS, type DiscoveredTranscript } from './transcript-discovery.ts';
import { serializeMarkdown, serializePageToMarkdown } from '../markdown.ts';
import type { Page, PageType } from '../types.ts';
import { validateSourceId } from '../utils.ts';
@@ -862,7 +862,7 @@ async function loadSynthConfig(engine: BrainEngine): Promise<SynthConfig> {
DEFAULT_SUBAGENT_WAIT_TIMEOUT_MS,
);
let excludePatterns: string[] = ['medical', 'therapy'];
let excludePatterns: string[] = [...DEFAULT_EXCLUDE_PATTERNS];
if (excludeStr) {
try {
const parsed = JSON.parse(excludeStr);
+8
View File
@@ -119,6 +119,14 @@ export function isDreamOutput(content: string, bypass = false): boolean {
return DREAM_OUTPUT_MARKER_RE.test(content);
}
/**
* Sensitivity categories dream excludes from transcript ingestion by default.
* The single source for this vocabulary: `dream.synthesize.exclude_patterns`
* overrides it at runtime, and test/frontmatter-inference.test.ts asserts no
* shipped DIRECTORY_RULE binds a path to one of these.
*/
export const DEFAULT_EXCLUDE_PATTERNS: readonly string[] = ['medical', 'therapy'];
/**
* Auto-wrap bare-word patterns in `\b<word>\b`. Power users can pass full
* regex (e.g. `^therapy:`) which we honor verbatim. Heuristic: any input
-8
View File
@@ -112,14 +112,6 @@ export const DIRECTORY_RULES: DirectoryRule[] = [
datePattern: 'filename',
titleStrategy: 'filename',
},
{
pathPrefix: 'apple notes/jan bowman notes/',
type: 'apple-note',
source: 'apple-notes',
tags: ['therapy', 'jan-bowman'],
datePattern: 'filename',
titleStrategy: 'filename',
},
// Catch-all for Apple Notes not in a subfolder
{
pathPrefix: 'apple notes/',
+26
View File
@@ -6,6 +6,10 @@
*/
import { describe, test, expect } from 'bun:test';
import {
compileExcludePatterns,
DEFAULT_EXCLUDE_PATTERNS,
} from '../src/core/cycle/transcript-discovery.ts';
import {
inferFrontmatter,
extractDateFromFilename,
@@ -336,6 +340,28 @@ describe('DIRECTORY_RULES', () => {
return sameFields && [...(r.tags ?? [])].sort().join(',') === derived;
};
// Transcripts matching gbrain's sensitivity vocabulary are dropped before any
// LLM call. A shipped DIRECTORY_RULE that maps a specific person's folder
// onto one of those categories encodes a private fact about a real individual
// into every install, which the Privacy rule in CLAUDE.md forbids for
// checked-in code. Personal mappings belong in the operator's own notes.
//
// Matched with the production compiler, not a local `includes`: bare words
// compile to \b<word>\b, so `therapy-notes` and `medical records` are caught
// the same way discoverTranscripts catches them. An exact-equality check
// would let those spellings recreate the association with CI green.
test('no shipped rule binds a path to a sensitive category', () => {
const res = compileExcludePatterns([...DEFAULT_EXCLUDE_PATTERNS]);
expect(res.length).toBe(DEFAULT_EXCLUDE_PATTERNS.length); // no silent drop
const offenders = DIRECTORY_RULES.filter(r =>
(r.tags ?? []).some(t => res.some(re => re.test(t))),
);
// Report indices, not prefixes: an offending prefix is by definition the
// kind of string this test exists to keep out of public artifacts, and a
// failing assertion is printed into CI logs.
expect(offenders.map(r => DIRECTORY_RULES.indexOf(r))).toEqual([]);
});
test('Apple Notes rules are more specific than the catch-all', () => {
const appleRules = DIRECTORY_RULES.filter(isAppleRule);
expect(appleRules.length).toBeGreaterThan(1); // subfolder rules + catch-all