From aef34823e6808141919bdb2b542856db62cf4e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Gro=C3=9F?= Date: Sat, 31 Oct 2026 20:10:42 +0100 Subject: [PATCH] docs: a package documents the third-party code it contains Decision 125: a package carries a THIRD-PARTY-NOTICES.txt only when it contains third-party code (a bundled assembly, copied source, a binary release), built from the shipping closure with the license texts. A package that bundles nothing, which is every package today, documents its own license, copyright and dependency list, and its dependencies' licenses are held to an allow-list by a conventions test (#181), not listed. No SBOM is shipped. CONTRIBUTING gains "Licenses and third-party code", AGENTS.md the rule. Refs #180 Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 3 + CONTRIBUTING.md | 15 +++++ ...uments-the-third-party-code-it-contains.md | 65 +++++++++++++++++++ design/adr/README.md | 1 + 4 files changed, 84 insertions(+) create mode 100644 design/adr/0125-a-package-documents-the-third-party-code-it-contains.md diff --git a/AGENTS.md b/AGENTS.md index ae2b6c1..708bb2f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -162,6 +162,9 @@ the whole page. A ranked miss proves nothing. introduce is CMTK1011. A new generated member joins that check, or a hand-written one is kept silently. - **Diagnostic ids (`CMTK`) are public contract.** Never renumber a shipped rule, and never ship a new rule at Error severity in a minor version. +- **A package contains this repository's code and nothing else.** Third-party code copied into `src/` or + bundled into a package brings a `THIRD-PARTY-NOTICES.txt` into that package, with the license texts; a + package reference must be under an allowed license ([decision 125](design/adr/0125-a-package-documents-the-third-party-code-it-contains.md)). - **A README's or a docs page's C# block is compiled code.** Change it and its region in `test/CodoMetis.TypeKit.Samples` together, or `ReadmeSampleTests` fails; the region's scaffolding (the types and variables it assumes) stays outside the markers. An output a block states in a comment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4cc4477..c59b920 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -167,6 +167,21 @@ the design records cite commits by hash. Found-By: CA ``` +## Licenses and third-party code + +Every package is MIT, set once in `Directory.Build.props`, and contains this repository's code and nothing +else. A package that bundles nothing needs no notices file: NuGet carries each dependency's license with its own +package ([decision 125](design/adr/0125-a-package-documents-the-third-party-code-it-contains.md)). + +Before a shipped package gets anything third-party: + +- **A package reference** has to be under a license the decision allows (MIT, Apache-2.0, BSD-2-Clause, + BSD-3-Clause, ISC), and a reference under any other says so in its pull request. +- **Code copied into `src/`, or an assembly bundled or merged into a package,** keeps its original header and + brings a `THIRD-PARTY-NOTICES.txt` into the package, with each entry's license text. Generate it from the + shipping projects alone, never by hand, and never with a test, tool or spike package in it. +- **Test, tool and spike packages** are never shipped, and need nothing. + ## Releasing The packages share one version and are released together, only through diff --git a/design/adr/0125-a-package-documents-the-third-party-code-it-contains.md b/design/adr/0125-a-package-documents-the-third-party-code-it-contains.md new file mode 100644 index 0000000..8200895 --- /dev/null +++ b/design/adr/0125-a-package-documents-the-third-party-code-it-contains.md @@ -0,0 +1,65 @@ +# 0125. A package documents the third-party code it contains, and its dependencies' licenses are checked, not listed + +Date: 2026-10-30 +Status: open + +Context: 2026-10-30, #180. A project outside this repository ships a `THIRD-PARTY-NOTICES.TXT` generated from +its dependencies, and the question was whether the public repositories should document third-party licenses +the same way. This record is an engineering rule for this repository, not legal advice. It rests on what the +MIT and Apache-2.0 texts ask for: the notice and, for Apache-2.0, the license and any `NOTICE` travel with +copies of the licensed work that are redistributed. + +## Decision + +**What a package contains decides what it documents.** + +1. **A package that contains only this repository's code carries no notices file.** Every package does today. + Its license is the `PackageLicenseExpression`, its copyright the `Copyright` property, and its dependencies + the nuspec's list, which NuGet restores with each dependency's own package and license. +2. **A package that contains third-party code carries a `THIRD-PARTY-NOTICES.txt` inside the artifact.** + Third-party code is an assembly bundled or merged into the package, source copied into `src/`, or a binary + or container release of an application. The file lists what the artifact contains and nothing else, so it is + built from the shipping projects' closure alone (no test, tool or spike package), holds the license text of + each entry rather than a link, and is regenerated in the release workflow, never by hand. Copied source also + keeps its original header. +3. **Dependencies' licenses are checked, not listed.** A conventions test holds every package a shipping + project resolves to an allow-list of SPDX ids, and fails a package with only a `licenseUrl` unless an + exceptions list names it with a reason (#181). The allow-list starts at MIT, Apache-2.0, BSD-2-Clause, + BSD-3-Clause and ISC; #181 measures what the shipping closure declares, and the list is that and no wider. +4. **No SBOM is shipped.** GitHub's dependency graph exports one (SPDX 2.3, `GET /repos/{owner}/{repo}/dependency-graph/sbom`), + which is an inventory. GitHub's documentation says it does not retrieve license information for + dependencies, so it is not the license record. +5. **Not adopted.** A notices file for a library that bundles nothing: it would list packages the artifact + does not contain, test packages among them, and say nothing the nuspec does not. REUSE headers on every file: + every file is under the one MIT license, so there is no per-file license to declare. + +The other public repositories take the same rule and write it down where they keep their contributor guide. + +## Evidence + +- **Package contents, 2026-10-30, 2.4.0.** `dotnet pack CodoMetis.TypeKit.slnx -c Release` gives seven `.nupkg`. + Each holds its nuspec, `README.md`, its own assembly and that assembly's XML documentation; the analyzers hold + `CodoMetis.TypeKit.Analyzers.dll` and `CodoMetis.TypeKit.Analyzers.CodeFixes.dll` under `analyzers/dotnet/cs`. + No third-party assembly is in any of them. +- **Dependencies.** `CodoMetis.TypeKit.Generators` depends on `Metalama.Framework` 2026.1.30 and + `CodoMetis.TypeKit`; `CodoMetis.TypeKit` on `CodoMetis.TypeKit.Analyzers`. Each nuspec has + `MIT` and `Copyright (c) 2026 CaffeinatedCoder`. +- **No copied code.** A search of `src/` for "adapted from", "ported from", "copied from", "derived from" and + copyright lines finds prose only. +- **The generated file that prompted this.** 102 entries (81 MIT, 16 Apache-2.0, 2 PostgreSQL, 1 BSD-3-Clause), + test and tooling packages (`xunit.v3`, `Moq`, `coverlet.MTP`, `Microsoft.NET.Test.Sdk`) among them, and no + license text in it, only each SPDX id and a link to licenses.nuget.org. For an application that ships its + dependencies, listing them is right. It would be wrong here on both counts: it would list what no package + of ours contains, and a link is not the text. +- **GitHub's SBOM** for this repository lists 187 packages, test and tooling packages included. + +## Consequences + +- No file is added to any package, and nothing new is maintained, until a package starts to contain third-party + code. Rule 2 then applies from that pull request on. +- Rule 2 has no guard yet. Nothing fails if a package starts to bundle an assembly; #181 records measuring a + pack-contents rule beside the allow-list. +- A new package reference whose license is not allowed fails the conventions tests until the list is changed on + purpose, in a pull request that says why. +- A README sentence that says the packages contain only TypeKit's code would be a promise, and needs a claim in + `test/oracles/claims.json` and the test that holds it. It is not written here. diff --git a/design/adr/README.md b/design/adr/README.md index e9f5359..b08389b 100644 --- a/design/adr/README.md +++ b/design/adr/README.md @@ -131,3 +131,4 @@ per area ([design](../plan.md)) link to the records they rest on. | [0122](0122-arithmetic-operators-are-opt-in-and-a-hand-written-one-is-a-seam.md) | A plain value object gets the arithmetic operators (`+`, `-`, `*`, `/`, `%`, unary `-` and `+`, and their `checked` forms) of the operator interfaces it declares, where the wrapped type implements the same interface with the value object replaced by itself; each calls the wrapped type's through `GeneratedArithmetic`, a constrained generic call with its context stated; never by default and never on a validated value object, which keeps CS0535; a hand-written operator for the same operands, or an explicit implementation of the interface, its own or a base record's, is a seam, kept with its `checked` form, so 2.3 code builds unchanged; refines decision 28 | 2026-10-30 | accepted; refined by [0123](0123-a-hand-written-operator-is-refused-in-a-query.md) and [0124](0124-an-operator-in-a-query-is-the-wrapped-type-s-arithmetic.md) | | [0123](0123-a-hand-written-operator-is-refused-in-a-query.md) | An arithmetic, bitwise or shift operator a value object declares by hand is refused in an EF Core query, naming the value object and `.Value`, by an interceptor and, for query filters, when the model is built; the generated ones carry `[TranslatedAsWrappedArithmetic]`, which is what tells them apart; a conversion operator is left to EF; refines decision 122 | 2026-10-30 | accepted | | [0124](0124-an-operator-in-a-query-is-the-wrapped-type-s-arithmetic.md) | In an EF Core query, every generated arithmetic operator is rewritten to the wrapped type's operator over `ProviderValue`, which translates only through TypeKit's converter, its value-object result `Materialize`d and re-typed, never cast; `byte`, `short` and `char` operators are refused; refines decision 122, on decision 123's mark | 2026-10-30 | accepted | +| [0125](0125-a-package-documents-the-third-party-code-it-contains.md) | A package carries a `THIRD-PARTY-NOTICES.txt` only when it contains third-party code (a bundled assembly, copied source, a binary release), built from the shipping closure with the license texts; a package that bundles nothing documents its own license, copyright and dependency list, and its dependencies' licenses are held to an allow-list by a conventions test, not listed (#181); no SBOM is shipped, since GitHub's export is an inventory without license data | 2026-10-30 | open |