-
-
Notifications
You must be signed in to change notification settings - Fork 71
Expand file tree
/
Copy pathwrangler.jsonc
More file actions
333 lines (333 loc) · 23.5 KB
/
Copy pathwrangler.jsonc
File metadata and controls
333 lines (333 loc) · 23.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
{
"$schema": "node_modules/wrangler/config-schema.json",
// Auto-deploys to production via Cloudflare Workers Builds on push to `main`
// (deploy command: `npm run deploy:api` — applies pending D1 migrations, then `wrangler deploy`).
"name": "loopover-api",
"main": "src/index.ts",
"workers_dev": true,
"preview_urls": false,
"compatibility_date": "2026-05-28",
"compatibility_flags": ["nodejs_compat"],
"placement": {
"mode": "smart",
},
"observability": {
"enabled": true,
"logs": {
"enabled": true,
"head_sampling_rate": 1,
},
"traces": {
"enabled": true,
"head_sampling_rate": 1,
},
},
"vars": {
// GITHUB_APP_ID / GITHUB_APP_SLUG (the retired review App's identity) removed 2026-07-12: that App has
// been fully deleted. Cloud no longer holds its credentials either (GITHUB_APP_PRIVATE_KEY/
// GITHUB_WEBHOOK_SECRET Worker secrets removed in the same change) -- review execution is self-host-only,
// brokered through the separate Orb App (ORB_GITHUB_APP_ID, a Worker secret).
"GITHUB_OAUTH_CLIENT_ID": "Ov23lixYxDzyUKE070sm",
"GITHUB_WEBHOOK_MAX_BODY_BYTES": "1048576",
"GITTENSOR_UPSTREAM_REPO": "entrius/gittensor",
"GITTENSOR_UPSTREAM_REF": "test",
"GITTENSOR_REGISTRY_URL": "https://raw.githubusercontent.com/entrius/gittensor/test/gittensor/validator/weights/master_repositories.json",
// #703: apply upstream sigmoid time-decay in score previews, using each repo's resolved per-repo
// hyperparameters (registry scoring.time_decay overlaid on the upstream defaults). A fresh PR is
// unaffected (decay 1.0); only aged-PR projections decay. Owner-reviewed; this is the go-live switch.
"SCORING_TIME_DECAY_ENABLED": "true",
"LOOPOVER_AUTO_FILE_DRIFT_ISSUES": "false",
"LOOPOVER_DRIFT_ISSUE_REPO": "JSONbored/loopover",
// LoopOver rebrand (issue #4765): full cutover, loopover.ai only. gittensory.aethereal.dev is retired
// as a production origin -- no longer routed to this Worker (see routes[] below) and no longer accepted
// as a PUBLIC_SITE_ORIGIN_ALIASES redirect target. normalizeReturnTo (src/auth/github-oauth.ts) already
// treats an unset PUBLIC_SITE_ORIGIN_ALIASES as "no aliases" with zero code changes needed -- the
// aliasing mechanism itself stays in the codebase as a generic self-host feature, production just no
// longer configures it. PUBLIC_API_ORIGIN builds this Worker's own GitHub OAuth redirect_uri
// (githubOAuthCallbackUrl); that OAuth App's callback URL on GitHub's side is already
// https://api.loopover.ai/v1/auth/github/callback.
"PUBLIC_API_ORIGIN": "https://api.loopover.ai",
"PUBLIC_SITE_ORIGIN": "https://loopover.ai",
"ADMIN_GITHUB_LOGINS": "JSONbored",
// Hosted reviews are retired. Cloudflare now serves the public API + Orb broker only; review execution runs
// in the self-host container, where Redis-backed transient state is mandatory. The Cloudflare API worker no
// longer binds Workers AI, Vectorize, R2 review audit storage, or Browser Rendering for review execution.
// Inline comments (#inline-comments): leave quiet, non-blocking inline comments on changed lines, on top of
// the decision summary. Requires the repo in LOOPOVER_REVIEW_REPOS AND review.inline_comments in its
// .loopover.yml. Default OFF — flag-OFF the model is never asked for inline findings (byte-identical).
"LOOPOVER_REVIEW_INLINE_COMMENTS": "false",
// Convergence (safety): run the ported safety scan in the review path — defang untrusted PR
// title/body/diff before the AI reviewer sees it, and surface a secret-leak blocker from the diff.
// Default OFF — flag-OFF keeps the review path byte-identical.
"LOOPOVER_REVIEW_SAFETY": "false",
// Convergence (visual capture): capture a before/after screenshot for PRs touching WEB-VISIBLE files.
// Self-host equivalents are BROWSER_WS_ENDPOINT + REVIEW_AUDIT_DIR; Cloudflare no longer binds these review
// resources. DEFAULT OFF — flag-OFF captures nothing (byte-identical).
"LOOPOVER_REVIEW_SCREENSHOTS": "false",
// Convergence (grounding): ground the AI reviewer prompt with the PR's finished CI status + the full
// post-change content of the changed files, so a non-frontier model verifies claims instead of guessing.
// Default OFF — flag-OFF keeps the reviewer prompt byte-identical and makes no extra GitHub fetch.
"LOOPOVER_REVIEW_GROUNDING": "false",
// Convergence (e2eTests, #4190/#4189): master kill-switch for the opt-in, maintainer-triggered AI-generated
// E2E test coverage feature. Default OFF — flag-OFF the feature is never active for any repo regardless of
// a per-repo features.e2eTests override.
"LOOPOVER_REVIEW_E2E_TESTS": "false",
// Convergence (improvementSignal, #4738, foundation phase of the #4737 epic): master kill-switch for the
// read-only, advisory PR quality-delta signal (the positive-axis counterpart to slop.ts's risk score).
// Config-as-code activation only — no tier reads this flag yet. Default OFF — flag-OFF the feature is
// never active for any repo regardless of a per-repo features.improvementSignal override.
"LOOPOVER_REVIEW_IMPROVEMENT_SIGNAL": "false",
// #one-shot-review-cadence: fleet-wide default AI review re-trigger cadence, used only when a repo's
// .loopover.yml review.auto_review.cadence is unset (a per-repo value always wins). Default OFF (false)
// = "one_shot": AI-generated content (main review, slop, linked-issue satisfaction) freezes after its
// first pass; only an explicit maintainer retrigger spends a fresh call. Truthy = "continuous": every
// push/CI-completion/sweep re-runs AI content generation, for operators who prefer that. The deterministic
// gate always re-evaluates regardless of this flag.
"LOOPOVER_REVIEW_CONTINUOUS": "false",
// Convergence (reputation): factor the INTERNAL-only ported submitter-reputation signal into the AI-spend
// gate — a new / burst / low-reputation submitter is downgraded to a deterministic-only review (AI neurons
// skipped), and the per-(project, submitter) outcome is recorded after the gate decides. The reputation is
// NEVER surfaced publicly. Default OFF — flag-OFF reads nothing, records nothing, and leaves the AI-spend
// gate byte-identical.
"LOOPOVER_REVIEW_REPUTATION": "false",
// Convergence (ops / observability): drive two OPERATOR surfaces off gittensory's own review-outcome data
// — (1) a cron-tick anomaly scan over the gate-block ledger + recommendation/slop calibration that emits a
// structured `ops_anomaly` log on drift, and (2) a bearer-gated GET /v1/internal/ops/stats outcome
// aggregate. Read-only observability; the auto-tune/config-mutation self-improve loop is NOT wired here.
// Default OFF — flag-OFF the cron enqueues no ops job and the endpoint 404s, byte-identical to today.
"LOOPOVER_REVIEW_OPS": "false",
// Self-heal (#audit-sweep-fanout-isolation follow-up): an hourly watchdog over the SAME acting-autonomy repo
// set the scheduled regate sweep covers — a repo with open PRs whose last-regated marker hasn't advanced in
// over the staleness window gets a structured `sweep_liveness_stale` log (Sentry-visible) AND a single
// targeted `agent-regate-sweep` re-enqueue for just that repo, so a stalled sweep recovers on its own instead
// of requiring a human to notice and manually trigger it. Default OFF — flag-OFF the cron enqueues no
// watchdog job, byte-identical to today.
"LOOPOVER_SWEEP_WATCHDOG": "false",
// Self-heal: a short-interval cron list-diffs GitHub's open PR numbers against the local table for every
// acting-autonomy repo, and catches up (fetch + upsert + regate) any PR number GitHub has that the local
// table doesn't — a silently-lost "opened" webhook, caught within minutes instead of the 6-hour
// backfillRegisteredRepositories freshness window. Default OFF — flag-OFF the cron enqueues no
// reconciliation job, byte-identical to today.
"LOOPOVER_PR_RECONCILIATION": "false",
// Convergence (RAG retrieval): at review time, query the codebase vector index for code/docs semantically
// related to the PR's changed files and append a RELEVANT EXISTING CODE / DOCS section to the reviewer
// prompt — additive reference context (callers, related modules, conventions), exactly like grounding.
// Default OFF — flag-OFF performs no retrieval, uses no adapter, makes no vector query, and keeps the
// reviewer prompt byte-identical. Self-host injects a Qdrant/sqlite/pg vector adapter; Cloudflare no longer
// binds Vectorize for review execution.
"LOOPOVER_REVIEW_RAG": "false",
// Deterministic impact map (#2184, part of #1971): the operator-level kill-switch for computing (from the
// RAG index + changed symbols) which other repo files plausibly need re-checking, then rendering that as a
// compact section in the unified review comment and/or feeding it into AI-review grounding as additive
// reference context. ANDed with the per-repo `.loopover.yml review.impact_map` opt-in — neither alone is
// sufficient. Default OFF — flag-OFF performs no symbol extraction, no RAG query, and adds no prompt/comment
// section, byte-identical to today.
"LOOPOVER_REVIEW_IMPACT_MAP": "false",
// Repo quality-culture profile (#2995): at review time, append an ADDITIVE "REPO QUALITY-CULTURE PROFILE"
// reference block — typical merged-PR size + common accepted labels, derived deterministically from this
// repo's OWN recent_merged_pull_requests history. Reference-only grounding, exactly like RAG; never a
// gate/scoring input. Also requires the per-repo `.loopover.yml` review.culture_profile: true opt-in.
// Default OFF — flag-OFF performs no extra D1 read and keeps the reviewer prompt byte-identical.
"LOOPOVER_REVIEW_CULTURE_PROFILE": "false",
// Review memory (#2179, part of #1964): the operator-level kill-switch for repeat-false-positive
// suppression — before an advisory (non-blocking) AI finding is surfaced, it is matched against this
// repo's stored review_suppression signals (a maintainer's own past false-positive dismissals) and
// demoted/dropped on a match. ANDed with the per-repo `.loopover.yml review.memory` opt-in — neither
// alone is sufficient. ADVISORY-ONLY: never applied to gate blockers, so it can never change the
// merge/close disposition. Default OFF — flag-OFF performs no suppression-store read and no matching,
// byte-identical to today.
"LOOPOVER_REVIEW_MEMORY": "false",
// Convergence (content/registry SURFACE LANE): when truthy AND the repo is in LOOPOVER_REVIEW_REPOS, the
// deterministic, AI-FREE surface review drives the gate for registry-submission PRs (metagraphed). Default
// OFF (false): the processor takes no new branch + resolves no files, so the gate disposition is byte-
// identical until deliberately enabled per-repo. See review/content-lane-wire.
"LOOPOVER_REVIEW_CONTENT_LANE": "false",
// Convergence (self-improve / auto-tune): run the ported self-improvement loop on the cron tick over
// gittensory's own review-outcome data — compute tuning recommendations, SHADOW-SOAK any strictly-
// tightening one, and AUTO-PROMOTE it to live ONLY after the soak window passes the gate; every action is
// audited. It can ONLY EVER tighten the gate (a loosening recommendation is never applied). Default OFF —
// flag-OFF the cron enqueues no selftune job, does zero tuning work, reads/writes no override, byte-
// identical to today. Config-application (reading a promoted override into the live gate) is a deferred
// follow-up — see src/review/selftune-wire.ts.
"LOOPOVER_REVIEW_SELFTUNE": "false",
// Experimental `gittensor` plugin (the `experimental:` manifest block, first key): the operator-level
// kill-switch for gittensory's original subnet mining-registry/scoring integration, now opt-in rather than
// a core dependency. ANDed with the per-repo `.loopover.yml experimental.gittensor` opt-in — neither
// alone is sufficient, and unlike `features:` there is no LOOPOVER_REVIEW_REPOS allowlist fallback.
// Default OFF — flag-OFF (or every repo unset), refresh-registry is never enqueued (see src/index.ts),
// registry/sync.ts persists nothing for this instance, and a self-host box makes zero outbound contact
// with the gittensor subnet registry. See src/review/gittensor-wire.ts.
"LOOPOVER_EXPERIMENTAL_GITTENSOR": "false",
// Maintainer recap digest (#1963, #2248): deliver a cross-repo RecapReport -- gittensory's own gate-
// precision + outcome-calibration data folded across every scanned repo -- to Discord on a cron cadence
// (LOOPOVER_RECAP_CADENCE=daily|weekly, default weekly; LOOPOVER_RECAP_HOUR / LOOPOVER_RECAP_DAY
// pick when). Default OFF — flag-OFF the cron enqueues no recap job, byte-identical to today.
"LOOPOVER_MAINTAINER_RECAP": "false",
// #1941: route the live CI aggregate (the gate's check/status read) through ONE GraphQL statusCheckRollup query
// instead of the paginated /check-runs + /status + /check-suites REST reads — moving that hot path onto the
// SEPARATE GraphQL rate-limit bucket. Default OFF: the gate uses the proven REST aggregate, byte-identical. When
// ON, the GraphQL path reuses the REST-resolved required contexts and still falls back to REST on any error,
// unexpected shape, or >100 rollup contexts.
"GITHUB_STATUS_ROLLUP_GRAPHQL": "false",
// Convergence (#issue-coding-plan): the `@gittensory plan` command. Default OFF — `@gittensory plan` falls
// through to the existing mention path (byte-identical). Hosted planning is retired with the Cloudflare AI
// binding; self-host can run planning through the configured self-host AI provider.
"LOOPOVER_REVIEW_PLANNER": "false",
// Convergence (port): public OAuth draft-submission flow ported from reviewbot. Default OFF — every
// /v1/drafts endpoint 404s and no draft behavior runs. Turning it on also needs the
// DRAFT_TOKEN_ENCRYPTION_SECRET worker secret + GITHUB_OAUTH_CLIENT_SECRET to be set.
"LOOPOVER_REVIEW_DRAFT": "false",
// Convergence prep (#preconv-parity): SHADOW-record each finalized gittensory-native gate decision
// (source='gittensory-native') into the review_audit audit-source table (migration 0049), and serve the
// pre-cutover parity readiness report at GET /v1/internal/parity. RECORD-ONLY — changes no review behavior.
// Default OFF — flag-OFF records nothing (no D1 write, the review path is byte-identical) and the endpoint
// 404s. The cross-system comparison vs reviewbot's authoritative rows is a deploy-time dual-run step.
"LOOPOVER_REVIEW_PARITY_AUDIT": "false",
// Convergence (cutover): comma-separated allowlist of repo full-names ("owner/repo") that may run the
// PER-PR converged review features (safety, grounding, RAG, reputation, unified comment). A feature
// activates for a repo ONLY when its global flag above is ON AND the repo is listed here — so the cutover
// rolls forward one repo at a time (e.g. "JSONbored/gittensory,JSONbored/awesome-claude"). Default "" →
// NO repos converged → the per-PR converged path stays dormant for every repo regardless of the global
// flags (byte-identical to today). The cron/endpoint flags (ops/selftune/parity/draft) stay global.
"LOOPOVER_REVIEW_REPOS": "",
// Proof of Power (#1059): serve the public homepage stats counter at GET /v1/public/stats, computed LIVE
// from the public review ledger (audit_events + pull_requests plus Orb aggregates) behind a 60s cache. ON — the above-the-fold band
// shows PRs reviewed / filtered-without-merge % / maintainer time saved / decision accuracy for the
// reviewed repos. Flag-OFF the endpoint 404s and the homepage band renders nothing (counts only, no PR
// content/authors/scores/rewards). See src/review/public-stats.ts.
"LOOPOVER_PUBLIC_STATS": "true",
// Proof of Power (#1059): the own-ledger allowlist for the public stats counter (DELIBERATELY separate from
// LOOPOVER_REVIEW_REPOS above, which went empty when these repos' LIVE processing moved to self-host — see
// src/env.d.ts for the full split rationale). These three repos' historical audit_events rows remain real and
// safe to publish even though the cutover allowlist above no longer lists them.
// JSONbored/gittensory kept alongside the post-rename JSONbored/loopover name: this repo's own
// pre-rename audit_events rows are still stored under the old full_name and remain real/safe to publish.
"LOOPOVER_PUBLIC_STATS_REPOS": "JSONbored/gittensory,JSONbored/loopover,JSONbored/awesome-claude,JSONbored/metagraphed",
// Website chrome repo stats are public and proxied through the server-side GitHub token, so require
// an explicit narrow allowlist instead of letting unset config proxy arbitrary owner/repo pairs.
"PUBLIC_REPO_STATS_ALLOWLIST": "JSONbored/loopover",
// Duplicate-winner adjudication (#dup-winner): when a same-issue cluster of OPEN PRs forms, spare exactly
// ONE winner — the lowest-numbered (earliest opened) open PR — instead of blocking/closing every sibling.
// Only the LOSERS get the duplicate blocker + close reason + slop penalty + panel block; the winner is
// judged on its own merits. See src/signals/duplicate-winner.ts. ENABLED (#dup-winner-enable): a live
// dry-run audit found the flag-OFF behavior closing EVERY sibling of a duplicate cluster (e.g. #1648 AND
// #1695 both closed) — the opposite of "spare one good PR". With it ON, the earliest open PR in a cluster
// is judged on its merits and only the true duplicates close.
"LOOPOVER_DUPLICATE_WINNER": "true",
// Open-PR file-path collision (#2653): enrich changedFiles on the reviewed PR and its open siblings from
// the pull_request_files cache before building the collision report, so two independently-open PRs on the
// same file get flagged the way two title-similar PRs already are. ENABLED: a repo-wide shadow test against
// the live open-PR queue found path-only term overlap alone drove 12 of 17 newly-flagged pairs to false
// positives (shared generic directory-segment tokens like src/review/test/unit, zero actual shared files) —
// fixed by requiring an actual shared, non-lockfile file path before a path-driven match clusters (see the
// sharesMeaningfulFile guard in buildCollisionReport). Re-validated post-fix: every remaining flagged pair is
// backed by a real shared file.
"LOOPOVER_OPEN_PR_FILE_COLLISION": "true",
// Waste elimination for known automation authors (settings/automation-bot-skip.ts): skip AI review, gate
// evaluation, and public-surface publish entirely for a PR/event genuinely triggered by github-actions[bot]
// (release-please), Renovate, or Dependabot. Default-ON, unlike most flags above -- see that module's own
// doc comment for why. A repo can override via its own repository_settings.skip_automation_bot_authors
// column ("off"/"enabled"), independent of this global default.
"LOOPOVER_SKIP_AUTOMATION_BOT_PRS": "true",
},
"routes": [
// LoopOver rebrand (issue #4762): full cutover, api.loopover.ai only.
{
"pattern": "api.loopover.ai",
"custom_domain": true,
},
],
// R2 bucket bindings were previously configured directly via the dashboard, not tracked in code (#5332).
// REVIEW_AUDIT backs both the review-audit ledger and the /loopover/shot screenshot cache (key-prefixed);
// VISUAL_CAPTURE_PUBLIC is provisioned for a future split of public-facing screenshot storage but is not
// yet read/written by any code path.
"r2_buckets": [
{
"binding": "REVIEW_AUDIT",
"bucket_name": "loopover-review-audit",
},
{
"binding": "VISUAL_CAPTURE_PUBLIC",
"bucket_name": "loopover-visual-capture-public",
},
],
"d1_databases": [
{
"binding": "DB",
"database_name": "loopover",
"database_id": "b2c79dd6-7771-4b1f-aa6b-085d5f3e9528",
"migrations_dir": "migrations",
},
],
// TODO (convergence follow-up): a per-PR LOCK Durable Object (`SubmissionLock` mutex) so concurrent
// webhook deliveries for the same PR serialize. That is a separate, more-involved sub-task — it needs a DO
// class (ported) + its own `migrations` tag (`new_sqlite_classes: ["SubmissionLock"]`) + a `durable_objects`
// binding here. NOT ported in this chunk; the review path keeps its current concurrency behavior until then.
"durable_objects": {
"bindings": [
{
"name": "RATE_LIMITER",
"class_name": "RateLimiter",
},
],
},
"migrations": [
{
"tag": "v1-rate-limiter",
"new_sqlite_classes": ["RateLimiter"],
},
],
// Queue rename (#4768): the producer writes to loopover-jobs. The old gittensory-jobs/-dlq drain-window
// consumers were removed once `wrangler queues info gittensory-jobs` confirmed 0 producers and the queue
// fully drained -- those two queues are retired (no longer bound here at all).
//
// gittensory-webhooks/-dlq were never part of this rename: the WEBHOOKS binding (src/env.d.ts) is only ever
// read by enqueueWebhookByEnv's self-host-only code path (gated behind isSelfHostedReviewRuntime, which is
// always false on this hosted Worker -- see src/github/webhook.ts) -- direct-review-app webhook enqueue is
// retired in favor of the Orb broker's /v1/orb/webhook ingress. Those two queues had 0 producers (leftover
// from before that retirement) and were deleted outright rather than renamed.
"queues": {
"producers": [
{
"binding": "JOBS",
"queue": "loopover-jobs",
},
],
"consumers": [
{
// API/broker maintenance lane. Review execution jobs are ignored unless the self-host Redis-backed
// runtime binding exists; the deployed Cloudflare worker does not bind it.
// - max_batch_size 5 (was 10): one batch can't bundle as many heavy sweep/backfill jobs at once.
// - max_concurrency 3: bounded fan-out — enough to drain metagraphed's worst sweep within the 2-min
// cron interval, but not so wide it floods the shared GitHub installation rate bucket. (A follow-up
// may tighten this to 2 once the sweep fans into tiny per-PR jobs.)
// - retry_delay 30: a failed job backs off 30s instead of re-delivering immediately and re-hammering
// the already-overloaded path.
"queue": "loopover-jobs",
"max_batch_size": 5,
"max_batch_timeout": 5,
"max_concurrency": 3,
// After max_retries failed attempts a job is dead-lettered so a persistently-failing job is observable
// rather than vanishing silently. The DLQ consumer below picks them up.
"max_retries": 3,
"retry_delay": 30,
"dead_letter_queue": "loopover-jobs-dlq",
},
{
// DLQ consumer: receives jobs that exhausted all main-queue retries. Logs each dead-lettered
// job for observability (Cloudflare Workers logs + audit_events) and acks immediately — no
// further retries (the job already failed max_retries times). max_retries: 0 prevents the
// DLQ consumer itself from sending messages to a secondary DLQ on handler error.
"queue": "loopover-jobs-dlq",
"max_batch_size": 10,
"max_batch_timeout": 30,
"max_retries": 0,
},
],
},
"triggers": {
// Broker/API maintenance tick. The self-host container runs the review sweep; Cloudflare does not execute
// hosted reviews.
"crons": ["*/2 * * * *"],
},
}