fix(copyright): keep a trailing acronym-with-period holder (e.g. CERN.)#1322
Merged
Conversation
A single all-caps acronym carrying a sentence-final period (`CERN.`) lexes as a `Pn` token, unlike its period-less spelling `CERN`, which lexes as `Caps`. A bare `Caps` acronym reduces to a `NameCaps` node and is absorbed onto a year-only copyright via the `strong_first` path, but a bare trailing `Pn` matched no absorption branch, so the holder was dropped — leaving a holder-less `Copyright (c) <year>`. Isolated lines were rescued only by the line-anchored `extend_year_only_copyrights_with_trailing_text` repair (regex `^copyright`), which cannot fire when prose precedes the copyright. On flask `tests/test_cli.py` (`... Revised BSD License. Copyright © 2015 CERN.`) that produced `Copyright (c) 2015` with no holder. Absorb a lone trailing `Pn` leaf on the same line as a holder-less, year-bearing copyright clause, mirroring the existing `Caps`/`NameCaps` treatment so the two source-faithful spellings behave consistently. Scoped to a year-only clause so it cannot swallow ordinary prose; a genuine year-only notice still yields no holder. Adds detector regression tests covering the flask shape plus `Example Corp`, a diacritic holder (`Björn`), and a year-only negative guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
Greptile SummaryFixes copyright extraction for same-line, trailing acronym holders with sentence-final periods.
Confidence Score: 5/5The PR appears safe to merge with no actionable defects identified. The new absorption path is constrained to same-line Important Files Changed
Reviews (1): Last reviewed commit: "fix(copyright): keep a trailing acronym-..." | Re-trigger Greptile |
mstykow
added a commit
that referenced
this pull request
Jul 23, 2026
Rebased onto main (#1321 deps-as-components + #1322 copyright fix) and regenerated: express 1->45, ripgrep 11->114, flask 4->54 components, 0 dangling dependsOn refs. `generate-sbom-examples --check` passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com>
mstykow
added a commit
that referenced
this pull request
Jul 23, 2026
…kio) (#1318) * feat(xtask): add generate-sbom-examples and checked-in SBOM examples Add a durable `generate-sbom-examples` xtask that produces the SBOM examples under `examples/sbom/`. For each verified target it shallow- fetches the repo at a pinned commit through the shared repo cache, runs the current-build Provenant with `scan --license --package --copyright`, and writes SPDX tag-value plus CycloneDX JSON documents and a short provenance README. The embedded tool version is pinned to the workspace package version so committed output is deterministic. `--check` regenerates in place and diffs against the committed files after normalizing every per-run volatile field (SPDX `Created`, CycloneDX `serialNumber`/`metadata.timestamp`, the embedded tool version across SPDX/CycloneDX/READMEs, and any random package-UID suffix); tool versions are normalized so a routine release bump does not fail the check before regeneration. Wire the `--check` into CI alongside the other generated-artifact checks and fold regeneration into `release.sh` after the version bump so the examples refresh on each release. Exclude the generated files from prettier (matching the OpenAPI-doc precedent). Targets (ripgrep 15.2.0, express v5.2.1, flask 3.1.3) were verified against ScanCode with `compare-outputs`: no medium-or-major license, copyright, or package regressions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com> * chore(examples): regenerate SBOM examples with dependency components Rebased onto main (#1321 deps-as-components + #1322 copyright fix) and regenerated: express 1->45, ripgrep 11->114, flask 4->54 components, 0 dangling dependsOn refs. `generate-sbom-examples --check` passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com> * refactor(xtask): make SBOM examples on-demand; add tokio; stamp 1.0.1 The SBOM examples are illustrative artifacts, not golden fixtures, so regenerate them on demand instead of drift-checking on every change: - Drop the generator's --check mode, all field normalization, the per-PR CI "Check SBOM examples" step (~14 min/PR, re-cloned + rescanned four repos), and the release.sh regen hook. - Write mode now prunes any examples/sbom/ directory not in TARGETS, so regeneration is authoritative (addresses the obsolete-outputs review note). - Add tokio (tokio-1.53.1) as a fourth verified target: a Cargo workspace that showcases monorepo-aware, multi-package inventory. Verified CLEAN vs ScanCode. - Honor an explicit PROVENANT_BUILD_VERSION over the workspace default and stamp the examples 1.0.1 — the release the complete-inventory SBOM behavior ships in. - READMEs now auto-compute component/dependency counts from the generated CycloneDX and list the per-target, source-faithful differences from ScanCode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com> --------- Signed-off-by: Maxim Stykow <maxim.stykow@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Copyright © <year> <ACRONYM>.when prose preceded the marker on the same line.CERN.) lexes as aPntoken, whereas its period-less spelling (CERN) lexes asCaps. A bareCapsreduces to aNameCapsnode and is absorbed onto a year-only copyright via thestrong_firstpath inshould_start_absorbing; a bare trailingPnmatched no absorption branch and was dropped, yielding a holder-lessCopyright (c) <year>.extend_year_only_copyrights_with_trailing_textrepair (regex anchored at^copyright), which cannot fire when prose precedes the copyright — so any real-world file with the copyright mid-line lost the holder.tests/test_cli.py@22d924701a6ae2e4cd01e9a15bbaf3946094af65(... Revised BSD License. Copyright © 2015 CERN.): reportedCopyright © 2015with no holder; now reportsCopyright © 2015 CERN.with holderCERN.should_start_absorbing, absorb a lone trailingPnleaf on the same line as a holder-less, year-bearing copyright clause, mirroring the existingCaps/NameCapstreatment so the two source-faithful spellings behave consistently. Scoped to a year-only clause so it cannot swallow ordinary prose.Scope and exclusions
Pnacronym holder; detector regression tests.CERN.(kept asPn, which is still correct in name contexts such asName Pn); no change to the line-anchored repair heuristic.How to verify
its Revised BSD License. Copyright © 2015 CERN.with--copyright; observe the holderCERNis captured and the statement keepsCERN..Copyright © 2015 CERN. All rights reserved.(rights-reserved stripped from holder, holder stillCERN);Copyright © 2015 U.S. Government(multi-token name unaffected); a bare year-onlyCopyright © 2015after prose (correctly yields no holder — no over-capture of surrounding prose).Expected-output fixture changes
copyright_golden),scanner_copyright_credits,post_processing_golden, and thecopyright::unit tests all pass unchanged. New coverage is added as unit tests insrc/copyright/detector/tests.rs.