feat!: optional fail-closed fallback, legend output, richer prompt & docs
BREAKING CHANGE: regex fallback is now opt-in (patterns no longer defaults
to presets.swiss). With no fallback an LLM failure throws AnonymizationError
(fail-closed) and the pre-filter is bypassed; at least one of llm/patterns is
required. AnonymizationResult gains a required `legend`; anonymizeChunks seed
is now { mapping, legend? } and returns legend.
- prompt: model may coin new UPPERCASE abbreviations and returns a 'legende'
explaining every abbreviation used (French); backfilled by DEFAULT_LEGEND
- PatternDef.meaning surfaces in the legend; swiss/generic presets get meanings
- AnonymizationError (exported) wraps the cause on fail-closed
- README: drop the chatbot provenance line; add 'How it works' + nLPD sections
- 34 tests / 99% coverage; bump to 0.2.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@ describe('openAICompatibleProvider', () => {
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const r = await openAICompatibleProvider(opts).anonymize('a@b.ch');
|
||||
expect(r).toEqual({ anon: '[EMAIL_1]', mapping: { '[EMAIL_1]': 'a@b.ch' } });
|
||||
expect(r).toEqual({ anon: '[EMAIL_1]', mapping: { '[EMAIL_1]': 'a@b.ch' }, legend: {} });
|
||||
|
||||
const [url, init] = fetchMock.mock.calls[0];
|
||||
expect(url).toBe('https://api.example.com/v1/chat/completions');
|
||||
@@ -35,6 +35,18 @@ describe('openAICompatibleProvider', () => {
|
||||
expect(init.headers.Authorization).toBe('Bearer k');
|
||||
});
|
||||
|
||||
it('parses the model legende into result.legend, keeping only string values', async () => {
|
||||
const fetchMock = mockFetchJson({
|
||||
texte_anonymise: '[PER_1.NOM:M]',
|
||||
mapping: { '[PER_1.NOM:M]': 'Alain Jaccard' },
|
||||
legende: { PER: 'Personne', NOM: 'Nom de famille', M: 'Masculin', BAD: 42 },
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const r = await openAICompatibleProvider(opts).anonymize('Alain Jaccard');
|
||||
expect(r.legend).toEqual({ PER: 'Personne', NOM: 'Nom de famille', M: 'Masculin' });
|
||||
});
|
||||
|
||||
it('anonymizeBatch() returns {segments, mapping} and includes used ids in the prompt', async () => {
|
||||
const fetchMock = mockFetchJson({ segments: ['[PER_2.NOM:M]'], mapping: { '[PER_2.NOM:M]': 'Bob' } });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
Reference in New Issue
Block a user