Skip to content

Commit 312e4fd

Browse files
committed
Fix native local image ownership across RF3 foundation fixtures
Transfer the original verified Aspire image preparation and its ownership through physical-owner, remote-query, request-phase fault and follower-restart fixtures. Admit one exact eight-case combined selection and preserve original cancellation, state, receipt and joined-cleanup assertions. Reorder the private cancellation parameter and existing imports required by native analysis and the full formatter. Validation: canonical full dotnet format verification passed; strict full Release solution build passed with zero warnings and errors. Source drift was zero. Native selection and eight RF3 operation cases remain pending the coherent lifetime integration; this is a source/build checkpoint, not completed runtime or Linux qualification.
1 parent f2c38db commit 312e4fd

20 files changed

Lines changed: 151 additions & 37 deletions

‎docs/Features/TestInfrastructure/WholeClassLocalRf3Admission.md‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,48 @@ REQ/AC-RF3-CURRENT-001 preserves every preceding selector and additionally admit
4343
`/*/*/(SafeProjectorOperationRf3Tests|SqlParserAdmissionRf3WholeFlowTests|GraphSearchLineageRf3Tests|AtomicTriadStagedRf3Tests|CompetingInboxPublicTests|QueueViewLeaseIsolationTests)/*`
4444

4545
The same Node selector, fixture environment restoration and preparation-model lifecycle controls cover every new selection. They retain the original six classes and combined filter. New combined-order refusal swaps its actual first two classes; no UID is authored or inferred. AppHost model controls preserve the native nonempty-filter boundary and test mixed-identity refusal before resources, unique image prerequisite, runner dependency, native50 and joined model disposal. Actual native case census, rebuilt DLL/PDB identities, source-bound image creation, SDK/MCP RF3 operations, cold recovery and original cleanup remain OPEN until genuine Root execution; Comparison checks run only in Linux GitHub Actions. Functional coverage remains the original closed eleven-case cohort; these selectors add no coverage contributors or performance qualification.
46+
47+
48+
## Native image ownership for four foundation fixtures
49+
50+
REQ/AC-RF3-IMAGE-OWNERSHIP-001 requires PhysicalOwnerRegistrationRf3Tests,
51+
RemotePartitionQueryRf3Tests, RequestCqrsPhaseFaultTests and
52+
RequestCqrsRf3FollowerRestartTests to use the existing
53+
LocalRf3ImageTestSession before their original image proof and native startup.
54+
The same verified Selection and original preparation owner flow into each
55+
existing wave. Unselected GitHub receipt admission stays strict. Mixed identity,
56+
unknown image or failed preparation cannot acquire database resources.
57+
58+
REQ/AC-RF3-IMAGE-OWNERSHIP-002 requires original caller/producer settlement,
59+
joined AppHost shutdown and storage-lock checks before local image disposal.
60+
Transfer ownership once; join a preparation which fails before transfer through
61+
the existing never-built cleanup. Preserve original primary and cleanup failures,
62+
all physical groups, roots and unknown-ownership retention. The existing restart,
63+
cancellation, persisted permissions, state and complete receipt assertions remain.
64+
65+
REQ/AC-RF3-IMAGE-OWNERSHIP-003 admits one additional exact combined filter:
66+
67+
`/*/*/(PhysicalOwnerRegistrationRf3Tests|RemotePartitionQueryRf3Tests|RequestCqrsPhaseFaultTests|RequestCqrsRf3FollowerRestartTests)/*`
68+
69+
Node and native fixture gates must agree. The current model selection inventory
70+
grows from fourteen to fifteen by appending that single literal; all previous
71+
filters remain. Native Node operation controls also reject expanded/reordered/
72+
partial/whitespace variants and unapproved individual class filters, conserve
73+
inputs and prove the exact healthy selection afterward. Existing
74+
NativeTUnitSelectionTests supplies four native cases for these controls.
75+
76+
The RF3 source declarations predict eight cases: one physical-owner operation,
77+
two SDK/MCP remote-query argument instances, four request-phase fault operations
78+
and one follower-restart operation. Original rebuilt native TRX and exact method/
79+
argument identities must prove eight passed, zero failed and zero skipped.
80+
Parameterless NotInParallel remains on all four classes and native parallelism50
81+
is unchanged. No production code, deadline, assertion, coverage contributor or
82+
UID changes. Source counts and reviews do not prove runtime success.
83+
84+
ADR-117 and the existing image ownership contracts remain sufficient: no new
85+
product/trust/persistence/topology boundary is introduced. Root integrates the
86+
coherent six fixture files and four selector/control files, formats them, builds
87+
the strict solution, passes the four selection cases, then executes the eight
88+
original RF3 operations. Local and exact-source Linux qualification are OPEN
89+
until their own original results exist. No migration or persisted rollout is
90+
needed; rollback reverts this coherent test-only enrollment.

‎scripts/Features/TestInfrastructure/run-tests.mjs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ localImageFilters.add("/*/*/CrossTenantRf3WholeFlowTests/Kl015ForeignWritesScans
7777
localImageFilters.add("/*/*/RemotePartitionQueryRf3Tests/AcPqueryRemote001To005DestinationDenialLiteralMergeReceiptReplayAndOwnedRestart");
7878
localImageFilters.add("/*/*/FunctionalDatabaseColdReopenTests/SingleInstanceColdReopensAllModelsAndReplaysOriginalPublicCommands");
7979
localImageFilters.add("/*/*/FunctionalDatabaseColdReopenTests/ThreeNodeColdReopensAllModelsAndReplaysOriginalPublicCommands");
80+
localImageFilters.add("/*/*/(PhysicalOwnerRegistrationRf3Tests|RemotePartitionQueryRf3Tests|RequestCqrsPhaseFaultTests|RequestCqrsRf3FollowerRestartTests)/*");
8081
const nativeTextPreparedFilter = '/*/*/(NativeTextAsyncRf3Tests)|(NativeTextMaintenanceRf3Tests)|(NativeTextRf3LeaderLossTests)|(NativeTextRf3Tests)|(NativeTextWaitRf3Tests)/*';
8182
const localImageGithubIdentity = ['KEYLOAD_IMAGE_RECEIPT', 'GITHUB_SHA', 'GITHUB_ACTIONS'];
8283
const localImageInheritedIdentity = ['KEYLOAD_IMAGE_PROVENANCE', 'KEYLOAD_LOCAL_IMAGE_RECEIPT',

‎tests/KeyLoad.IntegrationTests/Features/ClusterReplication/Helpers/LocalRf3ImageSelection.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ internal static class LocalRf3ImageSelection
8383
private const string RemotePartitionQueryFilterArgument = "--KeyLoadTests:Filter=/*/*/RemotePartitionQueryRf3Tests/AcPqueryRemote001To005DestinationDenialLiteralMergeReceiptReplayAndOwnedRestart";
8484
private const string FunctionalSingleColdFilterArgument = "--KeyLoadTests:Filter=/*/*/FunctionalDatabaseColdReopenTests/SingleInstanceColdReopensAllModelsAndReplaysOriginalPublicCommands";
8585
private const string FunctionalClusterColdFilterArgument = "--KeyLoadTests:Filter=/*/*/FunctionalDatabaseColdReopenTests/ThreeNodeColdReopensAllModelsAndReplaysOriginalPublicCommands";
86+
private const string NativeImageEnrollmentFilterArgument = "--KeyLoadTests:Filter=/*/*/(PhysicalOwnerRegistrationRf3Tests|RemotePartitionQueryRf3Tests|RequestCqrsPhaseFaultTests|RequestCqrsRf3FollowerRestartTests)/*";
8687
private const string EnabledArgument = "--KeyLoadTests:LocalRf3Image:Enabled=true";
8788
private const string EnabledValue = "true";
8889
private const int MaximumNativeArgumentCharacters = 4096;
@@ -138,7 +139,7 @@ or FoundationAdmissionAuthorityFilterArgument or FoundationTelemetryFilterArgume
138139
or AspireFaultFilterArgument or AcceptedRestartCancellationFilterArgument or OriginalRetireAspireFilterArgument
139140
or FunctionalSingleFilterArgument or FunctionalClusterFilterArgument or PartitionQueryValidationFilterArgument
140141
or CrossTenantWholeFlowFilterArgument
141-
or RemotePartitionQueryFilterArgument or FunctionalSingleColdFilterArgument or FunctionalClusterColdFilterArgument
142+
or RemotePartitionQueryFilterArgument or FunctionalSingleColdFilterArgument or FunctionalClusterColdFilterArgument or NativeImageEnrollmentFilterArgument
142143
or CurrentGraphSearchPathPolicyFilterArgument or CurrentSampleChunkCorrectionFilterArgument or CurrentSqlGraphPublicFilterArgument or CurrentSqlGraphSamplePublicFilterArgument or CurrentGraphSamplePublicFilterArgument or CurrentFoundationRf3FilterArgument, EnabledArgument]
143144
|| Environment.GetEnvironmentVariable(NativeCoverageArgumentsEnvironment) is not null
144145
|| HasAmbientGithubIdentity()

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Assertions/ControlledRetireAspirePublicAssertions.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using KeyLoad.Client;
22
using KeyLoad.Core.Features.InternalSerialization;
3-
using KeyLoad.Server.Features.ClusterRouting;
43
using KeyLoad.IntegrationTests.Features.ClientApi;
54
using KeyLoad.IntegrationTests.Features.QueryExecution;
5+
using KeyLoad.Server.Features.ClusterRouting;
66
using C = KeyLoad.IntegrationTests.Features.ClusterRouting.ControlledRetireAspireCorpus;
77

88
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Cases/PhysicalOwnerRegistrationRf3Tests.cs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using KeyLoad.IntegrationTests.Features.ClusterReplication;
12
using KeyLoad.Server;
23

34
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;
@@ -19,8 +20,13 @@ public async Task AcOwnerRegister001To003RegistersConfiguredOwnersThenJoinsAllNo
1920
await ServerFailureObserver.ObserveAsync(async () =>
2021
{
2122
evidence.Enter(PhysicalOwnerRegistrationRf3Phase.WaveStart);
23+
var preparation = await LocalRf3ImageTestSession.StartIfSelectedAsync(deadline.Token).ConfigureAwait(false);
24+
var selection = preparation?.Selection ?? LocalRf3ImageSelection.Read();
2225
wave = await TwoRf3MembershipWave.StartOwnedAsync(
23-
new TwoRf3MembershipWave(null, register: true, nativeMembershipDiagnostics: true), deadline.Token).ConfigureAwait(false);
26+
new TwoRf3MembershipWave(selection, register: true, nativeMembershipDiagnostics: true)
27+
{
28+
localImagePreparation = preparation
29+
}, deadline.Token).ConfigureAwait(false);
2430
await PhysicalOwnerRegistrationRf3Observation.WaitAsync(wave.Application, evidence, deadline.Token).ConfigureAwait(false);
2531
evidence.Enter(PhysicalOwnerRegistrationRf3Phase.Fingerprint);
2632
await TwoRf3MembershipFingerprintOracle.VerifyAsync(wave.Application, wave.Profile, deadline.Token).ConfigureAwait(false);

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Cases/RequestCqrsRf3FollowerRestartTests.cs‎

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Aspire.Hosting;
22
using KeyLoad.IntegrationTests.Features.ClusterReplication;
33
using KeyLoad.IntegrationTests.Features.StorageRecovery;
4+
using KeyLoad.Server;
45

56
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;
67

@@ -13,16 +14,30 @@ public async Task TwoCompatibleVotersServeAndRestartedFollowerPublishesANewSigne
1314
using var deadlineTimeout = new CancellationTokenSource(RequestCqrsRf3Protocol.ParentDeadline, TimeProvider.System);
1415
using var deadline = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current!.Execution.CancellationToken, deadlineTimeout.Token);
1516
var dataRoot = CreatePrivateRoot();
16-
var (profile, _) = await NodeEpochRf3Profile.CreatePriorAsync(dataRoot, deadline.Token).ConfigureAwait(false);
17-
var images = await RequestCqrsRf3ImageProof.ReadAsync(deadline.Token).ConfigureAwait(false);
18-
var currentReference = new Dictionary<string, string>(StringComparer.Ordinal)
17+
var failures = new List<Exception>();
18+
LocalRf3ImageTestSession? localImageSession = null;
19+
await ServerFailureObserver.ObserveAsync(async () =>
1920
{
20-
[RequestCqrsRf3Protocol.Node1] = images.Current,
21-
[RequestCqrsRf3Protocol.Node2] = images.Current,
22-
[RequestCqrsRf3Protocol.Node3] = images.Current
23-
};
24-
var run = new RequestCqrsRf3FollowerRun(dataRoot, profile, deadline.Token);
25-
await run.ExecuteAsync(currentReference).ConfigureAwait(false);
21+
var (profile, _) = await NodeEpochRf3Profile.CreatePriorAsync(dataRoot, deadline.Token).ConfigureAwait(false);
22+
localImageSession = await LocalRf3ImageTestSession.StartIfSelectedAsync(deadline.Token).ConfigureAwait(false);
23+
var images = await RequestCqrsRf3ImageProof.ReadAsync(deadline.Token, localImageSession?.Selection).ConfigureAwait(false);
24+
var currentReference = new Dictionary<string, string>(StringComparer.Ordinal)
25+
{
26+
[RequestCqrsRf3Protocol.Node1] = images.Current,
27+
[RequestCqrsRf3Protocol.Node2] = images.Current,
28+
[RequestCqrsRf3Protocol.Node3] = images.Current
29+
};
30+
var run = new RequestCqrsRf3FollowerRun(dataRoot, profile, deadline.Token);
31+
var preparation = localImageSession;
32+
localImageSession = null;
33+
await run.ExecuteAsync(currentReference, preparation).ConfigureAwait(false);
34+
}, failures).ConfigureAwait(false);
35+
if (localImageSession is { } preparationBeforeTransfer)
36+
{
37+
await ClusterFixtureLocalImageLifecycle.JoinAsync(preparationBeforeTransfer, dataRoot,
38+
stopped: false, neverBuilt: true, failures).ConfigureAwait(false);
39+
}
40+
ServerFailureObserver.ThrowIfAny(failures);
2641
Directory.Delete(dataRoot, recursive: true);
2742
}
2843

@@ -42,9 +57,9 @@ private static string CreatePrivateRoot()
4257
internal sealed class RequestCqrsRf3FollowerRun(string dataRoot, NodeEpochRf3Profile profile,
4358
CancellationToken cancellationToken)
4459
{
45-
internal Task ExecuteAsync(IReadOnlyDictionary<string, string> images)
60+
internal Task ExecuteAsync(IReadOnlyDictionary<string, string> images, LocalRf3ImageTestSession? localImageSession)
4661
=> RequestCqrsRf3Epoch7WaveRunner.RunAsync(dataRoot, images, false, true,
47-
RunInWaveAsync, cancellationToken);
62+
RunInWaveAsync, cancellationToken, localImageSession: localImageSession);
4863

4964
private async Task RunInWaveAsync(RequestCqrsRf3Wave wave)
5065
{

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Helpers/ControlledRetireAspireBlob.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using KeyLoad.Client;
22
using KeyLoad.Core.Features.InternalSerialization;
3-
using KeyLoad.Server.Features.ClusterRouting;
43
using KeyLoad.IntegrationTests.Features.ClientApi;
54
using KeyLoad.IntegrationTests.Features.QueryExecution;
65
using KeyLoad.Server;
6+
using KeyLoad.Server.Features.ClusterRouting;
77
using C = KeyLoad.IntegrationTests.Features.ClusterRouting.ControlledRetireAspireCorpus;
88

99
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Helpers/ControlledRetireAspireFixture.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using KeyLoad.Clustering;
2-
using KeyLoad.Server;
32
using KeyLoad.IntegrationTests.Features.ClientApi;
4-
using ManagedCode.Communication;
3+
using KeyLoad.Server;
54
using KeyLoad.Server.Features.ClusterRouting;
5+
using ManagedCode.Communication;
66
using P = KeyLoad.IntegrationTests.Features.ClusterRouting.ControlledRetireAspireProtocol;
77

88
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Helpers/ControlledRetireAspireSeed.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using KeyLoad.Core.Features.InternalSerialization;
22
using KeyLoad.IntegrationTests.Features.ClientApi;
3-
using KeyLoad.Server.Features.ClusterRouting;
43
using KeyLoad.IntegrationTests.Features.QueryExecution;
4+
using KeyLoad.Server.Features.ClusterRouting;
55
using C = KeyLoad.IntegrationTests.Features.ClusterRouting.ControlledRetireAspireCorpus;
66

77
namespace KeyLoad.IntegrationTests.Features.ClusterRouting;

‎tests/KeyLoad.IntegrationTests/Features/ClusterRouting/Helpers/ControlledRetireAspireTrial.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using KeyLoad.Client;
2-
using KeyLoad.Server.Features.ClusterRouting;
32
using KeyLoad.IntegrationTests.Features.QueryExecution;
43
using KeyLoad.Server;
4+
using KeyLoad.Server.Features.ClusterRouting;
55
using ManagedCode.Communication;
66
using P = KeyLoad.IntegrationTests.Features.ClusterRouting.ControlledRetireAspireProtocol;
77

0 commit comments

Comments
 (0)