ValidationResult for every requirement in the tender, with a MET, PARTIALLY_MET, or NOT_MET verdict, an AI-generated reasoning paragraph, and a numeric confidence score.
Validation Result Schema
Each comparison between a tender requirement and the proposal document is represented by aValidationResult object.
How Validation Works
Fetch tender requirements from the database
ValidateProposal use case loads the saved TenderAnalysis (including all extracted Requirement objects) from Turso using the tenderId parameter. If no tender is found, a 404 error is returned immediately.Parse the proposal PDF
MIN_JUSTIFICATION_LENGTH (10 characters), the proposal is rejected as unreadable.Generate embeddings for requirements if missing
gemini-embedding-001 and persisted back to the requirements table. This step ensures the vector index is always up to date.Semantic similarity search
SIMILARITY_THRESHOLD of 0.3 are flagged as relevant.Batch LLM comparison
BATCH_CHUNK_SIZE (3 requirements per batch). Up to MAX_AI_CONCURRENCY (3) batches are sent to Gemini in parallel using the Senior Evaluator system prompt, which instructs the model to perform a deep semantic search — not to return “not specified” if any numerical or project experience requirement is present in the text.Map internal AI statuses to ValidationStatus
COMPLIANT, NON_COMPLIANT, PARTIAL). These are normalised to the domain model:COMPLIANT→METPARTIAL→PARTIALLY_METNON_COMPLIANTor any other value →NOT_MET
Mark non-relevant requirements as NOT_MET
NOT_MET status with a confidence of 0.3 and a note that the requirement was filtered by semantic search. This completes the result set without incurring additional LLM calls.Save results to the database
ValidationResult objects are merged with any pre-existing SCOPE_CHECK result and saved back to the TenderAnalysis record in Turso. The complete list of results is then returned to the frontend.Vector Search Pre-filtering
Before any LLM call is made, TenderCheck AI uses Googlegemini-embedding-001 to generate high-dimensional vector embeddings (3,072 dimensions as implemented by VectorSearchService) and filters out requirements that are semantically unrelated to the proposal content.
NOT_MET verdict automatically, avoiding up to 60–80% of LLM calls compared to processing every requirement individually.
Confidence Score
Theconfidence field in every ValidationResult is normalised to the 0.0–1.0 range before being stored.
- The AI may return confidence as a fraction (
0.95) or as a percentage (95). TenderCheck AI detects this automatically: if the raw score is greater than1, it is divided by100. - If the AI returns no score at all, the system falls back to
DEFAULT_CONFIDENCE_SCORE = 75, which normalises to0.75. - The frontend displays confidence as a percentage by multiplying by
100if the stored value is already in the0–1range.
How to Validate a Proposal
Complete a tender analysis first
COMPLETED tender analysis. Follow the Tender Analysis flow to extract requirements before proceeding.Open the completed analysis
Upload the proposal PDF
.pdf files up to 50 MB are accepted.Submit and wait for validation
Review the Validation Summary
12 / 15), and optional requirements met.Inspect individual verdicts in ComparisonResults
MET / PARTIALLY_MET / NOT_MET badge, the AI’s reasoning paragraph, and any evidence quote extracted from the proposal. AI confidence is shown as a percentage.Exporting Results
Once validation is complete, the full analysis — including all requirements and their validation verdicts — can be exported from theAnalysisResults header card:
PDF Export
export.service.ts. Suitable for sharing with procurement teams or archiving.JSON Export
TenderAnalysis object (including all ValidationResult entries) as a structured JSON file. Useful for integration with other systems.docs/Testing_docs/Oferta_Offer_IT_Security.pdf (included in the repository) to test the full validation pipeline against the matching IT security tender. The pair is designed to produce a mix of MET, PARTIALLY_MET, and NOT_MET results.