Skip to content

feat(cymbal): add the path resolution service - #107633

Draft
ablaszkiewicz wants to merge 1 commit into
masterfrom
feat/cymbal-path-resolution-service
Draft

ablaszkiewicz wants to merge 1 commit into
masterfrom
feat/cymbal-path-resolution-service

Conversation

@ablaszkiewicz

@ablaszkiewicz ablaszkiewicz commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Merge order

  1. feat(error-tracking): list repository files with git #107631 feat(error-tracking): list repository files with git
  2. feat(error-tracking): store the file list of each release #107632 feat(error-tracking): store the file list of each release
  3. feat(integrations): check that the GitLab token can read the repository #107637 feat(integrations): check that the GitLab token can read the repository
  4. 👉 feat(cymbal): add the path resolution service #107633 feat(cymbal): add the path resolution service
  5. feat(cymbal): add repo paths to frames #107634 feat(cymbal): add repo paths to frames
  6. feat(error-tracking): link frames straight to their repo path #107635 feat(error-tracking): link frames straight to their repo path
  7. feat(error-tracking): scroll a frame's file at the release commit #107636 feat(error-tracking): scroll a frame's file at the release commit

Problem

  • Error tracking wants to link each stack frame to its file in the release repository. A frame path rarely equals the repository path: bundlers, build machines and containers add prefixes (webpack://app/./src/index.tsx, /home/runner/work/shop/shop/app/models.py).
  • The file list of a commit can hold 100k+ paths. Loading every list into every processing pod wastes memory.
  • This PR adds a small service that answers "which repository files are these frame paths?" for one commit. Nothing calls it yet. The caller comes in the next layer.

Changes

  • New run mode CYMBAL_MODE=path_resolution, deployed as cymbal-path-resolution, serving gRPC cymbal.path_resolution.v1.ResolvePaths.
  • One request per exception: team, repo slug, full commit, and at most 100 frame paths. The response has one result per path, in order.
  • Matching finds the longest trailing part of the frame path that is also the end of a repository file, skipping empty, . and .. segments:
Outcome When Path returned Cacheable
SURE exactly one file matches yes yes
SUPPORT several files match, and the sure matches of the same request pick one yes no
TIE several files match, and nothing decides no no
NO_MATCH no file matches no yes
  • File lists come from object storage, written by the release job in feat(error-tracking): store the file list of each release #107632. The service keeps them in a moka cache weighed by bytes (2 GiB by default).
  • A cache miss starts one load per key, shared by concurrent requests. The load finishes and fills the cache even when the request that started it gives up. Missing lists are remembered for 120 s.
  • Auth is a dedicated shared secret in x-cymbal-path-resolution-secret, with rotation. It is not INTERNAL_API_SECRET, so a leak reaches this service only.
  • No Postgres, Kafka or Redis. The lists never change, so object storage plus the in-memory cache is enough.
  • Local dev: bin/start-rust-service cymbal-path-resolution and an mprocs entry.
  • rust/cymbal/src/modes/path_resolution/README.md documents the contract, the config and the deployment order.

Note

The service needs a deployment (headless Kubernetes service, memory sized for the cache) before the caller is turned on. The caller treats an unreachable service as "no path", so the order is safe either way.

How did you test this code?

  • matching.rs holds the reference vectors: prefixes, relative segments, file-name-only matches, votes, and ties.
  • list_store.rs tests catch a missing list that reaches storage on every request, concurrent misses that load twice, a load that dies with its caller, and a list that decompresses past the limit.
  • auth.rs tests catch a retired secret that still works, and an empty secret list that lets requests through.
  • service.rs tests catch results out of request order and invalid requests that get an answer.
  • End to end on a local stack with the rest of the series: processing cymbal called the service and wrote repo_path on the frames.

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Release status

  • No feature flag controls this change
  • This change is behind a feature flag and is not available to users
  • This change makes a previously flagged feature available to everyone

Nothing calls the service yet.

Automatic notifications

  • Publish to changelog?

Docs update

None under docs/. The mode README in the cymbal crate covers the service.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5 (claude-opus-5-5, 1M context)

  • Session: https://claude.ai/code/session_01DpTwx89x8Wu9Nu9B82mPEj
  • Skills invoked: /writing-tests, /writing-code-comments, /writing-pr-descriptions, /stacking-prs.
  • CodeRabbit CLI: skipped. The CLI was signed out, and the person chose to skip setup.
  • The first design cached lists in Valkey. It was dropped in favor of object storage plus rendezvous routing to one warm pod per list.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DpTwx89x8Wu9Nu9B82mPEj

@ablaszkiewicz ablaszkiewicz self-assigned this Sep 28, 2026
@trunk-io

trunk-io Bot commented Sep 28, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Comment density — 3% of added code lines are comments (44 of 1283)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
rust/cymbal/src/modes/path_resolution/list_store.rs 13 322
rust/cymbal/src/modes/path_resolution/matching.rs 8 240
rust/cymbal/src/modes/path_resolution/config.rs 6 65
rust/cymbal/src/modes/path_resolution/file_index.rs 6 104
rust/cymbal/src/core/repo_slug.rs 3 52
rust/cymbal/src/modes/path_resolution/auth.rs 3 69
rust/cymbal/src/modes/path_resolution/mod.rs 3 140
rust/cymbal/src/core/metric_consts.rs 1 7

This check does not block merging. It updates on every push and clears when the share drops.

✅ Bundle size — no change

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 68.94 MiB · no change

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.57 MiB · 22 files no change █████████░ 85.5% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.56 MiB · 629 files no change █████████░ 88.4% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.38 MiB · 2,332 files no change █████████░ 88.5% of 8.34 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
854 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
267.6 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
100.4 KiB src/lib/api.ts
88.4 KiB src/products.tsx
69.4 KiB src/lib/lemon-ui/icons/icons.tsx
40.1 KiB src/lib/utils/eventUsageLogic.ts
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
28.4 KiB src/scenes/scenes.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
301.8 KiB ../node_modules/.pnpm/posthog-js@1.434.14_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
271.7 KiB src/taxonomy/core-filter-definitions-by-group.json
267.6 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
100.4 KiB src/lib/api.ts
98.5 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
88.4 KiB src/products.tsx

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

✅ Toolbar bundle — eager 2.38 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.38 MiB · 19 files no change ████░░░░░░ 41.5% of 5.72 MiB
Deferred (lazy) 2.10 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
800.0 KiB dist/toolbar/toolbar-app-6DYXIWRU.css
651.4 KiB dist/toolbar/chunk-chunk-TVTQKACM.js
483.6 KiB dist/toolbar/chunk-chunk-6JFSEK3E.js
138.3 KiB dist/toolbar/chunk-chunk-CP4QT72J.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-OHYAIWFE.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-577JVGVT.js
21.0 KiB dist/toolbar/chunk-chunk-GNB7IYR7.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — no change

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 946.22 MiB · no change

@ablaszkiewicz
ablaszkiewicz added this pull request to stack #107639 September 28, 2026 11:53
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Adds a new gRPC service for mapping file paths to repository paths.

The PR should not merge until callers cannot cache unloaded-list results and concurrent cold loads have a resource bound.

Reviews (1) · Last reviewed commit: "feat(cymbal): add the path resolution se..."

| `OUTCOME_TIE` | Several files match, and nothing decides. | empty |
| `OUTCOME_NO_MATCH` | No file matches. | empty |

`SURE` and `NO_MATCH` depend only on the path and the commit, so callers may cache them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 No-match results can become stale. When the list is missing or object storage fails, the service returns NO_MATCH for every path. This guidance lets callers cache those results, so they can keep returning “no path” after the list is written or storage recovers. Say that NO_MATCH is cacheable only when list_state is LIST_STATE_LOADED.

Prompt To Fix With AI
This is a comment left during a code review.
Path: rust/cymbal/src/modes/path_resolution/README.md
Line: 50

Comment:
**No-match results can become stale.** When the list is missing or object storage fails, the service returns `NO_MATCH` for every path. This guidance lets callers cache those results, so they can keep returning “no path” after the list is written or storage recovers. Say that `NO_MATCH` is cacheable only when `list_state` is `LIST_STATE_LOADED`.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

// it passes its deadline. Concurrent misses for one key share a single load.
let store = self.clone();
let key = key.clone();
let load = tokio::spawn(async move {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Cold loads can exhaust memory. Each distinct cold key starts a background load that continues after its request ends. These loads are outside the 2 GiB cache budget; with up to 256 concurrent requests and 64 MiB allowed per list, cold-key traffic can use many GiB more than the cache and exhaust a pod. Bound concurrent loads or their aggregate memory separately from request concurrency.

Prompt To Fix With AI
This is a comment left during a code review.
Path: rust/cymbal/src/modes/path_resolution/list_store.rs
Line: 120

Comment:
**Cold loads can exhaust memory.** Each distinct cold key starts a background load that continues after its request ends. These loads are outside the 2 GiB cache budget; with up to 256 concurrent requests and 64 MiB allowed per list, cold-key traffic can use many GiB more than the cache and exhaust a pod. Bound concurrent loads or their aggregate memory separately from request concurrency.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

repo: request.repo,
commit: request.commit,
};
let (list_state, outcomes) = match self.store.get(&key).await {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Empty requests load file lists. A request with no paths passes validation but still fetches and indexes the entire list on a cold key. That spends an object-storage read and cache work without producing any path results. Return an empty response before loading the list.

Prompt To Fix With AI
This is a comment left during a code review.
Path: rust/cymbal/src/modes/path_resolution/service.rs
Line: 46

Comment:
**Empty requests load file lists.** A request with no paths passes validation but still fetches and indexes the entire list on a cold key. That spends an object-storage read and cache work without producing any path results. Return an empty response before loading the list.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: fd4c1bce-aab2-4f2b-90ea-b8317294f873

📥 Commits

Reviewing files that changed from the base of the PR and between 64f69bd and c9f1d87.

📒 Files selected for processing (21)
  • bin/mprocs.yaml
  • bin/start-rust-service
  • proto/cymbal/path_resolution/v1/path_resolution.proto
  • rust/cymbal-proto/README.md
  • rust/cymbal-proto/build.rs
  • rust/cymbal-proto/src/lib.rs
  • rust/cymbal/Cargo.toml
  • rust/cymbal/README.md
  • rust/cymbal/src/core/metric_consts.rs
  • rust/cymbal/src/core/mod.rs
  • rust/cymbal/src/core/repo_slug.rs
  • rust/cymbal/src/main.rs
  • rust/cymbal/src/modes/mod.rs
  • rust/cymbal/src/modes/path_resolution/README.md
  • rust/cymbal/src/modes/path_resolution/auth.rs
  • rust/cymbal/src/modes/path_resolution/config.rs
  • rust/cymbal/src/modes/path_resolution/file_index.rs
  • rust/cymbal/src/modes/path_resolution/list_store.rs
  • rust/cymbal/src/modes/path_resolution/matching.rs
  • rust/cymbal/src/modes/path_resolution/mod.rs
  • rust/cymbal/src/modes/path_resolution/service.rs

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

The change adds the cymbal.path_resolution.v1 gRPC API and a new Cymbal mode. The service validates requests, loads and caches compressed repository file lists, matches frame paths to repository paths, and returns ordered outcomes. It also adds shared-secret authentication, metrics, readiness and shutdown handling, configuration, startup wiring, and deployment and usage documentation.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to c9f1d

No confirmed issue blocks merging this service before its caller is enabled. Confirm file-list compatibility and deployment health checks before enabling the caller.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to c9f1d

The new service limits access with a dedicated secret and validates requests, but anyone holding that secret can select file lists across teams. Distinct requests can also continue loading lists after callers disconnect. Actual deployment access controls and callers are not established, so the practical exposure remains uncertain.

Retained concerns

  • Medium · security · inferred: An accepted service-wide bearer secret permits requests for any syntactically valid team, repository, and commit; no caller-to-resource authorization is visible. This creates a cross-team repository-path lookup capability for any holder of that secret, although its actual distribution and network reachability are unknown.
  • Medium · security · inferred: Distinct cache misses start independent object-storage and decode work that survives request cancellation. Repeated high-cardinality requests can accumulate work beyond the active-RPC limit, making the new service and its storage dependency susceptible to resource amplification by a credential holder.
Security review details

Security Blast Radius

  • inferred — A holder of the dedicated secret can probe matching repository paths for any valid team, repo, and commit key available in the configured bucket and folder. The RPC does not return an entire list, and actual reachable callers and credential distribution are unknown.

Security Findings and Attack Paths

  • inferred — If an unauthorized party obtains the service secret and can reach the listener, it can select cross-team lookup keys. Repeated distinct keys, particularly with early disconnects, can continue consuming background storage and decode capacity. Neither access condition is verified in the available deployment evidence.

Trust Boundaries and Controls

  • observed — The gRPC interceptor rejects missing or invalid secrets before the handler. Input validation prevents malformed repo or commit components from selecting storage keys; these controls do not authorize a valid key for a particular caller.

Resilience and Maintainability Implications

  • inferred — The active-RPC limit, per-read timeout, negative-cache TTL, and decompression limit constrain individual paths, but do not provide a global bound on detached distinct-key loads. The shared S3 client collects the compressed body before the decompression limit applies.

Hardening Proposals

  • proposed — Bind callers to an approved service identity and, where required, authorized team scope; verify network and channel protections and secret distribution in deployment configuration. Avoid requiring bucket-wide listing solely for the startup check if a narrower access check suffices.
  • proposed — Apply aggregate admission and byte limits to storage loads and decode work, including work retained after cancellation, while preserving same-key coalescing and retry after transient failures.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and aligned with the repository template. It explains the problem, user-visible changes, testing, release status, documentation impact, and agent context. It also documents…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

@trunk-io

trunk-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Event Pipeline E2E tests (fold+groupBatchCreates=false) we do not leave things in inconsistent state if $identify is run concurrently A test expected the value 2 but received 1, indicating a mismatch in the expected and actual output. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

Adds CYMBAL_MODE=path_resolution, a gRPC service that maps the frame paths
of one exception to files of the release commit. It reads the commit's file
list from object storage, keeps lists in a byte-weighed in-memory cache with
single-flight background loads, and matches paths statelessly. Nothing calls
it yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ablaszkiewicz
ablaszkiewicz force-pushed the feat/cymbal-path-resolution-service branch from d99a91f to 9eecb21 Compare September 28, 2026 16:19
@hosthog

hosthog Bot commented Sep 28, 2026

Copy link
Copy Markdown

HostHog preview — storybook-quill

Latest build (9eecb21): https://2dcb3947e01d4e32b04dc9f50da22156.hosthog.dev

Employee-gated; every push gets a fresh URL whose content never changes. All previews stop serving when the PR closes.

@hosthog

hosthog Bot commented Sep 28, 2026

Copy link
Copy Markdown

HostHog preview — posthog-desktop-web

Latest build (9eecb21): https://c992798f34864e49ad5d1d75b17a87b1.hosthog.dev

Employee-gated; every push gets a fresh URL whose content never changes. All previews stop serving when the PR closes.

This branch has not been deployed

No deployments
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.

1 participant