Files
Conflict_Checker/NOTES.md
T
woogiandCursor a6b0c8fdfa
Docker Release / build-and-push (push) Successful in 1m27s
Docker Release / release (push) Skipped
Add per-job run logs and separate vision/text model selection.
Capture pipeline stdout into job.log + API/UI so failed runs can be reviewed, and let users pick OpenRouter vision vs text models independently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 14:56:48 -05:00

6.4 KiB
Raw Blame History

Session Notes — Conflict Checker

Orientation for a new coding session. Setup and Docker details live in README.md. This file tracks what the code actually does and what tends to waste time.

What this is

Cross-discipline design contradiction / senior-architect QAQC for construction drawing PDFs (Arch, Struct, Mech, Elec, Plumb, FP, etc.). Flags disagreements between disciplines before a set goes to bid/permit.

Not IronBids scope-ownership conflict checker.

Source of truth: Scout IT Gitea — gitea.scoutitsystems.com/woogi/Conflict_Checker.

Stack

Layer Detail
API Python 3.12, FastAPI, Uvicorn (backend/main.py)
UI Single static file frontend/index.html, served by FastAPI
Pipeline Shared by web + CLI: backend/pipeline/runner.py
LLM OpenRouter via openai SDK; default google/gemini-2.5-pro. Vision always OpenRouter; text stages can use local vLLM
PDF pdf2image + system poppler-utils → JPEG page images
Jobs In-memory threads (backend/jobs.py) — no Redis/DB
Deploy Docker Compose; app on port 8099

Live pipeline (authoritative)

README still describes an older 5-stage extract-then-compare loop. Trust runner.py. Actual flow:

PDF → images → extract → sheet index → jurisdiction
    → normalize → project intelligence (GOIDs)
    → cluster → conflict reason
    → QAQC / code / constructability
    → dedup-validate → risk → RFIs → report
Runner stage Module Notes
PDF → images pdf_processor Rasterize
Extract assertions extractor Vision, per sheet
Classify sheet index sheet_index LLM
Jurisdiction profile jurisdiction After cover meta
Normalize normalizer LLM batches
Project intelligence normalizer.build_project_intelligence GOIDs + relationships
Cluster llm_clusterer or clusterer Default CLUSTERER=llm
Conflicts conflict_checker Per-cluster vision reason
QAQC / code / constructability qaqc_review, code_review, constructability Full-set / batched
Validate & dedup validator Merges conflict + QAQC + code + construct issues
Risk / RFIs risk, rfi Text-only
Report report conflicts.json + report.md (+ stage JSON dumps when out_dir set)

Design notes for Stage 2/3 engines also live under Changes/*.docx.

Where to change what

Concern File
Prompts, vocab, conflict taxonomy backend/prompts.py
Env knobs backend/config.py, backend/.env.example
HTTP API backend/main.py/health, /models, /check, /jobs/{id}, /jobs/{id}/log, /jobs/{id}/sheet-image/{page}
CLI tuning loop cli/run_check.py
LLM client, cache, cost, per-run model overrides backend/llm.py
OpenRouter vision/text model lists backend/models_catalog.py
Job registry + stdout tee log backend/jobs.py, backend/job_log.py
Stage helpers (prompt render, issue validate) backend/pipeline/_stage.py
Code text corpus (Stage 7) backend/code_corpus/
Hybrid local LLM helper scripts/setup_vllm.sh

Older prompt snapshot: backend/prompts.py.v1.

Gotchas

  1. Prompt placeholders — Use str.replace via _stage.render, never str.format. Prompts contain literal { JSON braces.
  2. Clustering — Default is LLM (CLUSTERER=llm); empty LLM result falls back to deterministic. Deterministic clusters need ≥2 disciplines (or schedule-vs-plan); single-discipline “missing” gaps are a known limit.
  3. Jobs are in-memory — Process restart clears job status; reports on disk under backend/outputs/<job_id>/ can still be reloaded via get_job disk fallback. Run logs persist as job.log in that same folder and via GET /jobs/{id}/log.
  4. Dependency pinhttpx==0.27.2 with openai==1.51.0. httpx ≥0.28 breaks openais proxies= kwarg.
  5. Code corpus licensing — Only ada_2010.txt is shipped. Do not paste IBC/IFC/IECC without a license (see backend/code_corpus/README.md).
  6. Dual assertion schema — Newer {sheet, objects[]} is mapped to legacy {assertions[]} with attribute/value for older stages.
  7. Grounding guard — Extractor drops objects whose numeric claims are not in source_text (graphical-only objects allowed).
  8. Cost counters — Module-global LLM cost accounting; overlapping jobs share counters. Same for stdout tee logging and per-run model overrides.
  9. Samplessamples/*.pdf are gitignored; drop PDFs locally for CLI runs.
  10. README drift — Treat README for setup/CI; treat this file + runner.py for pipeline truth. prompts.py header may still say some prompts are unwired — they are wired through the runner.
  11. Two models — Vision (MODEL, image stages) and text (TEXT_MODEL, non-image). UI exposes separate dropdowns from OpenRouters /models (cached ~1h). Hybrid still runs vision on OpenRouter; text dropdown also covers local name override + cloud fallback.
  12. Job log — Pipeline print() output is teed into memory + outputs/<job_id>/job.log. Status polls include log_tail; completed/error jobs include full log.

Quick start pointers

  • Full setup: README.md (docker compose up -d --buildhttp://localhost:8099).
  • Local CLI: python cli/run_check.py samples/your_set.pdf --out out/your_set.
  • Prompt iteration: set LLM_CACHE=true in backend/.env so unchanged stages replay for free; clear with rm -rf backend/.llm_cache.
  • Artifacts: assertions.json, clusters.json, per-stage JSON, conflicts.json, report.md under the chosen out_dir or backend/outputs/.
  • No automated test suite; validate via CLI dumps and golden-set diffs (described in README).

Conflict categories (taxonomy)

Defined in backend/prompts.py: dimensional_disagreement, elevation_disagreement, location_mismatch, missing_element, schedule_vs_plan_mismatch, detail_vs_plan_mismatch, tag_or_reference_inconsistency, spatial_clash, note_or_spec_contradiction.