docs(integration): record Unscouted pilot evidence (#22)
quality-gate / quality (push) Failing after 1m35s
quality-gate / container (push) Has been skipped

This commit is contained in:
KyuubiYoru
2026-07-16 21:53:48 +02:00
parent f368fec6eb
commit 6bad659c12
4 changed files with 215 additions and 3 deletions
+3 -3
View File
@@ -119,9 +119,9 @@ versioning, and secure rollout seams are in the
The always-on three-party scenarios, optional Linux namespace topology, and The always-on three-party scenarios, optional Linux namespace topology, and
simulation limits are documented in the simulation limits are documented in the
[deterministic topology harness](docs/integration/topology-harness.md). [deterministic topology harness](docs/integration/topology-harness.md).
The current consumer evidence and the still-open public-package, Godot-process, The current consumer evidence and remaining external gates are tracked in the
fallback, reconnect, Linux, and external-NAT gates are tracked in the [SpaceGame consumer pilot](docs/integration/spacegame-pilot.md) and independent
[SpaceGame consumer pilot](docs/integration/spacegame-pilot.md). [Unscouted consumer pilot](docs/integration/unscouted-pilot.md).
## Development ## Development
+82
View File
@@ -0,0 +1,82 @@
{
"schemaVersion": "1.0",
"recordedAt": "2026-07-16",
"issue": 22,
"consumerIssue": "HeiKyu/Unscouted#459",
"result": "checkpoint-pass-with-external-gates",
"rendezvousConfigurationCommit": "f368fec6eb4344a6042974f58f888cf0f1ac8e8e",
"consumerImplementationCommit": "1e5886aa7f1e44689b4c75e32693eb7b19fd72d7",
"consumerEvidenceCommit": "f0574a7de82aadff6495ca5657dfc19cf7c2f67c",
"consumerIssueComment": 11499,
"packages": {
"FinalFactory.Rendezvous.Client": {
"version": "1.0.0",
"source": "local-candidate",
"sourceCommit": "07004cd75fe172aa5dfdb3edda22fc280a4c4477",
"sha256": "fb156cf48b49f75c244dd25ea7cc4aa9fc6fab0a878393bb7efd5d9b131d0395"
},
"FinalFactory.Rendezvous.Contracts": {
"version": "1.0.0",
"source": "local-candidate",
"sourceCommit": "07004cd75fe172aa5dfdb3edda22fc280a4c4477",
"sha256": "a82ba986d3905d599096d1d8ce8f32cd4feb104abfca37b0f65e0d2ef3df9a6f"
},
"LiteNetLib": {
"version": "2.1.4"
}
},
"configuration": {
"gameId": "unscouted",
"environmentId": "smoke",
"regionId": "local",
"protocolVersion": 1,
"publisherTrust": "ManagedDedicated",
"fallbackPolicy": "DedicatedEndpointAllowed",
"metadataKeys": ["mode", "world", "mods"],
"metadataMaxKeys": 3,
"metadataMaxBytes": 512
},
"godotRun": {
"runtime": "Godot 4.7 .NET Linux x86_64",
"processes": [
"Rendezvous hardened Compose service",
"Godot Unscouted host",
"Godot incompatible-protocol client",
"Godot direct client",
"Godot fallback client"
],
"gameplayTransport": "unscouted-litenetlib",
"rendezvousGameplayPayloadPath": "none",
"directGameplay": true,
"fallbackGameplay": true,
"authenticatedSessions": 2,
"gameplayExchanges": 2,
"hostLeaseRenewed": true,
"deregistered": true,
"playerIdentityOwner": "unscouted",
"canonicalGameStateOwner": "unscouted"
},
"negativePaths": {
"incompatibleProtocol": "proven-no-compatible-listing",
"wrongGame": "proven-exact-NotFound",
"wrongEnvironment": "proven-exact-NotFound",
"punchTimeout": "proven-typed-failure-then-game-owned-fallback",
"unexpectedMetadata": "consumer-regression-tested"
},
"verification": {
"rendezvousDebugTests": { "passed": 299, "failed": 0 },
"rendezvousReleaseTests": { "passed": 299, "failed": 0 },
"consumerDebugTests": { "passed": 3310, "skipped": 15, "failed": 0 },
"consumerReleaseTests": { "passed": 3310, "skipped": 15, "failed": 0 },
"consumerGdUnitTests": { "passed": 360, "skipped": 0, "failed": 0 },
"consumerExport": "not-applicable-no-export-presets",
"format": "passed",
"shellcheck": "passed",
"godotPilot": "passed",
"adversarialReview": "passed-after-fixes"
},
"openGates": [
"public-package-restore",
"representative-external-nat"
]
}
+99
View File
@@ -0,0 +1,99 @@
# Unscouted consumer pilot
Tracking: Rendezvous #22 and Unscouted #459.
The current checkpoint independently proves that the v1 contracts are not
shaped only around SpaceGame. A real Godot Unscouted host and clients consume
the same Client and Contracts package surface, use one caller-owned LiteNetLib
socket for NAT callbacks and gameplay, perform Unscouted's own keypair
authentication and host admission, exchange gameplay, and exercise a
game-owned fallback. The public package restore and representative external
NAT/CGNAT canary remain required before #22 can close.
## Pinned checkpoint
| Input | Value |
| --- | --- |
| Rendezvous configuration source | `f368fec6eb4344a6042974f58f888cf0f1ac8e8e` |
| Rendezvous package source | `07004cd75fe172aa5dfdb3edda22fc280a4c4477` |
| Unscouted implementation | `1e5886aa7f1e44689b4c75e32693eb7b19fd72d7` |
| Unscouted evidence | `f0574a7de82aadff6495ca5657dfc19cf7c2f67c` |
| Client package | `FinalFactory.Rendezvous.Client` `1.0.0` |
| Contracts package | `FinalFactory.Rendezvous.Contracts` `1.0.0` |
| LiteNetLib | `2.1.4` |
| Godot | `4.7.stable.mono.arch_linux.5b4e0cb0f` |
| Game / environment / region | `unscouted` / `smoke` / `local` |
| Rendezvous and gameplay protocol | `1` |
The exact package hashes are recorded in
[`unscouted.json`](../evidence/consumers/unscouted.json). A clean restore into an
empty package directory using only the consumer's checked-in `NuGet.config`
returns `NU1101` for both packages. The verified local run used those exact
candidate package files from the existing cache. This proves compatibility,
not immutable registry publication.
## Game-neutral service boundary
Rendezvous #22 adds provisioning data, not an Unscouted branch in the server or
SDK. The local production-shaped tenant permits protocol `1`, region `local`,
public managed-dedicated listings, and the three bounded presentation keys
`mode`, `world`, and `mods`. The short-lived credential helper accepts only the
explicitly provisioned `space-game` and `unscouted` scopes and selects a
distinct game-scoped signing-key ID and subject.
The consumer rejects any metadata key outside its three-key presentation
schema and neutralizes control/BBCode characters before display. Rendezvous
never receives Unscouted player keys or resolved identities, colony authority,
simulation or persistence state, fog/interest state, or gameplay packets.
## Proven real Godot path
The normal `NetLaunch` argument path recognizes `--rendezvous-pilot` and opens a
dedicated scene. That scene uses Unscouted's real `LiteNetLibTransport`,
`GameServer`, `GameClient`, `ServerAuthenticator`, and `ClientAuthenticator`.
It is not a copied SDK adapter.
One bounded run against the hardened Compose service started a host plus:
- a protocol-`999` client that found no compatible listing;
- a direct client that received an authorized introduction, completed
same-socket traversal, passed Unscouted keypair admission, and exchanged an
Unscouted gameplay ping/pong; and
- a client pointed at a non-listening mediator that received a typed traversal
failure, applied the fallback decision in Unscouted code, repeated admission,
and exchanged the same gameplay ping/pong through the ordinary game
transport.
The direct client also proved that both a `space-game` join request and a
`production` environment join request return exact `NotFound` results for the
Unscouted listing. The host renewed its lease, admitted two independently
authenticated sessions, completed two gameplay exchanges, and deregistered the
listing on shutdown.
## Verification
- Rendezvous Debug and Release: 299 tests passed in each configuration, zero
failures.
- Unscouted Debug and Release: non-incremental builds passed; 3,310 tests passed
with 15 intentional skips in each configuration.
- Unscouted gdUnit/Godot: 360 tests passed, zero skipped or failed. The harness
fix in Unscouted #461 keeps compilation headless and leaves the open editor's
build tree unchanged.
- The final Godot pilot, ShellCheck, JSON/whitespace checks, formatting gate,
and adversarial branch review passed.
- Export is not applicable because the Unscouted checkout has no
`export_presets.cfg`; both C# configurations and the actual Godot entry point
were exercised.
## Remaining acceptance gates
Do not mark #22 passed until both external gates have direct evidence:
1. publish or expose the exact immutable `1.0.0` packages on the configured
Gitea feed and repeat the empty-cache consumer restore; and
2. run the same Godot host/client path across representative residential,
CGNAT, and IPv6/multi-host networks, recording the topology and typed
direct/fallback outcome.
The loopback run proves the real process, socket, authentication, and gameplay
shape. It does not claim production Internet traversal coverage.
@@ -259,6 +259,37 @@ public sealed partial class DocumentationContractTests
Assert.DoesNotMatch(ReusableCredential(), guide); Assert.DoesNotMatch(ReusableCredential(), guide);
} }
[Fact]
public void UnscoutedPilotEvidenceProvesAnIndependentGameBoundaryAndKeepsExternalGatesOpen()
{
string root = FindRepositoryRoot();
string guide = File.ReadAllText(Path.Combine(root, "docs", "integration", "unscouted-pilot.md"));
using JsonDocument evidence = JsonDocument.Parse(File.ReadAllText(
Path.Combine(root, "docs", "evidence", "consumers", "unscouted.json")));
JsonElement record = evidence.RootElement;
JsonElement run = record.GetProperty("godotRun");
JsonElement negative = record.GetProperty("negativePaths");
Assert.Equal("checkpoint-pass-with-external-gates", record.GetProperty("result").GetString());
Assert.Equal("unscouted", record.GetProperty("configuration").GetProperty("gameId").GetString());
Assert.Equal(["mode", "world", "mods"], record.GetProperty("configuration").GetProperty("metadataKeys")
.EnumerateArray().Select(static value => value.GetString()));
Assert.Equal("none", run.GetProperty("rendezvousGameplayPayloadPath").GetString());
Assert.Equal("unscouted-litenetlib", run.GetProperty("gameplayTransport").GetString());
Assert.True(run.GetProperty("directGameplay").GetBoolean());
Assert.True(run.GetProperty("fallbackGameplay").GetBoolean());
Assert.Equal(2, run.GetProperty("authenticatedSessions").GetInt32());
Assert.Equal("proven-exact-NotFound", negative.GetProperty("wrongGame").GetString());
Assert.Equal("proven-exact-NotFound", negative.GetProperty("wrongEnvironment").GetString());
Assert.Equal(3310, record.GetProperty("verification").GetProperty("consumerDebugTests").GetProperty("passed").GetInt32());
Assert.Equal(360, record.GetProperty("verification").GetProperty("consumerGdUnitTests").GetProperty("passed").GetInt32());
Assert.Contains("public-package-restore", record.GetProperty("openGates").EnumerateArray().Select(static gate => gate.GetString()));
Assert.Contains("representative-external-nat", record.GetProperty("openGates").EnumerateArray().Select(static gate => gate.GetString()));
Assert.Contains("Do not mark #22 passed", guide, StringComparison.Ordinal);
Assert.Contains("not an Unscouted branch", guide, StringComparison.Ordinal);
Assert.DoesNotMatch(ReusableCredential(), guide);
}
[GeneratedRegex(@"rv1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+", RegexOptions.CultureInvariant)] [GeneratedRegex(@"rv1\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+", RegexOptions.CultureInvariant)]
private static partial Regex ReusableCredential(); private static partial Regex ReusableCredential();