Conversation
Introduce replayCacheTtlMinutes (5-120 min, default 30) as a database-backed system setting controlling how long completed Replay payloads remain reusable in the PostgreSQL durable layer. The Redis hot-layer TTL is capped to the same window so both tiers expire in sync. This replaces the removed REPLAY_COMPLETED_TTL_SECONDS environment variable, moving the durable TTL into the admin-editable settings surface with full validation, i18n labels, API schema, and UI input. Also fix the replay cleanup query to bind the cutoff Date through sql.param for correct PostgreSQL type coercion, and preserve wrapped database error causes in the cleanup scheduler logging.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough新增 Replay 完成载荷缓存 TTL 配置。系统支持数据库存储、API 校验、设置界面、运行时 TTL 计算和清理日志。代理新增 Remote Compaction v2 处理、请求体同步和流帧识别。ReplaySpool 改进终止清理。密钥禁用失败使用专用错误码。 ChangesReplay 缓存 TTL
Remote Compaction v2
密钥禁用错误码
代理数据隔离与 ReplaySpool
Estimated code review effort: 5 (Critical) | ~100 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (6)
tests/unit/repository/system-config-degradation-ladder.test.ts (1)
317-317: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value建议将更新调用次数改为派生值。
读取路径的断言已改为由
RECENT_COLUMNS.length派生(第 194、227-229 行)。写入路径仍使用字面量23。每次新增系统设置列,都需要手工修改此数字。如果写入降级阶梯与RECENT_COLUMNS存在固定关系,请改为派生表达式,保持两条路径一致。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/unit/repository/system-config-degradation-ladder.test.ts` at line 317, 将 system-config degradation ladder 写入路径中 updateMock 的固定调用次数 23 改为基于 RECENT_COLUMNS.length 的派生表达式,复用读取路径的既有关系,确保新增系统设置列时读写断言保持一致。tests/api/v1/system/system-config.test.ts (1)
183-191: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win建议补充上界与边界值用例。
当前只覆盖了下界外的
4。允许范围为 5-120。建议再加121(上界外,期望 400)与5、120(边界内,期望 200),以锁定范围两端的行为。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/api/v1/system/system-config.test.ts` around lines 183 - 191, Extend the replayCacheTtlMinutes validation cases in the system settings test to cover 121 as an invalid upper-bound value expecting 400, and 5 and 120 as valid boundary values expecting 200. Keep the existing invalid value 4 assertion and reuse the same authorized PUT request flow.tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx (1)
249-251: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value建议避免硬编码本地化文案。
此处断言完整的英文文案。如果
messages/en/settings/config.json中replayCacheTtlInvalid的措辞调整,此测试会失败,但功能并未回归。建议从消息文件读取该键的值再断言,使测试只验证“显示了对应错误码的本地化消息”。♻️ 参考改法
+import enConfigMessages from "`@/`../messages/en/settings/config.json"; + ... expect(sonnerMocks.toast.error).toHaveBeenCalledWith( - "Replay cache duration must be a whole number from 5 to 120 minutes." + enConfigMessages.form.replayCacheTtlInvalid );导入路径需按仓库现有的 messages 导入方式调整。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx` around lines 249 - 251, Update the assertion in the replay-cache validation test to import and use the localized value for the replayCacheTtlInvalid message from the repository’s established messages-loading mechanism, instead of hardcoding the English text. Keep the assertion focused on verifying that toast.error receives that message.src/drizzle/schema.ts (1)
1059-1060: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value建议复用默认值常量,避免多处硬编码。
此处默认值硬编码为
30。仓库其他位置(src/repository/system-config.ts、src/repository/_shared/transformers.ts)使用REPLAY_CACHE_TTL_MINUTES_DEFAULT。如果该常量将来调整,本行不会同步。可以引入该常量以保持单一事实来源。注意:修改后仍需保证生成的迁移 SQL 默认值不变。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/drizzle/schema.ts` around lines 1059 - 1060, 将 replayCacheTtlMinutes 的默认值改为复用 REPLAY_CACHE_TTL_MINUTES_DEFAULT,并补充必要的导入,避免继续硬编码 30;同时确认生成的迁移 SQL 默认值仍保持为 30。tests/unit/actions/system-config-save.test.ts (1)
164-173: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win补充 5 和 120 的有效边界测试。
当前测试只验证 30 通过,验证 4、121 和 30.5 被拒绝。请增加
5和120的有效参数化案例。这样可以确认允许范围是闭区间[5, 120],并防止边界条件回归。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/unit/actions/system-config-save.test.ts` around lines 164 - 173, 在 Replay cache TTL 参数化测试中补充有效值 5 和 120 的测试案例,分别验证 saveSystemSettings 返回成功并调用 updateSystemSettingsMock。保留现有对 4、121 和 30.5 的拒绝断言,以确认允许范围为闭区间 [5, 120]。src/repository/system-config.ts (1)
287-292: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value将 old-schema Replay 列更新降级的回归测试补在现有退化阶梯测试中。
replayCacheTtlMinutes已进入近代阶梯并被旧 schema 更新路径处理;system-config-update-missing-columns.test.ts没有覆盖replayCacheTtlMinutes+ 旧世代set/returning组合,而system-config-degradation-ladder.test.ts已覆盖更新路径的完整降阶梯列集合。避免为同一场景新增分散测试文件。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/repository/system-config.ts` around lines 287 - 292, 在现有 system-config-degradation-ladder.test.ts 的完整降阶梯测试中补充 replayCacheTtlMinutes 的旧 schema 更新回归覆盖,验证缺少该列时旧世代 set/returning 组合仍按预期降级。不要新增分散测试文件,并保持 system-config-update-missing-columns.test.ts 的职责不变。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/instrumentation.ts`:
- Around line 331-340: 调整 runReplayCleanupTick 的成功与失败日志调用,将结构化对象参数放在消息字符串之前,确保
deleted 统计和 describeSchedulerError(error) 返回的字段被 Pino 合并为日志字段;同步更新
tests/unit/instrumentation-replay-cleanup.test.ts 中对应的参数顺序断言。
In `@src/lib/validation/schemas.ts`:
- Around line 24-28: Update the import of REPLAY_CACHE_TTL_INVALID_ERROR_CODE,
REPLAY_CACHE_TTL_MINUTES_MAX, and REPLAY_CACHE_TTL_MINUTES_MIN in schemas.ts to
use the `@/lib/validation/replay-settings` path alias instead of the relative
./replay-settings path.
In `@src/repository/_shared/transformers.ts`:
- Line 324: Update the replayCacheTtlMinutes handling in toSystemSettings to
validate database values are within the allowed 5–120 minute range before
returning them; fall back to REPLAY_CACHE_TTL_MINUTES_DEFAULT for missing or
out-of-range values, while preserving valid configured values.
---
Nitpick comments:
In `@src/drizzle/schema.ts`:
- Around line 1059-1060: 将 replayCacheTtlMinutes 的默认值改为复用
REPLAY_CACHE_TTL_MINUTES_DEFAULT,并补充必要的导入,避免继续硬编码 30;同时确认生成的迁移 SQL 默认值仍保持为 30。
In `@src/repository/system-config.ts`:
- Around line 287-292: 在现有 system-config-degradation-ladder.test.ts 的完整降阶梯测试中补充
replayCacheTtlMinutes 的旧 schema 更新回归覆盖,验证缺少该列时旧世代 set/returning
组合仍按预期降级。不要新增分散测试文件,并保持 system-config-update-missing-columns.test.ts 的职责不变。
In `@tests/api/v1/system/system-config.test.ts`:
- Around line 183-191: Extend the replayCacheTtlMinutes validation cases in the
system settings test to cover 121 as an invalid upper-bound value expecting 400,
and 5 and 120 as valid boundary values expecting 200. Keep the existing invalid
value 4 assertion and reuse the same authorized PUT request flow.
In `@tests/unit/actions/system-config-save.test.ts`:
- Around line 164-173: 在 Replay cache TTL 参数化测试中补充有效值 5 和 120 的测试案例,分别验证
saveSystemSettings 返回成功并调用 updateSystemSettingsMock。保留现有对 4、121 和 30.5
的拒绝断言,以确认允许范围为闭区间 [5, 120]。
In `@tests/unit/repository/system-config-degradation-ladder.test.ts`:
- Line 317: 将 system-config degradation ladder 写入路径中 updateMock 的固定调用次数 23 改为基于
RECENT_COLUMNS.length 的派生表达式,复用读取路径的既有关系,确保新增系统设置列时读写断言保持一致。
In `@tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx`:
- Around line 249-251: Update the assertion in the replay-cache validation test
to import and use the localized value for the replayCacheTtlInvalid message from
the repository’s established messages-loading mechanism, instead of hardcoding
the English text. Keep the assertion focused on verifying that toast.error
receives that message.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 95c21ff2-fc4c-45fb-bdae-fca91ade7d71
📒 Files selected for processing (34)
drizzle/0119_tiresome_banshee.sqldrizzle/meta/0119_snapshot.jsondrizzle/meta/_journal.jsonmessages/en/settings/config.jsonmessages/ja/settings/config.jsonmessages/ru/settings/config.jsonmessages/zh-CN/settings/config.jsonmessages/zh-TW/settings/config.jsonsrc/actions/system-config.tssrc/app/[locale]/settings/config/_components/system-settings-form.tsxsrc/app/[locale]/settings/config/page.tsxsrc/app/api/v1/resources/system/router.tssrc/app/v1/_lib/proxy/replay/replay-store.tssrc/drizzle/schema.tssrc/instrumentation.tssrc/lib/api-client/v1/openapi-types.gen.tssrc/lib/api/v1/schemas/system-config.tssrc/lib/config/env.schema.tssrc/lib/config/system-settings-cache.tssrc/lib/system-settings/proxy-runtime.tssrc/lib/validation/replay-settings.tssrc/lib/validation/schemas.tssrc/repository/_shared/transformers.test.tssrc/repository/_shared/transformers.tssrc/repository/system-config.tssrc/types/system-config.tstests/api/v1/system/system-config.test.tstests/unit/actions/system-config-save.test.tstests/unit/instrumentation-replay-cleanup.test.tstests/unit/proxy/replay-store.test.tstests/unit/proxy/stream-gate-mode-resolution.test.tstests/unit/repository/system-config-degradation-ladder.test.tstests/unit/repository/system-config-update-missing-columns.test.tstests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx
💤 Files with no reviewable changes (1)
- src/lib/config/env.schema.ts
🧪 测试结果
总体结果: ✅ 所有测试通过 |
🧪 测试结果
总体结果: ✅ 所有测试通过 |
There was a problem hiding this comment.
Code Review Summary
No significant issues identified in this PR.
PR Size: XL
- Lines changed: 5932
- Files changed: 34
- Split suggestions:
- Separate the generated Drizzle migration/snapshot artifacts from the hand-written runtime changes.
- Separate the replay TTL/settings surface work from the replay cleanup SQL/logging fix.
- Separate generated OpenAPI client/types updates from UI and test updates.
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean
- Type safety - Clean
- Documentation accuracy - Clean
- Test coverage - Adequate
- Code clarity - Good
Automated review by Codex AI
There was a problem hiding this comment.
- Review for PR
#1402is complete. - Applied the
size/XLlabel and posted the required summary review comment on the PR. - No inline review comments were added because no changed-line issues survived validation at the required confidence threshold.
- The posted XL split suggestions recommend separating generated Drizzle artifacts, replay TTL/settings changes, and generated OpenAPI updates from the runtime/UI/test work.
- Validation notes:
git diff --checkpassed; targetedvitestexecution was not possible here becausebunxis unavailable in this environment.
If you want, I can still do a second-pass review focused on one area such as replay cleanup, settings validation, or the UI form changes.
The toSystemSettings transformer now validates that replayCacheTtlMinutes is an integer within the min/max bounds (5–120), falling back to the default for any out-of-range or non-integer value. Previously, arbitrary values from the database would pass through unchecked. The API update handler now maps replay TTL validation failures to the REPLAY_CACHE_TTL_INVALID error code via getReplayCacheTtlValidationErrorCode, so clients receive a precise error instead of a generic validation failure. Additional review-driven fixes: - Schema default references the shared REPLAY_CACHE_TTL_MINUTES_DEFAULT constant instead of a magic number - Import paths in schemas.ts normalized to absolute module specifiers - Tests cover boundary values (5, 120), upper-limit rejection (121), and invalid-value fallback in the transformer - Degradation ladder test includes replayCacheTtlMinutes in its update payload and returning-column assertions - Form test uses the i18n message key instead of a hardcoded string
The replay cleanup scheduler passed the message string as the first argument and the structured data object as the second, which is the reverse of the pino calling convention. Swap them so the data object is first and the message string is second, matching the rest of the codebase. Test expectations updated accordingly.
🧪 测试结果
总体结果: ✅ 所有测试通过 |
* fix(proxy): support remote compaction v2 passthrough * fix(proxy): address remote compaction review feedback * fix(proxy): localize normalized request errors * test(proxy): cover localized normalization errors
🧪 测试结果
总体结果: ✅ 所有测试通过 |
* fix(proxy): prevent shared mutation and replay memory retention Rectifiers and cache TTL overrides mutated shared nested arrays in place, leaking attempt-specific edits across concurrent shadow sessions and the original request. Switch to copy-on-write: filtered arrays are assigned through the top-level message object, TTL override rebuilds only changed message entries, and shadow sessions shallow-copy the request message while sharing the readonly buffer instead of deep-cloning multi-MB request bodies per shadow. ReplaySpool retained full payload while Redis or PG writes blocked and abort/disable raced with in-flight flushes. Payload is now snapshotted and cleared before persistence; abort immediately releases accumulated parts and queued batches, deduplicates concurrent calls through a shared barrier, and fences store cleanup through the writeChain so concurrency quota is freed only after cleanup completes. Streaming detection now reads the stream flag directly from the outgoing message instead of re-parsing the serialized body. * fix(types): resolve tsgo type inference failures for zod 4 body parsing tsgo (TypeScript native preview) could not infer the generic output type from JsonBodySchema<T>'s structural safeParse signature because zod 4 uses this-type polymorphism (core.output<this>) instead of a plain generic. This left body.data as unknown across all v1 API handlers, producing 36 TS18046/TS2698/TS2345 errors. Switch parseHonoJsonBody/parseJsonBody/parseJson to infer the schema type directly (<S extends z.ZodType>) and extract the output via z.output<S>, which tsgo resolves correctly. Add explicit parameter annotations to four zod .transform()/.refine() callbacks where tsgo also failed to infer the this-dependent input type. CI Run: https://github.com/ding113/claude-code-hub/actions/runs/31245382874 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
🧪 测试结果
总体结果: ✅ 所有测试通过 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/app/v1/_lib/proxy/replay/replay-spool.ts (1)
410-412: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value建议把新增字段声明移到类顶部的字段块。
released、aborting、abortPromise声明在teardown()之后、release()之前。类字段在构造时初始化,因此方法体内读取this.aborting没有运行时问题。但这三个字段被第 129、150、180、201、249、334 行等多处方法引用,声明位置分散会降低可读性。♻️ 建议的调整
private writeChain: Promise<void> = Promise.resolve(); private metaWritten = false; + private released = false; + private aborting = false; + private abortPromise: Promise<void> | null = null;- private released = false; - private aborting = false; - private abortPromise: Promise<void> | null = null; - private release(): void {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/v1/_lib/proxy/replay/replay-spool.ts` around lines 410 - 412, 将 released、aborting 和 abortPromise 三个字段声明移到类顶部的字段声明区域,位于其他实例字段附近;保留其现有初始化值和类型不变,并移除 teardown() 与 release() 之间的重复声明,不修改 teardown()、release() 及其他方法的行为。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/app/v1/_lib/proxy/replay/replay-spool.ts`:
- Around line 410-412: 将 released、aborting 和 abortPromise
三个字段声明移到类顶部的字段声明区域,位于其他实例字段附近;保留其现有初始化值和类型不变,并移除 teardown() 与 release()
之间的重复声明,不修改 teardown()、release() 及其他方法的行为。
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a995a0f9-999e-41d2-9a41-5eb918e75ca7
📒 Files selected for processing (13)
src/app/api/v1/resources/providers/handlers.tssrc/app/v1/_lib/proxy/billing-header-rectifier.tssrc/app/v1/_lib/proxy/forwarder.tssrc/app/v1/_lib/proxy/replay/replay-spool.tssrc/lib/api/v1/_shared/request-body.tssrc/lib/api/v1/schemas/audit-logs.tssrc/lib/api/v1/schemas/me.tssrc/lib/api/v1/schemas/system-config.tssrc/lib/api/v1/schemas/usage-logs.tstests/unit/proxy/billing-header-rectifier.test.tstests/unit/proxy/cache-ttl-override.test.tstests/unit/proxy/proxy-forwarder-hedge-first-byte.test.tstests/unit/proxy/replay-spool.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/api/v1/schemas/system-config.ts
…1411) * fix(stream-gate): recognize Responses compaction in terminal frames Some Responses upstreams return compaction output only in response.completed without first emitting response.output_item.done, so the content gate treated the stream as empty and triggered false failover with circuit-breaking. classifyParsedFrame now accepts the protocol family and, for openai-responses, detects a compaction output item with non-empty encrypted_content inside response.completed, classifying the frame as content so the gate commits the stream. Regression tests cover compaction-only terminal frames and custom tool-call input deltas across the classifier, content gate, and forwarder integration paths. Fixes #1410 * fix(stream-gate): require non-empty string for compaction encrypted_content The compaction signal rule on response.output_item.done accepted any truthy encrypted_content value, allowing non-string types (booleans, numbers, objects) to be misclassified as content. Consolidate the per-item type guard into isNonEmptyCompactionItem and apply it to both response.output_item.done and response.completed paths so the opaque state must be a non-empty string before a frame is committed as content. Add regression tests covering malformed encrypted_content types across event variants.
🧪 测试结果
总体结果: ✅ 所有测试通过 |
fix(proxy): bound Replay disconnect memory retention (#1408)
🧪 测试结果
总体结果: ✅ 所有测试通过 |
* feat(availability): outbox + 1m projection buckets for admin monitoring Replace on-the-fly message_request scans with trigger/outbox-fed avail_bucket_1m/avail_current so availability APIs stay fast under load. * fix(availability): address review on projection freshness and worker safety * fix(availability): stable provider lock order in projection worker Sort provider/bucket ids before upsert and recompute so concurrent worker instances take avail_current locks in the same order.
Co-authored-by: GPT-5 <noreply@openai.com>
Deduplicate request-scoped Redis session response bodies while preserving legacy reader compatibility, response snapshot semantics, redaction boundaries, TTL behavior, and termination cleanup.\n\nAdd generation fencing for late writers, atomic legacy fallback reads, full-session cleanup coverage, Redis integration regression tests, and the 64 x 5 MiB RDB load fixture.\n\nCloses #1415
Reformats floorToUtcMinute and projection-worker test mocks to satisfy Biome line-width rules. Reorders CURRENT_PROVIDER_STATUS_WINDOW_MINUTES ahead of the calculateAvailabilityScore export in index.ts to match alphabetical sorting.
🧪 测试结果
总体结果: ✅ 所有测试通过 |
Release summary
This release PR promotes the current
devbranch tomainasv0.9.3.Included changes
Datewithout the Drizzle timestamp encoder.cause,name,message, andcodein cleanup scheduler logs.replayCacheTtlMinutessystem setting.REPLAY_TTL_SECONDS.replay_payloadscleanup remains documented in PR fix(replay): repair cleanup and add configurable cache TTL #1400; merging this release does not immediately reclaim the historical table/TOAST disk space.Source PR
Validation
dev.devworkflows passed:Release notes
v0.9.3maindevGreptile Summary
The release adds configurable Replay retention, repairs Replay cleanup and error logging, bounds and deduplicates session response-body storage, and introduces database-backed availability projections.
replayCacheTtlMinutessetting across migrations, repository access, validation, REST/OpenAPI, runtime caching, and localized settings UI.Confidence Score: 5/5
The PR appears safe to merge because no blocking failure remains.
No blocking failure remains.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR Request[Proxy request] --> ReplaySpool[Bounded Replay spool] ReplaySpool --> Redis[(Redis hot Replay)] ReplaySpool -->|after billing commit| Postgres[(PostgreSQL durable Replay)] Settings[System settings] --> Runtime[Runtime TTL resolver] Runtime --> ReplaySpool Request --> MessageRequest[Finalized message_request] MessageRequest --> Trigger[Outbox trigger] Trigger --> Outbox[(outbox_events)] Outbox --> Worker[Availability projection worker] Worker --> Buckets[(avail_bucket_1m)] Worker --> Current[(avail_current)] Buckets --> Dashboard[Availability dashboard] Current --> DashboardReviews (10): Last reviewed commit: "style(availability): apply Biome formatt..." | Re-trigger Greptile
Context used (5)