Repository navigation
feat(db): vendor the pg-boss schema into a committed migration - #104
Conversation
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 32 minutes. View limit details
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Code Review
This pull request vendors the pg-boss schema (crove_jobs) into committed migrations, removing the need to run pg-boss with runtime migrations enabled. It introduces a new script pnpm db:vendor:pgboss to generate these migrations, adapts pg-boss plans to pin search_path and drop transaction wrappers, and adds database tests to verify the schema installation and upgrades. The feedback suggests a more robust way to resolve the pg-boss package.json file path directly rather than traversing up from its entry point.
b288e73 to
1c78d1e
Compare
…sion Review feedback on #104: pg-boss has no exports map, so resolving its package.json does not depend on the dist/ layout of its entry point. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013LrvuThKGaPX1uDwUiwmGQ
e077359 to
f4a0ba7
Compare
f4a0ba7 to
3f95eea
Compare
3f95eea to
f509227
Compare
Security review (session)The Verdict: approve with nits. Nothing was blocking. The two hardening items are fixed here, because the migration has not been applied anywhere yet and could be regenerated in place. Fixed in
Follow-up
Checked and fine
Re-validated locally on
Generated by Claude Code |
8822a98 to
29a4c81
Compare
29a4c81 to
e6e36b8
Compare
e6e36b8 to
84ac81c
Compare
|
Rebased onto Migration renamed again. It is now Ported fix for Two adaptations to code that landed on
Local results (postgres:17):
Generated by Claude Code |
84ac81c to
116e5b9
Compare
116e5b9 to
f298639
Compare
f298639 to
a112442
Compare
a112442 to
1757f57
Compare
1757f57 to
4c5e87e
Compare
4c5e87e to
7ff2d7e
Compare
7ff2d7e to
a3df837
Compare
a3df837 to
ce8de18
Compare
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
|
Taking over this PR from its original cloud session (idle since 2026-10-16 17:49 UTC). This session will rebase onto Generated by Claude Code |
|
Original (cloud) session here. Understood: this PR is yours, and I won't push to State as I left it:
Generated by Claude Code |
External-tenant gate T6: committed SQL is the only schema, also for crove_jobs. - pnpm db:vendor:pgboss (apps/kernel/src/vendor-pgboss.ts) renders pg-boss's own construction plans (or, after an upgrade, its migration plans from the vendored version) into supabase/migrations. The SQL loses its BEGIN/COMMIT and advisory lock (the runner applies each file in one transaction under its own lock), every function pins search_path, and a version-guarded DO block leaves an existing install at the same version alone and stops on any other version. - The generated 20261016201000_crove_jobs_pgboss_v46.sql also creates the three queues, grants the schema only to crove_worker (no PUBLIC EXECUTE) and adds crove_kernel.jobs_schema_version() for the API role. - Nothing runs pg-boss with migrate: true. The worker keeps migrate: false, which refuses another schema version. migrateJobs stays as a no-op only because main's invariant suite (run from base by protected.yml) still calls it; it goes with those calls in a follow-up. - /readyz answers 503 jobs_schema until the database version equals the one the pinned pg-boss expects (read from pg-boss/package.json). - Tests: a unit test fails CI when pg-boss changes its schema version without a vendored migration; database tests cover a fresh install (version, queues, pinned functions, privileges, a job round trip as crove_worker with migrate: false), an install pg-boss created itself, and a wrong version. Closes #25 Hardening from the session security review: - A database where pg-boss created crove_jobs at runtime kept its six functions without a pinned search_path, because the version guard leaves the schema in place. The migration now pins every crove_jobs function whose setting differs (idempotent; the migration role created them). - crove_worker could write crove_jobs.version, which decides whether a vendored upgrade runs: setting it ahead would skip an upgrade while /readyz reports ready. The worker now has UPDATE only on the maintenance columns pg-boss stamps with migrate: false, and the guards require exactly one version row. - Upgrades refuse a queue.table_name pg-boss would not create, since its upgrade plans put that column into SQL and the worker may write it. With the prober (#148) and the widened guard (#167) on main: - The job schema exists right after migrate, so the prober's db test now expects it, and hides the schema to cover the missing-schema finding. - The guard's crove_jobs CREATE check skips roles that act as the runner, like its TEMPORARY check: such a role already has all the runner has. Before #25 the check never saw crove_jobs at migrate time. Claude-Session: https://claude.ai/code/session_013LrvuThKGaPX1uDwUiwmGQ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ce8de18 to
77d4d29
Compare
|
Rebased onto
Generated by Claude Code |
- social.publish.record writes only a call that has no outcome yet, so a reconcile that finds a post whose pending submission already succeeded records it published instead of failing on the ledger guard forever. - The token-refused path reads the connection FOR UPDATE before mark_expired updates it, so two jobs of one channel cannot deadlock on an upgraded share lock. - The publish queues are created by the S4 migration, now that the pg-boss schema and its queues are committed SQL (#104). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(social): publish each post exactly once (S4) The publish pipeline of Social plan §3.4 (#234), on the sandbox channel: - crove_kernel.external_call: the ledger of visible calls. A call is written as started and committed before it is made; tenant roles only insert it and update its outcome, and a guard trigger refuses any change once it has one. - social.publish.begin and social.publish.record around the one provider call; a call already started under the variant's key is made again only when the adapter declares the step safe or idempotent, otherwise it is reconciled or handed to a person. Never a blind retry. - A worker sweep every 15 seconds (crove_social.publish_due, worker only) queues due, stale, pending and reconnected variants on stately social-publish-<provider> queues. - Rate limits and transient refusals start a new attempt at the retry time; an expired token pauses the variant and marks the channel expired; reconnecting resumes it. - social.variant.retry and social.variant.resolve for failed and needs_attention variants, with the post page showing each outcome. - Publisher interface and the in-memory sandbox publisher in @crove/channel; shared variant helpers move to variants.ts. Tests: database tests for each outcome, including a worker that dies between the call and its result (reconciled, or needs_attention, never posted twice); the e2e spec now sees the worker publish the post. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(social): close the review's publish gaps - An ambiguous variant waits a minute before its reconcile in begin too, not only in the sweep, so a duplicate job cannot reconcile too early and send a person to publish again. - publish_due filters active orgs and the worker's providers before each kind's limit and gives each kind its own share, so rows nobody works on never crowd out the rest. - A paused variant stamps its connection's version (read under a share lock, stored in SQL) and resumes when the connection is active and has changed; no clocks from two processes are compared. - A token refused after a reconnect starts a new attempt instead of pausing, and mark_expired leaves a changed connection alone. - begin leaves a variant in a queue paused after the sweep alone; a run that stalled after begin records unknown without calling; a post processing for a day is reconciled; a disconnected channel says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(social): leave a finished call alone, lock the channel once - social.publish.record writes only a call that has no outcome yet, so a reconcile that finds a post whose pending submission already succeeded records it published instead of failing on the ledger guard forever. - The token-refused path reads the connection FOR UPDATE before mark_expired updates it, so two jobs of one channel cannot deadlock on an upgraded share lock. - The publish queues are created by the S4 migration, now that the pg-boss schema and its queues are committed SQL (#104). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #25
External-tenant gate T6: committed SQL is the only schema,
crove_jobsincluded. Until now themigraterole started pg-boss withmigrate: trueand let it create its schema at runtime.What changes
pnpm db:vendor:pgboss(apps/kernel/src/vendor-pgboss.ts, with the rendering injobs-schema.ts). When the pinned pg-boss expects a schema version that no migration vendors yet, it writessupabase/migrations/<now>_crove_jobs_pgboss_v<N>.sql. The SQL comes from pg-boss's owngetConstructionPlansthe first time, or fromgetMigrationPlansstarting at the vendored version for upgrades. The renderer changes pg-boss's SQL in these ways, and checks each change:BEGIN/COMMIT/advisory lock: the runner applies each file in one transaction under its own lock.SET search_path = pg_catalog, pg_temp(the AGENTS.md rule).DOblock:crove_jobsfunction whosesearch_pathdiffers gets the pin, so pre-Vendor the pg-boss schema into committed migrations #25 installs end up like fresh ones.queue.table_namethat pg-boss would not create, because pg-boss's upgrade plans put that column into SQL.20261019034500_crove_jobs_pgboss_v46.sql, generated from pg-boss 12.38.0, schema 46. It is renamed on each rebase so it sorts after every file onmain(the Docs check's migration-order step enforces this); it now follows feat(social): posts, per-channel variants, review decisions and queues (S3) #297's20261019000000. It also:QUEUESinjobs-schema.ts), each with the policycreateQueuegave it. That includes feat(kernel): retention purges and org offboarding with export #211'skernel-org-exportandkernel-retention-purge, and feat(kernel): positions, agents, tasks and wake-ups (ADR-0029 Phase 1, T18) #245'skernel-agent-dispatch,kernel-agent-sweepandkernel-agent-wake; the last one isstately, the rest arestandard;EXECUTEfromPUBLIC;crove_workeronly; table writes cover feat(kernel): retention purges and org offboarding with export #211's retention schedule. Oncrove_jobs.versionthe worker may update only the maintenance columns pg-boss stamps withmigrate: false. The version decides whether an upgrade runs, so only migrations write it;crove_kernel.jobs_schema_version()(definer,crove_apponly).migrate: trueanywhere. Nothing starts pg-boss withmigrate: true. The worker keepsmigrate: false, createSchema: false, so pg-boss refuses to start on any other schema version.migrateJobsstays as an exported no-op only becausemain's invariant suite (sessions.db.test.ts) and a few ordinary tests still call it. Removing it is Remove the migrateJobs no-op once #104 is on main #130./readyzanswers 503jobs_schemauntil the database version equals the version the installed pg-boss expects (read from itspackage.json,pgboss.schema).JOB_SCHEMA,QUEUESand the queue policies (feat(kernel): positions, agents, tasks and wake-ups (ADR-0029 Phase 1, T18) #245'sQUEUE_OPTIONS, asqueueOptions()) move tojobs-schema.ts. A new queue or policy needs a new migration; the database test fails until it has one.packages/db/src/migrate.ts: the comment on feat(db): guard pinned search_path on crove_* functions and revoke TEMP from Crove roles #97'scrove_jobsexemption is updated. The check that no other role mayCREATEincrove_jobsnow skips roles that act as the runner (members of it, like the invariant suite's_proxy), as the TEMPORARY check already does. Dropping the exemption is proposed on Widen the definer hardening guard (follow-ups from #97) #100.migraterole and deploy steps, the state paragraph, the Vietnamese page, and the new command in AGENTS.md.Tests
jobs-schema.test.ts):table_nameguards.jobs.db.test.ts, PostgreSQL 17):PUBLICorcrove_appEXECUTEand noCREATEfor the worker, andcrove_appreads only the version;crove_workerwithmigrate: falsestarts and round-trips a job;kernel.db.test.ts,inbound-rotation.db.test.ts,prober.db.test.ts, feat(kernel): per-deployment module enablement #198'smodule-enablement.db.test.tsand the newblob-sweep.db.test.tsrun on the vendored schema (QUEUESnow imported fromjobs-schema.ts). feat(kernel): retention purges and org offboarding with export #211's retention and offboarding tests and feat(kernel): positions, agents, tasks and wake-ups (ADR-0029 Phase 1, T18) #245's agent tests start the worker on it too.mainat docs: pick work by the 2026-10-17 backlog milestones #334 (539974d):pnpm lint,pnpm typecheck,pnpm docs:checkandtools/ci/migration-order.mjspass;crove_jobs.queuethat the migration creates.Notes
pnpm db:vendor:pgboss, then review and commit the new migration. pg-boss's exported migration plans build indexes inline, so a largecrove_jobsupgrade belongs in the promote window (plan §4).http.ts,migrate.tsand AGENTS.md. The invariant job runsmain's suite against this code, which is why themigrateJobsno-op exists.🤖 Generated with Claude Code
https://claude.ai/code/session_013LrvuThKGaPX1uDwUiwmGQ