From 0ea4ede2348e6fb10fc3c2d9ff5d79885b1ec4ee Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 08:40:09 +0000 Subject: [PATCH 1/4] Update non-shipped test/benchmark packages and SourceLink to latest Bump test tooling (NUnit, NUnit3TestAdapter, Test.Sdk) and the Microsoft.Extensions.* packages used only by the test and benchmark projects to their latest stable versions, plus SourceLink in the library (build-only, PrivateAssets=All). The shipped library's Microsoft.Extensions.* dependencies stay pinned at 8.0.0 on purpose: for a multi-target library those versions are a minimum floor imposed on consumers, so keeping the LTS floor maximizes compatibility across netstandard2.0/net8.0/net10.0. https://claude.ai/code/session_01WVsnjDXjACmcLWJLGNMKVL --- .../PasswordGenerator.Benchmarks.csproj | 2 +- PasswordGenerator.Tests/PasswordGenerator.Tests.csproj | 10 +++++----- PasswordGenerator/PasswordGenerator.csproj | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PasswordGenerator.Benchmarks/PasswordGenerator.Benchmarks.csproj b/PasswordGenerator.Benchmarks/PasswordGenerator.Benchmarks.csproj index f445b44..f9c107c 100644 --- a/PasswordGenerator.Benchmarks/PasswordGenerator.Benchmarks.csproj +++ b/PasswordGenerator.Benchmarks/PasswordGenerator.Benchmarks.csproj @@ -10,7 +10,7 @@ - + diff --git a/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj b/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj index d2b0146..4c92b7e 100644 --- a/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj +++ b/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj @@ -9,11 +9,11 @@ - - - - - + + + + + diff --git a/PasswordGenerator/PasswordGenerator.csproj b/PasswordGenerator/PasswordGenerator.csproj index 933fdf5..2ff2a43 100644 --- a/PasswordGenerator/PasswordGenerator.csproj +++ b/PasswordGenerator/PasswordGenerator.csproj @@ -41,7 +41,7 @@ - + From 55ffccc600cc4d89695459689ab4d066fa68193c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 08:53:08 +0000 Subject: [PATCH 2/4] Correct SourceLink.GitHub to latest stable 10.0.300 11.0.100 is preview-only and does not exist as a stable release, so restore failed. Pin to the actual latest stable, 10.0.300. https://claude.ai/code/session_01WVsnjDXjACmcLWJLGNMKVL --- PasswordGenerator/PasswordGenerator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PasswordGenerator/PasswordGenerator.csproj b/PasswordGenerator/PasswordGenerator.csproj index 2ff2a43..9600988 100644 --- a/PasswordGenerator/PasswordGenerator.csproj +++ b/PasswordGenerator/PasswordGenerator.csproj @@ -41,7 +41,7 @@ - + From dba423d64e5362d8872ee16a5160f6da5b8b4ed2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 09:54:54 +0000 Subject: [PATCH 3/4] Drop netstandard2.0 from v3; make v3 docs the current docs Target net8.0;net10.0 only and remove the netstandard2.0 fallback in CryptoRandomSource (the #if rejection-sampling path, the RNG field, and IDisposable), which are no longer needed now that GetInt32 is available on every target. Restructure docs so v3 is the current state: flatten the former v3-target/* into docs/ (present tense, no "target/future" framing) and move the v2.1.0 snapshot, review/verification docs, and v3 planning docs into docs/archive/ with historical banners noting netstandard2.0 was dropped. Update Readme, CHANGELOG, migration guide, and cross-links. https://claude.ai/code/session_01WVsnjDXjACmcLWJLGNMKVL --- CHANGELOG.md | 10 ++- PasswordGenerator/CryptoRandomSource.cs | 48 +----------- PasswordGenerator/PasswordGenerator.csproj | 4 +- Readme.md | 12 ++- docs/README.md | 74 +++++++++---------- docs/{v3-target => }/api-surface.md | 14 ++-- docs/{v3-target => }/architecture.md | 36 ++++----- .../V3_REVIEW_AND_DOCUMENTATION.md | 4 + docs/{ => archive}/V3_VERIFICATION.md | 5 ++ docs/{v3-target => archive}/before-after.md | 4 + .../current-state/api-surface.md | 4 +- .../current-state/architecture.md | 2 +- .../current-state/generation-flow.md | 4 +- .../implementation-plan.md | 10 ++- docs/{v3-target => archive}/roadmap.md | 8 +- docs/{v3-target => }/configuration-and-di.md | 8 +- docs/{v3-target => }/generation-flow.md | 27 ++++--- docs/{v3-target => }/migration-v2-to-v3.md | 3 + docs/v3-local-nuget-test.md | 6 +- 19 files changed, 133 insertions(+), 150 deletions(-) rename docs/{v3-target => }/api-surface.md (85%) rename docs/{v3-target => }/architecture.md (73%) rename docs/{ => archive}/V3_REVIEW_AND_DOCUMENTATION.md (98%) rename docs/{ => archive}/V3_VERIFICATION.md (97%) rename docs/{v3-target => archive}/before-after.md (93%) rename docs/{ => archive}/current-state/api-surface.md (94%) rename docs/{ => archive}/current-state/architecture.md (97%) rename docs/{ => archive}/current-state/generation-flow.md (95%) rename docs/{v3-target => archive}/implementation-plan.md (97%) rename docs/{v3-target => archive}/roadmap.md (87%) rename docs/{v3-target => }/configuration-and-di.md (90%) rename docs/{v3-target => }/generation-flow.md (75%) rename docs/{v3-target => }/migration-v2-to-v3.md (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b126ea..0181e40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,17 @@ All notable changes to this project are documented here. This project adheres to ## 3.0.0 A major release focused on cryptographic correctness, a modern API, and broader use cases. -See the [v2 → v3 migration guide](docs/v3-target/migration-v2-to-v3.md). +See the [v2 → v3 migration guide](docs/migration-v2-to-v3.md). ### Breaking changes - **Invalid settings now throw** `ArgumentException` from `Next()` instead of returning an error message as the "password". Use `TryNext(out var password)` for a non-throwing path. +- **Minimum runtime is now .NET 8.** The package targets `net8.0` and `net10.0`; `netstandard2.0` + has been dropped. Consumers on .NET Framework or other older runtimes should stay on the 2.x line. ### Security / correctness fixes - Cryptographically secure RNG (`CryptoRandomSource`) with **unbiased** integer sampling - (rejection sampling — removes modulo bias). + (via `RandomNumberGenerator.GetInt32` — removes modulo bias). - Fixed an off-by-one in length handling and removed the GUID-based shuffle in favour of a Fisher–Yates shuffle. - Disposed/owned RNG lifecycle; removed dead code and the static RNG. @@ -32,7 +34,7 @@ See the [v2 → v3 migration guide](docs/v3-target/migration-v2-to-v3.md). `PasswordOptions.DefaultBatchCount`. ### Packaging -- Multi-targets `netstandard2.0` and `net8.0`; nullable reference types enabled. +- Multi-targets `net8.0` and `net10.0`; nullable reference types enabled. - Single source of version truth in the csproj (removed the stale `.nuspec`). - `PackageIcon` + `PackageReadmeFile` (clears `NU5048`), SourceLink, deterministic build, and a `.snupkg` symbol package. @@ -44,4 +46,4 @@ See the [v2 → v3 migration guide](docs/v3-target/migration-v2-to-v3.md). ## 2.1.0 and earlier See the project history and the original review in -[`docs/V3_REVIEW_AND_DOCUMENTATION.md`](docs/V3_REVIEW_AND_DOCUMENTATION.md). +[`docs/archive/V3_REVIEW_AND_DOCUMENTATION.md`](docs/archive/V3_REVIEW_AND_DOCUMENTATION.md). diff --git a/PasswordGenerator/CryptoRandomSource.cs b/PasswordGenerator/CryptoRandomSource.cs index 7118b26..93a220e 100644 --- a/PasswordGenerator/CryptoRandomSource.cs +++ b/PasswordGenerator/CryptoRandomSource.cs @@ -4,58 +4,18 @@ namespace PasswordGenerator { /// - /// backed by a cryptographic RNG. - /// On modern targets it uses ; on - /// netstandard2.0 it uses rejection sampling so the result is uniform across the whole - /// range with no modulo bias and no off-by-one. + /// backed by a cryptographic RNG. Uses + /// , which samples uniformly across the whole + /// range with no modulo bias. /// - public sealed class CryptoRandomSource : IRandomSource, IDisposable + public sealed class CryptoRandomSource : IRandomSource { -#if !NET8_0_OR_GREATER - private readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); -#endif - public int NextInt(int maxExclusive) { if (maxExclusive <= 0) throw new ArgumentOutOfRangeException(nameof(maxExclusive), "maxExclusive must be positive."); -#if NET8_0_OR_GREATER return RandomNumberGenerator.GetInt32(maxExclusive); -#else - if (maxExclusive == 1) return 0; - - var range = (uint)maxExclusive; - - // Largest multiple of range that is <= 2^32. Values at or above this are rejected so the - // accepted region is a whole number of buckets, giving an unbiased result mod range. - const ulong fullSpace = 1UL << 32; - var limit = fullSpace - fullSpace % range; - - uint value; - do - { - value = NextUInt32(); - } while (value >= limit); - - return (int)(value % range); -#endif - } - -#if !NET8_0_OR_GREATER - private uint NextUInt32() - { - var buffer = new byte[4]; - _rng.GetBytes(buffer); - return BitConverter.ToUInt32(buffer, 0); - } -#endif - - public void Dispose() - { -#if !NET8_0_OR_GREATER - _rng.Dispose(); -#endif } } } diff --git a/PasswordGenerator/PasswordGenerator.csproj b/PasswordGenerator/PasswordGenerator.csproj index 9600988..ae8ce7a 100644 --- a/PasswordGenerator/PasswordGenerator.csproj +++ b/PasswordGenerator/PasswordGenerator.csproj @@ -1,7 +1,7 @@ - netstandard2.0;net8.0;net10.0 + net8.0;net10.0 enable latest @@ -20,7 +20,7 @@ MIT passwordgeneratorlogo.png README.md - Password,Passphrase,Generator,OWASP,NIST,Security,Random,Crypto,OTP,ApiKey,Entropy,dotnet,netstandard,DependencyInjection + Password,Passphrase,Generator,OWASP,NIST,Security,Random,Crypto,OTP,ApiKey,Entropy,dotnet,DependencyInjection 3.0.0 is a major release: cryptographically secure RNG with unbiased sampling, exception/TryNext error handling, async APIs, dependency-injection support, presets (OWASP/NIST/OTP/API key/passphrase), custom pools, exclude-ambiguous, per-class minimums and entropy estimation. See the migration guide for upgrading from 2.x. false diff --git a/Readme.md b/Readme.md index 9cbd20d..e3fa558 100644 --- a/Readme.md +++ b/Readme.md @@ -14,12 +14,10 @@ Install via NuGet: ``` Install-Package PasswordGenerator ``` [Or click here to go to the package landing page](https://www.nuget.org/packages/PasswordGenerator) -It targets `netstandard2.0` and `net8.0`, so it runs on .NET Framework, .NET Core and modern .NET. -See the chart below: +It targets `net8.0` and `net10.0`, so it requires .NET 8 or later. If you need to run on .NET +Framework or other older runtimes, use the 2.x line (which targets `netstandard2.0`). -![Compatibility Chart](https://github.com/prjseal/PasswordGenerator/blob/master/compatibility.png "Compatibility Chart") - -> **Upgrading from 2.x?** See the [v2 → v3 migration guide](docs/v3-target/migration-v2-to-v3.md). +> **Upgrading from 2.x?** See the [v2 → v3 migration guide](docs/migration-v2-to-v3.md). > The v2 API still works; the one behavioural change is that invalid settings now **throw** (or use > `TryNext`) instead of returning an error string as the "password". @@ -82,7 +80,7 @@ var password = pwd.Next(); ## Presets Ready-made starting points; later fluent calls still override them. See the -[standards mapping](docs/v3-target/migration-v2-to-v3.md#6-standards-mapping-for-the-presets) for the +[standards mapping](docs/migration-v2-to-v3.md#6-standards-mapping-for-the-presets) for the OWASP/NIST rationale. ```csharp @@ -150,6 +148,6 @@ public class SignupService(IPasswordGenerator generator) ## Documentation -- [v2 → v3 migration guide](docs/v3-target/migration-v2-to-v3.md) +- [v2 → v3 migration guide](docs/migration-v2-to-v3.md) - [Changelog](CHANGELOG.md) - [Design & architecture docs](docs/README.md) diff --git a/docs/README.md b/docs/README.md index 04b8357..33d9e0a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,53 +1,53 @@ # PasswordGenerator — Documentation -This folder is the working reference for the package: the **shipped v3 design** and the historical -review of the v2.1.0 code it replaced. Diagrams are written in [Mermaid](https://mermaid.js.org/) and -render directly on GitHub. +This folder is the working reference for the package as it ships today (**v3**). Diagrams are written +in [Mermaid](https://mermaid.js.org/) and render directly on GitHub. ## How the docs fit together ```mermaid flowchart LR - subgraph Review["Review & verification"] - A[V3_REVIEW_AND_DOCUMENTATION.md
full review of v2.1.0] - B[V3_VERIFICATION.md
every issue re-checked vs current source] + subgraph Docs["the docs — current (v3)"] + D1[architecture.md] + D2[generation-flow.md] + D3[api-surface.md] + D4[configuration-and-di.md] + D5[migration-v2-to-v3.md] + D6[v3-local-nuget-test.md] end - subgraph Current["current-state/ — what we have"] - C1[architecture.md] - C2[generation-flow.md] - C3[api-surface.md] + subgraph Archive["archive/ — historical"] + A1[V3_REVIEW_AND_DOCUMENTATION.md] + A2[V3_VERIFICATION.md] + A3[current-state/ v2.1.0 snapshot] + A4[before-after.md] + A5[roadmap.md] + A6[implementation-plan.md] end - subgraph Target["v3-target/ — where we are going"] - T1[architecture.md] - T2[generation-flow.md] - T3[api-surface.md] - T4[configuration-and-di.md] - T5[before-after.md] - T6[roadmap.md] - T7[implementation-plan.md] - T8[migration-v2-to-v3.md] - end - A --> B --> Current - Current --> Target - T5 -. compares .-> Current - T6 --> T7 + Docs -. superseded by .-> Archive ``` ## Reading order -1. **`V3_REVIEW_AND_DOCUMENTATION.md`** — the original full review (API, bugs, packaging, gaps). -2. **`V3_VERIFICATION.md`** — each issue re-checked against the current `master` source, with verdicts. -3. **`current-state/`** — diagrammed snapshot of the v2.1.0 code (now **historical**; the issues it - documents are resolved in v3 — see the root [`CHANGELOG.md`](../CHANGELOG.md)). -4. **`v3-target/`** — the v3 design (now **shipped**), diagrammed, with a before/after, a roadmap, a - phased **`implementation-plan.md`**, and the user-facing **`migration-v2-to-v3.md`**. +1. **`architecture.md`** — type relationships, the random source, and the multi-targeting strategy. +2. **`generation-flow.md`** — how `Next()`/`Generate()` build a password, plus the async path. +3. **`api-surface.md`** — the public fluent surface, presets, and batch/async APIs. +4. **`configuration-and-di.md`** — `PasswordOptions`, settings resolution, and DI registration. +5. **`migration-v2-to-v3.md`** — the user-facing upgrade guide from 2.x. +6. **`v3-local-nuget-test.md`** — local `dotnet pack` / install verification procedure. ## Conventions -- **Current state** describes `master` @ v2.1.0, `netstandard2.0`. Code references use - `file:line` against that source. -- **v3 target** describes the design that shipped in v3.0.0 (`netstandard2.0;net8.0`, nullable - enabled). The `implementation-plan.md` records where the shipped code intentionally diverged from - the earlier proposal (e.g. the `IPasswordBuilder` split was deferred and sync methods were not - obsoleted). -- Each "target" doc ends with a **Why this is better** note tied back to a verified issue. +- These docs describe **v3.0.0** as shipped: targets `net8.0;net10.0`, nullable enabled. +- Each doc ends with a **Why this is better** note. + +## Archive + +`archive/` keeps the material that led to v3 but no longer describes the current state: + +- **`V3_REVIEW_AND_DOCUMENTATION.md`** / **`V3_VERIFICATION.md`** — the original review and + issue-by-issue verification of the v2.1.0 code. +- **`current-state/`** — the diagrammed snapshot of the v2.1.0 (`netstandard2.0`) code that v3 replaced. +- **`roadmap.md`** / **`implementation-plan.md`** / **`before-after.md`** — the v3 planning documents. + +These are point-in-time records; where they recommend or describe `netstandard2.0` support, note that +v3 dropped it (see the root [`CHANGELOG.md`](../CHANGELOG.md)). diff --git a/docs/v3-target/api-surface.md b/docs/api-surface.md similarity index 85% rename from docs/v3-target/api-surface.md rename to docs/api-surface.md index 19e18fe..61723f4 100644 --- a/docs/v3-target/api-surface.md +++ b/docs/api-surface.md @@ -1,11 +1,11 @@ -# v3 Target — Public API Surface +# Public API Surface Keeps the familiar fluent feel; adds safety, presets, batch, async, and custom pools. -> **As shipped:** the fluent builder is the existing `IPassword` (the full `IPasswordBuilder`/`Build()` -> split from the early proposal was deferred). `Password` implements both `IPassword` and the new -> generation contract `IPasswordGenerator`. Passphrases return an `IPasswordGenerator` -> (`PassphraseGenerator`). See `implementation-plan.md` for the deviations. +> The fluent builder is `IPassword` (there is no separate `IPasswordBuilder`/`Build()` split). +> `Password` implements both `IPassword` and the generation contract `IPasswordGenerator`. +> Passphrases return an `IPasswordGenerator` (`PassphraseGenerator`). See +> `archive/implementation-plan.md` for how the shipped surface diverged from the early proposal. ## API map @@ -69,7 +69,7 @@ fluent call still overrides them (resolution order is documented in `configurati ## Surfacing the broader purpose The library is **not password-only**. The same surface generates OTPs, environment names, API keys, -and other identifiers — so v3 deliberately keeps the per-class `Include*` methods and adds +and other identifiers — so the library deliberately keeps the per-class `Include*` methods and adds `WithCharacters`/`WithAllAscii` rather than forcing OWASP composition or a global 12-char minimum. ## Deprecation / migration shape @@ -89,6 +89,6 @@ flowchart TD > of async would be an anti-pattern and would spam every consumer with build warnings. Async exists > for ergonomics and cancellation only. -**Why this is better:** every verified gap in `../current-state/api-surface.md` is closed +**Why this is better:** every gap noted in the v2.1.0 review (`archive/current-state/api-surface.md`) is closed (`TryNext`/async/DI/presets/appSettings/custom pools), failures become explicit, and existing single `.Next()` users still work unchanged, giving a gentle upgrade path. diff --git a/docs/v3-target/architecture.md b/docs/architecture.md similarity index 73% rename from docs/v3-target/architecture.md rename to docs/architecture.md index 6345600..c594d81 100644 --- a/docs/v3-target/architecture.md +++ b/docs/architecture.md @@ -1,7 +1,6 @@ -# v3 Target — Architecture +# Architecture -> Multi-target `netstandard2.0;net8.0`, nullable enabled. Aligns with the adjusted plan in -> `../V3_VERIFICATION.md` §3. As shipped, the existing `IPassword` remains the fluent builder (no +> Multi-targets `net8.0;net10.0`, nullable enabled. `IPassword` is the fluent builder (no > separate `IPasswordBuilder`/`Build()`); `Password` implements both `IPassword` and the generation > contract `IPasswordGenerator`. @@ -51,7 +50,7 @@ classDiagram +int NextInt(int maxExclusive) } class CryptoRandomSource { - GetInt32 on net8, rejection sampling on netstandard2.0 + RandomNumberGenerator.GetInt32 } class IEntropyEstimator { <> @@ -68,13 +67,13 @@ classDiagram Password ..> PoolEntropyEstimator : EstimateEntropyBits ``` -Key shifts from today: -- **`IRandomSource` abstraction** wraps the CSPRNG (unbiased `RandomNumberGenerator.GetInt32` on - `net8.0`; rejection-sampling fallback on `netstandard2.0`). No `static`, disposable-aware, - injectable. Fixes verified §5.2/§5.3/§5.6 and lets the Guid `Shuffle` be deleted (§5.5). +Key points: +- **`IRandomSource` abstraction** wraps the CSPRNG (unbiased `RandomNumberGenerator.GetInt32`). No + `static`, injectable — a deterministic `IRandomSource` can be injected in unit tests — and the + Guid-based `Shuffle` is gone in favour of Fisher–Yates. - **`PasswordOptions`** is the DI config object, bindable from `IConfiguration`. - **Presets** are static factory methods on `Password` that pre-fill the fluent builder. -- The `[Obsolete]` v2 wrappers are **removed** in v3 (recommended in `../V3_VERIFICATION.md` §4). +- The `[Obsolete]` v2 wrappers from earlier proposals are not present. ## Target composition (with DI) @@ -99,19 +98,20 @@ registration is only responsible for wiring `IRandomSource` and default `Passwor ```mermaid flowchart LR - subgraph ns["netstandard2.0 (broad reach: .NET Framework, Umbraco)"] - a["manual rejection sampling"] - end - subgraph net8["net8.0 (modern)"] + subgraph net8["net8.0"] b["RandomNumberGenerator.GetInt32"] end - IRandomSource --> ns + subgraph net10["net10.0"] + c["RandomNumberGenerator.GetInt32"] + end IRandomSource --> net8 + IRandomSource --> net10 ``` -`#if` inside `CryptoRandomSource` selects the optimal API per target while keeping one public surface. +Both targets use the same built-in `RandomNumberGenerator.GetInt32`, so `CryptoRandomSource` needs no +`#if` and exposes one uniform public surface. (`netstandard2.0`, which required a manual +rejection-sampling fallback, was dropped in v3 — see the [changelog](../CHANGELOG.md).) **Why this is better:** removes the `static`/undisposed RNG, makes randomness unbiased and testable -(inject a deterministic `IRandomSource` in unit tests), keeps .NET Framework users supported, and -gives modern consumers the fast built-in APIs — addressing verified issues §5.2, §5.3, §5.5, §5.6 and -gaps §8 (async/DI/multi-target) at the architecture level. +(inject a deterministic `IRandomSource` in unit tests), and uses the fast, allocation-free built-in +crypto API on every supported runtime. diff --git a/docs/V3_REVIEW_AND_DOCUMENTATION.md b/docs/archive/V3_REVIEW_AND_DOCUMENTATION.md similarity index 98% rename from docs/V3_REVIEW_AND_DOCUMENTATION.md rename to docs/archive/V3_REVIEW_AND_DOCUMENTATION.md index 5a9987d..1c56c1c 100644 --- a/docs/V3_REVIEW_AND_DOCUMENTATION.md +++ b/docs/archive/V3_REVIEW_AND_DOCUMENTATION.md @@ -1,5 +1,9 @@ # PasswordGenerator — Full Package Documentation & v3 Review +> **Archived / historical.** Review of the v2.1.0 source written to plan v3, kept for reference. +> Where it recommends multi-targeting `netstandard2.0`, note that v3 dropped `netstandard2.0` and +> targets `net8.0;net10.0`. See the root [`CHANGELOG.md`](../../CHANGELOG.md). + > Purpose: a single, self-contained reference for the `PasswordGenerator` NuGet package as it > stands today (v2.1.0). Written so it can be pasted into a Claude chat to plan v3. It covers > what the package is, every public API, the internal implementation, confirmed bugs, design diff --git a/docs/V3_VERIFICATION.md b/docs/archive/V3_VERIFICATION.md similarity index 97% rename from docs/V3_VERIFICATION.md rename to docs/archive/V3_VERIFICATION.md index 1127482..35f8da2 100644 --- a/docs/V3_VERIFICATION.md +++ b/docs/archive/V3_VERIFICATION.md @@ -1,5 +1,10 @@ # PasswordGenerator v3 — Verification Report +> **Archived / historical (2026-05-24).** Point-in-time analysis of the v2.1.0 source, kept for +> reference. Its target-framework recommendation (multi-target `netstandard2.0;net8.0`) was **not** +> followed: v3 dropped `netstandard2.0` and targets `net8.0;net10.0`. See the root +> [`CHANGELOG.md`](../../CHANGELOG.md). + > Companion to `V3_REVIEW_AND_DOCUMENTATION.md` and the v3 Planning Addendum. > This document does the verification the addendum asked for: every item from the original > review's bug list (§5) and feature gaps (§8) was re-checked against the **current source**, diff --git a/docs/v3-target/before-after.md b/docs/archive/before-after.md similarity index 93% rename from docs/v3-target/before-after.md rename to docs/archive/before-after.md index acb93b9..e3ece99 100644 --- a/docs/v3-target/before-after.md +++ b/docs/archive/before-after.md @@ -1,5 +1,9 @@ # v3 Target — Before / After +> **Archived / historical.** A v3 planning document, kept for reference and superseded by the shipped +> v3 docs in [`../`](../README.md). The "after" column reflects the early plan; note that v3 ultimately +> **dropped `netstandard2.0`** (targets `net8.0;net10.0`). + Side-by-side of the things that change most, each tied to a verified issue. ## 1. Failure handling diff --git a/docs/current-state/api-surface.md b/docs/archive/current-state/api-surface.md similarity index 94% rename from docs/current-state/api-surface.md rename to docs/archive/current-state/api-surface.md index 7f0f6b5..84b1089 100644 --- a/docs/current-state/api-surface.md +++ b/docs/archive/current-state/api-surface.md @@ -1,7 +1,7 @@ # Current State — Public API Surface (v2.1.0) > **Historical.** This describes v2.1.0. The issues noted here are resolved in v3 — see the root -> [`CHANGELOG.md`](../../CHANGELOG.md) and the [migration guide](../v3-target/migration-v2-to-v3.md). +> [`CHANGELOG.md`](../../../CHANGELOG.md) and the [migration guide](../../migration-v2-to-v3.md). What a caller can do today, and how configuration is resolved. @@ -74,4 +74,4 @@ flowchart TD | Exclude-ambiguous, per-class minimums, entropy estimate | ✅ | | `netstandard2.0` + `net8.0` multi-target / nullable | ✅ (netstandard2.0 only) | -These gaps define the v3 surface in `../v3-target/api-surface.md`. +These gaps define the v3 surface in `../../api-surface.md`. diff --git a/docs/current-state/architecture.md b/docs/archive/current-state/architecture.md similarity index 97% rename from docs/current-state/architecture.md rename to docs/archive/current-state/architecture.md index b903995..3de1bcf 100644 --- a/docs/current-state/architecture.md +++ b/docs/archive/current-state/architecture.md @@ -1,7 +1,7 @@ # Current State — Architecture (v2.1.0) > **Historical.** This describes v2.1.0. The issues noted here are resolved in v3 — see the root -> [`CHANGELOG.md`](../../CHANGELOG.md) and the [migration guide](../v3-target/migration-v2-to-v3.md). +> [`CHANGELOG.md`](../../../CHANGELOG.md) and the [migration guide](../../migration-v2-to-v3.md). `master` @ v2.1.0 · target `netstandard2.0` · no third-party runtime dependencies. diff --git a/docs/current-state/generation-flow.md b/docs/archive/current-state/generation-flow.md similarity index 95% rename from docs/current-state/generation-flow.md rename to docs/archive/current-state/generation-flow.md index 7f2afa0..ac54286 100644 --- a/docs/current-state/generation-flow.md +++ b/docs/archive/current-state/generation-flow.md @@ -1,7 +1,7 @@ # Current State — Generation Flow (v2.1.0) > **Historical.** This describes v2.1.0. The issues noted here are resolved in v3 — see the root -> [`CHANGELOG.md`](../../CHANGELOG.md) and the [migration guide](../v3-target/migration-v2-to-v3.md). +> [`CHANGELOG.md`](../../../CHANGELOG.md) and the [migration guide](../../migration-v2-to-v3.md). How `Next()` produces a password today (`Password.cs:114-193`). @@ -91,4 +91,4 @@ stateDiagram-v2 ``` The whole correctness contract hinges on probabilistic retry + string sentinels — the core thing v3 -replaces (see `../v3-target/generation-flow.md`). +replaces (see `../../generation-flow.md`). diff --git a/docs/v3-target/implementation-plan.md b/docs/archive/implementation-plan.md similarity index 97% rename from docs/v3-target/implementation-plan.md rename to docs/archive/implementation-plan.md index 7c6f8e3..56d0299 100644 --- a/docs/v3-target/implementation-plan.md +++ b/docs/archive/implementation-plan.md @@ -1,8 +1,12 @@ # v3 Target — Implementation Plan (phased) -> Actionable, phase-by-phase plan to deliver the v3 design in `architecture.md`, -> `generation-flow.md`, `api-surface.md`, `configuration-and-di.md` and `before-after.md`. -> Sequencing follows `roadmap.md`; issue numbers (§5.x / §8) reference `../V3_VERIFICATION.md`. +> **Archived / historical.** This is a v3 planning document, kept for reference and superseded by the +> shipped v3 docs in [`../`](../README.md). Note that v3 ultimately **dropped `netstandard2.0`** +> (targets `net8.0;net10.0`), contrary to the multi-target plan described here. + +> Actionable, phase-by-phase plan to deliver the v3 design in `../architecture.md`, +> `../generation-flow.md`, `../api-surface.md`, `../configuration-and-di.md` and `before-after.md`. +> Sequencing follows `roadmap.md`; issue numbers (§5.x / §8) reference `V3_VERIFICATION.md`. ## Working principles diff --git a/docs/v3-target/roadmap.md b/docs/archive/roadmap.md similarity index 87% rename from docs/v3-target/roadmap.md rename to docs/archive/roadmap.md index 58fa049..5a95746 100644 --- a/docs/v3-target/roadmap.md +++ b/docs/archive/roadmap.md @@ -1,6 +1,10 @@ # v3 Target — Roadmap -Tiered delivery from the adjusted plan in `../V3_VERIFICATION.md` §3. Sequencing only — not committed +> **Archived / historical.** This is a v3 planning document, kept for reference. It is superseded by +> the shipped v3 docs in [`../`](../README.md). Note that v3 ultimately **dropped `netstandard2.0`** +> (targets `net8.0;net10.0`), contrary to the multi-target recommendation below. + +Tiered delivery from the adjusted plan in `V3_VERIFICATION.md` §3. Sequencing only — not committed dates. (Delivered in v3.0.0; see `implementation-plan.md` for where the shipped code diverged.) ## Tiers as phases @@ -76,7 +80,7 @@ flowchart TD class D1,D2,D3 q; ``` -See `../V3_VERIFICATION.md` §4 for the reasoning behind each recommendation. +See `V3_VERIFICATION.md` §4 for the reasoning behind each recommendation. ## Release-note discipline diff --git a/docs/v3-target/configuration-and-di.md b/docs/configuration-and-di.md similarity index 90% rename from docs/v3-target/configuration-and-di.md rename to docs/configuration-and-di.md index 2645040..31ed2fc 100644 --- a/docs/v3-target/configuration-and-di.md +++ b/docs/configuration-and-di.md @@ -1,4 +1,4 @@ -# v3 Target — Configuration & Dependency Injection +# Configuration & Dependency Injection ## Settings resolution order @@ -49,7 +49,7 @@ sequenceDiagram Svc->>Svc: generator.Generate(5) ``` -Two overloads (answering open question #3 in `../V3_VERIFICATION.md`): +Two overloads: ```csharp services.AddPasswordGenerator(options => { options.Length = 20; }); // code @@ -72,6 +72,6 @@ The fluent API must produce identical results whether the instance is constructe resolved from the container; DI only changes *how the dependencies are supplied*, not *what the builder does*. -**Why this is better:** teams can centralise password policy in `appSettings` (closing verified gap -§8) without forcing it on every call site, the RNG dependency is wired once, and unit tests can swap +**Why this is better:** teams can centralise password policy in `appSettings` +without forcing it on every call site, the RNG dependency is wired once, and unit tests can swap `IRandomSource` for a deterministic stub. diff --git a/docs/v3-target/generation-flow.md b/docs/generation-flow.md similarity index 75% rename from docs/v3-target/generation-flow.md rename to docs/generation-flow.md index 6bd1aed..90d9f96 100644 --- a/docs/v3-target/generation-flow.md +++ b/docs/generation-flow.md @@ -1,8 +1,8 @@ -# v3 Target — Generation Flow +# Generation Flow -Replaces probabilistic retry + string sentinels with **deterministic construction + exceptions**. +Uses **deterministic construction + exceptions** rather than probabilistic retry + string sentinels. -## Target `Next()` / `TryNext()` flow +## `Next()` / `TryNext()` flow ```mermaid flowchart TD @@ -20,14 +20,13 @@ flowchart TD class Throw bad; ``` -**What changed vs today (`../current-state/generation-flow.md`):** +**Design properties:** - No retry loop, no `MaximumAttempts` gamble, **no `"Try again"` string**. Required classes are - *guaranteed* by construction (fixes the probabilistic guarantee gap, §8). -- Invalid configuration **throws** (`Next()`) or returns `false` (`TryNext`) — never a fake password - (fixes §5.1 and §5.8). + *guaranteed* by construction. +- Invalid configuration **throws** (`Next()`) or returns `false` (`TryNext`) — never a fake password. - Selection uses unbiased `IRandomSource.NextInt(maxExclusive)` — no `% (len-1)` off-by-one, no - modulo bias (fixes §5.2, §5.3). -- Shuffle is a real crypto Fisher–Yates, replacing `orderby Guid.NewGuid()` (fixes/cleans §5.5). + modulo bias. +- Shuffle is a real crypto Fisher–Yates, not `orderby Guid.NewGuid()`. ## Deterministic class-seeding (the core idea) @@ -54,23 +53,23 @@ sequenceDiagram RNG-->>Gen: index end Gen-->>App: Task> - Note over App,Gen: sync Next()/Generate() still exist
and are fully supported (NOT obsoleted) + Note over App,Gen: sync Next()/Generate() also exist
and are fully supported (NOT obsoleted) ``` > Note: generation is CPU-bound, so async mainly helps large-batch ergonomics and cancellation, not -> raw throughput — the **BenchmarkDotNet** suite (plan §10/§12) exists to prove where async actually +> raw throughput — the **BenchmarkDotNet** suite exists to prove where async actually > pays off, with numbers published in every release note. -## Failure contract — before vs after +## Failure contract — v2.1.0 vs v3 ```mermaid stateDiagram-v2 - state "v2.1.0 (today)" as Old { + state "v2.1.0 (previous)" as Old { [*] --> RetryLoop RetryLoop --> OKo: valid RetryLoop --> StrFail: attempts exhausted → 'Try again' STRING } - state "v3 (target)" as New { + state "v3 (current)" as New { [*] --> Validate Validate --> BuildOK: build guarantees validity Validate --> Throw: invalid config → exception / false diff --git a/docs/v3-target/migration-v2-to-v3.md b/docs/migration-v2-to-v3.md similarity index 96% rename from docs/v3-target/migration-v2-to-v3.md rename to docs/migration-v2-to-v3.md index 67816c7..809e4b9 100644 --- a/docs/v3-target/migration-v2-to-v3.md +++ b/docs/migration-v2-to-v3.md @@ -8,6 +8,9 @@ about, plus the new capabilities you can adopt at your own pace. > **Length range:** valid password lengths are **4–256** characters (the old "8–128" Readme claim was > never the actual limit). +> **Runtime requirement:** v3 targets `net8.0` and `net10.0` and **drops `netstandard2.0`**. You need +> .NET 8 or later. Projects on .NET Framework or other older runtimes should stay on the 2.x line. + --- ## 1. The one breaking change: error strings → exceptions / `TryNext` diff --git a/docs/v3-local-nuget-test.md b/docs/v3-local-nuget-test.md index 3c70469..9f6b377 100644 --- a/docs/v3-local-nuget-test.md +++ b/docs/v3-local-nuget-test.md @@ -21,13 +21,13 @@ dotnet pack PasswordGenerator/PasswordGenerator.csproj -c Release -o /tmp/localn Output (trimmed): ``` -PasswordGenerator -> .../bin/Release/netstandard2.0/PasswordGenerator.dll PasswordGenerator -> .../bin/Release/net8.0/PasswordGenerator.dll +PasswordGenerator -> .../bin/Release/net10.0/PasswordGenerator.dll Successfully created package '/tmp/localnuget/PasswordGenerator.3.0.0.nupkg'. Successfully created package '/tmp/localnuget/PasswordGenerator.3.0.0.snupkg'. ``` -The package multi-targets `netstandard2.0` and `net8.0`, and a `.snupkg` symbol package is +The package multi-targets `net8.0` and `net10.0`, and a `.snupkg` symbol package is produced alongside it. **Expected** — this matches the packaging notes in `CHANGELOG.md`. > The only build warnings were `SourceLink` notices that the source-control information is @@ -375,7 +375,7 @@ passwords matching `DefaultBatchCount`. | # | Scenario | Result | Expected? | |---|----------|--------|-----------| -| – | `dotnet pack` (netstandard2.0 + net8.0, .snupkg) | Built | Yes | +| – | `dotnet pack` (net8.0 + net10.0, .snupkg) | Built | Yes | | – | Register local feed + install package | Installed, framework-compatible | Yes | | 1 | Basic default | length 16, all classes | Yes | | 2 | Explicit length 32 | length 32 | Yes | From d6d11714238fb89be74e30be630740f35d2cee60 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 10:09:35 +0000 Subject: [PATCH 4/4] Run tests against both net8.0 and net10.0 Multi-target the test project so the suite exercises the library on both shipped target frameworks rather than net8.0 only. https://claude.ai/code/session_01WVsnjDXjACmcLWJLGNMKVL --- PasswordGenerator.Tests/PasswordGenerator.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj b/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj index 4c92b7e..40a0cae 100644 --- a/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj +++ b/PasswordGenerator.Tests/PasswordGenerator.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0;net10.0 enable latest