Add a Negative Consumer Fixture
Make a compile-time boundary failure specific, reproducible, and impossible to pass for an unrelated reason.
What a negative fixture proves
A negative consumer fixture proves that deliberately invalid public-consumer code is rejected for the intended reason. It is appropriate for private seams, deleted operations, template requirements, forbidden conversions, or a header that must not enter a component’s public include closure.
An unrelated broken include can make every forbidden line appear protected. Sharp Runtime compiles an all-sites-off baseline and then enables one numbered site at a time, checking that diagnostics point into that site and contain a declared fragment.
Create the fixture
// NEGATIVE-FIXTURE: component=Collections.Core
#include "System/Collections/Generic/List.hpp"
#ifndef SHARP_RUNTIME_NEGATIVE_SITE
#define SHARP_RUNTIME_NEGATIVE_SITE 0
#endif
int main() {
System::Collections::Generic::List<int> values;
#if SHARP_RUNTIME_NEGATIVE_SITE == 1
// NEGATIVE(copy-from-const-view): expected diagnostic fragment
// | second accepted compiler diagnostic fragment
deliberately_invalid_expression(values);
#else
values.Add(1); // migrated/valid spelling keeps baseline compilable
#endif
return 0;
}
This is a scaffold, not a ready repository fixture: replace both the marker id and diagnostic fragments with the actual compiler output for the contract under test. Site numbers must be contiguous from 1, marker ids unique, and every enabled site must add—not remove—code relative to the clean baseline.
Select the real owning component
The NEGATIVE-FIXTURE directive names a physical component registered in CMake. The checker derives that target’s public include directories, definitions, language features, options, and public dependency closure. It intentionally does not expose private dependencies, which is often exactly the boundary being tested.
Write stable diagnostic expectations
Use one or more short semantic fragments from diagnostics, not a complete compiler paragraph with paths, line numbers, template backtraces, or toolchain-specific punctuation. The checker accepts a site only when at least one declared fragment appears and fixture-attributed diagnostics stay inside the enabled region.
| Fragile expectation | Better expectation |
|---|---|
| Complete GCC message with absolute paths | use of deleted function |
| Exact template instantiation stack | constraints not satisfied |
| Only “compilation failed” | A fragment identifying the protected contract |
Run one fixture with one compiler job
SHARP_RUNTIME_BUILD_JOBS=1 \
python3 scripts/check_negative_consumer_fixtures.py \
--root /path/to/pinned/sharp-runtime \
--fixture 'collections_mutation_version_negative.cpp' \
--jobs 1 \
--no-ccache \
--verbose
The checker permits one or two jobs; explicit --jobs 1 is the conservative choice on a memory-constrained host. Use --list first to inspect discovered fixtures and site identifiers without compiling them.
Interpret the outcomes
- Baseline fails: repair the fixture scaffolding or public include closure before trusting site results.
- Site compiles: the formerly forbidden expression is now legal; decide whether that is an intended API change.
- Site fails outside its region: the failure does not prove the intended contract.
- Expected fragment absent: review whether the compiler found a different, possibly earlier error.
- Unknown component: correct ownership rather than supplying ad hoc include paths.
Keep a positive migration path
The all-sites-off branch should show the supported replacement when one exists. A private test seam may have no consumer migration; say so in the file and point users to the public observable behavior they can test instead. Avoid documenting private implementation names as if consumers may depend on them.
Complete boundary validation
Run the fixture checker alongside the repository’s module-boundary validator and ordinary positive consumer fixtures. The three answer different questions:
- Can a valid consumer build and link?
- Does a forbidden expression remain rejected for the intended reason?
- Does the declared component graph expose exactly the intended headers and links?
Record compiler identity and selected source SHA with results. A negative diagnostic validated on GCC is not automatically a current Clang or MSVC evidence claim.