feat(signals): add deterministic copycat containment engine for gate.copycat (#1969)#5129
feat(signals): add deterministic copycat containment engine for gate.copycat (#1969)#5129carlh7777 wants to merge 2 commits into
Conversation
… scoring and direction assessment This commit introduces the `copycat` module, which provides a deterministic mechanism for detecting code plagiarism by measuring the containment of added code in prior art. Key features include: - Calculation of containment scores based on shingling of code lines. - Determination of copy direction based on submission timestamps. - Public-safe findings that report potential overlaps without revealing sensitive information. Additionally, unit tests for the `copycat` functionality have been added to ensure accuracy and reliability of the detection mechanisms.
|
🚨 Contributor flagged. Click here for more info: Superagent Dashboard |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5129 +/- ##
=======================================
Coverage 94.32% 94.32%
=======================================
Files 471 472 +1
Lines 39821 39861 +40
Branches 14533 14547 +14
=======================================
+ Hits 37560 37600 +40
Misses 1583 1583
Partials 678 678
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-11 21:58:40 UTC
✅ Suggested Action - Approve/Merge
Review summary Blockers
Nits — 5 non-blocking
Flagged checks (non-blocking)
Review context
Contributor next steps
Signal definitions
[BETA] Chat with GittensoryAsk Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
|
An AI reviewer flagged a likely defect, but its confidence was below this repository's configured close-confidence floor, so this is held for a maintainer to confirm instead of closing automatically. Resolve the flagged defect (see the review notes), or ask a maintainer to override. |
This commit refactors the `copycat` module to improve the shingle generation process by introducing a new function, `codeShingleList`, which preserves duplicates in the shingles. The existing `codeShingles` function is updated to return a distinct set of shingles. Additionally, the containment scoring logic is adjusted to work with the new shingle list format, ensuring accurate scoring based on the total shingle count. These changes enhance the module's ability to detect code plagiarism more effectively.
Summary
Adds the deterministic copycat/plagiarism containment engine (
src/signals/copycat.ts) — the detection primitive the already-scaffolded but currently-inertgate.copycat.mode/gate.copycat.minScoreconfig (#4140) was threaded for. It's a natural sibling of the deterministic anti-slop signal (src/signals/slop.ts) and duplicate-cluster adjudication (src/signals/duplicate-winner.ts), and follows the house style of the miner-side self-plagiarism throttle (packages/gittensory-engine/src/governor/self-plagiarism.ts).Given a PR's added code and one piece of prior art, it:
},return null;) don't inflate the score; whitespace/case-normalized so pure reformatting never reads as copied content.ambiguous.warn→ info /label→ warning /block→ critical) into a public-safe finding.Precision-first / false-accusation-averse (the issue's hard requirement): a finding is emitted only when the mode is non-
off, the score clears the (resolved) threshold, and the candidate is unambiguously the later submission. An earlier-submitted victim — or any ambiguous timing — is never flagged. The engine is pure: no IO, noDate.now(), no randomness; identical inputs always yield the identical verdict.Scoped to the engine + direction + tier mapping. The gate call-site that feeds real added-code/prior-art in and turns a
wouldActverdict into an actual label/block + the cross-repo "strikes" escalation is a deferred follow-up — mirroring the config's own documented "CURRENTLY INERT … later, separate PRs against #1969" plan, and howself-plagiarism.ts"gates nothing on its own."Closes #1969
Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally (focused):npx vitest run test/unit/copycat.test.ts— 21 pass, v8 coverage 100% statements / 100% branches / 100% functions / 100% lines onsrc/signals/copycat.ts(every changed line and branch). Will run fullnpm run test:ci+npm auditbefore push.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderatewouldActguard (off, sub-threshold, victim-direction).If any required check was skipped, explain why:
New self-contained pure module under
src/signals/plus its unit test. It touches no workflow, MCP, OpenAPI, DB/migration, or UI surface, soactionlint,build:mcp/test:mcp-pack,ui:*, andui:openapi:checkare N/A. It's a new file with no engine-package twin, sotest:engine-paritydoes not apply. Fulltest:ci+npm auditwill run before push.Safety
publicTextreports the containment score + threshold only — never raw code, filenames, or any contributor identity — and is accusation-neutral ("please confirm originality or attribution").UI Evidence
N/A — no UI/frontend/docs changes in this PR.
Notes
DEFAULT_COPYCAT_MIN_SCORE = 85(mirrors the 0.85 spirit of the self-plagiarism throttle); an out-of-range/non-numericgate.copycat.minScoreclamps to 0-100 and falls back to the default.offor the direction is ambiguous — only the finding is gated on the precision guards.