mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 00:48:18 +00:00
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:
committed by
Sina Matian
co-authored by
masashiono0611
parent
23c7b0eb16
commit
a849d833eb
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/',
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user