# .NET benchmark SDK discovery and output ownership

2026-10-03, functional generation
`8a85a5bd8af6` (full source pin in the retained manifests).

## Change

`bench/dotnet/Directory.Build.props` identifies its own harness through the
exported support marker before selecting the default SDK. The existing
`LibhftDotnetSource` property remains the input; a private normalized value
allows command-line paths with or without a trailing separator. Missing
explicit SDKs fail without borrowing an enclosing development checkout.
Both existing SDK project references consume that same normalized input.

Benchmark outputs now follow the owning harness rather than the SDK's relative
project path. With `LIBHFT_BUILD_ROOT`, devel preserves `bench/dotnet/...` and
the archive uses `dotnet/...`, matching the existing shared `build_path` API.
The SDK still owns its own policy. The original three XML files are retained
under `internal/bench/dotnet/discovery-before-20261003/`.

Runtime C# bodies, shared helper APIs, Stage 2 adapters/prepared generations,
wire fixtures, physical installers and report gates are unchanged. The
microbench owner confirmed no .NET preparation/output overlap; its SCAN
capture retains its original frozen inputs and queue.

## Actual source archive and SDK checks

The complete pinned harness selection plus templates contains **751 files**;
the separately supplied raw public .NET SDK selection plus templates contains
**661 files**. Neither source has Git. The harness is named `bench` inside an
unrelated Git/development tree with an instrumented enclosing SDK trap.
These source selections are functional inputs, not a qualified public release.

HP status, compiler/JVM processes and memory are retained before the outermost
high-priority **shared** job. The first lease waits behind existing work. These
are functional checks; the continuation preflight also sees unrelated compiler
activity, so there is no exclusive or timing claim.

- Four actual MSBuild property cases pass: archive default sibling SDK,
  explicit SDK with spaces/no separator, explicit SDK with separator, and
  development default. The archive never selects the enclosing trap.
- Both explicit cases retain `bin/` and `obj/` beneath the declared build root
  with the correct flat harness suffix; development retains its old suffix.
- An explicit missing SDK refuses. A separate original-policy fixture reproduces
  the old command-line no-separator refusal. No qualified archive input is
  changed for either control.
- The actual default managed solution freshly builds against the supplied
  open SDK, with build servers disabled and at most two MSBuild jobs. It requires
  no third-party engine input. Its fresh managed benchmark CLI returns success.
- The actual engine-free framework suite passes **94 tests**, with zero
  failures, errors or skipped/not-executed tests. The SDK engine suite and
  native binding are not part of this suite.
- All 751 harness and 661 SDK files retain bytes and Git modes; no source
  outputs appear. The original managed products retain their hashes during
  the separate framework continuation. Disposable materializations are removed.

## Retained original failure

The first controller passes discovery/refusals, the fresh solution build and
CLI execution, then incorrectly requires the word `usage` or `options` in the
help text. The actual output directly lists `--role` and `--scenario`. Its
original failed receipt/output stay unchanged. A separate read-only continuation
checks the real help options, runs the framework suite with separate outputs,
and verifies both original sources and original managed products. No production
source fix or recreated successful build is inferred from that correction.

[Source maps, actual commands, property values, build output, original failure
and TRX receipt](evidence/dotnet-sdk-discovery-20261003/).
Both full generations and source tarballs are retained under
`~/archive/libhft/dotnet-sdk-discovery-20261003-8a85a5bd8af6*`; the SDK tarball
stays outside repository and website evidence.

## Remaining work

The multi-client tests still reference `tools/provider-smoke`, which the public
SDK deliberately excludes because that workload belongs to the harness.
Its ownership/migration, test source discovery, actual native loading, managed
and native four-flow functional/physical checks, source/licence review and
whole-release qualification remain open. None is replaced by a skip or by
this managed build/framework receipt. Concurrent SDK source changes retain
their own pins and require their own builds before runtime admission.

## Concurrent integration

All qualified .NET discovery, project-reference, managed benchmark and framework
runtime/test inputs stay byte identical after rebase. Of the 751 old harness
inputs, 743 remain unchanged. Eight differences preserve the other session's
commercial-export policy, public guide/attribution corrections and comment-only
build-root annotations. The stricter public manifest also excludes commercial
driver selections; the original larger archive stays as an immutable private
functional generation, without release admission.

Of the 661 recorded SDK inputs, 627 remain unchanged. Thirty-four changes
include commercial-reference cleanup, journal ownership/replay fixes and the
managed 64-bit sequence codec. Their exact before/after hashes remain in
`readonly-framework/integration-inputs.json`. None acquires a new SDK build
from this older receipt. Shared build/layout helpers and all actually executed
benchmark/framework inputs remain unchanged.

Integrated readiness selects 744 files, with zero private/unresolved references
or dead links, and 83 textual escapes. Its new commercial-engine scrub rule
reports 44 findings in the remaining benchmark/report sources. These are a
new public-source migration worklist; the earlier clean scan is historical,
not a waiver of the new rule. No failed receipt or original map is rewritten.
