diff --git a/.agent-runs/2026-05-21-civiczone-v1-public-use/active-control-state.md b/.agent-runs/2026-05-21-civiczone-v1-public-use/active-control-state.md new file mode 100644 index 0000000..8f43eaa --- /dev/null +++ b/.agent-runs/2026-05-21-civiczone-v1-public-use/active-control-state.md @@ -0,0 +1,25 @@ +# Active Control State + +Run: `2026-05-21-civiczone-v1-public-use` +Pipeline: `module-release` +Pipeline version: `agent-pipeline-codex v0.9.0` +Active module: `CivicZone` +Target: `v1.0.0 public-use module release` +Status: `IN_PROGRESS` + +## Current Rung + +Scope read and gap audit. + +## Stop Condition + +No valid stop condition is active. + +## Scope Boundary + +Implementation writes are limited to `C:\Users\scott\OneDrive\Desktop\Claude\civiczone`. +Minimum required suite-level installer/control-plane truth may be written under +`C:\Users\scott\OneDrive\Desktop\Claude\CivicSuite-clerk-core-city-release`. +Queue evidence may be written to `C:\Users\scott\OneDrive\Desktop\Claude\ACTIVE_RELEASE_QUEUE.md`. + +Queued module repos are read-only references. diff --git a/.agent-runs/2026-05-21-civiczone-v1-public-use/implementation-report.md b/.agent-runs/2026-05-21-civiczone-v1-public-use/implementation-report.md new file mode 100644 index 0000000..9421141 --- /dev/null +++ b/.agent-runs/2026-05-21-civiczone-v1-public-use/implementation-report.md @@ -0,0 +1,44 @@ +# CivicZone v1.0.0 Implementation Report + +**DoD readiness: READY** + +**DoD checklist: 18 total, 18 ready, 0 blocked, 0 deferred** + +## Scope + +Active release lock: CivicZone only. + +Implemented the source-repo v1.0.0 release candidate for CivicZone. Queued +module repos remained read-only. + +## Changes + +- Promoted CivicZone version truth to `1.0.0`. +- Aligned CivicCore dependency and GitHub workflows to the published + CivicCore `1.1.0` wheel. +- Rebuilt `/civiczone` as a browser-usable resident workflow surface with live + parcel lookup, cited Q&A, empty, error, and planner-review states. +- Added `/civiczone/staff` as a browser staff workflow shell for planner Q&A, + ambiguity review, analytics, and staff-report outline actions. +- Hardened staff API access with CivicCore trusted-header/proxy validation. +- Updated tests for version truth, CivicCore compatibility, public/staff UI, + staff role checks, and spoofed-header rejection from untrusted sources. +- Updated current-facing docs, QA evidence, careful-coding evidence, and + release-gate audit evidence. + +## Verification + +- `python -m pytest -q`: 71 passed, 3 warnings. +- `bash scripts/verify-docs.sh`: PASS. +- `python -m ruff check .`: PASS. +- `bash scripts/verify-release.sh`: PASS, built wheel, sdist, and SHA256SUMS. +- `git diff --check`: clean, CRLF warnings only. +- Browser QA: resident and staff desktop/mobile surfaces, loading/success/empty + /error/partial states, console checks, keyboard/focus, and layout evidence + saved under `docs/qa/`. + +## Remaining Release Mechanics + +The source repo release candidate is ready for branch, commit, push, PR, CI, +merge, tag/release, then CivicSuite installer/module-selection truth. The full +module Definition of Done is not complete until those follow-through gates pass. diff --git a/.agent-runs/2026-05-21-civiczone-v1-public-use/manifest.yaml b/.agent-runs/2026-05-21-civiczone-v1-public-use/manifest.yaml new file mode 100644 index 0000000..5d50466 --- /dev/null +++ b/.agent-runs/2026-05-21-civiczone-v1-public-use/manifest.yaml @@ -0,0 +1,22 @@ +run_id: "2026-05-21-civiczone-v1-public-use" +pipeline: "module-release" +pipeline_version: "agent-pipeline-codex v0.9.0" +goal: "Release CivicZone v1.0.0 as a public-use CivicSuite module with spec scope, UX QA, docs, tests, adversarial validation, installer/module-selection truth, PR/merge/tag/release, and CI evidence." +active_module: "CivicZone" +target_version: "1.0.0" +source_of_truth: + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\ACTIVE_RELEASE_QUEUE.md" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\CivicSuite-clerk-core-city-release\\docs\\CivicSuiteUnifiedSpec.md" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civiczone\\AGENTS.md" +acceptance: + - "CivicZone version truth is 1.0.0 across code, docs, tests, release verifier, artifacts, tag, and suite truth." + - "CivicZone implements the required CivicSuiteUnifiedSpec section 10 public/staff workflows without making zoning determinations." + - "Resident and staff routes have desktop/mobile browser QA, console, keyboard/focus, copy, and loading/success/empty/error/partial evidence." + - "Local tests, lint/static checks, docs checks, release verifier, build artifacts, and SHA256SUMS pass." + - "Adversarial local integration mocks cover bad inputs, stale/missing data, spoofed roles/providers, unavailable dependencies, air-gap boundaries, and public/staff permission boundaries." + - "Release-gate audit has no unresolved Blocker or Critical findings." + - "CivicSuite installer/module-selection truth includes CivicZone 1.0.0 and passes live main verification after merge." +platform_boundary: + linux: "full lifecycle evidence required where suite installer gates exercise lifecycle" + windows: "supported; archive/readiness and available matching-host evidence must be recorded honestly" + macos: "beta-level support unless a real matching-host lifecycle is proven; do not claim macOS lifecycle certification" diff --git a/.agent-runs/2026-05-21-civiczone-v1-public-use/run.log b/.agent-runs/2026-05-21-civiczone-v1-public-use/run.log new file mode 100644 index 0000000..cd15181 --- /dev/null +++ b/.agent-runs/2026-05-21-civiczone-v1-public-use/run.log @@ -0,0 +1,8 @@ +2026-05-21T12:00:00Z | START | CivicZone v1.0.0 module-release run created under agent-pipeline-codex v0.9.0 pattern. +2026-05-21T12:00:00Z | ACTIVE_LOCK | CivicZone only. Queued modules read-only. +2026-05-21T12:00:00Z | SCOPE | Scope read started from ACTIVE_RELEASE_QUEUE.md, CivicSuiteUnifiedSpec.md section 10, live GitHub main, and current CivicZone source. +2026-05-21T13:00:00Z | BASELINE | Initial pytest failed 1 test due CivicCore 1.1.0 runtime vs stale 1.0.1 expectation; docs and Ruff passed. +2026-05-21T13:30:00Z | EXECUTE | CivicZone source v1.0.0 release candidate implemented with public/staff browser surfaces and trusted staff auth. +2026-05-21T14:00:00Z | BROWSER_QA | Resident and staff desktop/mobile browser QA passed; console clean after favicon fix. +2026-05-21T14:15:00Z | VERIFY | scripts/verify-release.sh passed with 71 tests, docs gate, placeholder import gate, Ruff, build artifacts, and SHA256SUMS. +2026-05-21T14:20:00Z | AUDIT | Release-gate audit recorded with 0 unresolved Blocker/Critical findings for source repo release candidate. diff --git a/.agent-runs/2026-05-21-civiczone-v1-public-use/scope-lock.yaml b/.agent-runs/2026-05-21-civiczone-v1-public-use/scope-lock.yaml new file mode 100644 index 0000000..c031148 --- /dev/null +++ b/.agent-runs/2026-05-21-civiczone-v1-public-use/scope-lock.yaml @@ -0,0 +1,36 @@ +run_id: "2026-05-21-civiczone-v1-public-use" +active_module: "CivicZone" +allowed_write_paths: + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civiczone" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\CivicSuite-clerk-core-city-release" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\ACTIVE_RELEASE_QUEUE.md" +allowed_suite_paths: + - "installer/modules.json" + - "scripts/verify-suite-state.py" + - "README.md" + - "README.txt" + - "STATUS.md" + - "FAQ.md" + - "USER-MANUAL.md" + - "USER-MANUAL.txt" + - "CHANGELOG.md" + - "docs/CivicSuiteUnifiedSpec.md" + - "docs/release-recovery-status.md" + - "docs/release-lockstep/downstream-pins.md" + - "docs/compatibility/index.md" + - "docs/installer/**" + - "installer/dist/**" +forbidden_write_paths: + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civicplan" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civicpermit" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civicinspect" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civicboards" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civicnotice" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civic311" + - "C:\\Users\\scott\\OneDrive\\Desktop\\Claude\\civiccomms" +rules: + - "Queued module repos are read-only references." + - "No public-use, product-ready, finished, or released claim until Definition of Done evidence exists." + - "No macOS lifecycle certification claim." + - "All frontend changes require browser evidence before commit." + - "Non-trivial fixes require careful-coding evidence." diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e272d8a..982e8cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: cache: pip - name: Install CivicCore release wheel - run: python -m pip install https://github.com/CivicSuite/civiccore/releases/download/v1.0.1/civiccore-1.0.1-py3-none-any.whl + run: python -m pip install https://github.com/CivicSuite/civiccore/releases/download/v1.1.0/civiccore-1.1.0-py3-none-any.whl - name: Install package and test dependencies run: python -m pip install -e ".[dev]" diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index bb5b1d7..d2abd77 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -13,7 +13,7 @@ jobs: with: python-version: "3.11" - name: Install CivicCore release wheel - run: python -m pip install https://github.com/CivicSuite/civiccore/releases/download/v1.0.1/civiccore-1.0.1-py3-none-any.whl + run: python -m pip install https://github.com/CivicSuite/civiccore/releases/download/v1.1.0/civiccore-1.1.0-py3-none-any.whl - name: Install package run: python -m pip install -e ".[dev]" - name: Run release gate diff --git a/AGENTS.md b/AGENTS.md index d2ab521..4a8cb02 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,7 +18,7 @@ ## Placeholder Package Warning -Do not import from CivicCore placeholder packages until CivicCore ships real implementations for them: `audit`, `auth`, `catalog`, `connectors`, `exemptions`, `ingest`, `notifications`, `onboarding`, `scaffold`, `search`, `verification`. +Do not import from CivicCore placeholder packages until CivicCore ships real implementations for them: `audit`, `catalog`, `connectors`, `exemptions`, `ingest`, `notifications`, `onboarding`, `scaffold`, `search`, `verification`. CivicCore `auth` is no longer treated as a placeholder for CivicZone v1.0.0 because the current release uses its trusted-header helpers for staff access validation. ## Milestone Rule diff --git a/CHANGELOG.md b/CHANGELOG.md index b7af12b..5ced777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,18 +13,13 @@ The format follows Keep a Changelog, and this project follows Semantic Versionin ## [Unreleased] -### Changed - -- feat(deps): bump civiccore pin to v1.0.1 (security hardening recovery patch) - -## [1.0.0] - 2026-05-07 +## [1.0.0] - 2026-05-21 -### Recovery note +### Release note -- The `1.0.0` label was checked through the suite release-recovery pass with a - fresh local release gate and live browser QA. Treat the original release date - as historical; the recovery evidence is recorded in - `docs/release-recovery-status.md`. +- CivicZone is promoted from the demoted `0.2.0` recovery posture to the active + `1.0.0` public-use module release after the current scope, UX, docs, tests, + adversarial validation, and release-gate pass. ### Added @@ -32,12 +27,13 @@ The format follows Keep a Changelog, and this project follows Semantic Versionin - Staff workflow APIs for planner Q&A, ambiguity review queue, high-volume question analytics, staff-report outline support, and flagged-answer review. - Database-backed staff workflow records for planner questions, ambiguity queue items, and flagged answer reviews when `CIVICZONE_PARCEL_RULE_DB_URL` is configured. - Local adversarial integration mocks for Esri ArcGIS REST, GeoJSON fallback, CivicCode, CivicClerk, CivicPlan, CivicAccess, county assessor, and CKAN boundary validation. -- Resident UI copy and visible state guidance for loading, success, empty, error, and partial outcomes. +- Browser-usable resident UI for live parcel lookup, cited Q&A, empty, error, and planner-review states. +- Browser staff workflow shell for planner Q&A, ambiguity queue creation, analytics, and staff-report outline support. ### Changed -- Published CivicZone release surfaces at `1.0.0`; the later suite - release-recovery pass records fresh verification evidence. +- CivicCore dependency alignment moves to the published CivicCore `1.1.0` wheel. +- Staff workflow APIs now validate trusted municipal staff headers through the CivicCore trusted-proxy helper with loopback-only local defaults. - Updated runtime and documentation boundaries to describe the v1 product without claiming legal advice, official zoning determinations, or live external vendor calls by default. ## [0.1.2] - 2026-05-07 diff --git a/README.md b/README.md index 4e77992..782d9db 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ CivicZone is CivicSuite's parcel-aware zoning and land-use Q&A module. -Current state: **published v0.2.0 recovery label recovered through suite release-recovery evidence**. This repo contains a FastAPI service, health/root endpoints, documentation gates, canonical zoning schema models, Alembic migrations, deterministic parcel/zone lookup, cited use-rule lookup, cited dimensional-rule prechecks, resident Q&A with refusal and escalation rules, optional database-backed parcel/rule, resident-question ledger, and staff-workflow records through `CIVICZONE_PARCEL_RULE_DB_URL`, staff-only precedent protection, an accessible resident UI at `/civiczone`, adversarial local integration mocks, and CivicCore v1.0.0 release-wheel dependency alignment. See [docs/release-recovery-status.md](docs/release-recovery-status.md) for the local release gate, browser QA, and CI evidence. +Current state: **CivicZone v1.0.0 public-use module release**. This repo contains a FastAPI service, health/root endpoints, documentation gates, canonical zoning schema models, Alembic migrations, deterministic parcel/zone lookup, cited use-rule lookup, cited dimensional-rule prechecks, resident Q&A with refusal and escalation rules, optional database-backed parcel/rule, resident-question ledger, and staff-workflow records through `CIVICZONE_PARCEL_RULE_DB_URL`, staff-only precedent protection, a browser-usable resident UI at `/civiczone`, a staff workflow shell at `/civiczone/staff`, adversarial local integration mocks, trusted-proxy staff access validation, and CivicCore v1.1.0 release-wheel dependency alignment. See [docs/release-recovery-status.md](docs/release-recovery-status.md) for historical recovery context and current release evidence. ## Product Boundaries @@ -26,6 +26,7 @@ bash scripts/verify-release.sh - `GET /` returns current module status and operator next step. - `GET /health` returns package and CivicCore version information. - `GET /civiczone` returns the accessible resident lookup UI. +- `GET /civiczone/staff` returns the staff workflow shell; staff API actions require trusted municipal access headers from an approved proxy/source. - `POST /api/v1/civiczone/parcels/lookup` returns sample parcel zone context for `100-200-300` / `123 Main St`. - `POST /api/v1/civiczone/rules/use` returns sample use status with citation. - `POST /api/v1/civiczone/rules/dimensional` returns sample dimensional rule values with citation. @@ -42,7 +43,7 @@ Resident question text is stored only when `CIVICZONE_PARCEL_RULE_DB_URL` is con Set `CIVICZONE_PARCEL_RULE_DB_URL` to enable persistent parcel, use-rule, dimensional-rule, resident-question ledger, and staff workflow records. When unset, CivicZone uses deterministic in-memory sample data and does not persist question or staff workflow rows. -Staff workflow endpoints require trusted municipal access headers: +Staff workflow endpoints require trusted municipal access headers from a configured trusted proxy/source. Local development accepts loopback by default. Shared deployments should set `CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS` and strip client-supplied staff headers before requests reach CivicZone. - `X-CivicZone-Principal` - `X-CivicZone-Role: planner`, `staff`, or `zoning_admin` diff --git a/README.txt b/README.txt index 27cd6cc..21d9470 100644 --- a/README.txt +++ b/README.txt @@ -3,7 +3,7 @@ CivicZone CivicZone is CivicSuite's parcel-aware zoning and land-use Q&A module. -Current state: published v0.2.0 recovery label recovered through suite release-recovery evidence. This repo contains a FastAPI service, health/root endpoints, documentation gates, canonical zoning schema models, Alembic migrations, deterministic parcel/zone lookup, cited use-rule lookup, cited dimensional-rule prechecks, resident Q&A with refusal and escalation rules, optional database-backed parcel/rule, resident-question ledger, and staff-workflow records through CIVICZONE_PARCEL_RULE_DB_URL, staff-only precedent protection, an accessible resident UI at /civiczone, adversarial local integration mocks, and CivicCore v1.0.0 release-wheel dependency alignment. See docs/release-recovery-status.md for the local release gate, browser QA, and CI evidence. +Current state: CivicZone v1.0.0 public-use module release. This repo contains a FastAPI service, health/root endpoints, documentation gates, canonical zoning schema models, Alembic migrations, deterministic parcel/zone lookup, cited use-rule lookup, cited dimensional-rule prechecks, resident Q&A with refusal and escalation rules, optional database-backed parcel/rule, resident-question ledger, and staff-workflow records through CIVICZONE_PARCEL_RULE_DB_URL, staff-only precedent protection, a browser-usable resident UI at /civiczone, a staff workflow shell at /civiczone/staff, adversarial local integration mocks, trusted-proxy staff access validation, and CivicCore v1.1.0 release-wheel dependency alignment. See docs/release-recovery-status.md for historical recovery context and current release evidence. Product boundaries: @@ -14,7 +14,7 @@ Product boundaries: Set CIVICZONE_PARCEL_RULE_DB_URL to enable persistent parcel, use-rule, dimensional-rule, resident-question ledger, and staff workflow records. When unset, CivicZone uses deterministic in-memory sample data and does not persist question or staff workflow rows. -Staff workflow endpoints require trusted municipal access headers: +Staff workflow endpoints require trusted municipal access headers from a configured trusted proxy/source. Local development accepts loopback by default. Shared deployments should set CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS and strip client-supplied staff headers before requests reach CivicZone. - X-CivicZone-Principal - X-CivicZone-Role: planner, staff, or zoning_admin diff --git a/SECURITY.md b/SECURITY.md index 761fb7d..8108f2a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,5 @@ # Security -CivicZone Current version: 0.2.0. Deploy it behind the city's trusted access layer, with local parcel/rule data reviewed by planning staff, and with official zoning determinations routed to municipal staff. +CivicZone Current version: 1.0.0. Deploy it behind the city's trusted access layer, set `CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS` for the reverse proxy allowed to inject staff headers, review local parcel/rule data with planning staff, and route official zoning determinations to municipal staff. Report suspected vulnerabilities privately to the project maintainer. Do not open public issues containing exploit details, secrets, or sensitive municipal data. diff --git a/USER-MANUAL.md b/USER-MANUAL.md index 345f86e..0def740 100644 --- a/USER-MANUAL.md +++ b/USER-MANUAL.md @@ -4,17 +4,18 @@ CivicZone answers routine parcel-aware zoning questions with citations. It is not a zoning determination tool, not legal advice, and not a replacement for planner review. -Current state: published 0.2.0 recovery label recovered through suite release-recovery evidence. The package, health endpoints, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger records, staff workflow records, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, an accessible resident UI at `/civiczone`, and CivicCore v1.0.0 release-wheel dependency alignment exist. CivicZone does not call live external systems by default, does not provide legal advice, and does not make official zoning determinations. See `docs/release-recovery-status.md` for the local release gate, browser QA, and CI evidence. +Current state: CivicZone v1.0.0 public-use module release. The package, health endpoints, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger records, staff workflow records, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, a browser-usable resident UI at `/civiczone`, a staff workflow shell at `/civiczone/staff`, trusted-proxy staff access validation, and CivicCore v1.1.0 release-wheel dependency alignment exist. CivicZone does not call live external systems by default, does not provide legal advice, and does not make official zoning determinations. See `docs/release-recovery-status.md` for historical recovery context and current release evidence. The resident UI shows a pre-filled parcel lookup for `123 Main St`, zone context, use and dimensional-rule cards, citation-grounded Q&A, visible loading/success/empty/error/partial state guidance, and planner-escalation guidance. It is informational only: it is not legal advice, not a zoning determination, and not a replacement for municipal planning staff. ## For IT And Technical Staff -CivicZone is a FastAPI Python package pinned to the published CivicCore v1.0.0 release wheel. The current runtime exposes: +CivicZone is a FastAPI Python package pinned to the published CivicCore v1.1.0 release wheel. The current runtime exposes: - `GET /` - `GET /health` - `GET /civiczone` +- `GET /civiczone/staff` - Canonical SQLAlchemy models for zones, overlays, parcels, use rules, dimensional rules, citations, precedents, interpretation notes, and zone questions. - Alembic migration `civiczone_0001_schema`. - Alembic migration `civiczone_0002_parcel_rules` for optional parcel/rule lookup records. @@ -33,7 +34,7 @@ CivicZone is a FastAPI Python package pinned to the published CivicCore v1.0.0 r Set `CIVICZONE_PARCEL_RULE_DB_URL` to persist parcel, use-rule, dimensional-rule, resident-question ledger, and staff workflow data. Leave it unset for deterministic in-memory sample data during local development and documentation examples. -Staff workflow endpoints require trusted municipal access headers: +Staff workflow endpoints require trusted municipal access headers from a configured trusted proxy/source. Local development accepts loopback by default. Shared deployments should set `CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS` and strip client-supplied staff headers before requests reach CivicZone. - `X-CivicZone-Principal` - `X-CivicZone-Role: planner`, `staff`, or `zoning_admin` @@ -53,7 +54,7 @@ bash scripts/verify-release.sh ```mermaid flowchart LR Resident["Resident or planner"] --> CivicZone["CivicZone"] -CivicZone --> CivicCore["CivicCore v1.0.0"] +CivicZone --> CivicCore["CivicCore v1.1.0"] CivicZone --> CivicCode["CivicCode v1.0.0+"] CivicZone --> LocalMocks["Adversarial local integration mocks"] CivicZone -. configured .-> GIS["Local GIS / assessor datasets"] diff --git a/USER-MANUAL.txt b/USER-MANUAL.txt index 50d4abc..e410c11 100644 --- a/USER-MANUAL.txt +++ b/USER-MANUAL.txt @@ -4,17 +4,18 @@ CivicZone answers routine parcel-aware zoning questions with citations. It is not a zoning determination tool, not legal advice, and not a replacement for planner review. -Current state: published 0.2.0 recovery label recovered through suite release-recovery evidence. The package, health endpoints, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger records, staff workflow records, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, an accessible resident UI at `/civiczone`, and CivicCore v1.0.0 release-wheel dependency alignment exist. CivicZone does not call live external systems by default, does not provide legal advice, and does not make official zoning determinations. See `docs/release-recovery-status.md` for the local release gate, browser QA, and CI evidence. +Current state: CivicZone v1.0.0 public-use module release. The package, health endpoints, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger records, staff workflow records, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, a browser-usable resident UI at /civiczone, a staff workflow shell at /civiczone/staff, trusted-proxy staff access validation, and CivicCore v1.1.0 release-wheel dependency alignment exist. CivicZone does not call live external systems by default, does not provide legal advice, and does not make official zoning determinations. See docs/release-recovery-status.md for historical recovery context and current release evidence. The resident UI shows a pre-filled parcel lookup for `123 Main St`, zone context, use and dimensional-rule cards, citation-grounded Q&A, visible loading/success/empty/error/partial state guidance, and planner-escalation guidance. It is informational only: it is not legal advice, not a zoning determination, and not a replacement for municipal planning staff. ## For IT And Technical Staff -CivicZone is a FastAPI Python package pinned to the published CivicCore v1.0.0 release wheel. The current runtime exposes: +CivicZone is a FastAPI Python package pinned to the published CivicCore v1.1.0 release wheel. The current runtime exposes: - `GET /` - `GET /health` - `GET /civiczone` +- `GET /civiczone/staff` - Canonical SQLAlchemy models for zones, overlays, parcels, use rules, dimensional rules, citations, precedents, interpretation notes, and zone questions. - Alembic migration `civiczone_0001_schema`. - Alembic migration `civiczone_0002_parcel_rules` for optional parcel/rule lookup records. @@ -33,7 +34,7 @@ CivicZone is a FastAPI Python package pinned to the published CivicCore v1.0.0 r Set CIVICZONE_PARCEL_RULE_DB_URL to persist parcel, use-rule, dimensional-rule, resident-question ledger, and staff workflow data. Leave it unset for deterministic in-memory sample data during local development and documentation examples. -Staff workflow endpoints require trusted municipal access headers: +Staff workflow endpoints require trusted municipal access headers from a configured trusted proxy/source. Local development accepts loopback by default. Shared deployments should set CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS and strip client-supplied staff headers before requests reach CivicZone. - X-CivicZone-Principal - X-CivicZone-Role: planner, staff, or zoning_admin @@ -53,7 +54,7 @@ bash scripts/verify-release.sh ```mermaid flowchart LR Resident["Resident or planner"] --> CivicZone["CivicZone"] -CivicZone --> CivicCore["CivicCore v1.0.0"] +CivicZone --> CivicCore["CivicCore v1.1.0"] CivicZone --> CivicCode["CivicCode v1.0.0+"] CivicZone --> LocalMocks["Adversarial local integration mocks"] CivicZone -. configured .-> GIS["Local GIS / assessor datasets"] diff --git a/civiczone/__init__.py b/civiczone/__init__.py index b222345..4f14a57 100644 --- a/civiczone/__init__.py +++ b/civiczone/__init__.py @@ -1,3 +1,3 @@ """CivicZone package.""" -__version__ = "0.2.0" +__version__ = "1.0.0" diff --git a/civiczone/main.py b/civiczone/main.py index 5e10899..c2e0f7a 100644 --- a/civiczone/main.py +++ b/civiczone/main.py @@ -4,6 +4,12 @@ import os from civiccore import __version__ as CIVICCORE_VERSION +from civiccore.auth import ( + TrustedHeaderAuthConfig, + authorize_trusted_header_roles, + enforce_trusted_proxy_source, + load_trusted_header_auth_config, +) from fastapi import Depends, FastAPI, HTTPException, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import HTMLResponse, JSONResponse @@ -15,6 +21,7 @@ from civiczone.question_ledger import ZoneQuestionLedgerRepository from civiczone.qa import answer_zoning_question from civiczone.rule_lookup import RuleLookupError, RuleLookupRepository, lookup_dimensional_rule, lookup_use_rule +from civiczone.staff_ui import render_staff_workspace_page from civiczone.staff_context import classify_for_planner_review, get_staff_precedent from civiczone.staff_workflows import StaffWorkflowStore @@ -66,12 +73,12 @@ def root() -> dict[str, str]: "version": __version__, "status": "v1 parcel-aware zoning Q&A runtime", "message": ( - "CivicZone v0.2.0 provides deterministic parcel lookup, cited use-rule lookup, cited dimensional prechecks, " + "CivicZone v1.0.0 provides deterministic parcel lookup, cited use-rule lookup, cited dimensional prechecks, " "resident zoning Q&A with refusal and escalation rules, staff workflow APIs, optional database-backed parcel/rule and question-ledger records, " - "canonical zoning schema migrations, adversarial local integration mocks, and an accessible resident UI. " + "canonical zoning schema migrations, adversarial local integration mocks, an accessible resident UI, and a staff workflow UI shell. " "It does not make zoning determinations, give legal advice, replace planner review, or call live external systems by default." ), - "next_step": "Configure local parcel/rule data, connect the trusted municipal access layer, and route official decisions to planning staff.", + "next_step": "Configure local parcel/rule data, set the trusted staff proxy CIDR list, and route official decisions to planning staff.", } @@ -94,6 +101,13 @@ def public_civiczone_page() -> str: return render_public_lookup_page() +@app.get("/civiczone/staff", response_class=HTMLResponse) +def staff_civiczone_page() -> str: + """Return the staff workflow shell without exposing staff data in HTML.""" + + return render_staff_workspace_page() + + class ParcelLookupRequest(BaseModel): parcel_number: str | None = Field(default=None) address: str | None = Field(default=None) @@ -156,31 +170,44 @@ class FlaggedAnswerImproveRequest(BaseModel): def _require_staff_access(request: Request) -> StaffPrincipal: allowed_roles = {"planner", "staff", "zoning_admin"} - subject = request.headers.get("X-CivicZone-Principal", "").strip() - if not subject: - raise HTTPException( - status_code=401, - detail={ - "message": "Trusted identity header missing for CivicZone staff workflow access.", - "fix": "Send X-CivicZone-Principal from the trusted municipal access layer.", - }, - ) - roles = tuple( - role.strip() - for raw_value in request.headers.getlist("X-CivicZone-Role") - for role in raw_value.split(",") - if role.strip() + config = _staff_trusted_header_config() + enforce_trusted_proxy_source( + request.client.host if request.client else None, + service_name="CivicZone", + feature_name="staff workflow access", + config=config, + trusted_proxy_env_var="CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS", + ) + principal = authorize_trusted_header_roles( + request.headers, + service_name="CivicZone", + feature_name="staff workflow access", + principal_header_name=config.principal_header_name, + roles_header_name=config.roles_header_name, + allowed_roles=allowed_roles, + provider_name=config.provider_name, + ) + return StaffPrincipal(subject=principal.subject or "staff", roles=tuple(sorted(principal.roles))) + + +def _staff_trusted_header_config() -> TrustedHeaderAuthConfig: + config = load_trusted_header_auth_config( + provider_env_var="CIVICZONE_STAFF_AUTH_PROVIDER", + provider_default="CivicZone staff shell", + principal_header_env_var="CIVICZONE_STAFF_PRINCIPAL_HEADER", + principal_header_default="X-CivicZone-Principal", + roles_header_env_var="CIVICZONE_STAFF_ROLES_HEADER", + roles_header_default="X-CivicZone-Role", + trusted_proxy_env_var="CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS", + ) + if config.trusted_proxy_cidrs: + return config + return TrustedHeaderAuthConfig( + provider_name=config.provider_name, + principal_header_name=config.principal_header_name, + roles_header_name=config.roles_header_name, + trusted_proxy_cidrs=("127.0.0.1/32", "::1/128"), ) - if not allowed_roles.intersection(roles): - raise HTTPException( - status_code=403, - detail={ - "message": "CivicZone staff workflow access requires a staff planning role.", - "fix": "Send X-CivicZone-Role with planner, staff, or zoning_admin.", - "required_roles": sorted(allowed_roles), - }, - ) - return StaffPrincipal(subject=subject, roles=roles) @app.post("/api/v1/civiczone/parcels/lookup") diff --git a/civiczone/public_ui.py b/civiczone/public_ui.py index be97b49..4a22f42 100644 --- a/civiczone/public_ui.py +++ b/civiczone/public_ui.py @@ -1,283 +1,355 @@ -"""Static public UI shell for CivicZone's resident zoning lookup surface.""" +"""Public resident UI for CivicZone.""" from __future__ import annotations def render_public_lookup_page() -> str: - """Render the accessible public-facing CivicZone lookup page.""" + """Render the browser-usable public CivicZone lookup page.""" return """ -CivicZone Public Lookup + +CivicZone Resident Lookup
-

CivicSuite / CivicZone resident lookup

-

Find zoning context before you ask for a ruling.

-

CivicZone helps residents and staff inspect parcel zoning context, cited use rules, dimensional standards, and escalation paths without turning informational guidance into an official determination.

-
-
-
-

Parcel lookup

-

123 Main St

-
- - -

This example is pre-filled. Cities can load local parcel and rule records with CIVICZONE_PARCEL_RULE_DB_URL.

-
-
-

R-2 Residential District

-
    -
  • Parcel: 100-200-300
  • -
  • Overlay: Historic District Overlay
  • -
  • Constraints: Historic review required for exterior alterations; ADU review may require planner confirmation.
  • -
  • Source: configured local zoning dataset or bundled municipal sample fixture.
  • -
+
+
+

Lookup and question

+

The sample city dataset includes parcel 100-200-300 at 123 Main St in R-2.

+
+
+
+ +
-
- -
-

Use rule

-

Accessory dwelling unit

-
-

Conditional use review

-

In sample zone R-2, an accessory dwelling unit is shown as conditionally allowed.

-

Citation: Sample Zoning Code § 18.20.040.

+ +
+ + +
-
+ +
+ Ready +

Submit the sample lookup to see parcel context, citations, and the non-determination boundary.

+
+
+ +
+ + """ diff --git a/civiczone/staff_ui.py b/civiczone/staff_ui.py new file mode 100644 index 0000000..f707489 --- /dev/null +++ b/civiczone/staff_ui.py @@ -0,0 +1,264 @@ +"""Staff workflow UI shell for CivicZone.""" + +from __future__ import annotations + + +def render_staff_workspace_page() -> str: + """Render a browser-usable staff shell that calls staff APIs through trusted headers.""" + + return """ + + + + + +CivicZone Staff Workspace + + + +
+

CivicZone staff workspace

+

Planner Q&A, ambiguity review queue, analytics, report outlines, and flagged-answer improvement. Staff API calls require trusted municipal access headers from an approved proxy.

+
+
+
+

Staff action

+
+
+ + +
+ + +
+ + + + +
+
+
+

Staff-only boundary: this page does not embed staff data. The API rejects missing identity headers, unauthorized roles, or headers not received through a trusted proxy/source.

+
+
+
+

Result

+
+ Ready +

Run a staff action through the configured access layer.

+
+
+
+ + + + +""" diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md index bb55fe6..2011671 100644 --- a/docs/IMPLEMENTATION_PLAN.md +++ b/docs/IMPLEMENTATION_PLAN.md @@ -10,5 +10,9 @@ Build order: 6. Add planner escalation and staff-only context. 7. Add public UI and accessibility pass. 8. Cut v0.1.0 and update the umbrella compatibility matrix. +9. Promote CivicZone to v1.0.0 with browser-usable resident and staff surfaces, + trusted-proxy staff access validation, current CivicCore compatibility, + adversarial integration validation, and CivicSuite installer/module-selection + truth. The implementation must remain local-first and citation-first throughout. diff --git a/docs/MILESTONES.md b/docs/MILESTONES.md index 3eae5d3..05acb08 100644 --- a/docs/MILESTONES.md +++ b/docs/MILESTONES.md @@ -62,3 +62,17 @@ Acceptance criteria: - Version surfaces match. - GitHub release publishes wheel, sdist, and checksums. - Umbrella compatibility matrix is updated. + +## Milestone 9 - v1.0.0 Public-Use Release + +Acceptance criteria: +- Version surfaces match `1.0.0`. +- CivicCore compatibility is aligned to the published CivicCore v1.1.0 wheel. +- Resident UI runs live parcel lookup, cited Q&A, empty, error, and + planner-review states. +- Staff UI shell supports planner Q&A, ambiguity review, analytics, and + staff-report outline actions through trusted municipal access headers. +- Staff APIs validate headers through the trusted proxy/source allowlist. +- Full tests, docs gate, Ruff, release gate, browser QA, adversarial validation, + release-gate audit, CI, tag/release, and CivicSuite installer/module-selection + truth pass. diff --git a/docs/index.html b/docs/index.html index fc69af1..c22c1c9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,11 +7,11 @@ @@ -23,9 +23,9 @@

Zoning answers with citations, not guesses.

CivicZone is the parcel-aware zoning and land-use module for CivicSuite. It helps residents and planners find routine zoning information while escalating actual determinations to staff.

- v0.2.0 recovery label recovered with release evidence + v1.0.0 public-use module release

Current State

-

The published v0.2.0 recovery label has been checked through the suite release-recovery pass; see the recovery status. The FastAPI service, root endpoint, health endpoint, documentation gates, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger, and staff workflow records via CIVICZONE_PARCEL_RULE_DB_URL, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, and accessible resident UI exist. CivicZone does not make official zoning determinations, provide legal advice, or call live external vendor systems by default.

+

CivicZone v1.0.0 includes the FastAPI service, root endpoint, health endpoint, documentation gates, canonical zoning schema, Alembic migrations, parcel/zone lookup API, use and dimensional rule APIs, optional database-backed parcel/rule lookup records, resident question ledger, staff workflow records via CIVICZONE_PARCEL_RULE_DB_URL, citation-grounded resident Q&A, staff-only precedent protection, local adversarial integration mocks, browser-usable resident UI, staff workflow shell, trusted-proxy staff access validation, and CivicCore v1.1.0 dependency alignment. CivicZone does not make official zoning determinations, provide legal advice, or call live external vendor systems by default.

diff --git a/docs/qa/civiczone-v1-browser-qa.md b/docs/qa/civiczone-v1-browser-qa.md index a574099..bd9e8d5 100644 --- a/docs/qa/civiczone-v1-browser-qa.md +++ b/docs/qa/civiczone-v1-browser-qa.md @@ -1,6 +1,46 @@ -# CivicZone v0.2.0 Browser QA Evidence +# CivicZone v1.0.0 Browser QA Evidence -- desktop: 200 OK, screenshot=docs/qa/civiczone-v1-public-desktop.png, console_messages=0, focused=['Skip to main content', 'Open API documentation'] -- mobile: 200 OK, screenshot=docs/qa/civiczone-v1-public-mobile.png, console_messages=0, focused=['Skip to main content', 'Open API documentation'] +Date: 2026-05-21 -Checked states: loading, success, empty, error, partial. Checked copy: legal/determination boundary, actionable empty-state fix path, staff-only precedent boundary. Checked keyboard: skip link and API docs link receive focus. Browser console had no errors. +## Surfaces + +| Surface | Viewport | Result | Evidence | +|---|---:|---|---| +| Resident lookup `/civiczone` | 1440x1000 | PASS | `docs/qa/civiczone-v1-public-desktop-resident-ready.png` | +| Resident success state | 1440x1000 | PASS | `docs/qa/civiczone-v1-public-desktop-resident-success.png` | +| Resident empty state | 1440x1000 | PASS | `docs/qa/civiczone-v1-public-desktop-resident-empty.png` | +| Resident planner-review partial state | 1440x1000 | PASS | `docs/qa/civiczone-v1-public-desktop-resident-partial.png` | +| Resident lookup `/civiczone` | 390x844 | PASS | `docs/qa/civiczone-v1-public-mobile-ready.png` | +| Resident mobile states | 390x844 | PASS | `docs/qa/civiczone-v1-public-mobile-states.png` | +| Staff workspace `/civiczone/staff` | 1440x1000 | PASS | `docs/qa/civiczone-v1-staff-desktop-ready.png` | +| Staff answer workflow | 1440x1000 | PASS | `docs/qa/civiczone-v1-staff-desktop-answer.png` | +| Staff queue, analytics, outline workflows | 1440x1000 | PASS | `docs/qa/civiczone-v1-staff-desktop-workflows.png` | +| Staff unauthorized-role error | 1440x1000 | PASS | `docs/qa/civiczone-v1-staff-desktop-auth-error.png` | +| Staff workspace `/civiczone/staff` | 390x844 | PASS | `docs/qa/civiczone-v1-staff-mobile-ready.png` | +| Staff answer workflow | 390x844 | PASS | `docs/qa/civiczone-v1-staff-mobile-answer.png` | + +## State Matrix + +| State | Evidence | Result | +|---|---|---| +| Loading | Buttons disable and status text changes during fetch | PASS | +| Success | Parcel `100-200-300`, zone `R-2`, ADU answer, citation `CMC 18.42.030` render | PASS | +| Empty | Missing parcel returns actionable "load local records or use sample parcel" fix path | PASS | +| Error | Staff role changed to `resident` returns actionable allowed-role error | PASS | +| Partial/degraded | Determination request routes to planner review with non-determination boundary | PASS | + +## Console, Keyboard, Layout + +- Desktop resident console: `docs/qa/civiczone-v1-public-desktop-console.json`, zero errors/warnings. +- Desktop staff console: `docs/qa/civiczone-v1-staff-desktop-console.json`, zero errors/warnings. +- Mobile console: `docs/qa/civiczone-v1-mobile-console.json`, zero errors/warnings after favicon fix. +- Keyboard/focus/layout: `docs/qa/civiczone-v1-keyboard-focus-layout.json`. +- Public and staff pages had no horizontal overflow at desktop checks. +- Focus reached skip link, fields, workflow buttons, and staff workspace link in visible order. + +## Copy Review + +- Resident copy states that CivicZone provides information only and does not make zoning determinations or provide legal advice. +- Empty and error states include a concrete fix path. +- Staff page states that staff API actions require trusted municipal access headers from an approved proxy. +- Staff workflow output remains review support; official determinations stay with planning staff. diff --git a/docs/qa/civiczone-v1-browser-recheck-console.json b/docs/qa/civiczone-v1-browser-recheck-console.json new file mode 100644 index 0000000..2bca72f --- /dev/null +++ b/docs/qa/civiczone-v1-browser-recheck-console.json @@ -0,0 +1,4 @@ +{ + "residentLogs2": [], + "staffLogs2": [] +} \ No newline at end of file diff --git a/docs/qa/civiczone-v1-careful-coding.md b/docs/qa/civiczone-v1-careful-coding.md index 5358c21..9933a1e 100644 --- a/docs/qa/civiczone-v1-careful-coding.md +++ b/docs/qa/civiczone-v1-careful-coding.md @@ -1,25 +1,28 @@ -# CivicZone v0.2.0 Careful-Coding Evidence +# CivicZone v1.0.0 Careful-Coding Evidence -Date: 2026-05-07 +Date: 2026-05-21 Scope: CivicZone active module only. ## Pre-Edit Trace -1. Callers read: resident routes, staff routes, parcel lookup, rule lookup, question ledger, public UI, and release verifier. -2. Runtime context traced: FastAPI app, optional `CIVICZONE_PARCEL_RULE_DB_URL`, in-memory fallback, staff trusted headers, WSL/bash release gate, and Docker-backed migration test. -3. Fan-out search: stale release terms, route names, version surfaces, docs claims, and CivicCore placeholder imports. -4. Data contract identified: parcel/rule result shapes, `ZoneAnswer`, staff workflow payloads, integration mock result/error shapes, browser UI copy and state text. -5. Blast radius: CivicZone API responses, resident UI, docs, release artifacts, tests, GitHub release workflow. +1. Callers read: `GET /civiczone`, new `GET /civiczone/staff`, every `/api/v1/civiczone/staff/*` route, resident Q&A routes, public UI tests, staff workflow tests, release verifier, docs verifier, and GitHub workflows. +2. Runtime context traced: FastAPI sync route handlers under Uvicorn/TestClient; staff routes run behind trusted municipal headers and now validate source through CivicCore trusted-proxy helpers; resident UI uses same-origin browser `fetch`; optional persistence remains behind `CIVICZONE_PARCEL_RULE_DB_URL`. +3. Fan-out search: `0.2.0`, `1.0.1`, `v0.2.0`, recovery labels, CivicCore placeholder import guard, public UI static-state claims, staff-header docs, release workflows, and test expectations. +4. Data contract identified: package version, CivicCore wheel URL/hash, root/health version payloads, staff auth failure semantics, public/staff HTML render paths, browser state evidence, and release artifact names. +5. Blast radius: CivicZone API responses, staff route authorization, resident and staff browser UX, docs, release verifier, GitHub verify/release workflows, package artifacts, and future suite truth. ## Post-Edit Proof -6. End-to-end re-read: root/health, resident Q&A, staff Q&A, ambiguity queue, analytics, flagged-answer review, integration mocks, docs, release script. -7. Code path narrated: resident asks an ADU question, CivicZone resolves a cited use rule, returns answer/citation/confidence/next step, records the configured ledger row, and displays the informational boundary in the UI. -8. Render/data path proved: Playwright desktop and mobile walkthroughs saved screenshots and verified loading, success, empty, error, and partial state copy with zero browser console errors. -9. Five-lens self-audit: - - Engineering: full tests passed; placeholder imports blocked; release route/docs mismatch fixed; release-gate staff-workflow durability finding fixed. - - UX: desktop/mobile browser pass, keyboard focus, actionable empty/error/partial copy. - - QA: WSL `scripts/verify-release.sh` passed with 65 tests and v1 artifacts. - - Tests: targeted and full pytest runs pass; adversarial mock tests cover malformed, stale, spoofed, unavailable, and air-gap cases; staff workflow persistence survives store reset when `CIVICZONE_PARCEL_RULE_DB_URL` is configured. - - Docs: README, changelog, user manual, security note, docs index, browser QA evidence, careful-coding evidence, and release workflow updated. +6. Changed files re-read: `civiczone/main.py`, `civiczone/public_ui.py`, `civiczone/staff_ui.py`, tests, release scripts, README/manual/security/changelog/docs, and QA evidence. +7. Code path narrated: resident submits parcel/question -> `/api/v1/civiczone/parcels/lookup` returns cited parcel context -> `/api/v1/civiczone/questions/answer` returns answer/refusal/escalation -> UI renders success, empty, error, or planner-review partial state with actionable copy and non-determination boundary. +8. Staff path narrated: staff enters principal/role -> browser calls staff API with trusted headers -> FastAPI enforces trusted proxy/source and role -> staff Q&A, ambiguity queue, analytics, and report outline return staff-only records or actionable auth errors. +9. Render/data path proved: browser screenshots and console logs are saved under `docs/qa/`; desktop and mobile resident/staff surfaces passed; keyboard focus and no-horizontal-overflow checks are recorded. + +## Five-Lens Self-Audit + +- Engineering: full release verifier passes with 71 tests, docs gate, placeholder import gate, Ruff, build artifacts, and SHA256SUMS. +- UX: resident and staff browser flows have loading, success, empty, error, and partial states; copy gives concrete next steps. +- QA: desktop/mobile screenshots, console logs, keyboard/focus, layout, and adversarial mock coverage are recorded. +- Tests: staff route tests cover missing auth, underprivileged roles, trusted-source rejection, persistence, and resident/staff leakage boundaries. +- Docs: current-facing docs now say CivicZone v1.0.0, CivicCore v1.1.0, trusted-proxy staff access, and no legal/determination/live-vendor overclaims. diff --git a/docs/qa/civiczone-v1-keyboard-focus-layout.json b/docs/qa/civiczone-v1-keyboard-focus-layout.json new file mode 100644 index 0000000..912f1d3 --- /dev/null +++ b/docs/qa/civiczone-v1-keyboard-focus-layout.json @@ -0,0 +1,88 @@ +{ + "public": [ + { + "tag": "A", + "id": "", + "text": "Skip to main content" + }, + { + "tag": "INPUT", + "id": "parcel", + "text": "100-200-300" + }, + { + "tag": "INPUT", + "id": "address", + "text": "123 Main St" + }, + { + "tag": "TEXTAREA", + "id": "question", + "text": "Can I build an ADU?" + }, + { + "tag": "BUTTON", + "id": "run", + "text": "Run lookup" + }, + { + "tag": "BUTTON", + "id": "empty", + "text": "Check missing parcel" + }, + { + "tag": "BUTTON", + "id": "partial", + "text": "Check planner review" + }, + { + "tag": "A", + "id": "", + "text": "Staff workspace" + } + ], + "staff": [ + { + "tag": "INPUT", + "id": "principal", + "text": "planner@example.gov" + }, + { + "tag": "INPUT", + "id": "role", + "text": "planner" + }, + { + "tag": "INPUT", + "id": "zone", + "text": "R-2" + }, + { + "tag": "TEXTAREA", + "id": "question", + "text": "What is the front setback?" + }, + { + "tag": "BUTTON", + "id": "answer", + "text": "Answer" + }, + { + "tag": "BUTTON", + "id": "queue", + "text": "Create review item" + }, + { + "tag": "BUTTON", + "id": "analytics", + "text": "Analytics" + }, + { + "tag": "BUTTON", + "id": "outline", + "text": "Report outline" + } + ], + "overflowPublic": false, + "overflowStaff": false +} \ No newline at end of file diff --git a/docs/qa/civiczone-v1-mobile-console-recheck.png b/docs/qa/civiczone-v1-mobile-console-recheck.png new file mode 100644 index 0000000..6aebc85 Binary files /dev/null and b/docs/qa/civiczone-v1-mobile-console-recheck.png differ diff --git a/docs/qa/civiczone-v1-mobile-console.json b/docs/qa/civiczone-v1-mobile-console.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/docs/qa/civiczone-v1-mobile-console.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/docs/qa/civiczone-v1-public-desktop-console.json b/docs/qa/civiczone-v1-public-desktop-console.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/docs/qa/civiczone-v1-public-desktop-console.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/docs/qa/civiczone-v1-public-desktop-resident-empty.png b/docs/qa/civiczone-v1-public-desktop-resident-empty.png new file mode 100644 index 0000000..0aad68c Binary files /dev/null and b/docs/qa/civiczone-v1-public-desktop-resident-empty.png differ diff --git a/docs/qa/civiczone-v1-public-desktop-resident-partial.png b/docs/qa/civiczone-v1-public-desktop-resident-partial.png new file mode 100644 index 0000000..f1bfe71 Binary files /dev/null and b/docs/qa/civiczone-v1-public-desktop-resident-partial.png differ diff --git a/docs/qa/civiczone-v1-public-desktop-resident-ready.png b/docs/qa/civiczone-v1-public-desktop-resident-ready.png new file mode 100644 index 0000000..39558f9 Binary files /dev/null and b/docs/qa/civiczone-v1-public-desktop-resident-ready.png differ diff --git a/docs/qa/civiczone-v1-public-desktop-resident-success.png b/docs/qa/civiczone-v1-public-desktop-resident-success.png new file mode 100644 index 0000000..2226150 Binary files /dev/null and b/docs/qa/civiczone-v1-public-desktop-resident-success.png differ diff --git a/docs/qa/civiczone-v1-public-mobile-ready.png b/docs/qa/civiczone-v1-public-mobile-ready.png new file mode 100644 index 0000000..d4a35f3 Binary files /dev/null and b/docs/qa/civiczone-v1-public-mobile-ready.png differ diff --git a/docs/qa/civiczone-v1-public-mobile-states.png b/docs/qa/civiczone-v1-public-mobile-states.png new file mode 100644 index 0000000..2451116 Binary files /dev/null and b/docs/qa/civiczone-v1-public-mobile-states.png differ diff --git a/docs/qa/civiczone-v1-release-gate-audit.md b/docs/qa/civiczone-v1-release-gate-audit.md index ccb1fd3..9983a6d 100644 --- a/docs/qa/civiczone-v1-release-gate-audit.md +++ b/docs/qa/civiczone-v1-release-gate-audit.md @@ -1,138 +1,140 @@ -# CivicZone v0.2.0 Release-Gate Audit +# CivicZone v1.0.0 Release-Gate Audit -Date: 2026-05-07 +Date: 2026-05-21 ## 1. Executive Audit - Scope: `C:\Users\scott\OneDrive\Desktop\Claude\civiczone` - Audit mode: release-gate -- Active cleanup: yes, current local release-candidate branch -- Local checkout vs live remote: local `cbab60b` is ahead of tracked remote `d118fc2` by two commits -- Verdict: PASS after one Critical release-gate fix -- Ship posture: push/PR/merge/tag may proceed after CI is green -- Severity summary: Blocker 0, Critical 1 fixed, Major 0, Minor 0, Nit 0 -- Static audit confidence: High -- Runtime sign-off confidence: High -- CI/workflow posture: `verify.yml` runs `scripts/verify-release.sh`; `release.yml` publishes v-tag artifacts +- Active cleanup: yes, current local v1.0.0 release run +- Local checkout vs live remote: local HEAD and `origin/main` both start at `71ded10744c06d7db334f834cb8b9d8533f853b2`; this audit covers local uncommitted release changes after that baseline. +- Verdict: PASS for source-repo release candidate; full module completion still requires PR, tag/release, CI, and CivicSuite installer/module-selection truth after this source work lands. +- Ship posture: source PR may proceed after the current diff is committed and pushed. +- Severity summary: Blocker 0, Critical 0, Major 0, Minor 0, Nit 0 unresolved. +- Static audit confidence: High. +- Runtime sign-off confidence: High for local/mock CivicZone v1 scope. +- CI/workflow posture: `verify.yml` and `release.yml` install CivicCore v1.1.0 and run `scripts/verify-release.sh`. -Real state: CivicZone v0.2.0 now provides cited parcel-aware zoning lookup, resident Q&A with refusal/escalation, staff workflow APIs, local adversarial integration mocks, database-backed parcel/rule/question/staff workflow records when configured, and browser-verified resident UI. It does not provide legal advice, official zoning determinations, or live external vendor calls by default. - -Top cross-cutting finding: `ENG-001` staff workflow state was initially in-process only. Fixed by adding database-backed staff question, ambiguity queue, and flagged-answer records plus migration and persistence tests. +Real state: CivicZone v1.0.0 now provides cited parcel-aware zoning lookup, resident Q&A with refusal/escalation, browser-usable resident and staff surfaces, trusted-proxy staff access validation, staff workflow APIs, local adversarial integration mocks, optional database-backed parcel/rule/question/staff workflow records, current docs, and v1.0.0 build artifacts. It does not provide legal advice, official zoning determinations, live vendor calls, or macOS lifecycle certification. ## 2. Audit Coverage Ledger -| Lane | Status | Evidence | Blocker | +| Lane | Status | Evidence summary | Blocker | |---|---|---|---| -| remote parity | Checked | `HEAD=cbab60b`, upstream `d118fc2`, local ahead 2 | none | -| local-vs-live commit truth | Checked | `git fetch origin --prune`; branch ahead only | none | +| remote parity | Checked | `HEAD=origin/main=71ded10744c06d7db334f834cb8b9d8533f853b2` before local diff | none | +| local-vs-live commit truth | Checked | `git fetch --prune origin`, `git rev-parse HEAD`, `git rev-parse origin/main` | none | | CI/workflow presence | Checked | `.github/workflows/verify.yml`, `.github/workflows/release.yml` | none | -| Windows install path | Checked | local Python test and Ruff commands passed | none | -| Linux or Unix install path | Checked | WSL/bash `scripts/verify-release.sh` passed | none | -| platform parity verdict | Checked | Windows-targeted pytest and WSL release gate both passed | none | -| first boot | Checked | local Uvicorn health and `/civiczone` browser QA passed | none | -| required post-install steps | Checked | README/manual document editable install and verify command | none | -| migrations | Checked | Docker pgvector Alembic test passed through `civiczone_0004_staff_workflows` | none | -| seed/bootstrap requirements | Checked | deterministic sample data and optional DB config documented | none | -| runtime dependency and model requirements | Checked | Published CivicCore v1.0.0 release wheel; no live LLM dependency | none | -| first-boot dependency truth | Checked | no DB required for sample mode; DB enables persistence | none | -| secrets and credential handling | Checked | no hard-coded production secret found | none | -| auth and session handling | Checked | staff endpoints require trusted principal and role headers | none | -| authorization and role boundaries | Checked | resident role rejected; staff-only visibility tested | none | +| Windows install path | Partially checked | Local Windows Python tests/Ruff/release gate passed; cleanroom installer truth is suite-level follow-through | none for source PR | +| Linux or Unix install path | Checked | Bash `scripts/verify-release.sh` passed locally | none | +| platform parity verdict | Partially checked | Source package is cross-platform Python; suite installer lifecycle is separate follow-through | none for source PR | +| first boot | Checked | Uvicorn served `/civiczone`, `/civiczone/staff`, APIs on `127.0.0.1:8011` | none | +| required post-install steps | Checked | README/manual document install, verify, DB, and staff proxy config | none | +| migrations | Checked | Existing pgvector/Alembic tests passed | none | +| seed/bootstrap requirements | Checked | deterministic sample parcel/rule data; optional DB config documented | none | +| runtime dependency and model requirements | Checked | CivicCore v1.1.0 wheel; no model/LLM dependency | none | +| first-boot dependency truth | Checked | sample mode runs without DB; DB enables persistence | none | +| secrets and credential handling | Checked | secret scan found only test Postgres password fixture | none | +| auth and session handling | Checked | staff APIs enforce trusted proxy/source plus principal/role headers | none | +| authorization and role boundaries | Checked | missing, resident role, and untrusted-source tests pass | none | | response-schema sensitive-data exposure | Checked | resident answers do not expose staff-only records | none | -| audit and compliance logging | Checked | resident ledger and staff workflow records persist when DB configured | none | -| external and admin surfaces | Checked | integration mocks reject live endpoints | none | -| connector implementation completeness | Checked | adversarial local mocks cover specified integration boundaries | none | -| connector docs truth | Checked | docs say local mocks, not live external proof | none | -| background jobs and schedulers | Not applicable | no scheduler shipped | none | -| frontend critical journeys | Checked | Playwright desktop/mobile `/civiczone` | none | -| loading states | Checked | visible state copy in browser evidence | none | -| empty states | Checked | actionable no-parcel copy in browser evidence | none | -| error states | Checked | error/partial copy in browser evidence and API tests | none | -| partial states | Checked | stale/missing-citation escalation covered | none | -| accessibility cues | Checked | skip link, focus, landmarks, console evidence | none | -| docs truthfulness | Checked | docs gate and route mismatch fixed | none | -| version consistency | Checked | `1.0.0` code/docs/artifacts verified | none | -| release artifact consistency | Checked | wheel, sdist, `SHA256SUMS.txt` built | none | -| test realism | Checked | 65 tests include Docker pgvector and adversarial mocks | none | +| audit and compliance logging | Checked | question/staff workflow records persist when DB configured | none | +| external and admin surfaces | Checked | local mock adapters reject live endpoints and spoofed providers | none | +| connector implementation completeness | Checked | mocks cover Esri, GeoJSON, CivicCode, CivicClerk, CivicPlan, CivicAccess, assessor, CKAN | none | +| connector docs truth | Checked | docs say local/adversarial mocks, not live integrations | none | +| background jobs and schedulers | Not applicable | none shipped | none | +| frontend critical journeys | Checked | resident and staff browser flows exercised | none | +| loading states | Checked | browser QA states and screenshots | none | +| empty states | Checked | missing parcel state screenshot and copy | none | +| error states | Checked | staff unauthorized-role error screenshot and test | none | +| partial states | Checked | determination request routes to planner-review partial state | none | +| accessibility cues | Checked | skip link, labels, focus order, no horizontal overflow | none | +| docs truthfulness | Checked | docs gate passed and current docs updated | none | +| version consistency | Checked | release verifier passed v1.0.0 surfaces | none | +| release artifact consistency | Checked | wheel, sdist, SHA256SUMS built | none | +| test realism | Checked | 71 tests include API, DB, auth, mocks, UI HTML, release gates | none | | runtime, build, and test verification | Checked | `scripts/verify-release.sh` passed | none | -| browser verification | Checked | desktop/mobile screenshots and console log evidence | none | -| prior audit or verification challenge | Checked | audit-found Critical fixed and reverified | none | +| browser verification | Checked | desktop/mobile screenshots and console JSON saved under `docs/qa/` | none | +| prior audit or verification challenge | Checked | stale recovery audit replaced; current release audit recorded | none | ## 3. Claim Verification Matrix | Claim | Source | Verdict | Evidence | |---|---|---|---| -| CivicZone is v1.0.0 | README, package, release gate | True | version check and v1 artifacts passed | -| Resident Q&A is cited and bounded | README/API/tests | True | cited ADU/setback tests and disclaimer tests pass | -| Determinations/legal advice are not provided | README/UI/API/tests | True | refusal/escalation tests and UI copy pass | -| Staff workflows exist | README/API/tests | True | Q&A, queue, analytics, report outline, flagged review tests pass | -| Staff workflows persist with DB config | README/tests | True | reset-survival persistence test passes | -| External integrations are local/adversarial mocks | README/tests | True | live endpoint, spoof, stale, malformed, unavailable tests pass | -| Browser UI is accessible enough for release gate | QA evidence/tests | True | desktop/mobile/focus/console evidence saved | -| Release artifacts are created | release gate | True | wheel, sdist, checksums built | -| Remote already contains release candidate | git | False | local branch ahead 2 before push | +| CivicZone version is 1.0.0 | package, docs, release gate | True | `scripts/verify-release.sh` passed and built `civiczone-1.0.0` artifacts | +| CivicCore dependency is v1.1.0 | pyproject/workflows/health test | True | dependency hash checked against GitHub release asset | +| Resident Q&A is cited and bounded | API/tests/browser | True | ADU success renders `CMC 18.42.030`; legal/determination boundaries remain visible | +| Staff workflows exist | API/tests/browser | True | staff Q&A, queue, analytics, outline, flagged-answer tests and browser evidence | +| Staff-only routes are protected | main/tests | True | missing, role, and untrusted-source tests pass | +| Public UI is browser usable | `/civiczone` | True | live `fetch` workflows verified desktop/mobile | +| Staff UI is browser usable | `/civiczone/staff` | True | staff workflow shell verified desktop/mobile | +| Live vendor integrations are available | docs/code | False/not claimed | adapters are local adversarial mocks only | +| Official zoning determinations are available | docs/code | False/not claimed | docs/UI/API state informational-only boundary | +| Full module DoD is complete | queue/DoD | Partially true | source gate is ready; PR, tag/release, suite truth, and CI remain to complete | ## 4. What The Dev Team Needs To Do Now Must fix before ship: -- None unresolved. + +- None unresolved in the source repo release candidate. Should fix this sprint: -- None unresolved. + +- Complete the remaining release mechanics after source PR: merge, tag/release, verify CI, update CivicSuite installer/module-selection truth, and verify suite main. Can defer if consciously accepted: -- Add richer automated a11y tooling beyond current focus/landmark/browser checks in a later hardening sprint. + +- None needed for the source release candidate. Live Esri/CivicCode/CivicClerk/CivicPlan/CivicAccess integrations are not claimed by this module release; the shipped contract is local/adversarial integration validation. ## 5. Next-Sprint Watchlist -- Architecture: consider extracting staff workflow persistence into a shared repository pattern if more staff tables are added. -- Security and compliance debt: replace trusted-header shim with CivicAccess/CivicCore auth when that dependency is real. -- UX debt: make the resident lookup interactive against live configured local data in a future UI sprint. -- Docs debt: keep historical v0 browser QA notes separate from current v1 evidence. -- Install and bootstrap debt: add a city seed-data guide when real municipal fixture packs exist. -- Test debt: add automated contrast/a11y runner when the frontend becomes interactive. -- Operational and release debt: consider provenance signing parity with CivicCode in a later release-infra sprint. +- Architecture: consider shared trusted-header middleware for modules now that CivicCore auth is real. +- Security and compliance debt: add audit-event signing when suite-wide compliance logging is standardized. +- UX debt: add richer staff workflow filtering if city users need high-volume queues. +- Docs debt: keep historical recovery files clearly separate from current release evidence. +- Install and bootstrap debt: add municipal sample data import recipes when real fixture packs exist. +- Test debt: add automated axe/contrast checks if a frontend build tool is introduced. +- Operational and release debt: suite installer/module-selection truth must follow the source release before CivicZone is marked complete in the queue. ## 6. Engineering Deep Dive -Checked FastAPI routes, runtime helpers, staff workflow store, integration mocks, migrations, release scripts, and tests. The release-gate Critical was in staff workflow durability. It is fixed with SQLAlchemy-backed tables, hydration, migration `civiczone_0004_staff_workflows`, and persistence tests. +Checked FastAPI routes, package versioning, CivicCore dependency pin, UI render functions, release scripts, tests, workflows, and docs. The main code risk was changing staff auth while preserving API compatibility. The implementation now uses CivicCore trusted-proxy validation and keeps payload shapes unchanged. ## 7. Security And Authorization Deep Dive -Checked trusted principal/role header behavior, resident/staff boundaries, staff-only response visibility, secret search, and live endpoint rejection. Staff auth remains a trusted-access-layer integration boundary, documented as such; no production tokens or private keys were found. +Checked staff auth source enforcement, role checks, public/staff leakage, secret scan, and external-call rejection. Staff headers are accepted only from a trusted proxy/source, with loopback default for local development and `CIVICZONE_STAFF_TRUSTED_PROXY_CIDRS` for shared deployments. ## 8. UI/UX Deep Dive -Checked `/civiczone` at desktop and mobile widths with Playwright. Evidence saved: `docs/qa/civiczone-v1-public-desktop.png`, `docs/qa/civiczone-v1-public-mobile.png`, and `docs/qa/civiczone-v1-browser-qa.md`. Console errors: zero. Keyboard focus: skip link and API docs link. +Checked resident lookup and staff workspace at desktop and mobile widths. Loading, success, empty, error, and partial states render with actionable copy. Console is clean after the favicon fix. Focus order is recorded and usable. ## 9. Product/PM Deep Dive -Checked CivicSuite scope against current runtime. Product promise is now accurate: informational zoning context, citations, escalation, staff workflows, local integration mocks, and no official determinations. +CivicZone fits the spec promise: routine parcel-aware zoning context with citations, escalation for judgment calls, and staff review support. It does not overclaim official determinations or live integrations. ## 10. Documentation Deep Dive -Checked README, changelog, user manual, security note, docs index, release workflow, careful-coding evidence, and browser evidence. Docs now match implemented route names and persistence behavior. +Checked README, README.txt, manual, security note, changelog, docs index, implementation plan, milestones, recovery status, and QA docs. Current-facing docs now use `1.0.0` and CivicCore `1.1.0`. ## 11. Install / Bootstrap / Seeding Deep Dive -Checked local editable install path, WSL release path, deterministic sample mode, optional database configuration, and Docker-backed migrations. No external deployment proof is required; adversarial mocks are used for integration behavior. +Checked editable install/release gate, deterministic sample mode, optional DB configuration, migrations, and release artifacts. No external deployment proof is claimed here; suite installer/module-selection evidence is the required follow-through after the source release. ## 12. Version And Release Consistency Deep Dive -Checked `pyproject.toml`, `civiczone/__init__.py`, docs, release gate, wheel, sdist, and checksum generation. All current release surfaces are `1.0.0`. +Checked `pyproject.toml`, `civiczone/__init__.py`, `/health`, tests, scripts, docs, workflows, wheel, sdist, and SHA256SUMS. All current release surfaces are synchronized to `1.0.0` and CivicCore `1.1.0`. ## 13. Test Engineering Deep Dive -Checked test collection and execution. `scripts/verify-release.sh` reports 65 passed tests, including Docker pgvector migration coverage, resident safety tests, adversarial integration mocks, staff authorization, and staff persistence. +`python -m pytest -q` passed with 71 tests. Coverage includes runtime routes, migrations, parcel/rule lookup, Q&A, staff workflows, persistence, adversarial mocks, public/staff UI shells, and auth boundaries. ## 14. Runtime QA Deep Dive -Checked WSL release verification, local browser runtime, console output, and focus behavior. Runtime sign-off is high for local/mock v1 release scope. +Uvicorn served the app locally. Browser QA covered resident/staff desktop and mobile paths, console output, keyboard/focus, no horizontal overflow, and UI states. Evidence is saved under `docs/qa/`. ## 15. Cross-Cutting Synthesis -CivicZone is ready for push and PR CI as a v1.0.0 release candidate. The one material release-gate issue was found, fixed, and reverified before publication. +CivicZone source is ready for PR and CI. The current release candidate materially improves trust by replacing static public evidence with real browser workflows and hardening staff access through CivicCore auth helpers. ## 16. Verification Gaps And Sign-Off Limits -No external deployment proof was performed by directive. Live vendor integrations are not claimed. CivicAccess/CivicCore production auth is represented by trusted local headers until the shared auth module exists. +This audit does not claim suite-level installer/module-selection completion, a GitHub release tag, live vendor integrations, external municipal validation, airgap testing, or macOS lifecycle certification. Those must not be claimed until separately proven. diff --git a/docs/qa/civiczone-v1-staff-desktop-answer.png b/docs/qa/civiczone-v1-staff-desktop-answer.png new file mode 100644 index 0000000..872d318 Binary files /dev/null and b/docs/qa/civiczone-v1-staff-desktop-answer.png differ diff --git a/docs/qa/civiczone-v1-staff-desktop-auth-error.png b/docs/qa/civiczone-v1-staff-desktop-auth-error.png new file mode 100644 index 0000000..0f45ff8 Binary files /dev/null and b/docs/qa/civiczone-v1-staff-desktop-auth-error.png differ diff --git a/docs/qa/civiczone-v1-staff-desktop-console.json b/docs/qa/civiczone-v1-staff-desktop-console.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/docs/qa/civiczone-v1-staff-desktop-console.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/docs/qa/civiczone-v1-staff-desktop-ready.png b/docs/qa/civiczone-v1-staff-desktop-ready.png new file mode 100644 index 0000000..4e30f67 Binary files /dev/null and b/docs/qa/civiczone-v1-staff-desktop-ready.png differ diff --git a/docs/qa/civiczone-v1-staff-desktop-workflows.png b/docs/qa/civiczone-v1-staff-desktop-workflows.png new file mode 100644 index 0000000..720152d Binary files /dev/null and b/docs/qa/civiczone-v1-staff-desktop-workflows.png differ diff --git a/docs/qa/civiczone-v1-staff-mobile-answer.png b/docs/qa/civiczone-v1-staff-mobile-answer.png new file mode 100644 index 0000000..ca3e1d2 Binary files /dev/null and b/docs/qa/civiczone-v1-staff-mobile-answer.png differ diff --git a/docs/qa/civiczone-v1-staff-mobile-ready.png b/docs/qa/civiczone-v1-staff-mobile-ready.png new file mode 100644 index 0000000..cb5c5f4 Binary files /dev/null and b/docs/qa/civiczone-v1-staff-mobile-ready.png differ diff --git a/docs/release-recovery-status.md b/docs/release-recovery-status.md index 52ddcfd..699f328 100644 --- a/docs/release-recovery-status.md +++ b/docs/release-recovery-status.md @@ -1,23 +1,22 @@ # CivicZone Release Recovery Status -Date: 2026-05-09 +Date: 2026-05-21 Repo: `CivicSuite/civiczone` ## Current Verdict -`v1.0.0` exists as a published label. The suite release-recovery pass has now -rechecked the repo with the local release gate, live browser QA, documentation -truth checks, build artifacts, and current CivicCore v1.0.0 dependency -alignment. The original release date remains historical; this file records the -fresh recovery evidence. +CivicZone has moved from the demoted `0.2.0` recovery posture to the active +`1.0.0` public-use module release path. The prior recovery pass remains +historical context; current release evidence is recorded in the v1 release +evidence and browser QA files generated by the active run. ## Recovery Gates | Gate | Current status | Evidence | | --- | --- | --- | -| Public claim recovery | Passing locally | README, text README, user manual, docs landing page, changelog, and docs checks now describe the recovered v0.2.0 recovery label without overstating legal advice, official determinations, or live vendor behavior. | +| Public claim recovery | Passing locally | README, text README, user manual, docs landing page, changelog, and docs checks now describe the active v1.0.0 release without overstating legal advice, official determinations, or live vendor behavior. | | Native WSL/Linux proof | Historical pass | WSL selected `.venv-wsl/bin/python3`, reported platform `linux`, and completed `VERIFY-RELEASE: PASSED`. | -| Runtime install proof | Historical pass | Fresh WSL editable install succeeded after switching to the published CivicCore v1.0.0 release wheel and enabling direct references in Hatch metadata. | +| Runtime install proof | Historical pass | Fresh WSL editable install succeeded after switching to the published CivicCore release wheel and enabling direct references in Hatch metadata. Current release alignment is CivicCore v1.1.0. | | Security scan | Historical pass | Tracked-file secret scan returned no matches. | | Docs-source enforcement | Passing locally | `scripts/verify-docs.sh` blocks stale product-release claims. | | Mock-vs-production labeling | Passing locally | Existing docs distinguish local adversarial mocks, no legal advice, no official zoning determinations, and no live vendor calls by default. | @@ -39,7 +38,7 @@ fresh recovery evidence. ## Sign-Off Boundary -This recovery status does not erase or rewrite the existing `1.0.0` package -version. It changes the public posture: CivicZone's current `v1.0.0` code path -has fresh local release-gate and browser evidence. Remote PR/CI evidence is the -remaining publication step for this recovery update. +This file is retained as the recovery-history pointer. Current `1.0.0` release +evidence must come from the active CivicZone v1.0.0 run, current release gate, +browser QA, GitHub CI, release artifacts, and suite installer/module-selection +truth. diff --git a/pyproject.toml b/pyproject.toml index 818117a..038fd5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "civiczone" -version = "0.2.0" +version = "1.0.0" description = "CivicZone runtime foundation for parcel-aware zoning and land-use Q&A." readme = "README.md" requires-python = ">=3.11" @@ -13,7 +13,7 @@ authors = [ { name = "CivicSuite contributors" } ] dependencies = [ - "civiccore @ https://github.com/CivicSuite/civiccore/releases/download/v1.0.1/civiccore-1.0.1-py3-none-any.whl#sha256=561d7a8f73260d50de79351d330876d2cb3488c0e046a2888e82fe09d1e03969", + "civiccore @ https://github.com/CivicSuite/civiccore/releases/download/v1.1.0/civiccore-1.1.0-py3-none-any.whl#sha256=3ab146f4fea2ae99640d5b1b013be1a9676de5f91b783eaeaa913043a2ae2b87", "fastapi>=0.115.0,<1.0.0", "uvicorn[standard]>=0.30.0,<1.0.0", ] diff --git a/scripts/check-civiccore-placeholder-imports.py b/scripts/check-civiccore-placeholder-imports.py index 51e91a6..bdeac4c 100644 --- a/scripts/check-civiccore-placeholder-imports.py +++ b/scripts/check-civiccore-placeholder-imports.py @@ -6,7 +6,6 @@ PLACEHOLDERS = { "audit", - "auth", "catalog", "connectors", "exemptions", @@ -32,7 +31,7 @@ def main() -> int: package = match.group(1) if package in PLACEHOLDERS: failures.append( - f"{path}: civiccore.{package} is a placeholder package in v0.2.0. " + f"{path}: civiccore.{package} is still treated as a placeholder package for CivicZone v1. " "See AGENTS.md section 3.1." ) diff --git a/scripts/verify-docs.sh b/scripts/verify-docs.sh index b468d89..8175a84 100755 --- a/scripts/verify-docs.sh +++ b/scripts/verify-docs.sh @@ -70,6 +70,8 @@ bad_markers=( "v0.2.0 recovery release" "0.2.0 recovery release" "current product release" + "current state: published v0.2.0" + "recovery label recovered" ) for file in "${current_files[@]}"; do diff --git a/scripts/verify-release.sh b/scripts/verify-release.sh index b73f1eb..684aa29 100755 --- a/scripts/verify-release.sh +++ b/scripts/verify-release.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -VERSION="0.2.0" +VERSION="1.0.0" find_python() { local candidates=() @@ -40,7 +40,7 @@ ${PYTHON_BIN} - <<'PY' from pathlib import Path import tomllib -version = "0.2.0" +version = "1.0.0" root = Path(".") pyproject = tomllib.loads((root / "pyproject.toml").read_text(encoding="utf-8")) assert pyproject["project"]["version"] == version, pyproject["project"]["version"] @@ -56,7 +56,7 @@ for path in [ "SECURITY.md", ]: text = (root / path).read_text(encoding="utf-8") - assert "0.2.0" in text, f"missing release version in {path}" + assert "1.0.0" in text, f"missing release version in {path}" assert "0.1.0.dev0" not in text, f"stale dev version in {path}" print("PASS: version surfaces synchronized") PY @@ -81,8 +81,8 @@ from pathlib import Path import hashlib dist = Path("dist") -wheel = dist / "civiczone-0.2.0-py3-none-any.whl" -sdist = dist / "civiczone-0.2.0.tar.gz" +wheel = dist / "civiczone-1.0.0-py3-none-any.whl" +sdist = dist / "civiczone-1.0.0.tar.gz" assert wheel.exists(), f"missing {wheel}" assert sdist.exists(), f"missing {sdist}" lines = [] diff --git a/tests/test_milestone_6_planner_staff_context.py b/tests/test_milestone_6_planner_staff_context.py index 97125e6..9ed0bd8 100644 --- a/tests/test_milestone_6_planner_staff_context.py +++ b/tests/test_milestone_6_planner_staff_context.py @@ -5,7 +5,7 @@ from civiczone.staff_context import classify_for_planner_review, get_staff_precedent -client = TestClient(app) +client = TestClient(app, client=("127.0.0.1", 50000)) def test_variance_question_escalates_to_planner_review() -> None: diff --git a/tests/test_milestone_7_public_ui_accessibility.py b/tests/test_milestone_7_public_ui_accessibility.py index 4dc1a2a..93ce9b2 100644 --- a/tests/test_milestone_7_public_ui_accessibility.py +++ b/tests/test_milestone_7_public_ui_accessibility.py @@ -16,24 +16,24 @@ def test_public_ui_route_returns_accessible_html() -> None: assert '' in text assert '' in text assert '
' in text - assert "aria-label=\"Current product state\"" in text assert "aria-live=\"polite\"" in text - assert "v0.2.0 cited zoning lookup" in text - assert "Run lookup' in text -def test_public_ui_shows_sample_outputs_and_citations() -> None: +def test_public_ui_shows_real_api_workflow_bindings() -> None: response = client.get("/civiczone") text = response.text assert "123 Main St" in text assert "100-200-300" in text - assert "R-2 Residential District" in text - assert "Historic District Overlay" in text - assert "Sample Zoning Code" in text - assert "§" not in text - assert "Conditional use review" in text - assert "20-foot front setback" in text + assert "sample city dataset" in text + assert "R-2" in text + assert "ADU" in text + assert "§" not in text + assert "fetch(" in text + assert "/api/v1/civiczone/parcels/lookup" in text + assert "/api/v1/civiczone/questions/answer" in text def test_public_ui_keeps_boundaries_actionable_and_honest() -> None: @@ -43,9 +43,20 @@ def test_public_ui_keeps_boundaries_actionable_and_honest() -> None: assert "does not provide legal advice" in text assert "does not make a zoning determination" in text assert "does not replace your planning department" in text - assert "routes judgment calls" in text - assert "No parcel was found" in text - assert "Staff-only precedent context is kept out" in text + assert "Missing parcels explain" in text + assert "Staff workspace" in text assert "Shipping v0.1.0" not in text assert "v0.1.0 public UI foundation" not in text assert "zoning determinations are available" not in text + + +def test_staff_ui_route_returns_browser_shell_without_embedded_staff_data() -> None: + response = client.get("/civiczone/staff") + text = response.text + + assert response.status_code == 200 + assert "CivicZone staff workspace" in text + assert "X-CivicZone-Principal" in text + assert "X-CivicZone-Role" in text + assert "/api/v1/civiczone/staff/questions/answer" in text + assert "staff_only" not in text diff --git a/tests/test_runtime_foundation.py b/tests/test_runtime_foundation.py index 4936ad3..f11629e 100644 --- a/tests/test_runtime_foundation.py +++ b/tests/test_runtime_foundation.py @@ -12,7 +12,7 @@ def test_package_version_is_100() -> None: - assert civiczone.__version__ == "0.2.0" + assert civiczone.__version__ == "1.0.0" def test_pyproject_uses_published_civiccore_release_wheel() -> None: @@ -22,9 +22,9 @@ def test_pyproject_uses_published_civiccore_release_wheel() -> None: assert data["tool"]["hatch"]["metadata"]["allow-direct-references"] is True assert ( "civiccore @ https://github.com/CivicSuite/civiccore/releases/download/" - "v1.0.1/civiccore-1.0.1-py3-none-any.whl#sha256=561d7a8f73260d50de79351d330876d2cb3488c0e046a2888e82fe09d1e03969" + "v1.1.0/civiccore-1.1.0-py3-none-any.whl#sha256=3ab146f4fea2ae99640d5b1b013be1a9676de5f91b783eaeaa913043a2ae2b87" ) in dependencies - assert "civiccore==1.0.1" not in dependencies + assert "civiccore==1.1.0" not in dependencies def test_root_endpoint_states_runtime_boundary() -> None: @@ -33,13 +33,13 @@ def test_root_endpoint_states_runtime_boundary() -> None: payload = response.json() assert payload["name"] == "CivicZone" - assert payload["version"] == "0.2.0" + assert payload["version"] == "1.0.0" assert payload["status"] == "v1 parcel-aware zoning Q&A runtime" assert "optional database-backed parcel/rule" in payload["message"] assert "staff workflow APIs" in payload["message"] assert "does not make zoning determinations" in payload["message"] assert payload["next_step"].startswith("Configure local parcel/rule data") - assert "trusted municipal access layer" in payload["next_step"] + assert "trusted staff proxy CIDR list" in payload["next_step"] def test_health_endpoint_reports_versions() -> None: @@ -49,8 +49,8 @@ def test_health_endpoint_reports_versions() -> None: assert payload["status"] == "ok" assert payload["service"] == "civiczone" - assert payload["version"] == "0.2.0" - assert payload["civiccore_version"] == "1.0.1" + assert payload["version"] == "1.0.0" + assert payload["civiccore_version"] == "1.1.0" def test_release_gate_prefers_native_unix_python_before_windows_launcher() -> None: @@ -66,8 +66,8 @@ def test_release_gate_prefers_native_unix_python_before_windows_launcher() -> No def test_documentation_gate_blocks_stale_product_release_claims() -> None: script = (ROOT / "scripts" / "verify-docs.sh").read_text(encoding="utf-8") - assert "v0.2.0 recovery release" in script - assert "0.2.0 recovery release" in script + assert "current state: published v0.2.0" in script + assert "recovery label recovered" in script assert "current product release" in script @@ -82,6 +82,5 @@ def test_current_docs_mark_v1_label_as_recovered_without_product_release_overcla for path, text in docs.items(): lowered = text.lower() - assert "release-recovery" in lowered, path + assert "1.0.0" in lowered, path assert "provisional" not in lowered, path - assert "product release" not in lowered, path diff --git a/tests/test_staff_workflow_api.py b/tests/test_staff_workflow_api.py index 64dd272..91af04a 100644 --- a/tests/test_staff_workflow_api.py +++ b/tests/test_staff_workflow_api.py @@ -5,7 +5,8 @@ from civiczone.main import app -client = TestClient(app) +client = TestClient(app, client=("127.0.0.1", 50000)) +untrusted_client = TestClient(app, client=("203.0.113.10", 50000)) STAFF_HEADERS = {"X-CivicZone-Principal": "planner@example.gov", "X-CivicZone-Role": "staff"} RESIDENT_HEADERS = {"X-CivicZone-Principal": "resident@example.gov", "X-CivicZone-Role": "resident"} @@ -36,6 +37,18 @@ def test_staff_workflow_api_rejects_missing_and_underprivileged_auth() -> None: ] +def test_staff_workflow_api_rejects_spoofed_headers_from_untrusted_source() -> None: + response = untrusted_client.post( + "/api/v1/civiczone/staff/questions/answer", + json={"zone_code": "R-2", "question": "What is the front setback?"}, + headers=STAFF_HEADERS, + ) + + assert response.status_code == 403 + assert "approved proxy" in response.json()["detail"]["message"] + assert "strip client-supplied copies" in response.json()["detail"]["fix"] + + def test_planner_question_answer_returns_code_cross_references() -> None: response = client.post( "/api/v1/civiczone/staff/questions/answer",