diff --git a/docs/WarningWavesProposal.md b/docs/WarningWavesProposal.md
new file mode 100644
index 00000000000..affce29ac41
--- /dev/null
+++ b/docs/WarningWavesProposal.md
@@ -0,0 +1,167 @@
+# Proposal: Warning Levels for Razor
+
+> **Status:** The infrastructure described here was implemented in [dotnet/razor#13016](https://github.com/dotnet/razor/pull/13016) and ships in Razor 18.7. The shipped feature is named **warning levels** (`RazorWarningLevel`) rather than warning waves. No new warnings have been classified at non-default levels yet — that work is layered on top of this infrastructure as warnings are introduced.
+
+## Summary
+
+This proposal introduces **warning levels** to the Razor compiler, a feature modeled after [C#'s warning waves](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/warning-waves). Warning levels allow users to adopt new .NET versions and Razor language features without being forced to immediately address new warnings that could break their build.
+
+## Motivation
+
+### The Problem
+
+Currently, upgrading to a newer version of .NET brings the corresponding Razor language version by default as the language version is tied to the TFM. When new warnings are introduced in a language version, users with `true` face a difficult choice:
+
+1. **Fix all new warnings immediately** - This can be time-consuming and block upgrades, especially for large codebases.
+2. **Downgrade the language version** - This allows the upgrade but prevents users from using new language features.
+3. **Disable specific warnings** - This requires identifying each new warning and suppressing them individually, which is error-prone and may hide legitimate issues.
+
+None of these options are ideal. Users should be able to upgrade their TFM and use new language features without being blocked by new warnings.
+
+### The Solution
+
+Warning levels decouple the introduction of new warnings from the language version. Users can:
+
+- Upgrade their TFM and get the new Razor language version
+- Set the warning level lower to suppress new warnings
+- Still use all new language features
+- Address new warnings at their own pace
+
+## Design
+
+### Warning Level Numbering
+
+Each warning is tagged with an integer **warning level**. The compiler reports a warning only when its level is less than or equal to the configured `RazorWarningLevel`.
+
+| Warning level | Description |
+|---------------|-------------------------------------------------------------------------------------------------|
+| `0` | **Always reported.** Level 0 warnings are not part of any wave and are emitted at every level. |
+| `N` (>= 1) | Reported only when `RazorWarningLevel` is `>= N`. Conventionally `N` matches the Razor language version major in which the warning was introduced (e.g. level `11` for warnings added in Razor 11). |
+
+**Default behaviour.** When `RazorWarningLevel` is not set, the compiler uses `RazorLanguageVersion.GetDefaultWarningLevel()`, which currently returns the language version's major number. So a project on Razor 11 implicitly gets `RazorWarningLevel = 11` and therefore sees every level <= 11.
+
+**Existing warnings are unaffected.** All warnings that exist today were authored without specifying a level, so they default to level `0` and continue to be reported regardless of the configured `RazorWarningLevel`. No project sees a behavior change until new warnings are added at higher levels.
+
+### Configuration
+
+Users configure the warning level via an MSBuild property that is forwarded to the source generator as an `AnalyzerConfigOptions` global option (`build_property.RazorWarningLevel`):
+
+```xml
+
+ net11.0
+
+
+
+
+ 10
+
+```
+
+The value must be empty or a non-negative integer. An empty value is treated as "use the default". Any other value (negative, non-numeric, etc.) produces diagnostic **`RZ3601`**: *Invalid value '{0}' for RazorWarningLevel. Must be empty or a non-negative integer.*
+
+### Behavior
+
+1. **Default behaviour.** With no configuration, the warning level equals the language version's major number, so users see every warning appropriate for their language version.
+
+2. **Lowered warning level.** When `RazorWarningLevel` is set lower than the default:
+ - Warnings whose level is greater than the configured value are suppressed.
+ - All language features remain available.
+ - Level-0 warnings continue to be reported.
+
+3. **Raised warning level.** Setting `RazorWarningLevel` higher than the language version's default is allowed; it opts in to warnings introduced in future language versions.
+
+4. **Invalid values.** Any value that is not empty and not a non-negative integer produces `RZ3601` and the compiler falls back to the default level.
+
+5. **Errors are not affected.** Warning levels only control warnings, not compiler errors.
+
+### Warning Classification
+
+Each Razor warning declares its level on `RazorDiagnosticDescriptor`. Diagnostics expose the level via `RazorDiagnostic.WarningLevel`, and warnings without an explicit level default to `0`:
+
+```csharp
+// Example: A warning introduced at level 11 (Razor 11.0).
+public static readonly RazorDiagnosticDescriptor Component_SomeNewWarning = new(
+ "RZ10001",
+ () => "Some new warning message",
+ RazorDiagnosticSeverity.Warning,
+ warningLevel: 11);
+```
+
+### Plumbing
+
+The warning level is threaded through the compiler:
+
+- `RazorConfiguration` carries `RazorWarningLevel` (default `0`).
+- `RazorProjectEngine` copies it into `RazorCodeGenerationOptions.RazorWarningLevel` (with `WithRazorWarningLevel(int)` to mutate).
+- `CodeRenderingContext.GetDiagnostics()` is the central filter: it keeps a diagnostic when `diagnostic.WarningLevel <= options.RazorWarningLevel`. Errors are always kept.
+- The source generator (`RazorSourceGenerator.RazorProviders`) reads `build_property.RazorWarningLevel` from `AnalyzerConfigOptions`, parses it, and emits `RZ3601` on invalid input.
+
+## Example Scenarios
+
+### Scenario 1: Smooth Upgrade Path
+
+A team with `TreatWarningsAsErrors` enabled wants to upgrade from .NET 10 to .NET 11:
+
+```xml
+
+
+ net10.0
+ true
+
+
+
+
+ net11.0
+ true
+ 10
+
+```
+
+The team can now:
+
+- Use .NET 11 runtime and libraries.
+- Use Razor 11.0 language features.
+- Address new warnings incrementally by raising or removing `RazorWarningLevel`.
+
+### Scenario 2: Gradual Warning Adoption
+
+A team wants to adopt warnings one level at a time:
+
+```xml
+
+10
+
+
+11
+
+
+12
+```
+
+## Implementation Status
+
+The infrastructure landed in [#13016](https://github.com/dotnet/razor/pull/13016):
+
+- ✅ `RazorWarningLevel` MSBuild property plumbed through the source generator (`build_property.RazorWarningLevel`).
+- ✅ `WarningLevel` added to `RazorDiagnosticDescriptor` / `RazorDiagnostic` (defaults to `0`).
+- ✅ `RazorConfiguration`, `RazorCodeGenerationOptions`, and `RazorProjectEngine` all carry the level.
+- ✅ `CodeRenderingContext.GetDiagnostics()` filters warnings by level.
+- ✅ `RZ3601` reported for invalid `RazorWarningLevel` values.
+- ✅ `RazorLanguageVersion.GetDefaultWarningLevel()` defines the default (currently `Major`).
+
+Still to do (follow-up work):
+
+- Author the first batch of non-zero-level warnings.
+- IDE/tooling integration so live diagnostics also respect the configured level.
+- User-facing documentation listing each warning and the level at which it was introduced.
+
+## Open Questions
+
+1. Should `#pragma warning` directives be honoured as an override (e.g. so a project on level 10 can still opt into a single level-11 warning)? Not implemented in #13016.
+2. Should we expose a `Latest` / `Preview` sentinel for early adopters, or is "set the integer high enough" sufficient?
+3. What is the minimum warning level we should accept? Today the parser only enforces `>= 0`.
+
+## References
+
+- [C# Warning Waves Documentation](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/warning-waves)
+- [dotnet/razor#13016 — Implementation PR](https://github.com/dotnet/razor/pull/13016)