diff --git a/.github/workflows/cleanroom.yml b/.github/workflows/cleanroom.yml index 486d63d..fe98aab 100644 --- a/.github/workflows/cleanroom.yml +++ b/.github/workflows/cleanroom.yml @@ -22,7 +22,7 @@ on: jobs: cleanroom: - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest timeout-minutes: 90 permissions: contents: read diff --git a/.github/workflows/release-preflight.yml b/.github/workflows/release-preflight.yml index 19e4a32..2db5b29 100644 --- a/.github/workflows/release-preflight.yml +++ b/.github/workflows/release-preflight.yml @@ -38,7 +38,7 @@ on: jobs: preflight-release-provenance: - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest permissions: contents: read defaults: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fd2a51..f123af7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ on: release_tag: description: "Published release tag to rehearse from cold caches" required: true - default: "v1.0.3" + default: "v1.0.4" permissions: contents: write @@ -104,7 +104,7 @@ jobs: preflight: name: Preflight release provenance fixtures if: github.event_name == 'push' - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest defaults: run: working-directory: civicclerk-release-${{ github.run_id }} @@ -130,7 +130,7 @@ jobs: verify-build: if: github.event_name == 'push' - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest needs: preflight defaults: run: @@ -144,6 +144,9 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.11" + - uses: actions/setup-node@v5 + with: + node-version: "22" - name: Install CivicCore freeze release wheel run: python -m pip install https://github.com/CivicSuite/civiccore/releases/download/v1.2.0/civiccore-1.2.0-py3-none-any.whl - name: Install package and test dependencies @@ -213,7 +216,7 @@ jobs: name: Create draft GitHub Release if: github.event_name == 'push' needs: [verify-build] - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest defaults: run: working-directory: civicclerk-release-${{ github.run_id }} @@ -381,7 +384,7 @@ jobs: name: Publish GitHub Release if: github.event_name == 'push' needs: [release-cleanroom-rehearsal] - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest steps: - name: Publish release after cleanroom rehearsal env: diff --git a/CHANGELOG.md b/CHANGELOG.md index c093d4b..2bdf20f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to CivicClerk are documented here. ## [Unreleased] +## [1.0.4] - 2026-06-13 + ### Added - Added the live CivicCode handoff emitter for adopted ordinance/resolution handoffs. When `CIVICCODE_INTAKE_URL` and the suite bearer handoff value are @@ -11,16 +13,27 @@ All notable changes to CivicClerk are documented here. intake contract with bearer authorization, records delivered/failed/ unconfigured status on the local handoff record, and exposes a manual retry endpoint for operator-controlled recovery. +- Added Persistence Phase 1 for the public-meeting legal record: motions, + votes, action items, minutes drafts, public archive records, and resident + comments can now persist through the configured database-backed repositories, + with an HTTP-level restart-survival test covering the full record path. ### Changed - Staff bearer mode now accepts CivicCore suite session bearer tokens for `/staff/session` while preserving the legacy configured-token path. - Integration-depth readiness metadata now distinguishes live-wire or in-process boundary validation from supplemental adversarial mock checks. +- Moved CivicClerk CI, cleanroom, release-preflight, and release publication + jobs to GitHub-hosted `ubuntu-latest` runners; release frontend verification + now pins Node 22 and installs only the Playwright headless Chromium shell. ### Fixed - Isolated the static staff workflow UI test from process-local meeting outcome records so the full release gate verifies the empty-state contract reliably. +- Serialized audit-chain writes across the persistence repositories, appended + events only after database commits, normalized blank DB URL environment + values to in-memory fallback, and gated public comment intake on database + truth instead of caller-supplied snapshots. ## [1.0.3] - 2026-05-23 diff --git a/README.md b/README.md index 21b6cbf..641ac7c 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ **CivicClerk is the CivicSuite module for municipal meetings, agendas, packets, minutes, votes, notices, and public meeting archives.** -Status: CivicClerk v1.0.3 runtime foundation label is provisional during the CivicSuite release recovery. -Current version: `1.0.3` +Status: CivicClerk v1.0.4 runtime foundation label is provisional during the CivicSuite release recovery. +Current version: `1.0.4` Repository: Depends on: published, Sigstore-attested `civiccore` 1.2.0 wheel from the `v1.2.0` release asset ## Release Recovery Notice CivicClerk is not product-ready for public promotion while the CivicSuite -release recovery is active. Treat the current `v1.0.3` recovery patch +release recovery is active. Treat the current `v1.0.4` recovery patch as provisional until this repo re-earns release status through the recovery gates: full local backend tests, frontend unit tests, real Playwright user-flow tests, WSL runtime install proof, release consistency checks, secret/security @@ -303,7 +303,7 @@ Shipped in this foundation: "Windows protected your PC" first-install experience, why this small free open-source project ships unsigned installers, and when it is OK to choose "More info" -> "Run anyway" -- CivicClerk v1.0.3 release gate and build artifacts +- CivicClerk v1.0.4 release gate and build artifacts - `scripts/start_fresh_install_rehearsal.ps1` to rehearse the documented Windows-first wheel install and first-run smoke checks from an isolated `.fresh-install-rehearsal` virtual environment @@ -406,7 +406,7 @@ A new user can inspect and run the foundation, open staff workflow screens at `/ python -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install --upgrade pip - python -m pip install dist/civicclerk-1.0.3-py3-none-any.whl + python -m pip install dist/civicclerk-1.0.4-py3-none-any.whl ``` 5. Start the FastAPI app from the installed package: @@ -417,7 +417,7 @@ A new user can inspect and run the foundation, open staff workflow screens at `/ ``` 6. Confirm the fresh-machine smoke-check path: - - `GET http://127.0.0.1:8776/health` must return `{"status":"ok","service":"civicclerk","version":"1.0.3","civiccore":"1.2.0"}` + - `GET http://127.0.0.1:8776/health` must return `{"status":"ok","service":"civicclerk","version":"1.0.4","civiccore":"1.2.0"}` - `GET http://127.0.0.1:8776/staff/auth-readiness` must report `mode: "protected"` and explain that anonymous staff writes are denied until OIDC, bearer, or trusted-header deployment is configured - Open `http://127.0.0.1:8776/staff` and confirm the first workflow shell loads - In the Docker product path, open `http://127.0.0.1:8080/public` and confirm the React resident public portal loads official agenda, packet, and approved-minutes sections without exposing restricted-session existence. @@ -500,7 +500,7 @@ empty rehearsal database. The Windows installer package under The installer is unsigned, local-rehearsal oriented, and still requires Docker Desktop; use OIDC, bearer, or trusted-header auth before any shared deployment. -The foundation is intentionally thin. Canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, agenda item lifecycle persistence, meeting lifecycle enforcement, meeting records, packet snapshot versioning, packet assembly records, notice checklist records, shared notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, prompt YAML/evaluation gates, local-first connector import normalization, browser QA gates, CivicClerk v1.0.3 release artifacts, and CivicCore v1.2.0 packet export, browser-evidence verification, connector runtime validation, and trusted-header config enforcement primitives are present. Minutes drafts require sentence-level citations, YAML prompt-version provenance, and human approval before acceptance, and they are never auto-adopted or auto-posted. Anonymous public archive endpoints do not reveal closed-session content in response bodies, counts, suggestions, or error messages. Connector imports record source provenance and do not require outbound network calls in the default local profile. The vendor live-sync foundation now validates proposed vendor source URLs without network calls, blocks credentials in URLs, persists source/run/failure state in `vendor_sync_sources`, `vendor_sync_run_log`, and `vendor_sync_failures`, computes source health as `healthy`, `degraded`, or `circuit_open`, persists `last_success_cursor_at`, plans connector-specific delta URLs from that cursor, advances it only after fully successful normalized pulls, and follows the CivicRecords AI circuit-breaker pattern of five consecutive full-run failures or two grace-period failures after unpause. Public packet exports block closed-session/restricted sources and include manifest, checksum, provenance, and audit evidence. Agenda item records now persist lifecycle status and CivicCore-verifiable transition audit hashes when `CIVICCLERK_AGENDA_ITEM_DB_URL` is configured, and ready agenda intake records can be promoted into those lifecycle records while preserving the generated agenda item id, promotion timestamp, and audit hash on the intake record. Meeting records now persist scheduled starts, meeting body ids, locations, normalized meeting type, lifecycle status, and CivicCore-verifiable transition and schedule-edit audit hashes when `CIVICCLERK_MEETING_DB_URL` is configured; schedule edits are allowed before the in-session lock point, write audit entries, and validate changed meeting body ids before accepting create/update requests. Vendor sync source, run, failure, and cursor state persist when `CIVICCLERK_VENDOR_SYNC_DB_URL` is configured; the API records operator state and no-network cursor resets without pulling vendors, while `scripts/run_vendor_live_sync.py` provides an explicitly enabled one-source pull runner that records outcomes in the same circuit-breaker ledger. Packet assembly records now persist source references, citations, linked packet snapshot ids, and durable audit hashes. Notice checklist records persist compliance outcomes, warnings, posting proof, and durable audit hashes. Browser QA now checks loading, success, empty, error, and partial states plus keyboard, focus, contrast, and console evidence, and release screenshots are bound to the current docs page through shared CivicCore verification helpers. CivicClerk v1.0.3 now pairs with the published `civiccore` 1.2.0 wheel from the `v1.2.0` release asset. The first staff auth foundation is now explicit: fresh installs default to `CIVICCLERK_STAFF_AUTH_MODE=protected` so anonymous staff writes are denied, local rehearsals can explicitly opt into `CIVICCLERK_STAFF_AUTH_MODE=open`, municipal identity-provider deployments can set `CIVICCLERK_STAFF_AUTH_MODE=oidc` plus issuer, audience, JWKS, role-claim, algorithm, authorization URL, token URL, client, redirect URI, and session-cookie-secret settings, bearer-protected pilots can set `CIVICCLERK_STAFF_AUTH_MODE=bearer` plus `CIVICCLERK_STAFF_AUTH_TOKEN_ROLES`, and trusted reverse-proxy deployments can set `CIVICCLERK_STAFF_AUTH_MODE=trusted_header` plus `CIVICCLERK_STAFF_SSO_PRINCIPAL_HEADER`, `CIVICCLERK_STAFF_SSO_ROLES_HEADER`, `CIVICCLERK_STAFF_SSO_PROVIDER`, and `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES`. The `/staff/auth-readiness` endpoint now tells operators whether those OIDC token-validation, OIDC browser-login, bearer, or trusted-proxy settings are merely present or actually deployment-ready, and it includes a loopback-only rehearsal recipe so trusted-header testing does not require inventing a custom proxy first. +The foundation is intentionally thin. Canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, agenda item lifecycle persistence, meeting lifecycle enforcement, meeting records, packet snapshot versioning, packet assembly records, notice checklist records, shared notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, prompt YAML/evaluation gates, local-first connector import normalization, browser QA gates, CivicClerk v1.0.4 release artifacts, and CivicCore v1.2.0 packet export, browser-evidence verification, connector runtime validation, and trusted-header config enforcement primitives are present. Minutes drafts require sentence-level citations, YAML prompt-version provenance, and human approval before acceptance, and they are never auto-adopted or auto-posted. Anonymous public archive endpoints do not reveal closed-session content in response bodies, counts, suggestions, or error messages. Connector imports record source provenance and do not require outbound network calls in the default local profile. The vendor live-sync foundation now validates proposed vendor source URLs without network calls, blocks credentials in URLs, persists source/run/failure state in `vendor_sync_sources`, `vendor_sync_run_log`, and `vendor_sync_failures`, computes source health as `healthy`, `degraded`, or `circuit_open`, persists `last_success_cursor_at`, plans connector-specific delta URLs from that cursor, advances it only after fully successful normalized pulls, and follows the CivicRecords AI circuit-breaker pattern of five consecutive full-run failures or two grace-period failures after unpause. Public packet exports block closed-session/restricted sources and include manifest, checksum, provenance, and audit evidence. Agenda item records now persist lifecycle status and CivicCore-verifiable transition audit hashes when `CIVICCLERK_AGENDA_ITEM_DB_URL` is configured, and ready agenda intake records can be promoted into those lifecycle records while preserving the generated agenda item id, promotion timestamp, and audit hash on the intake record. Meeting records now persist scheduled starts, meeting body ids, locations, normalized meeting type, lifecycle status, and CivicCore-verifiable transition and schedule-edit audit hashes when `CIVICCLERK_MEETING_DB_URL` is configured; schedule edits are allowed before the in-session lock point, write audit entries, and validate changed meeting body ids before accepting create/update requests. Vendor sync source, run, failure, and cursor state persist when `CIVICCLERK_VENDOR_SYNC_DB_URL` is configured; the API records operator state and no-network cursor resets without pulling vendors, while `scripts/run_vendor_live_sync.py` provides an explicitly enabled one-source pull runner that records outcomes in the same circuit-breaker ledger. Packet assembly records now persist source references, citations, linked packet snapshot ids, and durable audit hashes. Notice checklist records persist compliance outcomes, warnings, posting proof, and durable audit hashes. Browser QA now checks loading, success, empty, error, and partial states plus keyboard, focus, contrast, and console evidence, and release screenshots are bound to the current docs page through shared CivicCore verification helpers. CivicClerk v1.0.4 now pairs with the published `civiccore` 1.2.0 wheel from the `v1.2.0` release asset. The first staff auth foundation is now explicit: fresh installs default to `CIVICCLERK_STAFF_AUTH_MODE=protected` so anonymous staff writes are denied, local rehearsals can explicitly opt into `CIVICCLERK_STAFF_AUTH_MODE=open`, municipal identity-provider deployments can set `CIVICCLERK_STAFF_AUTH_MODE=oidc` plus issuer, audience, JWKS, role-claim, algorithm, authorization URL, token URL, client, redirect URI, and session-cookie-secret settings, bearer-protected pilots can set `CIVICCLERK_STAFF_AUTH_MODE=bearer` plus `CIVICCLERK_STAFF_AUTH_TOKEN_ROLES`, and trusted reverse-proxy deployments can set `CIVICCLERK_STAFF_AUTH_MODE=trusted_header` plus `CIVICCLERK_STAFF_SSO_PRINCIPAL_HEADER`, `CIVICCLERK_STAFF_SSO_ROLES_HEADER`, `CIVICCLERK_STAFF_SSO_PROVIDER`, and `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES`. The `/staff/auth-readiness` endpoint now tells operators whether those OIDC token-validation, OIDC browser-login, bearer, or trusted-proxy settings are merely present or actually deployment-ready, and it includes a loopback-only rehearsal recipe so trusted-header testing does not require inventing a custom proxy first. The staff experience at `/staff` now includes a product cockpit plus first workflow screens for agenda intake, packet assembly/export, notice checklist/posting-proof, meeting outcome, minutes draft, public archive, connector import, and vendor sync work. It is intentionally honest: the cockpit gives clerks a day-at-a-glance desk, reads the live agenda intake queue for ready/pending/needs-revision counts, the Agenda Intake, Packet Assembly, Notice Checklist, Meeting Outcomes, Minutes Draft, and Vendor Sync panels render live queue/record rows with escaped user-submitted titles where applicable and actionable empty/unavailable-store rows, the workflow screens can submit their corresponding live API actions, the auth panel now renders concrete protected-session and protected-write probes from `/staff/auth-readiness` when OIDC, bearer, or trusted-header mode is ready, it surfaces the loopback-only local proxy rehearsal command and env vars when trusted-header mode is being staged, and the broader multi-role React clerk console is now beginning under `frontend/`. The React slice uses the CivicSuite mockup direction for a real staff shell, meeting body management, meeting scheduling, meeting calendar, lifecycle ribbon, audit/evidence drawer, pre-lock schedule editing, Agenda Intake submit/review/promotion, Packet Builder promoted-item selection, packet draft creation, per-meeting queue review, packet finalization, Notice Checklist statutory deadline review, legal-blocker copy, posting-proof attachment, immutable audit-hash evidence, Public Posting resident-safe list/detail/search, Meeting Outcomes motion/vote/action capture with immutable-record guidance, Minutes Draft source/citation/provenance capture, Vendor Sync source-health/circuit-breaker/cursor visibility with no-network run logging and full-reconciliation reset guidance, and no-dead-end QA states. The Docker profile now seeds Brookfield demo data so city IT can open the React app and see live work immediately; the unsigned Windows installer wraps that same stack for install/repair and daily start. The resident-facing `/public` route in the nginx product path now opens the React public portal directly, loads public calendar records, public-safe detail, and anonymous archive search from the live public APIs, and keeps restricted-session existence, counts, and summaries out of resident copy. @@ -508,11 +508,11 @@ For Windows installer packaging, `install.ps1` is the install/repair entrypoint For the first real trusted-header deployment handoff, `docs/examples/trusted-header-nginx.conf` now ships a reference nginx bridge that strips client-supplied identity headers, sets proxy-owned staff headers, and points operators back to `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES` plus the `/staff/auth-readiness` contract before live staff traffic is trusted. -For fresh Windows install rehearsals, `scripts/start_fresh_install_rehearsal.ps1` now prints and can execute the documented wheel-install path from an isolated `.fresh-install-rehearsal` virtual environment: create venv, upgrade pip, install `dist/civicclerk-1.0.3-py3-none-any.whl`, set `CIVICCLERK_STAFF_AUTH_MODE=protected`, launch the installed app on `127.0.0.1:8776`, verify `/health`, verify `/staff/auth-readiness`, and fetch `/staff`. If the wheel is missing, the helper tells the operator to build it with `python -m build` before trying again. +For fresh Windows install rehearsals, `scripts/start_fresh_install_rehearsal.ps1` now prints and can execute the documented wheel-install path from an isolated `.fresh-install-rehearsal` virtual environment: create venv, upgrade pip, install `dist/civicclerk-1.0.4-py3-none-any.whl`, set `CIVICCLERK_STAFF_AUTH_MODE=protected`, launch the installed app on `127.0.0.1:8776`, verify `/health`, verify `/staff/auth-readiness`, and fetch `/staff`. If the wheel is missing, the helper tells the operator to build it with `python -m build` before trying again. For fresh Bash install rehearsals on Linux, macOS, or Git Bash, `scripts/start_fresh_install_rehearsal.sh` now prints and can execute the same wheel-install path from an isolated `.fresh-install-rehearsal/.venv`, with the same `/health`, `/staff/auth-readiness`, `/staff`, missing-wheel, occupied-port, and Python `venv` prerequisite checks as the Windows helper. On Debian or Ubuntu, install `python3-venv` before executing the helper. -For IT release handoff, `scripts/build_release_handoff_bundle.ps1` and `scripts/build_release_handoff_bundle.sh` now print and can create `dist/civicclerk-1.0.3-release-handoff.zip` containing the built wheel, source distribution, checksums, current README/manual/changelog/license, docs landing page, deployment env profile example, installer-readiness helper, enterprise signing-readiness helper, connector sync readiness helper, vendor live-sync readiness helper, protected deployment smoke helper, trusted-header nginx reference, and the fresh-install/protected-demo rehearsal helpers. Both helpers intentionally refuse to overwrite an existing bundle and they are release-input zips, not setup executables; build artifacts first with `bash scripts/verify-release.sh`. After the zip exists, `python scripts/check_installer_readiness.py` verifies the handoff bundle before the Windows setup package is built or handed to IT. +For IT release handoff, `scripts/build_release_handoff_bundle.ps1` and `scripts/build_release_handoff_bundle.sh` now print and can create `dist/civicclerk-1.0.4-release-handoff.zip` containing the built wheel, source distribution, checksums, current README/manual/changelog/license, docs landing page, deployment env profile example, installer-readiness helper, enterprise signing-readiness helper, connector sync readiness helper, vendor live-sync readiness helper, protected deployment smoke helper, trusted-header nginx reference, and the fresh-install/protected-demo rehearsal helpers. Both helpers intentionally refuse to overwrite an existing bundle and they are release-input zips, not setup executables; build artifacts first with `bash scripts/verify-release.sh`. After the zip exists, `python scripts/check_installer_readiness.py` verifies the handoff bundle before the Windows setup package is built or handed to IT. For connector import operations, `python scripts/check_connector_sync_readiness.py` verifies the supported Granicus, Legistar, PrimeGov, and NovusAGENDA local payload contracts without outbound network calls. It can also validate a proposed `--source-url` or `--odbc-connection-string` through the shared CivicCore host guards before vendor-network live sync is designed. `python scripts/check_vendor_live_sync_readiness.py --connector legistar --source-url https://vendor.example.gov/api/meetings --auth-method bearer_token` checks the first live-sync source contract, rejects credentials in URLs, previews `healthy`/`degraded`/`circuit_open`, and simulates the circuit breaker without contacting the vendor. With `CIVICCLERK_VENDOR_SYNC_DB_URL` set, `POST /vendor-live-sync/sources` saves a validated source and `POST /vendor-live-sync/sources/{id}/run-log` records success, partial, or failed run outcomes into the durable no-network ledger; `GET /vendor-live-sync/sources` and `GET /vendor-live-sync/sources/{id}/run-log` expose the operator health state and actionable fix text. When IT has exported local JSON files, `python scripts/run_connector_import_sync.py --payload-dir path\to\exports --output connector-import-ledger.json` normalizes `.json` or `/*.json` payloads through the same import contract and writes a provenance ledger. In the Docker product path, IT can enable the same local-first normalization on a schedule with `CIVICCLERK_CONNECTOR_SYNC_ENABLED=true`, drop approved exports into `CIVICCLERK_CONNECTOR_SYNC_PAYLOAD_DIR_HOST`, and review the ledger at `CIVICCLERK_CONNECTOR_SYNC_LEDGER_PATH`. This scheduled local export-drop sync still does not contact vendors, and the vendor live-sync ledger does not contact vendors until a later adapter/scheduled-pull slice is built. diff --git a/README.txt b/README.txt index 21b6cbf..641ac7c 100644 --- a/README.txt +++ b/README.txt @@ -2,15 +2,15 @@ **CivicClerk is the CivicSuite module for municipal meetings, agendas, packets, minutes, votes, notices, and public meeting archives.** -Status: CivicClerk v1.0.3 runtime foundation label is provisional during the CivicSuite release recovery. -Current version: `1.0.3` +Status: CivicClerk v1.0.4 runtime foundation label is provisional during the CivicSuite release recovery. +Current version: `1.0.4` Repository: Depends on: published, Sigstore-attested `civiccore` 1.2.0 wheel from the `v1.2.0` release asset ## Release Recovery Notice CivicClerk is not product-ready for public promotion while the CivicSuite -release recovery is active. Treat the current `v1.0.3` recovery patch +release recovery is active. Treat the current `v1.0.4` recovery patch as provisional until this repo re-earns release status through the recovery gates: full local backend tests, frontend unit tests, real Playwright user-flow tests, WSL runtime install proof, release consistency checks, secret/security @@ -303,7 +303,7 @@ Shipped in this foundation: "Windows protected your PC" first-install experience, why this small free open-source project ships unsigned installers, and when it is OK to choose "More info" -> "Run anyway" -- CivicClerk v1.0.3 release gate and build artifacts +- CivicClerk v1.0.4 release gate and build artifacts - `scripts/start_fresh_install_rehearsal.ps1` to rehearse the documented Windows-first wheel install and first-run smoke checks from an isolated `.fresh-install-rehearsal` virtual environment @@ -406,7 +406,7 @@ A new user can inspect and run the foundation, open staff workflow screens at `/ python -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install --upgrade pip - python -m pip install dist/civicclerk-1.0.3-py3-none-any.whl + python -m pip install dist/civicclerk-1.0.4-py3-none-any.whl ``` 5. Start the FastAPI app from the installed package: @@ -417,7 +417,7 @@ A new user can inspect and run the foundation, open staff workflow screens at `/ ``` 6. Confirm the fresh-machine smoke-check path: - - `GET http://127.0.0.1:8776/health` must return `{"status":"ok","service":"civicclerk","version":"1.0.3","civiccore":"1.2.0"}` + - `GET http://127.0.0.1:8776/health` must return `{"status":"ok","service":"civicclerk","version":"1.0.4","civiccore":"1.2.0"}` - `GET http://127.0.0.1:8776/staff/auth-readiness` must report `mode: "protected"` and explain that anonymous staff writes are denied until OIDC, bearer, or trusted-header deployment is configured - Open `http://127.0.0.1:8776/staff` and confirm the first workflow shell loads - In the Docker product path, open `http://127.0.0.1:8080/public` and confirm the React resident public portal loads official agenda, packet, and approved-minutes sections without exposing restricted-session existence. @@ -500,7 +500,7 @@ empty rehearsal database. The Windows installer package under The installer is unsigned, local-rehearsal oriented, and still requires Docker Desktop; use OIDC, bearer, or trusted-header auth before any shared deployment. -The foundation is intentionally thin. Canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, agenda item lifecycle persistence, meeting lifecycle enforcement, meeting records, packet snapshot versioning, packet assembly records, notice checklist records, shared notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, prompt YAML/evaluation gates, local-first connector import normalization, browser QA gates, CivicClerk v1.0.3 release artifacts, and CivicCore v1.2.0 packet export, browser-evidence verification, connector runtime validation, and trusted-header config enforcement primitives are present. Minutes drafts require sentence-level citations, YAML prompt-version provenance, and human approval before acceptance, and they are never auto-adopted or auto-posted. Anonymous public archive endpoints do not reveal closed-session content in response bodies, counts, suggestions, or error messages. Connector imports record source provenance and do not require outbound network calls in the default local profile. The vendor live-sync foundation now validates proposed vendor source URLs without network calls, blocks credentials in URLs, persists source/run/failure state in `vendor_sync_sources`, `vendor_sync_run_log`, and `vendor_sync_failures`, computes source health as `healthy`, `degraded`, or `circuit_open`, persists `last_success_cursor_at`, plans connector-specific delta URLs from that cursor, advances it only after fully successful normalized pulls, and follows the CivicRecords AI circuit-breaker pattern of five consecutive full-run failures or two grace-period failures after unpause. Public packet exports block closed-session/restricted sources and include manifest, checksum, provenance, and audit evidence. Agenda item records now persist lifecycle status and CivicCore-verifiable transition audit hashes when `CIVICCLERK_AGENDA_ITEM_DB_URL` is configured, and ready agenda intake records can be promoted into those lifecycle records while preserving the generated agenda item id, promotion timestamp, and audit hash on the intake record. Meeting records now persist scheduled starts, meeting body ids, locations, normalized meeting type, lifecycle status, and CivicCore-verifiable transition and schedule-edit audit hashes when `CIVICCLERK_MEETING_DB_URL` is configured; schedule edits are allowed before the in-session lock point, write audit entries, and validate changed meeting body ids before accepting create/update requests. Vendor sync source, run, failure, and cursor state persist when `CIVICCLERK_VENDOR_SYNC_DB_URL` is configured; the API records operator state and no-network cursor resets without pulling vendors, while `scripts/run_vendor_live_sync.py` provides an explicitly enabled one-source pull runner that records outcomes in the same circuit-breaker ledger. Packet assembly records now persist source references, citations, linked packet snapshot ids, and durable audit hashes. Notice checklist records persist compliance outcomes, warnings, posting proof, and durable audit hashes. Browser QA now checks loading, success, empty, error, and partial states plus keyboard, focus, contrast, and console evidence, and release screenshots are bound to the current docs page through shared CivicCore verification helpers. CivicClerk v1.0.3 now pairs with the published `civiccore` 1.2.0 wheel from the `v1.2.0` release asset. The first staff auth foundation is now explicit: fresh installs default to `CIVICCLERK_STAFF_AUTH_MODE=protected` so anonymous staff writes are denied, local rehearsals can explicitly opt into `CIVICCLERK_STAFF_AUTH_MODE=open`, municipal identity-provider deployments can set `CIVICCLERK_STAFF_AUTH_MODE=oidc` plus issuer, audience, JWKS, role-claim, algorithm, authorization URL, token URL, client, redirect URI, and session-cookie-secret settings, bearer-protected pilots can set `CIVICCLERK_STAFF_AUTH_MODE=bearer` plus `CIVICCLERK_STAFF_AUTH_TOKEN_ROLES`, and trusted reverse-proxy deployments can set `CIVICCLERK_STAFF_AUTH_MODE=trusted_header` plus `CIVICCLERK_STAFF_SSO_PRINCIPAL_HEADER`, `CIVICCLERK_STAFF_SSO_ROLES_HEADER`, `CIVICCLERK_STAFF_SSO_PROVIDER`, and `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES`. The `/staff/auth-readiness` endpoint now tells operators whether those OIDC token-validation, OIDC browser-login, bearer, or trusted-proxy settings are merely present or actually deployment-ready, and it includes a loopback-only rehearsal recipe so trusted-header testing does not require inventing a custom proxy first. +The foundation is intentionally thin. Canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, agenda item lifecycle persistence, meeting lifecycle enforcement, meeting records, packet snapshot versioning, packet assembly records, notice checklist records, shared notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, prompt YAML/evaluation gates, local-first connector import normalization, browser QA gates, CivicClerk v1.0.4 release artifacts, and CivicCore v1.2.0 packet export, browser-evidence verification, connector runtime validation, and trusted-header config enforcement primitives are present. Minutes drafts require sentence-level citations, YAML prompt-version provenance, and human approval before acceptance, and they are never auto-adopted or auto-posted. Anonymous public archive endpoints do not reveal closed-session content in response bodies, counts, suggestions, or error messages. Connector imports record source provenance and do not require outbound network calls in the default local profile. The vendor live-sync foundation now validates proposed vendor source URLs without network calls, blocks credentials in URLs, persists source/run/failure state in `vendor_sync_sources`, `vendor_sync_run_log`, and `vendor_sync_failures`, computes source health as `healthy`, `degraded`, or `circuit_open`, persists `last_success_cursor_at`, plans connector-specific delta URLs from that cursor, advances it only after fully successful normalized pulls, and follows the CivicRecords AI circuit-breaker pattern of five consecutive full-run failures or two grace-period failures after unpause. Public packet exports block closed-session/restricted sources and include manifest, checksum, provenance, and audit evidence. Agenda item records now persist lifecycle status and CivicCore-verifiable transition audit hashes when `CIVICCLERK_AGENDA_ITEM_DB_URL` is configured, and ready agenda intake records can be promoted into those lifecycle records while preserving the generated agenda item id, promotion timestamp, and audit hash on the intake record. Meeting records now persist scheduled starts, meeting body ids, locations, normalized meeting type, lifecycle status, and CivicCore-verifiable transition and schedule-edit audit hashes when `CIVICCLERK_MEETING_DB_URL` is configured; schedule edits are allowed before the in-session lock point, write audit entries, and validate changed meeting body ids before accepting create/update requests. Vendor sync source, run, failure, and cursor state persist when `CIVICCLERK_VENDOR_SYNC_DB_URL` is configured; the API records operator state and no-network cursor resets without pulling vendors, while `scripts/run_vendor_live_sync.py` provides an explicitly enabled one-source pull runner that records outcomes in the same circuit-breaker ledger. Packet assembly records now persist source references, citations, linked packet snapshot ids, and durable audit hashes. Notice checklist records persist compliance outcomes, warnings, posting proof, and durable audit hashes. Browser QA now checks loading, success, empty, error, and partial states plus keyboard, focus, contrast, and console evidence, and release screenshots are bound to the current docs page through shared CivicCore verification helpers. CivicClerk v1.0.4 now pairs with the published `civiccore` 1.2.0 wheel from the `v1.2.0` release asset. The first staff auth foundation is now explicit: fresh installs default to `CIVICCLERK_STAFF_AUTH_MODE=protected` so anonymous staff writes are denied, local rehearsals can explicitly opt into `CIVICCLERK_STAFF_AUTH_MODE=open`, municipal identity-provider deployments can set `CIVICCLERK_STAFF_AUTH_MODE=oidc` plus issuer, audience, JWKS, role-claim, algorithm, authorization URL, token URL, client, redirect URI, and session-cookie-secret settings, bearer-protected pilots can set `CIVICCLERK_STAFF_AUTH_MODE=bearer` plus `CIVICCLERK_STAFF_AUTH_TOKEN_ROLES`, and trusted reverse-proxy deployments can set `CIVICCLERK_STAFF_AUTH_MODE=trusted_header` plus `CIVICCLERK_STAFF_SSO_PRINCIPAL_HEADER`, `CIVICCLERK_STAFF_SSO_ROLES_HEADER`, `CIVICCLERK_STAFF_SSO_PROVIDER`, and `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES`. The `/staff/auth-readiness` endpoint now tells operators whether those OIDC token-validation, OIDC browser-login, bearer, or trusted-proxy settings are merely present or actually deployment-ready, and it includes a loopback-only rehearsal recipe so trusted-header testing does not require inventing a custom proxy first. The staff experience at `/staff` now includes a product cockpit plus first workflow screens for agenda intake, packet assembly/export, notice checklist/posting-proof, meeting outcome, minutes draft, public archive, connector import, and vendor sync work. It is intentionally honest: the cockpit gives clerks a day-at-a-glance desk, reads the live agenda intake queue for ready/pending/needs-revision counts, the Agenda Intake, Packet Assembly, Notice Checklist, Meeting Outcomes, Minutes Draft, and Vendor Sync panels render live queue/record rows with escaped user-submitted titles where applicable and actionable empty/unavailable-store rows, the workflow screens can submit their corresponding live API actions, the auth panel now renders concrete protected-session and protected-write probes from `/staff/auth-readiness` when OIDC, bearer, or trusted-header mode is ready, it surfaces the loopback-only local proxy rehearsal command and env vars when trusted-header mode is being staged, and the broader multi-role React clerk console is now beginning under `frontend/`. The React slice uses the CivicSuite mockup direction for a real staff shell, meeting body management, meeting scheduling, meeting calendar, lifecycle ribbon, audit/evidence drawer, pre-lock schedule editing, Agenda Intake submit/review/promotion, Packet Builder promoted-item selection, packet draft creation, per-meeting queue review, packet finalization, Notice Checklist statutory deadline review, legal-blocker copy, posting-proof attachment, immutable audit-hash evidence, Public Posting resident-safe list/detail/search, Meeting Outcomes motion/vote/action capture with immutable-record guidance, Minutes Draft source/citation/provenance capture, Vendor Sync source-health/circuit-breaker/cursor visibility with no-network run logging and full-reconciliation reset guidance, and no-dead-end QA states. The Docker profile now seeds Brookfield demo data so city IT can open the React app and see live work immediately; the unsigned Windows installer wraps that same stack for install/repair and daily start. The resident-facing `/public` route in the nginx product path now opens the React public portal directly, loads public calendar records, public-safe detail, and anonymous archive search from the live public APIs, and keeps restricted-session existence, counts, and summaries out of resident copy. @@ -508,11 +508,11 @@ For Windows installer packaging, `install.ps1` is the install/repair entrypoint For the first real trusted-header deployment handoff, `docs/examples/trusted-header-nginx.conf` now ships a reference nginx bridge that strips client-supplied identity headers, sets proxy-owned staff headers, and points operators back to `CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES` plus the `/staff/auth-readiness` contract before live staff traffic is trusted. -For fresh Windows install rehearsals, `scripts/start_fresh_install_rehearsal.ps1` now prints and can execute the documented wheel-install path from an isolated `.fresh-install-rehearsal` virtual environment: create venv, upgrade pip, install `dist/civicclerk-1.0.3-py3-none-any.whl`, set `CIVICCLERK_STAFF_AUTH_MODE=protected`, launch the installed app on `127.0.0.1:8776`, verify `/health`, verify `/staff/auth-readiness`, and fetch `/staff`. If the wheel is missing, the helper tells the operator to build it with `python -m build` before trying again. +For fresh Windows install rehearsals, `scripts/start_fresh_install_rehearsal.ps1` now prints and can execute the documented wheel-install path from an isolated `.fresh-install-rehearsal` virtual environment: create venv, upgrade pip, install `dist/civicclerk-1.0.4-py3-none-any.whl`, set `CIVICCLERK_STAFF_AUTH_MODE=protected`, launch the installed app on `127.0.0.1:8776`, verify `/health`, verify `/staff/auth-readiness`, and fetch `/staff`. If the wheel is missing, the helper tells the operator to build it with `python -m build` before trying again. For fresh Bash install rehearsals on Linux, macOS, or Git Bash, `scripts/start_fresh_install_rehearsal.sh` now prints and can execute the same wheel-install path from an isolated `.fresh-install-rehearsal/.venv`, with the same `/health`, `/staff/auth-readiness`, `/staff`, missing-wheel, occupied-port, and Python `venv` prerequisite checks as the Windows helper. On Debian or Ubuntu, install `python3-venv` before executing the helper. -For IT release handoff, `scripts/build_release_handoff_bundle.ps1` and `scripts/build_release_handoff_bundle.sh` now print and can create `dist/civicclerk-1.0.3-release-handoff.zip` containing the built wheel, source distribution, checksums, current README/manual/changelog/license, docs landing page, deployment env profile example, installer-readiness helper, enterprise signing-readiness helper, connector sync readiness helper, vendor live-sync readiness helper, protected deployment smoke helper, trusted-header nginx reference, and the fresh-install/protected-demo rehearsal helpers. Both helpers intentionally refuse to overwrite an existing bundle and they are release-input zips, not setup executables; build artifacts first with `bash scripts/verify-release.sh`. After the zip exists, `python scripts/check_installer_readiness.py` verifies the handoff bundle before the Windows setup package is built or handed to IT. +For IT release handoff, `scripts/build_release_handoff_bundle.ps1` and `scripts/build_release_handoff_bundle.sh` now print and can create `dist/civicclerk-1.0.4-release-handoff.zip` containing the built wheel, source distribution, checksums, current README/manual/changelog/license, docs landing page, deployment env profile example, installer-readiness helper, enterprise signing-readiness helper, connector sync readiness helper, vendor live-sync readiness helper, protected deployment smoke helper, trusted-header nginx reference, and the fresh-install/protected-demo rehearsal helpers. Both helpers intentionally refuse to overwrite an existing bundle and they are release-input zips, not setup executables; build artifacts first with `bash scripts/verify-release.sh`. After the zip exists, `python scripts/check_installer_readiness.py` verifies the handoff bundle before the Windows setup package is built or handed to IT. For connector import operations, `python scripts/check_connector_sync_readiness.py` verifies the supported Granicus, Legistar, PrimeGov, and NovusAGENDA local payload contracts without outbound network calls. It can also validate a proposed `--source-url` or `--odbc-connection-string` through the shared CivicCore host guards before vendor-network live sync is designed. `python scripts/check_vendor_live_sync_readiness.py --connector legistar --source-url https://vendor.example.gov/api/meetings --auth-method bearer_token` checks the first live-sync source contract, rejects credentials in URLs, previews `healthy`/`degraded`/`circuit_open`, and simulates the circuit breaker without contacting the vendor. With `CIVICCLERK_VENDOR_SYNC_DB_URL` set, `POST /vendor-live-sync/sources` saves a validated source and `POST /vendor-live-sync/sources/{id}/run-log` records success, partial, or failed run outcomes into the durable no-network ledger; `GET /vendor-live-sync/sources` and `GET /vendor-live-sync/sources/{id}/run-log` expose the operator health state and actionable fix text. When IT has exported local JSON files, `python scripts/run_connector_import_sync.py --payload-dir path\to\exports --output connector-import-ledger.json` normalizes `.json` or `/*.json` payloads through the same import contract and writes a provenance ledger. In the Docker product path, IT can enable the same local-first normalization on a schedule with `CIVICCLERK_CONNECTOR_SYNC_ENABLED=true`, drop approved exports into `CIVICCLERK_CONNECTOR_SYNC_PAYLOAD_DIR_HOST`, and review the ledger at `CIVICCLERK_CONNECTOR_SYNC_LEDGER_PATH`. This scheduled local export-drop sync still does not contact vendors, and the vendor live-sync ledger does not contact vendors until a later adapter/scheduled-pull slice is built. diff --git a/USER-MANUAL.md b/USER-MANUAL.md index 085178f..d76d175 100644 --- a/USER-MANUAL.md +++ b/USER-MANUAL.md @@ -1,12 +1,12 @@ # CivicClerk User Manual -Status: CivicClerk v1.0.3 runtime foundation label is provisional during release recovery -Version: `1.0.3` +Status: CivicClerk v1.0.4 runtime foundation label is provisional during release recovery +Version: `1.0.4` ## Release Recovery Notice CivicClerk is not product-ready for public promotion while the CivicSuite -release recovery is active. The current `v1.0.3` recovery patch is the supported release +release recovery is active. The current `v1.0.4` recovery patch is the supported release until the repo passes the recovery gates: full backend tests, frontend tests, tracked Playwright user-flow tests, WSL runtime install proof, consistency gates, security scans, docs-source parity, and explicit separation between @@ -64,7 +64,7 @@ minutes drafting, ordinance/resolution extraction, closed-session safe refusal, and public plain-language meeting explanation, local-first connector imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, no-network vendor live-sync readiness plus durable source/run -ledgering, accessibility/browser QA gates, provisional CivicClerk v1.0.3 release +ledgering, accessibility/browser QA gates, provisional CivicClerk v1.0.4 release artifacts, CivicCore 1.2.0 freeze-backed packet export bundles, a database-backed agenda intake queue with clerk readiness review, database-backed meeting records with lifecycle audit entries, database-backed packet assembly records @@ -371,14 +371,14 @@ is the Windows PowerShell path: python -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install --upgrade pip -python -m pip install dist/civicclerk-1.0.3-py3-none-any.whl +python -m pip install dist/civicclerk-1.0.4-py3-none-any.whl $env:CIVICCLERK_STAFF_AUTH_MODE="protected" python -m uvicorn civicclerk.main:app --host 127.0.0.1 --port 8776 ``` Then verify these first-run checks: -- `GET /health` returns `{"status":"ok","service":"civicclerk","version":"1.0.3","civiccore":"1.2.0"}` +- `GET /health` returns `{"status":"ok","service":"civicclerk","version":"1.0.4","civiccore":"1.2.0"}` - `GET /staff/auth-readiness` returns `mode: "protected"` and explains that anonymous staff writes are denied until OIDC, bearer, or trusted-header deployment is configured - `GET /staff` renders the first workflow shell without console errors @@ -429,7 +429,7 @@ wheel, source distribution, checksums, current docs, trusted-header reference, installer-readiness helper, enterprise signing-readiness helper, and install rehearsal helpers. After `bash scripts/verify-release.sh` has built `dist/`, rerun without `-PrintOnly` or `--print-only` to create -`dist/civicclerk-1.0.3-release-handoff.zip`. If that zip already exists, the +`dist/civicclerk-1.0.4-release-handoff.zip`. If that zip already exists, the helpers stop instead of overwriting it. After the handoff zip exists, verify the installer input contract: @@ -761,7 +761,7 @@ provenance and actionable errors, without requiring outbound runtime calls. Milestone 11 adds browser QA evidence and a CI gate for loading, success, empty, error, and partial states plus keyboard navigation, focus states, contrast, and console checks. Milestone 12 synchronizes version surfaces, -builds release artifacts and checksums, and publishes CivicClerk v1.0.3. +builds release artifacts and checksums, and publishes CivicClerk v1.0.4. CC-7 extends browser QA to every named spec page through `node scripts/capture-cc7-browser-qa.mjs`; the verification script requires the resulting 200-case ledger before browser-visible changes can merge. diff --git a/USER-MANUAL.txt b/USER-MANUAL.txt index 085178f..d76d175 100644 --- a/USER-MANUAL.txt +++ b/USER-MANUAL.txt @@ -1,12 +1,12 @@ # CivicClerk User Manual -Status: CivicClerk v1.0.3 runtime foundation label is provisional during release recovery -Version: `1.0.3` +Status: CivicClerk v1.0.4 runtime foundation label is provisional during release recovery +Version: `1.0.4` ## Release Recovery Notice CivicClerk is not product-ready for public promotion while the CivicSuite -release recovery is active. The current `v1.0.3` recovery patch is the supported release +release recovery is active. The current `v1.0.4` recovery patch is the supported release until the repo passes the recovery gates: full backend tests, frontend tests, tracked Playwright user-flow tests, WSL runtime install proof, consistency gates, security scans, docs-source parity, and explicit separation between @@ -64,7 +64,7 @@ minutes drafting, ordinance/resolution extraction, closed-session safe refusal, and public plain-language meeting explanation, local-first connector imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, no-network vendor live-sync readiness plus durable source/run -ledgering, accessibility/browser QA gates, provisional CivicClerk v1.0.3 release +ledgering, accessibility/browser QA gates, provisional CivicClerk v1.0.4 release artifacts, CivicCore 1.2.0 freeze-backed packet export bundles, a database-backed agenda intake queue with clerk readiness review, database-backed meeting records with lifecycle audit entries, database-backed packet assembly records @@ -371,14 +371,14 @@ is the Windows PowerShell path: python -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install --upgrade pip -python -m pip install dist/civicclerk-1.0.3-py3-none-any.whl +python -m pip install dist/civicclerk-1.0.4-py3-none-any.whl $env:CIVICCLERK_STAFF_AUTH_MODE="protected" python -m uvicorn civicclerk.main:app --host 127.0.0.1 --port 8776 ``` Then verify these first-run checks: -- `GET /health` returns `{"status":"ok","service":"civicclerk","version":"1.0.3","civiccore":"1.2.0"}` +- `GET /health` returns `{"status":"ok","service":"civicclerk","version":"1.0.4","civiccore":"1.2.0"}` - `GET /staff/auth-readiness` returns `mode: "protected"` and explains that anonymous staff writes are denied until OIDC, bearer, or trusted-header deployment is configured - `GET /staff` renders the first workflow shell without console errors @@ -429,7 +429,7 @@ wheel, source distribution, checksums, current docs, trusted-header reference, installer-readiness helper, enterprise signing-readiness helper, and install rehearsal helpers. After `bash scripts/verify-release.sh` has built `dist/`, rerun without `-PrintOnly` or `--print-only` to create -`dist/civicclerk-1.0.3-release-handoff.zip`. If that zip already exists, the +`dist/civicclerk-1.0.4-release-handoff.zip`. If that zip already exists, the helpers stop instead of overwriting it. After the handoff zip exists, verify the installer input contract: @@ -761,7 +761,7 @@ provenance and actionable errors, without requiring outbound runtime calls. Milestone 11 adds browser QA evidence and a CI gate for loading, success, empty, error, and partial states plus keyboard navigation, focus states, contrast, and console checks. Milestone 12 synchronizes version surfaces, -builds release artifacts and checksums, and publishes CivicClerk v1.0.3. +builds release artifacts and checksums, and publishes CivicClerk v1.0.4. CC-7 extends browser QA to every named spec page through `node scripts/capture-cc7-browser-qa.mjs`; the verification script requires the resulting 200-case ledger before browser-visible changes can merge. diff --git a/civicclerk/__init__.py b/civicclerk/__init__.py index d2b848f..753d30f 100644 --- a/civicclerk/__init__.py +++ b/civicclerk/__init__.py @@ -1,3 +1,3 @@ """CivicClerk runtime package.""" -__version__ = "1.0.3" +__version__ = "1.0.4" diff --git a/docs/api/openapi.json b/docs/api/openapi.json index 6be8cbc..594393b 100644 --- a/docs/api/openapi.json +++ b/docs/api/openapi.json @@ -1496,7 +1496,7 @@ "info": { "summary": "Runtime foundation for CivicClerk municipal meeting workflows.", "title": "CivicClerk", - "version": "1.0.3" + "version": "1.0.4" }, "openapi": "3.1.0", "paths": { diff --git a/docs/browser-qa-v1.0.4-release-desktop.png b/docs/browser-qa-v1.0.4-release-desktop.png new file mode 100644 index 0000000..6413724 Binary files /dev/null and b/docs/browser-qa-v1.0.4-release-desktop.png differ diff --git a/docs/browser-qa-v1.0.4-release-mobile.png b/docs/browser-qa-v1.0.4-release-mobile.png new file mode 100644 index 0000000..d4cedd4 Binary files /dev/null and b/docs/browser-qa-v1.0.4-release-mobile.png differ diff --git a/docs/browser-qa/release-evidence.json b/docs/browser-qa/release-evidence.json index e5553e6..900f4a0 100644 --- a/docs/browser-qa/release-evidence.json +++ b/docs/browser-qa/release-evidence.json @@ -1,10 +1,10 @@ { "page": "docs/index.html", - "page_sha256": "c9200d663c22a23de8f85eb1fe44889f7cbce73e792ca32c93fb3e6213617631", - "reviewed_at": "2026-06-11T07:48:00Z", + "page_sha256": "f249e21e4accf977572353a714a23259af1a5cbb30fc3fbc87953af0f7443b99", + "reviewed_at": "2026-06-13T00:21:46Z", "screenshots": { - "desktop": "docs/browser-qa-v1.0.3-release-desktop.png", - "mobile": "docs/browser-qa-v1.0.3-release-mobile.png" + "desktop": "docs/browser-qa-v1.0.4-release-desktop.png", + "mobile": "docs/browser-qa-v1.0.4-release-mobile.png" }, - "version": "1.0.3" + "version": "1.0.4" } diff --git a/docs/index.html b/docs/index.html index 83aa7c1..8d93d5c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -51,9 +51,9 @@
CivicSuite release recovery

CivicClerk

CivicClerk is municipal meeting software for agendas, packets, notices, minutes, motions, votes, action items, and public meeting archives.

-

Recovery notice: CivicClerk is not product-ready for public promotion while CivicSuite release recovery is active. Treat the current v1.0.3 recovery patch as a provisional supported release until the repo re-earns release status through recovery gates covering backend tests, frontend tests, real Playwright user-flow tests, WSL runtime install proof, release consistency, security scans, docs-source parity, and explicit mock validation versus production deployment labeling. Integration release depth requires live-wire or in-process boundary validation; adversarial mock checks are supplemental regression coverage and are not a claim that a city production deployment has occurred.

+

Recovery notice: CivicClerk is not product-ready for public promotion while CivicSuite release recovery is active. Treat the current v1.0.4 recovery patch as a provisional supported release until the repo re-earns release status through recovery gates covering backend tests, frontend tests, real Playwright user-flow tests, WSL runtime install proof, release consistency, security scans, docs-source parity, and explicit mock validation versus production deployment labeling. Integration release depth requires live-wire or in-process boundary validation; adversarial mock checks are supplemental regression coverage and are not a claim that a city production deployment has occurred.

Release provenance: CivicClerk now uses the strengthened CivicCore preflight gate for release-class workflows. GitHub can show a Verified badge for the target commit even when the release tag is lightweight or unsigned, so post-baseline releases use a Sigstore-signed release-attestation.json plus bundle as the trust artifact. The prior v0.1.20 release is historical pre-gate and must not be promoted as an attested baseline; see docs/ops/tier1-retrofit-ledger.md for the CO-4 decision.

-

Status: CivicClerk v1.0.3 React/Docker product rehearsal release with canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, database-backed agenda item lifecycle records, meeting lifecycle enforcement, database-backed meeting records, packet snapshot versioning, database-backed packet assembly records, database-backed notice checklist records, shared CivicCore notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public calendar/detail/archive endpoints, versioned prompt YAML evaluation gates resolved through civiccore.llm.resolve_template under consumer_app="civicclerk", local-first connector imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, vendor live-sync readiness/circuit-breaker/persistence primitives, browser QA gates, release artifacts, staff workflow screens at /staff, the resident-facing React public portal at /public in the Docker/nginx product path, the React staff workspace under frontend/, Docker Compose product rehearsal, seeded Brookfield demo data, OIDC staff-token validation, OIDC browser sign-in/session-cookie foundation, React staff access/session polish, and unsigned Windows installer source packaging with explicit SmartScreen guidance. IT staff can smoke-check the FastAPI app, inspect the schema plan, exercise agenda intake, persisted agenda item lifecycle records, persisted meeting body records, persisted meeting records with body ids, locations, and pre-lock schedule-edit audit entries, packet assembly, notice checklist, motion, vote, action item, minutes citation, closed-session archive filtering, source provenance import rules, vendor source URL/credential-placement guards, persisted vendor source/run/failure state through CIVICCLERK_VENDOR_SYNC_DB_URL, sync health states, circuit-open fix paths, persisted last_success_cursor_at delta cursors, no-network cursor reset for full reconciliation, and packet export manifests/checksums, run prompt evals with outbound network blocked for citations, closed-session refusal, legal-determination refusal, public approval gates, and mutation stability, verify loading, success, empty, error, partial, keyboard, focus, contrast, and console evidence, and run install.ps1 to create .env, start Docker Compose, wait for health checks, and open the React staff app. The staff cockpit and intake, packet assembly/export, notice checklist, meeting outcome, minutes draft, public archive, connector import, and vendor sync screens now give clerks and IT a day-at-a-glance desk, read the live agenda intake queue, render live panel rows with actionable empty/unavailable states, submit their live API actions, show source health/circuit state, record no-network vendor sync run outcomes, show cursor state/reset guidance, and disclose staff auth posture. The React app translates the CivicSuite mockup into a typed shell, staff access/session status, meeting body management, meeting scheduling, Clerk Meeting Runbook next-safe-action guidance across agenda, packet, notice, outcomes, minutes, and public posting, meeting calendar, meeting detail lifecycle ribbon, pre-lock schedule editing, Agenda Intake submit/review/promotion into canonical agenda lifecycle work, Packet Builder packet draft creation, per-meeting queue review, packet finalization, Notice Checklist statutory deadline review, Official Notice Record proof summary, legal readiness proof chain, basis/approval capture, posting-proof attachment, legal-blocker copy, immutable audit-hash evidence, resident-oriented Public Posting list/detail/archive search with official agenda, packet, approved-minutes sections and restricted-record non-disclosure guidance, Meeting Outcomes motion/vote/action capture with append-only correction guidance, Minutes Draft source-material entry, sentence-level citation capture, prompt/model provenance, human approver capture, blocked auto-posting visibility, Vendor Sync source-health/circuit-breaker/cursor visibility with full reconciliation reset, audit/evidence drawer, required QA states, and live /api/meetings, /api/meeting-bodies, /api/agenda-intake, /api/meetings/{id}/packet-assemblies, /api/packet-assemblies/{id}/finalize, /api/meetings/{id}/notice-checklists, /api/notice-checklists/{id}/posting-proof, /api/meetings/{id}/motions, /api/motions/{id}/votes, /api/meetings/{id}/action-items, /api/meetings/{id}/minutes/drafts, /api/minutes/{id}/post, /api/public/meetings, /api/public/archive/search, /api/vendor-live-sync/sources, and /api/vendor-live-sync/sources/{id}/cursor-reset loading. The nginx product routes /staff and /public now open the React staff dashboard and public portal directly while workflow API calls stay behind /api/... and exact staff auth contracts stay proxied to the backend. Docker/PostgreSQL backup and restore rehearsal now uses pg_dump and pg_restore against a temporary restore database without overwriting source data. OIDC browser sign-in now starts at /staff/login with authorization-code + PKCE parameters, returns through /staff/oidc/callback, and stores a signed HttpOnly CivicClerk staff session cookie instead of the raw OIDC token. Scheduled local connector export-drop ingestion is now available through Celery Beat for approved JSON files without vendor network calls, and scripts/check_vendor_live_sync_readiness.py plus /vendor-live-sync/sources now preview, persist, and surface the vendor live-sync source/run health contract without contacting vendors. The reusable mock-city suite now proves Legistar, Granicus, PrimeGov, NovusAGENDA, Brookfield Entra ID-style OIDC, and Brookfield backup-retention/off-host policy contracts without vendor, identity-provider, or storage-provider network calls or secret-bearing reports. The guarded vendor-network runner and disabled-by-default Celery Beat schedule can now pull configured approved source IDs only after IT enables both live-sync gates and credentials; reports show delta_request_url, cursor_param, cursor_value, and cursor_advanced_at, failed or partial pulls leave the cursor unchanged, and operators can clear or move the cursor locally before a controlled reconciliation pull while preserving the reason as a cursor_reset run-log event. Release readiness keeps adversarial mock-city municipal IdP, vendor API, protected-auth, and backup-retention suites as regression coverage; integration release-depth claims require live-wire or in-process boundary validation. The public Windows installer is unsigned because CivicSuite is a small free open-source project; SmartScreen warnings are expected, and users may choose More info and Run anyway only for official CivicSuite release artifacts or verified local builds. The /staff/auth-readiness contract tells operators whether OIDC token validation, OIDC browser login, bearer-token, or trusted-header staff auth is deployment-ready and includes protected smoke probes plus loopback-only proxy rehearsal guidance.

+

Status: CivicClerk v1.0.4 React/Docker product rehearsal release with canonical schema, Alembic scaffolding, agenda item lifecycle enforcement, database-backed agenda item lifecycle records, meeting lifecycle enforcement, database-backed meeting records, packet snapshot versioning, database-backed packet assembly records, database-backed notice checklist records, shared CivicCore notice compliance enforcement, immutable motion capture, immutable vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public calendar/detail/archive endpoints, versioned prompt YAML evaluation gates resolved through civiccore.llm.resolve_template under consumer_app="civicclerk", local-first connector imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, vendor live-sync readiness/circuit-breaker/persistence primitives, browser QA gates, release artifacts, staff workflow screens at /staff, the resident-facing React public portal at /public in the Docker/nginx product path, the React staff workspace under frontend/, Docker Compose product rehearsal, seeded Brookfield demo data, OIDC staff-token validation, OIDC browser sign-in/session-cookie foundation, React staff access/session polish, and unsigned Windows installer source packaging with explicit SmartScreen guidance. IT staff can smoke-check the FastAPI app, inspect the schema plan, exercise agenda intake, persisted agenda item lifecycle records, persisted meeting body records, persisted meeting records with body ids, locations, and pre-lock schedule-edit audit entries, packet assembly, notice checklist, motion, vote, action item, minutes citation, closed-session archive filtering, source provenance import rules, vendor source URL/credential-placement guards, persisted vendor source/run/failure state through CIVICCLERK_VENDOR_SYNC_DB_URL, sync health states, circuit-open fix paths, persisted last_success_cursor_at delta cursors, no-network cursor reset for full reconciliation, and packet export manifests/checksums, run prompt evals with outbound network blocked for citations, closed-session refusal, legal-determination refusal, public approval gates, and mutation stability, verify loading, success, empty, error, partial, keyboard, focus, contrast, and console evidence, and run install.ps1 to create .env, start Docker Compose, wait for health checks, and open the React staff app. The staff cockpit and intake, packet assembly/export, notice checklist, meeting outcome, minutes draft, public archive, connector import, and vendor sync screens now give clerks and IT a day-at-a-glance desk, read the live agenda intake queue, render live panel rows with actionable empty/unavailable states, submit their live API actions, show source health/circuit state, record no-network vendor sync run outcomes, show cursor state/reset guidance, and disclose staff auth posture. The React app translates the CivicSuite mockup into a typed shell, staff access/session status, meeting body management, meeting scheduling, Clerk Meeting Runbook next-safe-action guidance across agenda, packet, notice, outcomes, minutes, and public posting, meeting calendar, meeting detail lifecycle ribbon, pre-lock schedule editing, Agenda Intake submit/review/promotion into canonical agenda lifecycle work, Packet Builder packet draft creation, per-meeting queue review, packet finalization, Notice Checklist statutory deadline review, Official Notice Record proof summary, legal readiness proof chain, basis/approval capture, posting-proof attachment, legal-blocker copy, immutable audit-hash evidence, resident-oriented Public Posting list/detail/archive search with official agenda, packet, approved-minutes sections and restricted-record non-disclosure guidance, Meeting Outcomes motion/vote/action capture with append-only correction guidance, Minutes Draft source-material entry, sentence-level citation capture, prompt/model provenance, human approver capture, blocked auto-posting visibility, Vendor Sync source-health/circuit-breaker/cursor visibility with full reconciliation reset, audit/evidence drawer, required QA states, and live /api/meetings, /api/meeting-bodies, /api/agenda-intake, /api/meetings/{id}/packet-assemblies, /api/packet-assemblies/{id}/finalize, /api/meetings/{id}/notice-checklists, /api/notice-checklists/{id}/posting-proof, /api/meetings/{id}/motions, /api/motions/{id}/votes, /api/meetings/{id}/action-items, /api/meetings/{id}/minutes/drafts, /api/minutes/{id}/post, /api/public/meetings, /api/public/archive/search, /api/vendor-live-sync/sources, and /api/vendor-live-sync/sources/{id}/cursor-reset loading. The nginx product routes /staff and /public now open the React staff dashboard and public portal directly while workflow API calls stay behind /api/... and exact staff auth contracts stay proxied to the backend. Docker/PostgreSQL backup and restore rehearsal now uses pg_dump and pg_restore against a temporary restore database without overwriting source data. OIDC browser sign-in now starts at /staff/login with authorization-code + PKCE parameters, returns through /staff/oidc/callback, and stores a signed HttpOnly CivicClerk staff session cookie instead of the raw OIDC token. Scheduled local connector export-drop ingestion is now available through Celery Beat for approved JSON files without vendor network calls, and scripts/check_vendor_live_sync_readiness.py plus /vendor-live-sync/sources now preview, persist, and surface the vendor live-sync source/run health contract without contacting vendors. The reusable mock-city suite now proves Legistar, Granicus, PrimeGov, NovusAGENDA, Brookfield Entra ID-style OIDC, and Brookfield backup-retention/off-host policy contracts without vendor, identity-provider, or storage-provider network calls or secret-bearing reports. The guarded vendor-network runner and disabled-by-default Celery Beat schedule can now pull configured approved source IDs only after IT enables both live-sync gates and credentials; reports show delta_request_url, cursor_param, cursor_value, and cursor_advanced_at, failed or partial pulls leave the cursor unchanged, and operators can clear or move the cursor locally before a controlled reconciliation pull while preserving the reason as a cursor_reset run-log event. Release readiness keeps adversarial mock-city municipal IdP, vendor API, protected-auth, and backup-retention suites as regression coverage; integration release-depth claims require live-wire or in-process boundary validation. The public Windows installer is unsigned because CivicSuite is a small free open-source project; SmartScreen warnings are expected, and users may choose More info and Run anyway only for official CivicSuite release artifacts or verified local builds. The /staff/auth-readiness contract tells operators whether OIDC token validation, OIDC browser login, bearer-token, or trusted-header staff auth is deployment-ready and includes protected smoke probes plus loopback-only proxy rehearsal guidance.

@@ -68,7 +68,7 @@

For members

For IT

Runtime foundation stack: FastAPI, published civiccore 1.2.0 wheel from the v1.2.0 release asset, configurable agenda intake database via CIVICCLERK_AGENDA_INTAKE_DB_URL, configurable agenda item lifecycle database via CIVICCLERK_AGENDA_ITEM_DB_URL, configurable meeting database via CIVICCLERK_MEETING_DB_URL, configurable packet assembly database via CIVICCLERK_PACKET_ASSEMBLY_DB_URL, configurable notice checklist database via CIVICCLERK_NOTICE_CHECKLIST_DB_URL, configurable motion/vote/action-item database via CIVICCLERK_MOTION_VOTE_DB_URL, configurable minutes draft database via CIVICCLERK_MINUTES_DB_URL, configurable public archive and resident comment database via CIVICCLERK_PUBLIC_ARCHIVE_DB_URL, configurable vendor sync ledger via CIVICCLERK_VENDOR_SYNC_DB_URL, staff auth mode via CIVICCLERK_STAFF_AUTH_MODE, OIDC browser login settings via CIVICCLERK_STAFF_OIDC_AUTHORIZATION_URL, CIVICCLERK_STAFF_OIDC_TOKEN_URL, CIVICCLERK_STAFF_OIDC_CLIENT_ID, CIVICCLERK_STAFF_OIDC_CLIENT_SECRET, CIVICCLERK_STAFF_OIDC_REDIRECT_URI, and CIVICCLERK_STAFF_OIDC_SESSION_COOKIE_SECRET, bearer token role mapping via CIVICCLERK_STAFF_AUTH_TOKEN_ROLES, trusted SSO bridge headers via CIVICCLERK_STAFF_SSO_PRINCIPAL_HEADER and CIVICCLERK_STAFF_SSO_ROLES_HEADER, trusted SSO provider labeling via CIVICCLERK_STAFF_SSO_PROVIDER, trusted proxy CIDR allowlist via CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES, canonical schema metadata, Alembic migration scaffold, agenda lifecycle enforcement, agenda item lifecycle persistence, meeting lifecycle enforcement, meeting persistence, packet snapshot versioning, packet assembly persistence, notice checklist persistence, shared notice compliance enforcement, CivicCore export manifests, SHA256 checksums, provenance bundles, hash-chained audit events, shared release-evidence verification helpers, shared connector runtime validation helpers, shared trusted-header config loading and proxy-source enforcement helpers, shared vendor sync source-list health projection, safe packet export names under CIVICCLERK_EXPORT_ROOT, immutable motion/vote capture, action-item capture, citation-gated minutes drafts with provenance, permission-aware public archive filtering, shared search normalization helpers, shared search-access helpers, nine versioned prompt YAML files resolved through civiccore.llm.resolve_template, offline evaluation harness, public prompt clerk-and-attorney approval ceremony, shared local-first connector import normalization, connector import-sync ledger generation from local export files, scheduled local connector export-drop ingestion via CIVICCLERK_CONNECTOR_SYNC_ENABLED, CIVICCLERK_CONNECTOR_SYNC_PAYLOAD_DIR_HOST, CIVICCLERK_CONNECTOR_SYNC_LEDGER_PATH, CIVICCLERK_CONNECTOR_SYNC_CONNECTORS, and CIVICCLERK_CONNECTOR_SYNC_INTERVAL_SECONDS, scheduled vendor-network pull gates through CIVICCLERK_VENDOR_NETWORK_SYNC_ENABLED, CIVICCLERK_VENDOR_NETWORK_SYNC_SCHEDULE_ENABLED, CIVICCLERK_VENDOR_NETWORK_SYNC_SOURCE_IDS, and CIVICCLERK_VENDOR_NETWORK_SYNC_REPORT_DIR, vendor live-sync readiness/circuit-breaker checks through scripts/check_vendor_live_sync_readiness.py, no-network vendor source/run/cursor-reset ledger endpoints under /vendor-live-sync/sources, browser QA evidence gates, pytest, docs verification, and placeholder-import CI gates. Docker Compose services now include PostgreSQL 17 + pgvector, Redis 7.2, Ollama, FastAPI, Celery worker, Celery Beat, and nginx-served React; CIVICCLERK_DEMO_SEED=1 seeds Brookfield demo meetings, packet, notice proof, outcomes, minutes, and public archive data by default for local rehearsal. Windows installer source packaging now provides unsigned Inno Setup build wiring, Docker Desktop prerequisite checks, Install or Repair and Start shortcuts, generated local database password setup, health checks, preserved Docker volumes on uninstall, and SmartScreen/Unknown Publisher guidance for the supported unsigned public installer path.

-

Fresh-machine rehearsal: the current documented path is the verified Windows PowerShell flow. Create a virtual environment, activate it with .\.venv\Scripts\Activate.ps1, install dist/civicclerk-1.0.3-py3-none-any.whl, set $env:CIVICCLERK_STAFF_AUTH_MODE="protected", start python -m uvicorn civicclerk.main:app --host 127.0.0.1 --port 8776, then verify /health, /staff/auth-readiness, and the rendered /staff workflow shell before moving to bearer or trusted-header deployment. For the Docker product path, run powershell -ExecutionPolicy Bypass -File install.ps1 to create .env, generate a local database password, start Docker Compose, wait for API and React health, and open the seeded staff app; build the unsigned setup executable with bash installer/windows/build-installer.sh on a workstation with Inno Setup 6. Windows SmartScreen may show Unknown Publisher or Windows protected your PC because CivicSuite is a small free open-source project and the installer is not signed with a paid publisher certificate; that warning is expected, and it is OK to choose More info and Run anyway only when the installer came from the official CivicSuite release source or your IT team built it from verified CivicSuite source. For repeatable scripted versions, run powershell -ExecutionPolicy Bypass -File scripts/start_fresh_install_rehearsal.ps1 -PrintOnly on Windows PowerShell or bash scripts/start_fresh_install_rehearsal.sh --print-only on Linux, macOS, or Git Bash to preview the isolated .fresh-install-rehearsal venv, wheel install, app command, and smoke-check URLs, then rerun without the print-only flag to execute those checks. Linux hosts need Python 3 with venv support, such as python3-venv on Debian or Ubuntu, before the Bash helper can create the rehearsal environment. For IT release handoff, run powershell -ExecutionPolicy Bypass -File scripts/build_release_handoff_bundle.ps1 -PrintOnly on Windows PowerShell or bash scripts/build_release_handoff_bundle.sh --print-only on Linux, macOS, or Git Bash to preview the release bundle, then rerun without the print-only flag after bash scripts/verify-release.sh has built the wheel, sdist, and checksums. After the zip exists, run python scripts/check_installer_readiness.py to verify release artifacts, checksums, docs, env examples, and rehearsal helpers before installer handoff. Before vendor-network live-sync design work, run python scripts/check_connector_sync_readiness.py to prove supported local connector payload contracts and optional URL/ODBC host guards without contacting vendors, then run python scripts/run_mock_city_environment_suite.py --output mock-city-report.json to prove the reusable City of Brookfield vendor-interface, municipal IdP, and backup-retention/off-host contract suite for future modules without contacting vendor, identity-provider, or storage-provider networks, then run python scripts/check_pilot_readiness.py after release artifacts and the handoff bundle exist to prove developer-owned readiness while keeping integration release-depth claims tied to live-wire or in-process boundary validation; set CIVICCLERK_VENDOR_SYNC_DB_URL and use POST /vendor-live-sync/sources, POST /vendor-live-sync/sources/{id}/run-log, and POST /vendor-live-sync/sources/{id}/cursor-reset to persist proposed source health, run outcomes, and full-reconciliation cursor resets without contacting vendors; when local export files are available, run python scripts/run_connector_import_sync.py --payload-dir path/to/exports --output connector-import-ledger.json to produce a normalized provenance ledger without contacting vendors, or set CIVICCLERK_CONNECTOR_SYNC_ENABLED=true with CIVICCLERK_CONNECTOR_SYNC_PAYLOAD_DIR_HOST=.\connector-imports in the Docker .env to let Celery Beat schedule the same local-first import repeatedly. Before moving beyond local rehearsal, run python scripts/check_deployment_readiness.py for a non-mutating deployment preflight, add --env-file path/to/deployment.env after copying docs/examples/deployment.env.example to validate a deployment profile without printing token or database values, or add --strict when CI or IT handoff should fail unless auth, persistent-store env vars, packet export root, release artifacts, docs, and trusted-header proxy references are deployment-ready. After strict readiness passes, run python scripts/check_protected_deployment_smoke.py --env-file path/to/deployment.env to execute /health, /staff/auth-readiness, the returned protected session probe, and the returned protected write probe with bearer tokens redacted from output. Before trusting restore operations on the wheel path, run powershell -ExecutionPolicy Bypass -File scripts/start_backup_restore_rehearsal.ps1 -PrintOnly on Windows PowerShell or bash scripts/start_backup_restore_rehearsal.sh --print-only on Linux, macOS, or Git Bash to preview the .backup-restore-rehearsal plan; rerun without the print-only flag to execute scripts/check_backup_restore_rehearsal.py, seed the five SQLite workflow stores, create backup/civicclerk-backup-manifest.json, restore databases and packet export evidence, and verify the restored records under the deployment env vars including CIVICCLERK_NOTICE_CHECKLIST_DB_URL and CIVICCLERK_EXPORT_ROOT. For the Docker/PostgreSQL product path, run powershell -ExecutionPolicy Bypass -File scripts/start_docker_backup_restore_rehearsal.ps1 -PrintOnly or bash scripts/start_docker_backup_restore_rehearsal.sh --print-only; rerun without print-only while Compose is running to execute scripts/check_docker_backup_restore_rehearsal.py, write .docker-backup-restore-rehearsal, capture backup/civicclerk-postgres.dump with pg_dump, restore with pg_restore into a temporary database, write backup/civicclerk-docker-backup-manifest.json, verify restored application tables, and drop the temporary restore database without overwriting the source database. If trusted-header rehearsal must happen before a real proxy is available, use the returned local proxy contract, set CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES=127.0.0.1/32, and run python scripts/local_trusted_header_proxy.py on the same workstation. If the deployment is moving to a real proxy, start from docs/examples/trusted-header-nginx.conf and the returned reverse_proxy_reference guidance before wiring in your real identity provider variables and TLS paths. For a repeatable protected demo profile on Windows, run powershell -ExecutionPolicy Bypass -File scripts/start_protected_demo_rehearsal.ps1 -PrintOnly first, then rerun it without -PrintOnly to launch the app on 8877 and the helper proxy on 8878. For the same flow from Bash on Linux, macOS, or Git Bash, run bash scripts/start_protected_demo_rehearsal.sh --print-only first, then rerun it without --print-only to launch the same app and helper proxy pair.

+

Fresh-machine rehearsal: the current documented path is the verified Windows PowerShell flow. Create a virtual environment, activate it with .\.venv\Scripts\Activate.ps1, install dist/civicclerk-1.0.4-py3-none-any.whl, set $env:CIVICCLERK_STAFF_AUTH_MODE="protected", start python -m uvicorn civicclerk.main:app --host 127.0.0.1 --port 8776, then verify /health, /staff/auth-readiness, and the rendered /staff workflow shell before moving to bearer or trusted-header deployment. For the Docker product path, run powershell -ExecutionPolicy Bypass -File install.ps1 to create .env, generate a local database password, start Docker Compose, wait for API and React health, and open the seeded staff app; build the unsigned setup executable with bash installer/windows/build-installer.sh on a workstation with Inno Setup 6. Windows SmartScreen may show Unknown Publisher or Windows protected your PC because CivicSuite is a small free open-source project and the installer is not signed with a paid publisher certificate; that warning is expected, and it is OK to choose More info and Run anyway only when the installer came from the official CivicSuite release source or your IT team built it from verified CivicSuite source. For repeatable scripted versions, run powershell -ExecutionPolicy Bypass -File scripts/start_fresh_install_rehearsal.ps1 -PrintOnly on Windows PowerShell or bash scripts/start_fresh_install_rehearsal.sh --print-only on Linux, macOS, or Git Bash to preview the isolated .fresh-install-rehearsal venv, wheel install, app command, and smoke-check URLs, then rerun without the print-only flag to execute those checks. Linux hosts need Python 3 with venv support, such as python3-venv on Debian or Ubuntu, before the Bash helper can create the rehearsal environment. For IT release handoff, run powershell -ExecutionPolicy Bypass -File scripts/build_release_handoff_bundle.ps1 -PrintOnly on Windows PowerShell or bash scripts/build_release_handoff_bundle.sh --print-only on Linux, macOS, or Git Bash to preview the release bundle, then rerun without the print-only flag after bash scripts/verify-release.sh has built the wheel, sdist, and checksums. After the zip exists, run python scripts/check_installer_readiness.py to verify release artifacts, checksums, docs, env examples, and rehearsal helpers before installer handoff. Before vendor-network live-sync design work, run python scripts/check_connector_sync_readiness.py to prove supported local connector payload contracts and optional URL/ODBC host guards without contacting vendors, then run python scripts/run_mock_city_environment_suite.py --output mock-city-report.json to prove the reusable City of Brookfield vendor-interface, municipal IdP, and backup-retention/off-host contract suite for future modules without contacting vendor, identity-provider, or storage-provider networks, then run python scripts/check_pilot_readiness.py after release artifacts and the handoff bundle exist to prove developer-owned readiness while keeping integration release-depth claims tied to live-wire or in-process boundary validation; set CIVICCLERK_VENDOR_SYNC_DB_URL and use POST /vendor-live-sync/sources, POST /vendor-live-sync/sources/{id}/run-log, and POST /vendor-live-sync/sources/{id}/cursor-reset to persist proposed source health, run outcomes, and full-reconciliation cursor resets without contacting vendors; when local export files are available, run python scripts/run_connector_import_sync.py --payload-dir path/to/exports --output connector-import-ledger.json to produce a normalized provenance ledger without contacting vendors, or set CIVICCLERK_CONNECTOR_SYNC_ENABLED=true with CIVICCLERK_CONNECTOR_SYNC_PAYLOAD_DIR_HOST=.\connector-imports in the Docker .env to let Celery Beat schedule the same local-first import repeatedly. Before moving beyond local rehearsal, run python scripts/check_deployment_readiness.py for a non-mutating deployment preflight, add --env-file path/to/deployment.env after copying docs/examples/deployment.env.example to validate a deployment profile without printing token or database values, or add --strict when CI or IT handoff should fail unless auth, persistent-store env vars, packet export root, release artifacts, docs, and trusted-header proxy references are deployment-ready. After strict readiness passes, run python scripts/check_protected_deployment_smoke.py --env-file path/to/deployment.env to execute /health, /staff/auth-readiness, the returned protected session probe, and the returned protected write probe with bearer tokens redacted from output. Before trusting restore operations on the wheel path, run powershell -ExecutionPolicy Bypass -File scripts/start_backup_restore_rehearsal.ps1 -PrintOnly on Windows PowerShell or bash scripts/start_backup_restore_rehearsal.sh --print-only on Linux, macOS, or Git Bash to preview the .backup-restore-rehearsal plan; rerun without the print-only flag to execute scripts/check_backup_restore_rehearsal.py, seed the five SQLite workflow stores, create backup/civicclerk-backup-manifest.json, restore databases and packet export evidence, and verify the restored records under the deployment env vars including CIVICCLERK_NOTICE_CHECKLIST_DB_URL and CIVICCLERK_EXPORT_ROOT. For the Docker/PostgreSQL product path, run powershell -ExecutionPolicy Bypass -File scripts/start_docker_backup_restore_rehearsal.ps1 -PrintOnly or bash scripts/start_docker_backup_restore_rehearsal.sh --print-only; rerun without print-only while Compose is running to execute scripts/check_docker_backup_restore_rehearsal.py, write .docker-backup-restore-rehearsal, capture backup/civicclerk-postgres.dump with pg_dump, restore with pg_restore into a temporary database, write backup/civicclerk-docker-backup-manifest.json, verify restored application tables, and drop the temporary restore database without overwriting the source database. If trusted-header rehearsal must happen before a real proxy is available, use the returned local proxy contract, set CIVICCLERK_STAFF_SSO_TRUSTED_PROXIES=127.0.0.1/32, and run python scripts/local_trusted_header_proxy.py on the same workstation. If the deployment is moving to a real proxy, start from docs/examples/trusted-header-nginx.conf and the returned reverse_proxy_reference guidance before wiring in your real identity provider variables and TLS paths. For a repeatable protected demo profile on Windows, run powershell -ExecutionPolicy Bypass -File scripts/start_protected_demo_rehearsal.ps1 -PrintOnly first, then rerun it without -PrintOnly to launch the app on 8877 and the helper proxy on 8878. For the same flow from Bash on Linux, macOS, or Git Bash, run bash scripts/start_protected_demo_rehearsal.sh --print-only first, then rerun it without --print-only to launch the same app and helper proxy pair.

For residents

@@ -78,7 +78,7 @@

For residents

What ships today

-

Documentation, governance files, issue templates, discussion seeds, a docs verification gate, a placeholder-import gate, a prompt evaluation gate, a browser QA gate, Python package metadata, CivicClerk v1.0.3 release artifacts, a release handoff bundle helper, unsigned Windows installer source packaging, an optional downstream installer signing-readiness helper, a deployment readiness preflight helper, a backup/restore rehearsal helper for the SQLite wheel path, a Docker/PostgreSQL backup/restore rehearsal helper for the Compose product path, scheduled local connector export-drop ingestion through Celery Beat, vendor live-sync readiness, persistence, circuit-breaker primitives, an explicitly enabled one-source vendor-network pull runner, a disabled-by-default scheduled vendor-network Celery Beat task, connector-specific delta request planning, and no-network cursor reset, a FastAPI runtime foundation with root, health, staff product cockpit, React staff workspace route, React public portal route, staff auth-readiness, and staff session endpoints, database-backed agenda intake review, database-backed agenda item lifecycle records, database-backed meeting records, database-backed packet assembly records, database-backed notice checklist records, durable vendor live-sync source/run/failure/cursor records, live staff motion/vote/action-item capture with seconded-by, recusal, and absence visibility, member packet review, live staff minutes draft capture, live staff public archive publishing with public downloads, summaries, adopted/signed minutes metadata, and comment intake, live staff connector import normalization, live staff vendor sync source-health and cursor visibility, live staff packet export bundle creation, canonical schema/Alembic scaffolding, CC-5 data model completion through civicclerk_0011_data_model for packet-version uniqueness, correction metadata, public-comment fields, closed-session ACLs, document references, and ordinance handoff status, agenda item lifecycle enforcement, meeting lifecycle enforcement, packet snapshot versioning, shared notice compliance enforcement, records-ready packet export bundles, immutable motion/vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, CC-6 prompt YAML resolver checks, source-provenanced local imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, and shared connector runtime validation helpers.

+

Documentation, governance files, issue templates, discussion seeds, a docs verification gate, a placeholder-import gate, a prompt evaluation gate, a browser QA gate, Python package metadata, CivicClerk v1.0.4 release artifacts, a release handoff bundle helper, unsigned Windows installer source packaging, an optional downstream installer signing-readiness helper, a deployment readiness preflight helper, a backup/restore rehearsal helper for the SQLite wheel path, a Docker/PostgreSQL backup/restore rehearsal helper for the Compose product path, scheduled local connector export-drop ingestion through Celery Beat, vendor live-sync readiness, persistence, circuit-breaker primitives, an explicitly enabled one-source vendor-network pull runner, a disabled-by-default scheduled vendor-network Celery Beat task, connector-specific delta request planning, and no-network cursor reset, a FastAPI runtime foundation with root, health, staff product cockpit, React staff workspace route, React public portal route, staff auth-readiness, and staff session endpoints, database-backed agenda intake review, database-backed agenda item lifecycle records, database-backed meeting records, database-backed packet assembly records, database-backed notice checklist records, durable vendor live-sync source/run/failure/cursor records, live staff motion/vote/action-item capture with seconded-by, recusal, and absence visibility, member packet review, live staff minutes draft capture, live staff public archive publishing with public downloads, summaries, adopted/signed minutes metadata, and comment intake, live staff connector import normalization, live staff vendor sync source-health and cursor visibility, live staff packet export bundle creation, canonical schema/Alembic scaffolding, CC-5 data model completion through civicclerk_0011_data_model for packet-version uniqueness, correction metadata, public-comment fields, closed-session ACLs, document references, and ordinance handoff status, agenda item lifecycle enforcement, meeting lifecycle enforcement, packet snapshot versioning, shared notice compliance enforcement, records-ready packet export bundles, immutable motion/vote capture, action-item capture, citation-gated minutes draft capture, permission-aware public archive endpoints, CC-6 prompt YAML resolver checks, source-provenanced local imports for Granicus, Legistar, PrimeGov, and NovusAGENDA, and shared connector runtime validation helpers.

CC-7 API/frontend completeness: the live FastAPI schema is published at docs/api/openapi.json and checked against app.openapi(). Staff report, transcript, ordinance/resolution handoff, public comment review, admin config, prompt admin, and /integrations/readiness routes are now in the contract, and the React workspace accepts direct QA routes for all 20 spec pages. The admin settings page shows live-wire or in-process integration-depth contracts for CivicRecords search, CivicCode handoff, codification export, city CMS posting, and vendor live API adapters; see docs/integration-depth-contracts.md. Browser QA evidence covers every page across loading, success, empty, error, and partial states at desktop and 390px mobile widths with console, keyboard, focus, contrast, visible copy, and horizontal-overflow checks.

CC-6 prompt library: nine versioned YAML prompts cover agenda item summary, staff report normalizer, packet completeness reviewer, notice compliance reviewer, motion/vote summary, minutes drafter, ordinance/resolution extractor, closed-session safe summarizer/refuser, and public plain-language meeting explainer. They resolve through civiccore.llm.resolve_template under consumer_app="civicclerk", pass offline evals for citation requirements, closed-session refusal, legal-determination refusal, public approval gates, and input mutation stability, and require a clerk-and-attorney approval ceremony before any public-facing prompt variant leaves staff-only rehearsal.

Read the README · Read the manual

diff --git a/pyproject.toml b/pyproject.toml index 9bd45a3..d02ffe0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "civicclerk" -version = "1.0.3" +version = "1.0.4" description = "CivicClerk runtime foundation for municipal meeting, agenda, packet, and minutes workflows." readme = "README.md" requires-python = ">=3.11" diff --git a/scripts/build_release_handoff_bundle.ps1 b/scripts/build_release_handoff_bundle.ps1 index 458392f..6991f46 100644 --- a/scripts/build_release_handoff_bundle.ps1 +++ b/scripts/build_release_handoff_bundle.ps1 @@ -1,5 +1,5 @@ param( - [string]$Version = "1.0.3", + [string]$Version = "1.0.4", [string]$OutputPath = "", [switch]$PrintOnly ) diff --git a/scripts/build_release_handoff_bundle.sh b/scripts/build_release_handoff_bundle.sh index cf1fa40..5b3651c 100755 --- a/scripts/build_release_handoff_bundle.sh +++ b/scripts/build_release_handoff_bundle.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -version="1.0.3" +version="1.0.4" output_path="" print_only=0 diff --git a/scripts/check_backup_restore_rehearsal.py b/scripts/check_backup_restore_rehearsal.py index 288a712..18996e0 100644 --- a/scripts/check_backup_restore_rehearsal.py +++ b/scripts/check_backup_restore_rehearsal.py @@ -11,11 +11,14 @@ import hashlib import json import shutil +import sys from dataclasses import dataclass from datetime import UTC, datetime from pathlib import Path ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) DEFAULT_REHEARSAL_ROOT = ROOT / ".backup-restore-rehearsal" STORE_FILES = { "CIVICCLERK_AGENDA_INTAKE_DB_URL": "agenda-intake.db", diff --git a/scripts/check_connector_sync_readiness.py b/scripts/check_connector_sync_readiness.py index 5bfa651..02477b5 100644 --- a/scripts/check_connector_sync_readiness.py +++ b/scripts/check_connector_sync_readiness.py @@ -4,9 +4,14 @@ import argparse import json +import sys from dataclasses import dataclass from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk.connectors import ( ConnectorImportError, SUPPORTED_CONNECTORS, diff --git a/scripts/check_deployment_readiness.py b/scripts/check_deployment_readiness.py index d370bd6..bc70933 100644 --- a/scripts/check_deployment_readiness.py +++ b/scripts/check_deployment_readiness.py @@ -6,10 +6,15 @@ import asyncio import os import shlex +import sys from dataclasses import dataclass from pathlib import Path from typing import Iterable +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from fastapi import HTTPException from civicclerk import __version__ @@ -22,7 +27,6 @@ from civiccore import __version__ as CIVICCORE_VERSION -ROOT = Path(__file__).resolve().parents[1] DIST_ROOT_ENV_VAR = "CIVICCLERK_DEPLOYMENT_PREFLIGHT_DIST_ROOT" DATABASE_ENV_VARS = ( "CIVICCLERK_AGENDA_INTAKE_DB_URL", diff --git a/scripts/check_enterprise_installer_signing.py b/scripts/check_enterprise_installer_signing.py index 2b6d7e8..271ca90 100644 --- a/scripts/check_enterprise_installer_signing.py +++ b/scripts/check_enterprise_installer_signing.py @@ -10,7 +10,7 @@ ROOT = Path(__file__).resolve().parents[1] -DEFAULT_VERSION = "1.0.3" +DEFAULT_VERSION = "1.0.4" DEFAULT_ARTIFACT = Path("installer/windows/build") / f"CivicClerk-{DEFAULT_VERSION}-Setup.exe" SIGNTOOL_ENV_VARS = ("CIVICCLERK_SIGNTOOL_PATH", "SIGNTOOL") SHA1_ENV_VAR = "CIVICCLERK_SIGNING_CERT_SHA1" diff --git a/scripts/check_installer_readiness.py b/scripts/check_installer_readiness.py index f3a758c..3a44967 100644 --- a/scripts/check_installer_readiness.py +++ b/scripts/check_installer_readiness.py @@ -10,7 +10,7 @@ ROOT = Path(__file__).resolve().parents[1] -DEFAULT_VERSION = "1.0.3" +DEFAULT_VERSION = "1.0.4" def _bundle_entries(version: str) -> tuple[str, ...]: diff --git a/scripts/check_pilot_readiness.py b/scripts/check_pilot_readiness.py index b34fea8..fbaa59c 100644 --- a/scripts/check_pilot_readiness.py +++ b/scripts/check_pilot_readiness.py @@ -4,9 +4,14 @@ import argparse import json +import sys from dataclasses import dataclass from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk import __version__ from civicclerk.mock_city_environment import ( MOCK_CITY_NAME, @@ -17,7 +22,6 @@ from scripts.check_installer_readiness import build_checks as build_installer_checks -ROOT = Path(__file__).resolve().parents[1] DEFAULT_VERSION = __version__ DOC_WARNING_FILES = ( "README.md", diff --git a/scripts/check_protected_deployment_smoke.py b/scripts/check_protected_deployment_smoke.py index b788b57..704942c 100644 --- a/scripts/check_protected_deployment_smoke.py +++ b/scripts/check_protected_deployment_smoke.py @@ -6,18 +6,20 @@ import asyncio import json import os +import sys from pathlib import Path from typing import Any +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + import httpx from civicclerk.main import STAFF_AUTH_TOKEN_ROLES_ENV_VAR, app from scripts.check_deployment_readiness import _load_env_file, build_checks -ROOT = Path(__file__).resolve().parents[1] - - def _redacted_headers(headers: dict[str, str]) -> dict[str, str]: redacted: dict[str, str] = {} for key, value in headers.items(): diff --git a/scripts/check_starter_set_integration.py b/scripts/check_starter_set_integration.py index fd4ed8e..dd966c4 100644 --- a/scripts/check_starter_set_integration.py +++ b/scripts/check_starter_set_integration.py @@ -4,13 +4,17 @@ import argparse import json +import sys from dataclasses import dataclass from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk import __version__ -ROOT = Path(__file__).resolve().parents[1] DEFAULT_UMBRELLA_ROOT = ROOT.parent / "civicsuite" EXPECTED_CIVICCORE_RUNTIME = "1.2.0" EXPECTED_RECORDS_VERSION = "1.6.1" @@ -164,7 +168,7 @@ def build_checks(*, umbrella_root: Path, require_archives: bool) -> list[Check]: required_phrases = ( "CivicCore installs first", "CivicRecords AI and CivicClerk are selectable", - "CivicClerk reports v1.0.3 with CivicCore v1.2.0", + "CivicClerk reports v1.0.4 with CivicCore v1.2.0", "--staff-mode bearer --workflow-proof", "Package Cleanroom Contract", "workflow_proof_requested=true", diff --git a/scripts/check_vendor_live_sync_readiness.py b/scripts/check_vendor_live_sync_readiness.py index 612190d..cb96551 100644 --- a/scripts/check_vendor_live_sync_readiness.py +++ b/scripts/check_vendor_live_sync_readiness.py @@ -3,6 +3,12 @@ from __future__ import annotations import argparse +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) from civicclerk.connectors import SUPPORTED_CONNECTORS from civicclerk.vendor_live_sync import ( diff --git a/scripts/cleanroom/civicclerk-cleanroom-runner.sh b/scripts/cleanroom/civicclerk-cleanroom-runner.sh index 13344d9..4518cef 100644 --- a/scripts/cleanroom/civicclerk-cleanroom-runner.sh +++ b/scripts/cleanroom/civicclerk-cleanroom-runner.sh @@ -142,7 +142,7 @@ import civicclerk from civicclerk.main import app assert civiccore.__version__ == "1.2.0" -assert civicclerk.__version__ == "1.0.3" +assert civicclerk.__version__ == "1.0.4" assert app.title == "CivicClerk" assert callable(civiccore.validate_manifest) assert callable(civiccore.import_meeting_payload) diff --git a/scripts/generate-openapi-spec.py b/scripts/generate-openapi-spec.py index f3f8348..cdbbaf7 100644 --- a/scripts/generate-openapi-spec.py +++ b/scripts/generate-openapi-spec.py @@ -3,12 +3,16 @@ from __future__ import annotations import json +import sys from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk.main import app -ROOT = Path(__file__).resolve().parents[1] OUTPUT = ROOT / "docs" / "api" / "openapi.json" diff --git a/scripts/run_connector_import_sync.py b/scripts/run_connector_import_sync.py index 820865e..7fa875c 100644 --- a/scripts/run_connector_import_sync.py +++ b/scripts/run_connector_import_sync.py @@ -3,8 +3,13 @@ from __future__ import annotations import argparse +import sys from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk.connector_import_sync import ImportAttempt, run_import_sync from civicclerk.connectors import SUPPORTED_CONNECTORS diff --git a/scripts/run_mock_city_environment_suite.py b/scripts/run_mock_city_environment_suite.py index 51f0eb8..17656cf 100644 --- a/scripts/run_mock_city_environment_suite.py +++ b/scripts/run_mock_city_environment_suite.py @@ -4,8 +4,13 @@ import argparse import json +import sys from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk.mock_city_environment import ( MOCK_CITY_NAME, mock_city_backup_retention_contract, diff --git a/scripts/run_vendor_live_sync.py b/scripts/run_vendor_live_sync.py index 43c63dc..d21f913 100644 --- a/scripts/run_vendor_live_sync.py +++ b/scripts/run_vendor_live_sync.py @@ -3,8 +3,13 @@ from __future__ import annotations import argparse +import sys from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civicclerk.vendor_network_sync import NETWORK_ENABLED_ENV_VAR, run_vendor_network_sync from civicclerk.vendor_sync_persistence import VendorSyncRepository diff --git a/scripts/start_fresh_install_rehearsal.ps1 b/scripts/start_fresh_install_rehearsal.ps1 index 6f345bf..cc4bb9d 100644 --- a/scripts/start_fresh_install_rehearsal.ps1 +++ b/scripts/start_fresh_install_rehearsal.ps1 @@ -1,5 +1,5 @@ param( - [string]$WheelPath = "dist/civicclerk-1.0.3-py3-none-any.whl", + [string]$WheelPath = "dist/civicclerk-1.0.4-py3-none-any.whl", [string]$RehearsalRoot = ".fresh-install-rehearsal", [int]$AppPort = 8776, [switch]$KeepServer, @@ -47,7 +47,7 @@ function Write-FreshInstallPlan { Write-Output "Smoke check: GET $AppUrl/health" Write-Output "Readiness check: GET $AppUrl/staff/auth-readiness" Write-Output "Browser check: open $AppUrl/staff" - Write-Output "Expected health: {`"status`":`"ok`",`"service`":`"civicclerk`",`"version`":`"1.0.3`",`"civiccore`":`"1.2.0`"}" + Write-Output "Expected health: {`"status`":`"ok`",`"service`":`"civicclerk`",`"version`":`"1.0.4`",`"civiccore`":`"1.2.0`"}" Write-Output "Expected auth readiness: mode=protected and anonymous staff writes denied" Write-Output "If the wheel is missing, build it first with: python -m build" Write-Output "If port $AppPort is already in use, stop the existing process or rerun with -AppPort set to an available port." @@ -135,8 +135,8 @@ try { throw "The installed CivicClerk app did not answer $appUrl/health within 20 seconds. Check the app process output and whether port $AppPort is already in use." } - if ($health.status -ne "ok" -or $health.service -ne "civicclerk" -or $health.version -ne "1.0.3" -or $health.civiccore -ne "1.2.0") { - throw "Unexpected /health response: $($health | ConvertTo-Json -Compress). Expected CivicClerk 1.0.3 with CivicCore 1.2.0." + if ($health.status -ne "ok" -or $health.service -ne "civicclerk" -or $health.version -ne "1.0.4" -or $health.civiccore -ne "1.2.0") { + throw "Unexpected /health response: $($health | ConvertTo-Json -Compress). Expected CivicClerk 1.0.4 with CivicCore 1.2.0." } $readiness = Invoke-JsonGet -Url "$appUrl/staff/auth-readiness" diff --git a/scripts/start_fresh_install_rehearsal.sh b/scripts/start_fresh_install_rehearsal.sh index d5dbe7d..2764b39 100755 --- a/scripts/start_fresh_install_rehearsal.sh +++ b/scripts/start_fresh_install_rehearsal.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -wheel_path="dist/civicclerk-1.0.3-py3-none-any.whl" +wheel_path="dist/civicclerk-1.0.4-py3-none-any.whl" rehearsal_root=".fresh-install-rehearsal" app_port=8776 keep_server=0 @@ -81,7 +81,7 @@ write_plan() { echo "Smoke check: GET ${app_url}/health" echo "Readiness check: GET ${app_url}/staff/auth-readiness" echo "Browser check: open ${app_url}/staff" - echo 'Expected health: {"status":"ok","service":"civicclerk","version":"1.0.3","civiccore":"1.2.0"}' + echo 'Expected health: {"status":"ok","service":"civicclerk","version":"1.0.4","civiccore":"1.2.0"}' echo "Expected auth readiness: mode=protected and anonymous staff writes denied" echo "If the wheel is missing, build it first with: python -m build" echo "If port ${app_port} is already in use, stop the existing process or rerun with --app-port set to an available port." @@ -165,13 +165,13 @@ for _ in {1..20}; do sleep 1 done -expected='{"civiccore": "1.2.0", "service": "civicclerk", "status": "ok", "version": "1.0.3"}' +expected='{"civiccore": "1.2.0", "service": "civicclerk", "status": "ok", "version": "1.0.4"}' if [[ -z "${health}" ]]; then echo "The installed CivicClerk app did not answer ${app_url}/health within 20 seconds. Check the app process output and whether port ${app_port} is already in use." >&2 exit 1 fi if [[ "${health}" != "${expected}" ]]; then - echo "Unexpected /health response: ${health}. Expected CivicClerk 1.0.3 with CivicCore 1.2.0." >&2 + echo "Unexpected /health response: ${health}. Expected CivicClerk 1.0.4 with CivicCore 1.2.0." >&2 exit 1 fi diff --git a/scripts/verify-browser-qa.py b/scripts/verify-browser-qa.py index ebc462c..54cc652 100644 --- a/scripts/verify-browser-qa.py +++ b/scripts/verify-browser-qa.py @@ -2,15 +2,19 @@ from __future__ import annotations -import tomllib import json +import sys +import tomllib from pathlib import Path +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + from civiccore.verification import validate_release_browser_evidence from civicclerk.cc7_completeness import CC7_FRONTEND_PAGES, REQUIRED_VIEW_STATES -ROOT = Path(__file__).resolve().parents[1] REQUIRED_STATES = ("loading", "success", "empty", "error", "partial") REQUIRED_CHECKS = ("keyboard", "focus", "contrast", "console") diff --git a/scripts/verify-release.sh b/scripts/verify-release.sh index e04d64f..4ee4fd2 100644 --- a/scripts/verify-release.sh +++ b/scripts/verify-release.sh @@ -88,7 +88,7 @@ if [[ -f "frontend/package-lock.json" ]]; then echo "==> frontend Playwright user flows" ( cd frontend - npx playwright install chromium + npx playwright install --only-shell chromium npm run test:e2e ) fi @@ -175,7 +175,7 @@ health = client.get("/health") assert health.status_code == 200, health.text payload = health.json() assert payload["status"] == "ok", payload -assert payload["version"] == "1.0.3", payload +assert payload["version"] == "1.0.4", payload staff = client.get("/staff") assert staff.status_code == 200, staff.text[:300] print("RUNTIME-INSTALL-PROOF: PASSED") diff --git a/tests/test_deployment_readiness_helper.py b/tests/test_deployment_readiness_helper.py index aebce12..1b5b80c 100644 --- a/tests/test_deployment_readiness_helper.py +++ b/tests/test_deployment_readiness_helper.py @@ -6,7 +6,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" DEPLOYMENT_ENV_VARS = ( "CIVICCLERK_STAFF_AUTH_MODE", "CIVICCLERK_STAFF_AUTH_TOKEN_ROLES", diff --git a/tests/test_enterprise_installer_signing.py b/tests/test_enterprise_installer_signing.py index 811f1c7..5a59b1e 100644 --- a/tests/test_enterprise_installer_signing.py +++ b/tests/test_enterprise_installer_signing.py @@ -7,7 +7,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" def test_enterprise_installer_signing_print_only_explains_inputs() -> None: diff --git a/tests/test_github_workflows.py b/tests/test_github_workflows.py index 1d873a8..d44b22b 100644 --- a/tests/test_github_workflows.py +++ b/tests/test_github_workflows.py @@ -25,7 +25,7 @@ def test_release_workflow_dispatch_release_tag_contract() -> None: release_tag = workflow_dispatch["inputs"]["release_tag"] assert release_tag["required"] is True - assert release_tag["default"] == "v1.0.3" + assert release_tag["default"] == "v1.0.4" def test_release_workflow_cleanroom_release_gate_contract() -> None: diff --git a/tests/test_installer_readiness_helper.py b/tests/test_installer_readiness_helper.py index bfa7827..88f0073 100644 --- a/tests/test_installer_readiness_helper.py +++ b/tests/test_installer_readiness_helper.py @@ -7,7 +7,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" def _bundle_entries(version: str) -> tuple[str, ...]: diff --git a/tests/test_milestone_12_release.py b/tests/test_milestone_12_release.py index d646b20..831cfd4 100644 --- a/tests/test_milestone_12_release.py +++ b/tests/test_milestone_12_release.py @@ -1,4 +1,4 @@ -"""Milestone 12+ v1.0.3 release contract.""" +"""Milestone 12+ v1.0.4 release contract.""" from __future__ import annotations @@ -31,13 +31,13 @@ def test_version_surfaces_are_synchronized_to_v101() -> None: ) changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8") - assert pyproject["project"]["version"] == "1.0.3" - assert __version__ == "1.0.3" - assert "Current version: `1.0.3`" in current_docs - assert "Version: `1.0.3`" in current_docs - assert "v1.0.3" in current_docs + assert pyproject["project"]["version"] == "1.0.4" + assert __version__ == "1.0.4" + assert "Current version: `1.0.4`" in current_docs + assert "Version: `1.0.4`" in current_docs + assert "v1.0.4" in current_docs assert "0.1.0.dev0" not in current_docs - assert "## [1.0.3] - 2026-05-23" in changelog + assert "## [1.0.4] - 2026-06-13" in changelog assert "## [1.0.0] - 2026-05-06" in changelog @@ -46,7 +46,7 @@ async def test_health_endpoint_reports_release_version() -> None: response = await client.get("/health") assert response.status_code == 200 - assert response.json()["version"] == "1.0.3" + assert response.json()["version"] == "1.0.4" def test_verify_release_script_exists_and_mentions_all_release_gates() -> None: @@ -91,7 +91,7 @@ def test_release_workflow_and_docs_reference_v101_release() -> None: assert "gh release create" in workflow assert "dist/*" in workflow assert "civiccore/releases/download/v1.2.0/civiccore-1.2.0-py3-none-any.whl" in workflow - assert "civicclerk v1.0.3" in docs + assert "civicclerk v1.0.4" in docs assert "published `civiccore` 1.2.0 wheel from the `v1.2.0` release asset" in docs @@ -110,7 +110,7 @@ def test_docs_include_fresh_machine_install_and_smoke_check_contract() -> None: for expected in [ "python -m venv .venv", ".\\.venv\\Scripts\\Activate.ps1", - "python -m pip install dist/civicclerk-1.0.3-py3-none-any.whl", + "python -m pip install dist/civicclerk-1.0.4-py3-none-any.whl", "python -m uvicorn civicclerk.main:app --host 127.0.0.1 --port 8776", "http://127.0.0.1:8776/health", "/staff/auth-readiness", @@ -228,7 +228,7 @@ def test_fresh_install_rehearsal_script_prints_expected_plan() -> None: "Smoke check: GET http://127.0.0.1:8776/health", "Readiness check: GET http://127.0.0.1:8776/staff/auth-readiness", "Browser check: open http://127.0.0.1:8776/staff", - "Expected health: {\"status\":\"ok\",\"service\":\"civicclerk\",\"version\":\"1.0.3\",\"civiccore\":\"1.2.0\"}", + "Expected health: {\"status\":\"ok\",\"service\":\"civicclerk\",\"version\":\"1.0.4\",\"civiccore\":\"1.2.0\"}", "If the wheel is missing, build it first with: python -m build", "If port 8776 is already in use, stop the existing process or rerun with -AppPort set to an available port.", "pass -KeepServer to keep it running", @@ -282,7 +282,7 @@ def test_fresh_install_rehearsal_bash_script_prints_expected_plan() -> None: "Smoke check: GET http://127.0.0.1:8776/health", "Readiness check: GET http://127.0.0.1:8776/staff/auth-readiness", "Browser check: open http://127.0.0.1:8776/staff", - "Expected health: {\"status\":\"ok\",\"service\":\"civicclerk\",\"version\":\"1.0.3\",\"civiccore\":\"1.2.0\"}", + "Expected health: {\"status\":\"ok\",\"service\":\"civicclerk\",\"version\":\"1.0.4\",\"civiccore\":\"1.2.0\"}", "If the wheel is missing, build it first with: python -m build", "If port 8776 is already in use, stop the existing process or rerun with --app-port set to an available port.", "pass --keep-server to keep it running", @@ -321,10 +321,10 @@ def test_release_handoff_bundle_script_prints_expected_plan() -> None: output = result.stdout for expected in [ "CivicClerk release handoff bundle", - "Version: 1.0.3", - "civicclerk-1.0.3-release-handoff.zip", - "dist/civicclerk-1.0.3-py3-none-any.whl", - "dist/civicclerk-1.0.3.tar.gz", + "Version: 1.0.4", + "civicclerk-1.0.4-release-handoff.zip", + "dist/civicclerk-1.0.4-py3-none-any.whl", + "dist/civicclerk-1.0.4.tar.gz", "dist/SHA256SUMS.txt", "scripts/check_installer_readiness.py", "scripts/check_enterprise_installer_signing.py", @@ -381,10 +381,10 @@ def test_release_handoff_bundle_bash_script_prints_expected_plan() -> None: output = result.stdout for expected in [ "CivicClerk release handoff bundle", - "Version: 1.0.3", - "civicclerk-1.0.3-release-handoff.zip", - "dist/civicclerk-1.0.3-py3-none-any.whl", - "dist/civicclerk-1.0.3.tar.gz", + "Version: 1.0.4", + "civicclerk-1.0.4-release-handoff.zip", + "dist/civicclerk-1.0.4-py3-none-any.whl", + "dist/civicclerk-1.0.4.tar.gz", "dist/SHA256SUMS.txt", "scripts/check_installer_readiness.py", "scripts/check_enterprise_installer_signing.py", diff --git a/tests/test_milestone_13_staff_workflow_ui.py b/tests/test_milestone_13_staff_workflow_ui.py index 7f468eb..3213d9a 100644 --- a/tests/test_milestone_13_staff_workflow_ui.py +++ b/tests/test_milestone_13_staff_workflow_ui.py @@ -12,7 +12,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" async def test_staff_ui_endpoint_renders_accessible_workflow_foundation() -> None: diff --git a/tests/test_milestone_1_runtime_foundation.py b/tests/test_milestone_1_runtime_foundation.py index 238a745..08fb8ed 100644 --- a/tests/test_milestone_1_runtime_foundation.py +++ b/tests/test_milestone_1_runtime_foundation.py @@ -13,7 +13,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" def load_pyproject() -> dict: diff --git a/tests/test_pilot_readiness_helper.py b/tests/test_pilot_readiness_helper.py index 1ffbfc8..c5354ee 100644 --- a/tests/test_pilot_readiness_helper.py +++ b/tests/test_pilot_readiness_helper.py @@ -7,7 +7,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" def _bundle_entries(version: str) -> tuple[str, ...]: diff --git a/tests/test_protected_deployment_smoke_helper.py b/tests/test_protected_deployment_smoke_helper.py index 9d20bcf..92f6179 100644 --- a/tests/test_protected_deployment_smoke_helper.py +++ b/tests/test_protected_deployment_smoke_helper.py @@ -5,7 +5,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" DEPLOYMENT_ENV_VARS = ( "CIVICCLERK_STAFF_AUTH_MODE", "CIVICCLERK_STAFF_AUTH_TOKEN_ROLES", diff --git a/tests/test_public_portal_ui.py b/tests/test_public_portal_ui.py index 45e5326..1c28e63 100644 --- a/tests/test_public_portal_ui.py +++ b/tests/test_public_portal_ui.py @@ -11,7 +11,7 @@ ROOT = Path(__file__).resolve().parents[1] -VERSION = "1.0.3" +VERSION = "1.0.4" @pytest.mark.asyncio diff --git a/tests/test_starter_set_integration_helper.py b/tests/test_starter_set_integration_helper.py index b1eeac8..50530b2 100644 --- a/tests/test_starter_set_integration_helper.py +++ b/tests/test_starter_set_integration_helper.py @@ -33,7 +33,7 @@ def _write_umbrella_fixture(root: Path) -> None: }, { "id": "civicclerk", - "current_version": "1.0.3", + "current_version": "1.0.4", "selectable": True, "civiccore_requirement": "1.2.0", "dependencies": ["civiccore"], @@ -48,7 +48,7 @@ def _write_umbrella_fixture(root: Path) -> None: [ "CivicCore installs first", "CivicRecords AI and CivicClerk are selectable", - "CivicClerk reports v1.0.3 with CivicCore v1.2.0", + "CivicClerk reports v1.0.4 with CivicCore v1.2.0", "--staff-mode bearer --workflow-proof", "Package Cleanroom Contract", "workflow_proof_requested=true", diff --git a/tests/test_suite_session_bearer_contract.py b/tests/test_suite_session_bearer_contract.py index 2ba2838..26fb4b6 100644 --- a/tests/test_suite_session_bearer_contract.py +++ b/tests/test_suite_session_bearer_contract.py @@ -8,16 +8,23 @@ from civicclerk.main import STAFF_AUTH_MODE_ENV_VAR, STAFF_BEARER_MODE, app +def _issue_suite_session_token(**kwargs: object) -> str: + try: + from civiccore.auth.suite_session import issue_suite_session_token + except ModuleNotFoundError: + from civicclerk.suite_session_compat import issue_suite_session_token + + return issue_suite_session_token(**kwargs) + + @pytest.mark.asyncio @pytest.mark.uses_civicclerk_default_staff_mode async def test_civicclerk_staff_session_accepts_civiccore_suite_bearer( monkeypatch: pytest.MonkeyPatch, ) -> None: - from civiccore.auth.suite_session import issue_suite_session_token - monkeypatch.setenv(STAFF_AUTH_MODE_ENV_VAR, STAFF_BEARER_MODE) monkeypatch.setenv("CIVICCORE_SUITE_SESSION_SECRET", "clerk-suite-session-secret") - token = issue_suite_session_token( + token = _issue_suite_session_token( subject="clerk@example.gov", roles=frozenset({"clerk_admin", "meeting_editor"}), session_id="clerk-suite-session", @@ -42,15 +49,13 @@ async def test_civicclerk_staff_logout_revokes_civiccore_suite_bearer( tmp_path, monkeypatch: pytest.MonkeyPatch, ) -> None: - from civiccore.auth.suite_session import issue_suite_session_token - monkeypatch.setenv(STAFF_AUTH_MODE_ENV_VAR, STAFF_BEARER_MODE) monkeypatch.setenv("CIVICCORE_SUITE_SESSION_SECRET", "clerk-suite-session-secret") monkeypatch.setenv( "CIVICCORE_SUITE_SESSION_REVOCATION_FILE", str(tmp_path / "suite-session-revocations.json"), ) - token = issue_suite_session_token( + token = _issue_suite_session_token( subject="clerk@example.gov", roles=frozenset({"clerk_admin", "meeting_editor"}), session_id="clerk-suite-session-logout",