@loopover/engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/LICENSE +661 -0
- package/README.md +676 -0
- package/dist/advisory/gate-advisory.d.ts +151 -0
- package/dist/advisory/gate-advisory.js +512 -0
- package/dist/ai-policy-map.d.ts +97 -0
- package/dist/ai-policy-map.js +377 -0
- package/dist/ams-policy-spec.d.ts +56 -0
- package/dist/ams-policy-spec.js +165 -0
- package/dist/calibration-dashboard.d.ts +23 -0
- package/dist/calibration-dashboard.js +65 -0
- package/dist/calibration-trend.d.ts +40 -0
- package/dist/calibration-trend.js +60 -0
- package/dist/contributor-fit.d.ts +24 -0
- package/dist/contributor-fit.js +50 -0
- package/dist/discovery-index-contract.d.ts +74 -0
- package/dist/discovery-index-contract.js +184 -0
- package/dist/discovery-soft-claim.d.ts +35 -0
- package/dist/discovery-soft-claim.js +50 -0
- package/dist/duplicate-winner.d.ts +57 -0
- package/dist/duplicate-winner.js +98 -0
- package/dist/feasibility.d.ts +27 -0
- package/dist/feasibility.js +86 -0
- package/dist/finding-severity-calibration.d.ts +116 -0
- package/dist/finding-severity-calibration.js +457 -0
- package/dist/fleet-run-manifest.d.ts +41 -0
- package/dist/fleet-run-manifest.js +151 -0
- package/dist/focus-manifest/guidance.d.ts +21 -0
- package/dist/focus-manifest/guidance.js +222 -0
- package/dist/focus-manifest.d.ts +826 -0
- package/dist/focus-manifest.js +2730 -0
- package/dist/gate-verdict-calibration.d.ts +111 -0
- package/dist/gate-verdict-calibration.js +411 -0
- package/dist/github/constants.d.ts +1 -0
- package/dist/github/constants.js +1 -0
- package/dist/github/sanitize-public-comment.d.ts +1 -0
- package/dist/github/sanitize-public-comment.js +26 -0
- package/dist/goal-model.d.ts +7 -0
- package/dist/goal-model.js +87 -0
- package/dist/governor/action-mode.d.ts +55 -0
- package/dist/governor/action-mode.js +74 -0
- package/dist/governor/budget-cap.d.ts +49 -0
- package/dist/governor/budget-cap.js +34 -0
- package/dist/governor/chokepoint.d.ts +58 -0
- package/dist/governor/chokepoint.js +269 -0
- package/dist/governor/kill-switch.d.ts +38 -0
- package/dist/governor/kill-switch.js +62 -0
- package/dist/governor/rate-limit.d.ts +40 -0
- package/dist/governor/rate-limit.js +63 -0
- package/dist/governor/reputation-throttle.d.ts +50 -0
- package/dist/governor/reputation-throttle.js +94 -0
- package/dist/governor/run-halt.d.ts +39 -0
- package/dist/governor/run-halt.js +83 -0
- package/dist/governor/self-plagiarism.d.ts +47 -0
- package/dist/governor/self-plagiarism.js +200 -0
- package/dist/governor/write-rate-limit.d.ts +52 -0
- package/dist/governor/write-rate-limit.js +132 -0
- package/dist/governor-ledger.d.ts +25 -0
- package/dist/governor-ledger.js +91 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.js +120 -0
- package/dist/issue-plan-decomposition.d.ts +18 -0
- package/dist/issue-plan-decomposition.js +56 -0
- package/dist/issue-rag-query.d.ts +12 -0
- package/dist/issue-rag-query.js +35 -0
- package/dist/local-scorer.d.ts +34 -0
- package/dist/local-scorer.js +36 -0
- package/dist/metadata-best-min-score.d.ts +9 -0
- package/dist/metadata-best-min-score.js +9 -0
- package/dist/metadata-best-pick.d.ts +9 -0
- package/dist/metadata-best-pick.js +9 -0
- package/dist/metadata-min-score.d.ts +9 -0
- package/dist/metadata-min-score.js +13 -0
- package/dist/metadata-top-min-score.d.ts +9 -0
- package/dist/metadata-top-min-score.js +13 -0
- package/dist/metadata-top-pick.d.ts +9 -0
- package/dist/metadata-top-pick.js +13 -0
- package/dist/miner/acceptance-criteria.d.ts +43 -0
- package/dist/miner/acceptance-criteria.js +77 -0
- package/dist/miner/agent-sdk-driver.d.ts +39 -0
- package/dist/miner/agent-sdk-driver.js +162 -0
- package/dist/miner/attempt-log.d.ts +29 -0
- package/dist/miner/attempt-log.js +100 -0
- package/dist/miner/attempt-metering.d.ts +39 -0
- package/dist/miner/attempt-metering.js +67 -0
- package/dist/miner/cli-subprocess-driver.d.ts +68 -0
- package/dist/miner/cli-subprocess-driver.js +272 -0
- package/dist/miner/coding-agent-driver.d.ts +33 -0
- package/dist/miner/coding-agent-driver.js +36 -0
- package/dist/miner/coding-agent-invoke.d.ts +11 -0
- package/dist/miner/coding-agent-invoke.js +80 -0
- package/dist/miner/coding-agent-mode.d.ts +25 -0
- package/dist/miner/coding-agent-mode.js +43 -0
- package/dist/miner/driver-factory.d.ts +82 -0
- package/dist/miner/driver-factory.js +169 -0
- package/dist/miner/harness-submission-trigger.d.ts +37 -0
- package/dist/miner/harness-submission-trigger.js +46 -0
- package/dist/miner/iterate-loop.d.ts +97 -0
- package/dist/miner/iterate-loop.js +278 -0
- package/dist/miner/iterate-policy.d.ts +98 -0
- package/dist/miner/iterate-policy.js +98 -0
- package/dist/miner/lint-guard.d.ts +50 -0
- package/dist/miner/lint-guard.js +68 -0
- package/dist/miner/local-write-tools.d.ts +81 -0
- package/dist/miner/local-write-tools.js +113 -0
- package/dist/miner/loop-reentry-policy.d.ts +36 -0
- package/dist/miner/loop-reentry-policy.js +53 -0
- package/dist/miner/repo-map.d.ts +51 -0
- package/dist/miner/repo-map.js +268 -0
- package/dist/miner/self-review-adapter.d.ts +106 -0
- package/dist/miner/self-review-adapter.js +83 -0
- package/dist/miner/submission-gate.d.ts +40 -0
- package/dist/miner/submission-gate.js +89 -0
- package/dist/miner/worktree-allocator.d.ts +59 -0
- package/dist/miner/worktree-allocator.js +60 -0
- package/dist/miner/worktree-pool.d.ts +55 -0
- package/dist/miner/worktree-pool.js +65 -0
- package/dist/miner-goal-lane-fit.d.ts +18 -0
- package/dist/miner-goal-lane-fit.js +76 -0
- package/dist/miner-goal-spec.d.ts +139 -0
- package/dist/miner-goal-spec.js +281 -0
- package/dist/miner-prediction-metrics.d.ts +16 -0
- package/dist/miner-prediction-metrics.js +61 -0
- package/dist/miner-telemetry.d.ts +32 -0
- package/dist/miner-telemetry.js +87 -0
- package/dist/objective-anchor.d.ts +125 -0
- package/dist/objective-anchor.js +401 -0
- package/dist/opportunity-competition.d.ts +6 -0
- package/dist/opportunity-competition.js +29 -0
- package/dist/opportunity-freshness.d.ts +18 -0
- package/dist/opportunity-freshness.js +55 -0
- package/dist/opportunity-metadata.d.ts +53 -0
- package/dist/opportunity-metadata.js +204 -0
- package/dist/opportunity-ranker.d.ts +46 -0
- package/dist/opportunity-ranker.js +74 -0
- package/dist/pairwise-calibration.d.ts +49 -0
- package/dist/pairwise-calibration.js +106 -0
- package/dist/phase7-calibration-loop.d.ts +136 -0
- package/dist/phase7-calibration-loop.js +437 -0
- package/dist/plan-blocked.d.ts +6 -0
- package/dist/plan-blocked.js +24 -0
- package/dist/plan-completed.d.ts +5 -0
- package/dist/plan-completed.js +6 -0
- package/dist/plan-completion.d.ts +6 -0
- package/dist/plan-completion.js +7 -0
- package/dist/plan-empty.d.ts +5 -0
- package/dist/plan-empty.js +6 -0
- package/dist/plan-export.d.ts +27 -0
- package/dist/plan-export.js +86 -0
- package/dist/plan-failure.d.ts +5 -0
- package/dist/plan-failure.js +6 -0
- package/dist/plan-overall-status.d.ts +6 -0
- package/dist/plan-overall-status.js +25 -0
- package/dist/plan-pending.d.ts +5 -0
- package/dist/plan-pending.js +6 -0
- package/dist/plan-progress-complete.d.ts +7 -0
- package/dist/plan-progress-complete.js +10 -0
- package/dist/plan-ready.d.ts +6 -0
- package/dist/plan-ready.js +12 -0
- package/dist/plan-running.d.ts +5 -0
- package/dist/plan-running.js +6 -0
- package/dist/plan-skipped.d.ts +5 -0
- package/dist/plan-skipped.js +6 -0
- package/dist/plan-step-count.d.ts +5 -0
- package/dist/plan-step-count.js +6 -0
- package/dist/plan-step-stats.d.ts +5 -0
- package/dist/plan-step-stats.js +6 -0
- package/dist/plan-templates.d.ts +25 -0
- package/dist/plan-templates.js +107 -0
- package/dist/plan-terminated.d.ts +6 -0
- package/dist/plan-terminated.js +9 -0
- package/dist/portfolio/non-convergence.d.ts +37 -0
- package/dist/portfolio/non-convergence.js +57 -0
- package/dist/portfolio/queue.d.ts +30 -0
- package/dist/portfolio/queue.js +150 -0
- package/dist/predicted-gate.d.ts +103 -0
- package/dist/predicted-gate.js +218 -0
- package/dist/prompt-packet.d.ts +11 -0
- package/dist/prompt-packet.js +34 -0
- package/dist/ranked-opportunity-best-min-score.d.ts +8 -0
- package/dist/ranked-opportunity-best-min-score.js +9 -0
- package/dist/ranked-opportunity-best-pick.d.ts +8 -0
- package/dist/ranked-opportunity-best-pick.js +9 -0
- package/dist/ranked-opportunity-min-score.d.ts +8 -0
- package/dist/ranked-opportunity-min-score.js +13 -0
- package/dist/ranked-opportunity-top-min-score.d.ts +8 -0
- package/dist/ranked-opportunity-top-min-score.js +13 -0
- package/dist/review/advisory-ai-routing-config.d.ts +8 -0
- package/dist/review/advisory-ai-routing-config.js +40 -0
- package/dist/review/check-names.d.ts +1 -0
- package/dist/review/check-names.js +1 -0
- package/dist/review/cla-check.d.ts +49 -0
- package/dist/review/cla-check.js +71 -0
- package/dist/review/diff-file-priority.d.ts +1 -0
- package/dist/review/diff-file-priority.js +12 -0
- package/dist/review/enrichment-analyzer-names.d.ts +3 -0
- package/dist/review/enrichment-analyzer-names.js +63 -0
- package/dist/review/guardrail-config.d.ts +10 -0
- package/dist/review/guardrail-config.js +62 -0
- package/dist/review/linked-issue-hard-rules-config.d.ts +4 -0
- package/dist/review/linked-issue-hard-rules-config.js +79 -0
- package/dist/review/linked-issue-label-propagation.d.ts +9 -0
- package/dist/review/linked-issue-label-propagation.js +114 -0
- package/dist/review/pre-merge-checks.d.ts +28 -0
- package/dist/review/pre-merge-checks.js +66 -0
- package/dist/review/review-thread-findings.d.ts +1 -0
- package/dist/review/review-thread-findings.js +1 -0
- package/dist/review/safe-url.d.ts +5 -0
- package/dist/review/safe-url.js +137 -0
- package/dist/review/screenshot-table-gate.d.ts +87 -0
- package/dist/review/screenshot-table-gate.js +340 -0
- package/dist/review/unlinked-issue-guardrail-config.d.ts +9 -0
- package/dist/review/unlinked-issue-guardrail-config.js +44 -0
- package/dist/reviewer-consensus-calibration.d.ts +113 -0
- package/dist/reviewer-consensus-calibration.js +493 -0
- package/dist/reward-risk.d.ts +223 -0
- package/dist/reward-risk.js +618 -0
- package/dist/scoring/label-match.d.ts +4 -0
- package/dist/scoring/label-match.js +145 -0
- package/dist/scoring/model.d.ts +31 -0
- package/dist/scoring/model.js +157 -0
- package/dist/scoring/pending-pr-scenarios.d.ts +44 -0
- package/dist/scoring/pending-pr-scenarios.js +145 -0
- package/dist/scoring/preview.d.ts +246 -0
- package/dist/scoring/preview.js +1108 -0
- package/dist/scoring/types.d.ts +131 -0
- package/dist/scoring/types.js +7 -0
- package/dist/settings/auto-close-exempt.d.ts +10 -0
- package/dist/settings/auto-close-exempt.js +58 -0
- package/dist/settings/autonomy.d.ts +33 -0
- package/dist/settings/autonomy.js +80 -0
- package/dist/settings/command-authorization.d.ts +49 -0
- package/dist/settings/command-authorization.js +222 -0
- package/dist/settings/contributor-blacklist.d.ts +17 -0
- package/dist/settings/contributor-blacklist.js +86 -0
- package/dist/settings/moderation-rules.d.ts +51 -0
- package/dist/settings/moderation-rules.js +104 -0
- package/dist/settings/pr-type-label.d.ts +70 -0
- package/dist/settings/pr-type-label.js +149 -0
- package/dist/signals/change-guardrail.d.ts +49 -0
- package/dist/signals/change-guardrail.js +164 -0
- package/dist/signals/check-summary.d.ts +9 -0
- package/dist/signals/check-summary.js +12 -0
- package/dist/signals/contributor-calibration.d.ts +23 -0
- package/dist/signals/contributor-calibration.js +47 -0
- package/dist/signals/duplicate-winner.d.ts +9 -0
- package/dist/signals/duplicate-winner.js +9 -0
- package/dist/signals/path-matchers.d.ts +36 -0
- package/dist/signals/path-matchers.js +371 -0
- package/dist/signals/predicted-gate-engine.d.ts +62 -0
- package/dist/signals/predicted-gate-engine.js +895 -0
- package/dist/signals/preflight-limits.d.ts +14 -0
- package/dist/signals/preflight-limits.js +14 -0
- package/dist/signals/slop.d.ts +56 -0
- package/dist/signals/slop.js +324 -0
- package/dist/signals/test-evidence.d.ts +25 -0
- package/dist/signals/test-evidence.js +108 -0
- package/dist/subprocess-env.d.ts +23 -0
- package/dist/subprocess-env.js +74 -0
- package/dist/track-record-summary.d.ts +92 -0
- package/dist/track-record-summary.js +301 -0
- package/dist/types/manifest-deps-types.d.ts +514 -0
- package/dist/types/manifest-deps-types.js +4 -0
- package/dist/types/predicted-gate-types.d.ts +338 -0
- package/dist/types/predicted-gate-types.js +3 -0
- package/dist/types/reward-risk-types.d.ts +319 -0
- package/dist/types/reward-risk-types.js +11 -0
- package/dist/utils/json.d.ts +1 -0
- package/dist/utils/json.js +3 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/package.json +80 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import type { AdvisoryAiRoutingConfig, AiReviewLowConfidenceDisposition, CombineStrategy, GatePolicyPack, GateRuleMode, JsonValue, LinkedIssueHardRulesConfig, LinkedIssueLabelPropagationConfig, OnMerge, PrTypeLabelSet, RepositorySettings, ReviewCheckMode, ScreenshotTableGateConfig, UnlinkedIssueGuardrailConfig } from "./types/manifest-deps-types.js";
|
|
2
|
+
import { type ReesAnalyzerName } from "./review/enrichment-analyzer-names.js";
|
|
3
|
+
export type FocusManifestSource = "repo_file" | "api_record" | "none";
|
|
4
|
+
export type FocusManifestLinkedIssuePolicy = "required" | "preferred" | "optional";
|
|
5
|
+
export type FocusManifestIssueDiscoveryPolicy = "encouraged" | "neutral" | "discouraged";
|
|
6
|
+
/**
|
|
7
|
+
* Maintainer-authored gate configuration declared as code in `.gittensory.yml` under `gate:`. Each
|
|
8
|
+
* field is `null` when the maintainer did not set it, so the resolver can layer the manifest OVER the
|
|
9
|
+
* DB-backed RepositorySettings (manifest > DB > safe defaults) without clobbering unset values. All
|
|
10
|
+
* of these flow through the SAME confirmed-contributor-gated `evaluateGateCheck` path — the manifest
|
|
11
|
+
* only chooses which deterministic blockers are active, never who can be blocked. There is no single
|
|
12
|
+
* gate master switch: each per-dimension mode (`linkedIssue`, `duplicates`, `readinessMode`, etc.)
|
|
13
|
+
* independently controls whether that dimension evaluates. `checkMode`/`enabled` (#2852) is a separate
|
|
14
|
+
* axis entirely: whether/how the "LoopOver Orb Review Agent" check-RUN publishes, independent of gate
|
|
15
|
+
* evaluation itself (which always runs regardless of `checkMode`/`enabled`) — see {@link ReviewCheckMode}.
|
|
16
|
+
*/
|
|
17
|
+
export type FocusManifestGateConfig = {
|
|
18
|
+
present: boolean;
|
|
19
|
+
/** `gate.enabled` (legacy): a boolean shorthand for `checkMode` below -- `true` maps to `"required"`,
|
|
20
|
+
* `false` maps to `"disabled"` (see resolveEffectiveSettings/applyGateConfigOverrides). Despite the name,
|
|
21
|
+
* this controls ONLY whether the "LoopOver Orb Review Agent" check-run publishes -- it has NO effect on
|
|
22
|
+
* gate evaluation, disposition, comments, labels, audit, spend, or autonomous merge/close, all of which run
|
|
23
|
+
* identically regardless of this field. It also cannot express `checkMode`'s third state (`"visible"`), and
|
|
24
|
+
* is silently ignored once `checkMode` is set (see the parse-time warning a few lines below this type).
|
|
25
|
+
* Caused two real incidents under this exact ambiguity (2026-07: an operator flipping `enabled` to restore
|
|
26
|
+
* unrelated spend/gate behavior twice got a surprise check-run side effect instead) -- prefer `checkMode`
|
|
27
|
+
* explicitly for any new config. */
|
|
28
|
+
enabled: boolean | null;
|
|
29
|
+
/** `gate.checkMode` (#2852): explicit required|visible|disabled review-check publish mode. Takes
|
|
30
|
+
* precedence over the legacy `enabled` boolean above when both are set (see resolveEffectiveSettings).
|
|
31
|
+
* null (unset) ⇒ fall back to `enabled`, then to `settings.reviewCheckMode` (DB/dashboard), then default. */
|
|
32
|
+
checkMode: ReviewCheckMode | null;
|
|
33
|
+
pack: GatePolicyPack | null;
|
|
34
|
+
linkedIssue: GateRuleMode | null;
|
|
35
|
+
duplicates: GateRuleMode | null;
|
|
36
|
+
/** `gate.readiness.mode`/`gate.readiness.minScore` -- this engine-layer pair folds into
|
|
37
|
+
* `RepositorySettings.qualityGateMode`/`qualityGateMinScore` (src/signals/focus-manifest.ts), a third
|
|
38
|
+
* spelling of the same concept alongside the yml key name; the `readiness` gate is distinct from the
|
|
39
|
+
* separate `mergeReadiness` composite gate above. */
|
|
40
|
+
readinessMode: GateRuleMode | null;
|
|
41
|
+
readinessMinScore: number | null;
|
|
42
|
+
slopMode: GateRuleMode | null;
|
|
43
|
+
slopMinScore: number | null;
|
|
44
|
+
slopAiAdvisory: boolean | null;
|
|
45
|
+
sizeMode: GateRuleMode | null;
|
|
46
|
+
/** `gate.lockfileIntegrity` (#2563): off|advisory|block, off by default. When not off, a changed
|
|
47
|
+
* `package-lock.json` diff is scanned for a `resolved`/`integrity` change unaccompanied by a matching
|
|
48
|
+
* `package.json` version bump, or a `resolved` URL outside `registry.npmjs.org` — a `lockfile_tamper_risk`
|
|
49
|
+
* finding (`block` additionally hard-blocks). Config-as-code only — no DB column or dashboard toggle. */
|
|
50
|
+
lockfileIntegrityMode: GateRuleMode | null;
|
|
51
|
+
aiReviewMode: GateRuleMode | null;
|
|
52
|
+
aiReviewByok: boolean | null;
|
|
53
|
+
aiReviewProvider: "anthropic" | "openai" | null;
|
|
54
|
+
aiReviewModel: string | null;
|
|
55
|
+
aiReviewAllAuthors: boolean | null;
|
|
56
|
+
/** `gate.aiReview.closeConfidence` (#7): minimum calibrated AI-reviewer confidence (0-1) for an AI defect to BLOCK
|
|
57
|
+
* under `aiReview.mode: block`. null (unset) ⇒ the gate's 0.93 default. Clamped to [0,1] at parse time. */
|
|
58
|
+
aiReviewCloseConfidence: number | null;
|
|
59
|
+
/** `gate.aiReview.lowConfidenceDisposition` (#4603): disposition for a sub-`closeConfidence`-floor
|
|
60
|
+
* `ai_consensus_defect`/`ai_review_split` finding. null (unset) ⇒ `hold_for_review` (the shipped default).
|
|
61
|
+
* DB-backed (dashboard-settable too, via the `/ai-review` route); this overrides the stored value -- mirrors
|
|
62
|
+
* `aiReviewMode` above, not the config-as-code-only `closeConfidence` sibling field just above. */
|
|
63
|
+
aiReviewLowConfidenceDisposition: AiReviewLowConfidenceDisposition | null;
|
|
64
|
+
/** `gate.aiReview.combine` (#2567): per-repo override of the self-host operator's `AI_REVIEW_PLAN.combine`
|
|
65
|
+
* boot default (single/consensus/synthesis). null (unset) ⇒ the operator's plan (or `consensus`). A
|
|
66
|
+
* REFINEMENT only — see {@link aiReviewOnMerge} for the operator-floor clamp `runGittensoryAiReview` applies
|
|
67
|
+
* to the paired `onMerge` field; `combine` itself is not floor-clamped (the three strategies are not ordered
|
|
68
|
+
* by strictness, so there is no single "loosening" direction to clamp). */
|
|
69
|
+
aiReviewCombine: CombineStrategy | null;
|
|
70
|
+
/** `gate.aiReview.onMerge` (#2567): per-repo override of the `synthesis` merge rule. `either` is the STRICTER
|
|
71
|
+
* rule (any one reviewer's blocker blocks/holds); `both` is more PERMISSIVE (requires every reviewer to
|
|
72
|
+
* agree). null (unset) ⇒ the operator's `AI_REVIEW_PLAN.onMerge`. A repo may only TIGHTEN the operator's
|
|
73
|
+
* floor (never loosen `either` down to `both`) — `runGittensoryAiReview` enforces the clamp at resolve time,
|
|
74
|
+
* since only it can see both the per-repo value and the operator's plan. */
|
|
75
|
+
aiReviewOnMerge: OnMerge | null;
|
|
76
|
+
/** `gate.aiReview.reviewers` (#2567): per-repo override of the named reviewer pair(s) to run, in place of the
|
|
77
|
+
* operator's `AI_REVIEW_PLAN.reviewers` (or the free Workers-AI pair when the operator configured none). null
|
|
78
|
+
* (unset) ⇒ the operator's plan. No operator floor applies to WHICH reviewers run (only `onMerge` gates
|
|
79
|
+
* strictness), so this always wins unclamped when set. */
|
|
80
|
+
aiReviewReviewers: ReadonlyArray<{
|
|
81
|
+
model: string;
|
|
82
|
+
fallback?: string | null | undefined;
|
|
83
|
+
}> | null;
|
|
84
|
+
mergeReadiness: GateRuleMode | null;
|
|
85
|
+
manifestPolicy: GateRuleMode | null;
|
|
86
|
+
selfAuthoredLinkedIssue: GateRuleMode | null;
|
|
87
|
+
/** `gate.linkedIssueSatisfaction` (#1961/#3906): off|advisory|block, off by default. When not off, an AI
|
|
88
|
+
* assessment of whether the PR's diff satisfies its primary linked issue's intent runs and renders as a
|
|
89
|
+
* collapsible section in the review comment; `block` additionally lets a confidence-floor-passing
|
|
90
|
+
* "unaddressed" verdict become a hard blocker. DB-backed (dashboard-settable too); this overrides the
|
|
91
|
+
* stored value -- mirrors `aiReviewMode` above, not the config-as-code-only `unlinkedIssueGuardrail`
|
|
92
|
+
* pattern. Distinct from the pre-existing, config-as-code-only `review.linkedIssueSatisfaction` (#2173,
|
|
93
|
+
* below) in type and storage -- but as of #4149 (`src/signals/focus-manifest.ts`'s
|
|
94
|
+
* `resolveEffectiveSettings`, ~line 611-618) `review.linkedIssueSatisfaction` IS folded in as a
|
|
95
|
+
* fallback alias whenever this `gate:` field is unset, so setting either spelling drives the same real
|
|
96
|
+
* merge/close decision. See `src/types.ts`'s `linkedIssueSatisfactionGateMode` doc for the authoritative
|
|
97
|
+
* cross-reference. */
|
|
98
|
+
linkedIssueSatisfaction: GateRuleMode | null;
|
|
99
|
+
dryRun: boolean | null;
|
|
100
|
+
firstTimeContributorGrace: boolean | null;
|
|
101
|
+
/** `gate.premergeContentRecheck` (#2550): for a PR touching `migrations/**`, re-verify against a live,
|
|
102
|
+
* freshly-fetched tip of the base branch — unioned with this PR's own new migration filenames — for a
|
|
103
|
+
* migration-number collision immediately before an agent-driven merge, not just at CI time against the
|
|
104
|
+
* PR's own stale branch snapshot. On a live collision, the merge is suppressed and the PR is held with a
|
|
105
|
+
* rebase-needed comment instead of merging blind. null (unset) ⇒ off (byte-identical to today) — this
|
|
106
|
+
* costs one extra, uncached GitHub Trees-API call for any PR that touches migrations/**, so it is opt-in
|
|
107
|
+
* rather than a new default. */
|
|
108
|
+
premergeContentRecheck: boolean | null;
|
|
109
|
+
/** `gate.requireFreshRebaseWindow` (#2552, anti-race): minutes. When the base branch has advanced within
|
|
110
|
+
* this window of the actual merge-decision moment, an agent-driven merge forces an `update_branch` +
|
|
111
|
+
* fresh CI recheck cycle before merging, instead of trusting a `mergeableState: clean` read that may
|
|
112
|
+
* already be stale relative to a sibling commit that just landed on the base. null (unset) ⇒ never force
|
|
113
|
+
* (byte-identical to today) — a discrete positive-minutes count, not a score, so it is neither clamped
|
|
114
|
+
* nor rounded; an invalid value (fractional, non-positive, non-finite) is dropped with a warning. */
|
|
115
|
+
requireFreshRebaseWindowMinutes: number | null;
|
|
116
|
+
/** `gate.claMode` (#2564): off/advisory/block. null (unset) ⇒ off (byte-identical to today) — a repo must
|
|
117
|
+
* explicitly opt in before any CLA consent check runs. */
|
|
118
|
+
claMode: GateRuleMode | null;
|
|
119
|
+
/** `gate.cla.consentPhrase` (#2564): the required PR-body consent phrase. null (unset) ⇒ phrase-match
|
|
120
|
+
* detection is not configured. */
|
|
121
|
+
claConsentPhrase: string | null;
|
|
122
|
+
/** `gate.cla.checkRunName` (#2564): the CLA-bot check-run name to trust. null (unset) ⇒ check-run
|
|
123
|
+
* detection is not configured. */
|
|
124
|
+
claCheckRunName: string | null;
|
|
125
|
+
/** `gate.cla.checkRunAppSlug`: the trusted GitHub App slug that must produce `checkRunName`. null (unset) ⇒
|
|
126
|
+
* check-run detection remains unresolved rather than trusting a spoofable name-only match. */
|
|
127
|
+
claCheckRunAppSlug: string | null;
|
|
128
|
+
/** `gate.expectedCiContexts` (#selfhost-ci-verification): CI check/status context names to treat as
|
|
129
|
+
* required when GitHub branch-protection required-status-checks are unreadable or unconfigured. null
|
|
130
|
+
* (unset) ⇒ no generic fallback configured — the live-CI aggregate keeps today's fold-all behavior
|
|
131
|
+
* when branch protection is also unreadable. See {@link RepositorySettings.expectedCiContexts}. */
|
|
132
|
+
expectedCiContexts: ReadonlyArray<string> | null;
|
|
133
|
+
/** `gate.aiJudgmentBlockers` (#3907): "gate" | "advisory", null (unset) ⇒ "advisory" (byte-identical to
|
|
134
|
+
* today everywhere that doesn't opt in). Config-as-code only, YML-only (no DB column, no dashboard
|
|
135
|
+
* toggle) — mirrors `contentLane`'s own YML-only shape, since this only has an effect for repos already
|
|
136
|
+
* running the registry content lane. When "gate", a confident AI-judgment-only finding that
|
|
137
|
+
* applySurfaceGate's default "advisory" behavior would otherwise let a decisive surface merge override
|
|
138
|
+
* instead SURVIVES into the deterministic gate's own blockers array, demoting `decision` away from
|
|
139
|
+
* `merge` — see content-lane-wire.ts's `applySurfaceGate` guard #3 and `evaluateWithSurfaceLane` for the
|
|
140
|
+
* wiring. This deliberately reopens exactly the risk #2592 accepted for the general case (an AI
|
|
141
|
+
* hallucination can one-shot-close a structurally-clean PR) as an explicit, per-repo, documented
|
|
142
|
+
* trade-off — never the default. */
|
|
143
|
+
aiJudgmentBlockersMode: "gate" | "advisory" | null;
|
|
144
|
+
/** `gate.copycat.mode` (#1969): off|warn|label|block, off by default. Config-as-code only -- no DB column
|
|
145
|
+
* or dashboard toggle. Deliberately a DEDICATED 4-value enum, not the shared `GateRuleMode` tri-state: the
|
|
146
|
+
* issue's tiered response is warn -> label -> block -> strikes, where "strikes" is a separate escalation
|
|
147
|
+
* action (reusing the existing cross-repo banned-contributors ledger once wired) rather than a 5th mode
|
|
148
|
+
* value. THIS FIELD IS CURRENTLY INERT -- the similarity/containment detection engine that would actually
|
|
149
|
+
* compute a copycat finding does not exist yet (tracked as later, separate PRs against #1969); parsing and
|
|
150
|
+
* threading this config end-to-end first proves the plumbing and lets an operator's `.gittensory.yml`
|
|
151
|
+
* already declare intent without waiting on the detection engine. */
|
|
152
|
+
copycatMode: CopycatGateMode | null;
|
|
153
|
+
/** `gate.copycat.minScore` (#1969): containment/similarity score (0-100) at/above which `copycatMode` acts.
|
|
154
|
+
* null (unset) ⇒ the (also currently inert) engine's own default threshold once it exists. Same 0-100
|
|
155
|
+
* clamp-and-round normalization as `slopMinScore`/`readinessMinScore` above. */
|
|
156
|
+
copycatMinScore: number | null;
|
|
157
|
+
};
|
|
158
|
+
/** `gate.copycat.mode` (#1969) -- see {@link FocusManifestGateConfig.copycatMode}'s doc comment for why this
|
|
159
|
+
* is a dedicated enum rather than the shared `GateRuleMode`. */
|
|
160
|
+
export type CopycatGateMode = "off" | "warn" | "label" | "block";
|
|
161
|
+
export declare const CONVERGED_FEATURE_KEYS: readonly ["rag", "reputation", "unifiedComment", "safety", "grounding", "e2eTests", "screenshots", "improvementSignal"];
|
|
162
|
+
export type ConvergedFeatureKey = (typeof CONVERGED_FEATURE_KEYS)[number];
|
|
163
|
+
/** Per-repo activation overrides for the converged review features (`features:` block). `true`/`false` force the
|
|
164
|
+
* feature on/off for THIS repo (subject to the env kill-switch); `null` (unset) ⇒ the resolver falls back to the
|
|
165
|
+
* `GITTENSORY_REVIEW_REPOS` allowlist default, so an operator who sets nothing keeps today's behavior. */
|
|
166
|
+
export type FocusManifestFeaturesConfig = {
|
|
167
|
+
present: boolean;
|
|
168
|
+
} & Record<ConvergedFeatureKey, boolean | null>;
|
|
169
|
+
/** Optional ecosystem/network integrations under the `experimental:` block — plugins that couple gittensory to
|
|
170
|
+
* an external system rather than core review behavior. Starts with `gittensor` (the subnet mining-registry/
|
|
171
|
+
* scoring integration gittensory originally shipped with); future plugins land in this same array as the
|
|
172
|
+
* product broadens beyond gittensor. Deliberately a SEPARATE block from `features:` (converged review
|
|
173
|
+
* capabilities) — an operator (especially self-host) should be able to see at a glance which toggles are "how
|
|
174
|
+
* gittensory reviews PRs" vs "which external network/ecosystem this instance opts into." */
|
|
175
|
+
export declare const EXPERIMENTAL_PLUGIN_KEYS: readonly ["gittensor"];
|
|
176
|
+
export type ExperimentalPluginKey = (typeof EXPERIMENTAL_PLUGIN_KEYS)[number];
|
|
177
|
+
/** Per-repo activation for `experimental:` plugins. Unlike `features:`, there is no `GITTENSORY_REVIEW_REPOS`
|
|
178
|
+
* allowlist fallback for ANY key here — every plugin is the "manifestOnly" precedence shape
|
|
179
|
+
* (`resolveManifestOnlyFeature`): OFF unless the operator's global env kill-switch AND an explicit per-repo
|
|
180
|
+
* `true` are BOTH set. So an instance that never opts in has zero footprint from any experimental plugin. */
|
|
181
|
+
export type FocusManifestExperimentalConfig = {
|
|
182
|
+
present: boolean;
|
|
183
|
+
} & Record<ExperimentalPluginKey, boolean | null>;
|
|
184
|
+
/**
|
|
185
|
+
* Per-repo registry-review lane configuration (`contentLane:` block, #2435) — lets a self-hosted maintainer
|
|
186
|
+
* configure their OWN registry (structural file-scope patterns + entry-count cap + dedup fields) without a
|
|
187
|
+
* gittensory code change. `entryFileGlob` and `collectionField` are the two REQUIRED fields to build a usable
|
|
188
|
+
* spec; `present` is true only when both are set (a partial config degrades to "not configured," not a broken
|
|
189
|
+
* half-spec — see `parseContentLaneConfig`). `validatorId` optionally references a code-registered domain
|
|
190
|
+
* validator (`review/content-lane/spec-resolver.ts`'s `REGISTRY_VALIDATORS`); omitted ⇒ structural gating only
|
|
191
|
+
* (scope/count/dedup), no domain-specific semantic check — see `RegistryLaneSpec.assessAppendedEntry`.
|
|
192
|
+
*/
|
|
193
|
+
export type FocusManifestContentLaneConfig = {
|
|
194
|
+
present: boolean;
|
|
195
|
+
entryFileGlob: string | null;
|
|
196
|
+
providerFileGlob: string | null;
|
|
197
|
+
artifactGlob: string | null;
|
|
198
|
+
collectionField: string | null;
|
|
199
|
+
maxAppendedEntries: number | null;
|
|
200
|
+
duplicateKeyFields: string[];
|
|
201
|
+
validatorId: string | null;
|
|
202
|
+
};
|
|
203
|
+
/** Which generated-file types the repo-doc generation roadmap (#2993) is allowed to touch for a repo.
|
|
204
|
+
* "agents" covers AGENTS.md/CLAUDE.md (#3000/#3004); "skills" covers generated Claude Code/Codex skill
|
|
205
|
+
* files once that generator lands (#3001) -- listed here now so a maintainer can opt in ahead of time. */
|
|
206
|
+
export type FocusManifestRepoDocGenerationScope = "agents" | "skills";
|
|
207
|
+
/**
|
|
208
|
+
* Per-repo opt-in for the repo-doc generation roadmap (#2993/#3002), declared as code under
|
|
209
|
+
* `repoDocGeneration:`. Purely a `.gittensory.yml` surface -- there is no DB-backed dashboard counterpart,
|
|
210
|
+
* so precedence is simply "the manifest value, or the default below when unset" (no DB layer to overlay).
|
|
211
|
+
* Defaults to fully disabled: a repo with no `repoDocGeneration:` block, or an explicit `enabled: false`,
|
|
212
|
+
* is never touched by the generator. `allowOverwriteExisting` is a SEPARATE opt-in specifically for a repo
|
|
213
|
+
* that already has a hand-maintained AGENTS.md/CLAUDE.md (no recognizable generated-content marker block,
|
|
214
|
+
* per generated-doc-refresh.ts's `manual-review-required` outcome) -- without it, that repo is left alone
|
|
215
|
+
* rather than proposed for a wholesale overwrite, even when `enabled` is true.
|
|
216
|
+
*/
|
|
217
|
+
export type FocusManifestRepoDocGenerationConfig = {
|
|
218
|
+
present: boolean;
|
|
219
|
+
enabled: boolean;
|
|
220
|
+
scope: FocusManifestRepoDocGenerationScope[];
|
|
221
|
+
allowOverwriteExisting: boolean;
|
|
222
|
+
/** How many days must elapse between scheduled refresh attempts for this repo (#3003). Default 7 (weekly).
|
|
223
|
+
* Purely a rate-limiting knob on the SCHEDULED sweep -- it never affects correctness, since
|
|
224
|
+
* openRepoDocPullRequest's own no-change short-circuit already prevents a redundant PR regardless of how
|
|
225
|
+
* often it's invoked; this just avoids re-checking a stable repo more often than the operator wants. */
|
|
226
|
+
refreshIntervalDays: number;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Per-repo opt-in for the periodic maintainer review-recap digest (#1963), declared as code under
|
|
230
|
+
* `reviewRecap:`. Mirrors `repoDocGeneration:` exactly: no DB-backed dashboard counterpart, so the parsed
|
|
231
|
+
* value (or the default below when unset) IS the effective value — there is no DB layer to overlay onto.
|
|
232
|
+
* Defaults to fully disabled: a repo with no `reviewRecap:` block, or an explicit `enabled: false`, never
|
|
233
|
+
* gets a recap posted. Discord delivery ONLY for now (reuses the SAME per-repo webhook resolution as the
|
|
234
|
+
* per-event notifier in notify-discord.ts, `resolveDiscordWebhook`) — Slack is a follow-up.
|
|
235
|
+
*/
|
|
236
|
+
export type FocusManifestReviewRecapConfig = {
|
|
237
|
+
present: boolean;
|
|
238
|
+
enabled: boolean;
|
|
239
|
+
/** How many days of review activity each recap covers, and (once the scheduler follow-up lands) how often
|
|
240
|
+
* it is posted. Default 7 (weekly). A purely descriptive/rate-limiting knob today — this PR ships only
|
|
241
|
+
* the manually-triggerable builder + delivery, so `cadenceDays` currently just sets the report WINDOW;
|
|
242
|
+
* the scheduled cron trigger is a scoped follow-up (see the PR description). */
|
|
243
|
+
cadenceDays: number;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Config-as-code override for the CROSS-repo maintainer recap digest's cron knobs (#1963, #2250), declared
|
|
247
|
+
* under `maintainerRecap:`. Distinct from `reviewRecap:` above (that is the single-repo digest's own window/
|
|
248
|
+
* enable knob); this instead overrides the GITTENSORY_MAINTAINER_RECAP / GITTENSORY_RECAP_CADENCE env vars
|
|
249
|
+
* that gate the cron-scheduled cross-repo digest (buildMaintainerRecap, #2239 / #2248) — read from the
|
|
250
|
+
* gittensory self-repo's manifest (resolveGittensorySelfRepoFullName), since the digest is an operator-level
|
|
251
|
+
* setting, not a per-contributor-repo one. Mirrors `reviewRecap:` exactly: no DB-backed counterpart, so the
|
|
252
|
+
* parsed value (or the default below when unset) IS the effective value. Not present (or present with no
|
|
253
|
+
* fields set) ⇒ the caller falls back to the env vars, byte-identical to before this override existed.
|
|
254
|
+
*/
|
|
255
|
+
export type FocusManifestMaintainerRecapConfig = {
|
|
256
|
+
present: boolean;
|
|
257
|
+
enabled: boolean;
|
|
258
|
+
cadence: "daily" | "weekly";
|
|
259
|
+
/** Delivery channel for the digest. Discord-only for now (mirrors deliverRecapToDiscord, #2245) — Slack
|
|
260
|
+
* delivery for this cross-repo digest is a follow-up, so any other value falls back to "discord". */
|
|
261
|
+
channel: "discord";
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Generic repository-settings override declared in `.gittensory.yml` under `settings:`. A partial of
|
|
265
|
+
* {@link RepositorySettings} — every behaviour a maintainer can toggle in the dashboard can be set here
|
|
266
|
+
* as code. Unset fields are omitted so the resolver layers it OVER the DB-backed settings
|
|
267
|
+
* (`.gittensory.yml` > dashboard settings > safe defaults). The friendly `gate:` block is a typed alias
|
|
268
|
+
* for the gate-related subset and wins over `settings:` for those fields.
|
|
269
|
+
*/
|
|
270
|
+
export type FocusManifestSettings = Partial<Pick<RepositorySettings, "commentMode" | "publicAudienceMode" | "publicSignalLevel" | "checkRunMode" | "checkRunDetailLevel" | "regateSweepOrderMode" | "reviewCheckMode" | "autoProjectMilestoneMatch" | "autoProjectMilestoneMatchBackend" | "linkedIssueGateMode" | "duplicatePrGateMode" | "selfAuthoredLinkedIssueGateMode" | "qualityGateMode" | "qualityGateMinScore" | "aiReviewMode" | "aiReviewByok" | "aiReviewProvider" | "aiReviewModel" | "aiReviewAllAuthors" | "closeOwnerAuthors" | "autoLabelEnabled" | "typeLabelsEnabled" | "badgeEnabled" | "publicQualityMetrics" | "gittensorLabel" | "createMissingLabel" | "publicSurface" | "includeMaintainerAuthors" | "requireLinkedIssue" | "backfillEnabled" | "autonomy" | "autoMaintain" | "agentPaused" | "agentDryRun" | "agentGlobalFreezeOverride" | "commandAuthorization" | "contributorBlacklist" | "blacklistLabel" | "contributorOpenPrCap" | "contributorOpenIssueCap" | "contributorCapLabel" | "contributorCapCancelCi" | "reviewNagPolicy" | "reviewNagMaxPings" | "reviewNagCooldownDays" | "reviewNagLabel" | "reviewNagMonitoredMentions" | "autoCloseExemptLogins" | "hardGuardrailGlobs" | "manualReviewLabel" | "readyToMergeLabel" | "changesRequestedLabel" | "migrationCollisionLabel" | "pendingClosureLabel" | "accountAgeThresholdDays" | "newAccountLabel" | "commandRateLimitPolicy" | "commandRateLimitMaxPerWindow" | "commandRateLimitAiMaxPerWindow" | "commandRateLimitWindowHours" | "moderationGateMode" | "moderationRules" | "moderationWarningLabel" | "moderationBannedLabel" | "reviewEvasionProtection" | "reviewEvasionLabel" | "reviewEvasionComment" | "mergeTrainMode">> & {
|
|
271
|
+
typeLabels?: Partial<PrTypeLabelSet> | null | undefined;
|
|
272
|
+
linkedIssueLabelPropagation?: Partial<LinkedIssueLabelPropagationConfig> | undefined;
|
|
273
|
+
linkedIssueHardRules?: Partial<LinkedIssueHardRulesConfig> | undefined;
|
|
274
|
+
unlinkedIssueGuardrail?: Partial<UnlinkedIssueGuardrailConfig> | undefined;
|
|
275
|
+
screenshotTableGate?: Partial<ScreenshotTableGateConfig> | undefined;
|
|
276
|
+
advisoryAiRouting?: Partial<AdvisoryAiRoutingConfig> | undefined;
|
|
277
|
+
};
|
|
278
|
+
/** Field keys for the public review-panel rows a maintainer can show/hide via `review.fields`. `improvementSignal`
|
|
279
|
+
* (#4744) is the newest: the optional row combining the deterministic structural-improvement tier (#4742) and,
|
|
280
|
+
* where also active, the LLM tier's composed value judgment (#4743) -- default-shown, like every sibling here,
|
|
281
|
+
* when the `improvementSignal` converged feature itself is active for the repo. */
|
|
282
|
+
export declare const REVIEW_FIELD_KEYS: readonly ["linkedIssue", "relatedWork", "reviewLoad", "validationEvidence", "openPrQueue", "contributorContext", "gateResult", "improvementSignal"];
|
|
283
|
+
export type ReviewFieldKey = (typeof REVIEW_FIELD_KEYS)[number];
|
|
284
|
+
export declare const REVIEW_PROFILES: readonly ["chill", "balanced", "assertive"];
|
|
285
|
+
export type ReviewProfile = (typeof REVIEW_PROFILES)[number];
|
|
286
|
+
export type ReviewFindingSeverity = "critical" | "major" | "minor" | "nitpick";
|
|
287
|
+
export declare const REVIEW_FINDING_SEVERITY_LADDER: readonly ["critical", "major", "minor", "nitpick"];
|
|
288
|
+
/**
|
|
289
|
+
* Maintainer overrides for the public review-panel CONTENT, declared under `review:`. Customizes the
|
|
290
|
+
* panel without changing what gittensory measures: a custom public-safe footer lead line, a custom intro
|
|
291
|
+
* note, and per-row show/hide toggles. The Gittensor attribution + register link is ALWAYS appended to
|
|
292
|
+
* the footer regardless (the growth surface is preserved); maintainer text that fails the public-safe
|
|
293
|
+
* filter is dropped, never published.
|
|
294
|
+
*/
|
|
295
|
+
export type FocusManifestReviewConfig = {
|
|
296
|
+
present: boolean;
|
|
297
|
+
footerText: string | null;
|
|
298
|
+
note: string | null;
|
|
299
|
+
fields: Partial<Record<ReviewFieldKey, boolean>>;
|
|
300
|
+
/** `review.enrichment`: per-repo REES enrichment-analyzer toggles (analyzer name → on/off). Only known analyzer
|
|
301
|
+
* keys are kept (unknown keys warn + drop at parse). Empty (default, absent) ⇒ the operator's default analyzer
|
|
302
|
+
* set runs unchanged (byte-identical). (#2050) */
|
|
303
|
+
enrichmentAnalyzers: Partial<Record<ReesAnalyzerName, boolean>>;
|
|
304
|
+
/** `review.profile`: chill / balanced / assertive. null (absent) = balanced = byte-identical reviewer prompt. */
|
|
305
|
+
profile: ReviewProfile | null;
|
|
306
|
+
/** `review.tone`: a bounded public-safe voice brief complementing `review.profile` (e.g. "concise, cite line numbers").
|
|
307
|
+
* Folded into the review-instructions slot at runtime. null (default, absent) ⇒ byte-identical prompt. (#2044) */
|
|
308
|
+
tone: string | null;
|
|
309
|
+
/** `review.security_focus`: when true, the AI reviewer is told to prioritize a security-defect category
|
|
310
|
+
* (injection, authn/authz bypass, secret handling, unsafe deserialization, SSRF, path traversal) with
|
|
311
|
+
* elevated scrutiny, ON TOP OF whatever `profile` volume is set — an orthogonal "what to prioritize" axis,
|
|
312
|
+
* not a fourth profile level. null/false (default, absent) = byte-identical reviewer prompt. (#review-security-focus) */
|
|
313
|
+
securityFocus: boolean | null;
|
|
314
|
+
/** `review.inline_comments`: when true, the AI reviewer ALSO leaves quiet, non-blocking inline PR comments on
|
|
315
|
+
* specific changed lines (in addition to the decision summary). null/false (default, absent) = no inline
|
|
316
|
+
* comments = byte-identical behavior. Operator-gated too (GITTENSORY_REVIEW_INLINE_COMMENTS + allowlist).
|
|
317
|
+
* (#inline-comments) */
|
|
318
|
+
inlineComments: boolean | null;
|
|
319
|
+
/** `review.fixHandoff`: when true, the reviewer emits fix-handoff blocks (copy-paste remediation guidance). null/
|
|
320
|
+
* false (default, absent) = no fix-handoff blocks = byte-identical. Operator-gated too (GITTENSORY_REVIEW_FIX_HANDOFF
|
|
321
|
+
* + the convergence cutover allowlist) — the manifest toggle is only one of the ANDed gates. (#2176, for #1962) */
|
|
322
|
+
fixHandoff: boolean | null;
|
|
323
|
+
/** `review.auto_merge_summary`: when true, the unified comment gains a READ-ONLY collapsible showing which
|
|
324
|
+
* auto-merge conditions currently pass/fail (CI green, gate passing, mergeable-clean, valid linked issue),
|
|
325
|
+
* rendered from already-computed readiness signals. SURFACE ONLY — never changes the merge/close decision.
|
|
326
|
+
* null/false (default, absent) = no summary = byte-identical. (#2051, for #1959) */
|
|
327
|
+
autoMergeSummary: boolean | null;
|
|
328
|
+
/** `review.suggestions`: when true, an inline finding whose AI-provided fix is precise enough to anchor to a
|
|
329
|
+
* single line is ALSO rendered as a GitHub-native ` ```suggestion ` block a contributor can commit in one
|
|
330
|
+
* click. Only takes effect when inline comments are already on (a suggestion has nothing to attach to
|
|
331
|
+
* otherwise) — this is an ADDITIONAL opt-in on top of `review.inline_comments`, not a replacement gate.
|
|
332
|
+
* null/false (default, absent) = no suggestion blocks = byte-identical behavior. (#1956) */
|
|
333
|
+
suggestions: boolean | null;
|
|
334
|
+
/** `review.changed_files_summary`: when true, the unified review comment (only rendered at all when the
|
|
335
|
+
* `unifiedComment` convergence feature is on) gains a deterministic, no-AI "Changed files" collapsible: one
|
|
336
|
+
* row per file category (source/test/docs/config/generated), with file counts and +/- totals, via the
|
|
337
|
+
* existing `classifyChangedFile` classifier (`src/review/changed-files-classify.ts`, built for this table
|
|
338
|
+
* under #2143). null/false (default, absent) = no changed-files section = byte-identical behavior. (#1957) */
|
|
339
|
+
changedFilesSummary: boolean | null;
|
|
340
|
+
/** `review.effort_score`: when true, the unified review comment (only rendered when the `unifiedComment`
|
|
341
|
+
* convergence feature is on) gains a compact "review effort: N/5 (~M min)" chip — a deterministic, no-AI
|
|
342
|
+
* complexity/time estimate from `estimateReviewEffort` (`src/review/review-effort.ts`), weighting each
|
|
343
|
+
* changed file's added lines by its category (source costs most; generated/vendored/lockfiles cost least)
|
|
344
|
+
* plus a fixed per-file overhead. Mirrors `changedFilesSummary` exactly: same table, same deterministic
|
|
345
|
+
* source, same display-only (never touches the AI prompt) shape. null/false (default, absent) = no chip =
|
|
346
|
+
* byte-identical behavior. (#1955) */
|
|
347
|
+
effortScore: boolean | null;
|
|
348
|
+
/** `review.impact_map` (#2184, config slice of #1971): when true, gates BOTH the deterministic impact-map
|
|
349
|
+
* computation (`computeImpactMap`, `src/review/impact-map.ts`) and its rendering as a compact section in
|
|
350
|
+
* the unified review comment (#2185) / additive AI-review grounding context (#2186). Deterministic/display
|
|
351
|
+
* + reference-context only — never touches the gate verdict. ALSO requires the global env kill-switch
|
|
352
|
+
* (`isImpactMapEnabled`, mirroring `isRagEnabled` in `src/review/rag-wire.ts:27`) to be on; the manifest
|
|
353
|
+
* flag alone cannot enable it for a self-host operator who hasn't opted in globally. null/false (default,
|
|
354
|
+
* absent) ⇒ no impact-map computation at all = byte-identical behavior. (#2184) */
|
|
355
|
+
impactMap: boolean | null;
|
|
356
|
+
/** `review.culture_profile` (#2995): when true, the AI reviewer's USER prompt gains an ADDITIVE "REPO
|
|
357
|
+
* QUALITY-CULTURE PROFILE" reference block — typical merged-PR size + common accepted labels, derived
|
|
358
|
+
* deterministically from this repo's OWN `recent_merged_pull_requests` history (see
|
|
359
|
+
* `src/review/repo-culture-profile.ts` / `repo-culture-profile-wire.ts`). Reference-only grounding, exactly
|
|
360
|
+
* like RAG/CI-grounding context: it never becomes a gate/scoring input and never changes the structured
|
|
361
|
+
* output contract. Also requires the global `GITTENSORY_REVIEW_CULTURE_PROFILE` kill-switch to be on (this
|
|
362
|
+
* field only opts THIS repo in once the capability itself is enabled). null/false (default, absent) = no
|
|
363
|
+
* section appended = byte-identical behavior. */
|
|
364
|
+
cultureProfile: boolean | null;
|
|
365
|
+
/** `review.selftune` (#4104): explicit per-repo FORCE-OFF for the self-improvement/auto-tune cron pass
|
|
366
|
+
* (`runSelfTune`, `src/review/selftune-wire.ts`) — `false` excludes this repo from tuning even though it's
|
|
367
|
+
* otherwise agent-configured (`isAgentConfigured`) and the global `GITTENSORY_REVIEW_SELFTUNE` kill-switch is
|
|
368
|
+
* on. Deliberately FORCE-OFF-ONLY (no `true` override): forcing a NON-agent-configured repo INTO tuning would
|
|
369
|
+
* bypass that separate, broader acting-autonomy consent boundary, which this key must not touch. Unlike
|
|
370
|
+
* `impactMap`/`cultureProfile` above, there is no `GITTENSORY_REVIEW_REPOS` allowlist fallback for selftune —
|
|
371
|
+
* its own scoping is `isAgentConfigured`, not the cutover allowlist — so this does NOT live under the generic
|
|
372
|
+
* `features:` block/`resolveConvergedFeature` (see `CONVERGED_FEATURE_KEYS`'s own comment). null/true
|
|
373
|
+
* (default, absent) ⇒ no change to today's agent-configured-repos-only behavior. */
|
|
374
|
+
selftune: boolean | null;
|
|
375
|
+
/** `review.memory` (#2179, config slice of #1964): when true, gates repeat-false-positive SUPPRESSION —
|
|
376
|
+
* before an advisory (non-blocking) AI finding is surfaced in the unified review comment, it is matched
|
|
377
|
+
* against this repo's stored `review_suppression` signals (a maintainer's own past false-positive
|
|
378
|
+
* dismissals, `src/db/repositories.ts`'s `listReviewSuppressions`, migrations/0114) and demoted/dropped on a
|
|
379
|
+
* match (`src/review/review-memory-match.ts`'s `matchSuppressions`). ADVISORY-ONLY BY CONSTRUCTION: it is
|
|
380
|
+
* never applied to gate blockers, so it can never change the merge/close disposition — only which
|
|
381
|
+
* non-blocking nits render. ALSO requires the global env kill-switch (`isReviewMemoryEnabled`, mirroring
|
|
382
|
+
* `isImpactMapEnabled` in `src/review/impact-map-wire.ts`) to be on; the manifest flag alone cannot enable
|
|
383
|
+
* it for a self-host operator who hasn't opted in globally. Fail-safe: a suppression-store read error or
|
|
384
|
+
* matcher throw leaves findings untouched. null/false (default, absent) ⇒ no suppression lookup at all =
|
|
385
|
+
* byte-identical behavior. */
|
|
386
|
+
reviewMemory: boolean | null;
|
|
387
|
+
/** `review.finding_categories`: when true, an inline finding is ALSO tagged with a category (security/
|
|
388
|
+
* correctness/performance/maintainability/tests/style) — the AI reviewer is asked to self-categorize, with a
|
|
389
|
+
* deterministic path/keyword fallback (`classifyFindingCategory`) covering whatever it omits. Only takes
|
|
390
|
+
* effect when inline comments are already on (a category has nothing to categorize otherwise) — this is an
|
|
391
|
+
* ADDITIONAL opt-in on top of `review.inline_comments`, not a replacement gate, mirroring `review.suggestions`.
|
|
392
|
+
* null/false (default, absent) = no category tagging = byte-identical behavior. (#1958) */
|
|
393
|
+
findingCategories: boolean | null;
|
|
394
|
+
/** `review.inline_comments_per_category`: optional per-category sub-cap applied before the total inline-comment
|
|
395
|
+
* cap so one category (e.g. style) cannot crowd out security/correctness findings. null (default, absent) ⇒
|
|
396
|
+
* byte-identical first-seen selection with only the hard total cap. (#2159) */
|
|
397
|
+
inlineCommentsPerCategory: number | null;
|
|
398
|
+
/** `review.min_finding_severity`: display-only floor for AI findings with a severity tier. Findings below the
|
|
399
|
+
* configured level are suppressed from inline comments — never from gate blockers. null (default, absent) ⇒ every
|
|
400
|
+
* finding shown = byte-identical behavior. (#2048) */
|
|
401
|
+
minFindingSeverity: ReviewFindingSeverity | null;
|
|
402
|
+
/** `review.max_findings`: optional caps on how many blocker/nit lines render in the unified review comment.
|
|
403
|
+
* Display-only — never removes a blocker from the gate decision. null sub-fields ⇒ no cap for that list.
|
|
404
|
+
* Default { blockers: null, nits: null } ⇒ byte-identical. (#2049) */
|
|
405
|
+
maxFindings: MaxFindingsConfig;
|
|
406
|
+
/** `review.comment_verbosity`: how much of the unified review comment's collapsible detail renders. `quiet`
|
|
407
|
+
* drops the Nits collapsible and every extra collapsible section (blockers/gate result/signals are never
|
|
408
|
+
* gated by this — only decorative detail is); `detailed` renders every collapsible pre-expanded. null/normal
|
|
409
|
+
* (default, absent) ⇒ byte-identical to today. Net-new vs the changed-files-summary (#1957) and effort-score
|
|
410
|
+
* (#1955) knobs. (#2047) */
|
|
411
|
+
commentVerbosity: CommentVerbosity | null;
|
|
412
|
+
/** `review.e2e_test_delivery` (#4197, part of the #4189 epic): how a `@gittensory generate-tests` result is
|
|
413
|
+
* delivered once `features.e2eTests` is on. `"comment"` (default, null/absent) posts the generated test as
|
|
414
|
+
* a reply comment only — no write access to the PR branch. `"commit"` pushes it as a real commit onto the
|
|
415
|
+
* PR's own head branch (git/trees -> git/commits -> a ref UPDATE, mirroring `repo-doc-pr.ts`'s write
|
|
416
|
+
* chokepoint) — a materially bigger blast radius, so it stays opt-in per repo even with e2eTests already
|
|
417
|
+
* on. `"commit"` mode is additionally blocked at runtime (regardless of this config) for a PR whose author
|
|
418
|
+
* is a confirmed Gittensor miner, to protect the external, upstream-computed score from ever including a
|
|
419
|
+
* maintainer-authored line the miner didn't write themselves — see `src/github/e2e-test-commit.ts`. */
|
|
420
|
+
e2eTestDelivery: E2eTestDeliveryMode | null;
|
|
421
|
+
/** `review.e2e_test_auto_trigger` (#4196, part of the #4189 epic): opts THIS repo into the `manifest_missing_tests`
|
|
422
|
+
* auto-trigger, which promotes that advisory finding into an actual unprompted generation run whenever a PR looks
|
|
423
|
+
* like it needs tests -- separate from `features.e2eTests`, which only unlocks the maintainer-initiated paths
|
|
424
|
+
* (the `@gittensory generate-tests` command and the PR-panel checkbox). Deliberately independent and OFF by
|
|
425
|
+
* default: enabling `e2eTests` for on-demand use must never, by itself, start firing generation unprompted on
|
|
426
|
+
* every under-tested PR (the exact loophole this field closes) -- a maintainer who *wants* the auto-trigger opts
|
|
427
|
+
* in explicitly per repo. null/false (default, absent) ⇒ the auto-trigger never fires, even with e2eTests on;
|
|
428
|
+
* true additionally requires e2eTests to already be enabled (this field alone does nothing). */
|
|
429
|
+
e2eTestAutoTrigger: boolean | null;
|
|
430
|
+
/** `review.path_instructions`: per-path natural-language guidance handed to the AI reviewer when the PR's
|
|
431
|
+
* changed files match the glob. Empty (default) ⇒ byte-identical reviewer prompt. Also consumed by
|
|
432
|
+
* AI-generated E2E test coverage (`resolveE2eTestGenInstructions` in `ai-e2e-test-gen.ts`, #4200) when
|
|
433
|
+
* that feature is enabled — the same maintainer-authored guidance steers both consumers, no separate
|
|
434
|
+
* test-generation-specific instructions schema. (#review-path-instructions) */
|
|
435
|
+
pathInstructions: ReviewPathInstruction[];
|
|
436
|
+
/** `review.instructions`: a repo-level natural-language brief handed to the AI reviewer on EVERY review (vs the
|
|
437
|
+
* per-path path_instructions) — the maintainer's conventions/voice for this repo. Bounded + public-safe at parse
|
|
438
|
+
* time (so it stays cost-cheap, unlike ingesting a whole CLAUDE.md). Also consumed by AI-generated E2E test
|
|
439
|
+
* coverage (#4200) for the same reason as pathInstructions above. null (default, absent) ⇒ byte-identical
|
|
440
|
+
* reviewer prompt. (#review-instructions) */
|
|
441
|
+
instructions: string | null;
|
|
442
|
+
/** `review.exclude_paths`: globs whose matching files are EXCLUDED from the AI review (diff + grounding + RAG)
|
|
443
|
+
* — generated/vendored/lockfiles the maintainer doesn't want reviewed. Empty (default) ⇒ every file is
|
|
444
|
+
* reviewed (byte-identical). Gate/slop/secret-scan are UNAFFECTED — this only narrows the AI review.
|
|
445
|
+
* (#review-exclude-paths) */
|
|
446
|
+
excludePaths: string[];
|
|
447
|
+
/** `review.path_filters`: include + `!`-negation globs that POSITIVELY scope the AI review AFTER
|
|
448
|
+
* `exclude_paths`. Include entries restrict to matching paths; leading `!` entries subtract matches.
|
|
449
|
+
* Both `*` and `**` cross slashes (see `compileManifestPathMatcher`). Empty (default) ⇒ every non-excluded
|
|
450
|
+
* file is reviewed (byte-identical). Gate/slop/secret-scan are UNAFFECTED. (#2043) */
|
|
451
|
+
pathFilters: string[];
|
|
452
|
+
/** `review.pre_merge_checks`: maintainer-declared DETERMINISTIC content assertions (title/description must
|
|
453
|
+
* contain a phrase, a label must be present), optionally gated to a path glob. Each FAILED check surfaces an
|
|
454
|
+
* advisory finding; a check with `enforce: true` becomes a hard gate blocker. Empty (default) ⇒ no finding
|
|
455
|
+
* (byte-identical). No AI judgment is involved. (#review-pre-merge-checks) */
|
|
456
|
+
preMergeChecks: PreMergeCheck[];
|
|
457
|
+
/** `review.auto_review`: deterministic eligibility filters that skip the AI review (never a gate failure).
|
|
458
|
+
* Empty/default ⇒ every PR is reviewed (byte-identical). (#1954 / #2038–#2041) */
|
|
459
|
+
autoReview: AutoReviewConfig;
|
|
460
|
+
/** `review.ai_model`: per-repo self-host reviewer model/effort overrides (claude-code / codex). Self-host only
|
|
461
|
+
* — a hosted (Workers-AI) repo ignores this entirely. All-null (default, absent) ⇒ the operator's global
|
|
462
|
+
* CLAUDE_AI_MODEL/CLAUDE_AI_EFFORT/CODEX_AI_MODEL/CODEX_AI_EFFORT env vars apply unchanged (byte-identical).
|
|
463
|
+
* (#selfhost-ai-model-override) */
|
|
464
|
+
aiModel: SelfHostAiModelConfig;
|
|
465
|
+
/** `review.visual`: per-repo before/after screenshot-capture config (#3609 preview / #3610 routes).
|
|
466
|
+
* All-empty (default, absent) ⇒ byte-identical to today (GitHub-native preview discovery, automatic
|
|
467
|
+
* file-to-route inference, built-in route cap). Only takes effect when the operator has also enabled
|
|
468
|
+
* GITTENSORY_REVIEW_SCREENSHOTS + the repo cutover allowlist — this config narrows/redirects that
|
|
469
|
+
* feature, it never turns it on by itself. */
|
|
470
|
+
visual: VisualConfig;
|
|
471
|
+
/** `review.linkedIssueSatisfaction`: how strictly a linked issue must actually be SATISFIED by the PR — `off`
|
|
472
|
+
* (default; not evaluated), `advisory` (surface a finding), or `block` (can become a hard blocker). CONFIG SLICE
|
|
473
|
+
* ONLY (#2173, for #1961): parsed + normalized here; the merge/close decision that reads this mode is a separate
|
|
474
|
+
* maintainer-only slice. null (default, absent) ⇒ byte-identical to today. */
|
|
475
|
+
linkedIssueSatisfaction: LinkedIssueSatisfactionMode | null;
|
|
476
|
+
/** Runtime provenance when the container-private shared base (`review.shared_config`, #2046) filled review
|
|
477
|
+
* fields from `GITTENSORY_REPO_CONFIG_DIR/_shared/.gittensory.yml`. Never parsed from maintainer YAML —
|
|
478
|
+
* set by the private-config loader only. null (default) ⇒ no shared overlay was applied. */
|
|
479
|
+
sharedConfigSource: string | null;
|
|
480
|
+
};
|
|
481
|
+
/** `review.linkedIssueSatisfaction` modes (#2173). `off` = not evaluated (same as unset). */
|
|
482
|
+
export declare const LINKED_ISSUE_SATISFACTION_MODES: readonly ["off", "advisory", "block"];
|
|
483
|
+
export type LinkedIssueSatisfactionMode = (typeof LINKED_ISSUE_SATISFACTION_MODES)[number];
|
|
484
|
+
/** `review.comment_verbosity` levels (#2047). `normal` = today's behavior (same as unset). */
|
|
485
|
+
export declare const COMMENT_VERBOSITY_LEVELS: readonly ["quiet", "normal", "detailed"];
|
|
486
|
+
export type CommentVerbosity = (typeof COMMENT_VERBOSITY_LEVELS)[number];
|
|
487
|
+
/** `review.e2e_test_delivery` modes (#4197). `comment` = today's behavior (same as unset). */
|
|
488
|
+
export declare const E2E_TEST_DELIVERY_MODES: readonly ["comment", "commit"];
|
|
489
|
+
export type E2eTestDeliveryMode = (typeof E2E_TEST_DELIVERY_MODES)[number];
|
|
490
|
+
/** `review.auto_review.cadence` (#one-shot-review-cadence). `one_shot` = the AI-generated content (main review,
|
|
491
|
+
* slop advisory, linked-issue satisfaction) is produced once per PR and never automatically regenerated
|
|
492
|
+
* afterward — not on a new push, not on CI-check completion, not on a scheduled sweep tick; only an explicit
|
|
493
|
+
* maintainer retrigger (the PR-panel checkbox or `@gittensory review` as a maintainer) spends a fresh call.
|
|
494
|
+
* `continuous` = the traditional behavior — every trigger re-runs AI content generation, subject to each
|
|
495
|
+
* feature's own head-SHA cache. Orthogonal to `aiReviewMode`'s enforcement-strictness axis (off/advisory/
|
|
496
|
+
* block) — the deterministic gate (CI status, mergeability, static-rule blockers) is NEVER affected by this
|
|
497
|
+
* and always re-evaluates on every pass regardless of cadence. */
|
|
498
|
+
export declare const AI_REVIEW_CADENCES: readonly ["one_shot", "continuous"];
|
|
499
|
+
export type AiReviewCadence = (typeof AI_REVIEW_CADENCES)[number];
|
|
500
|
+
/** Per-repo AI review eligibility knobs under `review.auto_review`. Unset fields are byte-identical defaults. */
|
|
501
|
+
export type AutoReviewConfig = {
|
|
502
|
+
/** `review.auto_review.skip_drafts`: when true, draft PRs skip AI review. null (default) ⇒ drafts reviewed as today. (#2038) */
|
|
503
|
+
skipDrafts: boolean | null;
|
|
504
|
+
/** `review.auto_review.cadence`: per-repo override of the AI review re-trigger cadence. null (default) ⇒
|
|
505
|
+
* inherit the operator's fleet-wide GITTENSORY_REVIEW_CONTINUOUS default (itself "one_shot" when unset).
|
|
506
|
+
* (#one-shot-review-cadence) */
|
|
507
|
+
cadence: AiReviewCadence | null;
|
|
508
|
+
/** `review.auto_review.ignore_authors`: author-login globs whose PRs skip AI review. Empty ⇒ every author. (#2039) */
|
|
509
|
+
ignoreAuthors: string[];
|
|
510
|
+
/** `review.auto_review.ignore_title_keywords`: case-insensitive title substrings that skip AI review. Empty ⇒ no skip. (#2040) */
|
|
511
|
+
ignoreTitleKeywords: string[];
|
|
512
|
+
/** `review.auto_review.skip_labels`: case-insensitive PR label names that skip AI review. Empty ⇒ no skip. (#2062) */
|
|
513
|
+
skipLabels: string[];
|
|
514
|
+
/** `review.auto_review.skip_docs_only`: when true, PRs whose every changed file classifies as docs skip AI review.
|
|
515
|
+
* null (default) ⇒ docs PRs reviewed as today. Empty changed-file list ⇒ NOT docs-only (fail-safe eligible). (#2063) */
|
|
516
|
+
skipDocsOnly: boolean | null;
|
|
517
|
+
/** `review.auto_review.max_added_lines`: skip AI review when total added lines exceed this cap. 0 (default) ⇒ no cap. (#2065) */
|
|
518
|
+
maxAddedLines: number;
|
|
519
|
+
/** `review.auto_review.max_files`: skip AI review when changed-file count exceeds this cap. 0 (default) ⇒ no cap. (#2065) */
|
|
520
|
+
maxFiles: number;
|
|
521
|
+
/** `review.auto_review.base_branches`: base-ref globs whose PRs ARE reviewed; empty/unset ⇒ every base. (#2041) */
|
|
522
|
+
baseBranches: string[];
|
|
523
|
+
/** `review.auto_review.auto_pause_after_reviewed_commits`: after N published AI reviews on this PR, pause further
|
|
524
|
+
* re-reviews. null/0 ⇒ byte-identical (re-review every sync). (#2042) */
|
|
525
|
+
autoPauseAfterReviewedCommits: number | null;
|
|
526
|
+
};
|
|
527
|
+
export type MaxFindingsConfig = {
|
|
528
|
+
blockers: number | null;
|
|
529
|
+
nits: number | null;
|
|
530
|
+
};
|
|
531
|
+
export declare const EMPTY_MAX_FINDINGS_CONFIG: MaxFindingsConfig;
|
|
532
|
+
export declare const EMPTY_AUTO_REVIEW_CONFIG: AutoReviewConfig;
|
|
533
|
+
/** Per-repo self-host reviewer model/effort overrides under `review.ai_model`. Each field independently overrides
|
|
534
|
+
* the matching global env var (CLAUDE_AI_MODEL / CLAUDE_AI_EFFORT / CODEX_AI_MODEL / CODEX_AI_EFFORT) for THIS
|
|
535
|
+
* repo only — it never widens what the operator's own env already permits, only narrows/redirects it, so a
|
|
536
|
+
* compromised repo config can change which model reviews it but not grant itself a new credential or provider.
|
|
537
|
+
* (#selfhost-ai-model-override) */
|
|
538
|
+
export type SelfHostAiModelConfig = {
|
|
539
|
+
/** `review.ai_model.claude_model`: overrides CLAUDE_AI_MODEL for this repo's claude-code reviewer. null (default) ⇒ the operator's global env var, then the provider's own default. */
|
|
540
|
+
claudeModel: string | null;
|
|
541
|
+
/** `review.ai_model.claude_effort`: overrides CLAUDE_AI_EFFORT for this repo's claude-code reviewer. null (default) ⇒ the operator's global env var, then "medium". */
|
|
542
|
+
claudeEffort: string | null;
|
|
543
|
+
/** `review.ai_model.codex_model`: overrides CODEX_AI_MODEL for this repo's codex reviewer. null (default) ⇒ the operator's global env var, then the account default. */
|
|
544
|
+
codexModel: string | null;
|
|
545
|
+
/** `review.ai_model.codex_effort`: overrides CODEX_AI_EFFORT for this repo's codex reviewer. null (default) ⇒ the operator's global env var, then "medium". */
|
|
546
|
+
codexEffort: string | null;
|
|
547
|
+
/** `review.ai_model.ollama_model` (#3902): overrides OLLAMA_AI_MODEL for this repo's ollama reviewer. null (default) ⇒ the operator's global env var, then the provider's own default. */
|
|
548
|
+
ollamaModel: string | null;
|
|
549
|
+
/** `review.ai_model.openai_model` (#3902): overrides OPENAI_AI_MODEL for this repo's openai reviewer. null (default) ⇒ the operator's global env var, then the provider's own default. */
|
|
550
|
+
openaiModel: string | null;
|
|
551
|
+
/** `review.ai_model.openai_compatible_model` (#3902): overrides OPENAI_COMPATIBLE_AI_MODEL for this repo's openai-compatible reviewer. null (default) ⇒ the operator's global env var, then the provider's own default. */
|
|
552
|
+
openaiCompatibleModel: string | null;
|
|
553
|
+
/** `review.ai_model.anthropic_model` (#3902): overrides ANTHROPIC_AI_MODEL for this repo's anthropic (BYOK Messages API) reviewer. null (default) ⇒ the operator's global env var, then the provider's own default. */
|
|
554
|
+
anthropicModel: string | null;
|
|
555
|
+
};
|
|
556
|
+
export declare const EMPTY_SELF_HOST_AI_MODEL_CONFIG: SelfHostAiModelConfig;
|
|
557
|
+
/** Per-repo before/after screenshot-capture config under `review.visual` (#3609 / #3610). Generic by design —
|
|
558
|
+
* every self-hoster wires their OWN repo's preview-deploy setup and route shape with config, not code. */
|
|
559
|
+
export type VisualConfig = {
|
|
560
|
+
/** `review.visual.production_url`: the repo's "before" production URL — e.g. `https://metagraph.sh` for a
|
|
561
|
+
* repo whose live site differs from the operator's own `PUBLIC_SITE_ORIGIN` env var (a single GLOBAL value
|
|
562
|
+
* with no per-repo awareness, correct for at most one repo on a multi-repo self-host instance). ALWAYS wins
|
|
563
|
+
* over `PUBLIC_SITE_ORIGIN` when set, mirroring `preview.url_template`'s precedence over GitHub-native
|
|
564
|
+
* discovery. null (default) ⇒ byte-identical to today (falls back to `PUBLIC_SITE_ORIGIN`). Validated at
|
|
565
|
+
* parse time against the same SSRF guard (`isSafeHttpUrl`) the renderer itself unconditionally applies. */
|
|
566
|
+
productionUrl: string | null;
|
|
567
|
+
preview: VisualPreviewConfig;
|
|
568
|
+
routes: VisualRoutesConfig;
|
|
569
|
+
themes: VisualTheme[];
|
|
570
|
+
/** `review.visual.gif`: capture a short scroll-through GIF (#3612) alongside the static before/after
|
|
571
|
+
* screenshots — evidence for scroll-linked behavior (parallax, reveal-on-scroll, a sticky header) that a
|
|
572
|
+
* single static shot can't show. Self-host only (see src/review/visual/scroll-gif.ts) and the heaviest
|
|
573
|
+
* capture mode this pipeline has (up to 6 extra renders per side) — false (default, every existing
|
|
574
|
+
* manifest) ⇒ byte-identical to today, no scroll frames captured at all. */
|
|
575
|
+
gif: boolean;
|
|
576
|
+
/** `review.visual.enabled` (#4083): a config-as-code override layered ON TOP OF the outer
|
|
577
|
+
* `GITTENSORY_REVIEW_SCREENSHOTS` / `GITTENSORY_REVIEW_REPOS` env-var gate, not a replacement for it. null
|
|
578
|
+
* (default, unset at every config layer) ⇒ defers entirely to that gate's own decision. `false` (settable at
|
|
579
|
+
* the global-default layer, or overridden per-repo) ⇒ forces capture off for this repo even when the env-var
|
|
580
|
+
* gate would otherwise allow it. `true` ⇒ no additional restriction — it does NOT bypass the env-var gate,
|
|
581
|
+
* it only opts back in at a layer where a global default of `false` disabled this repo. This is what lets an
|
|
582
|
+
* operator flip visual review on/off per-repo purely through the VPS config files, without a redeploy. */
|
|
583
|
+
enabled: boolean | null;
|
|
584
|
+
/** `review.visual.theme_storage_key` (#4109): the `localStorage` key the capture pipeline ALSO forces
|
|
585
|
+
* `theme` into (plus a reload) before rendering, for a target whose theming reads an explicit stored
|
|
586
|
+
* preference instead of consulting `prefers-color-scheme` — verified (against gittensory-ui's own
|
|
587
|
+
* dark-mode-only build) that `emulateMediaFeatures` alone has zero effect on that class of app, since it
|
|
588
|
+
* only changes what CSS media queries / `matchMedia` report. null (default) ⇒ no `localStorage` write, no
|
|
589
|
+
* reload — byte-identical to today. Only takes effect when `themes` is also configured; the key name is
|
|
590
|
+
* app-specific (there is no universal convention), so it is opaque, bounded, public-safe text, same shape
|
|
591
|
+
* as `review.ai_model`'s free-text fields. */
|
|
592
|
+
themeStorageKey: string | null;
|
|
593
|
+
/** `review.visual.actions_fallback` (#4112): when true, and ONLY when the existing GitHub-native discovery
|
|
594
|
+
* chain (Deployments API / commit checks / cloudflare-bot PR comment / an explicit `preview.url_template`)
|
|
595
|
+
* finds no preview at all for this PR, dispatch `.github/workflows/visual-capture-fallback.yml` -- a
|
|
596
|
+
* fork-safe GitHub Actions job that builds, serves, and screenshots the PR's own code with zero secrets --
|
|
597
|
+
* and use its captured PNGs as the "after" shot instead. false (default) ⇒ byte-identical to today (no
|
|
598
|
+
* dispatch, no change to the discovery order). Requires the target repo to have that workflow file present
|
|
599
|
+
* (see the workflow's own header comment for setup); a repo without it just never gets a fallback run, same
|
|
600
|
+
* as leaving this unset. (#3607 visual-capture convergence epic) */
|
|
601
|
+
actionsFallback: boolean;
|
|
602
|
+
};
|
|
603
|
+
/** A `prefers-color-scheme` value the capture pipeline can emulate before rendering (#3678). */
|
|
604
|
+
export type VisualTheme = "light" | "dark";
|
|
605
|
+
export type VisualPreviewConfig = {
|
|
606
|
+
/** `review.visual.preview.url_template`: the repo's "after" preview URL, with `{number}` (PR number),
|
|
607
|
+
* `{head_sha}` (full commit SHA), and `{head_sha_short}` (first 7 chars) placeholders substituted at
|
|
608
|
+
* capture time — e.g. `https://pr-{number}.myapp.workers.dev`. ALWAYS wins over GitHub-native preview
|
|
609
|
+
* discovery (the Deployments API / commit checks / cloudflare-bot PR comment) when set — an explicit,
|
|
610
|
+
* maintainer-configured template is a stronger signal than inference, and is the only option for a
|
|
611
|
+
* provider (e.g. Cloudflare Workers Builds' non-production branch builds) that doesn't surface a
|
|
612
|
+
* GitHub-visible deployment at all. null (default) ⇒ byte-identical to today (discovery unchanged).
|
|
613
|
+
* Validated at parse time against the same SSRF guard the renderer itself applies (isSafeHttpUrl) with
|
|
614
|
+
* placeholders substituted for a dummy value, so a malformed template warns at config-read time instead
|
|
615
|
+
* of only failing silently at render time — this is redundant with (not a replacement for) the
|
|
616
|
+
* renderer's own unconditional isSafeHttpUrl check on every resolved URL, regardless of source. */
|
|
617
|
+
urlTemplate: string | null;
|
|
618
|
+
};
|
|
619
|
+
export type VisualRoutesConfig = {
|
|
620
|
+
/** `review.visual.routes.paths`: an explicit, always-screenshotted route list. When non-empty, this
|
|
621
|
+
* REPLACES automatic file-to-route inference entirely — for repos whose routing convention isn't
|
|
622
|
+
* gittensory-ui's TanStack file-based one, an explicit list is simpler and more robust than trying to
|
|
623
|
+
* infer one. Empty (default) ⇒ automatic inference (falling back to "/" when nothing matches). */
|
|
624
|
+
paths: string[];
|
|
625
|
+
/** `review.visual.routes.max_routes`: overrides the built-in cap (2) on how many routes get screenshotted
|
|
626
|
+
* per PR. null (default) ⇒ built-in default. Applies whether routes come from `paths` above or from
|
|
627
|
+
* automatic inference. */
|
|
628
|
+
maxRoutes: number | null;
|
|
629
|
+
};
|
|
630
|
+
export declare const EMPTY_VISUAL_CONFIG: VisualConfig;
|
|
631
|
+
/** One `review.path_instructions[]` entry: a manifest path glob + the public-safe instructions to apply when a
|
|
632
|
+
* changed file matches it. */
|
|
633
|
+
export type ReviewPathInstruction = {
|
|
634
|
+
path: string;
|
|
635
|
+
instructions: string;
|
|
636
|
+
};
|
|
637
|
+
/** One `review.pre_merge_checks[]` entry — a DETERMINISTIC pre-merge assertion. `whenPaths` (empty ⇒ always
|
|
638
|
+
* applies) gates the check to PRs that touch a matching path. The check PASSES only when EVERY configured
|
|
639
|
+
* assertion holds: the PR title contains `titleContains`, the body contains `descriptionContains`, and the
|
|
640
|
+
* `requireLabel` label is present (case-insensitive substring / label match). `enforce` ⇒ a failure is a hard
|
|
641
|
+
* gate blocker; default (false) ⇒ advisory only. All strings are public-safe-filtered at parse time. */
|
|
642
|
+
export type PreMergeCheck = {
|
|
643
|
+
name: string;
|
|
644
|
+
whenPaths: string[];
|
|
645
|
+
titleContains: string | null;
|
|
646
|
+
descriptionContains: string | null;
|
|
647
|
+
requireLabel: string | null;
|
|
648
|
+
enforce: boolean;
|
|
649
|
+
};
|
|
650
|
+
/**
|
|
651
|
+
* Normalized maintainer focus manifest. Repo owners declare which work areas are wanted,
|
|
652
|
+
* preferred, and how PRs should present validation. Path-based manual review is intentionally
|
|
653
|
+
* not part of this manifest anymore; use `settings.hardGuardrailGlobs` for that single
|
|
654
|
+
* authoritative control. `maintainerNotes` are private review context and must never reach a public
|
|
655
|
+
* GitHub surface; `publicNotes` are explicitly opted into public output by the maintainer.
|
|
656
|
+
*/
|
|
657
|
+
export type FocusManifest = {
|
|
658
|
+
present: boolean;
|
|
659
|
+
source: FocusManifestSource;
|
|
660
|
+
wantedPaths: string[];
|
|
661
|
+
preferredLabels: string[];
|
|
662
|
+
linkedIssuePolicy: FocusManifestLinkedIssuePolicy;
|
|
663
|
+
testExpectations: string[];
|
|
664
|
+
issueDiscoveryPolicy: FocusManifestIssueDiscoveryPolicy;
|
|
665
|
+
maintainerNotes: string[];
|
|
666
|
+
publicNotes: string[];
|
|
667
|
+
gate: FocusManifestGateConfig;
|
|
668
|
+
settings: FocusManifestSettings;
|
|
669
|
+
review: FocusManifestReviewConfig;
|
|
670
|
+
features: FocusManifestFeaturesConfig;
|
|
671
|
+
experimental: FocusManifestExperimentalConfig;
|
|
672
|
+
contentLane: FocusManifestContentLaneConfig;
|
|
673
|
+
repoDocGeneration: FocusManifestRepoDocGenerationConfig;
|
|
674
|
+
reviewRecap: FocusManifestReviewRecapConfig;
|
|
675
|
+
maintainerRecap: FocusManifestMaintainerRecapConfig;
|
|
676
|
+
warnings: string[];
|
|
677
|
+
};
|
|
678
|
+
export type FocusManifestFinding = {
|
|
679
|
+
code: "manifest_off_focus" | "manifest_preferred_path" | "manifest_missing_preferred_label" | "manifest_linked_issue_required" | "manifest_linked_issue_preferred" | "manifest_missing_tests" | "manifest_issue_discovery_discouraged" | "manifest_malformed";
|
|
680
|
+
severity: "info" | "warning" | "critical";
|
|
681
|
+
title: string;
|
|
682
|
+
detail: string;
|
|
683
|
+
action?: string | undefined;
|
|
684
|
+
};
|
|
685
|
+
export type FocusManifestGuidance = {
|
|
686
|
+
present: boolean;
|
|
687
|
+
source: FocusManifestSource;
|
|
688
|
+
linkedIssuePolicy: FocusManifestLinkedIssuePolicy;
|
|
689
|
+
issueDiscoveryPolicy: FocusManifestIssueDiscoveryPolicy;
|
|
690
|
+
matchedWantedPaths: string[];
|
|
691
|
+
preferredLabelHits: string[];
|
|
692
|
+
findings: FocusManifestFinding[];
|
|
693
|
+
publicNextSteps: string[];
|
|
694
|
+
warnings: string[];
|
|
695
|
+
summary: string;
|
|
696
|
+
};
|
|
697
|
+
export declare const MAX_FOCUS_MANIFEST_BYTES: number;
|
|
698
|
+
/**
|
|
699
|
+
* Public-safe redaction guard shared with the local-branch packet renderer. Public manifest
|
|
700
|
+
* text must not leak reward, wallet/key, ranking, or local filesystem path material.
|
|
701
|
+
*/
|
|
702
|
+
export declare function isFocusManifestPublicSafe(text: string): boolean;
|
|
703
|
+
/** `gate.readiness.mode` (and its `settings.qualityGateMode` alias below) is documented and parsed as the shared
|
|
704
|
+
* off/advisory/block tri-state, but buildQualityGateWarning (src/rules/advisory.ts) always produces a
|
|
705
|
+
* warning-severity finding — never a blocker — and isConfiguredGateBlocker has no branch for it: readiness/
|
|
706
|
+
* quality is intentionally informational-only and can never hard-block a PR. Without this, a maintainer who
|
|
707
|
+
* sets `mode: block` believes a real quality floor is enforced when the effective behavior is silently
|
|
708
|
+
* advisory-only (#2267). Downgrade "block" to "advisory" here, with a clear deprecation warning, so the parsed
|
|
709
|
+
* config always matches what the gate actually does. Exported so the settings-write API routes (the
|
|
710
|
+
* dashboard/API path for the SAME `qualityGateMode` field) can apply the identical downgrade before persisting. */
|
|
711
|
+
export declare function normalizeReadinessGateMode(value: JsonValue | undefined, field: string, warnings: string[]): GateRuleMode | null;
|
|
712
|
+
/**
|
|
713
|
+
* Serialize a gate config back into the parse-compatible `gate:` shape so a cached manifest snapshot
|
|
714
|
+
* round-trips through {@link parseGateConfig} unchanged. Returns null when nothing is configured.
|
|
715
|
+
*/
|
|
716
|
+
export declare function gateConfigToJson(gate: FocusManifestGateConfig): JsonValue;
|
|
717
|
+
/** Serialize a features config back into the parse-compatible `features:` shape so a cached snapshot round-trips
|
|
718
|
+
* through {@link parseFeaturesConfig} unchanged. Returns null when nothing is configured. */
|
|
719
|
+
export declare function featuresConfigToJson(features: FocusManifestFeaturesConfig): JsonValue;
|
|
720
|
+
/** Serialize an experimental config back into the parse-compatible `experimental:` shape so a cached snapshot
|
|
721
|
+
* round-trips through {@link parseExperimentalConfig} unchanged. Returns null when nothing is configured. */
|
|
722
|
+
export declare function experimentalConfigToJson(experimental: FocusManifestExperimentalConfig): JsonValue;
|
|
723
|
+
/** Serialize a contentLane config back into the parse-compatible `contentLane:` shape so a cached snapshot
|
|
724
|
+
* round-trips through {@link parseContentLaneConfig} unchanged. Returns null when nothing is configured. */
|
|
725
|
+
export declare function contentLaneConfigToJson(contentLane: FocusManifestContentLaneConfig): JsonValue;
|
|
726
|
+
/** Serialize a repoDocGeneration config back into the parse-compatible shape so a cached snapshot round-trips
|
|
727
|
+
* through {@link parseRepoDocGenerationConfig} unchanged. Returns null when nothing is configured. */
|
|
728
|
+
export declare function repoDocGenerationConfigToJson(config: FocusManifestRepoDocGenerationConfig): JsonValue;
|
|
729
|
+
/** Serialize a reviewRecap config back into the parse-compatible shape so a cached snapshot round-trips
|
|
730
|
+
* through {@link parseReviewRecapConfig} unchanged. Returns null when nothing is configured. */
|
|
731
|
+
export declare function reviewRecapConfigToJson(config: FocusManifestReviewRecapConfig): JsonValue;
|
|
732
|
+
/** Serialize a maintainerRecap config back into the parse-compatible shape so a cached snapshot round-trips
|
|
733
|
+
* through {@link parseMaintainerRecapConfig} unchanged. Returns null when nothing is configured. */
|
|
734
|
+
export declare function maintainerRecapConfigToJson(config: FocusManifestMaintainerRecapConfig): JsonValue;
|
|
735
|
+
/** Serialize the settings override for the cache round-trip; returns null when nothing is set. */
|
|
736
|
+
export declare function settingsOverrideToJson(settings: FocusManifestSettings): JsonValue;
|
|
737
|
+
/** Overlay a higher-priority `review:` config onto a shared/base layer (#2046). Per-field: override wins when set;
|
|
738
|
+
* base fills gaps; defaults stay byte-identical. `sharedConfigSource` on the override is preserved when present. */
|
|
739
|
+
export declare function overlayReviewConfig(base: FocusManifestReviewConfig, override: FocusManifestReviewConfig): FocusManifestReviewConfig;
|
|
740
|
+
/** Parse a raw `review:` mapping value. Exported for the private-config shared overlay (#2046). */
|
|
741
|
+
export declare function parseReviewConfigMapping(value: JsonValue | undefined, warnings: string[]): FocusManifestReviewConfig;
|
|
742
|
+
/** Serialize the review config for the cache round-trip; returns null when nothing is set. */
|
|
743
|
+
export declare function reviewConfigToJson(review: FocusManifestReviewConfig): JsonValue;
|
|
744
|
+
/**
|
|
745
|
+
* Resolve the `review.path_instructions` that APPLY to a PR — those whose glob matches at least one changed path
|
|
746
|
+
* — into a single prompt section for the AI reviewer, or "" when none match (so the prompt stays byte-identical).
|
|
747
|
+
* Pure; uses the same manifest path-glob semantics (`matchesManifestPath`) as the rest of the manifest. Capped to
|
|
748
|
+
* keep the prompt bounded. (#review-path-instructions)
|
|
749
|
+
*/
|
|
750
|
+
export declare function parseFocusManifest(raw: unknown, source?: FocusManifestSource): FocusManifest;
|
|
751
|
+
/**
|
|
752
|
+
* Parse raw manifest file/record content (JSON or YAML). Malformed content degrades to an empty
|
|
753
|
+
* manifest with a warning rather than throwing, so a broken `.gittensory` config never breaks analysis.
|
|
754
|
+
*/
|
|
755
|
+
export declare function parseFocusManifestContent(content: string | null | undefined, source?: FocusManifestSource): FocusManifest;
|
|
756
|
+
/**
|
|
757
|
+
* Format a manifest's parse `warnings[]` into one grouped, deduped, order-preserving notice for the review
|
|
758
|
+
* surface — an acceptance criterion of #1670: an invalid/malformed `.gittensory.yml` value should fail
|
|
759
|
+
* clearly instead of silently falling back to a default. Empty/no warnings ⇒ `null` (byte-identical, no
|
|
760
|
+
* notice). Pure; reuses the warnings every parser already accumulates rather than a parallel schema. (#2056)
|
|
761
|
+
*/
|
|
762
|
+
export declare function formatManifestValidationNotice(warnings: string[]): string | null;
|
|
763
|
+
/**
|
|
764
|
+
* Match a changed path against a manifest path pattern. Supports exact paths, directory
|
|
765
|
+
* prefixes (`src/` or `src`), and `*` wildcards (`**` collapses to `*`).
|
|
766
|
+
*/
|
|
767
|
+
export declare function matchesManifestPath(path: string, pattern: string): boolean;
|
|
768
|
+
export type FocusManifestLanePreference = "preferred" | "neutral" | "discouraged";
|
|
769
|
+
export type FocusManifestPolicyContributionLane = {
|
|
770
|
+
id: string;
|
|
771
|
+
preference: "preferred" | "neutral" | "discouraged";
|
|
772
|
+
title: string;
|
|
773
|
+
summary: string;
|
|
774
|
+
preferredPaths: string[];
|
|
775
|
+
discouragedPaths: string[];
|
|
776
|
+
validationExpectations: string[];
|
|
777
|
+
publicNotes: string[];
|
|
778
|
+
};
|
|
779
|
+
export type FocusManifestPolicyLabelPolicy = {
|
|
780
|
+
preferredLabels: string[];
|
|
781
|
+
required: boolean;
|
|
782
|
+
};
|
|
783
|
+
export type FocusManifestPolicyValidation = {
|
|
784
|
+
expectations: string[];
|
|
785
|
+
linkedIssuePolicy: FocusManifestLinkedIssuePolicy;
|
|
786
|
+
};
|
|
787
|
+
export type FocusManifestPolicy = {
|
|
788
|
+
repoFullName: string;
|
|
789
|
+
generatedAt: string;
|
|
790
|
+
source: FocusManifestSource;
|
|
791
|
+
present: boolean;
|
|
792
|
+
publicSafe: {
|
|
793
|
+
contributionLanes: FocusManifestPolicyContributionLane[];
|
|
794
|
+
labelPolicy: FocusManifestPolicyLabelPolicy;
|
|
795
|
+
validation: FocusManifestPolicyValidation;
|
|
796
|
+
issueDiscoveryPolicy: FocusManifestIssueDiscoveryPolicy;
|
|
797
|
+
publicNotes: string[];
|
|
798
|
+
readinessWarnings: string[];
|
|
799
|
+
entryGuidance: string[];
|
|
800
|
+
summary: string;
|
|
801
|
+
};
|
|
802
|
+
authenticated: {
|
|
803
|
+
manifestSource: FocusManifestSource;
|
|
804
|
+
privateNoteCount: number;
|
|
805
|
+
manifestWarningCount: number;
|
|
806
|
+
parseWarnings: string[];
|
|
807
|
+
readinessWarnings: string[];
|
|
808
|
+
maintainerContext: string[];
|
|
809
|
+
};
|
|
810
|
+
};
|
|
811
|
+
/**
|
|
812
|
+
* Compile a normalized {@link FocusManifest} into a deterministic, machine-readable
|
|
813
|
+
* {@link FocusManifestPolicy}. Public-safe fields are segregated from authenticated
|
|
814
|
+
* (owner-only) fields. No reward, wallet, hotkey, raw trust, or private scoring
|
|
815
|
+
* language is allowed in public-safe output — unsafe strings are silently dropped.
|
|
816
|
+
*
|
|
817
|
+
* `repoFullName` is optional — when omitted it defaults to an empty string. Callers
|
|
818
|
+
* that persist the policy should supply the full name; single-manifest analysis
|
|
819
|
+
* callers may omit it.
|
|
820
|
+
*/
|
|
821
|
+
export declare function compileFocusManifestPolicy(manifest: FocusManifest, options?: {
|
|
822
|
+
generatedAt?: string;
|
|
823
|
+
}): FocusManifestPolicy;
|
|
824
|
+
export declare function compileFocusManifestPolicy(repoFullName: string, manifest: FocusManifest, options?: {
|
|
825
|
+
generatedAt?: string;
|
|
826
|
+
}): FocusManifestPolicy;
|