license-compliance-audit · git:20260728.aa372ed · 2026-07-28 · sha256 0127d16a4a293e30
license-compliance-audit git:20260728.aa372edA
Immutable. This exact content is served forever at /api/v1/blob/0127d16a4a293e30.
--- model_tier: medium name: license-compliance-audit description: "Run the offline (jscpd) and online (scanoss-py) similarity scanners on demand against a diff or path — the ONLY home of this repo's detection capability; no CI gate exists or ever ran it automatically" domain: engineering workspaces: - engineering packs: - engineering-base --- # license-compliance-audit Gate G0 (`road-to-provenance-and-license-governance`, Phase 0) measured both candidate similarity detectors against a frozen golden corpus and neither met the pre-registered bar for a CI gate. Council resolved (2026-07-28, Option A): **no `lint_code_provenance.ts` in any form — not even advisory.** This skill is the result of that decision: the scan capability that used to be a planned CI gate now exists only as something a human invokes deliberately, so every hit gets investigated *because* a human asked for it — never as a silent pipeline signal nobody reads. ## When to use - Before merging a diff that looks suspiciously similar to something you've seen elsewhere, or that a reviewer flagged. - During a periodic self-audit (e.g. the Phase-4 "run the full pipeline on this repo" dogfood exercise). - A reviewer or the `origin: uncertain` self-flag from [`code-provenance`](../../rules/code-provenance.md) names a residual-class file worth a closer look. Do NOT use when: - You expect this to run automatically in CI — it does not, by explicit council decision; nothing here is wired into any pipeline. - You expect a clean result to prove the code was not copied — it cannot; see the scope bound below. - You already have a specific, known source to check against a specific license — that's [`license-compliance-borrow-check`](../license-compliance-borrow-check/SKILL.md), a targeted one-source check, not a corpus-wide scan. ## Procedure 1. **Inspect available tooling.** The offline layer (L-1) is always available via `npx`: ```bash npx jscpd --version ``` The online layer (L0) is optional — check whether it is installed and reachable: ```bash scanoss-py --version # or: pip show scanoss ``` Offline-only is expected and fine in most environments; report it honestly rather than treating it as a failure. 2. **Run the offline scan (L-1)** against the target path or diff: ```bash npx jscpd <path> --min-tokens 25 ``` `--min-tokens 25` is the pre-registered shipping value — the best false-positive-clean point of the S0.3 sweep (`internal/bench/provenance/reports/baseline-2026-07-28.md`). Read every reported clone pair as a **candidate**, never a verdict. 3. **If L0 is reachable, run the fingerprint scan:** ```bash scanoss-py scan <path> ``` Only WFP fingerprints leave the machine, never raw source (privacy by construction, principle 7). If L0 is unreachable, rate-limited, or not installed, report the result as `partial (offline)` explicitly — never claim a full two-layer scan ran. 4. **Investigate every hit manually.** For each match: is the matched file already in `provenance/borrows.jsonl` (cleared)? Does it read like independent convergence on a common algorithm shape, or an unattributed real copy? Open both files side by side before deciding — a match id is a starting point, not a conclusion. 5. **Route unresolved hits.** A hit with no existing ledger entry and no independent-convergence explanation routes to [`license-compliance-borrow-check`](../license-compliance-borrow-check/SKILL.md) to classify and draft the entry. Never clear a hit yourself by simply deciding it's fine. 6. **Report the scope bound alongside every result** (see below) — a clean run means "nothing matched this KB/corpus at this sensitivity", never "no copying happened". ## What the measured numbers mean — and don't On the frozen synthetic corpus (`internal/bench/provenance/`, 36 files, content-sha256 `dbbc84a7…34bb3`): | layer | verbatim+rename recall | rename-only recall | false positives | |---|---:|---:|---:| | L-1 jscpd `--min-tokens 25` | 10/16 | 4/8 | 0/12 | | L0 scanoss | 4/16 | 0/8 | 2/12 | | **union (both layers)** | **12/16** | **4/8** | **2/12** | Full source: `internal/bench/provenance/reports/baseline-2026-07-28.md`. - **Scope bound:** the corpus is `synthetic-canonical` — independently authored implementations of well-known algorithm shapes, never fetched or pasted from any upstream file. This measures **transformation-depth sensitivity and false-positive rate on independent code** — it does **not** measure recall against SCANOSS's real-OSS knowledge base. No sample here is indexed anywhere, so a KB lookup returning zero hits says nothing about the detector's real-world recall. Real-KB recall is unmeasured and would need a second, real-snippet corpus. - **Rename-only laundering is not reliably caught** — 0/8 (SCANOSS), 4/8 (jscpd). The provenance ledger, not this scan, is the anti-launder control (see [`code-provenance`](../../rules/code-provenance.md)). - **No tool sees model training data.** Unconscious reproduction from training data is not addressed by this scan at all, regardless of outcome. ## Output format 1. Per scan target: which layer(s) actually ran, hit or clean, and — if the online layer was unreachable — the explicit `partial (offline)` marker (never a silent green presented as a full scan). 2. For every hit: the matched file/snippet, a manual same-shape-vs-real-copy judgment, and the routing decision (already ledgered / route to `license-compliance-borrow-check` / independent convergence, no action). 3. The scope-bound paragraph from the section above, restated so the requester never reads a clean result as a copying guarantee. ## Gotcha - **A clean scan is not proof of originality.** It means "nothing matched at this sensitivity, in this corpus/KB" — never "not copied from training data". - **Rename-only copies routinely pass both layers.** Do not trust a clean re-scan after a purely cosmetic rewrite as evidence of real transformation. - **Both of SCANOSS's measured false positives came from independently authored files** matching on convergent canonical-algorithm shape (MIT snippet matches) — a hit is an investigation trigger, not an accusation. - **Nothing here is wired into CI.** A hit found by this skill never blocked anything automatically; if you expected a pipeline signal, there isn't one — that's the point of Gate G0's Option A resolution. ## Do NOT - NEVER claim or imply this scan runs in CI — it explicitly does not, by council decision (Gate G0, Option A). - NEVER report a scan as complete when the online layer was unreachable — always say `partial (offline)`. - NEVER present a clean result as "provably not copied" — restate the scope bound every time a result is shared. - NEVER clear a hit without either a ledger entry or a documented independent-convergence judgment. ## See also - [`code-provenance`](../../rules/code-provenance.md) — the rule that makes the ledger, not this scan, the primary anti-launder control. - [`license-compliance-borrow-check`](../license-compliance-borrow-check/SKILL.md) — where an unresolved hit routes for classification + ledger drafting. - `internal/bench/provenance/reports/baseline-2026-07-28.md` — the full measured baseline this skill's numbers are drawn from. - `docs/CLAIMS.md` — claim `provenance-detector-transformation-sensitivity` (unbacked, carries the same scope bound).