Skip to content

Commit 3df5539

Browse files
Merge pull request #311 from Kaushik-Kumar-CEG/gsoc-2026-required-phrases-report
Add GSoC 2026 report for ScanCode required phrases
2 parents ad6f08a + 40fdf20 commit 3df5539

2 files changed

Lines changed: 280 additions & 0 deletions

File tree

docs/source/archive/gsoc-toc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ GSoC 2026
1515
:maxdepth: 2
1616

1717
gsoc/reports/2026/vulnerablecode_sampurna
18+
gsoc/reports/2026/scancode_required_phrases_kaushik
1819

1920
GSoC 2025
2021
---------
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
=============================================================================
2+
ScanCode-Toolkit: Mark required phrases for rules automatically using NLP/AI
3+
=============================================================================
4+
5+
| Mentee: **Kaushik Kumar R**
6+
| GitHub: `Kaushik-Kumar-CEG <https://github.com/Kaushik-Kumar-CEG>`_
7+
| LinkedIn: `Profile <https://www.linkedin.com/in/kaushik-kumar-ceg/>`_
8+
| Repository: `ScanCode Required Phrases
9+
<https://github.com/aboutcode-org/scancode-required-phrases>`_
10+
| Official GSoC project page: `Project Link
11+
<https://summerofcode.withgoogle.com/programs/2026/projects/K6CQtnjP>`_
12+
| GSoC Proposal: `Proposal Link
13+
<https://docs.google.com/document/d/1qXYTrIoF4Tn5q-dPMQicCFZ0NKbLj9jYN18ipyPyqZI/edit?usp=sharing>`_
14+
| Model: `Hugging Face
15+
<https://huggingface.co/Kaushik-Kumar-CEG/scancode-required-phrases-deberta-bioes-crf-hardened>`_
16+
17+
Overview
18+
--------
19+
20+
Required phrases help ScanCode avoid weak or partial license matches. They are
21+
marked with ``{{...}}`` inside a license rule. If the phrase is missing from the
22+
scanned text, that rule does not match.
23+
24+
Many rules do not have these markers yet. Existing ScanCode commands can copy
25+
known phrases to similar rules, but they need a phrase to start with. The work
26+
in `scancode-toolkit#3924
27+
<https://github.com/aboutcode-org/scancode-toolkit/pull/3924>`_ provides the
28+
rule APIs used here. This project adds an NLP model that can suggest a phrase
29+
directly from rule text.
30+
31+
A wrong phrase can hide a valid license match, so model output cannot be written
32+
to rules without checks and review. The work includes dataset generation, model
33+
training, prediction validation, a maintainer review command and a small
34+
ScanCode Toolkit wrapper.
35+
36+
The two main flows are:
37+
38+
.. code-block:: text
39+
40+
marked ScanCode rules -> dataset -> training -> public model
41+
unmarked rule -> prediction -> ScanCode checks -> review -> rule update
42+
43+
Work Completed
44+
--------------
45+
46+
Dataset and composite rules
47+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
The dataset command reads eligible ScanCode ``.RULE`` files and converts
50+
existing ``{{...}}`` markers into BIOES token labels. Text outside the markers
51+
is labelled ``O``.
52+
53+
The split is deterministic. Rules with rarer license expressions stay together
54+
in one split. Rules from common expressions are assigned by a hash of their
55+
identifiers to keep the splits balanced. After tokenizer alignment checks, the
56+
training run used 8,265 training rules, 1,044 validation rules and 1,004 test
57+
rules.
58+
59+
A separate command handles composite expressions. It uses phrases already known
60+
for the individual license keys and only updates a composite rule when every
61+
key has a safe, non-overlapping match.
62+
63+
Model training and inference
64+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
66+
The selected model is based on DeBERTa v3 large with BIOES labels and a constrained
67+
conditional random field (CRF) decoder. BIOES marks the start, inside, end and
68+
single-token cases for each phrase. The CRF keeps the decoded label sequence
69+
valid.
70+
71+
Training and test evaluation are kept separate. Test evaluation is opt-in and
72+
was run only for the selected model. The training command also reloads and
73+
checks the saved model before treating the output as complete.
74+
75+
The model is public on Hugging Face. It is pinned to revision
76+
``11215925b0f9b64cfcfbbb5492b52d6aeb5a572b`` for the default command.
77+
78+
.. list-table:: Model results
79+
:widths: 40 30 30
80+
:width: 100%
81+
:header-rows: 1
82+
83+
* - Metric
84+
- Validation
85+
- Test
86+
* - Precision
87+
- 0.8981
88+
- 0.8748
89+
* - Recall
90+
- 0.9035
91+
- 0.8784
92+
* - F1
93+
- 0.9008
94+
- 0.8766
95+
* - Exact match
96+
- 0.8563
97+
- 0.8197
98+
99+
Precision, recall and F1 are strict span metrics. The validation and test runs
100+
had no invalid BIOES paths.
101+
102+
Review and rule updates
103+
^^^^^^^^^^^^^^^^^^^^^^^
104+
105+
The main maintainer command is ``add-model-required-phrases``. It can review one
106+
rule, a directory of rules or eligible rules installed with ScanCode Toolkit.
107+
It shows the prediction, score, validation result, nearby text and the exact
108+
rule diff before asking for a decision.
109+
110+
A review can approve, reject, edit or defer a phrase. Sessions are saved as
111+
JSONL and can be resumed without loading the model again. Predict-only mode can
112+
write machine-readable JSON without creating a review session or changing any
113+
rule.
114+
115+
Batch mode requires explicit score thresholds. It does not write unless
116+
``--yes`` is supplied. ``--dry-run`` always prevents rule-file changes. After
117+
installed rules are changed, the command tells the maintainer to rebuild the
118+
ScanCode license index.
119+
120+
Safety checks
121+
^^^^^^^^^^^^^
122+
123+
Every prediction is treated as a candidate. ScanCode's own rule APIs decide
124+
whether the phrase can be inserted. The command blocks phrases that overlap
125+
protected content such as URLs and referenced filenames. It also rejects
126+
ambiguous repeated text, conflicting spans and predictions cut by model input
127+
limits.
128+
129+
Before applying a reviewed session, the command checks every path and file hash
130+
again. It prepares the complete update first, then writes each changed rule once
131+
using atomic replacement. File permissions and line endings are kept. A rule
132+
with a pending phrase is left unchanged.
133+
134+
Toolkit integration
135+
^^^^^^^^^^^^^^^^^^^
136+
137+
The model code and its optional dependencies live in the
138+
``scancode-required-phrases`` package. ScanCode Toolkit only gets a small source
139+
checkout wrapper. This keeps normal ScanCode installation and license scanning
140+
free from ML dependencies. The wrapper imports the package command and passes
141+
its arguments through.
142+
143+
A second Toolkit pull request contains ten manually reviewed rule changes from
144+
a fixed sample of 30 rules. The sample was selected before prediction and was
145+
checked against the final train, validation and test data.
146+
147+
The model returned 37 candidate phrases across 22 of the 30 rules. Twenty-one
148+
passed the insertion checks and 16 were blocked. Ten clear license-specific
149+
phrases were kept. Each updated rule still matched its original full text, while
150+
text missing the required phrase did not match that rule.
151+
152+
Using the Command
153+
-----------------
154+
155+
Install the inference dependencies from a package checkout:
156+
157+
.. code-block:: console
158+
159+
python -m pip install ".[inference]"
160+
161+
Review one rule:
162+
163+
.. code-block:: console
164+
165+
add-model-required-phrases --rule path/to/example.RULE
166+
167+
Run read-only prediction and save JSON:
168+
169+
.. code-block:: console
170+
171+
add-model-required-phrases --rule path/to/example.RULE \
172+
--predict-only --json predictions.json
173+
174+
Preview a batch without writing rule files:
175+
176+
.. code-block:: console
177+
178+
add-model-required-phrases --all --batch \
179+
--auto-score 0.90 --review-score 0.70 --dry-run
180+
181+
Linked Pull Requests
182+
--------------------
183+
184+
.. list-table::
185+
:widths: 8 62 30
186+
:width: 100%
187+
:header-rows: 1
188+
189+
* - No.
190+
- Work
191+
- Link
192+
* - 1
193+
- Dataset and composite required phrase commands
194+
- `scancode-required-phrases#1
195+
<https://github.com/aboutcode-org/scancode-required-phrases/pull/1>`_
196+
* - 2
197+
- Model training, export and read-only inference
198+
- `scancode-required-phrases#2
199+
<https://github.com/aboutcode-org/scancode-required-phrases/pull/2>`_
200+
* - 3
201+
- Model prediction and rule integration
202+
- `scancode-required-phrases#3
203+
<https://github.com/aboutcode-org/scancode-required-phrases/pull/3>`_
204+
* - 4
205+
- Human review workflow for model predictions
206+
- `scancode-required-phrases#4
207+
<https://github.com/aboutcode-org/scancode-required-phrases/pull/4>`_
208+
* - 5
209+
- ScanCode Toolkit command wrapper
210+
- `scancode-toolkit#5267
211+
<https://github.com/aboutcode-org/scancode-toolkit/pull/5267>`_
212+
* - 6
213+
- Reviewed model predictions for ten sample rules
214+
- `scancode-toolkit#5330
215+
<https://github.com/aboutcode-org/scancode-toolkit/pull/5330>`_
216+
217+
Testing
218+
-------
219+
220+
The package tests cover dataset generation, model loading, prediction decoding,
221+
rule validation, review sessions, stale files, dry runs, batch thresholds,
222+
atomic writes and command output. The complete package suite passed 322 tests.
223+
Documentation, style, source distributions and wheels were also checked.
224+
225+
The Toolkit wrapper passed its focused tests with a fake package and with the
226+
real public model. The ten evidence rules passed ScanCode rule validation and
227+
the focused required-phrase tests.
228+
229+
Earlier Work
230+
------------
231+
232+
Before GSoC, I worked on a few ScanCode license detection cases. These helped me
233+
understand rule data and how small rule changes affect matching.
234+
235+
* `Add a rule for CKSource Holding copyright
236+
<https://github.com/aboutcode-org/scancode-toolkit/pull/4649>`_
237+
* `Fix incorrect license detection in dragon4.c
238+
<https://github.com/aboutcode-org/scancode-toolkit/pull/4654>`_
239+
* `Fix JCalendar LGPL detected as GPL
240+
<https://github.com/aboutcode-org/scancode-toolkit/pull/4880>`_
241+
242+
Current Limits and Next Steps
243+
-----------------------------
244+
245+
The model can miss a phrase or suggest a boundary that is not useful. Scores are
246+
not enough to approve a change, which is why review and ScanCode validation stay
247+
part of the workflow. Long rules may also be truncated by the model and are not
248+
approved automatically.
249+
250+
The package pull requests and both Toolkit pull requests are still open. After
251+
they are reviewed and merged, I plan to prepare version ``0.1.0`` and help with
252+
the PyPI release. I will keep maintaining the dataset tools, training pipeline,
253+
model and review command. Maintainer feedback and reviewed rules can be used for
254+
future training runs.
255+
256+
One later area to study is `scancode-toolkit#3945
257+
<https://github.com/aboutcode-org/scancode-toolkit/issues/3945>`_. It considers
258+
ranking matches with required phrases instead of always filtering matches that
259+
miss them. The phrases produced by this project can still be used if that policy
260+
changes.
261+
262+
Closing Thoughts
263+
----------------
264+
265+
GSoC taught me much more than how to train an NLP model. I learned how ScanCode's
266+
license rules and matching code work, how to turn an experiment into a package
267+
and why review matters for even a small rule change.
268+
269+
The weekly community calls were one of my favourite parts of the project. I
270+
could show my progress, hear where an idea was weak and fix it before going too
271+
far. Thanks to `Ayan Sinha Mahapatra
272+
<https://github.com/AyanSinhaMahapatra>`_, `Philippe Ombredanne
273+
<https://github.com/pombredanne>`_ and `Dennis Clark
274+
<https://github.com/DennisClark>`_ for their time, feedback and patience.
275+
276+
I am very glad I got to work with the `AboutCode community
277+
<https://github.com/aboutcode-org>`_. I learned a lot from the reviews and the
278+
technical discussions. I plan to keep contributing to AboutCode and continue
279+
maintaining this work after GSoC.

0 commit comments

Comments
 (0)