SharpProof.Gates is a deterministic console gate:
docker compose run --rm tooling corpus -Configuration Release
docker compose run --rm tooling performance
docker compose run --rm tooling gates -Configuration Release
Run sp corpus-update -Configuration Release from the persistent Dev
Container when intentionally updating checked-in corpus evidence. The update
then occurs in the container-owned Git workspace rather than a disposable task
checkout.
The checked-in snapshot covers 228 base methods:
- 200 distinct real-world methods from the MIT-licensed
aalhour/C-Sharp-Algorithmsrepository, pinned to a full commit and spread across 87 upstream source files; and - 28 focused synthetic semantic seeds: 18 effect-contract cases and 10
compiler-bound
Requirescall-site cases.
The 200-method release floor applies only to the open-source methods. Their
exact source, file/method hashes, path and line provenance, commit, and license
are checked in under Corpus/; generated transformations cannot satisfy that
floor. The runner adds EnforcePure to each selected declaration without
rewriting its body or dependencies and analyzes the pinned upstream project as
one compilation.
Every synthetic seed is rendered in ten source forms, for 280 independently compiled metamorphic cases:
- baseline;
- method, class, parameter, and helper rename;
- escaped C# identifiers;
- comment and whitespace trivia;
- redundant parentheses;
- a local temporary;
- an
if (true)wrapper; - a named argument replacing a positional argument;
- alpha-renamed contract formals;
- reordered independent statements.
Together these produce 480 recorded cases. The runner compares real
SharpProofAnalyzer output with
Corpus/expected.canonical.snapshot. Each entry records the analyzer's
internal semantic outcome independently of diagnostics, so diagnostic silence
can never be interpreted as proof. Canonical diagnostics include ID, effective
severity, normalized source location, and the invariant-culture message.
Diagnostics and cases are sorted deterministically. The gate also replays every
synthetic baseline against the same Roslyn compilation (the cache path) and
analyzes one synthetic case per variant concurrently. See
Corpus/README.md for licensing, instrumentation, and the reproducible import
workflow.
Every case also carries an explicit reviewed Supported or
IntentionallyUnsupported label that is stored independently from its
expected verdict and canonical snapshot. A supported case that produces either
Unknown or SilentUnknown fails with zero tolerance; supported cases must
produce an accountable Proven or Refuted semantic outcome. Unknown results
in the intentionally unsupported set are counted by deterministic diagnostic-ID
bucket (or silent-unclassified). Corpus/unknown-reason-ratchet.json floors
the supported total and supported OSS-method count and caps both the total
Unknown count and every known bucket. A new bucket, a reduced supported count,
or any Unknown count above its reviewed maximum fails, so rewriting the
canonical snapshot cannot silently expand the unsupported surface.
Any diagnostic mismatch fails except an expected Proven result becoming
Unknown when the exact case is listed in Corpus/proven-to-unknown.json
with a non-empty explanation. Unused, stale, duplicate, or unexplained
allowances fail. The checked-in allowlist is intentionally empty.
The performance gate reads all limits from
eng/acceptance/contract.json. It refuses to run if the release protocol
is not exactly five warmups, 30 samples, and 200 IDE edits.
The package smoke gate separately proves that SharpProofProfile=off
contributes no analyzer items and that advisory/strict profiles contribute both
the analyzer and contract generator. The performance path compares an
unannotated advisory package build with its compiler-only baseline. The
analyzer still runs in the advisory build, while the absence of selected
contracts keeps its output quiet. The call-bearing fixture exercises the
contract-free activation screen. Candidate contract syntax is found from the
shared API inventory, while external parameter/return contracts are screened
directly from immutable compiler-reference metadata. When neither exists, no
semantic session or per-method callback is created. Contract, specification,
and effect state remains unrealized unless a selected callable or possible
external callee precondition needs it.
The gate copies the repository global.json above both temporary projects,
requires the temporary root to resolve the same SDK as the repository, and
records the configured version, roll-forward policy, resolved version, and
global.json SHA-256 in its JSON evidence. Five warmup pairs and 30 measured
pairs alternate which build runs first. Enforcement uses each pair's advisory
to baseline ratio. Each adjacent baseline-first/advisory-first ratio pair is
reduced by geometric mean to cancel multiplicative order bias, and the enforced
median is the conventional median of those balanced ratios. The p95 remains
the conservative nearest-rank percentile of all raw paired ratios. No retries
or outlier removal occur. The estimator version, raw elapsed times, raw ratios,
balanced ratios, raw and order-specific medians, and execution order for all
measured samples remain in the JSON result.
Managed retained memory holds 40 distinct compilation graphs live after a full collection. Relative and absolute retained-memory limits are enforced independently.
An independent enabled-analyzer retention probe analyzes 40 distinct effects-enabled compilations. Each compilation is created in a non-inlined helper and only a weak reference escapes. After forced full collection, the gate requires zero compilation graphs to remain reachable and separately bounds the process-retained managed-memory increase.
The IDE gate applies and analyzes 200 single-token edits with effects enabled. It enforces p95 and maximum latency. A separate 30-sample worker-core gate measures cancel-to-exit latency, while a real launcher process test measures the forced-termination deadline independently. The unannotated advisory and IDE analyzer performance paths reference neither SMT nor Z3.
Worker/package tests also exercise protocol version 11 manifest equality, stable claim IDs, policy-controlled SP0047/SP0048 output, cache validation against the current manifest, fatal run handling, and compiler artifact schema version 18, including generated contracts, portable whole-body CFG/IR, schema-2 relational source/implementation-IL/audited-pack summaries, compiler diagnostics, exact lowered-callable hydration, and independent whole-body counterexample replay. Package tests also cover deterministic, policy-aware SARIF 2.1.0 projection of validated responses.
scripts/Test-SharpProofTrustedMutations.ps1 requires a clean tracked tree and
the explicit -ExpectedCommit SHA for the checkout,
archives the exact HEAD into an isolated workspace, proves each focused
baseline test passes, then applies one deterministic mutation at a time. Each
mutation must still compile and must be killed by its designated assertion; a
survivor, timeout, ambiguous target, or missing target fails the run. The
current set covers scalar semantics, lowering, SMT comparison, API-spec
resolution, postcondition replay, fail-closed effect-result assembly,
cache/manifest binding, protocol manifest/result equality, and launcher
containment.
Pass one or more exact names through -MutationName to qualify a focused
mutation while developing the gate. Omitting it remains the release behavior
and runs the complete set.
Nightly and release-qualification workflows run this gate and retain its
commit-bound JSON summary as evidence. Release qualification records
mutations=passed only after all mutations are killed; this is a release
input, not an optional test report.