520 lines
18 KiB
Markdown
520 lines
18 KiB
Markdown
# SuiteLink Runtime Reconnect Implementation Plan
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Add a background receive loop with automatic reconnect and subscription replay so the client continues dispatching updates after transport/session failures.
|
|
|
|
**Architecture:** The implementation extends `SuiteLinkClient` with a supervised runtime loop and reconnect flow while keeping durable subscription intent separate from ephemeral session mappings. Recovery rebuilds transport/session state, replays subscriptions, and resumes update dispatch without caller polling.
|
|
|
|
**Tech Stack:** .NET 10, C#, xUnit, `SemaphoreSlim`, `CancellationTokenSource`, existing SuiteLink codec/session/transport layers
|
|
|
|
---
|
|
|
|
### Task 1: Add Durable Subscription Registry
|
|
|
|
**Files:**
|
|
- Create: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SubscriptionRegistrationEntry.cs`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientSubscriptionRegistryTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task SubscribeAsync_StoresDurableSubscriptionIntent()
|
|
{
|
|
var client = TestClientFactory.CreateReadyClient();
|
|
|
|
await client.SubscribeAsync("Pump001.Run", _ => { });
|
|
|
|
Assert.True(client.HasSubscription("Pump001.Run"));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientSubscriptionRegistryTests -v minimal`
|
|
Expected: FAIL with missing durable registry behavior
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add a durable registry entry model storing:
|
|
|
|
- `ItemName`
|
|
- callback
|
|
- requested tag id
|
|
|
|
Store these entries in `SuiteLinkClient` separately from `SuiteLinkSession`.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientSubscriptionRegistryTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SubscriptionRegistrationEntry.cs /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientSubscriptionRegistryTests.cs
|
|
git commit -m "feat: add durable subscription registry"
|
|
```
|
|
|
|
### Task 2: Make Subscription Handles Remove Durable Intent
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SubscriptionHandle.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientSubscriptionRegistryTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task DisposingSubscription_RemovesDurableSubscriptionIntent()
|
|
{
|
|
var client = TestClientFactory.CreateReadyClient();
|
|
var handle = await client.SubscribeAsync("Pump001.Run", _ => { });
|
|
|
|
await handle.DisposeAsync();
|
|
|
|
Assert.False(client.HasSubscription("Pump001.Run"));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter DisposingSubscription_RemovesDurableSubscriptionIntent -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Ensure handle disposal removes durable registry entries even when wire unadvise cannot be sent.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientSubscriptionRegistryTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SubscriptionHandle.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientSubscriptionRegistryTests.cs
|
|
git commit -m "feat: persist subscription intent across reconnects"
|
|
```
|
|
|
|
### Task 3: Add Runtime State For Background Loop
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SuiteLinkSessionState.cs`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientConnectionTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task ConnectAsync_TransitionsToReadyOnlyAfterRuntimeStarts()
|
|
{
|
|
var client = TestClientFactory.CreateReadyHandshakeClient();
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
|
|
Assert.True(client.IsConnected);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter ConnectAsync_TransitionsToReadyOnlyAfterRuntimeStarts -v minimal`
|
|
Expected: FAIL with missing ready/runtime state
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add:
|
|
|
|
- `Ready`
|
|
- `Reconnecting`
|
|
|
|
and transition `ConnectAsync` into `Ready` when the runtime loop has been established.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientConnectionTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SuiteLinkSessionState.cs /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientConnectionTests.cs
|
|
git commit -m "feat: add ready and reconnecting runtime states"
|
|
```
|
|
|
|
### Task 4: Start Background Receive Loop
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientRuntimeLoopTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task ConnectAsync_StartsBackgroundLoop_AndDispatchesUpdateWithoutManualPolling()
|
|
{
|
|
var updateReceived = new TaskCompletionSource<SuiteLinkTagUpdate>();
|
|
var client = TestClientFactory.CreateClientWithQueuedUpdate(updateReceived);
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
await client.SubscribeAsync("Pump001.Run", update => updateReceived.TrySetResult(update));
|
|
|
|
var update = await updateReceived.Task.WaitAsync(TimeSpan.FromSeconds(1));
|
|
Assert.True(update.Value.TryGetBoolean(out var value) && value);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientRuntimeLoopTests -v minimal`
|
|
Expected: FAIL because manual processing is still required
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Start a long-lived receive loop task after initial connect, and dispatch updates through existing session logic.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientRuntimeLoopTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientRuntimeLoopTests.cs
|
|
git commit -m "feat: add suitelink background receive loop"
|
|
```
|
|
|
|
### Task 5: Make ProcessIncomingAsync Internal Or Non-Primary
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/README.md`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientRuntimeLoopTests.cs`
|
|
|
|
**Step 1: Write the failing documentation/runtime check**
|
|
|
|
Define the intended runtime contract:
|
|
|
|
- normal operation uses background receive
|
|
- manual polling is not required for normal subscriptions
|
|
|
|
**Step 2: Run targeted tests**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientRuntimeLoopTests -v minimal`
|
|
Expected: PASS after Task 4
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Keep `ProcessIncomingAsync` only as an internal/test helper or document it as non-primary API.
|
|
|
|
**Step 4: Run test and docs verification**
|
|
|
|
Run: `rg -n "background receive|manual polling|ProcessIncomingAsync" /Users/dohertj2/Desktop/suitelinkclient/README.md`
|
|
Expected: PASS with updated wording
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/README.md
|
|
git commit -m "docs: describe background runtime model"
|
|
```
|
|
|
|
### Task 6: Detect EOF And Trigger Reconnect
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task ReceiveLoop_Eof_TransitionsToReconnecting()
|
|
{
|
|
var client = TestClientFactory.CreateClientThatEofsAfterConnect();
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
|
|
await Eventually.AssertAsync(() => Assert.Equal(SuiteLinkSessionState.Reconnecting, client.DebugState));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientReconnectTests -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Treat `ReceiveAsync == 0` as a disconnect trigger and start recovery.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientReconnectTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs
|
|
git commit -m "feat: detect disconnects and enter reconnect state"
|
|
```
|
|
|
|
### Task 7: Add Bounded Reconnect Backoff
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task Reconnect_UsesBoundedRetrySchedule()
|
|
{
|
|
var delays = new List<TimeSpan>();
|
|
var client = TestClientFactory.CreateReconnectTestClient(delays);
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
|
|
Assert.Contains(TimeSpan.FromSeconds(1), delays);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter Reconnect_UsesBoundedRetrySchedule -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Add a small capped delay schedule:
|
|
|
|
- 0s
|
|
- 1s
|
|
- 2s
|
|
- 5s
|
|
- 10s capped
|
|
|
|
Inject delay behavior for tests if needed.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientReconnectTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs
|
|
git commit -m "feat: add bounded reconnect backoff"
|
|
```
|
|
|
|
### Task 8: Replay Subscriptions After Reconnect
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SuiteLinkSession.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task Reconnect_ReplaysSubscriptions_AndRestoresDispatch()
|
|
{
|
|
var callbackCount = 0;
|
|
var client = TestClientFactory.CreateReconnectReplayClient(() => callbackCount++);
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
await client.SubscribeAsync("Pump001.Run", _ => callbackCount++);
|
|
|
|
await client.WaitForReconnectReadyAsync();
|
|
Assert.True(callbackCount > 0);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter Reconnect_ReplaysSubscriptions_AndRestoresDispatch -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
On successful reconnect:
|
|
|
|
- reset live session mappings
|
|
- replay all durable subscriptions one-by-one
|
|
- rebuild tag mappings from fresh ACKs
|
|
- return to `Ready`
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientReconnectTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/Internal/SuiteLinkSession.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientReconnectTests.cs
|
|
git commit -m "feat: replay subscriptions after reconnect"
|
|
```
|
|
|
|
### Task 9: Reject Writes During Reconnect
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientWriteTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task WriteAsync_DuringReconnect_ThrowsClearException()
|
|
{
|
|
var client = TestClientFactory.CreateReconnectingClient();
|
|
|
|
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
|
client.WriteAsync("Pump001.Run", SuiteLinkValue.FromBoolean(true)));
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter WriteAsync_DuringReconnect_ThrowsClearException -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Guard `WriteAsync` so it succeeds only in `Ready`.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientWriteTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientWriteTests.cs
|
|
git commit -m "feat: reject writes while reconnecting"
|
|
```
|
|
|
|
### Task 10: Stop Runtime Cleanly On Disconnect
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs`
|
|
- Test: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientConnectionTests.cs`
|
|
|
|
**Step 1: Write the failing test**
|
|
|
|
```csharp
|
|
[Fact]
|
|
public async Task DisconnectAsync_StopsReceiveAndReconnectLoops()
|
|
{
|
|
var client = TestClientFactory.CreateRunningClient();
|
|
|
|
await client.ConnectAsync(TestOptions.Create());
|
|
await client.DisconnectAsync();
|
|
|
|
Assert.False(client.IsConnected);
|
|
}
|
|
```
|
|
|
|
**Step 2: Run test to verify it fails**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter DisconnectAsync_StopsReceiveAndReconnectLoops -v minimal`
|
|
Expected: FAIL
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Cancel runtime loop tokens and stop reconnect attempts on disconnect/dispose.
|
|
|
|
**Step 4: Run test to verify it passes**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter SuiteLinkClientConnectionTests -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/src/SuiteLink.Client/SuiteLinkClient.cs /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.Tests/SuiteLinkClientConnectionTests.cs
|
|
git commit -m "feat: stop runtime loops on disconnect"
|
|
```
|
|
|
|
### Task 11: Update README And Integration Docs
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/README.md`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.IntegrationTests/README.md`
|
|
|
|
**Step 1: Write the failing documentation check**
|
|
|
|
Define required README terms:
|
|
|
|
- background receive loop
|
|
- automatic reconnect
|
|
- subscription replay
|
|
- writes rejected during reconnect
|
|
|
|
**Step 2: Run documentation review**
|
|
|
|
Run: `rg -n "background receive|automatic reconnect|subscription replay|reconnecting" /Users/dohertj2/Desktop/suitelinkclient/README.md /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.IntegrationTests/README.md`
|
|
Expected: FAIL until docs are updated
|
|
|
|
**Step 3: Write minimal implementation**
|
|
|
|
Update docs to describe the runtime model and recovery behavior honestly.
|
|
|
|
**Step 4: Run documentation review**
|
|
|
|
Run: `rg -n "background receive|automatic reconnect|subscription replay|reconnecting" /Users/dohertj2/Desktop/suitelinkclient/README.md /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.IntegrationTests/README.md`
|
|
Expected: PASS
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/README.md /Users/dohertj2/Desktop/suitelinkclient/tests/SuiteLink.Client.IntegrationTests/README.md
|
|
git commit -m "docs: describe runtime reconnect behavior"
|
|
```
|
|
|
|
### Task 12: Full Verification Pass
|
|
|
|
**Files:**
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/docs/plans/2026-03-17-runtime-reconnect-design.md`
|
|
- Modify: `/Users/dohertj2/Desktop/suitelinkclient/docs/plans/2026-03-17-runtime-reconnect-implementation-plan.md`
|
|
|
|
**Step 1: Run full test suite**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx -v minimal`
|
|
Expected: PASS with integration harness still conditional by default
|
|
|
|
**Step 2: Run release build**
|
|
|
|
Run: `dotnet build /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx -c Release`
|
|
Expected: PASS
|
|
|
|
**Step 3: Run reconnect-focused tests**
|
|
|
|
Run: `dotnet test /Users/dohertj2/Desktop/suitelinkclient/SuiteLink.Client.slnx --filter Reconnect -v minimal`
|
|
Expected: PASS
|
|
|
|
**Step 4: Update plan notes if implementation deviated**
|
|
|
|
Add short notes to the design/plan docs if final runtime behavior differs from original assumptions.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add /Users/dohertj2/Desktop/suitelinkclient/docs/plans/2026-03-17-runtime-reconnect-design.md /Users/dohertj2/Desktop/suitelinkclient/docs/plans/2026-03-17-runtime-reconnect-implementation-plan.md
|
|
git commit -m "docs: finalize reconnect implementation verification"
|
|
```
|