Skip to content

fix: prove runtime grants for cutover sets - #1760

Merged
bcdonadio merged 3 commits into
mainfrom
fix/1707-s23
Oct 25, 2026
Merged

bcdonadio merged 3 commits into
mainfrom
fix/1707-s23

Conversation

@bcdonadio

Copy link
Copy Markdown
Contributor

Why

After #1607, single-generation lcm migration activate proves the daemon runtime role's grants. lcm migration activate --set still ran every step under the transfer role and checked health through the transfer verifier, so a successful set activation did not show that the daemon could start. The set runbook also kept the old manual grant swap after activation.

How

This follows the #1607 design (PR #1713). Admission is caller-scoped, so the daemon and every other caller are unchanged.

  • Set activator (cutover-set-activate.ts): a required ordinarySettings input gives the runtime role its own connection. Transfer sessions (S0, S7) keep the settings derived from the prepared target.
    • Fresh and pre-selection: open the runtime connection, bind every member to its sealed destination (the existing ordinary S5 check, moved earlier), discover both live roles, then run S0 and the lease steps. The roles must be distinct by OID and name, unswitched (current_user = session_user) and on TLS. Role discovery failures refuse at S6 before any lease write and become a roll-forward interruption once an effect has begun.
    • Post-selection recovery binds pending members and discovers roles before the first fence read. Settled replay opens no session.
    • S6/S15 run runtime readiness with the transfer role as the admitted peer. S7 runs transfer readiness with the runtime role as the peer.
  • Shared discovery (activate-generation.ts): role discovery is extracted into one context-free helper that both activators use. Single-generation behavior is unchanged.
  • CLI (cli-cutover-set.ts): activate --set, and resume --set when it routes to activation, resolve LCM_POSTGRES_RUNTIME_URL only when activation actually runs (never on dry run). The URL is never printed. A missing or invalid URL refuses with activation-runtime-target-missing. Prepare, verify, rollback, abort and settled resume don't need it.
  • Result contract: set success now reports next: revoke-transfer-grants-then-start-daemon and transferGrantRevocation: required-before-daemon-start (replacing grantSwap). Exit 8 keeps set-restart-required, now with the revoke-only remedy.
  • Docs and help: the set runbook applies runtime grants after verify and before activate --set; after exit 0 the one manual step is revoking the transfer grants. There are notes for sets prepared or interrupted on an older build, and for no-peer callers (including the set rollback target check), which refuse until the transfer grants are revoked. lcm help and docs/migration-operations.md are swept too.
  • Rehearsal: set rows grant the runtime role before activation and resume, and revoke the transfer grants afterwards. docs/migration-rehearsal-gate.* is regenerated separately in Regenerate the cutover rehearsal gate after #1607 #1726.
  • Minor changeset; codecov ownership fragment.

Testing

  • Unit: runtime and transfer settings per session; S6/S15/S7 verifier closures with the reciprocal peer; identical, switched, insecure and unavailable roles refused before any lease call; ordinary drift on a second member only (S5 cutover-set-member-evidence-drifted, no guard calls); post-selection binding before fence reads; CLI URL handling (dry run, refusal without a service call, never rendered).
  • PostgreSQL 18 (rootless Podman): set activation and set rollback with two real login roles. The live runtime role is observed at every S6/S15 and the transfer role at every S7. A third grantee is refused at S6 with no unreleased lease. No-peer daemon readiness refuses before the transfer grants are revoked and passes after.
  • Cutover rehearsal on PostgreSQL 18: set rows S1, S3, S4 and S4b in one filtered run at the final head.
  • Final head: 26 files, 1,288 tests, with 100% statements, branches, functions and lines on all six changed production files. Typecheck and eslint are clean.

Reviewer guide

  1. preSelection, resolveMemberFences, observeHealth and memberCensus in src/migration/cutover-set-activate.ts.
  2. discoverMigrationActivationRoles in src/migration/activate-generation.ts.
  3. runActivation in src/migration/cli-cutover-set.ts, then the runbook in docs/migration-cutover-set.md.

Closes #1707

Cutover-set activation previously checked transfer-profile grants through
the ordinary session, so success did not prove daemon startup readiness.

Resolve a distinct runtime URL, bind and catalog-check both roles before
lease effects, admit only reciprocal peers, and align the CLI, docs, and
rehearsal handoff with the revoke-only post-activation step.

Migrate the PG18 set activation and rollback fixtures to distinct real
login roles.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Round-one review found that the real PostgreSQL set test did not observe
the active roles at S6, S7, and S15 or prove ordinary readiness after
the transfer role was revoked.

Wrap the production verifiers, prove the no-peer handoff, add the
second-member pre-lease drift case, and align the remaining operator and
rehearsal wording with the revoke-only post-activation step.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Bring the reviewed cutover-set runtime-role change onto the current main
head while preserving the upstream S21 and S23 fixes.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
@bcdonadio bcdonadio self-assigned this Oct 25, 2026
@bcdonadio
bcdonadio enabled auto-merge October 25, 2026 08:13
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T08:14:29.810677Z 261b661 PR opened
🔒 Security Review ✅ Completed 2026-10-25T08:16:10.543170Z 261b661 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@bcdonadio
bcdonadio merged commit 2ba9fb0 into main Oct 25, 2026
23 checks passed
@bcdonadio
bcdonadio deleted the fix/1707-s23 branch October 25, 2026 08:17
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.

Cutover-set activation should prove the runtime role's grants like #1607

1 participant