Mohd Zamin QuadriAI Engineer, BP-ITCS

Mohd Zamin Quadri  /  AI Engineer  /  BP-ITCS

Turning published law
into knowledge you can
check.

Production-oriented AI engineering across legal knowledge infrastructure, document intelligence, retrieval and data integrity. Five services take a statute from the body that publishes it to a queryable corpus that can prove what it contains — and refuse to serve what it cannot. I implemented four of them.

Read the architecture Talk track

Step 1 of 8   Start with the landscape: two workstreams, one platform.

Two workstreams, one platform

Both workstreams do the same fundamental thing: take a document that somebody else authored, and turn it into knowledge a machine can query without losing track of where it came from. One does it for German and EU legislation, the other for insurance documents.

They share Kafka, PostgreSQL, MinIO, Qdrant and Neo4j, and they share no topics, databases or collections. The Legal Knowledge Database is five services and I implemented four of them; the document workstream is three services I extended, one of which I started.

AUTHORITATIVE SOURCES AND INPUTSoutside the systemA · LEGAL KNOWLEDGE DATABASEfive services · four implemented by meB · AI COMPLIANCEthe product the corpus serves · existingC · DOCUMENT INTELLIGENCEextended by meD · MEDICAL-IMAGING CLASSIFICATION + TEST DATAresearch prototype · extended by meSHARED PLATFORMexisting infrastructure · one writer per storeLEVEL 2 · LANDSCAPEAI engineering systems I worked on at BP-ITCSFour workstreams over one event-driven platform. Colour is engineering role; border weight and the corner marker are authorship.Mohd Zamin QuadriAI Engineer · BP-ITCSgesetze-im-internet.deGerman federal law, GII-NORM XMLZIP per lawEUR-Lex / CELLAREU acts, FORMEX v4CELEX · fmx4Insurance documentspolicies, claims, invoices, conditionsPDF · PNG · TIFF · WEBPMedical imageschest radiographsentityType: MEDICAL_IMAGEEntity ProducerCaptures source bytes as evidence:4675 · javaIngestion PreprocessorStructures, cites, owns 14 gates:4698 · pythonIngestion LoaderEmbeds, converges derived stores:4697 · BGE-M3Legal KB DashboardOperator interface. Decides nothing.:3000 · next.jsHealth ServiceControl and verification boundary:8000 · /api/v1Legal ChatbotGrounded answers over the corpusexisting componentAssessment UI + backendStructured questionnaire and website scan; publishes work and consumes results:4000 · :4010 · ai_complianceKnowledge processorReads the questionnaire graph and the legal corpus, returns a grounded assessmentibp.events.ai.processedCompliance reportRendered to PDF behind a short-lived tokenassessment-evidencequestionnaire graphDocument ExtractorDocling conversion, then template-driven LLM field extraction6 insurance templatesIndexing ServiceChunks, embeds, upserts vectors per domain; DLQ on failureI created this serviceRAG ServiceRetrieval-only chat and query extraction/chat · /queryGlaux UIEvent dashboard with live service healthnext.js · STOMPDenseNet-121 classifierFive findings, sigmoid per class, one calibrated threshold eachDenseNet121-v2.0.0Grad-CAM++ attributionShows which regions drove each positive finding; anatomicalpriors deliberately offheatmaps to MinIOSeverity + ICD-10Urgency bands and a clinical code per findingHIGH · MODERATE · LOWSynthetic test dataVVG-compliant German insurance document set and generator,so no real customer document is neededai-contract-dataPostgreSQLcanonical state + evidencewriter: preprocessorQdrantdense 1024 + sparsewriter: loaderNeo4jprovisions + questionnairewriter: loaderMinIOcaptures, evidence, imageswriter: producerApache KafkaKRaft · the spine all four workstreams shareibp-kafka · :29192ROLEExternal sourceEvent / transportAI / MLPersistenceVerification / trustOperator / APIFLOWsynchronous requestasynchronous eventverification / read-onlyAUTHORSHIPPrimary implementationSignificant contributionIntegration / sharedExisting platformExternal / upstream
01The landscape. Colour is engineering role; border weight and the corner marker are authorship. Open the SVG

4

services I implemented, out of 20 repositories inspected

14

verification gates, of which seven are required for the aggregate badge

52

laws in the registry — 32 German, 20 EU; 25 certified as structurally complete

Counts are read from app/data/law_registry.yaml and audit/reports/corpus-certification-ledger.md as of 2026-09-12. The service README states 31 and 51; the registry has moved since, and the registry wins.

The one-paragraph version

A platform that does not only make authoritative information searchable, but makes claims about that information falsifiable.

LEVEL 1 · EXECUTIVEAuthoritative information, made trustworthy and machine-readableNo technology names. Four capabilities and the promise each one makes.Mohd Zamin QuadriAI Engineer · BP-ITCSAuthoritative informationPublished law and business documents, taken from the bodythat issues themA knowledge platformExtraction, structure, citation resolution and semantic indexingVerified knowledgeIndependent measurement of what was stored against what wasservedApplicationsGrounded search and answering, with operator control of thelifecycleTHE PROMISEWe can always show which file we used, and when.THE PROMISEContent becomes queryable without losing what it came from.THE PROMISEWe can state what is trustworthy, and what is merely present.THE PROMISEAnswers cite provisions, and a person decides what enters thecorpus.WHY THIS IS DIFFERENT FROM SEARCHThe distinction that matters at this level: the platform does not only make information searchable, it makes claims about that information falsifiable. Every stored item can be re-derived from the publisher's own bytes under a recorded set of rules, and if it cannot be, the system says so rather than serving itquietly.ROLEExternal sourceAI / MLVerification / trustOperator / API
02Level 1. Four capabilities, no technology names. Open the SVG

One law, end to end

Eleven stages. Each one either produces evidence, or is measured against evidence produced earlier.

DOCUMENT JOURNEYOne law, from publisher to queryable knowledgeEleven stages. Each one either produces evidence or is measured against evidence produced earlier.Mohd Zamin QuadriAI Engineer · BP-ITCSDiscoverRegistry names the law, its parser and its publisher slugapp/data/law_registry.yaml1AcquireHealth service downloads the ZIP, or resolves CELEX atCELLARAccept: application/zip;mtype=fmx42Prove the bytesSHA-256 over the captured bytes, carried on the event aszipHashfidelity.raw_integrity3CaptureWritten to MinIO under a fresh eventId prefix, thenpublished{eventId}/{filename}4Inventory the sourceAn independent walker builds the denominator,importing no parser codetools/oracle_gii_structure.py5ParseGII-NORM or FORMEX v4, dispatched from the registrygii_norm | formex_v46Extract referencesCitations resolved to provision-level identity tuplesrelationship_extractor.py7ChunkRetrieval units for active sections onlychunks · evidence_chunker8Persist canonicallyOne transaction: rows plus the three ruleset digestsPostgreSQL · law.structured9Embed and projectBGE-M3 dense + sparse, then converge Qdrant andNeo4j under count fencesPostgreSQL · law.embedded10Verify14 gates run automatically on completion; the verdictbecomes the badgeverification_checks11WHY THIS SEQUENCEThe order is not arbitrary. The source inventory (5) comes before the parser (6) so the denominator cannot be derived from the thing under test. Thearchive-mirror row is written last of all, after the object has been uploaded, read back, hashed and size-checked, because that row is what theraw-integrity gate treats as evidence.NO BACK DOORIngestion has no REST trigger. The only way a law enters the pipeline is a matching Kafka event, which is what makes replay and re-ingest the samecode path rather than two.ROLEExternal sourceAI / MLPersistenceVerification / trustFLOWsynchronous request
04From publisher to queryable knowledge. Open the SVG

Two orderings in that sequence are load-bearing. The independent source inventory is built before the parser runs, so the denominator used to check the extraction does not come from the thing being checked. And the archive-mirror row is written last of all — after the object has been uploaded, read back, hashed and size-checked — because that row is what the raw-integrity gate treats as evidence. A row that exists has to mean bytes that were verified.

THE SPINEFrom source of truth to trusted corpusThe conceptual shape of the system. Derived knowledge is never the evidence for itself.Mohd Zamin QuadriAI Engineer · BP-ITCSSource of truthWhat the publisher actually served, andwhenIngestTurn bytes into rows, under a recordedrule setDerived knowledgeRepresentations built for retrieval, not forrecordVerifyMeasure what is stored against what wasservedReconcileAnswer the live question, change nothingTrusted corpusWhat may be served to a question aboutthe lawThe publisher's own bytesSHA-256 digest at capture timeObject-locked evidence copyA described fetch, bound to a capture idNothing downstream may contradict thislayer.Registry decides what the law isParser dispatched, never guessedCitations resolved to identitiesThree ruleset digests recordedA generation remembers the rules that madeit.PostgreSQL — canonical rowsQdrant — dense + sparse vectorsNeo4j — provision graphEach derived id is a function of the rowsRebuildable from the layer above. Never thesource of a claim.14 gates, 4 dimensionsAn independent structural oracleCross-store equality, by exact countCurrency judged from recorded evidenceThe prover proves itself first, or issues noverdict at all.PostgreSQL identity tuples readQdrant and Neo4j comparedLIVE_CONSISTENT · DRIFT_DETECTEDCHECK_UNAVAILABLE is also an answerThe last sweep's answer, not a standingguarantee.A verdict per gate, not one badgeFreshness of the verdict itselfCurrency of the publisher's fileLive store integrityFour separate questions. Merging them wouldhide which one failed.WHY THE ORDER IS THE ARCHITECTURERead right to left and the reason for the shape appears: to trust the corpus you need reconciliation; to reconcile you need verification; to verify you need derived knowledge and the evidence it came from; and to have evidence you must have proven the bytes before parsing them. Every layer's claim is falsifiableagainst the layer above it, which is what the word trusted is doing in the last box.ROLEExternal sourceEvent / transportAI / MLVerification / trustOperator / API
05The conceptual spine. Derived knowledge is never the evidence for itself. Open the SVG

Why four stores

Each store is here because the others cannot do its job. The limitation row is the real justification.

KNOWLEDGE STORAGEFour stores, four jobs, one writer eachEach store is here because the others cannot do its job. The limitation row is the actual justification.Mohd Zamin QuadriAI Engineer · BP-ITCSPostgreSQLCanonical recordSole writer: Preprocessor (corpus) · Health Service(currency)HOLDSLaws, versions, sections, chunksCitations and law-level referencesSource evidence, append-onlyGate verdicts and ruleset provenanceCurrency observations and audit logCANNOTCannot search by meaning.DESIGN CONSEQUENCEON DELETE RESTRICT on currency_observations is why a wrong deleteis impossible rather than discouraged.QdrantSemantic retrievalsole writer: loaderHOLDSOne point per chunkdense 1024, cosine, named densesparse LEXICAL from the same modelpayload: law, section_number, title, raw_textRRF fusion server-sideCANNOTCannot follow a citation chain, cannot enforce integrity.DESIGN CONSEQUENCEPoint id is uuid5(ns, chunk_id), so a re-run overwrites and neverduplicates.Neo4jReference traversalsole writer: loaderHOLDS(:LawSection {id}) · (:Law {code})[:REFERS_TO] → LawSection[:CITES_LAW] → LawStub nodes for cited-but-not-ingestedMERGE by id; never recreatedCANNOTCannot search by meaning.DESIGN CONSEQUENCEA vector hit finds the matched provision. A compliance answer oftenneeds the one it cites.MinIOImmutable evidenceWriters: Entity Producer (captures) · Preprocessor(mirror)HOLDSCaptures under {eventId}/{filename}Evidence bucket with object lockDigest and size verified on read-backMirror row written last, as the gate's evidenceNever touched by withdrawalCANNOTCannot be queried at all; it holds bytes and digests.DESIGN CONSEQUENCECaptures are immutable by key, not by policy — no versioning, nocontent-addressing, no dedup.THE MECHANISM THAT REPLACES A DISTRIBUTED TRANSACTIONEvery derived identifier is a pure function of PostgreSQL content: uuid5(namespace, chunk_id) for a Qdrant point, MERGE by id for a graph node, MERGE by code for a law node. Identity is derived, never generated — and that single property is what makes Kafka redelivery idempotent across two stores with nodistributed transaction, and is the real answer to how the stores stay in step.ROLEPersistenceAUTHORSHIPPrimary implementation
06Four stores, four jobs, one writer each. Open the SVG

How they stay in step without a distributed transaction

Every derived identifier is a pure function of PostgreSQL content. A Qdrant point id is uuid5(namespace, chunk_id). A graph node is MERGE-d by id, a law node by code. Identity is derived, never generated — so re-running a delivery converges to the same state rather than duplicating it. That single property is what replaces a transaction across a relational store, a vector store and a graph store, and it is why a Kafka redelivery is safe rather than dangerous.

Can we trust what is being served?

The system answers that with fourteen gates and four separate statuses, and it deliberately refuses to answer it with one badge.

Seven gates are required for the aggregate the dashboard shows; the other seven are recorded and displayed anyway, because a measurement nobody can see is not a measurement. All fourteen apply to a German law. Twelve apply to an EU law: fidelity.xml_byte_partition and structure.source_profile are structurally inapplicable to FORMEX and say so in code, with a named reason rather than silence.

VERIFICATION · THE SHORT VERSIONWhy the verdict is worth believingSix mechanisms. Each one exists to stop the verification layer from confirming itself.Mohd Zamin QuadriAI Engineer · BP-ITCS1 · The bytes are hashed firstSHA-256 over the publisher's own file, before any parser reads it. A claim about a law is onlyas good as the bytes it came from.2 · A second, independent readingThe structural denominator comes from a different XML stack that imports no parser code,so a defect cannot be common to both.3 · The rules are hashed tooEvery generation records digests over the parser, the reference extractor and the registry. Abyte change is a rule change.4 · The prover proves itselfIf any already-certified law stops reproducing under today's rules, no law gets a verdict —including the one being certified.5 · Fourteen gates, none hiddenSeven are required for the badge; all fourteen are recorded and displayed. A measurementnobody can see is not a measurement.6 · Four answers, never one badgeVerification status, verdict freshness, source currency and live store integrity stay separate,so a green summary cannot hide which one failed.WHAT THIS DOES NOT CLAIMAnd the two limits that travel with it: a count matching is not proof — a citation misread onto a provision that does exist moves no count and fails no gate — and COMPLETE is machine structural assurance, not legal review. No law in the corpus is human-certified.The full gate inventory, the verdict pipeline and the three operations are in diagram 06.ROLEExternal sourceVerification / trustOperator / APIFLOWsynchronous requestAUTHORSHIPPrimary implementation
07The short version: six mechanisms, each one there to stop the verification layer from confirming itself. Open the SVG
TRUST AND VERIFICATIONCan we trust the knowledge currently being served?Fourteen gates answer it, and the answer is never one badge. Seven gates are required for the aggregate; the other seven are recorded and shown, because a hidden measurement is nota measurement.Mohd Zamin QuadriAI Engineer · BP-ITCSGATE IDQUESTION IT ASKSBADGEDEEUfidelity.raw_integrityis the archived file still the file we captured?requiredyesyescurrency.source_statehas the publisher's file changed?requiredyesyesprovenance.pipeline_profilewhich declared pipeline produced this?requiredyesyesstructure.section_inventoryis every source unit present?requiredyesyesfidelity.qdrant_payloaddoes search match the database?requiredyesyesfidelity.neo4j_graphdoes the graph match the database?requiredyesyesfidelity.xml_byte_partitiondoes the stored text reconstruct the source?requiredyesnot applicablefidelity.served_textis served text what the declared pipeline makes of it?recordedyesyesfidelity.reference_extractiondoes every stored reference reproduce?recordedyesyesfidelity.source_structureis each served unit exactly one publisher unit?recordedyesyesfidelity.source_substructureis the evidence tree what the source contains?recordedyesyesfidelity.citation_completenessis any detected citation missing?recordedyesyesprovenance.publisher_captureis this archive bound to a described fetch?recordedyesyesstructure.source_profileis the source served now inside our profile?recordedyesnot applicableTHE FOURTEEN GATESHOW A VERDICT IS PRODUCED1 · Captured source, digest-provenThe publisher's own bytes, in MinIO, hashed at capturefidelity.raw_integrity2 · An independent denominatorA second inventory of the same markup on a different stack — lxml streaming events, where production parsesthe whole tree — importing no parser codetools/oracle_gii_structure.py3 · The prover proves itself firstIf any already-certified law no longer reproduces under today's rules, no law gets a verdict — including the onebeing certifiedtools/prove_law.py4 · Run every applicable gateTriggered automatically by law.embedded, or on demand by an operator. Observer only.POST /internal/laws/{key}/verify5 · verification_checksOne row per gate per generation. The dashboard badge is read back from a view over this table.law_verification_stateWHAT THE GATES CANNOT SEEA count matching is not proof. A citation misread onto a provision that does exist produces no orphan, moves no countand fails no gate — which is why a separate human review of citation targets exists alongside the machine gates.COMPLETE is machine structural assurance. It is not legal review, and no law in the corpus claims to behuman-certified.FOUR QUESTIONS, FOUR ANSWERS · NEVER ONE BADGEVerification statusVERIFIED · MEASURED ·NOT_INGESTED · NOT_INGESTIBLEVerdict freshnesshow old the measurement itself isSource currencyhas the publisher moved since wecaptured?Live store integritydo Qdrant and Neo4j still matchPostgreSQL?WHY THEY ARE NOT MERGEDA single green summary would hide which of the four actually failed, so the dashboard keeps them apart. A law can be structurally perfect and out of date; it can be current and havedrifted in one derived store. Those are different problems with different fixes, and one badge cannot say which you have.THREE OPERATIONS TOUCH A LAW · ONLY ONE CHANGES ITReconciliation · changes nothingPOST /reconciliation-sweep1Read PostgreSQL identity tuples2Compare Qdrant and Neo4j3Report LIVE_CONSISTENT, DRIFT_DETECTED or CHECK_UNAVAILABLELIVE_CONSISTENT is the last sweep's answer, not a standing guarantee.Verify · changes nothingPOST /laws/{key}/verify1Poll the publisher, write a currency observation2Ask the preprocessor to run the gates3Return one outcome plus every gate verdictIt changes no version, section, chunk, vector or edge. Observer only.Re-ingest · changes the corpusPOST /laws/{key}/reingest1Fetch the source, submit a new capture2Preprocessor rewrites canonical state3Loader reconverges Qdrant and Neo4jZero-downtime: nothing is purged first, so the old generation stays queryable and a failed ingestleaves it untouched.WHY MEASUREMENT AND MUTATION ARE SEPARATEDThe distinction is the architecture. Two of the three operations are measurements and one is a mutation, and they are built so that an operator cannot reach for the mutation by accident: re-ingest requires DATA_SOURCE=live and LIFECYCLE_ACTIONS_ENABLED, while verify and reconcile need neither. A systemthat makes measuring as expensive as changing gets measured less often.ROLEExternal sourcePersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous requestverification / read-onlyAUTHORSHIPPrimary implementation
08The full version: the gate inventory, how a verdict is produced, and the three operations that touch a law. Open the SVG

What the gates cannot see

A count matching is not proof. A citation misread onto a provision that does exist produces no orphan, moves no count, and fails no gate — which is why a separate human review of citation targets sits alongside the machine gates, and why COMPLETE is defined as machine structural assurance rather than legal review. No law in the corpus claims to be human-certified.

FAILURE AND RECOVERYWhat actually goes wrong, and what happens nextEvery row is a failure the repositories document, with the recovery that exists — or the honest statement that none does.Mohd Zamin QuadriAI Engineer · BP-ITCSFAILUREWHEREIMMEDIATE EFFECTRECOVERYCLASSSource download failsHealth service cannot reach the publisher, or CELLARnegotiation failsNothing published, nothing writtenOperator retries. Re-ingest is idempotent at this stage.recoveredMinIO upload fails on a download-mode captureoriginUrl path, where MinIO is mandatory502; nothing publishedOperator retriesrecoveredMinIO upload fails on an upload-mode capturefile path, where MinIO is best-effortTolerated: publication continues with the inline copy, and the event hasno MinIO urlDegraded but consistentdegradedKafka ack times outProducer cannot confirm publication503 — and the send may already have reached the brokerA retry mints a new eventId, so the same bytes land under a second prefix.No compensation exists.acceptedOrphaned captureMinIO is written before Kafka; publication then failsAn object exists that no event referencesNothing removes it. Recorded as a known consequence.acceptedPre-flight detects unknown structureA law whose markup the model does not representBLOCKED before ingestionStop and report the gap. Never weaken the gate or special-case the law.by designEmbedding would be truncatedA chunk exceeds the model's 8192-token windowThe whole law is refused rather than storing a vector that misrepresentsits textFix the chunking, then replayby designQdrant converges, Neo4j failsPartial projectionNo law.embedded, offset uncommitted, consume loop endsRedelivery re-runs both stores from a fresh snapshot and convergesidenticallyrecoveredCrash between publish and commitOffset not yet committedlaw.embedded may be published twiceThe unique index on capture_id absorbs the duplicaterecoveredStores disagree at restDrift between canonical and derived stateReconciliation reports DRIFT_DETECTEDOperator decides: re-ingest, or investigate. Nothing self-heals.operatorA store is unreachable during a checkQdrant or Neo4j downCHECK_UNAVAILABLE — a first-class answer, distinct fromdisagreementRetry the sweeprecoveredPublisher has moved onThe source file changed since capturecurrency.source_state reportsSOURCE_CHANGED_REINGEST_REQUIREDOperator re-ingests. The old generation stays queryable until the new onecompletes.operatorRuleset changed since a generation was storedA byte changed in the parser, extractor or registryThe recorded digest no longer matches the installed one; the corpusbaseline fails and no law gets a verdictRe-extract from the held capture. If output is unchanged, revalidate; if itdiffers, replay.by designWithdrawal half-completesCanonical state committed, projection cleanup failedRECONCILIATION_REQUIRED 409 — the law is withdrawn and notservedRetry re-runs cleanup. Evidence is never touched by any step.recoveredA law is permanently unprocessableParse or gate failure that redelivery cannot fixNo dead-letter topic exists. It is redelivered for ever and blocks itspartition.Manual intervention. This is the clearest gap in the pipeline.gapACCEPTED, NOT UNNOTICEDThree of these are labelled accepted and one is labelled gap. That is the point of the diagram: a pipeline with no dead-letter topic, no bounded retry and no automatic repair is a deliberate position for a legal corpus — an automatic self-heal that silently re-derives knowledge is, after the fact, indistinguishable fromone that silently corrupted it — but it is a position with a real cost, and the cost is that one bad law can stall a partition until a human intervenes.ROLEPersistenceVerification / trustOperator / APIFailure path
09Fifteen documented failures, and the recovery that exists — or the statement that none does. Open the SVG

The query path

Deliberately separate from the ingestion path. Nothing here writes a store, and nothing here parses a law.

QUERY TIMERetrieval and grounded answeringThe query path is deliberately separate from the ingestion path. Nothing here writes a store, and nothing here parses a law.Mohd Zamin QuadriAI Engineer · BP-ITCSVERIFIED IN THIS WORKSPACEQueryOperator search, or a questionarriving as an eventGET /search ·ibp.events.inboundEmbed the queryBGE-M3, the same model thatembedded the corpusdense 1024 + sparseHybrid retrievalDense and sparse prefetch, fusedserver-side by RRFprefetch = max(limit, 20)QdrantOne point per chunk, both lawfamilies in one collectionpayload: law, section_number,title, raw_textCited chunksSection number and law key travelwith every chunk, so a citation isdata rather than generated textsection_number · lawquery_pointsANSWERING · EXISTING COMPONENT, NOT INSPECTABLE IN THIS WORKSPACEGraph expansionNeo4j holds what each provisioncites; the chatbot has access to itneeds verificationLegal ChatbotConsumes ibp.events.inbound,publishes ibp.events.ai.processedrepository not present hereLLMSelf-hosted, OpenAI-compatibleendpoint; the container runs fullyoffline for weightsHF_HUB_OFFLINE=1Grounded answerReturned with the provisions it wasbuilt fromibp.events.ai.processedCitation validationCheck each cited section againstthe corpus before the answer isshown. Zero LLM calls.DESIGNED, NOT IMPLEMENTEDTWO PATHS, ONE CORPUSIngestion-time components write stores and are the only things that do. Query-time components read. The separation is why a retrieval bug cannotcorrupt the corpus and why an ingestion replay cannot be triggered by a question.One consequence worth stating: the query path has no verification gate of its own. It trusts the corpus because the corpus was verified before it wasserved — which is exactly why the gates and the badge exist upstream.WHERE HALLUCINATED CITATIONS ARE ADDRESSED — AND WHERE THEY ARE NOT YETThe answer-level citation check is a design position, not delivered work. An LLM that cites a section which does not exist is the specific failure thatmakes a legal assistant dangerous, and validating cited section numbers against the corpus costs no model call.What does ship today is upstream of that: provenance on the source, structural fidelity gates on the extraction, and retrieval that carries the law keyand section number as payload rather than as prose.ROLEAI / MLPersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous requestverification / read-onlyAUTHORSHIPPrimary implementationExisting platform
10Query time. The answering stage is an existing component whose repository is not in the inspected workspace. Open the SVG

Retrieval is hybrid and single-round-trip: BGE-M3 produces a dense and a sparse vector from one pass, both are prefetched, and Qdrant fuses them server-side with reciprocal rank fusion. Dense catches meaning — a query for “duty to disclose” reaches the German Anzeigepflicht. Sparse catches exact tokens, which is what a citation like § 19 VVG actually is.

One refusal is worth more than the retrieval design. FlagEmbedding truncates silently past the model's 8192-token window, so the loader counts tokens first and raises for the whole law rather than storing a vector for text the model never fully saw. A silently truncated embedding is undetectable afterwards: it has the right dimensionality, sits in the right collection, and is wrong.

The operator control plane

Four actions, and what each one actually triggers behind the button.

OPERATOR SURFACEOPERATIONSThe operator control planeFour actions, and what each one actually triggers behind the button. The dashboard decides nothing: every badge it shows was decided by a gate and read back through one backend.Mohd Zamin QuadriAI Engineer · BP-ITCSLegal KB Dashboard7 pages · 27 components · 9 routehandlers. Holds no database, queue orobject-store client.one env var: LEGAL_KB_API_URLserver-side onlyHealth ServiceThe only backend. Owns currency,snapshots and the audit log; inspectseverything else.23 routes under /api/v1Ingest / Re-ingestPOST /laws/{key}/reingest1Health service downloads the current source itself, or resolves the CELEX for an EU act2Entity Producer captures the bytes, hashes them, writes MinIO, publishes events.inbound3Preprocessor rewrites canonical state in one transaction and publishes law.structured4Loader re-embeds and reconverges Qdrant and Neo4j, then publishes law.embedded5That event triggers verification with nobody asking for itReturns 202 immediately. The old generationstays queryable throughout and a failedingest leaves it untouched.VerifyPOST /laws/{key}/verify1Poll the publisher and bind the result to the capture id2Write one currency_observations row — evidence, not a verdict3Ask the preprocessor to run every applicable gate4Return one outcome plus the per-gate verdictsTakes minutes legitimately, so the route setsno-store and a 300-second timeout. Adefault fetch timeout would have reported afailure that never happened.ReconcilePOST /reconciliation-sweep1Read the identity tuples PostgreSQL holds2Count and compare what Qdrant and Neo4j actually hold now3Report LIVE_CONSISTENT, DRIFT_DETECTED or CHECK_UNAVAILABLECHECK_UNAVAILABLE is a first-classanswer. A store that cannot be reached isnot the same as a store that disagrees.Withdraw from active corpusDELETE /laws/{key}1Take a per-law lifecycle lock2Preprocessor withdraws canonical state in one transaction: sections and cascades deleted, inbound references deleted, version superseded, withdrawn_at set3Loader clears the law's Qdrant points and Neo4j graph, verifying zero4Report REMOVED, ALREADY_REMOVED, NOT_FOUND, RECONCILIATION_REQUIRED or ERRORThe order is not interchangeable: canonicalfirst, because that is the step that can berefused. No MinIO object, raw document,publisher capture, currency observation orverification check is ever touched.WHY THE OPERATOR SURFACE IS THIS NARROWEvery one of these is reachable only through the health service, and the two that change the corpus are double-gated behind DATA_SOURCE=live and LIFECYCLE_ACTIONS_ENABLED. The dashboard cannot reach the preprocessor, the loader, Kafka or any store directly — not by convention, but because it shipswith no client for any of them and exactly one configurable URL.ROLEVerification / trustOperator / APIFailure pathFLOWsynchronous requestAUTHORSHIPPrimary implementation
10Ingest, Verify, Reconcile, Withdraw — and the double gate on the two that change the corpus. Open the SVG
LIFECYCLERe-ingestion, and what it does to system stateA re-ingest does not clear the law first. Each store's own write path replaces it safely, which is what makes the operation survivable at any point.Mohd Zamin QuadriAI Engineer · BP-ITCSSERVEDthe current generation, verified1CAPTURE SUBMITTEDnew eventId, new prefix old captureintact2CANONICAL REPLACEDone transaction version superseded3PROJECTIONSCONVERGINGQdrant upsert then delete stale4MEASUREDgates have run, verdicts recorded5SERVEDthe new generation, verified6WHAT A READER SEES AT EACH STATESTATEPOSTGRESQL SERVESQDRANT SERVESNEO4J SERVESBADGE SHOWS1 SERVEDold generationold vectorsold graphVERIFIED2 CAPTURE SUBMITTEDold generationold vectorsold graphVERIFIED, ingest in progress3 CANONICAL REPLACEDnew generationold vectorsold graphstale — drift is real here4 PROJECTIONS CONVERGINGnew generationnew vectors after the fencenew graph after the fenceingest in progress5 MEASUREDnew generationnew vectorsnew graphverdict per gate6 SERVEDnew generationnew vectorsnew graphVERIFIEDTHE WINDOW THAT IS NOT HIDDENState 3 is the honest part of this diagram. Between the canonical commit and the projection fences, PostgreSQL holds the new generation while Qdrantand Neo4j still hold the old one. That window is real, it is short, and reconciliation will report it as DRIFT_DETECTED if it is sampled inside it.It is accepted rather than eliminated, because the alternative — a distributed transaction across a relational store, a vector store and a graph store —buys consistency at a cost the corpus does not need. Nothing serves a partial law: the old generation answers until the new one is complete.NOTHING ADVANCES ON ITS OWNNo state here is entered by a timer, a retry policy or a repair daemon. A re-ingest is an operator action, every transition is driven by an event theprevious stage published, and if a stage fails the machine stops in place rather than advancing.That is a deliberate choice about a legal corpus: an automatic self-heal that silently re-derives knowledge is indistinguishable, afterwards, from anautomatic self-heal that silently corrupted it.ROLEEvent / transportAI / MLPersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous request
12What a reader sees at each state of a re-ingest, including the window where the stores legitimately disagree. Open the SVG
STATE MODELThe states a law actually occupiesReconstructed from the technical states, event boundaries, gate verdicts and lifecycle columns that exist in code — not from a generic lifecycle template.Mohd Zamin QuadriAI Engineer · BP-ITCSREGISTEREDin law_registry.yaml; may be ingestible:falseCAPTUREDbytes in MinIO, SHA-256 recordedSTRUCTUREDcanonical PostgreSQL committedEMBEDDEDQdrant and Neo4j converged, fencespassedMEASUREDevery applicable gate has a verdictBLOCKEDpre-flight refused it; never ingestedINTEGRITY FAILEDa required gate failedSOURCE CHANGEDthe publisher has moved onVERIFIEDall required gates pass; currency validWITHDRAWNwithdrawn_at set; evidence retainedcaptureevents.inboundlaw.structuredlaw.embeddedpre-flightall passwithdrawre-ingestWHERE THESE STATES LIVETwo of these are not derived from a status column, and that is the interesting part. EMBEDDED exists because the loader publishes an event only afterboth count fences pass, and MEASURED exists because the preprocessor consumes that event and runs the gates unasked.So the state model is enforced by the event contract rather than by a field somebody has to remember to set.WITHDRAWN IS NOT DELETEDWITHDRAWN is not deletion. The laws row survives, withdrawn_at is set, and every piece of evidence — MinIO objects, raw documents, publishercaptures, currency observations, verification checks — is untouched.A law leaving the corpus does not make the record of what its publisher served untrue. That sentence is in the source, and it is why withdrawal anddeletion are different operations.ROLEExternal sourceEvent / transportAI / MLPersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous requestasynchronous eventrefused / blocked
13The states a law occupies, reconstructed from code rather than from a generic lifecycle template. Open the SVG

Withdrawing a law is not deleting it. The laws row survives, withdrawn_at is set, and no MinIO object, raw document, publisher capture, currency observation or verification check is touched by any step. A law leaving the corpus does not make the record of what its publisher served untrue.

Insurance document AI

A template is the extraction contract, not the model. That is what lets the model change without the pipeline changing.

EXTRACT · STRUCTURE · INDEXextended by meRETRIEVE · SERVEDOCUMENT INTELLIGENCEInsurance document AI — from PDF to structured understandingA template is the extraction contract, not the model. That is what lets the model change without the pipeline changing.Mohd Zamin QuadriAI Engineer · BP-ITCSDocument arrivesUploaded through the platform UI andstored in MinIO; an event names itibp.events.inboundbucket: ibp-documentsDocument ExtractorFilters by domain and entity type,downloads the file, converts it, extractsfieldsaccepted_domains: INSURANCEpython · fastapi + kafkaDocling ServeSidecar that converts PDF and imagebytes to Markdown over HTTPdocling-serve-cpu :5001do_ocr: "false"Extraction agentDiscovery, guided extraction andre-extraction against the active template,then post-validationprompt_builder · post_validatormax 6000 chars per callIndexing ServiceOptional LLM mapping, overlappingchunks, embeddings, vector upsertdomain-configuredDLQ on failureeventPOSTmarkdownibp.events.document.extractedibp.events.document.indexedibp.events.document.indexed.dlqTHE EXTRACTION CONTRACTDOCUMENT TYPEFIELDSIDENTIFIERVERSICHERUNGSPOLICEpolicy_number, customer_name, customer_id, insurer, effective_date, expiry_date,coverage_amount, vm_number, issue_date, currencycustomer_nameSCHADENMELDUNGclaim_number, policy_number, incident_date, report_date, claimant_name, customer_id,contract_number, damage_description, damage_amount, damage_locationclaimant_nameVERSICHERUNGSVERTRAGcontract_number, policy_number, customer_name, customer_id, signing_date, contract_start,contract_end, premiumcustomer_nameRECHNUNGinvoice_number, invoice_date, total_amount, vendor_nameARZTBERICHTpatient_name, diagnosispatient_nameAUSWEISfull_name, id_numberfull_nameWHY HINTS, NOT FINE-TUNINGEvery field carries an extraction_hint naming the German label variants to look for: "Look for:Policennummer, VS-Nr., Vertragsnummer, Police Nr."That is domain literacy encoded as data. It moves between models without retraining, and itis reviewable by someone who knows insurance but not Python.ONE CONTRACT, THREE CONSUMERSTemplates live in entity-reader and are published as versioned snapshots onibp.events.templates, which the extractor, the indexer and the RAG service all follow.Without that, a schema change means three services holding three stale copies of the samecontract.WHAT FIELD EXTRACTION ACTUALLY COSTExtraction was hardened against what real documents actually do: a policy-number regexrebuilt around three observed failure modes, a title-anchor fast path for conditionsdocuments, German umlaut mojibake repair, and replacement-character detection to catch aPDF that extracted as text but lost its font mapping.A silent corruption that looks like success is worse than a failure, which is the same principlethe legal pipeline's gates are built on.Qdrant · per-domain collectionsRouting is a declared filter on metadata.domain over a sharedtopic, not a topic splitibp_documents_insuranceibp_medical_imagesRAG ServiceRetrieval-only chat and query extraction; domain planners turn arequest into a retrieval plan/chat · /query · /statsAI Prediction ServiceDenseNet-121 chest X-ray classification with Grad-CAM++heatmaps written to MinIOmedical domain · not insuranceWHAT IS AND IS NOT MODELLEDThe correction worth making explicitly: this pipeline models customer, policy, coverage, claim, contract, invoice and identity documents, plus a medical report. It does not model vehicle, property, health or beneficiary domains — no template or domain configuration for them exists, so none is drawn.ROLEExternal sourceEvent / transportAI / MLPersistenceVerification / trustFailure pathFLOWsynchronous requestasynchronous eventverification / read-onlyexclusive writeAUTHORSHIPSignificant contributionExisting platform
14From PDF to structured understanding, with the six document templates that define what structured means. Open the SVG

The most portable piece of domain knowledge in that repository is a string: "Look for: Policennummer, VS-Nr., Vertragsnummer, Police Nr.". German insurance-document literacy, encoded as data, reviewable by someone who knows insurance but not Python, and carried between models without retraining.

Multi-label chest X-ray classification

A research/prototype medical-imaging classification pipeline — internally named “AI Radiologist”. Five findings, one calibrated decision threshold each, and a Grad-CAM++ attribution map.

Scope: this is a prototype. It is not a medical device, it has no regulatory clearance, it was not clinically validated or deployed, and it does not assist or replace a clinician. The internal project name is recorded here because that is what the repository calls it — it is not a claim about clinical role.

Five findings — atelectasis, cardiomegaly, consolidation, edema and effusion — each with an ICD-10 code and its own decision threshold. The thresholds are Youden’s J optima from a validation set, which is why they differ so widely: cardiomegaly is called positive at 0.130 and effusion only at 0.424. A single global cut-off would have been wrong for every class.

INFERENCE PATH · ONE STUDYevent in, enriched event outCOMPUTER VISION · RESEARCH PROTOTYPEMulti-label chest X-ray classification with explainabilityInternal project name: “AI Radiologist”. A research/prototype medical-imaging classification pipeline — not a medical device and not clinically deployed. Five findings, one calibratedthreshold each, and a Grad-CAM++ attribution map.Mohd Zamin QuadriAI Engineer · BP-ITCSStudy arrivesA medical image is uploaded and an eventnames it; the bytes live in object storageibp.events.inboundentityType: MEDICAL_IMAGEPreprocessDecode, resize to the model's inputgeometry, normalise224 × 224 · IMAGE_SIZEmax dimension 800 on re-encodeClassifyDenseNet-121 with a dropout + linear headover five findings. Sigmoid per class, notsoftmax — a study can show severalfindings at once.DenseNet121-v2.0.0torchvision · CUDA or DirectMLAttributeGrad-CAM++ over the final convolutionalblock, showing which regions drove eachpositive findingChattopadhay et al., WACV 2018keep 40% · floor 10%ReportPer-finding probability, its threshold, theverdict, an urgency band and an ICD-10code; heatmap written to object storageibp.events.ai.processedjet colormap · alpha 0.40FIVE FINDINGS, FIVE DECISION THRESHOLDSFINDINGTHRESHOLDICD-10WHAT IT MEANSAtelectasis0.329J98.11Partial lung collapseCardiomegaly0.130I51.7Enlarged heartConsolidation0.234R91.8Airspace filled with fluidEdema0.233J81.0Fluid in the lungsEffusion0.424J90Fluid in the pleural spaceWHY PER-CLASS THRESHOLDSA single global cut-off would have been wrong for every class. Cardiomegaly is called positive at 0.130 andEffusion only at 0.424 — the same raw score means different things per finding.The thresholds are Youden's J optima from a validation set, so each one maximises sensitivity plus specificity forits own class rather than for the average.PRESENCE IS NOT URGENCYPresence and urgency are answered separately. Presence uses the calibrated per-class threshold; urgency usesfixed probability bands — HIGH at 0.70, MODERATE at 0.40, otherwise LOW.Collapsing the two would make a confident low-acuity finding look like an emergency, and a borderlinehigh-acuity one look routine.A DESIGN DECISION · FACT FROM CODE, THEN MY READING OF ITFact · what exists in the codeA per-finding anatomical prior: cardiomegaly centre-left, effusion lower, edema perihilar,each with a boost factor. It is boost-only — the mask never suppresses, it only emphasises.Fact · it is switched offUSE_ANATOMICAL_HINTS = False, commented “DISABLED — trust Grad-CAM fully”. Thecode states the model’s attention is the ground truth for localisation and the hints are softonly.My reading · not documented in the codeAn engineering concern is that an anatomical prior could bias localisation towards expectedanatomy, so the attribution would tend to agree with the label rather than show what themodel used. That rationale is my interpretation of the decision, not a comment in the source.INTERPRETATION, AND THE LIMITSI read this as the same shape of decision as the legal corpus’s structural oracle — a check that shares the assumption of the thing it checks cannot falsify it. That parallel is my own framing across two codebases, not a claim that either was built with the other in mind.Stated plainly: a research/prototype classification pipeline with explainability and calibrated thresholds. Not a medical device, not clinically validated or deployed, no regulatory clearance, and no accuracy figure is claimed anywhere in this portfolio.ROLEExternal sourceAI / MLPersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous requestAUTHORSHIPPrimary implementationSignificant contributionExisting platform
17The inference path, the five decision thresholds, and the one decision worth defending. Open the SVG

A design decision, separated into fact and interpretation

What the code contains. A per-finding anatomical prior — cardiomegaly centre-left, effusion lower, edema perihilar, each with a boost factor. The mask is boost-only: it emphasises, it never suppresses. The flag controlling it is USE_ANATOMICAL_HINTS = False, commented “DISABLED — trust Grad-CAM fully”, and the surrounding comments state that the model’s attention is the ground truth for localisation and that the hints are soft only.

My reading of it, which the code does not state. An engineering concern is that an anatomical prior could bias localisation towards expected anatomy, so the attribution would tend to agree with the label rather than show what the model actually used. That rationale is my interpretation of the decision — the source documents “trust the model’s attention”, not an argument about explanation bias.

I also read it as the same shape of decision as the legal corpus’s independent oracle — a check that shares the assumption of the thing it checks cannot falsify it. That parallel is my own framing across two codebases, not a claim that either was built with the other in mind.

AI Compliance — what the corpus is for

The customer-facing assessment product. It is the reason the Legal Knowledge Database has to be verifiable rather than merely searchable.

A customer works through a structured questionnaire; a headless browser scans their site for evidence the questionnaire cannot ask for; a knowledge processor reads the questionnaire graph together with the legal corpus and produces a grounded assessment; the result is rendered to a PDF report behind a short-lived token.

THE PRODUCTexisting platform · not my codeTHE QUESTIONNAIRE BRIDGEa colleague's feature, inside a service I builtPRODUCT · INSURANCE AI COMPLIANCEAI Compliance — what the legal corpus is actually forThe customer-facing assessment product. It is the reason the Legal Knowledge Database has to be verifiable: its answers become a compliance report somebody relies on.Mohd Zamin QuadriAI Engineer · BP-ITCSAssessment UINext.js app on Bun. Customer works througha structured questionnaire; password,magic-link or SSO:4000 · auth: local | keycloakCompliance backendSpring Boot on JDK 25. Owns assessments,publishes work, consumes results, rendersthe report:4010 · PostgreSQL ai_complianceWebsite scanDrives a headless browser over thecustomer's site to gather evidence thequestionnaire cannot ask forPlaywright over websocketKnowledge processorReads questions, answers and flags withtheir embeddings from the graph, retrievesthe relevant provisions, and produces agrounded assessmentconsumes ibp.events.inboundReportRendered to PDF by a headless browserbehind a short-lived render tokentoken TTL 120sevidence bucket: assessment-evidenceRESTscanibp.events.inboundibp.events.inboundibp.events.ai.processedibp.events.ai-compliance.results.dltresultsundeliverableWHERE IT MEETS THE LEGAL KNOWLEDGE DATABASEQuestionnaire publishedA new questionnaire version lands in object storage and an eventannounces itdomain: AI_COMPLIANCEentityType: QUESTIONNAIRELoader ingests itA second consumer path inside the ingestion loader: fetch, skip ifthe content hash is unchanged, embed, storequestionnaire_loading_service.pyBGE-M3 · 1024-dimNeo4j · questionnaire graphQuestions, answers and compliance flags as nodes, each carryingits own embeddingHAS_QUESTION · HAS_OPTIONTRIGGERS_FLAGProcessor reads the graphTakes questions, answers, flags and embeddings straight from thegraph, so it needs no embedding model of its ownno local BGE-M3WHY THE CORPUS HAS TO BE VERIFIABLEThis is the answer to ‘why build a verification layer at all?’. A compliance report tells an insurance customer whether they meet an obligation, and citesthe provision it relied on. If the corpus behind that citation has drifted from what the publisher actually served, the report is confidently wrong — andnobody downstream can tell.So the gates, the provenance digests and the four separate trust answers are not engineering decoration. They are what makes this product's outputdefensible.WHOSE WORK THIS ISThe product itself is not my work. The assessment UI, the backend, the website scan and the knowledge processor were built by colleagues, and theirrepositories are not in the workspace this portfolio was audited from — so no internal detail is drawn.The questionnaire ingestion path is a colleague's feature living inside a service I implemented: I implemented the loader, its Kafka handling and itsembedding and graph-write layers; the questionnaire service on top of them is not mine to claim. It is marked Integration / shared, and its author iscredited in the private evidence pack.ROLEEvent / transportAI / MLPersistenceVerification / trustOperator / APIFailure pathFLOWsynchronous requestasynchronous eventAUTHORSHIPIntegration / sharedExisting platform
18The product, and the questionnaire bridge into the legal corpus. Authorship is marked per component. Open the SVG

Why the corpus has to be verifiable

A compliance report tells an insurance customer whether they meet an obligation, and cites the provision it relied on. If the corpus behind that citation has drifted from what the publisher actually served, the report is confidently wrong and nobody downstream can tell. The gates, the provenance digests and the four separate trust answers exist so that this product’s output is defensible.

Whose work this is: the assessment UI, the backend, the website scan and the knowledge processor were built by colleagues and their repositories are outside the workspace this portfolio was audited from, so no internal detail is drawn. The questionnaire ingestion path is a colleague’s feature living inside a service I implemented — I own the loader, its Kafka handling and its embedding and graph-write layers; the questionnaire service on top of them is marked Integration / shared rather than claimed.

Ten topics, two pipelines, one broker

Exact topic names, their producers and their consumers — and the places where the two pipelines differ in maturity.

EVENT-DRIVEN ARCHITECTURETen topics, two pipelines, one brokerExact topic names, their producers and their consumers. The two pipelines differ in maturity, and the diagram shows the difference rather than smoothing it.Mohd Zamin QuadriAI Engineer · BP-ITCSTOPICPRODUCED BYCONSUMED BYWHAT IT MEANSlegal.knowledge.database.events.inboundEntity ProducerIngestion Preprocessora capture exists; here is its envelope and digestlegal.knowledge.database.law.structuredPreprocessorIngestion Loadercanonical PostgreSQL is committed — and nothing morelegal.knowledge.database.law.embeddedLoaderPreprocessor, Health Serviceboth derived stores are durably converged: the completion boundarylegal.knowledge.database.questionnaire.structuredquestionnaire pathnot inspectable hereneeds verification — producer lives outside this workspaceibp.events.inboundplatform UI and backendDocument Extractor, Legal Chatbota document or a question has arrivedibp.events.document.extractedDocument ExtractorIndexing Servicemarkdown and extracted fields are attached to the eventibp.events.document.indexedIndexing Servicedownstream consumerschunks are embedded and searchableibp.events.document.indexed.dlqIndexing Serviceoperatorsthis document could not be indexedibp.events.templatesDocument ExtractorIndexing Service, RAG Servicea versioned template snapshot, so three services share one contractibp.events.ai / ibp.events.ai.processedAI servicesentity handlersan AI result is ready to persistDELIVERY SEMANTICS THAT WERE DESIGNED, NOT INHERITEDPartitioned by law identityThe Kafka key is law_key, so one law maps to one partition and twogenerations of the same law can never be processed concurrently.fix: key inbound events by law identityPublish, then commitThe loader converges both stores, publishes law.embedded, awaitsthe broker ack, and commits the offset last. A crash in betweenredelivers.the commit is last of allDuplicates absorbed, not preventedA redelivery may publish law.embedded twice.currency_observations carries a unique index on capture_id, so thesecond one cannot record a second observation.unique (capture_id)Skips commit tooA non-matching event has its offset committed and is skipped, so aforeign event cannot wedge the consumer or block its partition.domain=LEGAL, IMPORTEDWHAT IS MISSING, STATED AS MISSINGThe legal pipeline has no dead-letter topic, no bounded retry and no backoff. A permanently unprocessable law is redelivered for ever and blocks itspartition; the consume loop ends and waits for a human to restart the pod. Nothing re-ingests, rebuilds or rolls back on its own.The document pipeline does have a DLQ. That difference is real, and it is the clearest piece of outstanding work in the legal workstream.WHY REDELIVERY IS NOT A RISKRedelivery is safe because identity is derived rather than generated. A Qdrant point id is uuid5(namespace, chunk_id); a graph node is MERGE-d by id; alaw node is MERGE-d by code. Re-running a delivery converges to a byte-identical state.That is the property that replaces a distributed transaction across three stores, and it is why the absence of automatic retry is survivable rather thandangerous: a manual restart is just another delivery.ON A SYSTEM THAT IS NOT HERENote on scope: the brief for this portfolio asked for a GDMS Rule Mapper with gdms.* topics. No repository, topic, consumer, class, configuration or document for it exists anywhere in the inspected workspace — a case-insensitive search returned two hits, both inside base64 image data in unrelated files. It istherefore not drawn, and the event-driven work shown here is the work the repositories actually contain.ROLEEvent / transportAI / MLPersistenceVerification / trustOperator / APIFailure path
19The topic inventory, plus the four delivery properties that were designed rather than inherited. Open the SVG

What I built, extended and integrated

Commit shares are from git shortlog on 2026-09-12. A commit count is evidence of weight, not of line ownership, so every specific claim names a file or a commit.

CONTRIBUTION MAPWhat I built, what I contributed to, and what I did notFive classes, applied to all 20 inspected repositories. Commit share is evidence of weight, not of authorship — where the two disagree, the reason is stated and the conservative classwins.Mohd Zamin QuadriAI Engineer · BP-ITCSTHE FIVE CLASSESPrimary implementationI wrote the service and its design docs; majority ofcommitsSignificant contributionnamed features in a service someone else built, orthat I startedIntegration / sharedwired, configured or contributed to; not mine toclaimExisting platformbuilt by colleagues or third parties; my work dependson itExternal / upstreamoutside the system entirelyEVERY REPOSITORY, CLASSIFIEDREPOSITORYMY COMMITSCLASSWHAT THE CLASS RESTS ONknowledge-db-ingestion-preprocessor466 / 498Primarytwo parsers, 14 gates, oracle, prover, provenance, 84 migrationslegal-kb-dashboard144 / 167Primary7 pages, 27 components, 9 route handlers, the four-axis TrustPanellegal-kb-health-service123 / 148Primary23 routes, completion consumer, reconciliation, withdrawal orchestratorknowledge-db-ingestion-loader77 / 94PrimaryBGE-M3 embedding, hybrid retrieval, dual-store convergence fenceslocal-env63 / 113Significantthe whole legal-knowledge-database profile, WAL archiving, object lockentity-producer46 / 116SignificantEU/CELLAR Claim-Check ingestion, broker-confirmed publish, law-identity keyingdocument-extractor27 / 63Significantdual LLM+regex extraction, multi-format input, mojibake detectionai-utils17 / 61SignificantzipHash on BinaryAttachment, consumer commit(), configurable poll intervalai-prediction-service14 / 51SignificantGrad-CAM++ analyser, DenseNetV2 integration, calibrated severity thresholdsarchitecture10 / 13Significantarc42 documentation, ADR-003 and ADR-004indexing-service9 / 30SignificantI created the service; others continued it. Commit share understates it.ai-contract-data7 / 9SignificantVVG-compliant synthetic document set + generator. Data, not a service.glaux-ui5 / 243Integration / sharedminor changes onlyentity-handler5 / 46Integration / sharedminor changes onlyutils5 / 109Integration / sharedminor changes onlyentity-reader1 / 47Existing platformconsumed for templatesentity-ui-handler1 / 29Existing platformnot my workrag-service0 / 56Existing platformzero commits. Reads what my upstream services produce.parent0 / 43Existing platformshared Maven parentbase-images0 / 10Existing platformshared container basesWHAT THAT WORK ACTUALLY WASVerification / reliability14 gates across fidelity, citations, store equality and currencyA structural oracle on a different XML stack, importing no parser codeA prover that proves itself first or issues no verdict at allRuleset provenance digests over raw bytes, per source familyPre-flight blocking before ingestion rather than review after itData architecture~35 tables, 9 views, 84 migrations across four separated concernsOne writer per store, enforced by deleting the path that violated itDerived identity that makes redelivery idempotent with no 2PCExact count fences on both derived storesObject-locked evidence storage and WAL archivingAI & document intelligenceBGE-M3 dense + sparse; refuse the law rather than truncateHybrid retrieval with server-side RRF fusionGerman GII-NORM and EU FORMEX v4 parsersCitation extraction to provision-level identity tuplesTemplate-driven field extraction hardened against real documentsEvent-driven & operationsA three-topic contract with two distinct completion boundariesEU/CELLAR ingestion via the Claim-Check patternBroker-confirmed publication before HTTP successFour operator actions, each with real error and outcome states46 assurance and operational tools; a diagram standard across 5 reposWHAT I DID NOT BUILDNot mine, and stated so wherever this system is described: the Java entity platform, the RAG service (zero commits), the Glaux UI, the legal chatbot, and every third-party store. No production deployment is claimed — only Docker Compose stacks and CI image builds are evidenced. No business impact metric isclaimed, because none exists in any repository.The single sentence: I implemented four of the five services in the Legal Knowledge Database — the system that turns published German and EU law into verifiable machine-readable knowledge, where every store has exactly one writer and the system refuses to certify a law it cannot independently reproducefrom the publisher's own bytes.AUTHORSHIPPrimary implementationSignificant contributionIntegration / sharedExisting platformExternal / upstream
20Grouped by engineering responsibility, with an explicit list of what I did not build. Open the SVG

The four-level authorship encoding is consistent across every diagram here: a 2px accent border and a filled corner marker for what I implemented, a thinner border and a hollow marker for what I extended, a hairline for existing platform components, and a dashed hairline for external systems. Use the authorship control in the header to dim everything that is not primary work.

Five problems worth describing

Derived from commits, audit records and code comments. Each one has a constraint, a decision, a trade-off, and a consequence that was actually observed.

A verification gate that was wrong in a way counting could not reveal

Problem. ZPO passed fidelity.source_substructure cleanly and became the validation specimen for the evidence gates. BGB then reported every structural path three times.

Constraint. The gate had to hold for any German law, and a per-law exception would make the corpus unprovable as a whole: a rule that fires for one key cannot be validated by any other law's evidence.

Decision. Treat it as a defect in the gate, not in the data. ZPO's active version happens to carry a single evidence document; BGB carries three — one current and two superseded — and the gate pooled them.

Trade-off. Fixing the gate invalidated the confidence ZPO's pass had bought, and the rule became: audit each law's own structure read-only before re-ingesting it, and treat a count that matches another law's as a coincidence to verify rather than a baseline.

Consequence. Only running the gate against a second law exposed it. One specimen is not a test suite.

Import sorting invalidated the provenance of the whole corpus

Problem. A lint pass sorted the imports in three files. parser_rule_sha256 moved from 38eb6f833d0ab5ab to b36ddd87ed592417, with no behaviour change at all, and every stored generation's recorded ruleset stopped matching the installed one.

Constraint. The digest has to be exact to be worth anything. A provenance mechanism that tolerates “harmless” edits cannot tell you whether a stored law still reproduces.

Decision. Keep the digest byte-exact and disable I001 for those three files, recording why in pyproject.toml.

Trade-off. Three files are now exempt from a project-wide lint rule, which is a real inconsistency, accepted because the alternative weakens the only mechanism that can detect rule drift.

Consequence. The registry is part of the rule set too. A code comment records the reason: adding one long form moved eight citations in the AktG work.

Two stores, one snapshot, no distributed transaction

Problem. A law's vectors and its graph have to agree with canonical PostgreSQL, and Kafka can redeliver any message at any time.

Constraint. No distributed transaction across a relational store, a vector store and a graph store — the operational cost is not worth paying for a corpus that is re-derivable.

Decision. Make every derived identifier a pure function of PostgreSQL content, read the law from one REPEATABLE READ snapshot, converge each store in a deliberate order, and fence each on an exact count before publishing completion.

Trade-off. A real window exists between the canonical commit and the projection fences where the stores disagree. It is short, it is reported honestly by reconciliation as DRIFT_DETECTED, and nothing serves a partial law while it is open.

Consequence. Redelivery became a non-event, which is what made the absence of automatic retry survivable.

An endpoint that documented a measurement no code performed

Problem. The health service's validation endpoints returned a job with status="completed" and the note “Live health check completed against actual corpus stores”. The handler queried nothing.

Constraint. At the time there was no way for that service to invoke the gates, which live in the preprocessor.

Decision. Delete the four endpoints and write down, in the API reference, that the documentation had asserted a measurement no implementation performed.

Trade-off. A visible capability was removed rather than quietly left in place, which looks like regression until you read why.

Consequence. POST /laws/{key}/verify replaced them once the gates could actually be invoked. A green result from a check that never ran is worse than no check.

The running container was not the repository

Problem. Withdrawal was complete in the repository, the docs and the tests — and un-exercisable against the running stack for every law. The overlay images are built once and not rebuilt when files change, so the preprocessor was missing a module entirely and the loader still served the pre-rename route.

Constraint. An absent route returns 404, and the health service maps a 404 from the canonical step to NOT_FOUND — “no such law”. The symptom therefore reads as a data problem about the law you named.

Decision. Verify the running image rather than the repo: diff the container's files, or read the live route table from /openapi.json, before concluding a feature works or is broken.

Trade-off. Rebuild discipline is now a written ADR and a boot-time check rather than a habit.

Consequence. The misdirection cost more than the bug. What is running is not automatically what is written.

What I would keep, and what I would change

Keep

  • One writer per store. It turns “which service made this row wrong?” into a question with exactly one answer.
  • Derive identity, never generate it. Idempotency for free, across stores, with no coordination.
  • Separate the observer from the judge. The health service records what the publisher served; the preprocessor's gate decides what that means. Neither can quietly do the other's job.
  • Refuse rather than approximate. Blocking a law with unrecognised structure, and refusing a law whose chunks would truncate, both cost throughput and both prevent a silent corruption.
  • Keep four trust answers apart. One green badge would hide which question failed.
  • Write the limitations into the artefact. Every diagram in the source repositories states what it cannot promise.

Change

  • Add a dead-letter path to the legal pipeline. Today a permanently unprocessable law is redelivered for ever and blocks its partition. The document pipeline already has one.
  • Make the checker version impossible to forget. It failed to move once when a gate's semantics changed, so verdicts either side of that change are indistinguishable. Derive it from the gate implementations rather than maintaining it by hand.
  • Content-address the captures. Immutable by key is not immutable by policy: identical bytes submitted twice produce two objects, and an orphaned capture is possible because MinIO is written before Kafka.
  • Generate the gate list once. Three hand-maintained copies exist downstream; that is recorded as a known defect and it is the cause of the doc-versus-code drift found during this audit.
  • Build the FORMEX assurance contract. EU acts parse, ingest and are queryable, and none can be certified, because the pre-flight detectors are GII-shaped.
  • Re-own canonical deletion. A flag-gated purge path still contradicts the single-writer rule. It is recorded as debt rather than resolved by weakening the rule.

Longer form, with context and alternatives for each: ARCHITECTURE_DECISIONS.md.

How this was assembled, and what it does not claim

Twenty repositories were read before anything was drawn. Every claim on this site is traceable to a file, and the ones that are not are labelled as unverified rather than smoothed over.

Verified in code

  • Service names, ports, topics, routes, gate identifiers, table and view names, collection and bucket names — all read from source or configuration.
  • Store ownership, count fences, identity derivation, delivery ordering — read from the implementations.
  • Commit shares — git shortlog -sne per repository.
  • Corpus counts — the registry file and the generated certification ledger.

Not claimed

  • No GDMS Rule Mapper. Asked for in the brief; no repository, topic, consumer, class, configuration or document for it exists anywhere in the workspace. Not drawn.
  • No production deployment. Only Docker Compose stacks and CI image builds are evidenced. “Production-oriented” is the accurate word.
  • No PaddleOCR, no DeepSeek-OCR, no Redis. None appears in any dependency, configuration or source file.
  • No business impact metrics. None exists in any repository, so none is stated.
  • No agentic RAG graph. A ten-node design exists in the architecture material; langgraph is commented out and the retrieval package is empty. Labelled design throughout.

Inconsistencies found between documentation and code

  1. The health service's API reference states there is no delete endpoint. The route exists at app/api.py:585, implemented by app/withdrawal.py, and is documented correctly in the architecture doc. The route was removed and later reintroduced; that section was not updated. This site follows the code.
  2. The preprocessor README states 31 German laws and 51 in total. The registry holds 32 and 52 — DDG was added on 2026-09-03.
  3. The gate reference marks seven gates as EU-applicable, while families/formex.py implements four of the ones it excludes. The same file states checker version :9 where the code says :10. Its own header names the cause: three hand-maintained copies of the gate list exist downstream.

The method and the headline findings are in evidence-summary.md. The full trail — ten documents naming exact file paths, per-repository authorship and three documentation-versus-code discrepancies — is held privately and available on request. No credential, internal hostname, endpoint or client document appears anywhere in this published package.