diff --git a/modules/jarvos-secondbrain/packages/jarvos-secondbrain-notes/src/knowledge-optimizer.js b/modules/jarvos-secondbrain/packages/jarvos-secondbrain-notes/src/knowledge-optimizer.js index 780df3ba..acc9b5ac 100644 --- a/modules/jarvos-secondbrain/packages/jarvos-secondbrain-notes/src/knowledge-optimizer.js +++ b/modules/jarvos-secondbrain/packages/jarvos-secondbrain-notes/src/knowledge-optimizer.js @@ -210,6 +210,10 @@ function booleanish(value) { function sensitivityFor({ filePath, body, frontmatter }) { const tags = parseList(frontmatter.tags || frontmatter.tag || ''); + const declaredPrivacyTier = String(frontmatter.privacy_tier || '').trim().toLowerCase(); + const privacyTier = ['public', 'local-private', 'private', 'sensitive', 'secret'].includes(declaredPrivacyTier) + ? declaredPrivacyTier + : null; const haystack = [filePath, frontmatter.status, frontmatter.type, frontmatter.project, tags.join(' '), String(body || '')] .join('\n') .toLowerCase(); @@ -217,6 +221,9 @@ function sensitivityFor({ filePath, body, frontmatter }) { if (booleanish(frontmatter.private) || booleanish(frontmatter.sensitive)) { reasons.push('frontmatter marks note private/sensitive'); } + if (['private', 'sensitive', 'secret'].includes(privacyTier)) { + reasons.push(`frontmatter privacy_tier is ${privacyTier}`); + } if (tags.some((tag) => /^(private|sensitive|secret|credentials?|medical|financial|tax)$/i.test(tag))) { reasons.push('frontmatter tags exclude automatic import'); } @@ -224,7 +231,7 @@ function sensitivityFor({ filePath, body, frontmatter }) { if (haystack.includes(term)) reasons.push(`contains excluded term: ${term}`); } return { - privacyTier: reasons.length ? 'sensitive' : 'local-private', + privacyTier: privacyTier || (reasons.length ? 'sensitive' : 'local-private'), excluded: reasons.length > 0, reasons: [...new Set(reasons)], }; diff --git a/modules/jarvos-secondbrain/tests/knowledge-units.test.js b/modules/jarvos-secondbrain/tests/knowledge-units.test.js index f5afca72..d7077f57 100644 --- a/modules/jarvos-secondbrain/tests/knowledge-units.test.js +++ b/modules/jarvos-secondbrain/tests/knowledge-units.test.js @@ -125,3 +125,25 @@ test('sensitive notes keep local knowledge units but block downstream promotion' assert.equal(artifact.knowledgeUnits[0].downstreamEligibility.gbrain, false); assert.equal(artifact.knowledgeUnits[0].downstreamEligibility.memoryPromotion, false); }); + +test('declared private privacy tiers block downstream promotion', () => { + for (const privacyTier of ['private', 'sensitive', 'secret']) { + const { notesDir, filePath } = noteFixture(); + const artifact = buildArtifact({ + filePath, + notesDir, + title: 'Covert Plan', + body: 'This innocuous text does not match a sensitivity heuristic.', + frontmatter: { privacy_tier: privacyTier }, + created: true, + }); + + assert.equal(artifact.privacyTier, privacyTier); + assert.equal(artifact.sensitivity.excluded, true); + assert.equal(artifact.gbrain.status, 'skipped'); + assert.equal(artifact.memoryWiki.status, 'skipped'); + assert.equal(artifact.knowledgeUnits[0].privacyDecision.tier, privacyTier); + assert.equal(artifact.knowledgeUnits[0].downstreamEligibility.gbrain, false); + assert.equal(artifact.knowledgeUnits[0].downstreamEligibility.memoryWiki, false); + } +});