Override values are normalized to canonical SPDX (apache reads Apache-2.0), and a value that isn't a recognized SPDX expression is rejected at config load instead of silently classifying as unknown
refresh reports network and parse failures as a clean error instead of a traceback
report --output reports a failed file write as a clean error instead of a traceback
The project-name lookup tolerates a malformed pyproject.toml instead of raising
License classifications now apply to components of an expression containing a license outside the OSADL data (classifying CNRI-Python in Apache-2.0 AND CNRI-Python was ignored and warned as a typo)
Deprecated SPDX ids inside compound expressions now map to their modern forms (GPL-2.0+ AND MIT reads GPL-2.0-or-later AND MIT)
The Markdown report's Licenses Requiring Review section shows the SPDX expression for an unclassified license instead of "not detected"
A denied base license now also blocks its WITH exception forms (denying GPL-2.0-only catches GPL-2.0-only WITH Classpath-exception-2.0)
Compatibility analysis resolves OR expressions to the same branch as classification when a component is deemed by license-classifications, so conflicts on the chosen branch are no longer hidden
A license-classifications key written as a full compound expression now drops its components from compatibility analysis, matching component keys
A license string that isn't parseable no longer triggers a false denied-license violation when a denylist is configured; it is matched whole against the lists instead
A direct dependency that another direct dependency also requires is reported as direct instead of transitive
License strings are validated against the full SPDX license list: any valid SPDX expression is preserved instead of collapsing to UNKNOWN, is checked against allowed/denied lists, and displays in canonical form
WITH expressions survive normalization; a X WITH Y clause classifies as a single component keyed by its full text
The action item for a license without classification data now suggests license-classifications instead of calling the license unrecognized
check, recommend, and report messages say "unclassified" rather than "undetected" or "unrecognized", and the withheld-recommendation explanation no longer claims a classified license has no SPDX id
License overrides keyed by a PyPI-style name with hyphens or dots now apply
Dependencies declared in metadata but absent from the audited environment are no longer reported as phantom unknown packages
Packages installed as .egg-info (legacy setup.py installs), and dist-info directories whose name part contains hyphens, are now detected
check now reports the package and license that fall outside allowed-licenses
Ignore reasons containing | or a newline no longer break the Markdown Ignored Packages table
A malformed pyproject.toml now reports a clear error instead of a traceback
refresh writes cache files atomically so an interrupted download can't leave a half-written file behind
Report summaries count each package once: ignored packages are no longer also tallied as copyleft or unknown, and proprietary packages have their own count
The Markdown report omits the policy line when no policy was evaluated instead of showing a misleading FAILED
Source paths containing square brackets now render correctly in terminal output
JSON reports written with --output end with a trailing newline
Unrecognized licenses now show their actual declared identifier instead of UNKNOWN, distinguish undetected from unrecognized, and include their license text in Markdown reports for review
License classification via [tool.license-audit.license-classifications]: deem a license a category and have it apply to every package that uses it, including individual components of AND/OR expressions
Improved terminal rendering for recommend, check, and report commands with clearer formatting and shared layout helpers
Streamlined README and user guide, including an expanded CI integration guide
Internal refactor of the analyzer, policy engine, classifier, data store, SPDX normalizer, recommender, sources, and environment provisioning into class-based implementations (no change to CLI behavior or output contracts)