fix(standard): §4.3 — invert the LICENSE symlink direction — v1.38 - #17
Conversation
v1.36 required the root LICENSE to be a symlink into LICENSES/, on the premise that GitHub follows symlinks for license detection. It does not: GitHub's detector reads git blobs, and a symlink's blob is the target path, not the license text. Measured after v1.36 landed: anvil GPL-3.0 LICENSE (regular file) Standard NOASSERTION LICENSE (symlink) Construct NOASSERTION LICENSE (symlink) Inverted: the root LICENSE is a regular file holding the verbatim primary license text; LICENSES/<SPDX-id>.txt for that license symlinks back to it (ln -s ../LICENSE LICENSES/CC-BY-SA-4.0.txt). reuse reads the working tree through the filesystem, follows the link, and lints clean; GitHub gets a real blob. The text still exists exactly once, so v1.36's single-source-of-truth goal is preserved and two independently maintained copies remain non-compliant. Also added: the root text MUST be a canonical, unmodified copy as published — reflowed or Markdown-formatted license texts defeat detection even when the wording is intact. Secondary licenses in LICENSES/ stay regular files; only the primary license is linked. Self-applies: this repo's LICENSE is now the canonical CC-BY-SA-4.0 text (choosealicense.com copy, replacing the reflowed REUSE-shipped variant) and LICENSES/CC-BY-SA-4.0.txt symlinks to it. Verified: makeinfo --no-split → zero errors/warnings; reuse lint → compliant 8/8 in a fresh clone; .md companion regenerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Back-sync of Spacecraft-Software/Standard#17, plus the self-apply. GitHub's license detector reads git blobs, and a symlink's blob is the target path rather than the license text — so the v1.36 layout left this repo reporting NOASSERTION. §4.3 is inverted: the root LICENSE is a regular file holding the verbatim primary license text, and LICENSES/<SPDX-id>.txt for that license symlinks back to it. reuse follows the link through the filesystem and lints clean; GitHub gets a real blob. The text still exists exactly once. Self-apply: LICENSE now carries the canonical FSF GPL-3.0 text (the same text sibling repos ship, which GitHub detects as GPL-3.0), replacing the reflowed REUSE-shipped variant; LICENSES/GPL-3.0-or-later.txt symlinks to it. Apache-2.0, GFDL-1.3-or-later, and MIT stay regular files — they are secondary licenses (§4.2), not the repo's primary. SKILL.md §4.3 body, §5.2 LICENSE row, §16 checklist bullet, masthead, and frontmatter description synced; references/CHANGELOG.md entry added; both bundles rebuilt in the same commit. Frontmatter description: 935 chars (under the 1000-char limit). reuse lint: compliant, 604/604 files. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1e44843acf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| primary license, and @code{LICENSES/<SPDX-id>.txt} for that same license | ||
| is a @strong{symbolic link} to it. Every project MUST ship both. |
There was a problem hiding this comment.
Allow a non-symlink fallback for LICENSES
When a repository is checked out with core.symlinks=false—a common native-Windows configuration—Git materializes this entry as a regular file containing only ../LICENSE. Consequently LICENSES/<SPDX-id>.txt no longer contains the required verbatim license text, and tools reading that path cannot follow it, while the new prohibition on duplicate copies leaves such working trees no compliant fallback. Permit a copied/generated license file on filesystems that cannot preserve symlinks, or avoid making the symlink mandatory.
Useful? React with 👍 / 👎.
The problem with v1.36
v1.36 required the root
LICENSEto be a symlink intoLICENSES/, on the premise that GitHub follows symlinks for license detection. It does not. GitHub's detector reads git blobs, and a symlink's blob is the target path string, not the license text.Measured on the org right after v1.36 landed:
anvilGPL-3.0StandardNOASSERTIONConstructNOASSERTIONBoth repos that adopted the rule lost their license badge.
The fix
Invert the direction:
reusereads the working tree through the filesystem, so it follows the link —reuse lintclean, verified in a fresh clone.Also added: the root text MUST be a canonical, unmodified copy as published (FSF text for the GPL family, Creative Commons text for CC-BY-SA-4.0, or the choosealicense.com copy). The REUSE-shipped texts are reflowed (
©for(C), unwrapped lines) and are a second plausible cause of the detection failure; either way, reformatted texts defeat detection. Secondary licenses inLICENSES/(§4.2 upstream, differently-licensed tooling class) stay regular files — only the primary license is linked.§5.2
LICENSErow and the §16 checklist bullet updated to match.Self-applies
This repo's
LICENSEis now the canonical CC-BY-SA-4.0 text andLICENSES/CC-BY-SA-4.0.txtsymlinks to it.Verification
makeinfo --no-split→ zero errors, zero warningsreuse lint→ compliant, 8/8 files.mdcompanion regenerated;CHANGELOG.mdentry addedDetection itself can only be confirmed after merge (GitHub reads the default branch) — I'll re-check the API and report.
🤖 Generated with Claude Code