Skip to content

Feat/stit 766 ci - #334

Open
AlexAxthelm wants to merge 2 commits into
feat/stit-766-read-pathfrom
feat/stit-766-ci
Open

AlexAxthelm wants to merge 2 commits into
feat/stit-766-read-pathfrom
feat/stit-766-ci

Conversation

@AlexAxthelm

@AlexAxthelm AlexAxthelm commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fifth (last) PR of splitting #324 into smaller PRs for ease of review. Builds on #333

Wire up the new read model as part of CI/CD deployments. This adds an optional "wait" for the container deploy action, which checks that the cutover is complete before reporting green, which allows us to ensure that the traffic is all pointed at the new version before initiating a read-state rebuild (which is keyed on code version), so that we don't run into version conflicts on the read table.

In the moments where the new code version is live, but the rebuild hasn't happened yet, the application will have some degraded performance, since it falls back to the live coalescing path.


Summary

Fifth PR in the STIT-766 read-model stack (builds on #333). CI now rebuilds the read model after each API deploy, once the previous API revision has stopped serving.

Why the deploy has to wait first

  • New code doesn't trust old rows: the read model only counts as ready when it was built by the commit the API is running, so every deploy of new code reads live until a rebuild by that code finishes.
  • The old revision keeps writing during cutover: Azure Container Apps can keep the previous revision serving after the deploy action returns. Those writes refresh rows using the old code's rules.
  • Those writes are only a problem after the rebuild finishes: writes that land during the rebuild are caught (each row records the commit that computed it) and redone. One that lands after the rebuild has marked the table ready would be served. So the rebuild must not start until the old revision has stopped.

Changes

  • deploy-container.yml: new wait-for-cutover input (opt-in; only the API sets it).
    • After deploying, it polls az containerapp revision list every 10 s until no active revision runs another image and one running this image has finished provisioning, then waits 45 s for in-flight requests to drain.
    • It fails the deploy if the new revision fails to provision, or doesn't take over within 10 minutes.
    • A failed poll (ARM throttling, a network blip, an unexpected payload) is logged and retried, not fatal.
  • New rebuild-read-model.yml: runs python -m stitch.api.db.read_model.rebuild --if-stale from the deployed API image (so it records the same commit as the API), as stitch_app.
    • --if-stale makes it a no-op when the read model is already current, and resumes where a failed run stopped.
  • build-and-deploy.yml:
    • the API deploy sets wait-for-cutover: true;
    • the new rebuild-read-model job runs after it;
    • the PR summary waits for it.
    • Nothing waits on the rebuild: if it fails, the deploy still goes out and lists stay on the slower live path, which is correct, just slower.
  • PR summary comment: if the rebuild doesn't succeed on a PR, the summary shows a warning saying list reads are on the live path. build_pr_summary_comment.py now lets an entry contribute only warnings, with no table row.
  • Docs:

The stack

  1. Schema (feat(api): add the resource-state read model tables #330)
  2. Build and rebuild (feat(api): build/rebuild the resource-state read model tables #331)
  3. Writes keep the table current (feat(api): keep the resource-state read model current on writes #332)
  4. Read path, readiness cache and switch-off (feat(api): serve field lists from the resource-state read model #333)
  5. CI: rebuild after each deploy, after waiting for the cutover (this PR)

With this, the stack covers everything in #324, apart from the design docs, which are going in a separate PR.

Related issues

Part of: STIT-766
Replaces: #324 (split for review)

Testing

  • The workflows are tested by this PR's own CI run. On Feat/stit 766 resource state #324, the same cutover wait was seen working in a real deploy: the old revision was still active when the deploy action returned, and the step waited until it stopped. Things to check on this run:
    • Deploy API logs "waiting: … active revision(s) on another image" lines, then "Only revisions running … are active".
    • Rebuild Read Model runs after Deploy API and logs "the read model is ready".
    • The preview's list reads use the fast path: the resources.list_page query label instead of resources.list_ids + resources.list_hydrate.
  • Locally:
    • the three workflows parse, and yamllint reports nothing new compared with main (ignoring line length);
    • the summary script, fed only the rebuild's warning entry, renders just the Warnings section;
    • make check passes.
  • Not covered by automated tests: the cutover check's jq filter (the repo has no home for CI-script tests yet). It was checked against simulated revision lists locally and in the real deploy above. If it breaks, API deploys would time out after 10 minutes.

Checklist

  • PR is focused on a single concern
  • Tests pass locally and in CI
  • Docs updated for user-visible changes
  • AI-assisted portions declared (see CONTRIBUTING.md)

AI use: Claude Code split this out of #324 and wrote most of the workflow changes and docs. I reviewed it before committing. Verified by the local checks above and this PR's CI run (and, for the cutover wait, a real deploy on #324).

🤖 Generated with Claude Code

Add a Rebuild Read Model job that runs `rebuild --if-stale` from the
deployed API image once the API deploy finishes, so each deploy of new
code gets its fast path back without a manual step. The API deploy now
waits until the previous revision has stopped serving (plus 45 s for
in-flight requests), so the old code's writes can't land after the
rebuild marks the table ready. Nothing waits on the rebuild: if it
fails, lists stay on the slower live path and the PR summary comment
shows a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

CD summary 159a814

Frontend: https://witty-mushroom-017a3dc1e-334.westus2.1.azurestaticapps.net

Deployments (3)
service url fqdn
api open pr-0334-api.purplegrass-c07d0a94.westus2.azurecontainerapps.io
frontend https://witty-mushroom-017a3dc1e-334.westus2.1.azurestaticapps.net
stitch-llm open pr-0334-llm.purplegrass-c07d0a94.westus2.azurecontainerapps.io
Database (1)
db_name postgres_host postgres_port postgres_db
pr_0334 stitch-dev.postgres.database.azure.com 5432 pr_0334
Jobs (2)
job image postgres_db api_url auth_mode
db-migrations ghcr.io/rmi/stitch-api:pr-0334@sha256:7a961dc2995941192c4692cdf8c40c0a646b4e1e8cf330b0f38f82a157faabfa pr_0334
seed ghcr.io/rmi/stitch-seed:pr-0334@sha256:d4fd2a110684b179b87d2c3d62cf7ecef24d544886b749aa5a0a07549d5c4aea https://pr-0334-api.purplegrass-c07d0a94.westus2.azurecontainerapps.io/api/v1 stitch-client-bearer-token
Images (3)
build_time commit_time git_sha image image_digest
2026-10-16T08:46:07Z 2026-10-16T08:45:48Z c230a79 ghcr.io/rmi/stitch-api:pr-0334 ghcr.io/rmi/stitch-api:pr-0334@sha256:7a961dc2995941192c4692cdf8c40c0a646b4e1e8cf330b0f38f82a157faabfa
2026-10-16T08:46:09Z 2026-10-16T08:45:48Z c230a79 ghcr.io/rmi/stitch-seed:pr-0334 ghcr.io/rmi/stitch-seed:pr-0334@sha256:d4fd2a110684b179b87d2c3d62cf7ecef24d544886b749aa5a0a07549d5c4aea
2026-10-16T08:46:05Z 2026-10-16T08:45:48Z c230a79 ghcr.io/rmi/stitch-stitch-llm:pr-0334 ghcr.io/rmi/stitch-stitch-llm:pr-0334@sha256:09c31accaf1a110a4b31372c74e3e097218e78229e05082c6104a246ce940f72

@AlexAxthelm AlexAxthelm self-assigned this Oct 16, 2026
@AlexAxthelm
AlexAxthelm marked this pull request as ready for review October 16, 2026 09:19
Copilot AI balanced review requested due to automatic review settings October 16, 2026 09:19
@AlexAxthelm AlexAxthelm mentioned this pull request Oct 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Version-safety gaps can expose mixed-version read-model rows during cutover and after disabled-table repairs.

2 open findings
What changed in this PR

Completes the STIT-766 rollout by rebuilding the API’s permission-scoped read model after deployment cutover, with live-query fallback until ready.

Changes:

  • Adds cutover waiting, post-deploy rebuilds, and PR warning reporting.
  • Includes read-model storage, queries, write maintenance, and rebuild controls.
  • Adds regression tests and operational documentation.
File Description
HACKING.md Documents local rebuilds.
deployments/​CI_DEPLOYMENTS.md Explains automated deployment sequencing.
deployments/​api/​tests/​observability/​test_query_name_actions.py Verifies read-model query labels.
deployments/​api/​tests/​db/​read_model/​test_state.py Tests rebuilds, readiness, and repairs.
deployments/​api/​tests/​db/​read_model/​test_resource_state_schema.py Checks schema constraints and types.
deployments/​api/​tests/​db/​read_model/​test_rebuild_lock_postgres.py Tests rebuild locking.
deployments/​api/​tests/​db/​read_model/​test_rebuild_and_repair_postgres.py Tests concurrent rebuilds and repairs.
deployments/​api/​tests/​db/​read_model/​test_read_path.py Tests parity and live fallback.
deployments/​api/​tests/​db/​read_model/​test_read_path_postgres.py Tests PostgreSQL read consistency.
deployments/​api/​tests/​db/​read_model/​test_permissions.py Tests exact permission matching.
deployments/​api/​tests/​db/​read_model/​test_mutations.py Verifies write-maintained state.
deployments/​api/​tests/​db/​read_model/​test_concurrency_postgres.py Tests concurrent writes and locking.
deployments/​api/​tests/​db/​read_model/​scenarios.py Shares rebuild concurrency scenarios.
deployments/​api/​tests/​db/​read_model/​postgres.py Controls PostgreSQL test availability.
deployments/​api/​tests/​db/​read_model/​dataset.py Provides deterministic test data.
deployments/​api/​tests/​db/​read_model/​conftest.py Provides isolated database fixtures.
deployments/​api/​tests/​db/​read_model/​__init__.py Defines the test package.
deployments/​api/​tests/​conftest.py Resets cached readiness between tests.
deployments/​api/​src/​stitch/​api/​db/​read_model/​state.py Implements state maintenance and rebuilds.
deployments/​api/​src/​stitch/​api/​db/​read_model/​rebuild.py Adds the rebuild and repair CLI.
deployments/​api/​src/​stitch/​api/​db/​read_model/​permissions.py Defines permission profiles.
deployments/​api/​src/​stitch/​api/​db/​read_model/​__init__.py Documents the read-model package.
deployments/​api/​src/​stitch/​api/​db/​queries.py Adds stored-state queries.
deployments/​api/​src/​stitch/​api/​db/​og_field_source_actions.py Refreshes state on source attachments.
deployments/​api/​src/​stitch/​api/​db/​og_field_resource_actions.py Adds cached reads and write refreshes.
deployments/​api/​src/​stitch/​api/​db/​model/​og_field_resource_state.py Defines state and readiness models.
deployments/​api/​src/​stitch/​api/​db/​model/​__init__.py Exports the new models.
deployments/​api/​README.md Links rebuild guidance.
deployments/​api/​READ_MODEL.md Provides rollout and recovery guidance.
deployments/​api/​alembic/​versions/​48a49d197641_add_resource_state_read_model.py Creates read-model tables and indexes.
deployments/​api/​alembic/​versions/​2f2fb644b180_resource_state_disabled_flag.py Adds the operator disable flag.
.github/​workflows/​rebuild-read-model.yml Runs post-deploy rebuilds.
.github/​workflows/​python-test.yml Enables PostgreSQL tests in CI.
.github/​workflows/​deploy-container.yml Adds optional cutover waiting.
.github/​workflows/​build-and-deploy.yml Connects deployment and rebuild jobs.
.github/​scripts/​build_pr_summary_comment.py Supports warning-only entries.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread deployments/api/src/stitch/api/db/read_model/rebuild.py
Comment thread deployments/api/src/stitch/api/db/read_model/state.py
@AlexAxthelm AlexAxthelm mentioned this pull request Oct 16, 2026
4 tasks done
@AlexAxthelm AlexAxthelm mentioned this pull request Oct 16, 2026
@AlexAxthelm
AlexAxthelm changed the base branch from main to feat/stit-766-read-path October 16, 2026 11:18

This branch was successfully deployed

2 active (1 outdated) deployments
staging — 8170ecaa Deployed Oct 16, 2026 by AlexAxthelm via Deploy frontend / Build and Deploy Job #1229
development — 159a8143 Deployed Oct 16, 2026 by AlexAxthelm via close-static-web-app-preview #349
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants