Skip to content

ci: prepare guarded mapped Worker deploy-on-merge - #1687

Merged
jaywedgeworth22 merged 4 commits into
mainfrom
instinct/deploy-on-merge-20261016
Oct 17, 2026
Merged

jaywedgeworth22 merged 4 commits into
mainfrom
instinct/deploy-on-merge-20261016

Conversation

@jaywedgeworth22

@jaywedgeworth22 jaywedgeworth22 commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

ci: prepare guarded mapped Worker deploy-on-merge

Summary

Adds a disabled-by-default CI path for deploying a mapped set of Cloudflare Workers from exact main revisions. The workflow serializes deployments, rechecks main before mutation, tags Worker versions with the exact SHA, verifies 100% production routing to that version, and runs functional health probes. It also adds unit tests for deployment receipt and target gating, plus documentation for safe activation.

Functional changes

  • Guarded workflow (.github/workflows/worker-deploy.yml):
    • Runs on pushes to main, a 30-minute schedule (11,41 * * * *), and manual dispatch.
    • Only executes when repository variable WORKER_DEPLOY_ENABLED is true.
    • Deploys matrix targets expenses-jays-services and usage-monitor-receipt-inbox one at a time with max-parallel: 1 and fail-fast: false.
    • Uses concurrency group mapped-workers-production without cancel-in-progress.
    • Runs receipt inbox and lifecycle auditor tests, deployment script unit tests, fetches CLOUDFLARE_FLEET_API_TOKEN through Infisical, and invokes the deploy script.
  • Deployment driver (scripts/deploy-mapped-worker.py):
    • Reads target definitions from scripts/worker-targets.json.
    • Rejects unknown targets and targets without an approved health probe.
    • Rechecks current main SHA before mutation and again before upload; skips when superseded.
    • Verifies the deployed version tag matches the exact SHA and that production routing is 100% to a single version.
    • Runs pre/post functional health probes; for usage-monitor-receipt-* targets, runs the receipt inbox lifecycle verification.
    • Deploys with --keep-vars, --strict, exact SHA tag, and a main <sha> message.
  • Tests (scripts/test-deploy-mapped-worker.py):
    • Covers partial rollout not being accepted as an exact receipt, exact tag receipt, blocking of unconfigured probes, and explicit exclusion of start-jays-services and fleet-share-api.
  • Docs (docs/worker-deploy-automation.md):
    • Documents default-off activation, required credentials, exact-version receipt/probe expectations, excluded or incomplete targets, no secret rotation, no public health bypass, and unchanged iOS workflow.

Safety and activation

  • Automation remains off until WORKER_DEPLOY_ENABLED=true.
  • Activation is intended only after credentials, exact-version receipts, and functional probes are reviewed.
  • Existing Worker schema, bindings, and migrations remain owned by each Worker’s reviewed configuration.
  • Ambiguous or incomplete targets are excluded from the matrix; usage-monitor-receipt-lifecycle-auditor is explicitly excluded pending an approved health probe.

Validation

  • npx --no-install vitest run workers/receipt-inbox/index.test.mjs workers/receipt-lifecycle-auditor/index.test.mjs --maxWorkers=1 --no-file-parallelism
  • python3 scripts/test-deploy-mapped-worker.py

Automated review findings

  • High: the public docs file names the Fleet-OPS/prod/root Infisical operational path, which should remain in private workspaces.
  • High: current_main() is the only stale-deploy safety check but has no direct tests, so a regression there could be silent.
  • Medium: target tests only assert that some targets are absent from TARGETS; they do not assert that the workflow matrix workers are present in TARGETS.
  • Medium: review reported a business logic gap against PR requirements; the provided finding does not identify the specific location.
  • Low: probe() reads target["name"] in its error path, but target dicts from worker-targets.json do not have a name field, creating a latent KeyError.

Summary

Prepares the guarded mapped Worker deploy-on-merge automation by hardening the deploy script's probe handling, expanding test coverage around the deployment safeguards, and updating the accompanying documentation. All changes are preparation/guardrail work; deployment remains default-off.

Changes

Deploy script (scripts/deploy-mapped-worker.py)

  • probe() now accepts an optional target name (default "unnamed target") and uses that parameter in its "Functional probe not configured" error instead of reading a name key from the target dict. This prevents a KeyError on targets that don't carry a name field.
  • All probe() call sites now pass the worker name explicitly: the already-deployed/short-circuit path, the pre-deploy health check, and the post-deploy verification.
  • Added a clarifying comment documenting the fail-closed behavior: a live Worker that fails the pre-deploy probe must be recovered by a manual deploy or rollback, not by this job.

Tests (scripts/test-deploy-mapped-worker.py)

  • Reworked the unconfigured-probe test to assert the new error messages for both the unnamed case ({}) and a named target with no health route, confirming the error path no longer raises KeyError.
  • Added test_matrix_workers_are_mapped_with_probes, which parses the worker matrix from .github/workflows/worker-deploy.yml and asserts every matrix worker exists in TARGETS, has an approved functional probe, and that usage-monitor-receipt-lifecycle-auditor is excluded.
  • Added tests that current_main() reads the git/ref/heads/main endpoint and returns the SHA, and that a malformed API response is rejected.
  • Added a test asserting that a superseded main SHA skips before any mutation: deployed_tag, probe, and subprocess.run are never called.

Documentation (docs/worker-deploy-automation.md)

  • Documented that the pre-deploy probe fails closed — an unhealthy live Worker or unusable probe credentials stop the job before any upload, and fix-forward is a manual deploy/rollback.
  • Replaced the concrete credential location (Fleet-OPS/prod/root) with a reference to Infisical plus a private operations inventory maintained outside the public repository, keeping the CI bootstrap secret names unchanged.
  • Minor formatting/spacing cleanup; no change to the documented default-off behavior or excluded targets.

Notes

  • The code review raised one low-severity finding confirming the previous operational-path disclosure in docs/worker-deploy-automation.md was removed and replaced with Infisical/private-inventory references, resolving the earlier rule violation.
  • No secrets are rotated and activation remains off until cutover.

Comment thread scripts/deploy-mapped-worker.py Outdated
@kody-ai

This comment has been minimized.

@kody-ai

kody-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

kody code-review Business Logic medium

Business Rules Validation

Task: 5773430482 — Provision Canonical iOS Records to Unblock Widget Fix Delivery
Task Link: https://github.com/Simple-With-Us/Usage-Monitor/issues/1634

Status: Issues Found
Confidence: high

Findings

MUST_FIX: PR scope does not match the task scope (scope mismatch)

Requirement: "Provision Canonical iOS Records to Unblock Widget Fix Delivery" with active bundle IDs "Usage Monitor app: com.simplewithus.usage.client.ios", "Widget extension: com.simplewithus.usage.client.ios.widget", and "Local Monitor app: com.simplewithus.usage.local.ios".
Missing in code: No evidence in this PR diff of any iOS bundle identifier provisioning. The diff is entirely about a Cloudflare Workers deployment workflow (.github/workflows/worker-deploy.yml, scripts/deploy-mapped-worker.py, scripts/worker-targets.json, docs/worker-deploy-automation.md) and the PR description itself states "No iOS workflow is changed" and "No app/iOS workflows enabled."
Evidence (Code): No file in the diff references any of the required bundle IDs, the App Group group.com.simplewithus.usage, scripts/ios-fleet/apps.json, or Apple Developer Portal / App Store Connect records.
Suggested action: Open a PR that actually addresses the task scope: register the canonical iOS bundle IDs in the Apple Developer Portal, create the new App Store Connect records for the Client and Local apps, update scripts/ios-fleet/apps.json with the new Apple IDs (without the legacy IDs 6799230435 / 6799230729), and align the hosted ship script gating with the rollout document at docs/rollouts/2026-10-09-ios-bundle-identifiers.md. If this Workers PR is unrelated, it should be linked to its own task.

MUST_FIX: No evidence of registering the canonical Usage Monitor app bundle ID in this PR diff

Requirement: "Usage Monitor app: com.simplewithus.usage.client.ios" (AC #1)
Missing in code: No evidence in this PR diff of creating or referencing the Developer Portal App ID com.simplewithus.usage.client.ios, nor the corresponding App Store Connect record.
Evidence (Code): The diff does not touch any iOS provisioning or Apple Developer configuration files.
Suggested action: Add the provisioning/registration steps and required configuration entries required by the rollout document for com.simplewithus.usage.client.ios, including Push Notifications capability.

MUST_FIX: No evidence of registering the Widget extension App ID in this PR diff

Requirement: "Widget extension: com.simplewithus.usage.client.ios.widget" (AC #2) and "the widget is an extension inside the Client app, so it needs its own explicit Developer Portal App ID with App Groups enabled"
Missing in code: No evidence in this PR diff of creating an explicit Developer Portal App ID for com.simplewithus.usage.client.ios.widget or enabling App Groups on it.
Evidence (Code): The diff does not show changes in the iOS Developer Portal App ID area required by the task.
Suggested action: Add the explicit widget App ID registration with App Groups enabled per the rollout document.

MUST_FIX: No evidence of registering the Local Monitor app bundle ID in this PR diff

Requirement: "Local Monitor app: com.simplewithus.usage.local.ios" (AC #3)
Missing in code: No evidence in this PR diff of creating or referencing the Developer Portal App ID com.simplewithus.usage.local.ios or its App Store Connect record.
Evidence (Code): The diff does not touch any iOS provisioning or Apple Developer configuration files.
Suggested action: Add the Local Monitor App ID registration and pending App Store Connect record consistent with the rollout document.

MUST_FIX: No evidence of updating scripts/ios-fleet/apps.json to mark ASC records pending with new IDs in this PR diff

Requirement: "scripts/ios-fleet/apps.json intentionally keeps both ASC records pending, and the hosted ship script refuses to upload until the new host-app records are registered and their Apple IDs are configured. Do not use the legacy records 6799230435 / 6799230729; they belong to retired bundle IDs."
Missing in code: No evidence in this PR diff of changes to scripts/ios-fleet/apps.json or any hosted ship script gating on new Apple IDs.
Evidence (Code): scripts/ios-fleet/apps.json is not present in the diff, nor is any ship/upload script for iOS.
Suggested action: Update scripts/ios-fleet/apps.json so both ASC records are pending and reference the new canonical Apple IDs, and ensure the hosted ship script refuses uploads until those IDs are configured. Explicitly avoid the legacy IDs 6799230435 / 6799230729.

Requirements Verified

None of the task's iOS provisioning requirements are satisfied in this PR diff. The PR is a Cloudflare Workers deploy automation change that explicitly states no iOS workflows are changed.


Analysis performed by Kodus AI Business Rules Validator


💡 This validation runs automatically only on the first review of a pull request. To run it again, comment @kody -v business-logic.

Comment thread docs/worker-deploy-automation.md Outdated
Comment thread scripts/deploy-mapped-worker.py
Comment thread scripts/deploy-mapped-worker.py Outdated
Comment thread scripts/test-deploy-mapped-worker.py Outdated
jaywedgeworth22 and others added 2 commits October 17, 2026 02:31
probe() named a missing "name" key in its unconfigured-probe error, so the
guard raised KeyError instead of the intended RuntimeError.  It now takes the
target name from main(), and the test calls it without a name key so the old
code fails.

Add tests for current_main() (main ref URL, SHA extraction, malformed
response) and for the superseded-main skip, which must stop before any probe,
receipt read, or upload.  Add a drift check that every workflow matrix Worker
is mapped in worker-targets.json with an approved probe and the auditor stays
out of the matrix.

Docs: drop the private Infisical path from this public page and point to the
private operations inventory.  State that the pre-deploy probe fails closed
and that fix-forward for an already-broken Worker is a manual deploy.

Refs #1687

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kody-ai

kody-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

​

@jaywedgeworth22
jaywedgeworth22 enabled auto-merge (squash) October 17, 2026 07:33
@jaywedgeworth22
jaywedgeworth22 merged commit 1c3c653 into main Oct 17, 2026
11 checks passed
@jaywedgeworth22
jaywedgeworth22 deleted the instinct/deploy-on-merge-20261016 branch October 17, 2026 07:37
Comment thread docs/worker-deploy-automation.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants