feat(review): add gate.copycat.mode config scaffold for copycat detection - #4140
Conversation
|
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 #4140 +/- ##
=======================================
Coverage 93.73% 93.73%
=======================================
Files 387 387
Lines 36371 36382 +11
Branches 13316 13323 +7
=======================================
+ Hits 34092 34104 +12
Misses 1621 1621
+ Partials 658 657 -1
🚀 New features to boost your workflow:
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | b25d4c6 | Commit Preview URL Branch Preview URL |
Jul 08 2026, 10:19 AM |
|
Caution 🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥 🛑 Gittensory review result - fixes requiredReview updated: 2026-07-08 10:15:19 UTC
🛑 Suggested Action - Manual Review
Why this is blocked
CI checks failing
Review context
Contributor next steps
Signal definitions
Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. 🟩 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.
|
e86bed2 to
866cdb1
Compare
866cdb1 to
a2b943b
Compare
…tion Parses and threads a new gate.copycat.mode (off/warn/label/block) and gate.copycat.minScore end-to-end through the manifest, effective-settings resolver, and OpenAPI schema -- config-as-code only, no DB column. The similarity/containment detection engine that would consume this config does not exist yet; this field is deliberately inert (parsed and threaded, never read by any decision path) so an operator's .gittensory.yml can already declare intent ahead of the detection engine landing in a later PR.
The scaffold PR added copycatGateMode to RepositorySettings but missed two things docs:drift-check enforces for every *GateMode field: a GATE_MODE_MANIFEST entry in scripts/check-docs-drift.mjs, and real documentation on docs.how-reviews-work.tsx + docs.tuning.tsx. Both added, honestly noting the detection engine hasn't shipped yet. Bumps the synthetic-fixture gate-mode count in the drift-check's own test to match.
…t round-trip gate.copycat.mode and gate.copycat.minScore are independently optional in the source YML, but every existing gateConfigToJson round-trip test set both together (or left both null), leaving the "only one of the two is set" branch inside gateConfigToJson's copycat block uncovered.
a2b943b to
d5125b3
Compare
npm run ui:lint runs eslint's prettier/prettier rule as an error, not just npm run validate's plain prettier check -- the added JSX text wrapped in a way that check rejects.
Implements the deterministic containment/similarity engine gate.copycat.mode was parsed for since #4140 but never acted on. Scores a PR's added lines against a bounded, precision-first candidate set of earlier open siblings and recently-merged PRs on the same repo, resolving copy direction by submission timestamp so the original author is never flagged. warn surfaces an advisory finding; label also applies a label without blocking review; block also closes the PR and feeds the existing moderation-rules strikes ledger. Closes #1969
ui-preview.yml / ui-preview-deploy.yml (via the shared deploy-ui-preview composite) create a "preview/pr-<N>" GitHub Environment via createDeployment the first time a PR gets a preview build -- transient_environment: true is only a display hint, it never triggers deletion, and nothing else in the repo ever calls the delete-environment API. Confirmed live: 1254 of 1260 environments were preview/pr-* entries for already-closed PRs (spanning PR #4140-#8617), none carrying protection rules -- cleaned up directly via the API as a one-time sweep before adding this workflow. Mirrors cache-cleanup.yml's existing fix for the identical class of problem (GHA caches instead of environments): batched on a daily schedule, not a pull_request:[closed] trigger, so PR-close bursts never queue a runner per event and compete with real CI. No storage-budget urgency here unlike the 10GB cache cap, so daily is enough. Needs a new ENVIRONMENT_ADMIN_TOKEN secret -- deleting an environment requires repo scope (classic PAT) or Administration:write (fine-grained PAT); GITHUB_TOKEN can never be granted this via a permissions: block, confirmed against GitHub's own docs.
Summary
gate.copycat.mode(off | warn | label | block, defaultoff) andgate.copycat.minScoreto.gittensory.yml, following the exact wiring patterngate.slopalready uses (packages/gittensory-engine/src/focus-manifest.ts'sFocusManifestGateConfig/parseGateConfig/gateConfigToJson,src/signals/focus-manifest.ts'sapplyGateConfigOverrides,src/types.ts'sRepositorySettings,src/openapi/schemas.ts).copycatModeis a DEDICATED 4-value enum, not the sharedoff|advisory|blockGateRuleMode— the issue's tiered response is warn → label → block → strikes, where "strikes" is a separate escalation action (reusing the existing cross-repo banned-contributors ledger once wired) rather than a 5th mode value.claGateMode/lockfileIntegrityGateMode's precedent (confirmed by checking those fields are similarly absent fromsrc/db/schema.ts,src/db/repositories.ts,src/api/routes.ts, andsrc/signals/settings-preview.ts).src/rules/advisory.tsorsrc/queue/processors.tsreadscopycatGateMode. An operator can set it today with zero observable effect; it exists so intent can already be declared ahead of the detection engine landing.Scope
CONTRIBUTING.md.Validation
git diff --checknpm run typechecknpm run db:migrations:check/npm run db:schema-drift:check— no-ops confirmed (no DB schema touched, as expected for a config-as-code-only field).npm run ui:openapi(regeneratedapps/gittensory-ui/public/openapi.json) +npm run ui:openapi:check(clean) +npm run ui:openapi:settings-parity(confirmsRepositorySettingsSchemamatches theRepositorySettingstype at 100 fields, including the 2 new ones).npx vitest run test/unit/focus-manifest.test.ts— 558/558 passing, including 5 new dedicated tests (parse/round-trip thegate.copycatblock, all 4 mode tiers + rejection of the wrongadvisorytier, minScore clamping, byte-identical-when-absent, andresolveEffectiveSettingsprojection in both the set and DB-fallback branches) plus 2 existing exhaustiveness-check fixtures extended for the new fields.npx vitest run test/unit/openapi.test.ts test/unit/ci-openapi-settings-parity.test.ts test/unit/docs-examples-schema.test.ts— all passing.packages/gittensory-engine/src/focus-manifest.ts,src/signals/focus-manifest.ts) confirms every new line is covered; the reported uncovered line ranges in each file are pre-existing gaps unrelated to this diff (verified by line number).npm run test:workers,build:mcp,test:mcp-pack,ui:lint,ui:typecheck,ui:build,npm audit— not re-run locally (no worker/MCP/UI-component code touched); CI runs them authoritatively.Safety
.gittensory.yml.example/config/examples/gittensory.full.ymlinline documentation for the new keys.Notes
src/types.tsand the mirroredpackages/gittensory-engine/src/types/manifest-deps-types.ts, parse/serialize, resolver, OpenAPI schema + regenerated artifact, docs in both example files, tests) — confirmed by checkingclaGateMode's own footprint follows the same shape.duplicate-winner.ts's existing logic is confirmed to be pure scope-claim election, not code comparison), and the tiered gate wiring that actually readscopycatGateModeinsrc/rules/advisory.ts/src/queue/processors.ts.