feat(gate): add a CLA / license-compatibility gate dimension#2679
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 42aa98d | Commit Preview URL Branch Preview URL |
Jul 03 2026, 06:39 AM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2679 +/- ##
=======================================
Coverage 96.13% 96.13%
=======================================
Files 240 241 +1
Lines 26985 27030 +45
Branches 9792 9821 +29
=======================================
+ Hits 25941 25986 +45
Misses 433 433
Partials 611 611
🚀 New features to boost your workflow:
|
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-03 05:58:21 UTC
⏸️ Suggested Action - Manual Review
Review summary Blockers
Nits — 6 non-blocking
Concerns raised — review before merging
Review context
Contributor next steps
Signal definitions
🟩 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.
|
692758e to
102829a
Compare
Common OSS gate bots (the "CLA assistant" pattern) have no analog here, and because this gate auto-merges green PRs with no human in the loop, a repo that legally requires contributor sign-off before merge had no deterministic way to enforce that through gittensory. This adds gate.claMode: off/advisory/ block, mirroring the existing pre_merge_checks titleContains/descriptionContains deterministic-phrase-match pattern (src/review/pre-merge-checks.ts) plus a second detection method, a named CLA-bot check-run's conclusion, satisfied by EITHER method. Off by default, so a repo that has not opted in sees zero behavior change. Wired through the full config-as-code chain (types.ts RepositorySettings, openapi/schemas.ts RepositorySettingsSchema, focus-manifest.ts gate.claMode + gate.cla parsing/round-trip/resolveEffectiveSettings, advisory.ts GateCheckPolicy + isConfiguredGateBlocker + isEvaluationBlocker, queue/processors.ts gateCheckPolicy + the live evaluator call, and predicted-gate.ts for pre-submission prediction parity), the same sites every other GateRuleMode gate dimension touches. An unresolved check-run conclusion (a transient fetch failure, not a resolved "no such check-run") HOLDS the gate (cla_check_unresolved) instead of failing closed, mirroring pre_merge_check_unresolved. The block-mode blocker integrates with the existing gate disposition machinery unmodified, so it inherits the standing owner/admin auto-close exemption for free rather than re-implementing it. Closes #2564
Addresses gate-review findings on this PR: - evaluateClaCheck now HOLDS (cla_check_unresolved) whenever a configured check-run's conclusion is unresolved, even when consentPhrase is also configured but not yet satisfied -- deciding purely from an unsatisfied phrase could hard-fail a PR the check-run method would have saved. - fetchNamedCheckRunConclusion now returns undefined (unresolved) for a matching check-run that has not finished yet (status !== completed, conclusion: null is GitHub's own "not decided" contract), instead of coercing it to an empty string that read as a resolved, non-satisfying conclusion. - cla_check_unresolved is no longer an unconditional evaluation blocker: it now only holds the gate under claMode: block, matching advisory mode's contract of surfacing findings without affecting the verdict. Also renames a test fixture token to avoid tripping the generic-secret- assignment scanner on a placeholder value.
102829a to
42aa98d
Compare
Summary
gate.claMode: off | advisory | block(.gittensory.yml, defaultoff) — the gittensory analog of a "CLA assistant" check bot, since a repo that legally requires contributor sign-off before merge had no deterministic way to enforce it through the auto-merging gate.review.pre_merge_checkstitleContains/descriptionContainsdeterministic-phrase-match pattern exactly (src/review/pre-merge-checks.ts): a newsrc/review/cla-check.tsevaluator checks for a maintainer-configured consent phrase in the PR body (case-insensitive substring), and/or a named CLA-bot check-run's conclusion (success/neutral). Consent is satisfied when either configured method holds.cla_consent_missingfinding is always generated at severitywarning;isConfiguredGateBlocker(src/rules/advisory.ts) is what escalates it to a hard blocker underclaMode: block, exactly mirroring howmanifest_missing_tests/manifest_linked_issue_requiredwork — no new blocking mechanism, reuse of the existing one.cla_check_unresolvedinstead, whichisEvaluationBlockertreats as a neutral HOLD that re-evaluates automatically — mirroringpre_merge_check_unresolved— so a flaky fetch can never manufacture a false close.src/github/backfill.tsexportfetchNamedCheckRunConclusion(best-effort, single-call, fails toundefinednot a false negative) resolves the check-run-conclusion detection mode, following the same pattern as the existingfetchRequiredStatusContexts.gate-setting-wiringtemplate (reference.md) requires:types.tsRepositorySettings,openapi/schemas.tsRepositorySettingsSchema(regeneratedapps/gittensory-ui/public/openapi.json),focus-manifest.ts(gate.claMode+gate.cla.{consentPhrase,checkRunName}parse/round-trip/resolveEffectiveSettings),advisory.tsGateCheckPolicy,queue/processors.ts(gateCheckPolicy+ the live evaluation call site), andpredicted-gate.ts(pre-submission prediction parity — the metadata-only predictor never resolves a live check-run, so it only predicts the phrase-match method and discloses the check-run-only gap by never producing a false positive there)..gittensory.yml.exampleunder thegate:block, matching the style ofgate.size/gate.premergeContentRecheck.conclusion: "failure"+ the finding's title), so it automatically gets the same standingisContributorguard every other blocker gets (src/settings/agent-actions.ts) — one-shot close for a contributor PR, held for the owner/admin. Verified with a dedicated test.claModeunset ⇒undefined(no DB column, mirrorssizeGateMode/gate.premergeContentRecheck— config-as-code only), so a repo that has not opted in makes no extra GitHub call and pushes no finding.Closes #2564
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally (unsharded) — the newcla-check.tsevaluator is 100% lines/100% branches; every branch on every changed line inbackfill.ts,advisory.ts,predicted-gate.ts,focus-manifest.ts, andprocessors.tsis exercised on both sides (verified line-by-line againstcoverage/lcov.info).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=moderate— 0 vulnerabilitiestest/unit/cla-check.test.ts(14 tests: phrase-match, check-run-conclusion, either-method contract),test/unit/gate-check-policy.test.ts(block/advisory/off, unresolved-hold, resolveEffectiveSettings wiring),test/unit/focus-manifest.test.ts(parse/round-trip/public-safe filtering of the consent phrase and check-run name),test/unit/predicted-gate.test.ts(pre-submission prediction parity, including the check-run-only-config HOLD case),test/unit/backfill.test.ts(fetchNamedCheckRunConclusionfetch/fail-safe branches),test/unit/queue.test.ts(5 live end-to-end webhook tests: phrase block, phrase pass, off-by-default, check-run pass, check-run fail),test/unit/agent-actions.test.ts(owner-exemption for a CLA-flavored blocker).Ran
npm run test:ciend to end locally (all steps, includingui:build) — fully green, exit code 0. Also rannpm run test:coveragestandalone to inspectcoverage/lcov.infoline-by-line for my changed ranges.Safety
RepositorySettingsSchemaextended withclaGateMode/claConsentPhrase/claCheckRunName,openapi.jsonregenerated,ui:openapi:settings-paritypasses.sizeGateMode, which also has no dashboard toggle, config-as-code only.)UI Evidencesection — N/A, no visible/UI changes in this PR..gittensory.yml.example);CHANGELOG.mdis untouched (not a release-prep PR).Notes
claModemirrorssizeGateMode's established "config-as-code only, no DB column" precedent (also used bygate.dryRun/gate.premergeContentRecheck/gate.aiReview.closeConfidence) rather than the full-parity DB pathmanifestPolicyGateModeuses — this keeps the PR narrow and matches an existing, proven pattern for a new opt-in gate dimension; a follow-up could add the dashboard toggle if wanted.predicted-gate.ts) cannot resolve a live check-run before a PR exists, so a check-run-only CLA config predicts a HOLD (never a false pass or false block) rather than a real verdict — this is called out inline and is the same limitation the predictor already has for path-gatedpre_merge_checks.