Skip to content

feat(ci): export SPDX symbol table and reject dangling operators (#627 follow-up) - #630

Merged
enricopiovesan merged 1 commit into
mainfrom
claude/issue-627-spdx-exception-parity
Oct 2, 2026
Merged

enricopiovesan merged 1 commit into
mainfrom
claude/issue-627-spdx-exception-parity

Conversation

@enricopiovesan

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #627 / #629, decision-log entry 130. I ran a differential fuzz of traverse-cli's port of the ai rules (traverse-framework/traverse#1597) against this gate:

  • Structural ai rules: agreed on all 4,000 mutated ai objects.
  • SPDX: disagreed on 457 of 7,082 random expressions.

The SPDX disagreements have one main cause: license-expression 30.4.4 bundles ScanCode's licence database, and the Rust side has a different one.

  • ScanCode classifies 243 names as exceptions, valid only after WITH. Examples: eCos-2.0, MPL-2.0-no-copyleft-exception, GPL-3.0-with-GCC-exception, LicenseRef-scancode-*-exception.
  • Its licence list differs from the Rust spdx crate's.
  • It recognises multi-word aliases such as GPL 2.0.

Separately, it silently drops a trailing AND/OR, so MIT AND Apache-2.0 AND was accepted.

This PR exports the pinned symbol table so the CLI can resolve ids exactly as CI does, and fixes the trailing-operator bug here instead of having the CLI copy it.

Governing Spec

  • 001-registry-foundation
  • 002-capability-validation
  • 026-model-rights-compliance

Project Item

What Changed

  • spdx_symbol_table() writes scripts/ci/fixtures/spdx_symbols.json: 2,451 licence names and 243 exception names, keys and aliases. A test fails if the file is stale against the pinned license-expression.
  • validate_spdx_expression rejects a dangling trailing AND/OR/WITH with contract.invalid_licensing_spdx. No published contract is affected; I checked the whole tree before the change.
  • The corpus moves to 1.1.0 with 13 new SPDX fixtures:
    • dangling operators;
    • exception ids used as licences;
    • WITH followed by a ScanCode, deprecated or lowercase exception;
    • multi-word and short aliases;
    • LicenseRef case handling;
    • an id missing from the pinned database.
  • Docs: docs/model-rights.md, and decision-log entry 130.

Validation

  • test_ai_admission_corpus.py: 116 fixtures plus the symbol-table freshness test
  • test_capability_validation.py: 212 tests (with the connector fixture runner built, as in CI)
  • Whole-tree capability_validation.py passes
  • pre_pr_check.sh

🤖 Generated with Claude Code

…follow-up)

Differential fuzzing of traverse-cli's ai-rule port found SPDX divergence:
license-expression 30.4.4's ScanCode db classifies 243 names as exceptions,
its license list differs from the Rust spdx crate, it knows multi-word
aliases, and it silently drops a trailing AND/OR. Export the pinned symbol
table (with a staleness test), reject dangling operators, and add 13 corpus
fixtures (corpus 1.1.0). Decision-log entry 130.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enricopiovesan
enricopiovesan merged commit e9b8b10 into main Oct 2, 2026
11 checks passed
@enricopiovesan
enricopiovesan deleted the claude/issue-627-spdx-exception-parity branch October 2, 2026 19:53
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