Skip to content

Conversation

@otoriphoenix
Copy link
Contributor

@otoriphoenix otoriphoenix commented Nov 18, 2025

Checklist

General

Server

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the principle of data economy for all client-server REST calls.
  • I strictly followed the client coding guidelines.

Motivation and Context

Currently, a lot of traces collected by the Sentry SDK are noise. Certain endpoints are not important to trace to evaluate the functionality of Artemis. This PR implements a more dynamic sampling approach to filter out noise and make sure the data within Sentry stays relevant and legible.

Description

I implemented custom sampling criteria in both client and server code. The custom sampling filters out certain noisy transactions and reduces the sample rate of some others.

Steps for Testing

Prerequisites:

  • 1 Artemis account of any privilege
  1. Log in to Artemis
  2. Navigate around
  3. Log in to Sentry
  4. In Sentry, verify there are no new traces for GET /api/core/public/time

Testserver States

You can manage test servers using Helios. Check environment statuses in the environment list. To deploy to a test server, go to the CI/CD page, find your PR or branch, and trigger the deployment.

Review Progress

Performance Review

  • I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students.
  • I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Exam Mode Test

  • Test 1
  • Test 2

Performance Tests

  • Test 1
  • Test 2

Test Coverage

As the changes are rather small, I did not generate a coverage report. If necessary, I can add them.

Summary by CodeRabbit

  • Performance & Monitoring
    • Optimized transaction sampling with intelligent filtering to reduce monitoring overhead while maintaining comprehensive error visibility across environments.

@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Nov 18, 2025
@github-actions github-actions bot added server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) core Pull requests that affect the corresponding module labels Nov 18, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 18, 2025

Walkthrough

Custom Sentry traces samplers are introduced in both Java and TypeScript configurations to selectively sample transactions based on request properties and environment. Production sampling rates are reduced from 0.20 to 0.05, with specific endpoints excluded or downsampled. Environment blank-value handling is also standardized.

Changes

Cohort / File(s) Summary
Sentry Java Configuration
src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
Introduces TracesSamplerCallback to conditionally sample transactions, dropping HEAD requests and excluding/downsampling specific endpoints (time, iris/status, management). Updates production trace sample rate from 0.20 to 0.05. Improves environment blank-value detection using isBlank.
Sentry TypeScript Configuration
src/main/webapp/app/core/sentry/sentry.error-handler.ts
Replaces tracesSampleRate with tracesSampler callback using environment-specific logic (1.0 for non-prod, 0.05 for prod). Excludes api/core/public/time transactions and reduces iris status transactions to 0.001 sampling rate.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~20 minutes

  • Verify that the sampling rules (URL patterns, endpoints excluded/downsampled) are correct and intentional across both implementations
  • Confirm the production sampling rate reduction from 0.20 to 0.05 aligns with performance/observability requirements
  • Validate consistency between Java and TypeScript implementations of the sampling logic

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adjusting Sentry trace sampling to reduce load, which aligns with implementing custom sampling criteria across client and server code.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/adjust-trace-sampling

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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
Contributor

@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: 2

🧹 Nitpick comments (1)
src/main/webapp/app/core/sentry/sentry.error-handler.ts (1)

36-37: Align with TypeScript and style guidelines for minor improvements

The sampler implementation correctly uses stable Sentry v10.25.0 APIs—samplingContext.name and inheritOrSampleWith are both documented and available. Two optional style refinements align with project guidelines:

  • Change let defaultSampleRate to const (variable is never reassigned)
  • Use single quotes instead of double quotes for string literals
-        let defaultSampleRate: number = this.environment !== PROFILE_PROD ? 1.0 : 0.05;
+        const defaultSampleRate: number = this.environment !== PROFILE_PROD ? 1.0 : 0.05;
             
             tracesSampler: (samplingContext) => {
                 const { name, inheritOrSampleWith } = samplingContext;

                 // Sample none of the time transactions
-                if (name.includes("api/core/public/time")) {
+                if (name.includes('api/core/public/time')) {
                     return 0.0;
                 }
                 // Sample less of the iris status transactions
-                if (name.includes("api/iris/status")) {
+                if (name.includes('api/iris/status')) {
                     return 0.001;
                 }
                 // Fall back to default sample rate
                 return inheritOrSampleWith(defaultSampleRate);
             },
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c038ff and 13b61ce.

📒 Files selected for processing (2)
  • src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java (6 hunks)
  • src/main/webapp/app/core/sentry/sentry.error-handler.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

Files:

  • src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
src/main/webapp/**/*.ts

⚙️ CodeRabbit configuration file

angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

Files:

  • src/main/webapp/app/core/sentry/sentry.error-handler.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: otoriphoenix
Repo: ls1intum/Artemis PR: 11388
File: src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java:92-102
Timestamp: 2025-10-24T22:55:10.778Z
Learning: In src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java, the substring matching using env.contains("test") and env.contains("staging") in the getTracesSampleRate() method is intentional. The project has multiple testing and staging environments whose names contain these strings, and they want to apply a common sample rate (1.0) to all such environments.
Learnt from: otoriphoenix
Repo: ls1intum/Artemis PR: 11388
File: docker/artemis/config/postgres.env:5-5
Timestamp: 2025-09-30T10:31:58.026Z
Learning: When using Sentry JDBC instrumentation with P6Spy, only a minimal spy.properties configuration is required: `modulelist=com.p6spy.engine.spy.P6SpyFactory`. This is the recommended configuration per Sentry's official documentation and prevents creating unnecessary spy.log files while enabling Sentry's SentryJdbcEventListener to capture database query spans.
📚 Learning: 2025-10-24T22:55:10.778Z
Learnt from: otoriphoenix
Repo: ls1intum/Artemis PR: 11388
File: src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java:92-102
Timestamp: 2025-10-24T22:55:10.778Z
Learning: In src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java, the substring matching using env.contains("test") and env.contains("staging") in the getTracesSampleRate() method is intentional. The project has multiple testing and staging environments whose names contain these strings, and they want to apply a common sample rate (1.0) to all such environments.

Applied to files:

  • src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
  • src/main/webapp/app/core/sentry/sentry.error-handler.ts
📚 Learning: 2025-09-30T10:31:58.026Z
Learnt from: otoriphoenix
Repo: ls1intum/Artemis PR: 11388
File: docker/artemis/config/postgres.env:5-5
Timestamp: 2025-09-30T10:31:58.026Z
Learning: When using Sentry JDBC instrumentation with P6Spy, only a minimal spy.properties configuration is required: `modulelist=com.p6spy.engine.spy.P6SpyFactory`. This is the recommended configuration per Sentry's official documentation and prevents creating unnecessary spy.log files while enabling Sentry's SentryJdbcEventListener to capture database query spans.

Applied to files:

  • src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
🧬 Code graph analysis (1)
src/main/webapp/app/core/sentry/sentry.error-handler.ts (1)
src/main/webapp/app/app.constants.ts (2)
  • PROFILE_PROD (73-73)
  • VERSION (3-3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: bean-instantiation-check
  • GitHub Check: Build and Push Docker Image / Build linux/amd64 Docker Image for ls1intum/artemis
  • GitHub Check: Build and Push Docker Image / Build linux/arm64 Docker Image for ls1intum/artemis
  • GitHub Check: Build .war artifact
  • GitHub Check: Analyse
  • GitHub Check: client-style
  • GitHub Check: server-style
  • GitHub Check: client-tests
  • GitHub Check: server-tests
🔇 Additional comments (1)
src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java (1)

108-111: Verify actual sentry.environment values before applying this change

The learning from previous work confirms that contains() was intentional to match multiple environments whose names contain "test" or "staging" at any position (e.g., "my-test-backend", "staging-api"). The current code uses the narrower startsWith() check, which would miss such environments.

However, the actual impact depends on your deployment's specific environment naming patterns. Since configuration files are not accessible in the repository (likely set via environment variables or deployment-specific configs), you need to:

  1. Verify the actual sentry.environment values across all test and staging deployments
  2. Confirm whether narrowing to startsWith() is causing any environments to fall back to 0.0 sampling unintentionally

If your environments follow patterns like test-*, *-test, staging-*, or *-staging, then restoring contains() aligns with the documented intent. If all environments strictly start with these prefixes, then startsWith() is sufficient.

Comment on lines +6 to 7
import jakarta.servlet.http.HttpServletRequest;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Guard against missing/incorrect HttpServletRequest in tracesSampler

samplingContext.getCustomSamplingContext().get("request") is blindly cast and dereferenced. For non-HTTP transactions or if the custom context is not populated as expected, this will throw a NullPointerException (or ClassCastException) inside the sampler and can break tracing for all such transactions.

Consider defensively handling the absence or wrong type of request and falling back to the parent sampling decision or the environment-based default:

-            SentryOptions.TracesSamplerCallback tracesSampler = samplingContext -> {
-                HttpServletRequest request = (HttpServletRequest) samplingContext.getCustomSamplingContext().get("request");
-                String url = request.getRequestURI();
-                String method = request.getMethod();
+            SentryOptions.TracesSamplerCallback tracesSampler = samplingContext -> {
+                Object requestObject = samplingContext.getCustomSamplingContext().get("request");
+                if (!(requestObject instanceof HttpServletRequest request)) {
+                    // Non-HTTP transaction: respect parent decision or fall back to env-based default
+                    Boolean parentSampled = samplingContext.getTransactionContext().getParentSampled();
+                    if (parentSampled != null) {
+                        return parentSampled ? 1.0 : 0.0;
+                    }
+                    return getTracesSampleRate();
+                }
+
+                String url = request.getRequestURI();
+                String method = request.getMethod();
-                if (method.equals("HEAD")) {
+                if ("HEAD".equals(method)) {
                     // We're not interested in HEAD requests, so we just drop them (113 transactions per minute)
                     return 0.0;
                 }

This keeps the new filtering behavior while making the sampler robust for all transaction types.

Please double-check Sentry Java’s TracesSamplerCallback documentation for recommended use of customSamplingContext and parentSampled in your version.

Also applies to: 16-17, 57-90


🌐 Web query:

In Sentry Java, what guarantees are there about `customSamplingContext` and the presence of an HTTP `request` key in `TracesSamplerCallback`, and how is `parentSampled` intended to be used?

💡 Result:

Short answer:

  • customSamplingContext: The TracesSamplerCallback receives a SamplingContext that may include a CustomSamplingContext if one was passed to startTransaction; but its contents are not guaranteed by the SDK — it only contains what the caller or the specific integration put there. Server/framework integrations often put the incoming HTTP request under a "request" (or similar) key, but that is an integration-level convenience, not a universal language-level guarantee. [1][2][3]

  • presence of HTTP request key: There is no absolute guarantee the SamplingContext will contain an HTTP request key. Docs say server frameworks "may" include the request; example Spring integration shows reading a HttpServletRequest from the custom sampling context if present. Do not rely on it unless your framework/integration documents that it adds it or you explicitly pass it when starting the transaction. [2][3]

  • parentSampled usage: parentSampled is exposed on the TransactionContext (SamplingContext.transactionContext.parentSampled) and represents the sampling decision inherited from an upstream/parent transaction. The recommended usage is to respect (return) that decision in your tracesSampler (e.g., return 1.0 if parentSampled true, 0.0 if false) to avoid breaking distributed traces. You may override it, but doing so can break trace continuity. The tracesSampler may also return null (let SDK fall back) or a sample rate (0.0–1.0). [1][4]

Sources:
[1] Sentry sampling docs (sampling context & parent sampling precedence).
[2] Sentry Java/Spring tracing docs (example showing request in customSamplingContext).
[3] io.sentry.SamplingContext Javadoc (API: getCustomSamplingContext, getTransactionContext).
[4] Sentry Java sampling docs/example showing returning parentSampled in tracesSampler.


Now let me verify the actual code in the repository:


---

🏁 Script executed:

```shell
#!/bin/bash
# Inspect SentryConfiguration.java to verify the NPE vulnerability
fd SentryConfiguration.java --type f -x cat {} \; | head -150

Length of output: 5559


Guard against missing/incorrect HttpServletRequest in tracesSampler to prevent NullPointerException

Lines 57–59 cast and immediately dereference samplingContext.getCustomSamplingContext().get("request") without any null or type checks. The web search confirms that there is no guarantee the request key exists in the custom sampling context—it is added only if the Spring framework integration explicitly populates it. For non-HTTP transactions or if the context is not populated, this will throw a NullPointerException and crash the sampler, potentially breaking tracing for all such transactions.

Defensively handle the absence or wrong type of request by checking with instanceof and falling back to the parent sampling decision or the environment-based default:

             SentryOptions.TracesSamplerCallback tracesSampler = samplingContext -> {
-                HttpServletRequest request = (HttpServletRequest) samplingContext.getCustomSamplingContext().get("request");
+                Object requestObject = samplingContext.getCustomSamplingContext().get("request");
+                if (!(requestObject instanceof HttpServletRequest request)) {
+                    // Non-HTTP transaction: respect parent decision or fall back to env-based default
+                    Boolean parentSampled = samplingContext.getTransactionContext().getParentSampled();
+                    if (parentSampled != null) {
+                        return parentSampled ? 1.0 : 0.0;
+                    }
+                    return getTracesSampleRate();
+                }
+
                 String url = request.getRequestURI();
                 String method = request.getMethod();
-                if (method.equals("HEAD")) {
+                if ("HEAD".equals(method)) {

This keeps the existing filtering behavior while making the sampler robust for all transaction types.

📝 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
import jakarta.servlet.http.HttpServletRequest;
SentryOptions.TracesSamplerCallback tracesSampler = samplingContext -> {
Object requestObject = samplingContext.getCustomSamplingContext().get("request");
if (!(requestObject instanceof HttpServletRequest request)) {
// Non-HTTP transaction: respect parent decision or fall back to env-based default
Boolean parentSampled = samplingContext.getTransactionContext().getParentSampled();
if (parentSampled != null) {
return parentSampled ? 1.0 : 0.0;
}
return getTracesSampleRate();
}
String url = request.getRequestURI();
String method = request.getMethod();
if ("HEAD".equals(method)) {
return 0.0;
}
// ... remaining sampler logic
};
🤖 Prompt for AI Agents
In src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
around lines 57–59, the tracesSampler dereferences
samplingContext.getCustomSamplingContext().get("request") without null/type
checks which can cause a NullPointerException; update the sampler to first
retrieve the object into a variable, check for null and that it is an instance
of HttpServletRequest using instanceof, and only cast and use it when valid; if
missing or wrong type, fall back to the parent sampling decision or the
environment-based default sampling decision so non-HTTP transactions continue to
be sampled safely.

Comment on lines +57 to +59
// For more fine-grained control over what we want to sample, we define a custom traces sampler.
// By default, it returns null to instead use the tracesSampleRate (as specified per the Sentry documentation).
// This filters out noise to enable us to focus on the transactions that actually impact Artemis functionality.
Copy link
Contributor

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

Align sampler fallback behavior and comments with Sentry’s API

The comment says the sampler “by default … returns null to instead use the tracesSampleRate”, but the implementation never returns null; it always returns a concrete double (including getTracesSampleRate() in the default path). At the same time options.setTracesSampleRate(getTracesSampleRate()); is documented as “configured as a fallback”.

To avoid confusion:

  • Either rely on Sentry’s built-in fallback by returning null from the sampler in the default case and keeping setTracesSampleRate, or
  • Drop setTracesSampleRate entirely and treat getTracesSampleRate() as your explicit, environment-based default within the sampler (updating the comments accordingly).

Right now the comments suggest the former, while the code effectively does the latter.

-            // By default, it returns null to instead use the tracesSampleRate (as specified per the Sentry documentation).
+            // By default, it uses getTracesSampleRate(), mirroring the global tracesSampleRate configuration for root transactions.
...
-                options.setTracesSampleRate(getTracesSampleRate()); // configured as a fallback
+                // Optionally keep this if the sampler can return null in the future; otherwise it is unused.
+                options.setTracesSampleRate(getTracesSampleRate());

Pick one strategy and make the comments match to prevent future misconfigurations.

Please confirm in your Sentry Java version whether tracesSampleRate is consulted at all when a tracesSampler is provided and the callback never returns null.

Also applies to: 88-90, 97-99


🌐 Web query:

When `tracesSampler` is set in Sentry Java, is `tracesSampleRate` still applied if the sampler always returns a number (never `null`)?

💡 Result:

If you provide a tracesSampler that returns a numeric sampling decision (0.0–1.0), that decision takes precedence and tracesSampleRate is not used. TracesSampler overrides tracesSampleRate; tracesSampleRate is only used when no tracesSampler (and no parent sampling decision) is present. [1][2][3]

Sources:

  • Sentry Java options docs (tracesSampleRate / tracesSampler). [1]
  • Sentry Log4j2 tracing docs (tracesSampler takes precedence). [2]
  • Sentry unified tracing guidelines (behaviour and precedence). [3]

Align sampler fallback behavior and comments with Sentry's API

Sentry Java's tracesSampler overrides tracesSampleRate when it returns a numeric value. Since your implementation always returns a concrete double (never null), the setTracesSampleRate() call is unused, and the comments are misleading.

Update the comments to reflect the actual behavior:

  • The sampler does not fall back to tracesSampleRate; it always applies its own decision via getTracesSampleRate().
  • Remove or clarify the misleading reference to Sentry's fallback behavior.
  • Optionally document why setTracesSampleRate() is retained if there are plans for future null returns.

Example:

-            // By default, it returns null to instead use the tracesSampleRate (as specified per the Sentry documentation).
+            // By default, it uses getTracesSampleRate() as the sampling rate; tracesSampler overrides tracesSampleRate.

Also applies to: 88-90, 97-99

🤖 Prompt for AI Agents
In src/main/java/de/tum/cit/aet/artemis/core/config/SentryConfiguration.java
around lines 57-59 (also apply same clarification to 88-90 and 97-99): the
comments state the traces sampler will return null to fall back to
tracesSampleRate, but the implementation always returns a concrete double so
tracesSampleRate is never used; update the comments to state that the custom
traces sampler always makes the sampling decision (overriding tracesSampleRate),
remove or reword the misleading fallback reference, and optionally add a short
note explaining why setTracesSampleRate() remains in code (e.g., kept for
possible future null-return behavior) if you want to retain it.

@github-project-automation github-project-automation bot moved this from Work In Progress to Ready For Review in Artemis Development Nov 18, 2025
@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report205 ran201 passed3 skipped1 failed1h 16m 51s 276ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts
ts.Static code analysis tests › Configures SCA grading and makes a successful submission with SCA errors❌ failure2m 36s 385ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client Pull requests that update TypeScript code. (Added Automatically!) core Pull requests that affect the corresponding module server Pull requests that update Java code. (Added Automatically!)

Projects

Status: Ready For Review

Development

Successfully merging this pull request may close these issues.

2 participants