BuildCalc API

Changelog

Notable changes shipped to BuildCalc API. Mirrors CHANGELOG.md in the repo.

Format: Keep a Changelog. Versioning: Semantic Versioning.

Unreleased

(no changes yet)

0.4.0 — 2026-05-29

Audit-batch release. Closes audit-2/audit-5/audit-7 P0+P1 across security posture, MCP discoverability, and marketing surface drift. Stripe wired to LIVE-mode prices (chain completion); R2 backup pipeline added.

Highlights

  • Added: Browser-security headers middleware (app/middleware/security_headers.py) — HSTS (2-year max-age + includeSubDomains + preload), CSP (default-src 'none'; frame-ancestors 'none'), X-Content-Type-Options, X-Frame-Options DENY, Referrer-Policy, and a Permissions-Policy that disables every powerful browser feature. Production was previously emitting zero browser-security headers.

  • Added: IP-throttle on POST /v1/account/setup-intent (cap = 5 requests / 10 min per IP) — anonymous endpoint that creates real Stripe SetupIntents had no rate limit, Turnstile, or auth.

  • Added: data:products tag exposed to MCP (app/mcp/server.py) — 6 product endpoints + 40,700+ certified SKUs across 9 categories are now discoverable to MCP clients. Tool surface grew 97 → ~105.

  • Added: BodySizeLimitMiddleware (app/middleware/body_size_limit.py) — 1 MB default cap on POST/PUT/PATCH body via Content-Length advisory. Returns 413 with RFC 7807 envelope + Retry-After: 0 + X-Body-Limit headers.

  • Added: R2 backup script (scripts/backup_to_r2.py) — nightly Postgres dump + upload to Cloudflare R2 with 30-day retention.

  • Changed: MCP operation_id naming convention — codes vertical renamed to match the <vertical>_<verb> pattern already used by costs, benchmarks, and products:

    • list_codescodes_list
    • get_codecodes_get
    • list_code_sectionscodes_list_sections
    • get_code_sectioncodes_get_section
    • get_jurisdiction_applicable_codescodes_jurisdiction_applicable

    REST clients are unaffected (paths and methods unchanged). MCP clients re-discover tools via tools/list each session.

  • Changed: Stripe wired end-to-end on LIVE-mode prices. Customer Portal + metered overage + webhook signature verification all validated on real cards.

  • Fixed: DetachedInstanceError on APIKey ORM access from the usage-metering middleware — caused ~2 observability events/day. Middleware now uses a plain int stamped on request.state.api_key_id instead of the ORM instance.

  • Fixed: 3 Render cron services that had no startCommand and never produced a single job since creation (buildcalc-api-overage-processor hourly, bcapi-etl-bls-qcew quarterly, buildcalc-api-adoption-scraper quarterly). PATCHed via Render API; first-ever overage job ran 2026-05-29 01:58Z.

  • Fixed: CI pipeline was 100% red over the past 20 runs — pgpartman Docker image rename + setuptools < 81 pin for semgrep transitive + mypy advisory pass.

  • Fixed: Marketing surface drift sweep — calculator count (79 → 81), MCP tool count (95+ → ~105), Free tier quota (10k → 1k), status link (BetterStack → Instatus), and v0.4.0 propagated to llms.txt, agents.md, index.html, pricing.html, signup.html, dashboard.html, 404.html. Single source of truth: 81 calculators / 16 categories / 937 code sections / ~105 MCP tools / 40,723 SKUs / 1,000 calls/mo free / 9 product categories.

Operational

  • Postmortem: auth-wedge incident (docs/postmortems/2026-05-29-auth-wedge.md) documents the brief prod outage during the security-headers middleware rollout and the recovery procedure.

0.3.1 — 2026-05-21

Post-v0.3.0 polish + audit follow-up release. 40+ findings closed across 6 audit batches. Critical fix for stuck docs-site deploy (MDX parse error blocked CF Pages since 2026-05-19). Test suite grew from 484 → 552 passing.

Highlights

  • Fixed: docs site deploy unblocked — benchmarks.mdx:18 had (<250k) outside backticks; MDX 3.x parsed it as invalid JSX tag.
  • Added: live HTTP fetchers replace NotImplementedError stubs for Census C30/BCC/BPS + HUD SOC + EIA RECS (with SSRF allowlist + 200 MB fetch cap).
  • Added: MCP server exposes data:costs + data:benchmarks tags (~97 tools total across 4 verticals).
  • Added: docs/adr/0017-pyjwt-pysec-2025-183-accepted-risk.md + ADR-0015 stub + .github/CODEOWNERS.
  • Added: SDK Python databenchmarks/ module + TypeScript DataBenchmarksService.ts; docs/openapi.json snapshot refreshed (111 paths, 179 schemas).
  • Changed: CORS narrowed from * to explicit allowlist (apex + www + docs); SHA-pinned peter-evans/create-pull-request.
  • Changed: Phase 8 cron orchestrator replaced no-op stub with real per-source fetch + retry + idempotent upsert pipeline.
  • Changed: docs overview moved costs + benchmarks from "Coming" to "Live today"; products remains coming (gated LLC).
  • Changed: MCP tool count propagated "95+" across marketing landing + pricing + quickstart (was "85+").
  • Tests: 552 passing / 69 skipped (up from 484); 13 HTTP integration tests for /v1/benchmarks/*, 5 SDK round-trip tests, 6 fetcher unit tests.
  • Documentation: 4 broken GitHub private-repo links fixed (ADR-0014, topic_tags, CHANGELOG); cpiunc URL typo → cpi (2 locations); methodology pages expanded.

See repo CHANGELOG.md for full per-batch detail.

0.3.0 — 2026-05-20

Phase 8 benchmarks vertical SHIPPED. All 15 standardized US residential construction project-type benchmark orchestrators wired with 5-geography output (national + msa_large + msa_medium + msa_small + rural) from federal data (Census C30 + BPS + BCC + BLS OEWS + EIA RECS + HUD SOC). 137 unit tests passing.

Auto-generated Python + TypeScript SDKs also live in sdks/ directory (publishing to PyPI + npm deferred until NF Nation LLC formation).

Phase 7 products vertical paused on LLC formation (USCO DMCA safe-harbor needed for ICC-ES integration).

Added (Phase 8 sub-dels 3 + 4a + 4b + 5)

  • All remaining 14 project-type compute orchestrators: kitchen+bath remodels (4 types), exterior envelope (roof/siding/window/painting), interior systems (flooring/HVAC via EIA RECS/electrical panel), and additions (deck/garage/basement). Shared _compute_remodel_or_replacement() helper applies the standard 5-geography pattern with hand-set labor_pct/materials_pct splits per project type.
  • 98 parametrized unit tests (7 dimensions × 14 project types).
  • Total Phase 8 tests: 137/137 passing.

Added (Phase 8 sub-del 1)

  • Benchmarks vertical — infrastructure shipped. All 15 project types live in /v1/benchmarks/list with status="coming_soon" until per-project sub-dels populate data. 4 endpoint skeletons, 2-table schema with GIN index on trade_dependencies, 3 seed JSONs (methodology + scope_norms + msa_tiers; first methodology snapshot versioned for audit reproducibility), ETL framework with 3 core functions, ADR-0016 published, methodology page placeholder live. 4-level confidence taxonomy (measured / derived / derived_industry_method / interpolated) matches Phase 6 spirit.

Added

  • Auto-generated SDKs — Python (buildcalcapi) and TypeScript (@buildcalcapi/sdk) clients live under sdks/{python,typescript}/ of the repo. Generated from the committed docs/openapi.json snapshot via openapi-python-client + openapi-typescript-codegen. Cover all 107 endpoints across the live verticals (codes, calculators, costs).
  • Auto-regen GitHub Action — opens a PR with refreshed SDKs every time docs/openapi.json changes on main.

Deferred

  • PyPI + npm package publishing — held until NF Nation LLC is formed and owns the packages on the public registries. Until then SDKs install from source.

0.2.0 — 2026-05-19

Phase 6 costs vertical SHIPPED. Full federal-data labor + permits + materials coverage with 4-level confidence taxonomy.

Added

  • Costs vertical — county + ZIP labor paths live. Sub-deliverable 4 closes the labor endpoint with two new geographic paths. See Costs vertical for curl + response examples and Methodology for the formula + the 7 known limitations.
    • GET /v1/costs/labor?trade=&county={FIPS} — OEWS x QCEW geographic-scaled hourly wage estimate. Returns confidence from the 4-level taxonomy plus confidence_reason + methodology + inputs.* + paired_trades + all_trades_share_ratio + degenerate_msa + systematic_error_pct_range + bid_markup_factor_range + limitations_note + wage_vs_bid_note + sources + see_also. Full fallback chain: 5-digit NAICS county -> state-level -> parent NAICS 238 -> OEWS MSA direct.
    • GET /v1/costs/labor?trade=&zip={ZIP} — ZIP resolves to dominant county via HUD zip_county_crosswalk (max res_ratio), then treated as the county path. Response surfaces resolved_county_fips + resolved_msa_code.
    • GET /v1/costs/sources/qcew?area=&naics= — raw QCEW escape hatch.
  • Costs vertical — permits endpoint live. Census Building Permits Survey for ~3,100 US counties + ~930 CBSAs:
    • GET /v1/costs/permits?jurisdiction=US-XX-NNNNN or US-MSA-NNNNN — 4 structure-type breakouts (1u / 2u / 3-4u / 5+u) for buildings, units, and valuation.
    • GET /v1/costs/sources/permits/{jurisdiction_code} — raw escape hatch.
  • Methodology page at /docs/methodology/costs documents the OEWS x QCEW formula, 4-level confidence taxonomy, full fallback chain, and 7 known limitations (occupational composition, NAICS suppression bias, trade-pair coupling, dominant-county degeneracy, wage-vs-bid distinction, time-series misalignment, geographic completeness over precision).
  • 2 new Render crons for Phase 6 costs:
    • bcapi-etl-bls-qcew (quarterly) populates cost_labor_qcew + cost_labor_qcew_coverage from the BLS QCEW single-file CSV.
    • bcapi-etl-census-bps (monthly) populates cost_permits_bps from Census BPS county + CBSA monthly files.
  • openpyxl 3.1.* runtime dependency — required by the BLS OEWS XLSX parser. Adds ~1MB; no transitive vulnerabilities at pinning.
  • Costs vertical — labor endpoint (MSA path) live. BLS OEWS hourly wages for 11 construction trades across ~390 US MSAs. See the Costs vertical docs for full curl + response examples.
    • GET /v1/costs/labor?trade=&msa= — median + p25 + p75 hourly wage plus employment count for one (trade x MSA) cell. Returns confidence: "measured" (direct OEWS, no scaling).
    • GET /v1/costs/sources/oews?msa=&soc= — raw escape hatch returning integer-cents wages for one (MSA, SOC) cell.
  • Annual Render cron bcapi-etl-bls-oews runs app/etl/bls_oews.py on April 3 at 14:00 UTC after BLS's early-April release. Better Stack heartbeat with 7-day grace. Year-fallback tries current_year - 1 first.
  • Costs vertical — materials endpoint (PPI for 15 categories) live. Three new endpoints under /v1/costs/*. See the Costs vertical docs for full curl + response examples.
    • GET /v1/costs/list — dynamic per-vertical status (live / coming_soon) based on DB presence checks.
    • GET /v1/costs/materials?category=&period= — BLS Producer Price Index value + 12-month history for 15 construction categories. Multi-series categories (flooring / doors-windows / site) get equal-weight averaging.
    • GET /v1/costs/sources/ppi/{series_id} — raw escape hatch (24 trailing months of one BLS series).
  • Monthly Render cron bcapi-etl-bls-ppi runs app/etl/bls_ppi.py on day 16 at 14:00 UTC, after BLS's second-Thursday release. Better Stack heartbeat alerts on missed runs.
  • HUD USPS ZIP-CBSA crosswalk bootstrap (47k rows) prepping for the county / MSA labor and permits endpoints in subsequent sub-deliverables.
  • Codes vertical FTS integration tests + @pytest.mark.integration marker for the whole DB-touching subset of the test suite. Default pytest tests/ is now clean (325 passed / 48 skipped / 0 failed).
  • RequestIdMiddleware unit tests (6 new tests, 0 DB needed).
  • Public status page at buildcalc-api.betteruptime.com — Better Stack Uptime free tier monitors api / docs / landing + a heartbeat for the hourly overage cron.
  • Sitemap at docs.buildcalcapi.dev/sitemap.xml + crawl-permissive robots.txt (was still Disallow: / from staging hardening).
  • Custom 404 page on the marketing site with dark theme and next-step CTAs. CF Pages now returns HTTP 404 for unknown URLs.
  • metadataBase + root title template on the docs site — OG image refs are now absolute, social previews (Twitter / LinkedIn / Discord) no longer break.
  • /v1/openapi.json documented in the Quickstart with a note about the auth-gated schema and intentionally-disabled Swagger UI / ReDoc.
  • Account-management endpoints (/v1/account/{usage,api-keys}) now have full curl + sample-response docs — see Authentication → Account management.
  • NEC 2026 dual-edition seed (107 sections) — calc_links.py maps the Article 220 → 120 renumber. code_sections total: 937.
  • IRC stairs calculators (/v1/calc/stairs/*) accept optional irc_edition: "2021" | "2024" and return the citation in the requested edition's numbering.

Changed

  • ICC adoption scraper failures (URL break or 0 rows from the PDF) are now FATAL — the cron exits non-zero so a silent ICC outage no longer hides behind a green Render run.

0.1.0 — 2026-05-15

Initial production release. Public launch.

Added

  • 79 calculators across 16 categories (concrete, lumber, roofing, drywall, paint, flooring, HVAC, insulation, masonry, electrical, plumbing, doors-windows, gutters, stairs, site, misc). Every formula cites a US code section or manufacturer spec sheet.
  • Codes vertical — 830 hand-curated sections across IRC 2021/2024, IBC 2024, NEC 2023, IECC 2024, IPC 2024 + per-state adoption matrix for 49 states (codecheck.com NEC/IRC + ICC Master Chart Jan 2024 for IBC/IECC/IPC). See the Codes vertical docs.
  • MCP server at https://api.buildcalcapi.dev/mcp exposing all calculator + codes endpoints as auto-generated MCP tools (Streamable HTTP transport, MCP spec 2025-03-26). See the MCP integration docs.
  • Stripe metered billing — 4 tiers (Free 1k/mo · Starter $49 25k · Growth $249 250k · Enterprise custom from $1500). Hourly overage processor cron pushes usage records.
  • Programmatic signup at POST /v1/account/signup — supports both human flow (Cloudflare Turnstile + Stripe SetupIntent) and AI-agent flow (Stripe payment method on file, no challenge). See Authentication.
  • Mini-dashboard at buildcalcapi.dev/dashboard — self-service usage + key management + Stripe portal.
  • RFC 7807 problem+json error responses + Idempotency-Key support per IETF draft on mutating endpoints. See Errors.
  • Legal: Terms of Service (Common Paper CSA v2.1 + custom Cover Page) and Privacy Policy (hand-written, CCPA + multi-state).
  • GlitchTip error tracking (Cloud free tier, replaced Sentry 2026-05-31).

Not yet shipped

These verticals were originally scoped for v0.1.0 but are deferred to later milestones:

  • Costs vertical — BLS PPI/OEWS + HUD + Census derived indices.
  • Products vertical — ~6k SKUs across 10 categories with manufacturer spec attributes.
  • Benchmarks vertical — typical timelines + cost ranges across 15 project types.
  • Auto-generated SDKs (Python + TypeScript) — /v1/openapi.json is available auth-gated for SDK-generator tooling in the meantime.

On this page