This document defines the behavioral specification of the project.
It answers the question:
What should the system do?
While other governance documents serve different purposes:
- AGENTS.md -- development process rules
- ARCHITECTURE.md -- architectural principles
- DECISIONS.md -- historical design decisions
- SPECIFICATION.md -- expected behavior and contracts
When conflicts occur between implementation and documentation, the specification defined here takes precedence.
SPECIFICATION.md is the authoritative summary specification.
docs/specification.md is the detailed companion document for examples,
tables, edge cases, migration notes, and walkthroughs.
If SPECIFICATION.md and docs/specification.md disagree, this file
wins.
Specification changes must update both SPECIFICATION.md and
docs/specification.md unless the change is editorial only.
The specification describes externally observable behavior, including:
- public API behavior
- configuration semantics
- analyzer diagnostics and meanings
- command behavior (if applicable)
- configuration keys
- expected system reactions
Internal implementation details are not part of the specification.
Specifications describe observable behavior, not implementation details.
Avoid statements such as:
- internal algorithm choices
- specific class names
- internal data structures
Prefer describing:
- inputs
- outputs
- constraints
- guarantees
Behavior described here is considered contractual behavior.
Changes to specified behavior require:
- documentation update
- associated test updates
- justification recorded in
DECISIONS.md
For high-impact changes, update SPECIFICATION.md and DECISIONS.md in
the same change whenever practical.
Specification must clarify:
- expected input
- expected output
- allowed states
- invalid states
- error conditions
Ambiguous wording should be avoided.
Diagnostics define:
- ID
- Severity
- Trigger condition
- Expected fix or guidance
- Configurability via editorconfig
Detects contract names that do not use the required lower-kebab-case format.
Occurs when a contract name, implication endpoint name, or requirement-suppression contract-name argument is not lower-kebab-case.
Warning
.editorconfig key:
dotnet_diagnostic.DCA101.severity
Rename the offending contract name to lower-kebab-case. This diagnostic does not apply to target names or scope names.
Specification changes are considered high-impact changes.
Required steps:
- Update this file
- Update related tests
- Record reasoning in
DECISIONS.md - Mention change in PR description
An ADR may be drafted or even accepted earlier, but the specification
does not change until SPECIFICATION.md is updated.
Tests should validate the behavior described here.
If tests and specification disagree:
- check specification intent
- update tests if they are incorrect
- update specification if behavior legitimately changed
If a bug fix exposes previously unspecified behavior, decide and record the intended behavior in the specification before treating the fix as complete. Urgent temporary fixes must be followed by a tracked specification update.
AGENTS.md describes how changes are implemented.
SPECIFICATION.md defines what the system must do.
If uncertainty arises during implementation, consult this document first.
The analyzer resolves target and scope metadata using these rules:
- Type-level
ContractTargetandContractScopedeclarations take precedence over namespace-based inference for their respective metadata kinds. - Namespace-based inference is fallback-only and applies only when the type has no type-level explicit metadata of that kind.
- Assembly-level
ContractScopedeclarations always apply to types in the declaring assembly. - Type-level
ContractScopedeclarations add scopes for the type and do not remove assembly-level scopes. - Namespace-based scope inference may add fallback scope names alongside assembly-level scopes when the type has no type-level explicit scope declarations.
- Empty scope names on
ContractScope, including assembly-level declarations, reportDCA203. - In
external_dependency_policy = metadatamode, namespace-based inference remains limited to current-compilation types; referenced assemblies contribute explicit metadata and implication edges only. DCA200andDCA201validate declared targets and scopes against the current compilation only, even when external metadata matching is enabled.- Malformed implication definitions from referenced assemblies do not report diagnostics in the consuming compilation; those diagnostics remain owned by the compilation that declares the implication metadata.
Dependency extraction remains limited to strong type relationships.
The analyzer extracts dependencies from:
- constructor parameters
- non-constructor method parameters
- property types
- field types
- object creation
- static member usage
- base types
- implemented interfaces
The analyzer does not extract dependencies from weaker symbol
relationships such as attribute references, generic constraints,
typeof references, or return types.
Constructor parameters are always analyzed and are not controlled by
behavior_preset or any analyze_* option.
Requirement suppression remains exact-match only.
Each suppression matches one normalized dependency type or one normalized target/scope name together with one normalized contract name. Suppression does not broaden across other requirement kinds, wildcards, prefixes, or contract-only forms.
The EditorConfig policy surface remains limited to the current option set.
Supported policy categories are:
- dependency-source toggles
- reporting switches
- exclusions
behavior_presetnamespace_inference_max_segmentsexternal_dependency_policy
Any future expansion beyond these categories requires a separate design decision. These categories describe the current accepted product boundary, not an implied roadmap.
Namespace-based target and scope inference remains limited to the current fallback heuristics.
Supported inference remains:
- the final namespace segment by default
- the trailing two-segment fallback when
namespace_inference_max_segments = 2
Richer namespace-derived naming heuristics remain out of scope unless a separate design decision expands this boundary. That design space is not an accepted roadmap.
DependencyContractAnalyzer remains DI-agnostic.
The product does not analyze:
- DI registration analysis
- runtime dependency resolution
- Scrutor-style registration expansion
- factory registration behavior
- container-specific wiring rules
Contracts must be discoverable from the analyzed type surface and the documented metadata model rather than from container configuration.
Specification should evolve slowly.
Prefer:
- extending sections
- adding explicit clarifications
Avoid:
- rewriting existing meaning without explanation
- removing behavior without recording rationale in
DECISIONS.md