Repository navigation
Avoid restore snapshot mutation churn and synchronous index loading #12810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
austinywang
wants to merge
44
commits into
main
Choose a base branch
from
issue-12793-restore-resume-lifecycle
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
6654e4e
test: cover read-only restored lifecycle projection
austinywang 37ccc69
fix: keep restore snapshot reconciliation read-only and offload index…
austinywang 40daffd
fix: await resume evidence before the startup completion save
austinywang ab3fa56
Merge remote-tracking branch 'origin/main' into issue-12793-restore-r…
austinywang 1e8f4d0
test: reproduce restore binding loss before process observation
austinywang 1c907f8
Merge remote-tracking branch 'origin/main' into issue-12793-restore-r…
austinywang ac26501
fix: preserve restored process bindings until observation or expiry
austinywang 117edf2
fix: address restore review invariants
austinywang 4bc20b0
fix: quote restore observation project path
austinywang 56e0dd7
fix: import workspace shell state for restore helper
austinywang 7cca5d2
fix: avoid duplicate restore binding local
austinywang 4ff6bdd
Merge remote-tracking branch 'origin/main' into issue-12793-restore-r…
austinywang 5af0f3d
fix: address review freshness and package boundaries
austinywang f8bd716
fix: preserve fresh-index freeze invariant
austinywang 07274e7
fix: expose restore observation with public scalar types
austinywang 9d14169
fix: expose SSH restore observation limit to extension
austinywang 96f31a9
Merge remote-tracking branch 'origin/main' into issue-12793-restore-r…
austinywang 596f617
fix: use lifecycle signals for restore retention
austinywang 21f676e
fix: unwrap completed recovery indexes
austinywang c3a2721
fix: unwrap recovered binding index
austinywang ff8f2a6
fix: keep retry scheduling outside defer exits
austinywang 53faa57
fix: use concrete recovery binding map
austinywang 6f4f8c0
fix: clear restore observation at shell prompt
austinywang b9ced65
fix: tie restore cleanup to fresh lifecycle evidence
austinywang e038169
fix: retain restore protection on rejected replay
austinywang 0999678
Merge branch 'main' of https://github.com/manaflow-ai/cmux into issue…
austinywang aa390fc
fix: scope process save coordination
austinywang 9c0f415
Merge origin/main into restore resume lifecycle branch
austinywang 734919e
Fix restore lifecycle integration after main merge
austinywang 15bd488
Preserve resume bindings when process evidence is unavailable
austinywang 48bbcd8
Merge origin/main into restore resume lifecycle branch
austinywang 1aedc13
Fix resume binding equality after legacy field removal
austinywang 4e166cd
Update restore projection tests for current lifecycle API
austinywang 699b98e
Clean up remote-close test shells before later suites
austinywang 066ad28
Merge origin/main into restore resume lifecycle branch
austinywang 6f28153
Merge main (ce5cb45d55d9) into issue-12793-restore-resume-lifecycle
austinywang adeabe3
Bump Bonsplit for main split auto-layout API
austinywang bb4060a
Merge main (ecba57ac7195) into issue-12793-restore-resume-lifecycle
austinywang 7c5c5a9
test: bound restore observation and windowless freeze retries
austinywang 981d207
Bound restore observation and windowless freeze retries
austinywang 238cacd
Restore Bonsplit pointer rewound by #15747
austinywang 0883b13
Start restore observation window when the runtime spawns
austinywang bd84160
Fix test compilation after main merge
austinywang cdec6e6
Merge main (3b29735c8182) into issue-12793-restore-resume-lifecycle
austinywang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
...S/CmuxWorkspaces/Sources/CmuxWorkspaces/Session/RestoredProcessDetectionObservation.swift
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /// Owns the explicit lifecycle observation state for a process-backed restore binding. | ||
| /// | ||
| /// A restored binding is protected from empty scans while its terminal has not | ||
| /// yet spawned, because its restore command cannot have run. Once the runtime | ||
| /// spawns, protection lasts ``observationWindow``: a binding whose command never | ||
| /// launches, or whose shell never reports a prompt transition, then retires like | ||
| /// any unobserved binding instead of surviving every relaunch. | ||
| public struct RestoredProcessDetectionObservation: Equatable, Sendable { | ||
| /// Upper bound for a spawned restored shell to run its queued command. | ||
| /// | ||
| /// Measured on the suspending clock so machine sleep does not consume it. | ||
| public static let observationWindow: Duration = .seconds(300) | ||
|
|
||
| private enum Phase: Equatable, Sendable { | ||
| case awaitingRuntimeSpawn | ||
| case runtimeSpawned(at: SuspendingClock.Instant) | ||
| } | ||
|
|
||
| private var phase: Phase? | ||
|
|
||
| /// Creates a cleared observation policy. | ||
| public init() { | ||
| phase = nil | ||
| } | ||
|
|
||
| /// Arms observation until the runtime spawns and evidence arrives or the window elapses. | ||
| public mutating func arm() { | ||
| phase = .awaitingRuntimeSpawn | ||
| } | ||
|
|
||
| /// Starts the observation window once the restored terminal runtime exists. | ||
| /// | ||
| /// - Returns: Whether the observation state changed. | ||
| @discardableResult | ||
| public mutating func recordRuntimeSpawn(at now: SuspendingClock.Instant = .now) -> Bool { | ||
| guard phase == .awaitingRuntimeSpawn else { return false } | ||
| phase = .runtimeSpawned(at: now) | ||
| return true | ||
| } | ||
|
|
||
| /// Returns whether the restore binding remains protected from an empty scan. | ||
| public func preserves(at now: SuspendingClock.Instant = .now) -> Bool { | ||
| switch phase { | ||
| case nil: | ||
| return false | ||
| case .awaitingRuntimeSpawn: | ||
| return true | ||
| case .runtimeSpawned(let spawnedAt): | ||
| return spawnedAt.duration(to: now) < Self.observationWindow | ||
| } | ||
| } | ||
|
|
||
| /// Clears observation after authoritative process or shell evidence. | ||
| public mutating func clear() { | ||
| phase = nil | ||
| } | ||
| } |
39 changes: 39 additions & 0 deletions
39
...S/CmuxWorkspaces/Tests/CmuxWorkspacesTests/RestoredProcessDetectionObservationTests.swift
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import Testing | ||
| @testable import CmuxWorkspaces | ||
|
|
||
| @Suite struct RestoredProcessDetectionObservationTests { | ||
| @Test func armedLifecycleStatePreservesUntilCleared() { | ||
| var observation = RestoredProcessDetectionObservation() | ||
| #expect(!observation.preserves()) | ||
| observation.arm() | ||
| #expect(observation.preserves()) | ||
| observation.clear() | ||
| #expect(!observation.preserves()) | ||
| } | ||
|
|
||
| @Test func observationWaitsForTheRuntimeSpawnBeforeItsWindowStarts() { | ||
| // A paced or unviewed restored terminal may spawn long after restore; | ||
| // its command cannot have run, so the window must not start early. | ||
| var observation = RestoredProcessDetectionObservation() | ||
| observation.arm() | ||
| let spawnedAt = SuspendingClock.now.advanced(by: .seconds(3_600)) | ||
| #expect(observation.preserves(at: spawnedAt)) | ||
| // `recordRuntimeSpawn` is mutating, so each result is read outside the test macros. | ||
| let firstSpawn = observation.recordRuntimeSpawn(at: spawnedAt) | ||
| let repeatedSpawn = observation.recordRuntimeSpawn(at: spawnedAt.advanced(by: .seconds(10))) | ||
| #expect(firstSpawn) | ||
| #expect(!repeatedSpawn) | ||
| let window = RestoredProcessDetectionObservation.observationWindow | ||
| #expect(observation.preserves(at: spawnedAt.advanced(by: window - .seconds(1)))) | ||
| #expect(!observation.preserves(at: spawnedAt.advanced(by: window))) | ||
| } | ||
|
|
||
| @Test func aClearedObservationIgnoresALateSpawn() { | ||
| var observation = RestoredProcessDetectionObservation() | ||
| observation.arm() | ||
| observation.clear() | ||
| let lateSpawn = observation.recordRuntimeSpawn() | ||
| #expect(!lateSpawn) | ||
| #expect(!observation.preserves()) | ||
| } | ||
| } |
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.