Split/1 cli prompt store constants#503
Conversation
…pport - Switch LangGraph stream_mode from ["updates"] to ["events"] for fine-grained tool calls, LLM reasoning, and chain transitions in real-time - Add reasoning mapper (app/remote/reasoning.py) to translate events into human-readable spinner subtext (replaces fake cycling verbs) - Enhance StreamRenderer and _LiveSpinner to show live tool calls and LLM reasoning instead of cosmetic placeholders - Add astream_investigation() async runner and CLI bridge for local streaming with the same UX as remote - Add POST /investigate/stream SSE endpoint to the lightweight FastAPI server - Make opensre deploy fully interactive: context-aware menu, health check, confirmation prompts, branch selection - Add named remotes to the wizard store so multiple remote endpoints (ec2, staging, local) can coexist with an active selection - Deploy always saves the EC2 URL as a named remote and sets it active - opensre remote shows a remote picker when multiple remotes are configured Made-with: Cursor
…ions
Empty investigation reports were caused by two bugs:
1. _save_investigation used result.get('key', 'N/A') which returns ""
when the key exists but is empty, instead of the 'N/A' fallback.
Fixed with `or 'N/A'` to treat empty strings as missing.
2. Noise-classified alerts routed to END before diagnose/publish ran,
leaving root_cause, report, and problem_md as "". Now propagates
is_noise through the result dict and writes an explanatory message.
Also adds interactive investigation browser (select + view + save)
and persists streamed investigation results as .md files.
Made-with: Cursor
Keep managed EC2 deployment state in app-owned local storage, preserve streamed investigations on disconnect, and surface local streaming failures promptly so the remote CLI can stay stream-first and merge-ready. Made-with: Cursor
Redact api_token values in integration show output and allow vercel records to be shown through the managed integrations CLI so credentials are not exposed during inspection. Made-with: Cursor
Support Vercel incident discovery and RCA from the CLI and remote server so deployment failures can be selected, investigated, and correlated with GitHub code context. Made-with: Cursor
Use the project-scoped Vercel runtime log API and structured error fields so the CLI finds the same incidents users see in the dashboard. Add loading feedback after project selection and keep the Vercel RCA tests aligned with the updated behavior. Made-with: Cursor
Resolve the PR conflicts by keeping the Vercel RCA flows, setup verification behavior, and remote server integrations while bringing in the latest main-branch updates. Made-with: Cursor
- Add INTEGRATIONS_STORE_PATH and shared home constants; wire integrations store. - Add prompt_support (questionary escape/cancel) for opensre and wizard entrypoints. - Wizard prompt/store tweaks and tests; daily-update workflow and Makefile. Made-with: Cursor
Resolve conflicts by aligning integrations CLI, Vercel client (streaming runtime logs), poller, VercelLogsTool, and tests with main; remove the obsolete vercel incident subcommand from the branch side. Made-with: Cursor
Greptile SummaryThis PR introduces Confidence Score: 5/5Safe to merge; all findings are minor style suggestions with no correctness or reliability impact. The new module is logically correct: error paths are caught and surfaced via No files require special attention.
|
| Filename | Overview |
|---|---|
| app/integrations/vercel_incidents.py | New module providing interactive CLI helpers for Vercel incidents and RCA reports; logic is sound, but _die() should be typed -> Never and the unreachable return statements after each _die() call should be removed. |
| tests/integrations/test_vercel_incidents.py | Good test coverage for the happy path, error handling, and cache round-trip; one unnecessary monkeypatch (resolve_vercel_config) in the JSON-output test adds noise without providing signal. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[cmd_vercel_incidents] --> B{is_json_output?}
B -- Yes --> C[_load_incidents]
C --> D[collect_vercel_candidates]
D --> E[_json_echo payloads]
B -- No --> F[_load_projects]
F --> G[_select_project]
G -- None/exit --> Z[return]
G -- project selected --> H[_load_incidents_with_status]
H --> I{any candidates?}
I -- No --> Z
I -- Yes --> J[_select_incident]
J -- None/exit --> Z
J -- _refresh --> H
J -- candidate --> K[_incident_actions]
K --> L{action}
L -- view --> M[_load_cached_report / _render_report]
L -- run --> N[_execute_rca]
N --> O[run_investigation_cli_streaming]
O --> P[_save_report]
L -- back --> Z
L -- exit --> Z
M --> L
P --> L
Prompt To Fix All With AI
This is a comment left during a code review.
Path: app/integrations/vercel_incidents.py
Line: 348-349
Comment:
**Unreachable `return` after `_die()`**
`_die()` unconditionally raises `SystemExit`, so the `return` on the next line (and the two similar ones at lines 369–370 and 388–389) can never be reached. Consider annotating `_die` with `-> Never` (from `typing`) so type-checkers confirm this, and drop the dead `return` statements.
```suggestion
_die(f"{exc} {_repair_hint()}")
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: app/integrations/vercel_incidents.py
Line: 226-228
Comment:
**Implicit fall-through after `run` action**
After `_execute_rca(candidate)` the loop continues implicitly because there is no `continue`. This works correctly today, but an explicit `continue` would make the intent unambiguous and prevent a future `else`/`return` from being accidentally inserted between the two clauses.
```suggestion
if action == "run":
_execute_rca(candidate)
continue
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: tests/integrations/test_vercel_incidents.py
Line: 59-62
Comment:
**Unnecessary `resolve_vercel_config` patch in JSON test**
When `is_json_output()` returns `True`, `cmd_vercel_incidents` calls `_load_incidents → collect_vercel_candidates` directly and never reaches `_load_projects`, which is the only call site for `resolve_vercel_config`. The patch here is dead weight and may mislead future readers into thinking the JSON path depends on that config resolver.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "Merge branch 'main' into split/1-cli-pro..." | Re-trigger Greptile
| _die(f"{exc} {_repair_hint()}") | ||
| return |
There was a problem hiding this comment.
Unreachable
return after _die()
_die() unconditionally raises SystemExit, so the return on the next line (and the two similar ones at lines 369–370 and 388–389) can never be reached. Consider annotating _die with -> Never (from typing) so type-checkers confirm this, and drop the dead return statements.
| _die(f"{exc} {_repair_hint()}") | |
| return | |
| _die(f"{exc} {_repair_hint()}") |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/vercel_incidents.py
Line: 348-349
Comment:
**Unreachable `return` after `_die()`**
`_die()` unconditionally raises `SystemExit`, so the `return` on the next line (and the two similar ones at lines 369–370 and 388–389) can never be reached. Consider annotating `_die` with `-> Never` (from `typing`) so type-checkers confirm this, and drop the dead `return` statements.
```suggestion
_die(f"{exc} {_repair_hint()}")
```
How can I resolve this? If you propose a fix, please make it concise.| if action == "run": | ||
| _execute_rca(candidate) | ||
|
|
There was a problem hiding this comment.
Implicit fall-through after
run action
After _execute_rca(candidate) the loop continues implicitly because there is no continue. This works correctly today, but an explicit continue would make the intent unambiguous and prevent a future else/return from being accidentally inserted between the two clauses.
| if action == "run": | |
| _execute_rca(candidate) | |
| if action == "run": | |
| _execute_rca(candidate) | |
| continue |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/vercel_incidents.py
Line: 226-228
Comment:
**Implicit fall-through after `run` action**
After `_execute_rca(candidate)` the loop continues implicitly because there is no `continue`. This works correctly today, but an explicit `continue` would make the intent unambiguous and prevent a future `else`/`return` from being accidentally inserted between the two clauses.
```suggestion
if action == "run":
_execute_rca(candidate)
continue
```
How can I resolve this? If you propose a fix, please make it concise.| monkeypatch.setattr( | ||
| "app.integrations.vercel_incidents.resolve_vercel_config", | ||
| lambda: VercelConfig(api_token="tok_test", team_id=""), | ||
| ) |
There was a problem hiding this comment.
Unnecessary
resolve_vercel_config patch in JSON test
When is_json_output() returns True, cmd_vercel_incidents calls _load_incidents → collect_vercel_candidates directly and never reaches _load_projects, which is the only call site for resolve_vercel_config. The patch here is dead weight and may mislead future readers into thinking the JSON path depends on that config resolver.
Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/integrations/test_vercel_incidents.py
Line: 59-62
Comment:
**Unnecessary `resolve_vercel_config` patch in JSON test**
When `is_json_output()` returns `True`, `cmd_vercel_incidents` calls `_load_incidents → collect_vercel_candidates` directly and never reaches `_load_projects`, which is the only call site for `resolve_vercel_config`. The patch here is dead weight and may mislead future readers into thinking the JSON path depends on that config resolver.
How can I resolve this? If you propose a fix, please make it concise.
VaibhavUpreti
left a comment
There was a problem hiding this comment.
Merging this for now; the rest of the changes can be added in a new PR to maintain velocity
… drop redundant header, fix CodeQL - slack_delivery `_post_direct` exception log key reverted to ``type=%s`` (matching the exact pre-refactor format ``type=%s channel=%s thread_ts=%s detail=%s``) so existing log parsers that key off ``type=`` keep working. Per @muddlebee's nit on PR Tracer-Cloud#952. - DeliveryResponse field renamed ``error_type`` → ``exc_type``. Pythonic abbreviation for "exception type"; can't be ``type`` because that shadows the builtin. Field/log-key are intentionally distinct: the field is the Python attribute, the log key matches the legacy format. - Drop ``Content-Type: application/json; charset=utf-8`` from ``_slack_bearer_headers`` and ``_discord_auth_headers``. ``httpx.post`` already sets ``Content-Type: application/json`` automatically when the request uses the ``json=`` kwarg, so the explicit header was redundant. No behavioural change for Slack/Discord (UTF-8 is httpx's default encoding and neither provider parses the charset suffix). - Fix CodeQL py/import-and-import-from alerts on tests Tracer-Cloud#503/Tracer-Cloud#504. The ``test_module_does_not_import_httpx`` regression test in each delivery test file was importing the module under test via both ``import X as mod`` and ``from X import Y`` styles. Switched to a single ``from app.utils import <module>`` style so the same module is no longer dual-imported. Test count unchanged (3208 pass / 2 skipped / 1 xfail). Lint, format, and ``mypy app/utils/`` clean.
…#952) * refactor(utils): extract shared HTTP-post helper for delivery modules Closes #864. ``app/utils/slack_delivery.py``, ``app/utils/discord_delivery.py``, and ``app/utils/telegram_delivery.py`` each issued ``httpx.post`` directly, applied a per-provider timeout, parsed the response body, and converted exceptions to ``(False, error, ...)`` tuples. The transport pieces were identical; only the success criteria, auth scheme, and error-message extraction differed per provider. Add ``app/utils/delivery_transport.py`` with ``post_json`` plus a ``DeliveryResponse`` dataclass that captures the shared transport behavior: HTTP POST, timeout, optional ``follow_redirects``, exception suppression, and JSON decoding with graceful fallback. The helper deliberately does not decide provider-level success — callers inspect ``status_code`` / ``data`` per their own semantics. Refactored callers: - Slack: ``_call_reactions_api``, ``_post_direct``, ``_post_via_webapp``, ``_post_via_incoming_webhook`` — all four code paths now go through ``post_json``. ``send_slack_report`` orchestration unchanged. - Discord: ``post_discord_message``, ``create_discord_thread`` — same Bearer/Bot header pattern factored into ``_discord_auth_headers``. - Telegram: ``post_telegram_message`` — bot-token redaction in error messages preserved by re-running ``_redact_token`` over ``response.error``. Provider-specific payload building, success criteria (``data["ok"]`` for Slack, status codes for Discord/Telegram), and error extraction all stay in the calling modules. Public function signatures are unchanged. Tests: - ``tests/utils/test_delivery_transport.py`` (new) — 15 tests covering happy path, every transport-failure shape (httpx.ConnectError, ReadTimeout, RequestError, OSError, RuntimeError), JSON-decode fallbacks (non-JSON body, JSON array, empty body), header / timeout / follow_redirects pass-through, and DeliveryResponse frozen-dataclass invariants. - ``tests/utils/test_slack_delivery.py`` (new) — 24 tests covering all four Slack code paths, ``send_slack_report`` orchestration, and fallback chain ``direct → webapp``. - ``tests/utils/test_discord_delivery.py`` (extended) — 3 new tests pinning the helper-delegation contract: module no longer imports ``httpx``, ``post_discord_message`` and ``create_discord_thread`` both go through ``post_json``. - ``tests/utils/test_telegram_delivery.py`` (extended) — 3 new tests pinning the same contract plus a regression test that the bot-token is redacted out of error strings even when the failure originates from the shared transport. - All pre-existing tests in ``test_discord_delivery.py`` and ``test_telegram_delivery.py`` updated to patch ``app.utils.delivery_transport.httpx.post`` (the new transport boundary) instead of the per-module ``httpx.post`` import that no longer exists. Verification: - ``pytest tests/``: 3191 pass, 2 skipped, 1 xfailed, 0 failures. - ``pytest tests/utils/``: 105 pass, 1 skipped (was 32 + 26 = 58 across delivery modules; now 105 with helper + Slack additions). - ``ruff check app/ tests/`` and ``ruff format --check``: clean. - ``mypy app/utils/``: clean on touched modules; the 5 reported errors are pre-existing missing-stub warnings in ``app/integrations/{mariadb,mysql,hf_remote}`` unrelated to this PR. * ci: retrigger after anyio/mcp circular-import flake The previous CI run hit a known transient ImportError in anyio.lowlevel/mcp when opensre integrations list ran on a pytest-xdist worker. Reproduces zero times locally on origin/main and on this branch; pushing an empty commit to re-run with a fresh interpreter pool. * fix(utils): address greptile review on delivery transport refactor - Wrap `DeliveryResponse.data` in `MappingProxyType` so the frozen dataclass is fully immutable end-to-end. Mutating the parsed body now raises `TypeError` instead of silently succeeding, and caller- passed dicts can no longer leak mutations into the response. - Add `error_type` field on `DeliveryResponse` populated with `type(exc).__name__` on transport failures. `slack_delivery._post_direct` threads it back into the exception log so on-call can distinguish `TimeoutError` from `ConnectionError` at a glance — restores the pre-refactor log shape that #864 had dropped. - Add `TestDelegatesToSharedTransport` to `tests/utils/test_slack_delivery.py`, mirroring the regression class on the discord/telegram test files. Pins that `slack_delivery` does not import `httpx` and that all four code paths (`_call_reactions_api`, `_post_direct`, `_post_via_webapp`, `_post_via_incoming_webhook`) route through `delivery_transport.post_json`. - Add focused tests for the immutable-data, error_type, and slack exc_type-log behaviours (+17 tests; 3208 pass / 2 skipped / 1 xfail). Tighten `_discord_error_from_data` signature to `Mapping[str, Any]` so mypy stays clean against the new read-only `data` type. * refactor(utils): address review nits — restore log key, rename field, drop redundant header, fix CodeQL - slack_delivery `_post_direct` exception log key reverted to ``type=%s`` (matching the exact pre-refactor format ``type=%s channel=%s thread_ts=%s detail=%s``) so existing log parsers that key off ``type=`` keep working. Per @muddlebee's nit on PR #952. - DeliveryResponse field renamed ``error_type`` → ``exc_type``. Pythonic abbreviation for "exception type"; can't be ``type`` because that shadows the builtin. Field/log-key are intentionally distinct: the field is the Python attribute, the log key matches the legacy format. - Drop ``Content-Type: application/json; charset=utf-8`` from ``_slack_bearer_headers`` and ``_discord_auth_headers``. ``httpx.post`` already sets ``Content-Type: application/json`` automatically when the request uses the ``json=`` kwarg, so the explicit header was redundant. No behavioural change for Slack/Discord (UTF-8 is httpx's default encoding and neither provider parses the charset suffix). - Fix CodeQL py/import-and-import-from alerts on tests #503/#504. The ``test_module_does_not_import_httpx`` regression test in each delivery test file was importing the module under test via both ``import X as mod`` and ``from X import Y`` styles. Switched to a single ``from app.utils import <module>`` style so the same module is no longer dual-imported. Test count unchanged (3208 pass / 2 skipped / 1 xfail). Lint, format, and ``mypy app/utils/`` clean. * fix(slack): restore charset=utf-8 — Slack emits missing_charset warning without it Live e2e probe against real ``slack.com/api/chat.postMessage`` revealed that dropping the explicit ``Content-Type: application/json; charset=utf-8`` header (per the previous nit-fix commit) caused Slack to add a ``missing_charset`` entry to ``response_metadata.warnings`` on every request. httpx alone sets only the bare ``application/json`` for ``json=`` kwargs, but Slack's docs explicitly recommend the charset suffix (https://api.slack.com/web#posting_json) and emit the warning otherwise. Restored the ``charset=utf-8`` header on ``_slack_bearer_headers`` with an inline comment explaining the reason. ``_discord_auth_headers`` stays auth-only (Discord does not emit this warning, and its docs do not require the charset suffix). Pinned via direct header assertions on the two existing slack tests that already captured headers (``test_sends_correct_url_and_headers`` for the reactions API, ``test_sends_thread_reply_payload`` for chat.postMessage), so a future regression that re-drops the charset will fail loudly. Verified live: - direct ``chat.postMessage`` probe now returns ``warnings=[]`` (was ``['missing_charset']`` before this commit). - 38/38 live checks against real Slack / Discord / Telegram pass. - 3208 unit tests pass; lint / format / mypy clean.
Fixes #
Describe the changes you have made in this PR -
Screenshots of the UI changes (If any) -
Code Understanding and AI Usage
Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?
If you used AI assistance:
Explain your implementation approach:
Checklist before requesting a review
Note: Please check Allow edits from maintainers if you would like us to assist in the PR.