ConstructionBot RFI automation for gal (renamed from engineerbot 2026-08-15)
  • Rust 90.5%
  • HTML 7.9%
  • Shell 0.6%
  • Dockerfile 0.4%
  • JavaScript 0.4%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-18 10:24:09 -07:00
assets feat: multi-RFI pipeline, vendor-tag assignees, unified pipeline UI 2026-08-21 16:11:39 -07:00
docs deploy: ditc automated deploy 2026-09-18 09:55:40 -07:00
migrations feat: multi-RFI pipeline, vendor-tag assignees, unified pipeline UI 2026-08-21 16:11:39 -07:00
scripts ci: pre-deploy quality gate — test, clippy, endpoint + port consistency (W8, I5, I6) 2026-08-14 23:31:05 -07:00
src feat: multi-RFI pipeline, vendor-tag assignees, unified pipeline UI 2026-08-21 16:11:39 -07:00
templates feat: multi-RFI pipeline, vendor-tag assignees, unified pipeline UI 2026-08-21 16:11:39 -07:00
tests feat: multi-RFI pipeline, vendor-tag assignees, unified pipeline UI 2026-08-21 16:11:39 -07:00
theme deploy: ditc automated deploy 2026-08-12 16:29:48 -07:00
.gitignore docs: merge constructionbot-docs repo into the code repo (29 files: constitution, probes, QA logs, plans, phase drafts, sample RFIs, brainstorm, voice-gallery, spec-registry, wishlist) 2026-08-18 12:19:34 -07:00
Cargo.lock rename: engineerbot -> constructionbot (crate, binary, image, domain, paths) 2026-08-14 20:43:51 -07:00
Cargo.toml rename: engineerbot -> constructionbot (crate, binary, image, domain, paths) 2026-08-14 20:43:51 -07:00
config.example.toml feat: format multi-question RFI bodies as bullet points (Jake demo request) 2026-08-21 20:15:53 -07:00
config.toml feat: format multi-question RFI bodies as bullet points (Jake demo request) 2026-08-21 20:15:53 -07:00
Containerfile fix: touch both src files to force app crate recompile after dummy build 2026-08-21 09:47:27 -07:00
ingress.yaml feat(security): forward-auth proof header validation — close W3 spoofing gap 2026-08-15 06:21:53 -07:00
input.css feat: dark mode (theme v2.1) 2026-08-21 09:35:30 -07:00
manifest.yaml fix(manifest): declare FORWARD_AUTH_SECRET — app fail-closes at boot without it; router proof env consumes it (#94 defect 3) 2026-09-15 20:40:50 -07:00
provenance.json deploy: ditc automated deploy 2026-09-18 10:24:09 -07:00
README.md fix(rename): ingress upstream 58402 + purge engineerbot leftovers (C1, I1, I2) 2026-08-14 22:10:49 -07:00
tailwind.config.js feat: dark mode (theme v2.1) 2026-08-21 09:35:30 -07:00

ConstructionBot

Procore RFI dashboard for the gal tenant. Phase 1 (Layer A): operator drafts RFIs, attaches vendor PDFs, submits to the Procore sandbox. Phase 3 (Layer B): sage-LLM extraction from uploaded RFI PDFs with a human review gate before any Procore write.

Architecture

  • Rust/axum + askama + htmx — single binary, tenant Postgres, tokio background tasks in-process.
  • No secrets in the repo — DATABASE_URL, Procore client credentials, and SAGE_API_KEY arrive via env vars (manifest dit.secrets, resolved on the runner from OpenBao). Non-secret config in config.toml.
  • Human gate — every RFI passes through operator review before Procore. The extraction pre-fills the form; the operator edits and submits.
  • sha256-keyed cache — same PDF → same cached extraction, zero double sage compute (phase3-draft AC-3).

Quick start (local dev)

export DATABASE_URL=postgres://constructionbot:pw@localhost:5432/constructionbot
export PROCORE_CLIENT_ID=...     # sandbox DMSA client id
export PROCORE_CLIENT_SECRET=... # sandbox DMSA client secret
export SAGE_API_KEY=...          # sage auth (B0 confirms requirement)

cargo run -- --check-config   # validate config.toml
cargo run                     # serve on :8080

Tests

cargo test --lib               # unit tests (offline, no DB needed)
cargo clippy --all-targets -- -D warnings   # lint (clean)
scripts/no_hardcoded_endpoints.sh           # endpoint gate

# Integration tests (need DB + pdftotext):
nix-shell -p poppler-utils --run \
  'DATABASE_URL=postgres://... cargo test --test extraction_cache -- --ignored --nocapture'

# Corpus worksheet (need DB + pdftotext + sage):
nix-shell -p poppler-utils --run \
  'DATABASE_URL=... SAGE_API_KEY=... cargo test --test extraction_corpus -- --ignored --nocapture'

Phase 3 calibration — pilot week

Procedure

After deploying Layer B, run the extraction corpus suite per prompt change and record per-file edit counts:

  1. Run the corpus suite with the current prompt:

    nix-shell -p poppler-utils --run \
      'DATABASE_URL=... SAGE_API_KEY=... cargo test --test extraction_corpus -- --ignored --nocapture'
    
  2. Review the worksheet — for each fixture, the suite prints:

    • subject, question, confidence, assignee hint, spec section, drawings
  3. Upload each fixture through the dashboard and click "Create RFI from extraction." Count how many fields you manually edited before submitting.

  4. Record edit counts in the table below.

  5. Iterate the prompt — edit extraction_system_prompt in config.toml, restart the container (ditc deploy), re-run the suite.

Calibration table

Fixture Prompt ID Subject edits Question edits Assignee edits Total edits Notes
rfi1_civil_conflicting
rfi2_foundation_conduits
rfi4_mat_slab_transition

Target (phase3-draft)

  • 80% of vendor RFI uploads yield an extraction where the operator can click "Create RFI" with ≤2 manual edits.
  • Below 50% = Phase 3 extraction is net-negative; evaluate PlanGrep pivot or drop the feature.

Prompt iteration (phase3-draft AC-5)

Edit extraction_system_prompt in config.toml and restart the container. Each prompt change gets a new prompt_id (short hash of the prompt text), stored per extraction row for attribution. The corpus suite prints the prompt_id so you can compare results across prompt versions.