The problem

Construction submittal review compares a vendor cut sheet against a project specification. A mismatch can be costly, and a model-generated finding is not useful unless its evidence can be checked.

What SpecGuard does

SpecGuard audits one specification PDF and one submitted cut-sheet PDF. A Google ADK agent on Gemini 3.7 Flash proposes structured discrepancy claims. Each claim must carry a quote and page locator from both documents. A deterministic gate then verifies that the quoted characters occur on their cited pages before a finding can reach the Firestore ledger.

The gate is intentionally narrow: it proves cited text occurs on the cited page. It does not prove a discrepancy is correct, detect every PDF concealment technique, or make SHA-256 an accuracy mechanism.

Before model input, a deterministic text-layer integrity screen quarantines PDFs whose extracted text may not match their visible page. Rejected claims receive one bounded retry; verified findings are persisted, and the runtime drafts a page-cited RFI. Severity is an advisory Gemma integration; the current deployed revision records the disabled-endpoint fallback rather than inventing a label.

Measured results

All numbers come from EVAL.md in the repository: 100 real audits on 2026-08-25 (five document pairs, ten iterations, both agent modes), with every model-initiated tool call committed to EVAL-RECEIPTS.jsonl.

  • Original lane, both modes: 100% catch on both planted discrepancies, 0 false positives on the compliant cut sheet, and 100% quarantine of the altered fixture with zero model turns.
  • Messy lane (a 32-page specification against a 10-page two-product package with seven planted discrepancies and two compliant decoys): navigate mode caught 90% against full text's 86%, with zero decoy hits and zero invented findings in either mode. One planted case carries the whole gap between modes.
  • Across the 80 runs that reached the model, the gate rejected nothing: every quote was cited correctly on the first turn. The retry loop was therefore not exercised in this campaign; it is proven separately by tests that drive rejections deterministically, and EVAL.md says so rather than letting a clean table imply more.
  • 16 adversarial attempts to write around the ledger invariant, all refused (tests/adversarial/).
  • Two hand-run mutations of the gate, both caught by the offline suite of 680 tests, which needs no network or credentials; README records that count from its own run.
  • Live service: model step to persisted finding in 10.7 s and 12.2 s on a warm revision.

How it is built

SpecGuard uses Python, Google ADK, Gemini 3.7 Flash via Vertex AI, Cloud Run, Firestore, Cloud Storage, Secret Manager, FastAPI, PyMuPDF, and an offline pytest suite. The source repository includes fictional PDF fixtures, reproducible setup, an architecture diagram, a committed evaluation record, and per-call receipts for the published 100-audit campaign. The deployed revision reports its source Git commit in the /health response, so a reader can match the running service to the exact repository head.

The deployed sample service provides four public fictional sample audits and a deterministic gate playground. Arbitrary upload audits remain passphrase-gated to protect the demo budget.

Built With

  • cloud-run
  • cloud-storage
  • fastapi
  • firestore
  • gemini-3.7-flash
  • gemma-3-1b
  • google-adk-2.7.1
  • pydantic
  • pymupdf
  • pytest
  • python-3.12
  • ruff
  • secret-manager
  • uv
  • vertex-ai
Share this project:

Updates

Submission history