Skip to content

fix(standard): §4.3 — invert the LICENSE symlink direction — v1.38 - #17

Merged
UnbreakableMJ merged 1 commit into
mainfrom
standard/license-symlink-inverted
Jul 25, 2026
Merged

fix(standard): §4.3 — invert the LICENSE symlink direction — v1.38#17
UnbreakableMJ merged 1 commit into
mainfrom
standard/license-symlink-inverted

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

The problem with v1.36

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 string, not the license text.

Measured on the org right after v1.36 landed:

repo detected root LICENSE
anvil GPL-3.0 regular file
Standard NOASSERTION symlink
Construct NOASSERTION symlink

Both repos that adopted the rule lost their license badge.

The fix

Invert the direction:

cp <canonical license text> LICENSE
ln -s ../LICENSE LICENSES/GPL-3.0-or-later.txt
  • reuse reads the working tree through the filesystem, so it follows the link — reuse lint clean, verified in a fresh clone.
  • GitHub reads a real blob → license identified.
  • 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 (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 in LICENSES/ (§4.2 upstream, differently-licensed tooling class) stay regular files — only the primary license is linked.

§5.2 LICENSE row and the §16 checklist bullet updated to match.

Self-applies

This repo's LICENSE is now the canonical CC-BY-SA-4.0 text and LICENSES/CC-BY-SA-4.0.txt symlinks to it.

Verification

  • makeinfo --no-split → zero errors, zero warnings
  • reuse lint → compliant, 8/8 files
  • .md companion regenerated; CHANGELOG.md entry added

Detection itself can only be confirmed after merge (GitHub reads the default branch) — I'll re-check the API and report.

🤖 Generated with Claude Code

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>
@UnbreakableMJ
UnbreakableMJ merged commit 4df80fe into main Jul 25, 2026
1 check passed
@UnbreakableMJ
UnbreakableMJ deleted the standard/license-symlink-inverted branch July 25, 2026 23:53
UnbreakableMJ added a commit to Spacecraft-Software/Construct that referenced this pull request Jul 25, 2026
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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +602 to +603
primary license, and @code{LICENSES/<SPDX-id>.txt} for that same license
is a @strong{symbolic link} to it. Every project MUST ship both.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant