Novolis Docs
novolis-governance / nuget-only-policy.md

NuGet-only dependency policy

dotnetgovernancenovolis

Indisputable rule: In committed source, any dependency on another Novolis repository is expressed only via PackageReference from GitHub Packages or nuget.org. Cross-repo ProjectReference in .csproj, sibling-checkout MSBuild properties (NovolisRenderingSrc, etc.), conditional dual reference blocks in projects, and local folder feeds in nuget.config are forbidden.

Exception (build-time only): When building the meta solution Novolis.Platform (or with -p:NovolisUseProjectReferences=true), MSBuild may substitute existing Novolis.* PackageReferences for sibling ProjectReferences. See platform-project-ref-mode.md. That does not change committed .csproj files.

Allowed committed alternative: LibraryReference. Governance expands it when `Novolis.Packaging.targets` is imported: sibling .csproj → ProjectReference, otherwise PackageReference at 2026.1.*. Do not commit cross-repo ProjectReference or dual Package/Project conditionals. Do not PackageReference Novolis.MSBuild.LibraryReference inside the forest; that package is for consumers outside the workspace.

Git submodules are allowed as source checkouts for novolis-lab experiments. A lab may record selected library repositories in .gitmodules and use the workspace ProjectReference-mode mechanism during local iteration. The submodule path must never appear as a committed ProjectReference, source path property, or local feed. CI checks out labs without initializing submodules and restores the committed PackageReference graph from GitHub Packages.

Cursor agents: Use GPR for publish/CI consumers — never artifacts/nuget-local, pack-local.ps1, or novolis-local sources. For local multi-repo iteration before publish, use Novolis.Platform.slnx (ProjectReference mode). See .cursor/rules/nuget-only-dependencies.mdc.

Allowed

ScopeReference style
Same repositoryProjectReference to projects under that repo's src/, codegen/, or tests/
Another Novolis repo (committed)LibraryReference (governance expands it; version float 2026.1.*)
Another Novolis repo (local meta build)LibraryReference resolves the sibling project with no mode flag. Remaining PackageReference items still substitute via platform-project-ref-mode.md
Third-partyPackageReference with a pinned version on nuget.org

Float Novolis packages only on the platform line (2026.1.*). Do not use build-line floats such as 2026.1.10.* or 2026.1.1.* — those resolve to the latest CI build number and fail restore when that build was never published (publish race / failed merge).

Never publish throwaway versions such as 2026.1.99 or 1.0.0 to GitHub Packages. Under a 2026.1.* float, 2026.1.99 sorts above real CI builds like 2026.1.10.36 and will silently win restore. Delete such versions from the org feed if they appear.

Direct Novolis PackageReference is reserved for reviewed exceptions:

  • Novolis.Raylib and Novolis.Raylib.Native, because their packages carry native runtime assets and transitive native build targets.
  • Novolis.Avalonia.Packaging.Inno, because its package supplies installer MSBuild targets.
  • The explicit external-host package allowlist in

scripts/verify-library-reference-usage.ps1, until those hosts opt into governance packaging imports.

verify-library-reference-usage.ps1 enforces this distinction for governed novolis-* repositories and the explicitly listed external hosts. A new exception must be added deliberately to that script and documented here.

GPR maintenance

pwsh -File D:\novolis\novolis-governance\scripts\gpr-health-check.ps1
pwsh -File D:\novolis\novolis-governance\scripts\gpr-health-check.ps1 -SkipRemote

Covers: junk versions, build-line floats, local folder feeds, stale package ids (Host.NAudio → Output.NAudio, …), committed cross-repo ProjectReference leaks, and ProjectReference-mode map health. Optional: -CheckBrokenDeps for latest-nuspec → missing dependency versions.

Full runbook: gpr-maintenance.md.

Forbidden

  • ProjectReference in a committed `.csproj` whose path crosses into a sibling novolis-* directory
  • MSBuild properties that auto-detect sibling clones (NovolisRenderingSrc, UseLocalNovolis, …)
  • ItemGroup Condition blocks in `.csproj` that switch between ProjectReference and PackageReference
  • Submodule or junction paths used for compile-time dependencies in apps or libraries
  • Local folder NuGet feeds (novolis-local, artifacts/nuget-local, …)

Validation (required before merge)

dotnet run --file d:\novolis\novolis-governance\scripts\verify-nuget-only.cs
dotnet run --file d:\novolis\novolis-governance\scripts\verify-library-reference-usage.cs
dotnet run --project d:\novolis\novolis-tools\src\Novolis.Solution.Tool\Novolis.Solution.Tool.csproj --no-launch-profile -- verify --root d:\novolis
dotnet run --file d:\novolis\novolis-governance\scripts\verify-banned-packages.cs

CI should run verify-nuget-only.cs and verify-library-reference-usage.cs on every library repo and on novolis-lab, novolis-utilities, and novolis-apps. Banned third-party stacks (Markdig, QuestPDF): markdown-and-pdf-policy.md.

Proving a change is done

A dependency cleanup is not complete until:

  1. verify-nuget-only.ps1 and verify-library-reference-usage.ps1 exit 0

across the org checkout.

  1. Affected libraries are published to GitHub Packages (merge to main → CI publish).
  2. Consumers restore and build using nuget.org + github only (dotnet restore, dotnet build).

Local meta-solution builds prove API shape early; they do not replace step 2–3 for ship.

See nuget-setup.md and platform-project-ref-mode.md.

Related