Migrate the licensing engine to Nordstein.Core (closes #539) - #542
Merged
Conversation
Move the licensing engine to Nordstein.Core.Licensing (submodule bump) and turn Proxytrace.Licensing into the product policy plus a thin enum-typed facade: the LicenseFeature/LicenseLimit/LicenseTier enums, LicensePolicy, the issuer/audience, and the LicensePublicKeys trust root stay here, while JWT validation, activation, the snapshot, and the server check with offline grace now come from the Core engine, parameterized via ILicenseTierPolicy (enum member names remain the JWT claim values — the wire format is unchanged, preserved by tests on both sides). No downstream call site changes: ILicenseService, ILicenseActivator, LicenseSnapshot, the enums, and the exceptions keep their exact public surface; adapters convert at the boundary and rethrow engine rejections as the product's InvalidLicenseException. Also carries the cross-linked docs framework (core/CLAUDE.md pointer, Core doc references) and updates docs/code-reuse.md + docs/licensing.md for the split. Closes #539 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nv67JW3ZyVvVWvaLYTcBZj
The Nordstein.Core PR branch merged main, which includes the dependabot group bump moving the Microsoft.* platform packages to 10.0.11 and NSubstitute to 6.2.0. Advancing the submodule made those versions flow into the product's source-mode graph, turning every remaining 10.0.10 / 6.0.0 pin into an NU1605 package downgrade (this is what failed CI on the Core PR's merge ref). Align all product pins with the same versions. Full backend suite green after the bump (2,780 passed, 6 pre-existing Docker-gated skips). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nv67JW3ZyVvVWvaLYTcBZj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Third extraction tranche: the licensing engine moves to
Nordstein.Core.Licensing(companion PR NordsteinSoftware/Nordstein.Core#4, submodule bumped to its head), andProxytrace.Licensingbecomes the product policy + thin façade.What stays in the product (unchanged public surface)
LicenseFeature/LicenseLimit/LicenseTierenums,LicensePolicy,TierDefinitionLicensePublicKeystrust root (embedded key + build-time override), issuer/audience constantsILicenseService,ILicenseActivator,LicenseSnapshot(withFree/Invalid/Enterprisefactories),LicenseSource/LicenseStatus, the exceptions,LicenseServiceExtensions.EnsureZero downstream call-site changes — the 60+ consuming files in Api/Application/Proxy are untouched; adapters (
LicenseServiceAdapter,LicenseActivatorAdapter,LicenseSnapshotMapper,ProxytraceLicenseTierPolicy) convert at the boundary and rethrow engine rejections as the product'sInvalidLicenseException.Wire-format contract
Enum member names double as the JWT
tier/feat/limclaim values and are preserved exactly; pinned by façade tests (feature/limit overlays, offline claim, kiosk override round-trip). One announced divergence from the old parsing: an undefined numeric claim value (e.g.tier: "50", previously leaking(LicenseTier)50) now falls back to Free; numeric aliases of defined members ("100"→ Enterprise) still resolve. Both pinned by tests.Docs
docs/code-reuse.md(Core table + roadmap: licensing done),docs/licensing.md(split note; directives unchanged), plus the cross-linked Core docs framework (core/CLAUDE.md,core/docs/*) referenced from the updated root CLAUDE.md.Verification
-p:UseLocalCore=falseagainst freshly packed.nupkgs)ServerUrloverride seam)No user-facing behavior change → no CHANGELOG entry.
Closes #539
🤖 Generated with Claude Code
https://claude.ai/code/session_01Nv67JW3ZyVvVWvaLYTcBZj