CivicRecords AI v1.2.0
CivicRecords AI v1.2.0
Released 2026-04-23. Tagged at commit cc06abc. CI green on all three required jobs (Frontend, Backend, T2C bootstrap-failure smoke) on the release-prep chain 0b404c4 → 673e140 → cc06abc. 617 backend pytest + 36 frontend vitest all passing.
About this release
CivicRecords AI is an open-source, locally-hosted AI system for municipal open-records request processing. Every deployment is a sovereign instance owned by the city — no cloud, no telemetry, no outbound data transfer.
Windows installer is UNSIGNED by design. On first run, Windows SmartScreen will show "Windows protected your PC — Unknown publisher." To proceed: click More info → Run anyway, then confirm UAC. See installer/windows/README.md for the full walkthrough.
Headline: ENG-001 CLOSED
Both halves of the connector-credentials exposure gap are now shut:
- T2B runtime (earlier sprint) —
connection_configredacted fromGET /datasources/viaDataSourceRead; admin-onlyDataSourceAdminReadon write endpoints. - Tier 6 at-rest (this release) —
data_sources.connection_configJSONB is now stored as a versioned Fernet envelope ({"v":1,"ct":"<fernet-token>"}, AES-128-CBC + HMAC-SHA256) via a transparent SQLAlchemyEncryptedJSONBTypeDecorator.pg_dumpoutput, restored backups, and DB-superuser sessions see ciphertext only. Runtime callers still see a plain dict — zero API / admin-UI surface change.
Operator breaking change: ENCRYPTION_KEY env var is now required at startup. The installer auto-generates a Fernet key on fresh installs and prints a loud "BACK IT UP SEPARATELY FROM YOUR DATABASE" banner. Existing deployments need:
ENCRYPTION_KEY=$(python -c 'import base64,os; print(base64.urlsafe_b64encode(os.urandom(32)).decode())')
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY" >> .envThen back the key up. Losing it means losing decryption access to every connector's credentials. Key rotation is not supported in v1.2.0 and is tracked as a future slice; the "v":1 envelope tag leaves the door open.
Tier 5 — complete
Five slices shipped 2026-04-22 → 2026-04-23 and tagged in this release:
- T5A — Onboarding persistence. The single-phase adaptive interview now actually persists each answer onto the
CityProfilesingleton (creating the row on the first answer), normalizes yes/no forhas_dedicated_it, and transitionsonboarding_status(not_started→in_progress→complete). Skip advances the walk truthfully. Migration018_city_profile_state_nullable.py. - T5B — First-boot baseline seeding.
app/main.lifespanauto-seeds 175 state-scoped exemption rules across 51 jurisdictions, 5 compliance templates, and 12 notification templates. Idempotent via skip-if-exists — admin customizations survive re-seed. Every run emitscreated/skippedcounts. - T5C — 4-model Gemma 4 installer picker.
gemma4:e4bdefault. Fake tags (gemma4:12b,gemma4:27b) purged repo-wide.gemma4:26b/gemma4:31bselectable with explicit "requires stronger hardware" acknowledgment against the locked 32 GB target profile. - T5D — Install-time portal switch. New
PORTAL_MODEenv var (privatedefault,publicopt-in). Private mode keeps the deployment staff-only — login screen is the only externally reachable page. Public mode exposes exactly three surfaces: public landing page, resident-registration path, and authenticated records-request submission form forUserRole.PUBLIC. Anonymous submission, published-records search, resident dashboard, and track-my-request remain out of scope. Also fixes a pre-existing bug whereUserCreatesilently forced self-registrants toUserRole.STAFF. - T5E — Windows unsigned double-click installer. Real
.exebuilt with Inno Setup 6.x viachoco install innosetup -y+installer/windows/build-installer.shonwindows-latest. Start-vs-Install shortcut flow split (Start CivicRecords AI= dailydocker compose up -d;Install or Repair CivicRecords AI= full bootstrap + picker + model pull). Tag-derived version sourcing — no hardcoded drift.
Also in v1.2.0 (pre-release unreleased work folded in)
- April 14 accessibility Sessions A/B/B.1/B.2/C — global
:focus-visiblefallback + Geist Variable font,ring-[3px]focus on Button/Input/SelectTrigger,data-tablekeyboard row activation, 15 SelectTriggeraria-labels,LoadingRegionwithrole="status", CardTitleasprop, 7<h2>in RequestDetail, dialog focus trap verified. - April 19–21 security remediation T2A–T3D — CI ratchet (GitHub Actions, collected-vs-passed cross-check, bootstrap-failure smoke test); 24 dept-scoped handlers enforce
require_department_scope; 404/403 info-leak unified; Pattern D list fail-open closed; review_fee_waiver gap fixed; T2Bconnection_configredaction (runtime half of ENG-001); T2CFIRST_ADMIN_PASSWORDstartup validator + SSRF host validator; T3A admin-create path fix; T3D OpenAPI typegen + stale-check gate. - April 21–22 T4A/B/C — responsive AppShell with mobile drawer; Dashboard/Settings service-health truth fix; Add-Source wizard accessibility + validation; Button
forwardRefmigration; UX-001 radiogroup keyboard handler; QA-001 Settings-page hallucinated-rows removal.
Release-pipeline corrections during the cut
Two release-path corrections landed on top of the initial chore(release): cut v1.2.0 commit. Both are build-pipeline only — zero product behaviour change, no T5E scope reopen:
673e140— unbreakbuild-installer.shon windows-latest. Git Bash / MSYS2 was splitting/DMyAppVersion=…into two args before handing off to ISCC; fix pre-converts the.isspath withcygpath -wand setsMSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*'for the single ISCC invocation.cc06abc— unbreak artifact handoff between the build job and the create-release job.actions/upload-artifact@v7preserves thebuild/prefix relative toGITHUB_WORKSPACE, so the upload step was globbing the wrong directory; fix locates viafindand emits an actionable error if nothing matches.
Downloads
- Windows (double-click installer):
CivicRecordsAI-1.2.0-Setup.exe— attached below, with matching.sha256. Verify on the operator machine withGet-FileHash .\CivicRecordsAI-1.2.0-Setup.exe -Algorithm SHA256and compare against the checksum file. - Linux / macOS (guided script): clone the repo at
v1.2.0and run./install.sh. Prerequisites and step-by-step walkthrough: README.md and USER-MANUAL.md. Cross-platform native installer parity is explicit follow-on, not shipped here.
Docs
Not shipped (explicit scope discipline)
- No key rotation / MultiFernet / KMS / HSM / Vault integration. One key per deployment for v1.2.0.
- No signed Windows installer. Unsigned by design per the Scott-locked T5E signing posture α.
- No native macOS / Linux installer.
- No public portal expansion beyond T5D's three minimal surfaces (landing + resident-registration + authenticated submission).
- No anonymous walk-up submission.