Repository navigation
fix(web): disable AI chat on the EU instance - #997
Conversation
Hide every chat entry point (header button, command palette action, C shortcut, widget fix action) and redirect /chat to / when the dashboard is built for the EU region.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches📝 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 |
Maple observability review: 96/100Excellent · Observability looks complete · reviewed
PR #997 gates the AI chat feature off on the EU instance by hiding the chat entry points (header button, command palette action, global chat sheet, widget fix action) and redirecting /chat to / in the TanStack Router beforeLoad hook. The gating is a single client-side constant (aiChatEnabled in region.ts) and the change adds no observability at all: no client event, log, span, or metric is emitted when the feature is silently removed for EU users. All six hunks read; no unit the diff adds carries instrumentation, though the repo's existing web telemetry (web.vitals/web.performance) is unrelated to this feature's removal and needs no work here. Findings
What to changeObservability gap ( The change removes a user-facing feature (AI chat) from the EU instance by hiding or redirecting every entry point, but adds no telemetry: no client event, log, span attribute or metric. maple-web reports web.vitals and web.performance metrics to Maple; nothing on this new flag will appear. Six months from now, if EU users report that AI chat vanished, there will be no way to see from telemetry when the gate shipped, which region applied it, or whether any users still hit /chat redirects and were dropped on /. Observability gap ( The /chat beforeLoad redirect covers old notification deep links but produces no trace signal that the redirect happened — the span for the /chat navigation and the redirect outcome carry no distinguishing attribute, and no event is logged. If EU traffic still arrives on /chat (which the redirect implies it will), this traffic is invisible to Maple. What was reviewed
Score: 100, minus 25 per critical finding, 10 per warning and 2 per note. Check ids refer to Maple's instrumentation audit. Updated on every push. |
A review pass gets `review_files`, an @effect-agent/capabilities Subagent delegation. Past 12 reviewable files the prompt has it split the files into groups of related files and delegate each group, in parallel, to a `pr-review-worker` child: the parent's own read-only toolkit (the grant is exactly those tools, depth one), 16 calls and 4 minutes per child, at most 8 children and 4 at a time, reserved from the parent's budget. The child answers confirmed findings one per line; the parent verifies and files. Verified with review:local on #997 with a forcing prompt: the child ran, returned a finding, and the parent filed it through submit_review. docs/pr-review-agent-plan.md now describes the built agent end to end, including the GitHub App permissions and events it needs.
…maple conversations and fixes (#1001) * feat(pr-review): review pull requests for correctness, security and performance, not only observability The reviewer becomes a general code review agent. Observability stays as one lens with its maple-audit check ids. - Findings carry a category; only observability findings need a check id. - Verdict is clean | issues | not_applicable. A data migration rewrites stored reviews (gaps -> issues, instrumented -> clean, findings get category observability). - A finding may carry `replacement`, the exact code for its line range, posted as a GitHub suggestion over that range. - The prompt reads the repository's CLAUDE.md / AGENTS.md / .maple/review.md as rules and may read callers to confirm a bug. - Config and test files are reviewed; call budget 3/file + 6 (8..60), pass ceiling 80 calls / 12 minutes. - Check run renamed `Maple / review`. - docs/pr-review-agent-plan.md gains the phase 1-5 plan. * feat(pr-review): pr_context tool and a review:eval harness pr_context: one call returns the pull request's commits, what people and other bots already said on it (the App's own comments excluded) and the head commit's checks, failing first. The prompt calls it once so a review never repeats a thread or restates a CI failure. Wired through GithubAppClient -> GithubProvider -> VcsSourceService, and answered from `gh` in review:local. review:eval: `mine` blames each fix: commit's changed lines back to the squash-merged PR that wrote them; `run` reviews every curated case in pr-review-eval/corpus.json and counts it caught when a finding lands within three lines of what the fix changed. Seed corpus: five shipped bugs. * feat(pr-review): follow findings across pushes, resolve fixed threads, debounce bursts Phase 2 of the review agent. - pr_review_findings stores every posted finding with a pull request-wide handle (F1, F2, ...), its inline comment id and open | resolved | dismissed. - A later push's kickoff names the last reviewed head, the files changed since (GitHub compare) and the findings still open. submit_review returns `resolved` handles; the service replies "Fixed in <sha>" and resolves the thread through GraphQL resolveReviewThread. - A new finding within three lines of an open or dismissed one in the same category is not posted again. A thread a person resolved, or answered "won't fix", marks its finding dismissed before the next review. - The summary carries "Still open from earlier reviews" and "Fixed since the last review"; the score counts findings still open, not only new ones. - A synchronize is debounced: the row is queued at once (so an older head is still superseded) and the start is re-enqueued with a 90 s delay; the delayed copy starts only a row no later push replaced. Fix verification ignores the delayed copy. - Per-repository review settings (vcs_repositories.pr_review_config): instructions, ignored paths, categories, inline threshold, drafts. Stated in the kickoff and enforced on submit. * feat(pr-review): answer @maple on pull requests, re-review on request, commit asked-for fixes Phases 3 and 4 of the review agent. Conversation: - GitHub `issue_comment` and `pull_request_review_comment` webhooks map to a new `pull-request-comment` job only when a person (not a bot) mentions @maple on a pull request. VcsSyncService forwards it to an optional PullRequestCommentSink; apps/api binds PrReviewConversationService. - Answered for OWNER / MEMBER / COLLABORATOR only, 100 answers per org per day, once per comment (pr_review_replies unique on repository + comment). - Each answer is one turn of a new `pr-reply` agent on `<orgId>:prr-<id>` with the review's read-only tools, finishing on `submit_reply`. The thread it posts to (conversation or review-thread root) is bound on the row, never taken from the model. 👀 on receipt; a pass that ends without an answer says so on the pull request. - `@maple review` re-reviews the head now: no debounce, drafts included, a head already reviewed is reviewed again (PrReviewService.reviewNow). Fixes: - `@maple fix` offers `propose_edit`: exact oldText -> newText edits staged in pr_review_edits. On submit they are applied to the files at the head and committed through the Git Data API as one commit, fast-forwarding the PR branch (never forced). - Only for commenters with write/maintain/admin, only on the same repository's branch (never a fork or the default branch), never under .github/workflows or .git, at most 40 edits. A branch that moved since the head was read, or an edit that no longer applies, is reported instead of committed. Needs the App's `contents: write`. * feat(pr-review): repository review settings, review history API, reaction-based precision Phase 5 backend. - GET/PUT /api/integrations/github/repositories/:id/pr-review/config reads and writes a repository's PrReviewRepositoryConfig (instructions, ignored paths, lenses, inline threshold, drafts, dailyLimit). Any member reads, admins write; input is trimmed and de-duplicated. - GET /api/integrations/github/repositories/:id/pr-reviews lists the 50 most recent reviews with status, verdict, score and finding count. - dailyLimit caps reviews per repository per UTC day under the org ceiling. - The review-thread query now reads 👍 / 👎 on each inline comment. They are stored per finding (reactions_up/down) whenever threads are read: before a follow-up review and when the pull request closes, which also records last-minute dismissals. Totals land on the span as maple.pr_review.reactions_up / reactions_down, the live precision signal. * feat(web): review settings and history for a repository's pull request reviews A gear beside a repository's "Review PRs" switch (shown when the org has the prreview flag and the repository has reviews on) opens a dialog: - Settings: extra review rules, ignored paths, lenses, inline threshold, review drafts, daily limit. Loaded with githubGetPrReviewConfig, saved with githubSetPrReviewConfig; admins only, others see it read-only. - Recent reviews: the 50 newest from githubListPrReviews with outcome, score, findings, time and a link to the review comment; refetches every 5 s while one is queued or running. * feat(pr-review): fan a large pull request out to child reviewers A review pass gets `review_files`, an @effect-agent/capabilities Subagent delegation. Past 12 reviewable files the prompt has it split the files into groups of related files and delegate each group, in parallel, to a `pr-review-worker` child: the parent's own read-only toolkit (the grant is exactly those tools, depth one), 16 calls and 4 minutes per child, at most 8 children and 4 at a time, reserved from the parent's budget. The child answers confirmed findings one per line; the parent verifies and files. Verified with review:local on #997 with a forcing prompt: the child ran, returned a finding, and the parent filed it through submit_review. docs/pr-review-agent-plan.md now describes the built agent end to end, including the GitHub App permissions and events it needs. * fix(pr-review): accept quoted numbers and booleans in submit_review and review_files The first Opus eval lost two of five runs to a strict decode: the model sent line/endLine as "12" and coverage.instrumented as "true", and a tool-argument decode failure ends the run. The submission schema is meant to be lenient; numbers and booleans now accept their string forms and the normalizer parses them (an unparseable line still drops the finding). * fix(pr-review): accept null for any field a model leaves empty in submit_review The second Opus eval lost two runs to checkId: null on findings outside observability. Every submission field now accepts null as well as being optional; the normalizer already treats both as absent. * fix(pr-review): keep file modes in fix commits, and five review fixes - commitFiles keeps an edited file's mode from the parent tree and refuses symlinks and submodules, so a fix to a script no longer drops its exec bit. - A question or a negation in a finding's thread no longer dismisses it. - `@maple review` while that head's review is queued or running reports it as started instead of failing as a duplicate. - A failed read of a file being fixed stops the commit; only a 404 means the file is missing. - review_files bounds its paths in prepareInput, so an oversized group is a returned failure instead of a decode error that ends the parent run. - pr_context reads checks from the pull request's head, not the last commit on the first page. * fix(pr-review): address review feedback and fix CI after merging main CI: - Merge main. pr_context declares its `phrases`, which main's McpToolOptions now requires. - The four review migrations are regenerated on top of main's chat_workspace_credentials (they were never deployed): the verdict data migration, then one pr_review_agent schema migration. - pr-review-local decodes each gh read at the boundary instead of returning unknown (effect-lint). - dispatcher.test lists pr_context among the internal tools. - run-tool-failures.test expects the tool-call `label` main's #1011 added; main fails the same test. Review feedback: - A mention inside a quote or fenced code no longer starts a command, so quoting "@maple fix" cannot trigger a commit. The reply agent still gets the whole comment. - A reclaimed skipped or completed review clears skipReason and publishError. - githubListPrReviews decodes rows with decodeAll, so one bad row is a typed persistence error, not a 500. - review_files: the worker reports maintainability and observability check ids like the parent; `number` must be a positive integer; up to 12 children. - pr-review-local reads checks from the PR's head SHA. - review:eval rejects a flag without a value and a non-integer --limit, keeps insertion-only fix hunks, and reports a location match as "located" rather than claiming the bug was caught. - Settings dialog: controls are frozen while saving; review history keeps polling after a failed refresh. * fix(pr-review): refuse a fix whose path passes through a symlink or submodule commitFiles already refused a symlink or submodule as the edited file itself; an intermediate segment of that kind was treated as a new file, so the tree write would go through it or replace it. It is now refused the same way. * fix(pr-review): drop only unanchorable inline comments, read rules at the base - Inline comments are checked against the pull request's diff hunks before the review is posted. A comment outside the diff (or on a file with no patch, or a range spanning two hunks) is dropped alone and noted in the review body; the summary comment still carries it. Before, one bad line was a 422 that threw away every inline comment and its thread tracking. - The reviewer reads CLAUDE.md, AGENTS.md and .maple/review.md at the base SHA, so a pull request cannot rewrite the rules it is reviewed by. * fix(pr-review): keep post-save edits, clear stale results on reclaim, and two eval/fan-out bounds - Settings: a config refetch that lands after Save no longer replaces edits made since; it only resets fields the person left untouched. - A reclaimed review clears reportJson and score, so the history never shows the previous run's result while the new one runs. - review:eval writes located (not caught) in results.json, matching the summary. - review_files rejects a PR number that is not a safe integer.
…k on (#1052) The EU instance shipped with AI off (#997) because model calls would carry customer spans and logs to US providers. OpenRouter's in-region routing closes that: requests to eu.openrouter.ai are decrypted and served only by providers inside the EU, and a model with no EU provider is a 404 rather than a hop to the US. With MAPLE_REGION=eu, every OpenRouter call (chat, reviews, embeddings, decisions) goes to https://eu.openrouter.ai/api/v1. The EU catalogue serves none of the US defaults, so the EU instance defaults to openai/gpt-6-luna for chat, triage and reviews. Jev has no EU provider, so the EU has no decision model unless MAPLE_DECISION_MODEL is set; the triage route says so without calling out, and the gate reads no verdict as "investigate". Reverts the web gating from #997 so every chat entry point is back on EU.
Turns off Maple AI chat on the EU dashboard for now. One flag,
aiChatEnabled = currentRegion !== "eu"inapps/web/src/lib/region.ts, gates every entry point:Cshortcut (the global chat sheet never mounts)/chat, which now redirects to/(covers old notification deep links)US is unchanged.
Not covered: the EU API still forwards
/api/chat/*to its AI Worker, and the follow-up chat inside investigations still works. Both can be gated separately if needed.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by CodeRabbit