Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
`<license type="expression">MIT</license>` and `<copyright>Copyright (c) 2026 CaffeinatedCoder</copyright>`.
- **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.
1 change: 1 addition & 0 deletions design/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Loading