This guide adds a label, for example vehicle for number plates. A label has to exist in four places, or its suggestions are rejected or silently dropped.

1. Add it to the shared type

src/features/redact/workflow-domain.ts, add to RedactionLabel:

2. Add it to the runtime contract

src/features/redact/analysis-contract.ts, add "vehicle" to redactionLabelSchema. Responses with unknown labels fail this schema.

3. Ask Laya about it

qvac-service/reasoning.ts, add a question to privateQuestions (asked at both levels) or confidentialQuestions (Confidential only). The key is the label; the value is a statement that is true or false about one line of text:
See How to ask Laya your own questions for how to phrase it.

4. Ground it in the text

qvac-service/candidate-validation.ts:
  • add an entry to explanations, for example vehicle: "The block contains a vehicle registration.";
  • add a rule to groundedLabel() that returns "vehicle" when the OCR text supports it, placed before the generic name and other rules.
Without a rule, every vehicle candidate is dropped, because groundedLabel() returns null for labels it can’t confirm.

5. Test it

Add a case to qvac-service/candidate-validation.test.ts for text that should and shouldn’t match. Then:
To measure it on real inference, add an evaluation case with a labelled vehicle region.