Skip to content

feat: add symbolication support for 7 platforms#11

Merged
alltheseas merged 13 commits intomainfrom
feat/symbolication
Jan 16, 2026
Merged

feat: add symbolication support for 7 platforms#11
alltheseas merged 13 commits intomainfrom
feat/symbolication

Conversation

@alltheseas
Copy link
Owner

@alltheseas alltheseas commented Jan 16, 2026

Summary

  • Add symbolication library module with support for 7 platforms:
    • Android (ProGuard/R8 mapping.txt)
    • JavaScript/Electron (source maps)
    • Flutter/Dart (flutter symbolize)
    • Rust (backtrace parsing)
    • Go (goroutine stack parsing)
    • Python (traceback parsing)
    • React Native (Hermes + JS source maps)
  • Add bugstr symbolicate CLI command
  • Add POST /api/symbolicate web API endpoint
  • Add --mappings flag to bugstr serve

Closes #10

Test plan

  • All 25 unit tests pass
  • CLI command tested with Python and Go stack traces
  • Code compiles without errors
  • Manual test: bugstr symbolicate -P python < traceback.txt
  • Manual test: bugstr serve --mappings ./mappings then POST to /api/symbolicate
  • Manual test: 503 returned when --mappings not configured

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Symbolication support added for Android, JavaScript/Electron, Flutter, Rust, Go, Python, and React Native
    • New symbolicate CLI command with Pretty/Json output and a --mappings option
    • New POST /api/symbolicate web endpoint
    • Mapping store and on-disk mappings management (scan, upload, fallback lookup)
  • Bug Fixes

    • SDK: clearPendingReports() is now safe to call before initialization (no-op)
  • Documentation

    • Added project CHANGELOG with Unreleased and 0.1.0 notes

✏️ Tip: You can customize this high-level summary in your review settings.

alltheseas and others added 4 commits January 16, 2026 10:54
Add stack trace symbolication support for 7 platforms:
- Android: ProGuard/R8 mapping.txt parsing
- JavaScript/Electron: source map support
- Flutter/Dart: flutter symbolize integration
- Rust: backtrace parsing
- Go: goroutine stack parsing
- Python: traceback parsing
- React Native: Hermes bytecode + JS source maps

Includes MappingStore for organizing mapping files by
platform/app_id/version directory structure.

Closes #10

Signed-off-by: alltheseas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `bugstr symbolicate` command for symbolicating stack traces:
- Reads from file or stdin
- Supports all 7 platforms (android, electron, flutter, rust, go, python, react-native)
- Pretty and JSON output formats
- Uses mapping files from configurable directory

Usage:
  bugstr symbolicate -P python -i stack.txt
  echo "traceback..." | bugstr symbolicate -P go --format json

Signed-off-by: alltheseas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add POST /api/symbolicate endpoint for dashboard integration:
- Accepts stack trace with platform, app_id, version, build_id
- Returns symbolicated frames with function, file, line info
- Returns 503 if symbolication not configured

Add --mappings option to `bugstr serve`:
- Configures mapping files directory for symbolication
- Creates Symbolicator and passes to AppState
- Displays mappings path in startup banner

Signed-off-by: alltheseas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document symbolication feature and initial release notes.

Signed-off-by: alltheseas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

Adds a multi-platform symbolication subsystem: platform-specific symbolicators, an on-disk MappingStore with fallback logic, CLI symbolicate and optional --mappings for serve, and a POST /api/symbolicate endpoint. New crate dependencies added: regex, sourcemap, tempfile, and semver.

Changes

Cohort / File(s) Summary
Changelog & Manifest
rust/CHANGELOG.md, rust/Cargo.toml
New CHANGELOG; added dependencies regex, sourcemap, tempfile, semver.
Crate exports
rust/src/lib.rs
Added pub mod symbolication and re-exported symbolication types (MappingStore, Symbolicator, Symbolicated* etc.).
Core dispatcher & types
rust/src/symbolication/mod.rs
New Platform enum, SymbolicationContext, Symbolicator dispatcher, SymbolicatedFrame/Stack, and SymbolicationError.
Mapping store
rust/src/symbolication/store.rs
New on-disk MappingStore with scan, get, get_with_fallback (semver-aware), add/list/save mapping, path validation, and caching.
Platform symbolicators
rust/src/symbolication/android.rs, .../javascript.rs, .../flutter.rs, .../rust_sym.rs, .../go.rs, .../python.rs, .../react_native.rs
New platform-specific symbolicators (ProGuard parsing, source-map lookup, flutter symbolize invocation, Rust/Go/Python trace parsers, React Native handling). Unit tests included per module.
CLI integration
rust/src/bin/main.rs
New Symbolicate CLI variant, SymbolicateFormat enum, symbolicate_stack function, and serve accepts optional mappings wired into AppState.
Web API integration
rust/src/web.rs
Added POST /api/symbolicate endpoint, request/response types, and AppState.symbolicator: Option<Arc<Symbolicator>>.
Electron SDK fix
electron/src/sdk.ts
clearPendingReports() made a no-op if not initialized (runtime guard).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as "bugstr CLI"
    participant Store as "MappingStore"
    participant Sym as "Symbolicator"
    participant Formatter as "Output Formatter"

    User->>CLI: bugstr symbolicate --platform ... --mappings ...
    CLI->>Store: scan(mappings_dir)
    Store-->>CLI: mappings_loaded
    CLI->>Sym: Symbolicator::new(Store)
    CLI->>Sym: symbolicate(stack, context)
    Sym->>Store: get(platform, app_id, version)
    Store-->>Sym: MappingInfo?
    Sym->>Sym: dispatch to platform-specific symbolicator
    Sym-->>CLI: SymbolicatedStack
    CLI->>Formatter: format(result, Pretty|Json)
    Formatter-->>User: output
Loading
sequenceDiagram
    participant Client
    participant Web as "Web Server"
    participant AppState
    participant Sym as "Symbolicator"
    participant Store as "MappingStore"

    Client->>Web: POST /api/symbolicate {platform, stack, app_id, version}
    Web->>AppState: check symbolicator
    alt symbolicator configured
        AppState-->>Web: Some(Symbolicator)
        Web->>Sym: symbolicate(stack, context)
        Sym->>Store: get_with_fallback(platform, app_id, version)
        Store-->>Sym: MappingInfo?
        Sym->>Sym: platform dispatch & parse/deobfuscate
        Sym-->>Web: SymbolicatedStack
        Web-->>Client: 200 {frames, counts}
    else not configured
        AppState-->>Web: None
        Web-->>Client: 503 Service Unavailable
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs

Poem

🐰 I nibble through maps in moonlit code,

Lines once scrambled now find their road.
Seven tongues of traces, clever and bright,
MappingStore hums and brings back the light.
Hop, hop—symbolicated! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add symbolication support for 7 platforms' directly and clearly summarizes the main change—adding symbolication support across seven platforms.
Linked Issues check ✅ Passed The linked issue #10 provides minimal context (only 'symbolication' as title). However, the PR objectives clearly document that symbolication support for 7 platforms, CLI command, web API endpoint, and --mappings flag are implemented as intended.
Out of Scope Changes check ✅ Passed The PR includes symbolication for 7 platforms (Android, JavaScript, Flutter, Rust, Go, Python, React Native), CLI command, web API, MappingStore, and an Electron clearPendingReports fix. All changes are directly aligned with the stated symbolication objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
rust/src/symbolication/android.rs (1)

334-337: Consider Kotlin source file extension.

The source file extraction assumes .java extension. Android apps may use Kotlin (.kt). This is a minor inaccuracy since ProGuard mappings don't typically preserve the source file extension.

rust/src/symbolication/mod.rs (1)

94-107: Consider implementing std::str::FromStr trait for idiomatic parsing.

The from_str method name shadows the standard library's FromStr trait convention. Implementing FromStr would allow using .parse() and integrate better with Rust's ecosystem.

♻️ Proposed refactor
+use std::str::FromStr;
+
+impl FromStr for Platform {
+    type Err = std::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(match s.to_lowercase().as_str() {
+            "android" => Platform::Android,
+            "electron" | "javascript" | "js" => Platform::Electron,
+            "flutter" | "dart" => Platform::Flutter,
+            "rust" => Platform::Rust,
+            "go" | "golang" => Platform::Go,
+            "python" => Platform::Python,
+            "react-native" | "reactnative" | "rn" => Platform::ReactNative,
+            other => Platform::Unknown(other.to_string()),
+        })
+    }
+}

This enables:

let platform: Platform = "android".parse().unwrap();

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e29325 and 94c5027.

📒 Files selected for processing (7)
  • electron/CHANGELOG.md
  • electron/src/sdk.ts
  • rust/CHANGELOG.md
  • rust/src/bin/main.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
✅ Files skipped from review due to trivial changes (1)
  • rust/CHANGELOG.md
🧰 Additional context used
📓 Path-based instructions (4)
**/CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Files:

  • electron/CHANGELOG.md
**/*.{kt,dart,ts,tsx,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,dart,ts,tsx,rs,go,py}: All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
All code must be reviewable by human developers with clear, descriptive variable and function names, appropriate comments for non-obvious logic, and consistent formatting per language conventions

Files:

  • electron/src/sdk.ts
  • rust/src/bin/main.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
**/*.{kt,ts,tsx,dart,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,ts,tsx,dart,rs,go,py}: Rumor events must include sig: "" (empty string, not omitted) for NIP-17/59 implementation
Rumor events must include computed id field with SHA256 of serialized event in lowercase hex format (64 characters) for NIP-17/59 implementation
Event serialization order must be: [0, pubkey, created_at, kind, tags, content] for NIP-17/59 compliance
Seal events must be signed by the sender's key for NIP-17/59 implementation
Gift wrap events must be signed by an ephemeral key for NIP-17/59 implementation
All new code should have corresponding unit tests and test edge cases and error conditions

Files:

  • electron/src/sdk.ts
  • rust/src/bin/main.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
rust/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use rustdoc format (/// ... or //!) for docstrings in Rust code

Files:

  • rust/src/bin/main.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
🧠 Learnings (3)
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/CHANGELOG.md : All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Applied to files:

  • electron/CHANGELOG.md
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to rust/**/*.rs : Use rustdoc format (`/// ...` or `//!`) for docstrings in Rust code

Applied to files:

  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/*.{kt,dart,ts,tsx,rs,go,py} : All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs

Applied to files:

  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
🧬 Code graph analysis (3)
rust/src/bin/main.rs (5)
rust/src/storage.rs (3)
  • parse_crash_content (231-279)
  • count (184-187)
  • serde_json (233-233)
rust/src/web.rs (2)
  • create_router (32-50)
  • symbolicate_stack (93-147)
rust/src/symbolication/mod.rs (8)
  • new (471-473)
  • from_str (96-107)
  • display (278-293)
  • display (365-371)
  • percentage (395-401)
  • raw (248-257)
  • frames (366-369)
  • symbolicated (260-275)
rust/src/symbolication/store.rs (1)
  • new (167-172)
rust/src/lib.rs (1)
  • new (96-100)
rust/src/symbolication/android.rs (6)
rust/src/symbolication/mod.rs (5)
  • new (471-473)
  • symbolicate (522-558)
  • frames (366-369)
  • symbolicated (260-275)
  • raw (248-257)
rust/src/symbolication/store.rs (1)
  • new (167-172)
rust/src/symbolication/go.rs (2)
  • new (19-21)
  • symbolicate (27-40)
rust/src/symbolication/javascript.rs (2)
  • new (22-24)
  • symbolicate (27-123)
rust/src/lib.rs (1)
  • new (96-100)
rust/src/storage.rs (1)
  • open (44-49)
rust/src/symbolication/store.rs (1)
rust/src/symbolication/mod.rs (1)
  • from_str (96-107)
🔇 Additional comments (23)
electron/src/sdk.ts (1)

138-142: LGTM! Defensive guard prevents runtime error.

The early return when !initialized correctly prevents accessing the undefined store before init() is called. This aligns with the pattern used in other SDK functions (processPendingReports, handleMainProcessError, captureException).

electron/CHANGELOG.md (1)

13-15: LGTM! Changelog entry accurately documents the fix.

The entry correctly reflects the behavioral change in electron/src/sdk.ts and follows the Keep a Changelog format. Based on learnings, all user-facing changes require a CHANGELOG entry.

rust/src/symbolication/android.rs (4)

1-19: Excellent module documentation.

The rustdoc clearly explains the ProGuard/R8 mapping format variants, including the original line range suffixes for inlined methods. This follows the coding guidelines for documentation. As per coding guidelines.


131-159: Line mapping logic correctly implemented.

The parsing now properly separates obfuscated line ranges (obf_start, obf_end) from original source line ranges (orig_start, orig_end). The defaults at lines 138-144 correctly handle partial format variants (:origStart only, or no original line info).


226-268: Deobfuscation logic handles line ranges correctly.

The implementation properly:

  1. Matches incoming obfuscated line numbers against obf_start/obf_end ranges
  2. Calculates original line as orig_start + offset
  3. Preserves the input line number when method mapping exists but line range doesn't match (lines 265-267)

This correctly handles inlined/overloaded methods with distinct line ranges.


364-514: Comprehensive test coverage for ProGuard parsing.

The tests cover all major format variants (with/without line ranges, single vs. range original lines) and important edge cases (overloaded methods, unmapped methods, out-of-range lines). The assertions validate the offset calculations are correct.

rust/src/bin/main.rs (4)

194-306: Excellent rustdoc documentation.

The function documentation is comprehensive: covers all parameters with supported values, return types with error variants, output format examples, side effects, and usage examples. This addresses the previous review comment requesting fuller documentation. As per coding guidelines.


335-345: Mapping store correctly initialized with scan.

The MappingStore::new() followed by store.scan() ensures mappings are discovered before symbolication. The warning when no mappings are found provides good user feedback.


427-451: Symbolicator initialization correctly handles scan errors.

The implementation:

  1. Calls store.scan() (addressing previous critical review)
  2. Gracefully degrades on scan failure (server still runs, symbolication returns 503)
  3. Wraps in Arc for thread-safe sharing with async handlers

This is a good resilience pattern.


81-107: CLI command structure is well-designed.

The Symbolicate subcommand has sensible defaults (- for stdin, mappings directory), required platform flag with short -P, and optional app_id/version for mapping lookup. Follows the existing CLI patterns in this file.

rust/src/symbolication/store.rs (6)

68-145: Comprehensive struct documentation addresses past review.

The MappingStore documentation now covers:

  • Directory structure
  • Thread safety caveats
  • Security considerations for path validation
  • Usage examples

This addresses the previous comment requesting fuller rustdoc. As per learnings.


400-413: Semver comparison correctly implemented.

The version fallback now uses proper semantic versioning via the semver crate, with lexicographic fallback for non-semver strings. Valid semver versions sort higher than invalid ones, ensuring proper version selection. This addresses the previous review comment.


524-554: Path validation prevents directory traversal.

The validation covers key attack vectors:

  • Empty components
  • Exact . and ..
  • Substring .. (e.g., foo/../bar)
  • Both Unix (/) and Windows (\) path separators

This addresses the previous security review comment.


608-640: save_mapping validates all inputs before filesystem operations.

The implementation correctly:

  1. Validates all path components before constructing the path (lines 617-620)
  2. Creates directories and writes file only after validation
  3. Updates internal cache to maintain consistency

This addresses the previous security concern about untrusted path components.


665-741: Good test coverage for path validation security.

The tests comprehensively cover:

  • Parent traversal attempts (.., ../etc, foo/../bar)
  • Path separators (/, \, absolute paths)
  • Edge cases (empty, .)
  • Valid inputs (package names, versions, filenames)
  • Integration test for save_mapping with malicious inputs

222-284: Scan implementation is thorough.

The scan correctly:

  1. Clears existing cache to avoid stale entries
  2. Creates root directory if missing
  3. Recursively discovers mappings in the expected hierarchy
  4. Uses platform-specific file detection via find_mapping_file

The thread safety caveat in the struct documentation appropriately warns about concurrent access.

rust/src/symbolication/mod.rs (7)

1-34: LGTM!

Module-level documentation is comprehensive, uses correct //! rustdoc format, lists all supported platforms clearly, and includes a practical usage example.


35-52: LGTM!

Module declarations and public re-exports are well-organized, providing a clean API surface.


55-79: LGTM!

Error enum uses thiserror idiomatically with clear error messages. The InvalidPath variant appropriately supports the path validation mentioned in the PR for preventing directory traversal attacks.


124-173: LGTM!

The documentation for SymbolicationContext is now comprehensive, with detailed field descriptions, platform-specific examples, default behavior notes, and a working code example. This addresses the previous review feedback.


175-294: LGTM!

SymbolicatedFrame is well-documented with field semantics, display format, and executable examples. The implementation correctly handles both symbolicated and raw frames.


296-402: LGTM!

SymbolicatedStack has thorough documentation including the important note about total_count vs frames.len() semantics. The percentage() method correctly handles division by zero, and the display() method is cleanly implemented.


404-559: LGTM!

The Symbolicator implementation is well-documented with comprehensive rustdoc covering thread safety considerations, all error cases, and platform-specific stack trace formats. The dispatch logic correctly handles all Platform variants and returns an appropriate error for unknown platforms.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

🤖 Fix all issues with AI agents
In `@rust/CHANGELOG.md`:
- Around line 8-34: Update the changelog sections under the headings "##
[Unreleased]" and "## [0.1.0] - 2025-01-15" to include "Changed" and "Fixed"
subsections in addition to the existing "Added" lists; for each section add "###
Changed" and "### Fixed" headings and list any relevant entries or the word
"None" if there are no changes/fixes to report so the file follows the required
Added/Changed/Fixed format.

In `@rust/src/bin/main.rs`:
- Around line 308-312: The MappingStore created in the serve path (mappings_dir
-> MappingStore::new) never calls scan(), so Symbolicator::new(store) is
constructed with no mappings; update the block that builds the symbolicator to
call store.scan() (and await/handle the Result if async) before passing the
store into Symbolicator::new, and propagate or log any error appropriately so
mappings are actually loaded for the web server.
- Around line 223-225: The MappingStore is instantiated with
MappingStore::new(mappings_dir) but scan() is never invoked, so mappings are not
loaded; after creating store (the MappingStore::new call) call store.scan() and
handle its Result (e.g., propagate the error with ? or log and exit) before
constructing Symbolicator::new(store) so the symbolicator receives a populated
store; ensure you call store.scan() in the same scope where store is created and
handle any errors appropriately.

In `@rust/src/symbolication/android.rs`:
- Around line 92-116: The current code in the method_re capture block
incorrectly stores (start_line, end_line, start_line, end_line) into
MethodMapping.line_mapping; replace that with a representation that marks
obfuscated line ranges as unknown and stores only the original source range
(e.g. push (0, 0, start_line, end_line) or otherwise change the tuple order to
(obf_start, obf_end, orig_start, orig_end)); then update the deobfuscate_frame
logic to recognize an obfuscated range of 0 as "unknown" and fall back to
matching the incoming line against the stored original range (or otherwise
handle lack of obfuscated ranges). Modify usages of MethodMapping.line_mapping,
method_re parsing block, and deobfuscate_frame to consistently treat the first
two tuple fields as obfuscated ranges (possibly 0 when unavailable) and the last
two as original ranges.

In `@rust/src/symbolication/flutter.rs`:
- Around line 15-34: Update the public rustdoc for the FlutterSymbolicator
struct and its public methods (FlutterSymbolicator, new, symbolicate) to include
explicit descriptions of parameters (e.g., store: &MappingStore, stack_trace:
&str, context: &SymbolicationContext), the return type
(Result<SymbolicatedStack, SymbolicationError>), and the possible error cases
(what triggers SymbolicationError and when fallbacks occur). Add brief examples
showing how to construct a FlutterSymbolicator via FlutterSymbolicator::new and
call symbolicate, and document the behavior (uses `flutter symbolize` if
available, otherwise falls back to mapping parsing) and any panics/side-effects.
Ensure each public item has a short one-line summary followed by sections for
Arguments, Returns, Errors, and an optional Example.
- Around line 59-73: The current symbolicate() implementation in
rust/src/symbolication/flutter.rs writes to a fixed temp filename and unwraps
path UTF-8, causing race/symlink risks and panics; replace the fixed temp file
with tempfile::NamedTempFile (move tempfile from dev-dependencies to
[dependencies]) to create a unique temp file and let it be cleaned up, write the
stack_trace into that file, and pass the file path to Command by using .arg(...)
with the OsStr/Path (avoid to_str().unwrap()) so invalid UTF-8 won’t panic; also
add documentation comments to the public symbolicate() signature describing
parameters, return value, and possible errors.

In `@rust/src/symbolication/go.rs`:
- Around line 12-31: The public GoSymbolicator API lacks comprehensive rustdoc;
update the doc comments for the struct GoSymbolicator<'a> and its associated
methods (new and symbolicate) to include parameter descriptions (e.g., store:
&MappingStore, stack_trace: &str, context: &SymbolicationContext), the return
type details (SymbolicatedStack) and all error cases returned as
SymbolicationError, plus usage examples demonstrating typical invocation and
expected output; ensure you document lifetime semantics for 'a, explain what
MappingStore provides, describe side effects/constraints, and include code
examples and links to related types like SymbolicationContext and
SymbolicatedStack per project doc guidelines.
- Around line 54-88: The func_re regex doesn't match Go pointer-receiver names
like main.(*Type).Method; update the func_re used in the parsing loop (the Regex
assigned to func_re and its captures usage) to allow any characters (including
parentheses, asterisks and dots) in the function name portion (e.g., use a
pattern that captures "any chars" for the name and then the argument list), trim
surrounding whitespace from the captured name and args before assigning to
current_function/current_args, and keep the existing logic that saves a previous
frame into frames (SymbolicatedFrame creation) when current_function is taken.

In `@rust/src/symbolication/javascript.rs`:
- Around line 15-31: Add comprehensive rustdoc for the public
JavaScriptSymbolicator API: document the struct JavaScriptSymbolicator and its
methods (especially fn new and fn symbolicate) including descriptions of
parameters (store: &MappingStore, stack_trace: &str, context:
&SymbolicationContext), the return type (Result<SymbolicatedStack,
SymbolicationError>), all possible error cases from SymbolicationError, and
provide a short usage example showing construction via
JavaScriptSymbolicator::new and calling symbolicate; ensure docs follow project
guidelines and appear above the JavaScriptSymbolicator type and the symbolicate
method.
- Around line 54-63: The JavaScript stack frame regexes chrome_re and firefox_re
are incorrectly using ([^:]+) which stops at the first colon and breaks URLs and
Windows paths; update the Regex::new patterns for chrome_re and firefox_re to
use a non-greedy file capture like (.+?) and anchor the pattern so it matches
the file path up to the final :line:col (e.g., ensure the pattern expects
:(\d+):(\d+)$), then unwrap as before; modify the two Regex::new(...) calls
accordingly so file paths with embedded colons are captured correctly.

In `@rust/src/symbolication/python.rs`:
- Around line 13-33: Add comprehensive rustdoc comments for the public API
around PythonSymbolicator, including the struct, its constructor new(), and the
symbolicate() method: describe the purpose and behavior of PythonSymbolicator,
document parameters (store: &MappingStore for new; stack_trace: &str and
context: &SymbolicationContext for symbolicate), the return type
(Result<SymbolicatedStack, SymbolicationError>), list possible error cases
(SymbolicationError variants) and any side-effects, and include a short usage
example showing creating a PythonSymbolicator via new() and calling
symbolicate(); ensure docs follow project style (purpose, behavior, params,
returns, errors, example) and are placed above the struct and each public
method.
- Around line 24-41: The code fetches mapping info into _mapping_info in
symbolicate but never applies it, so bundled-app paths aren't resolved; either
use the mapping or remove the doc claim. Fix by retrieving the mapping result
from store.get_with_fallback (store in a named variable like mapping_info), then
thread it into the Python traceback processing: update parse_python_traceback to
accept an Option<MappingType> (or a reference) and apply path transformations to
each frame file path, or if you don't want to implement mapping, update the
symbolicate docstring to remove the "attempts to resolve bundled app paths"
claim; key symbols: symbolicate, parse_python_traceback, get_with_fallback, and
mapping_info.
- Around line 57-60: The exception_re currently matches any capitalized word and
so incorrectly captures the "Traceback ..." header; update the Regex used for
exception_re to only match a valid Python exception identifier (starts with a
letter or underscore, followed by letters, digits, underscores or dots) and
require a literal colon separator before the message (i.e., exception name
followed by ':' then optional whitespace and the message) so that only real
exception lines are parsed into frames.

In `@rust/src/symbolication/react_native.rs`:
- Around line 15-36: Add comprehensive rustdoc to the public
ReactNativeSymbolicator API: document the struct and its methods
(ReactNativeSymbolicator::new and ReactNativeSymbolicator::symbolicate)
including parameter descriptions (store: &MappingStore, stack_trace: &str,
context: &SymbolicationContext), return type (Result<SymbolicatedStack,
SymbolicationError>), all possible error cases produced by symbolicate, and
expected behavior for different frame types (JS, native, Hermes). Include a
short usage example showing construction via ReactNativeSymbolicator::new and
calling symbolicate, and note thread-safety or lifetime considerations tied to
the 'a lifetime if relevant. Ensure docs follow rustdoc conventions (///) and
mention when callers should handle or propagate SymbolicationError.
- Around line 85-133: The JS/Hermes parsing branch currently discards the parsed
file path (stored as _file) when no source-map token is found; update the
unsymbolicated fallback in the js_frame_re handling to preserve that parsed path
by mapping the parsed file (the variable _file produced alongside function,
line_num and col_num) into the SymbolicatedFrame's file field (e.g., file:
_file.map(|s| s.to_string())) instead of None, leaving the rest of the fields
and behavior (function, line, column, symbolicated: false) unchanged so it
matches how native Android frames retain file info.
- Around line 66-68: The regex in react_native.rs (js_frame_re) incorrectly uses
([^:]+) which stops at the first colon and breaks on URLs and Windows paths;
update the pattern to use (.+?) for the source capture and add an end-of-line
anchor ($) so it non-greedily captures up to the final :line:column sequence
(i.e., change the group for the file to (.+?) and append $ to the regex), then
update/add tests that exercise React Native frames with URLs (e.g.,
http://example.com:1:2345) and Windows/file:///C:/... paths to verify correct
parsing.

In `@rust/src/symbolication/rust_sym.rs`:
- Around line 12-32: Update the rustdoc for the public RustSymbolicator API:
expand the doc comment on the RustSymbolicator struct and its public methods
new() and symbolicate() to include parameter descriptions (e.g., explain the
store field and the parameters stack_trace: &str and context:
&SymbolicationContext), the return value (Result<SymbolicatedStack,
SymbolicationError>), the error conditions that may produce SymbolicationError,
and at least one short usage example showing constructing
RustSymbolicator::new(&store) and calling symbolicate(stack_trace, &context);
keep docs concise, follow project style (sections: Arguments, Returns, Errors,
Examples), and mention any relevant lifetime or thread-safety considerations for
the store reference.
- Around line 23-50: The docstring for symbolicate claims addr2line lookup for
stripped binaries but parse_rust_backtrace currently ignores the _symbols_path
and never uses mapping_info; either implement addr2line-based resolution or
change the docs. To fix: either (A) implement symbol resolution in
parse_rust_backtrace using the provided _symbols_path/mapping_info (call
addr2line or use gimli/addr2line crates to open the debug file and resolve
addresses found in stack_trace) and wire mapping_info.path from symbolicate into
parse_rust_backtrace, or (B) update the symbolicate docstring to remove the
claim about addr2line and state that only backtraces containing source info are
parsed; reference functions/vars: symbolicate, parse_rust_backtrace,
mapping_info, _symbols_path, store.get_with_fallback, and SymbolicationContext
to locate the code to change.

In `@rust/src/symbolication/store.rs`:
- Around line 205-209: The version fallback currently uses lexicographic
comparison via max_by with a.version.cmp(&b.version), which misorders semantic
versions; update the comparison to use semantic versioning (add semver = "1" to
Cargo.toml), parse versions with semver::Version::parse inside the max_by
comparator (treat parse failures as lesser than valid semver or fall back to
lexicographic), and replace the a.version.cmp(&b.version) comparator with the
semver-aware ordering so self.mappings selection returns the correct latest
semantic version.

In `@rust/src/web.rs`:
- Around line 26-29: AppState currently holds symbolicator directly
(Option<Symbolicator>) which can cause blocking in async handlers; change it to
Option<Arc<Symbolicator>> (or wrap the existing Symbolicator in Arc when
constructing AppState), then in the async handler call the blocking
symbolication via tokio::task::spawn_blocking by cloning the Arc and moving it
into spawn_blocking to call symbolicator.symbolicate(...) so all filesystem IO
and external process invocations happen off the Tokio worker threads; ensure you
clone any args needed (e.g., request data) into the closure and await the
spawn_blocking JoinHandle, converting its Result into the handler's response;
finally add unit tests for the handler (using #[tokio::test]) that exercise
success and error paths by injecting a test/mocked Symbolicator (Arc-wrapped) to
verify proper spawn_blocking behavior and error propagation.
🧹 Nitpick comments (9)
rust/src/symbolication/python.rs (1)

174-188: Add edge-case tests for headers and exception-only lines.
The test only checks a happy path. Please add cases to ensure the header line isn’t treated as an exception frame and that exceptions without messages (e.g., KeyboardInterrupt) are parsed correctly. As per coding guidelines, edge/error cases should be covered.

rust/src/symbolication/react_native.rs (1)

44-49: Surface sourcemap parse errors instead of silently ignoring.
.ok() hides invalid mappings and makes failures indistinguishable from “no map”. Consider returning ParseError (consistent with JavaScriptSymbolicator) so clients can troubleshoot.

♻️ Proposed refactor
-        let sourcemap = if let Some(info) = mapping_info {
-            let content = fs::read_to_string(&info.path)?;
-            SourceMap::from_reader(content.as_bytes()).ok()
-        } else {
-            None
-        };
+        let sourcemap = if let Some(info) = mapping_info {
+            let content = fs::read_to_string(&info.path)?;
+            Some(
+                SourceMap::from_reader(content.as_bytes())
+                    .map_err(|e| SymbolicationError::ParseError(e.to_string()))?,
+            )
+        } else {
+            None
+        };
rust/src/symbolication/android.rs (4)

55-63: Consider caching compiled regex patterns.

These regex patterns are compiled on every call to parse(). For better performance, consider using lazy_static! or std::sync::LazyLock (stable in Rust 1.80+) to compile these patterns once.

♻️ Suggested optimization using LazyLock
use std::sync::LazyLock;

static CLASS_RE: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^(\S+)\s+->\s+(\S+):$").unwrap()
});
static METHOD_RE: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^\s+(\d+):(\d+):(\S+)\s+(\S+)\((.*)\)\s+->\s+(\S+)$").unwrap()
});
// ... etc for other patterns

201-210: Public struct and method lack detailed documentation.

Per coding guidelines, public structs and methods should have documentation explaining purpose, parameters, and behavior. Consider adding parameter documentation for new().

📝 Suggested documentation improvement
 /// Android stack trace symbolicator.
+///
+/// Uses ProGuard/R8 mapping files to deobfuscate Android stack traces
+/// by translating obfuscated class and method names back to their originals.
 pub struct AndroidSymbolicator<'a> {
     store: &'a MappingStore,
 }

 impl<'a> AndroidSymbolicator<'a> {
     /// Create a new Android symbolicator.
+    ///
+    /// # Arguments
+    ///
+    /// * `store` - Reference to the mapping store containing ProGuard mapping files
     pub fn new(store: &'a MappingStore) -> Self {
         Self { store }
     }

244-246: Regex compiled inside symbolicate() on each call.

The frame_re pattern is compiled every time symbolicate() is invoked. This should be moved to a static lazy initialization for better performance, especially when symbolicating multiple stack traces.


299-325: Test coverage is minimal.

The test validates basic parsing but doesn't test:

  • The symbolicate() method end-to-end
  • Line number deobfuscation
  • Edge cases (malformed input, missing mappings)

Consider adding more comprehensive tests.

rust/src/bin/main.rs (1)

213-221: Consider making unknown platform a hard error for CLI.

Currently, an unknown platform prints a warning but continues. Since symbolication will likely fail or produce incorrect results for unknown platforms, consider returning an error instead to provide clearer feedback.

rust/src/symbolication/store.rs (1)

158-169: Fallback file search may return unrelated files.

The fallback logic that searches for any .map, .txt, or .symbols file could return an incorrect file if multiple files with these extensions exist in the directory. Consider logging a warning when using this fallback path to aid debugging.

rust/src/symbolication/mod.rs (1)

91-104: Consider implementing std::str::FromStr trait instead of inherent method.

The from_str method name shadows the standard FromStr trait convention. Implementing the trait would enable more idiomatic usage like "android".parse::<Platform>() and integration with other parsing utilities.

♻️ Suggested trait implementation
+use std::str::FromStr;
+
+impl FromStr for Platform {
+    type Err = std::convert::Infallible; // Never fails, returns Unknown for unrecognized
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(match s.to_lowercase().as_str() {
+            "android" => Platform::Android,
+            "electron" | "javascript" | "js" => Platform::Electron,
+            "flutter" | "dart" => Platform::Flutter,
+            "rust" => Platform::Rust,
+            "go" | "golang" => Platform::Go,
+            "python" => Platform::Python,
+            "react-native" | "reactnative" | "rn" => Platform::ReactNative,
+            other => Platform::Unknown(other.to_string()),
+        })
+    }
+}
-impl Platform {
-    /// Parse platform from string.
-    pub fn from_str(s: &str) -> Self {
-        ...
-    }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 050c090 and 4090f25.

📒 Files selected for processing (14)
  • rust/CHANGELOG.md
  • rust/Cargo.toml
  • rust/src/bin/main.rs
  • rust/src/lib.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/flutter.rs
  • rust/src/symbolication/go.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/rust_sym.rs
  • rust/src/symbolication/store.rs
  • rust/src/web.rs
🧰 Additional context used
📓 Path-based instructions (4)
rust/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use rustdoc format (/// ... or //!) for docstrings in Rust code

Files:

  • rust/src/lib.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/flutter.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/go.rs
  • rust/src/web.rs
  • rust/src/symbolication/rust_sym.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
**/*.{kt,dart,ts,tsx,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,dart,ts,tsx,rs,go,py}: All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
All code must be reviewable by human developers with clear, descriptive variable and function names, appropriate comments for non-obvious logic, and consistent formatting per language conventions

Files:

  • rust/src/lib.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/flutter.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/go.rs
  • rust/src/web.rs
  • rust/src/symbolication/rust_sym.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
**/*.{kt,ts,tsx,dart,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,ts,tsx,dart,rs,go,py}: Rumor events must include sig: "" (empty string, not omitted) for NIP-17/59 implementation
Rumor events must include computed id field with SHA256 of serialized event in lowercase hex format (64 characters) for NIP-17/59 implementation
Event serialization order must be: [0, pubkey, created_at, kind, tags, content] for NIP-17/59 compliance
Seal events must be signed by the sender's key for NIP-17/59 implementation
Gift wrap events must be signed by an ephemeral key for NIP-17/59 implementation
All new code should have corresponding unit tests and test edge cases and error conditions

Files:

  • rust/src/lib.rs
  • rust/src/symbolication/android.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/flutter.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/go.rs
  • rust/src/web.rs
  • rust/src/symbolication/rust_sym.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
**/CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Files:

  • rust/CHANGELOG.md
🧠 Learnings (2)
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/CHANGELOG.md : All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Applied to files:

  • rust/CHANGELOG.md
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to rust/**/*.rs : Use rustdoc format (`/// ...` or `//!`) for docstrings in Rust code

Applied to files:

  • rust/Cargo.toml
🧬 Code graph analysis (8)
rust/src/symbolication/flutter.rs (1)
rust/src/symbolication/mod.rs (4)
  • new (241-243)
  • symbolicate (246-282)
  • symbolicated (165-180)
  • raw (153-162)
rust/src/symbolication/python.rs (2)
rust/src/symbolication/mod.rs (2)
  • new (241-243)
  • symbolicate (246-282)
rust/src/symbolication/rust_sym.rs (2)
  • new (19-21)
  • symbolicate (28-43)
rust/src/symbolication/go.rs (2)
rust/src/symbolication/mod.rs (4)
  • new (241-243)
  • symbolicate (246-282)
  • frames (217-220)
  • raw (153-162)
rust/src/symbolication/store.rs (1)
  • new (61-66)
rust/src/web.rs (3)
rust/src/symbolication/store.rs (1)
  • get (175-182)
rust/src/bin/main.rs (2)
  • symbolicate_stack (195-291)
  • serde_json (697-697)
rust/src/symbolication/mod.rs (1)
  • from_str (93-104)
rust/src/symbolication/rust_sym.rs (3)
rust/src/lib.rs (2)
  • new (96-100)
  • path (103-105)
rust/src/symbolication/mod.rs (3)
  • new (241-243)
  • symbolicate (246-282)
  • raw (153-162)
rust/src/symbolication/store.rs (1)
  • new (61-66)
rust/src/symbolication/react_native.rs (3)
rust/src/symbolication/android.rs (2)
  • new (208-210)
  • symbolicate (213-291)
rust/src/symbolication/javascript.rs (2)
  • new (22-24)
  • symbolicate (27-121)
rust/src/symbolication/mod.rs (6)
  • new (241-243)
  • symbolicate (246-282)
  • frames (217-220)
  • symbolicated (165-180)
  • raw (153-162)
  • as_str (107-118)
rust/src/bin/main.rs (6)
rust/src/compression.rs (2)
  • decompress_payload (83-103)
  • map (195-197)
rust/src/storage.rs (2)
  • parse_crash_content (231-279)
  • serde_json (233-233)
rust/src/web.rs (2)
  • create_router (32-50)
  • symbolicate_stack (93-134)
rust/src/lib.rs (1)
  • new (96-100)
rust/src/event.rs (1)
  • new (40-56)
rust/src/symbolication/mod.rs (5)
  • from_str (93-104)
  • percentage (225-231)
  • raw (153-162)
  • frames (217-220)
  • symbolicated (165-180)
rust/src/symbolication/store.rs (9)
rust/src/lib.rs (2)
  • path (103-105)
  • new (96-100)
rust/src/symbolication/android.rs (1)
  • new (208-210)
rust/src/symbolication/flutter.rs (1)
  • new (22-24)
rust/src/symbolication/go.rs (1)
  • new (19-21)
rust/src/symbolication/javascript.rs (1)
  • new (22-24)
rust/src/symbolication/mod.rs (2)
  • new (241-243)
  • from_str (93-104)
rust/src/symbolication/python.rs (1)
  • new (20-22)
rust/src/symbolication/react_native.rs (1)
  • new (22-24)
rust/src/symbolication/rust_sym.rs (1)
  • new (19-21)
🔇 Additional comments (13)
rust/src/lib.rs (1)

29-38: Clean public exposure of the symbolication API.

Nice, consistent re-export surface at the crate root.

rust/Cargo.toml (1)

44-46: No actionable changes needed. Verification confirms regex 1.10 (MSRV 1.65.0), sourcemap 9.0, and tempfile 3.14 (MSRV 1.63.0) have no known RustSec advisories and are compatible with Rust edition 2021 (MSRV 1.56.0).

rust/src/symbolication/android.rs (1)

1-5: Good module-level documentation.

The rustdoc format is properly used with //! for module documentation, explaining the purpose and functionality clearly.

rust/src/bin/main.rs (2)

81-107: Good CLI design for the Symbolicate command.

The command structure is well-designed with appropriate flags, default values, and clear help text. The -P short option for platform and - default for stdin input follow common CLI conventions.


239-288: Good output formatting implementation.

The pretty and JSON output formats are well-implemented with appropriate use of colored output for the terminal and structured JSON for machine consumption.

rust/src/symbolication/store.rs (4)

1-4: Good module documentation.

Clear rustdoc format with appropriate description of the module's purpose.


40-66: Excellent documentation with directory structure example.

The code block showing the expected directory layout is very helpful for users understanding how to organize their mapping files.


73-136: Solid implementation of directory scanning.

The scan logic properly handles the platform/app/version hierarchy, gracefully creates the root directory if missing, and tracks discovered mappings. Error handling using ? propagation is appropriate.


292-307: Good test structure.

The test properly uses tempfile::tempdir() for isolated test environments and validates the basic scan and lookup functionality.

rust/src/symbolication/mod.rs (4)

1-33: Excellent module-level documentation with usage example.

The documentation clearly explains supported platforms, includes a practical code example, and follows rustdoc conventions properly.


55-76: Well-designed error enum using thiserror.

The error variants cover the expected failure modes with informative messages. The #[from] attribute on IoError enables seamless conversion from std::io::Error.


134-199: Clean data structure design for symbolicated frames.

The SymbolicatedFrame struct with its constructors (raw and symbolicated) and display method provides a clear API. The boolean symbolicated field makes it easy to distinguish processed vs unprocessed frames.


234-282: Clean dispatcher pattern for platform-specific symbolication.

The Symbolicator::symbolicate method cleanly dispatches to platform-specific implementations. The match is exhaustive and properly handles the Unknown variant with an error.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 8 to 34
## [Unreleased]

### Added
- Symbolication module with support for 7 platforms:
- Android (ProGuard/R8 mapping.txt parsing)
- JavaScript/Electron (source map support)
- Flutter/Dart (flutter symbolize integration)
- Rust (backtrace parsing)
- Go (goroutine stack parsing)
- Python (traceback parsing)
- React Native (Hermes bytecode + JS source maps)
- `bugstr symbolicate` CLI command for symbolicating stack traces
- `POST /api/symbolicate` web API endpoint for dashboard integration
- `--mappings` option for `bugstr serve` to enable symbolication
- `MappingStore` for organizing mapping files by platform/app/version

## [0.1.0] - 2025-01-15

### Added
- Initial release
- Crash report receiver with NIP-17 gift wrap decryption
- Web dashboard for viewing and grouping crash reports
- SQLite storage with deduplication
- Gzip compression support for large payloads
- `bugstr listen` command for terminal-only crash monitoring
- `bugstr serve` command for web dashboard with crash collection
- `bugstr pubkey` command to display receiver public key
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add Changed/Fixed sections to match required changelog format.

The guideline calls for Added/Changed/Fixed sections; currently only Added is present in both sections. As per coding guidelines, please include Changed and Fixed headings (even if “None”).

📄 Suggested changelog structure
 ## [Unreleased]

 ### Added
 - Symbolication module with support for 7 platforms:
   - Android (ProGuard/R8 mapping.txt parsing)
   - JavaScript/Electron (source map support)
   - Flutter/Dart (flutter symbolize integration)
   - Rust (backtrace parsing)
   - Go (goroutine stack parsing)
   - Python (traceback parsing)
   - React Native (Hermes bytecode + JS source maps)
 - `bugstr symbolicate` CLI command for symbolicating stack traces
 - `POST /api/symbolicate` web API endpoint for dashboard integration
 - `--mappings` option for `bugstr serve` to enable symbolication
 - `MappingStore` for organizing mapping files by platform/app/version
+
+### Changed
+- None
+
+### Fixed
+- None

 ## [0.1.0] - 2025-01-15

 ### Added
 - Initial release
 - Crash report receiver with NIP-17 gift wrap decryption
 - Web dashboard for viewing and grouping crash reports
 - SQLite storage with deduplication
 - Gzip compression support for large payloads
 - `bugstr listen` command for terminal-only crash monitoring
 - `bugstr serve` command for web dashboard with crash collection
 - `bugstr pubkey` command to display receiver public key
+
+### Changed
+- None
+
+### Fixed
+- None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## [Unreleased]
### Added
- Symbolication module with support for 7 platforms:
- Android (ProGuard/R8 mapping.txt parsing)
- JavaScript/Electron (source map support)
- Flutter/Dart (flutter symbolize integration)
- Rust (backtrace parsing)
- Go (goroutine stack parsing)
- Python (traceback parsing)
- React Native (Hermes bytecode + JS source maps)
- `bugstr symbolicate` CLI command for symbolicating stack traces
- `POST /api/symbolicate` web API endpoint for dashboard integration
- `--mappings` option for `bugstr serve` to enable symbolication
- `MappingStore` for organizing mapping files by platform/app/version
## [0.1.0] - 2025-01-15
### Added
- Initial release
- Crash report receiver with NIP-17 gift wrap decryption
- Web dashboard for viewing and grouping crash reports
- SQLite storage with deduplication
- Gzip compression support for large payloads
- `bugstr listen` command for terminal-only crash monitoring
- `bugstr serve` command for web dashboard with crash collection
- `bugstr pubkey` command to display receiver public key
## [Unreleased]
### Added
- Symbolication module with support for 7 platforms:
- Android (ProGuard/R8 mapping.txt parsing)
- JavaScript/Electron (source map support)
- Flutter/Dart (flutter symbolize integration)
- Rust (backtrace parsing)
- Go (goroutine stack parsing)
- Python (traceback parsing)
- React Native (Hermes bytecode + JS source maps)
- `bugstr symbolicate` CLI command for symbolicating stack traces
- `POST /api/symbolicate` web API endpoint for dashboard integration
- `--mappings` option for `bugstr serve` to enable symbolication
- `MappingStore` for organizing mapping files by platform/app/version
### Changed
- None
### Fixed
- None
## [0.1.0] - 2025-01-15
### Added
- Initial release
- Crash report receiver with NIP-17 gift wrap decryption
- Web dashboard for viewing and grouping crash reports
- SQLite storage with deduplication
- Gzip compression support for large payloads
- `bugstr listen` command for terminal-only crash monitoring
- `bugstr serve` command for web dashboard with crash collection
- `bugstr pubkey` command to display receiver public key
### Changed
- None
### Fixed
- None
🤖 Prompt for AI Agents
In `@rust/CHANGELOG.md` around lines 8 - 34, Update the changelog sections under
the headings "## [Unreleased]" and "## [0.1.0] - 2025-01-15" to include
"Changed" and "Fixed" subsections in addition to the existing "Added" lists; for
each section add "### Changed" and "### Fixed" headings and list any relevant
entries or the word "None" if there are no changes/fixes to report so the file
follows the required Added/Changed/Fixed format.

Comment on lines +15 to +34
/// Flutter stack trace symbolicator.
pub struct FlutterSymbolicator<'a> {
store: &'a MappingStore,
}

impl<'a> FlutterSymbolicator<'a> {
/// Create a new Flutter symbolicator.
pub fn new(store: &'a MappingStore) -> Self {
Self { store }
}

/// Symbolicate a Flutter stack trace.
///
/// Attempts to use the `flutter symbolize` command if available,
/// otherwise falls back to basic symbol file parsing.
pub fn symbolicate(
&self,
stack_trace: &str,
context: &SymbolicationContext,
) -> Result<SymbolicatedStack, SymbolicationError> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Expand rustdoc for public FlutterSymbolicator APIs (params/returns/errors).

The current docs are brief but don’t describe parameters, return values, or error cases. As per coding guidelines, please expand rustdoc on the public struct/methods to include those details (and a short usage example if appropriate).

🤖 Prompt for AI Agents
In `@rust/src/symbolication/flutter.rs` around lines 15 - 34, Update the public
rustdoc for the FlutterSymbolicator struct and its public methods
(FlutterSymbolicator, new, symbolicate) to include explicit descriptions of
parameters (e.g., store: &MappingStore, stack_trace: &str, context:
&SymbolicationContext), the return type (Result<SymbolicatedStack,
SymbolicationError>), and the possible error cases (what triggers
SymbolicationError and when fallbacks occur). Add brief examples showing how to
construct a FlutterSymbolicator via FlutterSymbolicator::new and call
symbolicate, and document the behavior (uses `flutter symbolize` if available,
otherwise falls back to mapping parsing) and any panics/side-effects. Ensure
each public item has a short one-line summary followed by sections for
Arguments, Returns, Errors, and an optional Example.

Comment on lines +12 to +32
/// Rust stack trace symbolicator.
pub struct RustSymbolicator<'a> {
store: &'a MappingStore,
}

impl<'a> RustSymbolicator<'a> {
/// Create a new Rust symbolicator.
pub fn new(store: &'a MappingStore) -> Self {
Self { store }
}

/// Symbolicate a Rust stack trace.
///
/// Rust stack traces from panics typically include source locations
/// in debug builds. For release builds with symbols stripped, this
/// attempts to use addr2line with debug symbols if available.
pub fn symbolicate(
&self,
stack_trace: &str,
context: &SymbolicationContext,
) -> Result<SymbolicatedStack, SymbolicationError> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Expand rustdoc for the public RustSymbolicator API.
The current docs don’t describe parameters, return values, error conditions, or usage examples. Please expand the rustdoc on the public struct and methods to meet the project’s documentation requirements. As per coding guidelines.

🤖 Prompt for AI Agents
In `@rust/src/symbolication/rust_sym.rs` around lines 12 - 32, Update the rustdoc
for the public RustSymbolicator API: expand the doc comment on the
RustSymbolicator struct and its public methods new() and symbolicate() to
include parameter descriptions (e.g., explain the store field and the parameters
stack_trace: &str and context: &SymbolicationContext), the return value
(Result<SymbolicatedStack, SymbolicationError>), the error conditions that may
produce SymbolicationError, and at least one short usage example showing
constructing RustSymbolicator::new(&store) and calling symbolicate(stack_trace,
&context); keep docs concise, follow project style (sections: Arguments,
Returns, Errors, Examples), and mention any relevant lifetime or thread-safety
considerations for the store reference.

Comment on lines +23 to +50
/// Symbolicate a Rust stack trace.
///
/// Rust stack traces from panics typically include source locations
/// in debug builds. For release builds with symbols stripped, this
/// attempts to use addr2line with debug symbols if available.
pub fn symbolicate(
&self,
stack_trace: &str,
context: &SymbolicationContext,
) -> Result<SymbolicatedStack, SymbolicationError> {
// Try to find debug symbols
let mapping_info = self.store.get_with_fallback(
&context.platform,
context.app_id.as_deref().unwrap_or("unknown"),
context.version.as_deref().unwrap_or("unknown"),
);

// Rust backtraces already include source info in debug builds
// We just need to parse and format them nicely
self.parse_rust_backtrace(stack_trace, mapping_info.map(|i| i.path.as_path()))
}

/// Parse a Rust backtrace.
fn parse_rust_backtrace(
&self,
stack_trace: &str,
_symbols_path: Option<&std::path::Path>,
) -> Result<SymbolicatedStack, SymbolicationError> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n rust/src/symbolication/rust_sym.rs | head -80

Repository: alltheseas/bugstr

Length of output: 3623


🏁 Script executed:

cat -n rust/src/symbolication/rust_sym.rs | tail -n +80 | head -60

Repository: alltheseas/bugstr

Length of output: 2399


Docs overpromise addr2line support that isn't implemented.

Lines 25–27 claim the method "attempts to use addr2line with debug symbols if available" for stripped binaries, but parse_rust_backtrace ignores the _symbols_path parameter and only parses location info already present in the backtrace text. No addr2line lookup occurs. Either implement the symbol resolution using the passed mapping, or update the docstring to accurately reflect that only pre-symbolicated backtraces are supported.

🤖 Prompt for AI Agents
In `@rust/src/symbolication/rust_sym.rs` around lines 23 - 50, The docstring for
symbolicate claims addr2line lookup for stripped binaries but
parse_rust_backtrace currently ignores the _symbols_path and never uses
mapping_info; either implement addr2line-based resolution or change the docs. To
fix: either (A) implement symbol resolution in parse_rust_backtrace using the
provided _symbols_path/mapping_info (call addr2line or use gimli/addr2line
crates to open the debug file and resolve addresses found in stack_trace) and
wire mapping_info.path from symbolicate into parse_rust_backtrace, or (B) update
the symbolicate docstring to remove the claim about addr2line and state that
only backtraces containing source info are parsed; reference functions/vars:
symbolicate, parse_rust_backtrace, mapping_info, _symbols_path,
store.get_with_fallback, and SymbolicationContext to locate the code to change.

Comment on lines 26 to 29
pub struct AppState {
pub storage: Mutex<CrashStorage>,
pub symbolicator: Option<Symbolicator>,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the web.rs file around the lines mentioned
fd web.rs --type f

Repository: alltheseas/bugstr

Length of output: 76


🏁 Script executed:

# Get the structure of the rust directory
git ls-files rust/ | head -20

Repository: alltheseas/bugstr

Length of output: 566


🏁 Script executed:

# Read rust/src/web.rs to see the AppState and handler code
wc -l rust/src/web.rs

Repository: alltheseas/bugstr

Length of output: 80


🏁 Script executed:

# Read the relevant sections of rust/src/web.rs
sed -n '20,40p' rust/src/web.rs
echo "---"
sed -n '85,150p' rust/src/web.rs

Repository: alltheseas/bugstr

Length of output: 3094


🏁 Script executed:

# Also examine the Symbolicator struct definition
cat -n rust/src/symbolication/mod.rs | head -100

Repository: alltheseas/bugstr

Length of output: 3597


🏁 Script executed:

# Continue reading the Symbolicator struct and symbolicate method
sed -n '100,250p' rust/src/symbolication/mod.rs

Repository: alltheseas/bugstr

Length of output: 4162


🏁 Script executed:

# Look for the actual symbolicate method implementation
rg "fn symbolicate" rust/src/symbolication/ -A 20

Repository: alltheseas/bugstr

Length of output: 16041


🏁 Script executed:

# Check if there are any tests for the web handler
rg "test\|#\[test\]" rust/src/web.rs -A 5

Repository: alltheseas/bugstr

Length of output: 43


🏁 Script executed:

# Check for tests in symbolication module
find rust -name "*test*" -o -name "*_test.rs"

Repository: alltheseas/bugstr

Length of output: 43


🏁 Script executed:

# Look at the flutter.rs implementation more closely
sed -n '1,150p' rust/src/symbolication/flutter.rs

Repository: alltheseas/bugstr

Length of output: 5319


🏁 Script executed:

# Check for any existing tests for the symbolicate handler
grep -r "symbolicate_stack\|POST.*symbolicate" rust/src --include="*.rs" | head -20

Repository: alltheseas/bugstr

Length of output: 401


🏁 Script executed:

# Look for any tokio::task usages in the codebase to see patterns
rg "spawn_blocking\|spawn\|tokio::task" rust/src --type rs -B 2 -A 2

Repository: alltheseas/bugstr

Length of output: 87


🏁 Script executed:

# Check the full symbolicate_stack handler to see the complete implementation
sed -n '92,150p' rust/src/web.rs

Repository: alltheseas/bugstr

Length of output: 2195


🏁 Script executed:

# Look at the complete Symbolicator::symbolicate method in mod.rs
sed -n '230,320p' rust/src/symbolication/mod.rs

Repository: alltheseas/bugstr

Length of output: 1882


🏁 Script executed:

# Check if there are any async operations in symbolication
rg "async\|await\|spawn" rust/src/symbolication/ -A 2

Repository: alltheseas/bugstr

Length of output: 43


🏁 Script executed:

# Check Android symbolication for blocking operations
sed -n '1,100p' rust/src/symbolication/android.rs

Repository: alltheseas/bugstr

Length of output: 3614


🏁 Script executed:

# Check if there are any other blocking operations we should know about
sed -n '1,80p' rust/src/symbolication/javascript.rs

Repository: alltheseas/bugstr

Length of output: 2882


🏁 Script executed:

# Verify the full context - check if store operations are also blocking
cat -n rust/src/symbolication/store.rs | head -60

Repository: alltheseas/bugstr

Length of output: 1960


🏁 Script executed:

# Check MappingStore::get_with_fallback which is called by all symbolication methods
sed -n '1,200p' rust/src/symbolication/store.rs

Repository: alltheseas/bugstr

Length of output: 6636


🏁 Script executed:

# Check if there are any existing tests that exercise the symbolicator
rg "#\[test\]|#\[tokio::test\]" rust/src -A 5

Repository: alltheseas/bugstr

Length of output: 8905


🏁 Script executed:

# Check Cargo.toml for test dependencies
cat rust/Cargo.toml | grep -A 10 "\[dev-dependencies\]"

Repository: alltheseas/bugstr

Length of output: 97


🏁 Script executed:

# Final check - are there any async tests or integration tests for web handlers?
find rust -name "*test*" -type f

Repository: alltheseas/bugstr

Length of output: 43


🏁 Script executed:

# Double-check the web.rs handler one more time to see if there's any context we missed
sed -n '1,30p' rust/src/web.rs

Repository: alltheseas/bugstr

Length of output: 813


Use tokio::task::spawn_blocking to offload filesystem IO and external process calls.

The symbolicator.symbolicate method performs blocking filesystem operations (reading mapping files, writing temp files) and spawns external tools like flutter symbolize. Calling this directly in an async handler risks blocking Tokio's worker threads under load. Wrap the symbolicator with Arc, move it into a blocking task via spawn_blocking, and add unit tests for the handler to cover success and error cases.

💡 Suggested approach
 pub struct AppState {
     pub storage: Mutex<CrashStorage>,
-    pub symbolicator: Option<Symbolicator>,
+    pub symbolicator: Option<Arc<Symbolicator>>,
 }

 async fn symbolicate_stack(
     State(state): State<Arc<AppState>>,
     Json(request): Json<SymbolicateRequest>,
 ) -> impl IntoResponse {
-    let Some(ref symbolicator) = state.symbolicator else {
+    let Some(symbolicator) = state.symbolicator.as_ref() else {
         return (
             StatusCode::SERVICE_UNAVAILABLE,
             Json(serde_json::json!({
                 "error": "Symbolication not configured. Start server with --mappings option."
             }))
         ).into_response();
     };

     let platform = Platform::from_str(&request.platform);
     let context = SymbolicationContext {
         platform,
         app_id: request.app_id,
         version: request.version,
         build_id: request.build_id,
     };

-    match symbolicator.symbolicate(&request.stack_trace, &context) {
+    let stack_trace = request.stack_trace.clone();
+    let result = match tokio::task::spawn_blocking({
+        let symbolicator = Arc::clone(symbolicator);
+        move || symbolicator.symbolicate(&stack_trace, &context)
+    }).await {
+        Ok(res) => res,
+        Err(_) => {
+            return (
+                StatusCode::INTERNAL_SERVER_ERROR,
+                Json(serde_json::json!({ "error": "Symbolication task failed" }))
+            ).into_response();
+        }
+    };
+
+    match result {
         Ok(result) => Json(SymbolicateResponse {
             symbolicated_count: result.symbolicated_count,
             total_count: result.total_count,
             percentage: result.percentage(),
             display: result.display(),
             frames: result.frames.iter().map(|f| FrameJson {
                 raw: f.raw.clone(),
                 function: f.function.clone(),
                 file: f.file.clone(),
                 line: f.line,
                 column: f.column,
                 symbolicated: f.symbolicated,
             }).collect(),
         }).into_response(),
         Err(e) => (
             StatusCode::BAD_REQUEST,
             Json(serde_json::json!({ "error": e.to_string() }))
         ).into_response(),
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub struct AppState {
pub storage: Mutex<CrashStorage>,
pub symbolicator: Option<Symbolicator>,
}
pub struct AppState {
pub storage: Mutex<CrashStorage>,
pub symbolicator: Option<Arc<Symbolicator>>,
}
🤖 Prompt for AI Agents
In `@rust/src/web.rs` around lines 26 - 29, AppState currently holds symbolicator
directly (Option<Symbolicator>) which can cause blocking in async handlers;
change it to Option<Arc<Symbolicator>> (or wrap the existing Symbolicator in Arc
when constructing AppState), then in the async handler call the blocking
symbolication via tokio::task::spawn_blocking by cloning the Arc and moving it
into spawn_blocking to call symbolicator.symbolicate(...) so all filesystem IO
and external process invocations happen off the Tokio worker threads; ensure you
clone any args needed (e.g., request data) into the closure and await the
spawn_blocking JoinHandle, converting its Result into the handler's response;
finally add unit tests for the handler (using #[tokio::test]) that exercise
success and error paths by injecting a test/mocked Symbolicator (Arc-wrapped) to
verify proper spawn_blocking behavior and error propagation.

alltheseas and others added 5 commits January 16, 2026 11:28
The MappingStore.scan() method was never being called, which meant
mapping files were never actually loaded. This fix ensures mappings
are scanned in both the CLI symbolicate command and the serve command.

Also adds helpful warnings when no mapping files are found in the
specified directory.

Signed-off-by: alltheseas

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Go: Match pointer receivers like main.(*Type).Method
- JavaScript: Handle colons in URLs and Windows paths
- Python: Require Error/Exception/Warning suffix to avoid matching "Traceback"
- React Native: Handle URLs in file paths, preserve file path in fallback

Adds tests for URL handling in JavaScript and React Native.

Signed-off-by: alltheseas

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change symbolicator to Arc<Symbolicator> for safe sharing across threads.
Use spawn_blocking to run CPU-intensive symbolication work without
blocking the async runtime's executor threads.

This prevents symbolication requests from blocking other API endpoints.

Signed-off-by: alltheseas

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- flutter.rs: Use NamedTempFile for secure temp file handling instead
  of predictable fixed path that could be exploited
- store.rs: Use semver for proper version comparison instead of
  lexicographic ordering (so 1.10.0 > 1.9.0)

Signed-off-by: alltheseas

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Changed/Fixed subsections to CHANGELOG (Keep a Changelog format)
- Fix incorrect claim about addr2line in Rust symbolication docs
  (we parse backtraces, not DWARF debug info)

Signed-off-by: alltheseas

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@rust/src/bin/main.rs`:
- Around line 194-202: The symbolicate_stack function lacks a comprehensive
rustdoc; add a full doc comment above fn symbolicate_stack describing the
function's purpose, each parameter (platform_str, input, mappings_dir, app_id,
version, format) including expected formats and ownership/borrowing semantics,
the return type (Result<(), Box<dyn std::error::Error>>) and all possible error
cases, the behavior and structure of the produced output (how SymbolicateFormat
affects output), any side effects (file/IO, logging), and examples of typical
usage and expected input/output snippets; also document panics/edge-cases and
reference the SymbolicateFormat enum and mapping lookup behavior so callers know
how to handle errors and parse results.

In `@rust/src/symbolication/mod.rs`:
- Around line 121-251: Add expanded rustdoc comments for the public API:
document SymbolicationContext (fields: platform, app_id, version, build_id) with
parameter semantics and when fields can be None; document SymbolicatedFrame
(raw, function, file, line, column, symbolicated) and include how display()
formats frames; document SymbolicatedStack (raw, frames, symbolicated_count,
total_count) with explanation of display() and percentage(); and add a detailed
doc for Symbolicator::symbolicate describing arguments, the Result return (Ok
with SymbolicatedStack and Err with SymbolicationError) and possible error
cases; include short usage examples for creating a SymbolicationContext, calling
Symbolicator::symbolicate, and handling SymbolicationError in the docs.

In `@rust/src/symbolication/store.rs`:
- Around line 31-77: The public MappingStore API lacks comprehensive rustdoc;
update the docs for the MappingStore type and its public methods
(MappingStore::new, MappingStore::root, MappingStore::scan,
MappingStore::get_with_fallback, MappingStore::save_mapping and any other public
helpers) to include parameter descriptions, return value semantics, possible
SymbolicationError variants/errors, side effects (e.g., clearing/refreshing
mappings), and a short usage example showing typical creation, scan, lookup
(with fallback) and save flows; ensure examples compile (use doc-tests),
document thread-safety or mutability expectations, and mention directory layout
expectations already shown in the type doc.
- Around line 246-285: Validate and sanitize all path components used by
mapping_path/save_mapping: ensure Platform (handle Platform::Unknown) yields
only allowed token strings, and reject or canonicalize app_id, version, and
filename if they are absolute, contain "..", or contain path separators (e.g.,
'/' or '\\'); perform these checks in save_mapping before calling mapping_path
(or add a helper like validate_component) and return an error on invalid input
so files cannot be written outside self.root; keep add_mapping and mapping_path
unchanged except only call them after validation.
♻️ Duplicate comments (5)
rust/CHANGELOG.md (1)

30-40: Add Changed/Fixed sections to the 0.1.0 release entry.

The [Unreleased] section now correctly includes all three sections, but the [0.1.0] release entry is still missing the Changed and Fixed headings. As per coding guidelines, all changelog entries should follow the same format.

📄 Suggested addition
 ## [0.1.0] - 2025-01-15

 ### Added
 - Initial release
 - Crash report receiver with NIP-17 gift wrap decryption
 - Web dashboard for viewing and grouping crash reports
 - SQLite storage with deduplication
 - Gzip compression support for large payloads
 - `bugstr listen` command for terminal-only crash monitoring
 - `bugstr serve` command for web dashboard with crash collection
 - `bugstr pubkey` command to display receiver public key
+
+### Changed
+- None
+
+### Fixed
+- None
rust/src/symbolication/react_native.rs (1)

15-36: Expand rustdoc for the public API.

The current documentation is minimal. Per coding guidelines, public methods should document parameters, return values, error cases, and usage examples. The symbolicate method would benefit from documenting:

  • Parameter descriptions (stack_trace, context)
  • Possible SymbolicationError variants returned
  • Example usage
rust/src/symbolication/python.rs (1)

34-41: Mapping lookup isn't applied, so bundled-app paths never resolve.

The symbolicate method fetches mapping info (lines 35-39) but stores it as _mapping_info without using it. The docstring on line 28 claims the method "attempts to resolve bundled app paths to original sources if a mapping is available", but no such resolution occurs.

Either apply the mapping to transform file paths or remove the misleading docstring claim.

rust/src/symbolication/go.rs (2)

12-31: Expand rustdoc for GoSymbolicator public API.
Current docs don’t describe parameters, return values, error cases, lifetime semantics, or usage examples. This is required for public APIs. As per coding guidelines, please expand the rustdoc accordingly.


54-88: Go function regex is still too restrictive for real-world stack traces.
Module paths often include - and generic receivers can introduce [...], which the current character class won’t match, so frames get skipped. A more permissive pattern (plus trimming) avoids false negatives; please also add test cases for module paths with hyphens and generic receivers.

🐛 Suggested fix
-        let func_re = Regex::new(r"^([a-zA-Z0-9_./]+(?:\(\*[^)]+\))?[a-zA-Z0-9_.]*)\(([^)]*)\)$").unwrap();
+        let func_re = Regex::new(r"^(.+)\(([^)]*)\)$").unwrap();
@@
-                current_function = Some(caps[1].to_string());
-                current_args = Some(caps[2].to_string());
+                current_function = Some(caps[1].trim().to_string());
+                current_args = Some(caps[2].trim().to_string());
🧹 Nitpick comments (6)
rust/src/symbolication/python.rs (2)

74-83: Consider whether symbolicated: true is semantically correct here.

All parsed Python frames are marked symbolicated: true, but no actual symbolication (path resolution from bundled apps) occurs. The frames simply preserve the existing source information from the traceback.

If the mapping was actually applied to resolve bundled paths, then marking as symbolicated would be appropriate. As-is, this inflates the "symbolicated percentage" metric to near 100% for Python traces without doing meaningful work.

Consider setting symbolicated: false for frames where no mapping transformation was applied, or document that Python frames are considered "symbolicated" because they inherently contain source information.


175-189: Consider adding more test coverage for edge cases.

The current test only verifies that frames are counted. Consider adding tests for:

  • Empty or malformed tracebacks
  • Tracebacks without an exception line
  • Multi-line exception messages (e.g., AssertionError with a diff)
  • Chained exceptions (During handling of... another exception occurred)
rust/src/symbolication/javascript.rs (1)

60-65: Chrome regex may over-match without end anchor.

The Firefox regex correctly uses $ anchor but the Chrome regex doesn't. Without the anchor, the Chrome pattern may match partial lines or include trailing content. Consider adding $ for consistency:

-        let chrome_re = Regex::new(
-            r"^\s*at\s+(?:(.+?)\s+)?\(?(.+):(\d+):(\d+)\)?"
-        ).unwrap();
+        let chrome_re = Regex::new(
+            r"^\s*at\s+(?:(.+?)\s+)?\(?(.+):(\d+):(\d+)\)?$"
+        ).unwrap();

The file capture is now (.+) which correctly handles URLs and Windows paths - this addresses the previous feedback about colons in paths.

rust/src/symbolication/react_native.rs (3)

66-69: Consider adding end anchor to JS frame regex for consistency.

The regex now correctly uses (.+) for the file capture (handling URLs), but lacks a $ end anchor. This matches the JavaScript symbolicator's Chrome regex. For robustness, consider adding $:

-        let js_frame_re = Regex::new(
-            r"^\s*at\s+(?:(.+?)\s+)?\(?(?:address at\s+)?(.+):(\d+):(\d+)\)?"
-        ).unwrap();
+        let js_frame_re = Regex::new(
+            r"^\s*at\s+(?:(.+?)\s+)?\(?(?:address at\s+)?(.+):(\d+):(\d+)\)?$"
+        ).unwrap();

145-155: Note: Native Android frames may still be obfuscated.

The comment says "Native frames are usually not obfuscated", but ProGuard/R8 can obfuscate Java class and method names. These frames are marked symbolicated: true but no ProGuard deobfuscation is applied. Consider either:

  1. Marking as symbolicated: false and adding a separate ProGuard lookup
  2. Updating the comment to clarify this limitation

191-219: Good URL test coverage; consider adding more frame type tests.

The URL test case (http://localhost:8081/index.bundle) verifies correct parsing. Consider adding tests for:

  • Hermes format: "at myFunction (address at index.android.bundle:1:2345)"
  • Native Android: "at com.example.MyClass.method(MyClass.java:42)"
  • Native iOS: "0 MyApp 0x00000001 myFunction + 123"
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4090f25 and 2e29325.

📒 Files selected for processing (11)
  • rust/CHANGELOG.md
  • rust/Cargo.toml
  • rust/src/bin/main.rs
  • rust/src/symbolication/flutter.rs
  • rust/src/symbolication/go.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/store.rs
  • rust/src/web.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • rust/Cargo.toml
  • rust/src/symbolication/flutter.rs
🧰 Additional context used
📓 Path-based instructions (4)
**/CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Files:

  • rust/CHANGELOG.md
rust/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use rustdoc format (/// ... or //!) for docstrings in Rust code

Files:

  • rust/src/web.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/python.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
  • rust/src/symbolication/go.rs
**/*.{kt,dart,ts,tsx,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,dart,ts,tsx,rs,go,py}: All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs
All code must be reviewable by human developers with clear, descriptive variable and function names, appropriate comments for non-obvious logic, and consistent formatting per language conventions

Files:

  • rust/src/web.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/python.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
  • rust/src/symbolication/go.rs
**/*.{kt,ts,tsx,dart,rs,go,py}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{kt,ts,tsx,dart,rs,go,py}: Rumor events must include sig: "" (empty string, not omitted) for NIP-17/59 implementation
Rumor events must include computed id field with SHA256 of serialized event in lowercase hex format (64 characters) for NIP-17/59 implementation
Event serialization order must be: [0, pubkey, created_at, kind, tags, content] for NIP-17/59 compliance
Seal events must be signed by the sender's key for NIP-17/59 implementation
Gift wrap events must be signed by an ephemeral key for NIP-17/59 implementation
All new code should have corresponding unit tests and test edge cases and error conditions

Files:

  • rust/src/web.rs
  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/python.rs
  • rust/src/bin/main.rs
  • rust/src/symbolication/mod.rs
  • rust/src/symbolication/store.rs
  • rust/src/symbolication/go.rs
🧠 Learnings (3)
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/CHANGELOG.md : All user-facing changes require a CHANGELOG.md entry following the specified format (Added, Changed, Fixed sections)

Applied to files:

  • rust/CHANGELOG.md
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to rust/**/*.rs : Use rustdoc format (`/// ...` or `//!`) for docstrings in Rust code

Applied to files:

  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/go.rs
📚 Learning: 2026-01-16T15:49:11.199Z
Learnt from: CR
Repo: alltheseas/bugstr PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T15:49:11.199Z
Learning: Applies to **/*.{kt,dart,ts,tsx,rs,go,py} : All public classes, methods, and non-trivial functions must have documentation explaining purpose, behavior, parameters, return values, exceptions, and usage examples for complex APIs

Applied to files:

  • rust/src/symbolication/react_native.rs
  • rust/src/symbolication/javascript.rs
  • rust/src/symbolication/python.rs
  • rust/src/symbolication/go.rs
🧬 Code graph analysis (5)
rust/src/web.rs (2)
rust/src/bin/main.rs (2)
  • symbolicate_stack (195-299)
  • serde_json (724-724)
rust/src/symbolication/mod.rs (1)
  • from_str (93-104)
rust/src/symbolication/react_native.rs (3)
rust/src/symbolication/mod.rs (6)
  • new (241-243)
  • symbolicate (246-282)
  • frames (217-220)
  • symbolicated (165-180)
  • raw (153-162)
  • as_str (107-118)
rust/src/symbolication/javascript.rs (2)
  • new (22-24)
  • symbolicate (27-123)
rust/src/symbolication/android.rs (2)
  • new (208-210)
  • symbolicate (213-291)
rust/src/symbolication/javascript.rs (2)
rust/src/symbolication/mod.rs (4)
  • new (241-243)
  • symbolicate (246-282)
  • symbolicated (165-180)
  • raw (153-162)
rust/src/symbolication/rust_sym.rs (2)
  • new (19-21)
  • symbolicate (28-43)
rust/src/bin/main.rs (3)
rust/src/storage.rs (3)
  • count (184-187)
  • serde_json (233-233)
  • open (44-49)
rust/src/web.rs (1)
  • symbolicate_stack (93-147)
rust/src/symbolication/mod.rs (5)
  • from_str (93-104)
  • percentage (225-231)
  • raw (153-162)
  • frames (217-220)
  • symbolicated (165-180)
rust/src/symbolication/store.rs (10)
rust/src/lib.rs (2)
  • path (103-105)
  • new (96-100)
rust/src/symbolication/mod.rs (2)
  • new (241-243)
  • from_str (93-104)
rust/src/symbolication/flutter.rs (1)
  • new (23-25)
rust/src/symbolication/go.rs (1)
  • new (19-21)
rust/src/symbolication/javascript.rs (1)
  • new (22-24)
rust/src/symbolication/python.rs (1)
  • new (20-22)
rust/src/symbolication/react_native.rs (1)
  • new (22-24)
rust/src/symbolication/rust_sym.rs (1)
  • new (19-21)
rust/src/symbolication/android.rs (1)
  • new (208-210)
rust/src/storage.rs (1)
  • count (184-187)
🔇 Additional comments (9)
rust/CHANGELOG.md (1)

8-29: LGTM!

The [Unreleased] section properly documents the new symbolication module, CLI command, API endpoint, and MappingStore additions with the correct Added/Changed/Fixed structure.

rust/src/web.rs (3)

92-147: LGTM! Good use of spawn_blocking for CPU-bound work.

The handler correctly:

  1. Returns 503 when symbolication is not configured
  2. Uses Arc::clone and spawn_blocking to offload filesystem I/O and CPU-bound parsing
  3. Handles both symbolication errors (400) and task panics (500)

This addresses the previous review feedback about blocking the async runtime.


244-275: LGTM!

Request and response types are well-structured with appropriate field documentation and serde derives.


25-29: LGTM!

AppState now correctly wraps Symbolicator in Arc to enable safe sharing across async tasks via spawn_blocking.

rust/src/symbolication/python.rs (1)

60-61: LGTM!

The exception regex now requires names to end with Error, Exception, or Warning, which correctly excludes the "Traceback" header line.

rust/src/symbolication/javascript.rs (2)

26-123: LGTM!

The symbolication flow correctly:

  1. Requires a mapping file (returns MappingNotFound error if absent)
  2. Converts 1-based stack frame coordinates to 0-based for sourcemap lookup
  3. Converts results back to 1-based for output
  4. Falls back to raw frames when no token is found

145-158: Good addition of URL test case.

The test_parse_chrome_stack_frame_with_url correctly verifies that URLs with ports (like http://localhost:8080/bundle.js) are parsed properly. Consider also adding a test for Windows paths (C:/Users/app.js:10:5 or file:///C:/path/bundle.js:10:5) to complete coverage.

rust/src/symbolication/react_native.rs (1)

126-136: LGTM!

Good fix - unsymbolicated JS/Hermes frames now correctly preserve the parsed file path, line, and column information instead of discarding them. This addresses the previous review feedback.

rust/src/bin/main.rs (1)

223-233: Nice improvement: mappings are scanned and empties are surfaced.
This prevents silent “mapping not found” behavior and gives clear operator feedback.

Also applies to: 316-331

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

alltheseas and others added 4 commits January 16, 2026 12:00
Add detailed rustdoc documentation for the symbolication module:
- symbolicate_stack function with parameters, errors, output formats
- SymbolicationContext, SymbolicatedFrame, SymbolicatedStack structs
- Symbolicator::symbolicate with error cases and examples
- MappingStore and all public methods with usage examples

Add path validation to MappingStore.save_mapping to prevent directory
traversal attacks:
- New InvalidPath error variant in SymbolicationError
- validate_path_component() rejects empty, "..", "/", "\" in paths
- 6 new tests for path validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix three issues in Android symbolication:

1. HIGH: Support R8/ProGuard :origStart:origEnd format
   - Parse method lines like "1:5:void m()💯104 -> a"
   - Correctly map obfuscated line numbers to original source lines

2. MEDIUM: Handle overloaded/inlined methods correctly
   - Store each line range with its associated method name
   - Different line ranges can map to different original methods

3. MEDIUM: Preserve original line number when mapping absent
   - Return original line number instead of None when no range matches
   - Useful location info no longer lost

Add 5 new tests covering R8 format, overloads, and line preservation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add initialization check to clearPendingReports() to prevent runtime
error when called before init(). Now silently returns (no-op) like
processPendingReports() and captureException().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rust:
- ProGuard/R8 :origStart:origEnd line range support
- Overloaded method differentiation by line range
- Line number preservation when mapping missing
- Path validation security in MappingStore

Electron:
- clearPendingReports() guard against uninitialized store

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@alltheseas alltheseas merged commit e0754ca into main Jan 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

symbolication

1 participant