Skip to content

Finish scheduled maintenance safety checks#1880

Merged
stefan-burke merged 1 commit into
mainfrom
work/scheduled-maintenance-review-fixes
Jul 21, 2026
Merged

Finish scheduled maintenance safety checks#1880
stefan-burke merged 1 commit into
mainfrom
work/scheduled-maintenance-review-fixes

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 21, 2026

Copy link
Copy Markdown
Member

What changed

  • declare every maintenance enablement check's settings and call costs, then verify the complete startup cost before any work starts
  • validate Deno app and revision responses with shared schemas, use the managed production domain, and wait for deployments to finish
  • read legacy unversioned built-site data as version 1
  • count child-site database reads through an execute-only reader

Why

These fixes address the five final review findings on #1862, which merged while the fixes were being prepared. The contracts make future maintenance tasks, Deno status changes, stored data, and child database reads fail clearly instead of drifting silently.

Configuration

Deno site builders now require DENO_DEPLOY_ORG_SLUG as well as the existing organization ID and token. This is used for the managed <app>.<organization>.deno.net domain.

Verification

  • nix develop -c deno task precommit
  • targeted mutation tests: 100% for maintenance definition/runner/registry, Deno API/schema, built-site blob parsing, site DB access, and config

Summary by CodeRabbit

  • New Features

    • Added support for Deno Deploy organization slugs, including organization-based production hostnames.
    • Deployments now wait for revision completion and report failures, timeouts, and invalid statuses.
    • Added validation for Deno Deploy API responses and environment-variable listings.
    • Improved maintenance task budgeting and database request accounting.
  • Bug Fixes

    • Preserved compatibility with legacy site-data blobs lacking version information.
  • Documentation

    • Documented new optional Deno Deploy environment variables.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates Deno Deploy configuration, schema validation, environment-variable retrieval, revision polling, and hostname generation. It also restructures maintenance startup checks around allowance budgets, instruments child-site database reads, and supports unversioned legacy site-data blobs.

Changes

Deno Deploy integration

Layer / File(s) Summary
Deno Deploy contracts and configuration
src/shared/config.ts, src/shared/deno-deploy-schema.ts, AGENTS.md, test/shared/config/env.test.ts, test/shared/deno-deploy-schema.test.ts, test/features/admin/builder/server.test.ts, test/shared/builder.test.ts
Deno Deploy now requires an organization slug, exposes a slug getter, documents the environment variables, and validates identity, environment-variable, and revision response shapes.
Deno API deployment flow
src/shared/deno-deploy-api.ts, test/shared/deno-deploy-api.test.ts, scripts/mutation/equivalent-mutants.txt
The client uses typed API parsing, retrieves environment-variable names, polls revisions through terminal states, reports deployment outcomes, and generates organization-scoped .deno.net hostnames.

Maintenance startup budgeting

Layer / File(s) Summary
Maintenance check contract and registry
src/shared/maintenance/definition.ts, src/shared/maintenance/registry.ts, test/shared/maintenance/definition.test.ts, test/shared/maintenance/registry.test.ts, test/shared/maintenance/fixtures.ts
Enablement, settings keys, and check call limits are nested under check; startup call totals and aggregate budget validation are added.
Allowance-aware maintenance execution
src/shared/maintenance/runner.ts, test/shared/maintenance/runner.test.ts, scripts/mutation/equivalent-mutants.txt
Maintenance candidates are filtered by wake policy and skipped before check evaluation when database, external, or total allowances cannot cover startup costs.

Site data compatibility

Layer / File(s) Summary
Legacy site-data parsing
src/shared/db/built-sites/blob.ts, test/shared/db/built-sites/blob.test.ts
Blob validation now accepts unversioned legacy data as version 1 through a union schema.

Child site database accounting

Layer / File(s) Summary
Instrumented site database reader
src/shared/site-db.ts, test/shared/site-db.test.ts
withSiteDb passes a reader wrapper that counts database round trips and enforces shared subrequest allowances.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant deployCode
  participant DenoDeployAPI
  participant waitForRevision
  deployCode->>DenoDeployAPI: submit deployment
  DenoDeployAPI-->>deployCode: revision id and status
  deployCode->>waitForRevision: poll revision
  waitForRevision->>DenoDeployAPI: fetch revision status
  DenoDeployAPI-->>waitForRevision: pending or terminal status
  waitForRevision-->>deployCode: success or deployment error
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main maintenance-safety work, even though the PR also includes related Deno and database fixes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch work/scheduled-maintenance-review-fixes

Comment @coderabbitai help to get the list of available commands.

@stefan-burke
stefan-burke enabled auto-merge July 21, 2026 20:11
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 21, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/shared/config/env.test.ts`:
- Around line 231-236: Restore the direct getDenoDeployOrgId regression
assertion in the required environment getter tests, rather than replacing it
with only getDenoDeployOrgSlug coverage. Keep both organization-ID and
organization-slug cases, using their respective environment keys and expected
values.

In `@test/shared/site-db.test.ts`:
- Around line 124-136: Update the test around readSiteSetting to capture its
returned value and assert the expected successful setting value before
validating getSubrequestUsage(). Keep the existing budget-counter assertions,
ensuring the test fails if the database read increments usage but execute does
not succeed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f7583c58-c9c5-4eb3-8bf3-d6620ca0225a

📥 Commits

Reviewing files that changed from the base of the PR and between 22987a2 and 43942f7.

📒 Files selected for processing (21)
  • AGENTS.md
  • scripts/mutation/equivalent-mutants.txt
  • src/shared/config.ts
  • src/shared/db/built-sites/blob.ts
  • src/shared/deno-deploy-api.ts
  • src/shared/deno-deploy-schema.ts
  • src/shared/maintenance/definition.ts
  • src/shared/maintenance/registry.ts
  • src/shared/maintenance/runner.ts
  • src/shared/site-db.ts
  • test/features/admin/builder/server.test.ts
  • test/shared/builder.test.ts
  • test/shared/config/env.test.ts
  • test/shared/db/built-sites/blob.test.ts
  • test/shared/deno-deploy-api.test.ts
  • test/shared/deno-deploy-schema.test.ts
  • test/shared/maintenance/definition.test.ts
  • test/shared/maintenance/fixtures.ts
  • test/shared/maintenance/registry.test.ts
  • test/shared/maintenance/runner.test.ts
  • test/shared/site-db.test.ts

Comment on lines +231 to +236
expectRequiredEnvGetter(
"getDenoDeployOrgSlug",
getDenoDeployOrgSlug,
"DENO_DEPLOY_ORG_SLUG",
"deploy-org",
);

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep the organization-ID getter regression case.

This replaces the direct getDenoDeployOrgId() contract test rather than adding slug coverage beside it. Restore the organization-ID assertion so both required configuration inputs are covered.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/shared/config/env.test.ts` around lines 231 - 236, Restore the direct
getDenoDeployOrgId regression assertion in the required environment getter
tests, rather than replacing it with only getDenoDeployOrgSlug coverage. Keep
both organization-ID and organization-slug cases, using their respective
environment keys and expected values.

Source: Coding guidelines

Comment on lines +124 to +136
test("counts a child database read against the shared request budget", async () => {
await runWithSubrequestBudget(async () => {
await readSiteSetting(
{ dbToken: "t", dbUrl: "libsql://u" },
"current_script_version",
);
expect(getSubrequestUsage()).toEqual({
database: 1,
external: 0,
total: 1,
});
});
});

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Assert that the read actually succeeded.

This test ignores readSiteSetting’s result, so it can pass when execute fails after usage is incremented. Capture the result and assert the expected successful value before checking the budget counters.

As per coding guidelines, tests must test observable behavior and use strong mutation-resistant assertions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/shared/site-db.test.ts` around lines 124 - 136, Update the test around
readSiteSetting to capture its returned value and assert the expected successful
setting value before validating getSubrequestUsage(). Keep the existing
budget-counter assertions, ensuring the test fails if the database read
increments usage but execute does not succeed.

Source: Coding guidelines

Merged via the queue into main with commit 22490f6 Jul 21, 2026
5 checks passed
@stefan-burke
stefan-burke deleted the work/scheduled-maintenance-review-fixes branch July 21, 2026 20:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43942f7c0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return okResult(undefined);
};

const REVISION_POLL_BACKOFF_MS = Array<number>(20).fill(1_000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid failing accepted Deno deploys after 20 seconds

When Deno accepts a revision but leaves it queued or building for more than 20 seconds, this hard timeout makes publishSite return { ok: false } even though the revision can still finish and route afterwards. In the builder flow the site has already been retained before publishSite runs, so operators can see a failed build with a recorded site that may later go live; either avoid treating an accepted pending revision as a synchronous failure or move the wait to a background status path.

Useful? React with 👍 / 👎.

Comment on lines +23 to +26
failure_reason: v.optional(
v.nullable(v.picklist(["error", "cancelled", "timed_out", "skipped"])),
null,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require revision failure_reason instead of defaulting it

For Deno revision responses, failure_reason is a documented field that should be present as null on non-failures, but this schema accepts it missing and invents null. If the API response loses that field, deploy failure handling continues with a fabricated value instead of failing at the boundary, which is exactly the structured external-data case this repo requires us to parse rather than default.

Useful? React with 👍 / 👎.

Comment on lines +49 to +52
const database =
1 +
settingsRead +
tasks.reduce((sum, task) => sum + task.check.maxDatabaseCalls, 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Count the settings version probe in startup cost

For a maintenance task whose activation check has no settings keys, this counts only one database startup call, but runWithinAllowance still calls settings.loadKeys([]), which probes settings_version, before syncMaintenanceTaskRows does its own write. Outside an already-prepared request where that version probe is not cached, combinedAllowance: 1 passes this preflight and then spends two database calls before any task runs, throwing instead of skipping the scheduler bookkeeping the new safety check is meant to avoid.

Useful? React with 👍 / 👎.

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.

1 participant