Repository navigation
fix: classify cutover-set activation failures like single-generation activation - #1749
Merged
Merged
Conversation
Set activation repeated three defects the single-generation activation already fixed (#1617, #1618, #1648). Scratch: activateCutoverSet created its scratch directory before any classification, so every early refusal touched the disk and an uninitialized home threw ENOENT. The directory is now allocated per member census through deps.allocateScratch, after the S7 identity check, and removed in a finally. The set prefix is kept by overriding the default allocator. An allocation failure marks the member unverifiable (state-unresolvable) so the S8 gate names it. An errno from the machine identity read is refused as state-unresolvable at S0. Target failures: identityCheck rethrew a StorageOperationError from the S0, S5 and S7 identity queries, and targetFailure missed the PortableStreamError(source-unavailable) wrapper of the census reader. Both now classify as target-unhealthy or target-unresolvable on the member and the gate refuses (or interrupts after a checkpoint). Every call site records the failure and continues, so a later member's checkpoint conflict still surfaces. Cancellation and other errors still reject. Applied: classifyApplied derived yes and no from the journal phase alone. It now mirrors the single-generation rules, comparing the live config and project map digests with the published or expected witnesses, or with the artifact's source witness when no journal of this set exists; in-flight phases and any readback failure are unknown. digestsMatch, recoveryFileDigests and APPLIED_IN_FLIGHT_PHASES are exported from activate-generation.ts (visibility only). Existing assertions that expected a phase-only no are updated to unknown where no source witness exists. Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Review of 8ec42d4 asked for the uninitialized-home test to pin the classification it relies on. It now runs the real default dependencies with a pass-through spy on allocateScratch and asserts a refusal at S0 with machine-identity-unregistered, effectBegun false, no allocator call and no scratch directory. The set activation doc said an early refusal leaves nothing on disk, but the append barrier still creates the empty LCM home. It now says only that an early refusal allocates no census scratch directory. Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
bcdonadio
enabled auto-merge
October 25, 2026 04:10
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Fixes #1673. The cutover-set activator (
src/migration/cutover-set-activate.ts) copied three pre-fix shapes from single-generation activation that #1618, #1648 and #1617 have since corrected there:.lcmthemkdtempthrewENOENTinstead of refusing.PortableStreamError("source-unavailable"), rejected the whole activation instead of being classified.appliedcame from the journal phase alone, without reading back the live config and project map.How
allocateScratchseam, keeping thecutover-set-activation-scratch-prefix) only after its identity check passes, and removes it when the read ends. An allocation failure marks that memberunverifiable/state-unresolvable, so the S8 gate names it. A filesystem error reading the machine identity refuses at S0 withstate-unresolvable; an unregistered identity keepsmachine-identity-unregistered.target-unhealthy/target-unresolvable), unwrapping onlyPortableStreamError("source-unavailable"). Each member is recorded and the loop continues, so the set gate (or, after a checkpoint, the roll-forward interruption) reports it with every other member's evidence. Cancellations and unknown errors still reject.applied: the same evidence-derived rule as single-generation activation.yesneeds the set's completed publication and live selection matching the published witnesses;noneeds the live selection to still match the pre-publication source or the journal's expected witnesses; anything else, including a readback failure, isunknown. The digest helpers are exported fromactivate-generation.ts(visibility only) so both activators share one digest convention.Testing
test/migration/cutover-set-activate-classification.test.ts: scratch laziness (including a fresh empty home refused at S0 with the real defaults and no allocation), identity and census failures at S0/S5/S7 before and after a checkpoint, a target failure that must not hide a later member's evidence conflict, and the fullappliedwitness matrix. 14 of the original 15 cases fail at the base commit; the remaining one guards errors that must keep rejecting.applied: "no"assertions incutover-set-activate-faults.test.tsbecome"unknown": in both, no source witness exists yet.activate-generation,cutover-set-rollback-replay,codecov-config): 343 passed;cutover-set-activate.tsandactivate-generation.tsat 100% statements, branches, functions and lines.pnpm run typecheck(all configs) and eslint pass.Reviewer guide
Start in
src/migration/cutover-set-activate.ts:memberCensus(scratch),identityCheck/targetFailureand their three call sites, thenclassifyApplied/classifyAgainstSource.activate-generation.tsonly gains threeexportkeywords. Docs: one paragraph indocs/migration-cutover-set.mdlinking to the single-generation rules. Metadata: patch changeset andtest/codecov-ownership/1673-cutover-set-activation-classification.yml.