This document is the authoritative inventory of SharpProof 1.0's implemented
product surface. SEMANTICS.md remains normative: if a
semantic rule here conflicts with it, SEMANTICS.md wins.
SharpProof admits code through explicit gates and then analyzes it
conservatively. Admission does not guarantee a proof. Missing models,
unsupported expressions, approximate facts, and exhausted budgets remain
Unknown or silent abstentions.
| Surface | Runs where | Implemented behavior | Current boundary |
|---|---|---|---|
| Effect contracts | Analyzer with SharpProofFeatures=effects or all; independent replay in the opt-in container worker |
Runs a bounded acyclic scalar CFG pass, then computes conservative may summaries for reads, writes, allocation, capabilities, exceptions, termination, and completeness; checks [EnforcePure], [ZeroAllocations], [AllowedCapabilities], [DoesNotThrow], [AllowedExceptions], and [EffectContract]; emits one accountable worker claim per selected attribute; independently replays unconditional definite managed object/array allocation, exact framework explicit-throw, empty-lock, and exact-Monitor events |
Impossible refined branches are excluded. A loop disables scalar refinement but the conservative all-block scan can still prove effect absence. The worker authenticates the selected effect, capability, and exception constraints and derives each replayed witness independently. Fresh allocation remains observably pure; receiver-field, user-exception, conditional, and may-only candidates remain typed Unknown |
| Call-site preconditions | Analyzer with SharpProofFeatures=contracts or all |
Binds source Contract.Requires clauses and closed parameter attributes with compiler symbols for ordinary calls and object creation; follows executable local-function, lambda, and anonymous-method child CFGs exactly once; combines exact IR replay with compilation-scoped Boolean, nullness, interval, cardinality, explicitly trusted return-annotation, approved API-spec result, and effect facts at definite call sites |
Unknown or captured values, possible throws, cycles, quoted expression-tree lambdas, and exhausted analysis budgets do not become violations or proofs; unsupported explicitly selected methods report SP0047 |
| Postconditions | Optional container worker with SharpProofFeatures=contracts or all; strict enables the worker by default |
Manifests Contract.Ensures and return attributes, including directly owned local-function, lambda, anonymous-method, and top-level claims, then proves admitted bounded obligations over normal-return paths with Boolean logic, bounded integer comparisons, checked long arithmetic, and replay-gated counterexamples |
The additional callable forms are currently visible as UnsupportedCallable; effects excludes postcondition claims; this is bounded Ensures verification, not arbitrary deep, recursive, looping, heap, or sequence verification |
| Relational callees | Build-time compiler collector plus the container worker | Infers quantifier-free relations for direct acyclic static scalar source methods and exact implementation IL, or imports an explicitly enabled schema-1 audited pack; composes every relation into the caller's Z3 obligation with a sealed transitive evidence closure | Boolean/supported-integer inputs and results only; no virtual/instance dispatch, generics, ref, heap, loops, recursion, reference-assembly body authority, or arbitrary pack files; unsupported cases remain Unknown |
| Worker body execution | Compiler collector plus opt-in container worker | The compiler emits portable whole-body CFG/IR; the worker executes its bounded acyclic subset with locals, reassignment, branches, multiple returns, entry-state Old, supported expressions, and eligible resolved API specs |
Loops, stateful instructions outside the narrow admitted model, unresolved calls, unsupported mutation, and exceeded bounds abstain |
ContractFor validation |
Incremental generator loaded with any non-off profile |
Validates companion type and member identity, including receiver, overload, generic constraints, ref/scoped kinds, nullability, defaults, and return shape | It validates and binds existing source; it emits no generated source and does not make an unsupported contract provable |
| External calls | Analyzer, compiler collector, and worker | Analyzer/compiler stages resolve exact original symbols against ApiSpecTable; bounded postcondition calls can instead use exact implementation-IL relations or explicitly selected audited relational packs; the artifact binds each admitted call to canonical evidence that the worker revalidates |
The worker does not turn arbitrary trusted metadata contracts, reference assemblies, or consumer-supplied pack files into proof facts; missing, ambiguous, untrusted, incomplete, or target-framework-inapplicable models fail closed |
| SMT | Worker only | Encodes the admitted Boolean and bounded-integer obligations; creates Proven only after unsat-core hygiene and Refuted only after executable replay |
No Z3 or verifier payload is loaded into the IDE analyzer |
Effect exception contracts cover modeled synchronous managed exception flows. Ambient catastrophic runtime failures such as memory or stack exhaustion are outside that universe unless source or an exact boundary explicitly throws or declares them. An unmodeled ordinary synchronous exception remains incomplete; it is not silently excluded.
Not active as 1.0 preview product features:
- complexity classification or complexity diagnostics;
- regex-to-SMT translation;
- metadata IL effect inference;
- standalone runtime-hazard queries;
- nullable-contract diagnostics;
- general, recursive, virtual, or heap-aware source-callee verification beyond the direct acyclic scalar relational-summary boundary;
- a mutable heap or general points-to model;
- arbitrary loops, recursion, reference equality, sequence elements, or broad SMT theories.
The exact decision table is SharpProof.Analyzer/LanguageSubsetGate.cs. The
following matrix summarizes that checked table.
| Category | Admitted | Rejected |
|---|---|---|
| Callable kinds | Non-generic ordinary methods, instance and static constructors, property getters/setters, event add/remove accessors, and explicit interface implementations | Async methods, generic source methods, ref returns, ref parameters, declarations without an operation root, and unsupported method kinds |
| Types | Primitive and admitted named/reference types, strings, and arrays whose element type is admitted | Open type parameters, delegates, dynamic, pointers, function pointers, ref-like types, and admitted containers whose nested type is unsupported |
| Statements and flow | Blocks, locals, assignments, return/throw, if, for, while, do, constant-clause switch, try/catch/finally, using, lock, labels/branches, object and array initialization |
foreach, async/iterator flow, local functions, closures, event raising, queries, deconstruction, switch expressions, patterns, with, ranges, inline arrays, collection expressions, and spread |
| Expressions | Literals, locals/parameters/instance, fields/properties, array access, built-in unary/binary/conversion operations, conditional/coalesce, is type, typeof, nameof, ordinary interpolation, object/array creation, and direct calls that pass shape checks |
User-defined operators or conversions, delegates, dynamic operations, function pointers, anonymous objects, tuples, unsafe/address operations, custom interpolated-string handlers, implicit indexers, and future unknown Roslyn operation kinds |
| Calls | Direct non-delegate calls without ref arguments; closed constructed generic calls only when an exact ApiSpec resolves |
Local/delegate/function-pointer calls, ref arguments, open generic shapes, and closed generic calls with no exact resolved spec |
The frontend has a second, expression-level exactness classifier. For example, an operation kind can pass the analyzer gate while a lifted operator, narrowing conversion, unsupported member access, or unsupported invocation form still causes frontend abstention. The effect scanner can likewise return an incomplete summary for admitted syntax.
The table describes selected effect and verifier-body admission. The separate call-site precondition pass traverses Roslyn child CFGs for executable local functions, lambdas, and anonymous methods without admitting those callable forms to effect or postcondition verification. Nested outcomes remain attached to their owner and are not folded into the containing method. Expression-tree lambdas remain quoted, non-executing code for this pass.
The verifier body subset is narrower than the analyzer gate: compiler artifact lowering and the worker executor accept only acyclic, bounded instructions they can substitute and model exactly. Analyzer admission must not be read as worker support.
| Contract | Binding and use |
|---|---|
Contract.Requires(condition) |
A precondition. The analyzer uses exact replay or managed CFG facts at definite call sites. The worker can use a bound precondition as a justified entry assumption. |
Contract.Ensures(condition) |
A normal-return postcondition and worker proof goal. The analyzer does not prove postconditions. |
Contract.Assume(condition) |
Explicit user evidence. It remains visible as a user-assumed proof justification. |
Contract.Result<T>() |
Valid only inside Ensures; substitutes the callable's normal return value. A direct runtime call throws. |
Contract.Old(value) |
Valid only inside Ensures; substitutes the entry-state value. Nested or otherwise invalid uses fail closed. A direct runtime call throws. |
The compiler elides Requires, Ensures, and Assume calls unless
SHARPPROOF_CONTRACTS is defined. SharpProof binds their compiler operations;
it does not parse free-form contract strings. Enabled analysis rejects that
reserved symbol through both package configuration and the final compiler
compilation, including source-local directives and generated syntax trees.
The binder currently consumes these attributes on ordinary methods and constructors:
| Attribute placement | Bound clause | Current consumer |
|---|---|---|
[NotNull] on a parameter |
parameter != null precondition for reference, string, or sequence IR values |
Analyzer exact replay/managed facts and worker entry assumptions |
[NotNull] on a return value |
result != null postcondition |
Worker |
[Positive] on a parameter |
parameter > 0 integer precondition |
Analyzer exact replay/managed facts and worker entry assumptions |
[Positive] on a return value |
result > 0 integer postcondition |
Worker |
[InRange(min, max)] on a parameter |
Inclusive integer precondition min <= parameter && parameter <= max |
Analyzer exact replay/managed facts and worker entry assumptions |
[InRange(min, max)] on a return value |
Inclusive integer postcondition | Worker |
Invalid value types, invalid ranges, and malformed intrinsic use make contract
binding fail closed. The three closed attributes are declared only for
parameter and return-value targets. The inactive [Pure] attribute has been
removed; [EnforcePure] is the implemented effect contract.
[ContractFor(typeof(Target))] permits a static companion class to hold
compiler-bound clauses for a target type. Instance target members use an
explicit first receiver parameter. The generator validates exact symbol shape;
see Diagnostics.
Any valid direct target clause owns the complete clause source. When no valid
direct clause exists, a valid companion remains usable even if the target has
a misplaced clause. That misplaced clause is SP0024 and is omitted as a whole
compiler-elided call, including its argument evaluation.
The default table has eleven BCL rows. Every row resolves by documentation comment ID and original symbol identity across the supported reference surfaces. Effects, allocation, throws, nullness, and cardinality are separate facets; an exact fact in one facet does not make an unknown facet exact.
| Spec ID and row | Effects | Allocation | Throws | Result fact |
|---|---|---|---|---|
bcl.array.empty - System.Array.Empty<T>() |
Unknown because the generic cache can trigger type initialization | Unknown | Does not throw | Non-null, empty sequence |
bcl.exception.ctor - System.Exception..ctor() |
Writes the fresh receiver | None at the call boundary | Does not throw | None |
bcl.exception.ctor.string - System.Exception..ctor(string) |
Writes the fresh receiver | None at the call boundary | Does not throw | None |
bcl.invalid-operation-exception.ctor - System.InvalidOperationException..ctor() |
Writes the fresh receiver | None at the call boundary | Does not throw | None |
bcl.invalid-operation-exception.ctor.string - System.InvalidOperationException..ctor(string) |
Writes the fresh receiver | None at the call boundary | Does not throw | None |
bcl.object.ctor - System.Object..ctor() |
None at the call boundary | None at the call boundary | Does not throw | None |
bcl.string.length - System.String.Length getter |
Reads receiver state | None | Does not throw | Result equals receiver length |
bcl.string.concat.string-string - System.String.Concat(string, string) |
None | May allocate | Does not throw | Non-null string |
bcl.list.add - List<T>.Add(T) |
Writes receiver state | May allocate | Unknown | None |
bcl.math.abs.int32 - Math.Abs(int) |
None | None | May throw OverflowException |
Result is non-negative on normal return |
bcl.enumerable.empty - Enumerable.Empty<T>() |
Unknown because the generic cache can trigger type initialization | Unknown | Does not throw | Non-null, empty sequence |
These eleven rows are the complete supported built-in BCL surface. Anything
outside this table, or any row that does not resolve exactly for the current
target framework, fails closed. Object creation always analyzes a source
constructor or resolves an exact catalog row; exception constructors are not
implicitly trusted. In particular,
AggregateException(IEnumerable<Exception>) is unmodeled and produces an
incomplete effect result. A direct throw new refutation witness is available
only when the exact constructor has approved DoesNotThrow and Terminates
facets; either facet remaining unknown prevents a definite witness.
The worker projects validated call-result facets only into bounded proxies:
- null equality for exact string, reference, and array call results;
- direct
Lengthobservations for array results; - source-width and cardinality bounds represented as integer facts.
Array.Empty<T>() has one narrow normal-return path that consumes its adjacent
memory-only havoc and uses non-null/empty array facts without claiming the call
is pure. Enumerable.Empty<T>() remains unsupported for cardinality proof
because IEnumerable<T> is not array-backed sequence IR. There is no general
reference/sequence SMT sort, alias analysis, element model, or heap model.
The table also contains compiler-bound ghost rows for Contract.Requires,
Ensures, Assume, Result, and Old. Those rows describe compiler-elided
contract semantics and the throwing behavior of direct Result/Old
invocation; they are not BCL coverage.
Contract API symbols are accepted only from the SharpProof.Attributes
assembly identity matching the analyzer payload. Clause methods also require
the exact supported signatures and one real
Conditional("SHARPPROOF_CONTRACTS") attribute. Rejected source/project
shadows, identity mismatches, and malformed lookalikes remain visibly selected
but contribute no contract, effect, trust, suppression, or compiler-bound
ghost specification evidence.
Provenrequires a hygienic core containing only lowered facts, resolved specs, verified contracts, or explicit user assumptions.Refutedrequires independent replay. For a postcondition candidate, the proof kernel first checks exact backend-model closure and re-evaluates the lowered assumptions and goal. The worker then independently executes the compiler-produced whole-body program along the concrete CFG path and evaluates the original postcondition over the reconstructed post-state. Contract-only ordinaryvoidmethods replay as exact zero-step programs. Constructor postconditions areUnsupportedBodyuntil base-constructor and field-initializer semantics are lowered. An executed API-spec or relational-summary call becomesUnknownwithCounterexampleNotReplayable. Any other unsupported or inconsistent replay state is a fatalCounterexampleReplayFailed; one on an unselected path does not block the refutation. Result models expose only canonical user variables. For an effect candidate, compiler artifact schema 18 admits unconditional definite managed object/array allocation, exact framework explicit-throw, empty-lock, and exact-Monitorevents. The worker recomputes each event's constraint and operation identities, checks its source-tree identity/span and sealed witness, and independently derives its effects, capabilities, and exact exception hierarchy. It evaluates the authenticated allowed-effect, capability, and exception constraints before publishingRefuted. Fresh allocation remains compatible with observableEnforcePure.Unknowncovers unsupported, unresolved, approximate, method-time-limited, or resource-exhausted claim analysis. Unsupported unannotated analyzer callables are silent; unsupported selected callables produce SP0047.- Protocol version 11 binds a compiler-manifest artifact and separately records run status, callable coverage, and one outcome for each stable manifest claim ID. Exact manifest/result equality is mandatory.
- The compiler artifact carries
SharpProofFeaturesasWorkerFeatureSet.contractsexcludes effect-only annotations,effectsexcludes postcondition claims and contract assumptions, andallselects both. The compiler gives every selected effect-attribute occurrence one typed claim backed by sealed compiler evidence. Repeated attributes share the effective combined constraint/evidence while retaining distinct IDs and ordinals. - Effect evidence distinguishes complete and incomplete may-effect summaries,
trusted complete boundaries, definite direct violations, and unavailable
evidence. A disallowed effect in a may-effect summary is not a replayed
counterexample, so it remains
Unknown(EffectContractNotEstablished). Definite receiver-field, user-constructed exception, static-initialization-sensitive allocation, and other unsupported direct candidates are not published as refutations; they becomeUnknown(CounterexampleNotReplayable). Conditional, path-dependent, and may-only conflicts without definite replay evidence remainUnknown(EffectContractNotEstablished). Structural replay-artifact tamper is malformed compiler evidence and fails asCompilerManifestMismatch; a semantic disagreement during an otherwise valid replay becomes the fatalUnknown(CounterexampleReplayFailed). - Proven postconditions expose
ContradictoryPreconditionsorNoModeledNormalReturnvacuity evidence in JSON and SARIF. Proven claims are not disk-cache entries. - Caller cancellation is run status
Canceled, project timeout isTimedOut, and infrastructure/protocol/backend/replay failure isFailed. None is a successful claim outcome. - Cache schema version 13 stores only complete, postcondition-only, all-refuted
payloads. Cache reads are checked against the entire current manifest, then
every supported scalar model is reconstructed and whole-body replayed.
Proven claims, effect claims, unsupported models,
Unknown, cancellation, timeout, malformed result, infrastructure failure, and failed replay are not semantic cache entries.require-provendisables the local semantic cache. SharpProofVerifyPolicymaps incomplete selected analysis to informational, warning, or error SP0047 reporting.SharpProofAssumptionPolicymaps user or trusted evidence to SP0048. These policies do not make fatal runs successful.
During container verification, the production analyzer captures compiler artifact schema version 18 from the post-generator compilation. The artifact contains:
- the feature-selected, sealed claim manifest;
- one record per selected callable, containing either a typed lowering failure or portable whole-body CFG/IR with bound contract clauses, canonical variables, body-entry state, parameter mappings, and exact API-spec witness metadata;
- canonical source, exact implementation-IL, and explicitly enabled audited specification-pack summary calls, including complete transitive evidence closure under relational-summary schema version 2 and specification-pack schema version 1;
- compiler-neutral ordered replay evidence for admitted unconditional allocation, exact-framework-throw, and synchronization events, including authenticated selected-constraint and semantic-operation hashes plus source-tree identity and span;
- compiler error diagnostics with mapped locations;
- handwritten and generated tree hashes with language version, documentation mode, source kind, preprocessor symbols, and parse features;
- a bounded proof-relevant compilation-option set, assembly and target identity, and compiler identity/MVID provenance; and
- reference provenance: manifest and linked-module paths, image hashes, byte sizes, names, MVIDs, symbol identity, image kind, embed-interop flag, and aliases. A module is capped at 256 MiB, the complete closure at 1 GiB, and the closure at 4,096 modules.
The bounded compilation-option record covers output kind, explicit main-type selection, optimization, platform, nullable context, metadata import, checked overflow, unsafe mode, determinism, global usings, warning level, general and per-diagnostic reporting options, reference-supersession state, the supported Default/Desktop assembly-identity comparer profile, and the fixed evidence-only resolver policy. Realized compiler error diagnostics are sealed alongside those options so opaque syntax-tree diagnostic providers also affect the fingerprint.
Source text and reference image bytes are not embedded. The compiler must be
able to read each file-backed PortableExecutableReference to record its
provenance, but the worker never rereads it. Resolver-dependent #r/#load,
missing-assembly resolver mode, reference supersession, custom
assembly-identity comparers, and non-file or unreadable references fail
artifact collection as SP0049. AdditionalFiles are sealed by canonical path
and content hash without embedding their raw contents. Analyzer configuration
and reporting policies are represented by their observable effects on the
final compilation and effective SharpProof options.
The launcher binds the artifact path to its exact bytes with SHA-256. The
worker reads those bytes once, validates the closed portable graph, requires
the embedded maximum expression depth to match the request, and requires exact
manifest/lowered-callable equality before any cache lookup or backend creation.
It does not construct a Roslyn compilation, parse source, or read references.
Compiler build identities and reference metadata are provenance and cache
identity rather than runtime compatibility gates. Compiler errors become
CompilationFailure; malformed lowered evidence, claim/assumption drift, or an
option mismatch becomes CompilerManifestMismatch.
Generated claims and supported bodies are therefore visible and executable
from compiler-produced IR, and candidate refutations receive independent
whole-body replay. The three-package split is complete. Each package has a
matching portable-PDB .snupkg with SourceLink bound to the package repository
commit, and package builds run SDK package validation. The package workflow
publishes the six NuGet artifacts with a deterministic SHA-256 manifest, an
SPDX 2.3 package/component SBOM, and SLSA build-provenance and SBOM
attestations for canonical master builds. Pull requests do not receive OIDC
or attestation-write permission.
The remaining integration limits are owner configuration of protected tags and the private/public NuGet environments, the first publications, and broader host qualification. Deterministic SARIF 2.1.0 is available as an opt-in projection of the validated worker response. The workflow already promotes only the tested bytes after revalidating tag, version, master ancestry, predecessor-tag order, hashes, SBOM, repository identity, and package inventory. Before publication, each of the three target V3 main-package identities at the release version must be absent. Main and symbol packages are published separately in dependency order without duplicate skipping. The symbol service has no symmetric V3 download surface, so a symbol-package collision is detected by the push and fails the release. Any partial or conflicting publication requires a new version. These limits are not worker-side compilation reconstruction, postcondition-counterexample replay, the admitted allocation/capability/exception effect replay, package separation, SARIF, or release-artifact provenance work. Replay support for receiver-field, user-exception, conditional, and other effect events remains an explicit preview.2 blocker.
See Typed abstention reasons for the exact enums and Analysis limits for configured budgets.